// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;
////////////////////////////////////////////////////////////////////////////////
/// ░▒█▀▀▄░█▀▀█░▒█▀▀█░█▀▀▄░▒█▀▄▀█░▄█░░▒█▄░▒█░▒█▀▀▀ ///
/// ░▒█░▒█░█▄▀█░▒█▄▄█▒█▄▄█░▒█▒█▒█░░█▒░▒█▒█▒█░▒█▀▀▀ ///
/// ░▒█▄▄█░█▄▄█░▒█░░░▒█░▒█░▒█░░▒█░▄█▄░▒█░░▀█░▒█▄▄▄ ///
////////////////////////////////////////////////////////////////////////////////
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC2981} from "./interfaces/IERC2981.sol";
import {IOpenSeaProxyRegistry} from "./interfaces/IOpenSeaProxyRegistry.sol";
import {IDopamineSmiley} from "./interfaces/IDopamineSmiley.sol";
import "./SmileyErrors.sol";
/// @title Dopamine's original smiley, designed by artist @evrlstng
contract DopamineSmiley is IDopamineSmiley, IERC721, IERC721Metadata, IERC2981 {
/// @notice The name of this NFT collection.
string public constant name = "Dopamine Smiley";
/// @notice The abbreviated name of this NFT collection.
string public constant symbol = "SMILEY";
/// @notice The total number of NFTs in circulation.
uint256 public constant totalSupply = 1;
/// @notice The URI the NFT points to for metadata resolution.
string public baseURI = "https://api.dopamine.xyz/smiley/metadata/";
/// @notice Gets the number of NFTs owned by an address.
/// @dev This implementation does not throw for zero-address queries.
mapping(address => uint256) public balanceOf;
/// @notice The address administering minting and metadata settings.
address public owner;
/// @notice Gets the assigned owner of an address.
/// @dev This implementation does not throw for NFTs of the zero address.
mapping(uint256 => address) public ownerOf;
/// @notice Gets the approved address for an NFT.
/// @dev This implementation does not throw for zero-address queries.
mapping(uint256 => address) public getApproved;
/// @notice The OS registry address - allowlisted for gasless OS approvals.
IOpenSeaProxyRegistry public proxyRegistry;
/// @dev Checks for an owner if an address is an authorized operator.
mapping(address => mapping(address => bool)) internal _operatorApprovals;
// EIP-2981 collection-wide royalties information.
RoyaltiesInfo internal _royaltiesInfo;
// EIP-165 identifiers for all supported interfaces.
bytes4 private constant _ERC165_INTERFACE_ID = 0x01ffc9a7;
bytes4 private constant _ERC721_INTERFACE_ID = 0x80ac58cd;
bytes4 private constant _ERC721_METADATA_INTERFACE_ID = 0x5b5e139f;
bytes4 private constant _ERC2981_METADATA_INTERFACE_ID = 0x2a55205a;
/// @notice Restricts a function call to address `owner`.
modifier onlyOwner() {
if (msg.sender != owner) {
revert OwnerOnly();
}
_;
}
/// @notice Creates Dopamine's original smiley.
/// @param proxyRegistry_ The OpenSea proxy registry address.
/// @param reserve_ Address to which EIP-2981 royalties direct to.
/// @param royalties_ Royalties sent to `reserve_` on sales, in bips.
constructor(
IOpenSeaProxyRegistry proxyRegistry_,
address reserve_,
uint96 royalties_
) {
owner = msg.sender;
proxyRegistry = proxyRegistry_;
setRoyalties(reserve_, royalties_);
balanceOf[owner] = 1;
ownerOf[1] = owner;
emit Transfer(address(0), owner, 1);
}
/// @notice Retrieves a URI describing the overall contract-level metadata.
/// @return A string URI pointing to the smiley contract metadata.
function contractURI() external view returns (string memory) {
return string(abi.encodePacked(baseURI, "contract"));
}
/// @notice Sets the base URI to `newBaseURI`.
/// @param newBaseURI The new base metadata URI to set for the collection.
/// @dev This function is only callable by the owner address.
function setBaseURI(string calldata newBaseURI) external onlyOwner {
baseURI = newBaseURI;
emit BaseURISet(newBaseURI);
}
/// @notice Sets the owner address to `newOwner`.
/// @param newOwner The address of the new owner.
/// @dev This function is only callable by the owner address.
function setOwner(address newOwner) external onlyOwner {
owner = newOwner;
emit OwnerChanged(owner, newOwner);
}
/// @notice Transfers NFT of id `id` from address `from` to address `to`,
/// with safety checks ensuring `to` is capable of receiving the NFT.
/// @dev Safety checks are only performed if `to` is a smart contract.
/// @param from The existing owner address of the NFT to be transferred.
/// @param to The address of the new owner of the NFT to be transferred.
/// @param id The id of the NFT being transferred.
/// @param data Additional transfer data to pass to the receiving contract.
function safeTransferFrom(
address from,
address to,
uint256 id,
bytes memory data
) external {
transferFrom(from, to, id);
if (
to.code.length != 0 &&
IERC721Receiver(to).onERC721Received(msg.sender, from, id, data)
!=
IERC721Receiver.onERC721Received.selector
) {
revert SafeTransferUnsupported();
}
}
/// @notice Transfers NFT of id `id` from address `from` to address `to`,
/// with safety checks ensuring `to` is capable of receiving the NFT.
/// @dev Safety checks are only performed if `to` is a smart contract.
/// @param from The existing owner address of the NFT to be transferred.
/// @param to The address of the new owner of the NFT to be transferred.
/// @param id The id of the NFT being transferred.
function safeTransferFrom(
address from,
address to,
uint256 id
) external {
transferFrom(from, to, id);
if (
to.code.length != 0 &&
IERC721Receiver(to).onERC721Received(msg.sender, from, id, "")
!=
IERC721Receiver.onERC721Received.selector
) {
revert SafeTransferUnsupported();
}
}
/// @inheritdoc IERC2981
function royaltyInfo(
uint256,
uint256 salePrice
) external view returns (address, uint256) {
RoyaltiesInfo memory royaltiesInfo = _royaltiesInfo;
uint256 royalties = (salePrice * royaltiesInfo.royalties) / 10000;
return (royaltiesInfo.receiver, royalties);
}
/// @notice Sets approved address of NFT of id `id` to address `approved`.
/// @param approved The new approved address for the NFT.
/// @param id The id of the NFT to approve.
function approve(address approved, uint256 id) external {
address owner = ownerOf[id];
if (msg.sender != owner && !_operatorApprovals[owner][msg.sender]) {
revert SenderUnauthorized();
}
getApproved[id] = approved;
emit Approval(owner, approved, id);
}
/// @notice Checks if `operator` is an authorized operator for `owner`.
/// @param owner The address of the owner.
/// @param operator The address for the owner's operator.
/// @return True if `operator` is approved operator of `owner`, else false.
function isApprovedForAll(address owner, address operator)
external
view
returns (bool)
{
return
proxyRegistry.proxies(owner) == operator ||
_operatorApprovals[owner][operator];
}
/// @notice Sets the operator for `msg.sender` to `operator`.
/// @param operator The operator address that will manage the sender's NFTs.
/// @param approved Whether operator is allowed to operate on sender's NFTs.
function setApprovalForAll(address operator, bool approved) external {
_operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
/// @notice Returns the metadata URI associated with the NFT of id `id`.
/// @param id The id of the NFT being queried.
/// @return A string URI pointing to the metadata of the queried NFT.
function tokenURI(uint256 id) external view returns (string memory) {
if (ownerOf[id] == address(0)) {
revert TokenNonExistent();
}
return string(abi.encodePacked(baseURI, _toString(id)));
}
/// @notice Checks if interface of identifier `id` is supported.
/// @param id The EIP-165 interface identifier.
/// @return True if interface id `id` is supported, false otherwise.
function supportsInterface(bytes4 id) external pure returns (bool) {
return
id == _ERC165_INTERFACE_ID ||
id == _ERC721_INTERFACE_ID ||
id == _ERC721_METADATA_INTERFACE_ID ||
id == _ERC2981_METADATA_INTERFACE_ID;
}
/// @notice Sets EIP-2981 royalty information for NFTs in the collection.
/// @param receiver Address which will receive token royalties.
/// @param royalties Amount of royalties to be sent, in bips.
function setRoyalties(
address receiver,
uint96 royalties
) public onlyOwner {
if (royalties > 10000) {
revert RoyaltiesTooHigh();
}
if (receiver == address(0)) {
revert ReceiverInvalid();
}
_royaltiesInfo = RoyaltiesInfo(receiver, royalties);
}
/// @notice Transfers NFT of id `id` from address `from` to address `to`,
/// without performing any safety checks.
/// @dev Existence of an NFT is inferred by having a non-zero owner address.
/// Transfers clear owner approvals, but `Approval` events are omitted.
/// @param from The existing owner address of the NFT to be transferred.
/// @param to The address of the new owner of the NFT to be transferred.
/// @param id The id of the NFT being transferred.
function transferFrom(
address from,
address to,
uint256 id
) public {
if (from != ownerOf[id]) {
revert OwnerInvalid();
}
if (
msg.sender != from &&
msg.sender != getApproved[id] &&
!_operatorApprovals[from][msg.sender]
) {
revert SenderUnauthorized();
}
if (to == address(0)) {
revert ReceiverInvalid();
}
delete getApproved[id];
unchecked {
balanceOf[from]--;
balanceOf[to]++;
}
ownerOf[id] = to;
emit Transfer(from, to, id);
}
/// @dev Converts a uint256 into a string.
/// @param value A positive uint256 value.
function _toString(uint256 value) internal pure returns (string memory) {
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);
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;
////////////////////////////////////////////////////////////////////////////////
/// ░▒█▀▀▄░█▀▀█░▒█▀▀█░█▀▀▄░▒█▀▄▀█░▄█░░▒█▄░▒█░▒█▀▀▀ ///
/// ░▒█░▒█░█▄▀█░▒█▄▄█▒█▄▄█░▒█▒█▒█░░█▒░▒█▒█▒█░▒█▀▀▀ ///
/// ░▒█▄▄█░█▄▄█░▒█░░░▒█░▒█░▒█░░▒█░▄█▄░▒█░░▀█░▒█▄▄▄ ///
////////////////////////////////////////////////////////////////////////////////
import "./IDopamineSmileyEvents.sol";
/// @title Dopamine ERC-721 smiley interface
interface IDopamineSmiley is IDopamineSmileyEvents {
/// @notice Gets the owner address, which controls metadata management.
function owner() external view returns (address);
/// @notice Retrieves a URI describing the overall contract-level metadata.
/// @return A string URI pointing to the tab contract metadata.
function contractURI() external view returns (string memory);
/// @notice Sets the base URI to `newBaseURI`.
/// @param newBaseURI The new base metadata URI to set for the collection.
/// @dev This function is only callable by the owner address.
function setBaseURI(string calldata newBaseURI) external;
/// @notice Sets the owner address to `newOwner`.
/// @param newOwner The address of the new owner.
/// @dev This function is only callable by the owner address.
function setOwner(address newOwner) external;
/// @notice Sets the EIP-2981 royalties for the NFT collection.
/// @param receiver Address to which royalties will be received.
/// @param royalties The amount of royalties to receive, in bips.
/// @dev This function is only callable by the owner address.
function setRoyalties(address receiver, uint96 royalties) external;
}
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.13;
////////////////////////////////////////////////////////////////////////////////
/// ░▒█▀▀▄░█▀▀█░▒█▀▀█░█▀▀▄░▒█▀▄▀█░▄█░░▒█▄░▒█░▒█▀▀▀ ///
/// ░▒█░▒█░█▄▀█░▒█▄▄█▒█▄▄█░▒█▒█▒█░░█▒░▒█▒█▒█░▒█▀▀▀ ///
/// ░▒█▄▄█░█▄▄█░▒█░░░▒█░▒█░▒█░░▒█░▄█▄░▒█░░▀█░▒█▄▄▄ ///
////////////////////////////////////////////////////////////////////////////////
/// @title Dopamine ERC-721 smiley events interface
interface IDopamineSmileyEvents {
/// @notice Emits when the Dopamine tab base URI is set to `baseUri`.
/// @param baseURI The base URI of the tab contract, as a string.
event BaseURISet(string baseURI);
/// @notice Emits when owner is changed from `oldOwner` to `newOwner`.
/// @param oldOwner The address of the previous owner.
/// @param newOwner The address of the new owner.
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;
////////////////////////////////////////////////////////////////////////////////
/// ░▒█▀▀▄░█▀▀█░▒█▀▀█░█▀▀▄░▒█▀▄▀█░▄█░░▒█▄░▒█░▒█▀▀▀ ///
/// ░▒█░▒█░█▄▀█░▒█▄▄█▒█▄▄█░▒█▒█▒█░░█▒░▒█▒█▒█░▒█▀▀▀ ///
/// ░▒█▄▄█░█▄▄█░▒█░░░▒█░▒█░▒█░░▒█░▄█▄░▒█░░▀█░▒█▄▄▄ ///
////////////////////////////////////////////////////////////////////////////////
/// @title Interface for the ERC-2981 royalties standard.
interface IERC2981 {
/// @notice RoyaltiesInfo stores token royalties information.
struct RoyaltiesInfo {
/// @notice The address to which royalties will be directed.
address receiver;
/// @notice The royalties amount, in bips.
uint96 royalties;
}
/// @notice Returns the address to which royalties are received along with
/// the royalties amount to be paid to them for a given sale price.
/// @param id The id of the NFT being queried for royalties information.
/// @param salePrice The sale price of the NFT, in some unit of exchange.
/// @return receiver The address of the royalties receiver.
/// @return royaltyAmount The royalty payment to be made given `salePrice`.
function royaltyInfo(
uint256 id,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - 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 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - 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 tokenId,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;
////////////////////////////////////////////////////////////////////////////////
/// ░▒█▀▀▄░█▀▀█░▒█▀▀█░█▀▀▄░▒█▀▄▀█░▄█░░▒█▄░▒█░▒█▀▀▀ ///
/// ░▒█░▒█░█▄▀█░▒█▄▄█▒█▄▄█░▒█▒█▒█░░█▒░▒█▒█▒█░▒█▀▀▀ ///
/// ░▒█▄▄█░█▄▄█░▒█░░░▒█░▒█░▒█░░▒█░▄█▄░▒█░░▀█░▒█▄▄▄ ///
////////////////////////////////////////////////////////////////////////////////
/// @title OpenSea proxy registry interface
interface IOpenSeaProxyRegistry {
/// @notice Returns the proxy account associated with an OS user address.
function proxies(address) external view returns (address);
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;
////////////////////////////////////////////////////////////////////////////////
/// ░▒█▀▀▄░█▀▀█░▒█▀▀█░█▀▀▄░▒█▀▄▀█░▄█░░▒█▄░▒█░▒█▀▀▀ ///
/// ░▒█░▒█░█▄▀█░▒█▄▄█▒█▄▄█░▒█▒█▒█░░█▒░▒█▒█▒█░▒█▀▀▀ ///
/// ░▒█▄▄█░█▄▄█░▒█░░░▒█░▒█░▒█░░▒█░▄█▄░▒█░░▀█░▒█▄▄▄ ///
////////////////////////////////////////////////////////////////////////////////
/// @notice Originating address does not own the NFT.
error OwnerInvalid();
/// @notice Function callable only by the owner.
error OwnerOnly();
/// @notice Receiving address cannot be the zero address.
error ReceiverInvalid();
/// @notice Royalties are set too high.
error RoyaltiesTooHigh();
/// @notice Receiving contract does not implement the EIP-721 wallet interface.
error SafeTransferUnsupported();
/// @notice Sender is not NFT owner, approved address, or owner operator.
error SenderUnauthorized();
/// @notice NFT does not exist.
error TokenNonExistent();
{
"compilationTarget": {
"src/DopamineSmiley.sol": "DopamineSmiley"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IOpenSeaProxyRegistry","name":"proxyRegistry_","type":"address"},{"internalType":"address","name":"reserve_","type":"address"},{"internalType":"uint96","name":"royalties_","type":"uint96"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"OwnerInvalid","type":"error"},{"inputs":[],"name":"OwnerOnly","type":"error"},{"inputs":[],"name":"ReceiverInvalid","type":"error"},{"inputs":[],"name":"RoyaltiesTooHigh","type":"error"},{"inputs":[],"name":"SafeTransferUnsupported","type":"error"},{"inputs":[],"name":"SenderUnauthorized","type":"error"},{"inputs":[],"name":"TokenNonExistent","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxyRegistry","outputs":[{"internalType":"contract IOpenSeaProxyRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"royalties","type":"uint96"}],"name":"setRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"id","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]