Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0x7AD52eceFFcb3bD41BC434a9AcFECdBC8Ef8450e
Balance 0 ETH
Nonce 1
Code Size 8825 bytes
Indexed Transactions 0 (1 on-chain, 0.7% indexed)
External Etherscan · Sourcify

Contract Bytecode

8825 bytes
0x608060405234801561001057600080fd5b50600436106101f05760003560e01c8063715018a61161010f578063b88d4fde116100a2578063e985e9c511610071578063e985e9c51461041b578063ed459df214610457578063f2fde38b1461046a578063ffbdc8cb1461047d57600080fd5b8063b88d4fde146103da578063c87b56dd146103ed578063e2e784d514610400578063e8a3d4851461041357600080fd5b80638da5cb5b116100de5780638da5cb5b146103995780638f32d59b146103ac57806395d89b41146103bf578063a22cb465146103c757600080fd5b8063715018a61461035957806379ba5097146103615780638a71bb2d146103695780638b6854a21461037257600080fd5b806342842e0e116101875780636352211e116101565780636352211e14610322578063646c2e33146103355780636c0360eb1461033e57806370a082311461034657600080fd5b806342842e0e146102d657806342966c68146102e95780634c00de82146102fc5780636039dca91461030f57600080fd5b806318160ddd116101c357806318160ddd1461027257806323452b9c1461028957806323b872dd146102915780632a55205a146102a457600080fd5b806301ffc9a7146101f557806306fdde031461021d578063081812fc14610232578063095ea7b31461025d575b600080fd5b610208610203366004611b65565b610492565b60405190151581526020015b60405180910390f35b6102256105c3565b6040516102149190611be1565b610245610240366004611bf4565b610651565b6040516001600160a01b039091168152602001610214565b61027061026b366004611c32565b6106f7565b005b61027b60065481565b604051908152602001610214565b610270610847565b61027061029f366004611c5e565b6108b3565b6102b76102b2366004611c9f565b61093a565b604080516001600160a01b039093168352602083019190915201610214565b6102706102e4366004611c5e565b610970565b6102706102f7366004611bf4565b61098b565b600c54610245906001600160a01b031681565b61027061031d366004611da6565b610a13565b610245610330366004611bf4565b610cf2565b61027b60055481565b610225610dbb565b61027b610354366004611ee2565b610dc8565b610270610e62565b610270610ec6565b61027b600d5481565b6102457f0000000000000000000000000e1c07384dd2ada007e4b819816fd34afb4678f181565b600054610245906001600160a01b031681565b6000546001600160a01b03163314610208565b610225610f8e565b6102706103d5366004611eff565b610f9b565b6102706103e8366004611f2b565b611061565b6102256103fb366004611bf4565b6110ef565b61027061040e366004611c32565b611123565b6102256111d8565b610208610429366004611fab565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205460ff1690565b6001546001600160a01b03163314610208565b610270610478366004611ee2565b611200565b61027b61048b366004611bf4565b5060055490565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061052557507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061057157507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b806105bd57507fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a00000000000000000000000000000000000000000000000000000000145b92915050565b600280546105d090611fe4565b80601f01602080910402602001604051908101604052809291908181526020018280546105fc90611fe4565b80156106495780601f1061061e57610100808354040283529160200191610649565b820191906000526020600020905b81548152906001019060200180831161062c57829003601f168201915b505050505081565b60008181526007602052604081205460ff16156106db5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e000000000000000000000000000000000000000060648201526084015b60405180910390fd5b506000908152600a60205260409020546001600160a01b031690565b600061070282610cf2565b9050806001600160a01b0316836001600160a01b0316141561078c5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f720000000000000000000000000000000000000000000000000000000000000060648201526084016106d2565b336001600160a01b03821614806107c657506001600160a01b0381166000908152600b6020908152604080832033845290915290205460ff165b6108385760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c000000000000000060648201526084016106d2565b61084283836112d2565b505050565b6000546001600160a01b031633146108a15760405162461bcd60e51b815260206004820152601860248201527f63616c6c6572206973206e6f7420746865206f776e65722e000000000000000060448201526064016106d2565b600180546001600160a01b0319169055565b6108bd3382611340565b61092f5760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f76656400000000000000000000000000000060648201526084016106d2565b610842838383611443565b600c54600d546001600160a01b03909116906000906127109061095d9085612035565b610967919061206a565b90509250929050565b61084283838360405180602001604052806000815250611061565b6109953382611340565b610a075760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f76656400000000000000000000000000000060648201526084016106d2565b610a1081611613565b50565b303b15610a1f57600080fd5b88518051610a3591600291602090910190611a9e565b506020808a01518051610a4c926003920190611a9e565b5060408901518051610a6691600491602090910190611a9e565b5060608901516005556080890151600655610a826000896116c3565b600c80546001600160a01b0319166001600160a01b0388811691909117909155600d86905560808a01519089169060009081907fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d90610ae39060019061207e565b60405190815260200160405180910390a46006546001600160a01b0389166000908152600960205260409020558215610ce7577f0000000000000000000000000e1c07384dd2ada007e4b819816fd34afb4678f16001600160a01b0316637d762af3604051806101000160405280306001600160a01b03168152602001600081526020016001600654610b76919061207e565b81526020018b6001600160a01b031681526020018a6001600160a01b031681526020018781526020018515158152602001848152506040518263ffffffff1660e01b8152600401610c2c91906000610100820190506001600160a01b0380845116835260208401516020840152604084015160408401528060608501511660608401528060808501511660808401525060a083015160a083015260c0830151151560c083015260e083015160e083015292915050565b600060405180830381600087803b158015610c4657600080fd5b505af1158015610c5a573d6000803e3d6000fd5b505050506001600160a01b038881166000818152600b602090815260408083207f0000000000000000000000000e1c07384dd2ada007e4b819816fd34afb4678f190951680845294825291829020805460ff1916600190811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35b505050505050505050565b6000818152600860205260408120546001600160a01b031680158015610d27575060008381526007602052604090205460ff16155b15610d3f5750506000546001600160a01b0316919050565b6001600160a01b0381166105bd5760405162461bcd60e51b815260206004820152602360248201527f4552433732313a20717565727920666f72206e6f6e6578697374656e7420746f60448201527f6b656e000000000000000000000000000000000000000000000000000000000060648201526084016106d2565b600480546105d090611fe4565b60006001600160a01b038216610e465760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f20616464726573730000000000000000000000000000000000000000000060648201526084016106d2565b506001600160a01b031660009081526009602052604090205490565b6000546001600160a01b03163314610ebc5760405162461bcd60e51b815260206004820152601860248201527f63616c6c6572206973206e6f7420746865206f776e65722e000000000000000060448201526064016106d2565b610ec4611712565b565b6001546001600160a01b03163314610f465760405162461bcd60e51b815260206004820152602c60248201527f63757272656e74206f776e6572206d757374207365742063616c6c657220617360448201527f206e657874206f776e65722e000000000000000000000000000000000000000060648201526084016106d2565b600180546001600160a01b0319908116909155600080543392168217815560405182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3565b600380546105d090611fe4565b6001600160a01b038216331415610ff45760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c65720000000000000060448201526064016106d2565b336000818152600b602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3191015b60405180910390a35050565b61106b3383611340565b6110dd5760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f76656400000000000000000000000000000060648201526084016106d2565b6110e98484848461174e565b50505050565b606060046110fc836117d7565b60405160200161110d92919061212f565b6040516020818303038152906040529050919050565b6000546001600160a01b0316331461117d5760405162461bcd60e51b815260206004820152601860248201527f63616c6c6572206973206e6f7420746865206f776e65722e000000000000000060448201526064016106d2565b600c80546001600160a01b0319166001600160a01b038416908117909155600d829055604080518381526020810184905282917f880886fe0560f4b0a18941fe4c443a499c03fd9491832ddfc895278ac7e8878c9101611055565b606060046040516020016111ec9190612154565b604051602081830303815290604052905090565b6000546001600160a01b0316331461125a5760405162461bcd60e51b815260206004820152601860248201527f63616c6c6572206973206e6f7420746865206f776e65722e000000000000000060448201526064016106d2565b6001600160a01b0381166112b05760405162461bcd60e51b815260206004820152601f60248201527f4e657874206f776e657220697320746865207a65726f20616464726573732e0060448201526064016106d2565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600a6020526040902080546001600160a01b0319166001600160a01b038416908117909155819061130782610cf2565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008181526007602052604081205460ff16156113c55760405162461bcd60e51b815260206004820152602360248201527f4552433732313a20717565727920666f72206e6f6e6578697374656e7420746f60448201527f6b656e000000000000000000000000000000000000000000000000000000000060648201526084016106d2565b60006113d083610cf2565b9050806001600160a01b0316846001600160a01b0316148061140b5750836001600160a01b031661140084610651565b6001600160a01b0316145b8061143b57506001600160a01b038082166000908152600b602090815260408083209388168352929052205460ff165b949350505050565b826001600160a01b031661145682610cf2565b6001600160a01b0316146114d25760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201527f73206e6f74206f776e000000000000000000000000000000000000000000000060648201526084016106d2565b6001600160a01b03821661154e5760405162461bcd60e51b815260206004820152603760248201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f726573732028757365206275726e20696e73746561642900000000000000000060648201526084016106d2565b6115596000826112d2565b6001600160a01b038316600090815260096020526040812080546001929061158290849061207e565b9091555050600081815260086020908152604080832080546001600160a01b0319166001600160a01b0387169081179091558352600990915281208054600192906115ce90849061218d565b909155505060405181906001600160a01b0380851691908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90600090a4505050565b600061161e82610cf2565b905061162b6000836112d2565b6001600160a01b038116600090815260096020526040812080546001929061165490849061207e565b9091555050600082815260086020908152604080832080546001600160a01b03191690556007909152808220805460ff19166001179055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b600080546001600160a01b0319166001600160a01b0383811691821783556040519192908516917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080546001600160a01b031916815560405181907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3565b611759848484611443565b61176584848484611909565b6110e95760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e746572000000000000000000000000000060648201526084016106d2565b60608161181757505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115611841578061182b816121a5565b915061183a9050600a8361206a565b915061181b565b60008167ffffffffffffffff81111561185c5761185c611cc1565b6040519080825280601f01601f191660200182016040528015611886576020820181803683370190505b5090505b841561143b5761189b60018361207e565b91506118a8600a866121c0565b6118b390603061218d565b60f81b8183815181106118c8576118c86121d4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350611902600a8661206a565b945061188a565b6000833b15611a93576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063150b7a029061195d9033908990889088906004016121ea565b6020604051808303816000875af1925050508015611998575060408051601f3d908101601f1916820190925261199591810190612226565b60015b611a48573d8080156119c6576040519150601f19603f3d011682016040523d82523d6000602084013e6119cb565b606091505b508051611a405760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e746572000000000000000000000000000060648201526084016106d2565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a020000000000000000000000000000000000000000000000000000000014905061143b565b506001949350505050565b828054611aaa90611fe4565b90600052602060002090601f016020900481019282611acc5760008555611b12565b82601f10611ae557805160ff1916838001178555611b12565b82800160010185558215611b12579182015b82811115611b12578251825591602001919060010190611af7565b50611b1e929150611b22565b5090565b5b80821115611b1e5760008155600101611b23565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610a1057600080fd5b600060208284031215611b7757600080fd5b8135611b8281611b37565b9392505050565b60005b83811015611ba4578181015183820152602001611b8c565b838111156110e95750506000910152565b60008151808452611bcd816020860160208601611b89565b601f01601f19169290920160200192915050565b602081526000611b826020830184611bb5565b600060208284031215611c0657600080fd5b5035919050565b6001600160a01b0381168114610a1057600080fd5b8035611c2d81611c0d565b919050565b60008060408385031215611c4557600080fd5b8235611c5081611c0d565b946020939093013593505050565b600080600060608486031215611c7357600080fd5b8335611c7e81611c0d565b92506020840135611c8e81611c0d565b929592945050506040919091013590565b60008060408385031215611cb257600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715611cfa57611cfa611cc1565b60405290565b600067ffffffffffffffff80841115611d1b57611d1b611cc1565b604051601f8501601f19908116603f01168101908282118183101715611d4357611d43611cc1565b81604052809350858152868686011115611d5c57600080fd5b858560208301376000602087830101525050509392505050565b600082601f830112611d8757600080fd5b611b8283833560208501611d00565b80358015158114611c2d57600080fd5b60008060008060008060008060006101208a8c031215611dc557600080fd5b893567ffffffffffffffff80821115611ddd57600080fd5b908b019060a0828e031215611df157600080fd5b611df9611cd7565b823582811115611e0857600080fd5b611e148f828601611d76565b825250602083013582811115611e2957600080fd5b611e358f828601611d76565b602083015250604083013582811115611e4d57600080fd5b611e598f828601611d76565b6040830152506060830135606082015260808301356080820152809b50505050611e8560208b01611c22565b9750611e9360408b01611c22565b9650611ea160608b01611c22565b955060808a0135945060a08a01359350611ebd60c08b01611d96565b9250611ecb60e08b01611d96565b91506101008a013590509295985092959850929598565b600060208284031215611ef457600080fd5b8135611b8281611c0d565b60008060408385031215611f1257600080fd5b8235611f1d81611c0d565b915061096760208401611d96565b60008060008060808587031215611f4157600080fd5b8435611f4c81611c0d565b93506020850135611f5c81611c0d565b925060408501359150606085013567ffffffffffffffff811115611f7f57600080fd5b8501601f81018713611f9057600080fd5b611f9f87823560208401611d00565b91505092959194509250565b60008060408385031215611fbe57600080fd5b8235611fc981611c0d565b91506020830135611fd981611c0d565b809150509250929050565b600181811c90821680611ff857607f821691505b6020821081141561201957634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561204f5761204f61201f565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261207957612079612054565b500490565b6000828210156120905761209061201f565b500390565b8054600090600181811c90808316806120af57607f831692505b60208084108214156120d157634e487b7160e01b600052602260045260246000fd5b8180156120e557600181146120f657612123565b60ff19861689528489019650612123565b60008881526020902060005b8681101561211b5781548b820152908501908301612102565b505084890196505b50505050505092915050565b600061213b8285612095565b835161214b818360208801611b89565b01949350505050565b60006121608284612095565b7f6d6574616461746100000000000000000000000000000000000000000000000081526008019392505050565b600082198211156121a0576121a061201f565b500190565b60006000198214156121b9576121b961201f565b5060010190565b6000826121cf576121cf612054565b500690565b634e487b7160e01b600052603260045260246000fd5b60006001600160a01b0380871683528086166020840152508360408301526080606083015261221c6080830184611bb5565b9695505050505050565b60006020828403121561223857600080fd5b8151611b8281611b3756fea2646970667358221220cb19a8ac90fbb5247db8e82c8531344781baa74579b708b1bf8097993d93df4764736f6c634300080a0033

Verified Source Code Full Match

Compiler: v0.8.10+commit.fc410830 EVM: london Optimization: Yes (2000 runs)
Ownable.sol 93 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

interface IOwnableEvents {
    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );
}

contract Ownable is IOwnableEvents {
    address public owner;
    address private nextOwner;

    // modifiers

    modifier onlyOwner() {
        require(isOwner(), "caller is not the owner.");
        _;
    }

    modifier onlyNextOwner() {
        require(isNextOwner(), "current owner must set caller as next owner.");
        _;
    }

    /**
     * @dev Initialize contract by setting transaction submitter as initial owner.
     */
    constructor(address owner_) {
        owner = owner_;
        emit OwnershipTransferred(address(0), owner);
    }

    /**
     * @dev Initiate ownership transfer by setting nextOwner.
     */
    function transferOwnership(address nextOwner_) external onlyOwner {
        require(nextOwner_ != address(0), "Next owner is the zero address.");

        nextOwner = nextOwner_;
    }

    /**
     * @dev Cancel ownership transfer by deleting nextOwner.
     */
    function cancelOwnershipTransfer() external onlyOwner {
        delete nextOwner;
    }

    /**
     * @dev Accepts ownership transfer by setting owner.
     */
    function acceptOwnership() external onlyNextOwner {
        delete nextOwner;

        owner = msg.sender;

        emit OwnershipTransferred(owner, msg.sender);
    }

    /**
     * @dev Renounce ownership by setting owner to zero address.
     */
    function renounceOwnership() external onlyOwner {
        _renounceOwnership();
    }

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return msg.sender == owner;
    }

    /**
     * @dev Returns true if the caller is the next owner.
     */
    function isNextOwner() public view returns (bool) {
        return msg.sender == nextOwner;
    }

    function _setOwner(address previousOwner, address newOwner) internal {
        owner = newOwner;
        emit OwnershipTransferred(previousOwner, owner);
    }

    function _renounceOwnership() internal {
        owner = address(0);

        emit OwnershipTransferred(owner, address(0));
    }
}
IERC165.sol 18 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

abstract contract ERC165 is IERC165 {
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override
        returns (bool)
    {
        return interfaceId == type(IERC165).interfaceId;
    }
}
IERC721.sol 89 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

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

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function approve(address to, uint256 tokenId) external;

    function getApproved(uint256 tokenId)
        external
        view
        returns (address operator);

    function setApprovalForAll(address operator, bool _approved) external;

    function isApprovedForAll(address owner, address operator)
        external
        view
        returns (bool);

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}

interface IERC721Events {
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 indexed tokenId
    );
    event Approval(
        address indexed owner,
        address indexed approved,
        uint256 indexed tokenId
    );
    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );
}

interface IERC721Metadata {
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function tokenURI(uint256 tokenId) external view returns (string memory);
}

interface IERC721Burnable is IERC721 {
    function burn(uint256 tokenId) external;
}

interface IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

interface IERC721Royalties {
    function getFeeRecipients(uint256 id)
        external
        view
        returns (address payable[] memory);

    function getFeeBps(uint256 id) external view returns (uint256[] memory);
}
IERC2309.sol 11 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

interface IERC2309 {
    event ConsecutiveTransfer(
        uint256 indexed fromTokenId,
        uint256 toTokenId,
        address indexed fromAddress,
        address indexed toAddress
    );
}
IERC2981.sol 23 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

/**
 * @title IERC2981
 * @notice Interface for the NFT Royalty Standard
 */
interface IERC2981 {
    // / bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a

    /**
     * @notice Called with the sale price to determine how much royalty
     *         is owed and to whom.
     * @param _tokenId - the NFT asset queried for royalty information
     * @param _salePrice - the sale price of the NFT asset specified by _tokenId
     * @return receiver - address of who should be sent the royalty payment
     * @return royaltyAmount - the royalty payment amount for _salePrice
     */
    function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
        external
        view
        returns (address receiver, uint256 royaltyAmount);
}
IMirrorOpenSaleV0.sol 73 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

interface IMirrorOpenSaleV0Events {
    event RegisteredSale(
        bytes32 h,
        address indexed token,
        uint256 startTokenId,
        uint256 endTokenId,
        address indexed operator,
        address indexed recipient,
        uint256 price,
        bool open,
        uint256 feePercentage
    );

    event Purchase(
        bytes32 h,
        address indexed token,
        uint256 tokenId,
        address indexed buyer,
        address indexed recipient
    );

    event Withdraw(
        bytes32 h,
        uint256 amount,
        uint256 fee,
        address indexed recipient
    );

    event OpenSale(bytes32 h);

    event CloseSale(bytes32 h);
}

interface IMirrorOpenSaleV0 {
    struct Sale {
        bool registered;
        bool open;
        uint256 sold;
        address operator;
    }

    struct SaleConfig {
        address token;
        uint256 startTokenId;
        uint256 endTokenId;
        address operator;
        address recipient;
        uint256 price;
        bool open;
        uint256 feePercentage;
    }

    function treasuryConfig() external returns (address);

    function feeRegistry() external returns (address);

    function tributaryRegistry() external returns (address);

    function sale(bytes32 h) external view returns (Sale memory);

    function register(SaleConfig calldata saleConfig_) external;

    function close(SaleConfig calldata saleConfig_) external;

    function open(SaleConfig calldata saleConfig_) external;

    function purchase(SaleConfig calldata saleConfig_, address recipient)
        external
        payable;
}
MirrorAllocatedEditionsLogic.sol 515 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

import {Ownable} from "../../lib/Ownable.sol";
import {IMirrorAllocatedEditionsLogic} from "./interface/IMirrorAllocatedEditionsLogic.sol";
import {IERC721, IERC721Events, IERC721Receiver, IERC721Metadata} from "../../lib/ERC721/interface/IERC721.sol";
import {IERC165} from "../../lib/ERC165/interface/IERC165.sol";
import {IERC2981} from "../../lib/ERC2981/interface/IERC2981.sol";
import {IMirrorOpenSaleV0} from "../../distributors/open-sale/interface/IMirrorOpenSaleV0.sol";
import {IERC2309} from "../../lib/ERC2309/interface/IERC2309.sol";

/**
 * @title MirrorAllocatedEditionsLogic
 * @author MirrorXYZ
 */
contract MirrorAllocatedEditionsLogic is
    Ownable,
    IMirrorAllocatedEditionsLogic,
    IERC721,
    IERC721Events,
    IERC165,
    IERC721Metadata,
    IERC2309,
    IERC2981
{
    /// @notice Token name
    string public override name;

    /// @notice Token symbol
    string public override symbol;

    /// @notice Token baseURI
    string public baseURI;

    /// @notice Token contentHash
    bytes32 public contentHash;

    /// @notice Token supply
    uint256 public totalSupply;

    /// @notice Burned tokens
    mapping(uint256 => bool) internal _burned;

    /// @notice Token owners
    mapping(uint256 => address) internal _owners;

    /// @notice Token balances
    mapping(address => uint256) internal _balances;

    /// @notice Token approvals
    mapping(uint256 => address) internal _tokenApprovals;

    /// @notice Token operator approvals
    mapping(address => mapping(address => bool)) internal _operatorApprovals;

    /// @notice Mirror open sale address
    address public immutable mirrorOpenSale;

    // ============ Royalty Info (ERC2981) ============

    /// @notice Account that will receive royalties
    /// @dev set address(0) to avoid royalties
    address public royaltyRecipient;

    /// @notice Royalty percentage
    uint256 public royaltyPercentage;

    /// @dev Sets zero address as owner since this is a logic contract
    /// @param mirrorOpenSale_ sale contract address
    constructor(address mirrorOpenSale_) Ownable(address(0)) {
        mirrorOpenSale = mirrorOpenSale_;
    }

    // ============ Constructor ============

    /// @dev Initialize contract
    /// @param metadata ERC721Metadata parameters
    /// @param owner_ owner of this contract
    /// @param fundingRecipient_ account that will receive funds from sales
    /// @param royaltyRecipient_ account that will receive royalties
    /// @param royaltyPercentage_ royalty percentage
    /// @param price sale listing price
    /// @param list whether to list on sale contract
    /// @param open whether to list with a closed or open sale
    /// @dev Initialize parameters, mint total suppply to owner. Reverts if called
    /// after contract deployment. If list is true, the open sale contract gets approval
    /// for all tokens.
    function initialize(
        NFTMetadata memory metadata,
        address owner_,
        address payable fundingRecipient_,
        address payable royaltyRecipient_,
        uint256 royaltyPercentage_,
        uint256 price,
        bool list,
        bool open,
        uint256 feePercentage
    ) external override {
        // ensure that this function is only callable during contract construction.
        assembly {
            if extcodesize(address()) {
                revert(0, 0)
            }
        }

        // NFT Metadata
        name = metadata.name;
        symbol = metadata.symbol;
        baseURI = metadata.baseURI;
        contentHash = metadata.contentHash;
        totalSupply = metadata.quantity;

        // Set owner
        _setOwner(address(0), owner_);

        // Royalties
        royaltyRecipient = royaltyRecipient_;
        royaltyPercentage = royaltyPercentage_;

        emit ConsecutiveTransfer(
            // fromTokenId
            0,
            // toTokenId
            metadata.quantity - 1,
            // fromAddress
            address(0),
            // toAddress
            owner_
        );

        _balances[owner_] = totalSupply;

        if (list) {
            IMirrorOpenSaleV0(mirrorOpenSale).register(
                IMirrorOpenSaleV0.SaleConfig({
                    token: address(this),
                    startTokenId: 0,
                    endTokenId: totalSupply - 1,
                    operator: owner_,
                    recipient: fundingRecipient_,
                    price: price,
                    open: open,
                    feePercentage: feePercentage
                })
            );

            _operatorApprovals[owner_][mirrorOpenSale] = true;

            emit ApprovalForAll(
                // owner
                owner_,
                // operator
                mirrorOpenSale,
                // approved
                true
            );
        }
    }

    // ============ ERC721 Methods ============

    function balanceOf(address owner_) public view override returns (uint256) {
        require(
            owner_ != address(0),
            "ERC721: balance query for the zero address"
        );

        return _balances[owner_];
    }

    function ownerOf(uint256 tokenId) public view override returns (address) {
        address _owner = _owners[tokenId];

        // if there is not owner set, and the token is not burned, the operator owns it
        if (_owner == address(0) && !_burned[tokenId]) {
            return owner;
        }

        require(_owner != address(0), "ERC721: query for nonexistent token");

        return _owner;
    }

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public override {
        //solhint-disable-next-line max-line-length
        require(
            _isApprovedOrOwner(msg.sender, tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );

        _transfer(from, to, tokenId);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public override {
        safeTransferFrom(from, to, tokenId, "");
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public override {
        require(
            _isApprovedOrOwner(msg.sender, tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );
        _safeTransfer(from, to, tokenId, _data);
    }

    function approve(address to, uint256 tokenId) public override {
        address owner_ = ownerOf(tokenId);
        require(to != owner_, "ERC721: approval to current owner");

        require(
            msg.sender == owner_ || isApprovedForAll(owner_, msg.sender),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    function getApproved(uint256 tokenId)
        public
        view
        override
        returns (address)
    {
        require(
            _exists(tokenId),
            "ERC721: approved query for nonexistent token"
        );

        return _tokenApprovals[tokenId];
    }

    function setApprovalForAll(address operator, bool approved)
        public
        override
    {
        require(operator != msg.sender, "ERC721: approve to caller");

        _operatorApprovals[msg.sender][operator] = approved;

        emit ApprovalForAll(
            // owner
            msg.sender,
            // operator
            operator,
            // approved
            approved
        );
    }

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

    // ============ ERC721 Metadata Methods ============

    function tokenURI(uint256 tokenId)
        public
        view
        override
        returns (string memory)
    {
        return string(abi.encodePacked(baseURI, _toString(tokenId)));
    }

    function contractURI() public view returns (string memory) {
        return string(abi.encodePacked(baseURI, "metadata"));
    }

    function getContentHash(uint256) public view returns (bytes32) {
        return contentHash;
    }

    // ============ Burn Method ============

    function burn(uint256 tokenId) public {
        require(
            _isApprovedOrOwner(msg.sender, tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );

        _burn(tokenId);
    }

    // ============ ERC2981 Methods ============

    /// @notice Get royalty info
    function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
        external
        view
        override
        returns (address receiver, uint256 royaltyAmount)
    {
        receiver = royaltyRecipient;
        royaltyAmount = (_salePrice * royaltyPercentage) / 10_000;
    }

    function setRoyaltyInfo(
        address payable royaltyRecipient_,
        uint256 royaltyPercentage_
    ) external override onlyOwner {
        royaltyRecipient = royaltyRecipient_;
        royaltyPercentage = royaltyPercentage_;

        emit RoyaltyChange(
            // oldRoyaltyRecipient
            royaltyRecipient,
            // oldRoyaltyPercentage
            royaltyPercentage,
            // newRoyaltyRecipient
            royaltyRecipient_,
            // newRoyaltyPercentage
            royaltyPercentage_
        );
    }

    // ============ IERC165 Method ============

    function supportsInterface(bytes4 interfaceId)
        public
        pure
        override
        returns (bool)
    {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            interfaceId == type(IERC165).interfaceId ||
            interfaceId == type(IERC2981).interfaceId;
    }

    // ============ Internal Methods ============

    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal {
        require(
            ownerOf(tokenId) == from,
            "ERC721: transfer of token that is not own"
        );

        require(
            to != address(0),
            "ERC721: transfer to the zero address (use burn instead)"
        );

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;

        _owners[tokenId] = to;
        _balances[to] += 1;

        emit Transfer(
            // from
            from,
            // to
            to,
            // tokenId
            tokenId
        );
    }

    function _exists(uint256 tokenId) internal view returns (bool) {
        return !_burned[tokenId];
    }

    function _burn(uint256 tokenId) internal {
        address owner_ = ownerOf(tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner_] -= 1;

        delete _owners[tokenId];

        _burned[tokenId] = true;

        emit Transfer(
            // from
            owner_,
            // to
            address(0),
            // tokenId
            tokenId
        );
    }

    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal {
        _transfer(from, to, tokenId);
        require(
            _checkOnERC721Received(from, to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    function _isApprovedOrOwner(address spender, uint256 tokenId)
        internal
        view
        returns (bool)
    {
        require(_exists(tokenId), "ERC721: query for nonexistent token");

        address owner_ = ownerOf(tokenId);

        return (spender == owner_ ||
            getApproved(tokenId) == spender ||
            isApprovedForAll(owner_, spender));
    }

    function _approve(address to, uint256 tokenId) internal {
        _tokenApprovals[tokenId] = to;

        emit Approval(
            // owner
            ownerOf(tokenId),
            // approved
            to,
            // tokenId
            tokenId
        );
    }

    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (_isContract(to)) {
            try
                IERC721Receiver(to).onERC721Received(
                    msg.sender,
                    from,
                    tokenId,
                    _data
                )
            returns (bytes4 retval) {
                return retval == IERC721Receiver(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert(
                        "ERC721: transfer to non ERC721Receiver implementer"
                    );
                } else {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7f6a1666fac8ecff5dd467d0938069bc221ea9e0/contracts/utils/Address.sol
    function _isContract(address account) internal view returns (bool) {
        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    // From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol
    function _toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        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(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
}
IMirrorAllocatedEditionsLogic.sol 36 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;

interface IMirrorAllocatedEditionsLogic {
    event RoyaltyChange(
        address indexed oldRoyaltyRecipient,
        uint256 oldRoyaltyPercentage,
        address indexed newRoyaltyRecipient,
        uint256 newRoyaltyPercentage
    );

    struct NFTMetadata {
        string name;
        string symbol;
        string baseURI;
        bytes32 contentHash;
        uint256 quantity;
    }

    function initialize(
        NFTMetadata memory metadata,
        address operator_,
        address payable fundingRecipient_,
        address payable royaltyRecipient_,
        uint256 royaltyPercentage_,
        uint256 price,
        bool list,
        bool open,
        uint256 feePercentage
    ) external;

    function setRoyaltyInfo(
        address payable royaltyRecipient_,
        uint256 royaltyPercentage_
    ) external;
}

Read Contract

balanceOf 0x70a08231 → uint256
baseURI 0x6c0360eb → string
contentHash 0x646c2e33 → bytes32
contractURI 0xe8a3d485 → string
getApproved 0x081812fc → address
getContentHash 0xffbdc8cb → bytes32
isApprovedForAll 0xe985e9c5 → bool
isNextOwner 0xed459df2 → bool
isOwner 0x8f32d59b → bool
mirrorOpenSale 0x8b6854a2 → address
name 0x06fdde03 → string
owner 0x8da5cb5b → address
ownerOf 0x6352211e → address
royaltyInfo 0x2a55205a → address, uint256
royaltyPercentage 0x8a71bb2d → uint256
royaltyRecipient 0x4c00de82 → address
supportsInterface 0x01ffc9a7 → bool
symbol 0x95d89b41 → string
tokenURI 0xc87b56dd → string
totalSupply 0x18160ddd → uint256

Write Contract 12 functions

These functions modify contract state and require a wallet transaction to execute.

acceptOwnership 0x79ba5097
No parameters
approve 0x095ea7b3
address to
uint256 tokenId
burn 0x42966c68
uint256 tokenId
cancelOwnershipTransfer 0x23452b9c
No parameters
initialize 0x71bbf622
tuple metadata
address owner_
address fundingRecipient_
address royaltyRecipient_
uint256 royaltyPercentage_
uint256 price
bool list
bool open
uint256 feePercentage
renounceOwnership 0x715018a6
No parameters
safeTransferFrom 0x42842e0e
address from
address to
uint256 tokenId
safeTransferFrom 0xb88d4fde
address from
address to
uint256 tokenId
bytes _data
setApprovalForAll 0xa22cb465
address operator
bool approved
setRoyaltyInfo 0xe2e784d5
address royaltyRecipient_
uint256 royaltyPercentage_
transferFrom 0x23b872dd
address from
address to
uint256 tokenId
transferOwnership 0xf2fde38b
address nextOwner_

Recent Transactions

This address has 1 on-chain transactions, but only 0.7% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →