编译器
0.8.20+commit.a1b79de6
文件 1 的 30:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 30:ContractMetadata.sol
pragma solidity ^0.8.0;
import "./interface/IContractMetadata.sol";
abstract contract ContractMetadata is IContractMetadata {
string public override contractURI;
function setContractURI(string memory _uri) external override {
if (!_canSetContractURI()) {
revert("Not authorized");
}
_setupContractURI(_uri);
}
function _setupContractURI(string memory _uri) internal {
string memory prevURI = contractURI;
contractURI = _uri;
emit ContractURIUpdated(prevURI, _uri);
}
function _canSetContractURI() internal view virtual returns (bool);
}
文件 3 的 30:ERC165.sol
pragma solidity ^0.8.0;
import "./interface/IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 4 的 30:ERC721ArtistProduct.sol
pragma solidity ^0.8.4;
import "./interface/IERC721ArtistProduct.sol";
import "@thirdweb-dev/contracts/eip/ERC165.sol";
import "@thirdweb-dev/contracts/eip/interface/IERC721Receiver.sol";
import "@thirdweb-dev/contracts/external-deps/openzeppelin/utils/Context.sol";
import "@thirdweb-dev/contracts/lib/TWStrings.sol";
import "@thirdweb-dev/contracts/lib/TWAddress.sol";
contract ERC721ArtistProduct is Context, ERC165, IERC721ArtistProduct {
using TWAddress for address;
using TWStrings for uint256;
uint256 constant PRODUCT_OFFSET_MIN = 1;
uint256 constant PRODUCT_OFFSET_MAX = 19;
uint256 private _productOffset;
uint256 internal _mintCounter;
uint256 internal _burnCounter;
string private _name;
string private _symbol;
mapping(uint256 => TokenOwnership) internal _ownerships;
mapping(uint256 => ProductData) private _productData;
mapping(uint256 => address) private _productArtist;
mapping(address => mapping(uint256 => uint256)) private _productBalance;
mapping(address => AddressData) private _addressData;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_, uint256 offset_) {
_name = name_;
_symbol = symbol_;
_setProductOffset(offset_);
}
function totalSupply() public view override returns (uint256) {
unchecked {
return _mintCounter - _burnCounter;
}
}
function productSupply(uint256 productId) public view returns (uint256) {
ProductData memory product = _productData[productId];
unchecked {
return product.numberMinted - product.numberBurned;
}
}
function _totalMinted() internal view returns (uint256) {
return _mintCounter;
}
function _totalBurned() internal view returns (uint256) {
return _burnCounter;
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function productBalanceOf(
address owner,
uint256 productId
) public view returns (uint256) {
if (owner == address(0)) revert BalanceQueryForZeroAddress();
return _productBalance[owner][productId];
}
function balanceOf(address owner) public view override returns (uint256) {
if (owner == address(0)) revert BalanceQueryForZeroAddress();
return uint256(_addressData[owner].balance);
}
function _getAddressData(address owner) internal view returns (AddressData memory) {
return _addressData[owner];
}
function _numberMinted(address owner) internal view returns (uint256) {
return uint256(_addressData[owner].numberMinted);
}
function _numberBurned(address owner) internal view returns (uint256) {
return uint256(_addressData[owner].numberBurned);
}
function _getAux(address owner) internal view returns (uint64) {
return _addressData[owner].aux;
}
function _setAux(address owner, uint64 aux) internal {
_addressData[owner].aux = aux;
}
function _getArtist(uint256 _productId) internal view returns (address) {
return _productArtist[_productId];
}
function _setArtist(uint256 _productId, address _artist) internal {
_productArtist[_productId] = _artist;
}
function _getProduct(uint256 _productId) internal view returns (ProductData memory) {
return _productData[_productId];
}
function _getProductOffset() internal view returns (uint256 _offset) {
uint256 offset = _productOffset;
while (offset % 10 == 0) {
offset /= 10;
++_offset;
}
}
function _setProductOffset(uint256 _offset) internal {
if (_mintCounter > 0) revert ProductOffsetAfterMinting();
if (_offset < PRODUCT_OFFSET_MIN || _offset > PRODUCT_OFFSET_MAX) {
revert ProductOffsetOutsideRange(
_offset,
PRODUCT_OFFSET_MIN,
PRODUCT_OFFSET_MAX
);
}
_productOffset = 10 ** _offset;
}
function _getProductMaxId() internal view returns (uint256) {
return type(uint256).max / _productOffset - _productOffset;
}
function _getProductMaxQuantity() internal view returns (uint64) {
return uint64(_productOffset - 1);
}
function _getProductQuantity(uint256 _productId) internal view returns (uint64) {
return _productData[_productId].quantity;
}
function _setProductQuantity(uint256 _productId, uint64 _quantity) internal {
if (_getProductMaxId() < _productId)
revert ProductIdExceedsOffsetMaximum(_productId, _getProductMaxId());
if (_getProductMaxQuantity() < _quantity)
revert ProductQuantityExceedsOffsetMaximum(
_quantity,
_getProductMaxQuantity()
);
ProductData storage product = _productData[_productId];
uint64 oldQuantity = product.quantity;
if (_quantity < product.numberMinted) revert ProductMintsExceedsQuantity();
product.quantity = _quantity;
emit ProductQuantityUpdated(_productId, oldQuantity, _quantity);
}
function _getProductMinted(uint256 _productId) internal view returns (uint64) {
return _productData[_productId].numberMinted;
}
function _getProductBurned(uint256 _productId) internal view returns (uint64) {
return _productData[_productId].numberBurned;
}
function _getProductLocked(uint256 _productId) internal view returns (bool) {
return _productData[_productId].locked;
}
function _setProductLocked(uint256 _productId, bool _locked) internal {
ProductData storage product = _productData[_productId];
if (product.quantity == 0) revert ProductNotConfigured();
product.locked = _locked;
emit ProductMintingRestricted(_productId, _locked);
}
function _getProductFrozen(uint256 _productId) internal view returns (bool) {
return _productData[_productId].frozen;
}
function _setProductFrozen(uint256 _productId, bool _frozen) internal {
ProductData storage product = _productData[_productId];
if (product.quantity == 0) revert ProductNotConfigured();
product.frozen = _frozen;
emit ProductTransfersRestricted(_productId, _frozen);
}
function _getProductBurnable(uint256 _productId) internal view returns (bool) {
return _productData[_productId].burnable;
}
function _setProductBurnable(uint256 _productId, bool _burnable) internal {
ProductData storage product = _productData[_productId];
if (product.quantity == 0) revert ProductNotConfigured();
product.burnable = _burnable;
emit ProductBurningRestricted(_productId, !_burnable);
}
function _getProductUniqueMetadata(uint256 _productId) internal view returns (bool) {
return _productData[_productId].uniqueMetadata;
}
function _setProductUniqueMetadata(uint256 _productId, bool _isUnique) internal {
ProductData storage product = _productData[_productId];
if (product.quantity == 0) revert ProductNotConfigured();
product.uniqueMetadata = _isUnique;
emit ProductUniqueTokenMetadata(_productId, _isUnique);
}
function _getProductId(uint256 _tokenId) internal view returns (uint256 _productId) {
if (_tokenId < _productOffset) revert ProductQueryForImpossibleToken();
_productId = _tokenId / _productOffset;
if (_productData[_productId].quantity == 0)
revert ProductQueryForNonexistantToken();
}
function _getNextTokenIds(
uint256 _productId,
uint256 _quantity
) internal view returns (uint256 startTokenId, uint256 finalTokenId) {
ProductData memory product = _productData[_productId];
if (product.quantity == 0) revert ProductNotConfigured();
if (product.quantity < product.numberMinted + _quantity)
revert ProductMintsExceedsQuantity();
startTokenId = _productId * _productOffset + product.numberMinted + 1;
finalTokenId = startTokenId + _quantity - 1;
}
function _getPrevTokenId(uint256 _productId) internal view returns (uint256) {
return _productId * _productOffset + _getProductMinted(_productId);
}
function _getMinTokenId(uint256 _productId) internal view returns (uint256) {
return _productId * _productOffset + 1;
}
function _getMaxTokenId(uint256 _productId) internal view returns (uint256) {
return _productId * _productOffset + _getProductQuantity(_productId) + 1;
}
function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) {
uint256 curr = tokenId;
uint256 productId = _getProductId(tokenId);
uint256 minTokenId = _getMinTokenId(productId);
unchecked {
if (minTokenId <= curr)
if (curr <= _getPrevTokenId(productId)) {
TokenOwnership memory ownership = _ownerships[curr];
if (!ownership.burned) {
if (ownership.addr != address(0)) {
return ownership;
}
while (minTokenId < curr) {
curr--;
ownership = _ownerships[curr];
if (ownership.addr != address(0)) {
return ownership;
}
}
}
}
}
revert OwnerQueryForNonexistentToken();
}
function ownerOf(uint256 tokenId) public view override returns (address) {
return _ownershipOf(tokenId).addr;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(
uint256 tokenId
) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
return
bytes(baseURI).length != 0
? string(abi.encodePacked(baseURI, tokenId.toString()))
: "";
}
function _baseURI() internal view virtual returns (string memory) {
return "";
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721ArtistProduct.ownerOf(tokenId);
if (to == owner) revert ApprovalToCurrentOwner();
if (_msgSender() != owner)
if (!isApprovedForAll(owner, _msgSender())) {
revert ApprovalCallerNotOwnerNorApproved();
}
_approve(to, tokenId, owner);
}
function getApproved(uint256 tokenId) public view override returns (address) {
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
if (operator == _msgSender()) revert ApproveToCaller();
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(
address owner,
address operator
) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
_transfer(from, to, tokenId);
if (to.isContract())
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
function _exists(uint256 tokenId) internal view returns (bool) {
uint256 productId = _getProductId(tokenId);
return
_getMinTokenId(productId) <= tokenId &&
tokenId <= _getPrevTokenId(productId) &&
!_ownerships[tokenId].burned;
}
function _safeMint(
address to,
uint256 productId,
uint256 quantity
) internal returns (uint256 startTokenId, uint256 finalTokenId) {
return _safeMint(to, productId, quantity, "");
}
function _safeMint(
address to,
uint256 productId,
uint256 quantity,
bytes memory _data
) internal returns (uint256 startTokenId, uint256 finalTokenId) {
uint256 startCount = _mintCounter;
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
if (_getProductLocked(productId)) revert ProductMintingDisabled();
(startTokenId, finalTokenId) = _getNextTokenIds(productId, quantity);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
unchecked {
_addressData[to].balance += uint64(quantity);
_addressData[to].numberMinted += uint64(quantity);
_ownerships[startTokenId].addr = to;
_ownerships[startTokenId].startTimestamp = uint64(block.timestamp);
_productBalance[to][productId] += quantity;
uint256 currTokenId = startTokenId;
finalTokenId++;
if (to.isContract()) {
do {
if (_productArtist[productId] != address(0)) {
emit Transfer(address(0), _productArtist[productId], currTokenId);
emit Transfer(_productArtist[productId], to, currTokenId);
} else {
emit Transfer(address(0), to, currTokenId);
}
if (
!_checkContractOnERC721Received(
address(0),
to,
currTokenId++,
_data
)
) {
revert TransferToNonERC721ReceiverImplementer();
}
} while (currTokenId < finalTokenId);
if (_mintCounter != startCount) revert();
} else {
do {
if (_productArtist[productId] != address(0)) {
emit Transfer(address(0), _productArtist[productId], currTokenId);
emit Transfer(_productArtist[productId], to, currTokenId);
} else {
emit Transfer(address(0), to, currTokenId);
}
++currTokenId;
} while (currTokenId < finalTokenId);
}
_mintCounter += quantity;
_productData[productId].numberMinted += uint64(quantity);
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
function _mint(
address to,
uint256 productId,
uint256 quantity
) internal returns (uint256 startTokenId, uint256 finalTokenId) {
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
if (_getProductLocked(productId)) revert ProductMintingDisabled();
(startTokenId, finalTokenId) = _getNextTokenIds(productId, quantity);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
unchecked {
_addressData[to].balance += uint64(quantity);
_addressData[to].numberMinted += uint64(quantity);
_ownerships[startTokenId].addr = to;
_ownerships[startTokenId].startTimestamp = uint64(block.timestamp);
_productBalance[to][productId] += quantity;
uint256 currTokenId = startTokenId;
finalTokenId++;
do {
if (_productArtist[productId] != address(0)) {
emit Transfer(address(0), _productArtist[productId], currTokenId);
emit Transfer(_productArtist[productId], to, currTokenId);
} else {
emit Transfer(address(0), to, currTokenId);
}
++currTokenId;
} while (currTokenId < finalTokenId);
_mintCounter += quantity;
_productData[productId].numberMinted += uint64(quantity);
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
function _transfer(address from, address to, uint256 tokenId) private {
TokenOwnership memory prevOwnership = _ownershipOf(tokenId);
if (prevOwnership.addr != from) revert TransferFromIncorrectOwner();
bool isApprovedOrOwner = (_msgSender() == from ||
isApprovedForAll(from, _msgSender()) ||
getApproved(tokenId) == _msgSender());
if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
if (to == address(0)) revert TransferToZeroAddress();
uint256 productId = _getProductId(tokenId);
if (_getProductFrozen(productId)) revert ProductTransfersDisabled();
_beforeTokenTransfers(from, to, tokenId, 1);
_approve(address(0), tokenId, from);
unchecked {
_addressData[from].balance -= 1;
_addressData[to].balance += 1;
_productBalance[from][productId] -= 1;
_productBalance[to][productId] += 1;
TokenOwnership storage currSlot = _ownerships[tokenId];
currSlot.addr = to;
currSlot.startTimestamp = uint64(block.timestamp);
TokenOwnership storage nextSlot = _ownerships[tokenId + 1];
if (nextSlot.addr == address(0)) {
if (tokenId != _getPrevTokenId(productId)) {
nextSlot.addr = from;
nextSlot.startTimestamp = prevOwnership.startTimestamp;
}
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
TokenOwnership memory prevOwnership = _ownershipOf(tokenId);
address from = prevOwnership.addr;
if (approvalCheck) {
bool isApprovedOrOwner = (_msgSender() == from ||
isApprovedForAll(from, _msgSender()) ||
getApproved(tokenId) == _msgSender());
if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
}
uint256 productId = _getProductId(tokenId);
if (!_getProductBurnable(productId)) revert ProductBurningDisabled();
_beforeTokenTransfers(from, address(0), tokenId, 1);
_approve(address(0), tokenId, from);
unchecked {
AddressData storage addressData = _addressData[from];
addressData.balance -= 1;
addressData.numberBurned += 1;
TokenOwnership storage currSlot = _ownerships[tokenId];
currSlot.addr = from;
currSlot.startTimestamp = uint64(block.timestamp);
currSlot.burned = true;
_productBalance[from][productId] -= 1;
TokenOwnership storage nextSlot = _ownerships[tokenId + 1];
if (nextSlot.addr == address(0)) {
if (tokenId != _getPrevTokenId(productId)) {
nextSlot.addr = from;
nextSlot.startTimestamp = prevOwnership.startTimestamp;
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
unchecked {
_burnCounter++;
_productData[productId].numberBurned++;
}
}
function _approve(address to, uint256 tokenId, address owner) private {
_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try
IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data)
returns (bytes4 retval) {
return retval == IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
}
文件 5 的 30:IContractMetadata.sol
pragma solidity ^0.8.0;
interface IContractMetadata {
function contractURI() external view returns (string memory);
function setContractURI(string calldata _uri) external;
event ContractURIUpdated(string prevURI, string newURI);
}
文件 6 的 30:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 7 的 30:IERC2981.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
interface IERC2981 is IERC165 {
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}
文件 8 的 30:IERC4906.sol
pragma solidity ^0.8.0;
import "@thirdweb-dev/contracts/eip/interface/IERC165.sol";
import "@thirdweb-dev/contracts/eip/interface/IERC721.sol";
interface IERC4906 is IERC165, IERC721 {
event MetadataUpdate(uint256 _tokenId);
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}
文件 9 的 30:IERC721.sol
pragma solidity ^0.8.0;
interface IERC721 {
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);
function balanceOf(address owner) external view returns (uint256);
function ownerOf(uint256 tokenId) external view returns (address);
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);
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;
}
文件 10 的 30:IERC721A.sol
pragma solidity ^0.8.4;
import "./IERC721.sol";
import "./IERC721Metadata.sol";
interface IERC721A is IERC721, IERC721Metadata {
error ApprovalCallerNotOwnerNorApproved();
error ApprovalQueryForNonexistentToken();
error ApproveToCaller();
error ApprovalToCurrentOwner();
error BalanceQueryForZeroAddress();
error MintToZeroAddress();
error MintZeroQuantity();
error OwnerQueryForNonexistentToken();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TransferToNonERC721ReceiverImplementer();
error TransferToZeroAddress();
error URIQueryForNonexistentToken();
struct TokenOwnership {
address addr;
uint64 startTimestamp;
bool burned;
}
struct AddressData {
uint64 balance;
uint64 numberMinted;
uint64 numberBurned;
uint64 aux;
}
function totalSupply() external view returns (uint256);
}
文件 11 的 30:IERC721ArtistProduct.sol
pragma solidity ^0.8.20;
import "@thirdweb-dev/contracts/eip/interface/IERC721A.sol";
interface IERC721ArtistProduct is IERC721A {
struct ProductData {
uint64 quantity;
uint64 numberMinted;
uint64 numberBurned;
bool locked;
bool frozen;
bool burnable;
bool uniqueMetadata;
}
function productSupply(uint256 productId) external view returns (uint256);
function productBalanceOf(
address owner,
uint256 productId
) external view returns (uint256);
event ProductQuantityUpdated(
uint256 indexed productId,
uint64 indexed oldQuantity,
uint64 indexed newQuantity
);
event ProductMintingRestricted(uint256 indexed productId, bool indexed isRestricted);
event ProductTransfersRestricted(
uint256 indexed productId,
bool indexed isRestricted
);
event ProductBurningRestricted(uint256 indexed productId, bool indexed isRestricted);
event ProductUniqueTokenMetadata(
uint256 indexed productId,
bool indexed isUniquePerToken
);
error ProductOffsetAfterMinting();
error ProductOffsetOutsideRange(uint256 requested, uint256 minumum, uint256 maximum);
error ProductIdExceedsOffsetMaximum(uint256 requested, uint256 maximum);
error ProductQuantityExceedsOffsetMaximum(uint256 requested, uint256 maximum);
error ProductMintsExceedsQuantity();
error ProductNotConfigured();
error ProductQueryForImpossibleToken();
error ProductQueryForNonexistantToken();
error ProductMintingDisabled();
error ProductBurningDisabled();
error ProductTransfersDisabled();
}
文件 12 的 30:IERC721Metadata.sol
pragma solidity ^0.8.0;
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);
}
文件 13 的 30:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 14 的 30:IMulticall.sol
pragma solidity ^0.8.0;
interface IMulticall {
function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}
文件 15 的 30:IOwnable.sol
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external view returns (address);
function setOwner(address _newOwner) external;
event OwnerUpdated(address indexed prevOwner, address indexed newOwner);
}
文件 16 的 30:IPermissions.sol
pragma solidity ^0.8.0;
interface IPermissions {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 17 的 30:IProductArtistToken.sol
pragma solidity ^0.8.20;
interface IProductArtistToken {
function mintTo(address _to, uint256 _productId) external;
function mintTo(address _to, uint256 _productId, bytes memory _data) external;
function mintTo(
address _to,
uint256 _productId,
string calldata _uri,
bytes memory _data
) external;
function batchMintTo(address _to, uint256 _productId, uint256 _quantity) external;
function batchMintTo(
address _to,
uint256 _productId,
uint256 _quantity,
bytes memory _data
) external;
function batchMintTo(
address _to,
uint256 _productId,
uint256 _quantity,
string[] calldata _uris,
bytes memory _data
) external;
event GlobalMintingRestricted(bool restricted);
event GlobalTransfersRestricted(bool restricted);
event GlobalBurningRestricted(bool restricted);
error BatchMintURICountMismatch();
error ManagerRoleRequired();
error MintingRoleRequired();
error GlobalMintingDisabled();
error GlobalTransfersDisabled();
error GlobalBurningDisabled();
}
文件 18 的 30:IProductCreators.sol
pragma solidity ^0.8.20;
interface IProductCreators {
struct ProductCreatorData {
uint256 index;
mapping(uint256 => CreatorData) creators;
}
struct CreatorData {
address creatorAddress;
string creatorInfo;
}
function getProductCreators(
uint256 _productId
) external view returns (CreatorData[] memory);
function setProductCreators(
uint256 _productId,
CreatorData[] calldata _creators
) external;
event ProductCreatorsUpdated(uint256 indexed productId, CreatorData[] creators);
error ProductCreatorNotAuthorized();
}
文件 19 的 30:IProductDataConnector.sol
pragma solidity ^0.8.20;
import "./IProductCreators.sol";
import "../../eip/interface/IERC4906.sol";
interface IProductDataConnector is IERC4906 {
function setDataContract(address dataContract_) external;
function getDataContract() external view returns (address);
function getProductCreators(
uint256 _productId
) external view returns (IProductCreators.CreatorData[] memory);
function setBaseURI(string calldata _uri) external;
function setTokenURI(uint256 _tokenId, string calldata _uri) external;
function setTokenURIs(
uint256 _tokenId,
uint256 _quantity,
string[] calldata _uris
) external;
function setTokenURIs(uint256[] calldata _tokenIds, string[] calldata _uris) external;
function setProductURI(uint256 _productId, string calldata _uri) external;
event BaseURIUpdated(string prevURI, string newURI);
event TokenURIUpdated(uint256 indexed tokenId, string prevURI, string newURI);
event ProductURIUpdated(uint256 indexed tokenId, string prevURI, string newURI);
error ProductDataContractNotConfigured();
error ProductDataNotAuthorized();
}
文件 20 的 30:IProductDataContract.sol
pragma solidity ^0.8.20;
import "../../extension/interface/IProductCreators.sol";
interface IProductDataContract {
function tieredURI(
uint256 _tokenId,
uint256 _productId,
bool _isUnique
) external view returns (string memory);
function getProductCreators(
uint256 _productId
) external view returns (IProductCreators.CreatorData[] memory);
function baseURI() external view returns (string memory);
function setBaseURI(string memory _uri) external returns (string memory);
function productURI(uint256 _productId) external view returns (string memory);
function setProductURI(
uint256 _productId,
string calldata _uri
) external returns (string memory);
function tokenURI(uint256 _tokenId) external view returns (string memory);
function setTokenURI(
uint256 _tokenId,
string calldata _uri
) external returns (string memory);
function setTokenURIs(
uint256[] calldata _tokenIds,
string[] calldata _uris
) external returns (string[] memory);
function setTokenURIs(
uint256 _startTokenId,
uint256 _quantity,
string[] calldata _uri
) external returns (string[] memory);
function runBeforeExtensions(
uint256 _productId,
address _from,
address _to,
uint256 _startTokenId,
uint256 _quantity
) external;
function runAfterExtensions(
uint256 _productId,
address _from,
address _to,
uint256 _startTokenId,
uint256 _quantity
) external;
error ManagerRoleRequired();
error CalledFromTokenOnly();
}
文件 21 的 30:IRoyalty.sol
pragma solidity ^0.8.0;
import "../../eip/interface/IERC2981.sol";
interface IRoyalty is IERC2981 {
struct RoyaltyInfo {
address recipient;
uint256 bps;
}
function getDefaultRoyaltyInfo() external view returns (address, uint16);
function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external;
function setRoyaltyInfoForToken(
uint256 tokenId,
address recipient,
uint256 bps
) external;
function getRoyaltyInfoForToken(uint256 tokenId) external view returns (address, uint16);
event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps);
event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps);
}
文件 22 的 30:Multicall.sol
pragma solidity ^0.8.0;
import "../lib/TWAddress.sol";
import "./interface/IMulticall.sol";
contract Multicall is IMulticall {
function multicall(bytes[] calldata data) external virtual override returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = TWAddress.functionDelegateCall(address(this), data[i]);
}
return results;
}
}
文件 23 的 30:Ownable.sol
pragma solidity ^0.8.0;
import "./interface/IOwnable.sol";
abstract contract Ownable is IOwnable {
address private _owner;
modifier onlyOwner() {
if (msg.sender != _owner) {
revert("Not authorized");
}
_;
}
function owner() public view override returns (address) {
return _owner;
}
function setOwner(address _newOwner) external override {
if (!_canSetOwner()) {
revert("Not authorized");
}
_setupOwner(_newOwner);
}
function _setupOwner(address _newOwner) internal {
address _prevOwner = _owner;
_owner = _newOwner;
emit OwnerUpdated(_prevOwner, _newOwner);
}
function _canSetOwner() internal view virtual returns (bool);
}
文件 24 的 30:Permissions.sol
pragma solidity ^0.8.0;
import "./interface/IPermissions.sol";
import "../lib/TWStrings.sol";
contract Permissions is IPermissions {
mapping(bytes32 => mapping(address => bool)) private _hasRole;
mapping(bytes32 => bytes32) private _getRoleAdmin;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role, msg.sender);
_;
}
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _hasRole[role][account];
}
function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) {
if (!_hasRole[role][address(0)]) {
return _hasRole[role][account];
}
return true;
}
function getRoleAdmin(bytes32 role) external view override returns (bytes32) {
return _getRoleAdmin[role];
}
function grantRole(bytes32 role, address account) public virtual override {
_checkRole(_getRoleAdmin[role], msg.sender);
if (_hasRole[role][account]) {
revert("Can only grant to non holders");
}
_setupRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override {
_checkRole(_getRoleAdmin[role], msg.sender);
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
if (msg.sender != account) {
revert("Can only renounce for self");
}
_revokeRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = _getRoleAdmin[role];
_getRoleAdmin[role] = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _setupRole(bytes32 role, address account) internal virtual {
_hasRole[role][account] = true;
emit RoleGranted(role, account, msg.sender);
}
function _revokeRole(bytes32 role, address account) internal virtual {
_checkRole(role, account);
delete _hasRole[role][account];
emit RoleRevoked(role, account, msg.sender);
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!_hasRole[role][account]) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
if (!hasRoleWithSwitch(role, account)) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
}
文件 25 的 30:ProductArtistToken.sol
pragma solidity ^0.8.20;
import "../eip/ERC721ArtistProduct.sol";
import "./interface/IProductArtistToken.sol";
import "../extension/ProductDataConnector.sol";
import "@thirdweb-dev/contracts/extension/ContractMetadata.sol";
import "@thirdweb-dev/contracts/extension/Multicall.sol";
import "@thirdweb-dev/contracts/extension/Ownable.sol";
import "@thirdweb-dev/contracts/extension/Royalty.sol";
import "@thirdweb-dev/contracts/extension/Permissions.sol";
import "@thirdweb-dev/contracts/lib/TWStrings.sol";
contract ProductArtistToken is
IProductArtistToken,
ERC721ArtistProduct,
ContractMetadata,
ProductDataConnector,
Multicall,
Ownable,
Royalty,
Permissions
{
using TWStrings for uint256;
bytes32 public constant BURNING_ROLE = keccak256("BURNING_ROLE");
bytes32 public constant MINTING_ROLE = keccak256("MINTING_ROLE");
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
bytes32 public constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");
constructor(
address defaultAdmin_,
string memory name_,
string memory symbol_,
uint256 productOffset_,
address royaltyRecipient_,
uint128 royaltyBps_
) ERC721ArtistProduct(name_, symbol_, productOffset_) {
_setupOwner(defaultAdmin_);
_setupRole(DEFAULT_ADMIN_ROLE, defaultAdmin_);
_setupRole(TRANSFER_ROLE, address(0));
_setupRole(MINTING_ROLE, address(0));
_setRoleAdmin(BURNING_ROLE, DEFAULT_ADMIN_ROLE);
_setRoleAdmin(MINTING_ROLE, DEFAULT_ADMIN_ROLE);
_setRoleAdmin(MANAGER_ROLE, DEFAULT_ADMIN_ROLE);
_setRoleAdmin(TRANSFER_ROLE, DEFAULT_ADMIN_ROLE);
_setupDefaultRoyaltyInfo(royaltyRecipient_, royaltyBps_);
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC721ArtistProduct, IERC165) returns (bool) {
return
interfaceId == 0x01ffc9a7 ||
interfaceId == 0x80ac58cd ||
interfaceId == 0x5b5e139f ||
interfaceId == 0x49064906 ||
interfaceId == type(IERC2981).interfaceId;
}
function tokenURI(
uint256 _tokenId
) public view override(ERC721ArtistProduct) returns (string memory) {
if (!_exists(_tokenId)) revert URIQueryForNonexistentToken();
uint256 productId = _getProductId(_tokenId);
bool isUnique = _getProductUniqueMetadata(productId);
return _tieredURI(_tokenId, productId, isUnique);
}
function mintTo(address _to, uint256 _productId) external onlyMinter {
_safeMint(_to, _productId, 1, "");
}
function mintTo(
address _to,
uint256 _productId,
bytes memory _data
) external onlyMinter {
_safeMint(_to, _productId, 1, _data);
}
function mintTo(
address _to,
uint256 _productId,
string calldata _uri,
bytes memory _data
) external onlyMinter {
(uint256 startTokenId, ) = _safeMint(_to, _productId, 1, _data);
_setTokenUri(startTokenId, _uri);
}
function batchMintTo(
address _to,
uint256 _productId,
uint256 _quantity
) external onlyMinter {
_safeMint(_to, _productId, _quantity);
}
function batchMintTo(
address _to,
uint256 _productId,
uint256 _quantity,
bytes memory _data
) external onlyMinter {
_safeMint(_to, _productId, _quantity, _data);
}
function batchMintTo(
address _to,
uint256 _productId,
uint256 _quantity,
string[] calldata _uris,
bytes memory _data
) external onlyMinter {
(uint256 startTokenId, ) = _safeMint(_to, _productId, _quantity, _data);
_setTokenUris(startTokenId, _quantity, _uris);
}
function burn(uint256 _tokenId) external {
_burn(_tokenId, true);
}
function totalMinted() external view returns (uint256) {
return _mintCounter;
}
function totalBurned() external view returns (uint256) {
return _burnCounter;
}
function getOwnerData(address _owner) external view returns (AddressData memory) {
return _getAddressData(_owner);
}
function getTokenData(
uint256 _tokenId
) external view returns (TokenOwnership memory) {
return _ownershipOf(_tokenId);
}
function getProductOffset() external view returns (uint256) {
return _getProductOffset();
}
function getProduct(uint256 _productId) external view returns (ProductData memory) {
return _getProduct(_productId);
}
function getProductArtist(uint256 _productId) external view returns (address) {
return _getArtist(_productId);
}
function getProductForToken(
uint256 _tokenId
) external view returns (ProductData memory) {
return _getProduct(_getProductId(_tokenId));
}
function getArtistForToken(uint256 _tokenId) external view returns (address) {
return _getArtist(_getProductId(_tokenId));
}
function isApprovedOrOwner(
address _operator,
uint256 _tokenId
) external view returns (bool isApprovedOrOwnerOf) {
address owner = ownerOf(_tokenId);
isApprovedOrOwnerOf = (_operator == owner ||
isApprovedForAll(owner, _operator) ||
getApproved(_tokenId) == _operator);
}
function setProductURI(
uint256 _productId,
string calldata _uri
) external override onlyManager {
_setProductUri(_productId, _uri);
if (_getProductQuantity(_productId) != 0) {
emit BatchMetadataUpdate(
_getMinTokenId(_productId),
_getMaxTokenId(_productId)
);
}
}
function setOwnerAux(address owner, uint64 aux) external onlyManager {
_setAux(owner, aux);
}
function setProductIdOffset(uint256 _offset) external onlyManager {
_setProductOffset(_offset);
}
function setProduct(uint256 _productId, uint64 _quantity) external onlyManager {
_setProductQuantity(_productId, _quantity);
}
function setProductArtist(uint256 _productId, address _artist) external onlyManager {
_setArtist(_productId, _artist);
}
function setProductUniqueMetadata(
uint256 _productId,
bool _isUnique
) external onlyManager {
_setProductUniqueMetadata(_productId, _isUnique);
}
function restrictProductMinting(
uint256 _productId,
bool _toRestrict
) external onlyManager {
_setProductLocked(_productId, _toRestrict);
}
function restrictProductTransfers(
uint256 _productId,
bool _toRestrict
) external onlyManager {
_setProductFrozen(_productId, _toRestrict);
}
function restrictProductBurning(
uint256 _productId,
bool _toRestrict
) external onlyManager {
_setProductBurnable(_productId, !_toRestrict);
}
function restrictMinting(bool _toRestrict) external onlyManager {
if (_toRestrict) {
_revokeRole(MINTING_ROLE, address(0));
} else {
_setupRole(MINTING_ROLE, address(0));
}
emit GlobalMintingRestricted(_toRestrict);
}
function restrictTransfers(bool _toRestrict) external onlyManager {
if (_toRestrict) {
_revokeRole(TRANSFER_ROLE, address(0));
} else {
_setupRole(TRANSFER_ROLE, address(0));
}
emit GlobalTransfersRestricted(_toRestrict);
}
function restrictBurning(bool _toRestrict) external onlyManager {
if (_toRestrict) {
_revokeRole(BURNING_ROLE, address(0));
} else {
_setupRole(BURNING_ROLE, address(0));
}
emit GlobalBurningRestricted(_toRestrict);
}
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal override(ERC721ArtistProduct) {
if (from != address(0) && to != address(0)) {
if (
!hasRole(TRANSFER_ROLE, address(0)) &&
!(hasRole(TRANSFER_ROLE, from) && hasRole(TRANSFER_ROLE, to))
) revert GlobalTransfersDisabled();
}
if (from != address(0) && to == address(0)) {
if (!hasRoleWithSwitch(BURNING_ROLE, from)) revert GlobalBurningDisabled();
}
if (from == address(0) && to != address(0)) {
if (!hasRole(MINTING_ROLE, address(0))) revert GlobalMintingDisabled();
}
_runBeforeExtensions(
_getProductId(startTokenId),
from,
to,
startTokenId,
quantity
);
}
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal override(ERC721ArtistProduct) {
_runAfterExtensions(
_getProductId(startTokenId),
from,
to,
startTokenId,
quantity
);
}
modifier onlyManager() {
_checkManagerAdmin();
_;
}
modifier onlyMinter() {
_checkMintingAdmin();
_;
}
function _checkManagerAdmin() internal view {
if (
!hasRole(DEFAULT_ADMIN_ROLE, msg.sender) && !hasRole(MANAGER_ROLE, msg.sender)
) {
revert ManagerRoleRequired();
}
}
function _checkMintingAdmin() internal view {
if (
!hasRole(DEFAULT_ADMIN_ROLE, msg.sender) && !hasRole(MINTING_ROLE, msg.sender)
) {
revert MintingRoleRequired();
}
}
function _canSetContractURI() internal view override returns (bool) {
return
hasRole(DEFAULT_ADMIN_ROLE, msg.sender) || hasRole(MANAGER_ROLE, msg.sender);
}
function _canSetData() internal view override returns (bool) {
return
hasRole(DEFAULT_ADMIN_ROLE, msg.sender) || hasRole(MANAGER_ROLE, msg.sender);
}
function _canSetOwner() internal view override returns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function _canSetRoyaltyInfo() internal view override returns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
}
文件 26 的 30:ProductDataConnector.sol
pragma solidity ^0.8.20;
import "./interface/IProductDataConnector.sol";
import "../base/interface/IProductDataContract.sol";
abstract contract ProductDataConnector is IProductDataConnector {
address private _dataContract;
function getDataContract() external view virtual returns (address) {
return _dataContract;
}
function getProductCreators(
uint256 _productId
) external view virtual returns (IProductCreators.CreatorData[] memory) {
if (_dataContract == address(0)) return new IProductCreators.CreatorData[](0);
return IProductDataContract(_dataContract).getProductCreators(_productId);
}
function setDataContract(address dataContract_) external virtual onlyData {
_dataContract = dataContract_;
}
function setBaseURI(string calldata _uri) external virtual onlyData {
_setBaseUri(_uri);
}
function setTokenURI(
uint256 _tokenId,
string calldata _uri
) external virtual onlyData {
_setTokenUri(_tokenId, _uri);
}
function setTokenURIs(
uint256 _tokenId,
uint256 _quantity,
string[] calldata _uris
) external virtual onlyData {
_setTokenUris(_tokenId, _quantity, _uris);
}
function setTokenURIs(
uint256[] calldata _tokenIds,
string[] calldata _uris
) external virtual onlyData {
_setTokenUris(_tokenIds, _uris);
}
function setProductURI(
uint256 _productId,
string calldata _uri
) external virtual onlyData {
_setProductUri(_productId, _uri);
}
modifier onlyConfigured() {
_notConfigured();
_;
}
modifier onlyData() {
_checkAuth();
_;
}
function _checkAuth() internal virtual {
if (!_canSetData()) revert ProductDataNotAuthorized();
}
function _canSetData() internal view virtual returns (bool);
function _notConfigured() internal virtual {
if (_dataContract == address(0)) revert ProductDataContractNotConfigured();
}
function _tieredURI(
uint256 _tokenId,
uint256 _productId,
bool _isUnique
) internal view returns (string memory) {
if (_dataContract == address(0)) return "";
return
IProductDataContract(_dataContract).tieredURI(
_tokenId,
_productId,
_isUnique
);
}
function _setBaseUri(string memory _uri) internal onlyConfigured {
string memory prevURI = IProductDataContract(_dataContract).setBaseURI(_uri);
emit BaseURIUpdated(prevURI, _uri);
}
function _setTokenUri(uint256 _tokenId, string memory _uri) internal onlyConfigured {
string memory prevURI = IProductDataContract(_dataContract).setTokenURI(
_tokenId,
_uri
);
emit TokenURIUpdated(_tokenId, prevURI, _uri);
emit MetadataUpdate(_tokenId);
}
function _setTokenUris(
uint256 _tokenId,
uint256 _quantity,
string[] memory _uris
) internal onlyConfigured {
string[] memory _prevURIs = IProductDataContract(_dataContract).setTokenURIs(
_tokenId,
_quantity,
_uris
);
unchecked {
for (uint i; i < _quantity; ) {
emit TokenURIUpdated(_tokenId + i, _prevURIs[i], _uris[i]);
++i;
}
emit BatchMetadataUpdate(_tokenId, _tokenId + _quantity - 1);
}
}
function _setTokenUris(
uint256[] memory _tokenIds,
string[] memory _uris
) internal onlyConfigured {
string[] memory _prevURIs = IProductDataContract(_dataContract).setTokenURIs(
_tokenIds,
_uris
);
uint256 length = _prevURIs.length;
for (uint i; i < length; ) {
emit TokenURIUpdated(_tokenIds[i], _prevURIs[i], _uris[i]);
emit MetadataUpdate(_tokenIds[i]);
unchecked {
++i;
}
}
}
function _setProductUri(
uint256 _productId,
string memory _uri
) internal onlyConfigured {
string memory prevURI = IProductDataContract(_dataContract).setProductURI(
_productId,
_uri
);
emit ProductURIUpdated(_productId, prevURI, _uri);
}
function _runBeforeExtensions(
uint256 _productId,
address _from,
address _to,
uint256 _startTokenId,
uint256 _quantity
) internal {
if (_dataContract == address(0)) return;
IProductDataContract(_dataContract).runBeforeExtensions(
_productId,
_from,
_to,
_startTokenId,
_quantity
);
}
function _runAfterExtensions(
uint256 _productId,
address _from,
address _to,
uint256 _startTokenId,
uint256 _quantity
) internal {
if (_dataContract == address(0)) return;
IProductDataContract(_dataContract).runAfterExtensions(
_productId,
_from,
_to,
_startTokenId,
_quantity
);
}
}
文件 27 的 30:Royalty.sol
pragma solidity ^0.8.0;
import "./interface/IRoyalty.sol";
abstract contract Royalty is IRoyalty {
address private royaltyRecipient;
uint16 private royaltyBps;
mapping(uint256 => RoyaltyInfo) private royaltyInfoForToken;
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
virtual
override
returns (address receiver, uint256 royaltyAmount)
{
(address recipient, uint256 bps) = getRoyaltyInfoForToken(tokenId);
receiver = recipient;
royaltyAmount = (salePrice * bps) / 10_000;
}
function getRoyaltyInfoForToken(uint256 _tokenId) public view override returns (address, uint16) {
RoyaltyInfo memory royaltyForToken = royaltyInfoForToken[_tokenId];
return
royaltyForToken.recipient == address(0)
? (royaltyRecipient, uint16(royaltyBps))
: (royaltyForToken.recipient, uint16(royaltyForToken.bps));
}
function getDefaultRoyaltyInfo() external view override returns (address, uint16) {
return (royaltyRecipient, uint16(royaltyBps));
}
function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external override {
if (!_canSetRoyaltyInfo()) {
revert("Not authorized");
}
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
}
function _setupDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) internal {
if (_royaltyBps > 10_000) {
revert("Exceeds max bps");
}
royaltyRecipient = _royaltyRecipient;
royaltyBps = uint16(_royaltyBps);
emit DefaultRoyalty(_royaltyRecipient, _royaltyBps);
}
function setRoyaltyInfoForToken(
uint256 _tokenId,
address _recipient,
uint256 _bps
) external override {
if (!_canSetRoyaltyInfo()) {
revert("Not authorized");
}
_setupRoyaltyInfoForToken(_tokenId, _recipient, _bps);
}
function _setupRoyaltyInfoForToken(
uint256 _tokenId,
address _recipient,
uint256 _bps
) internal {
if (_bps > 10_000) {
revert("Exceeds max bps");
}
royaltyInfoForToken[_tokenId] = RoyaltyInfo({ recipient: _recipient, bps: _bps });
emit RoyaltyForToken(_tokenId, _recipient, _bps);
}
function _canSetRoyaltyInfo() internal view virtual returns (bool);
}
文件 28 的 30:SykyArtistToken.sol
pragma solidity ^0.8.20;
import "../base/ProductArtistToken.sol";
string constant DEFAULT_NAME = "SYKYGOM";
string constant DEFAULT_SYMBOL = "SYKYGOM";
uint256 constant DEFAULT_SERIES_OFFSET = 6;
uint128 constant DEFAULT_ROYALTY_BPS = 1000;
contract SykyArtistToken is ProductArtistToken {
string public constant ENV = "MAINNET";
string public constant VER = "1.0.0";
constructor(
address defaultAdmin_,
address royaltyRecipient_
)
ProductArtistToken(
defaultAdmin_,
DEFAULT_NAME,
DEFAULT_SYMBOL,
DEFAULT_SERIES_OFFSET,
royaltyRecipient_,
DEFAULT_ROYALTY_BPS
)
{}
}
文件 29 的 30:TWAddress.sol
pragma solidity ^0.8.0;
library TWAddress {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 30 的 30:TWStrings.sol
pragma solidity ^0.8.0;
library TWStrings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
{
"compilationTarget": {
"contracts/syky/SykyArtistToken.sol": "SykyArtistToken"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 300
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"defaultAdmin_","type":"address"},{"internalType":"address","name":"royaltyRecipient_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApprovalToCurrentOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"BatchMintURICountMismatch","type":"error"},{"inputs":[],"name":"GlobalBurningDisabled","type":"error"},{"inputs":[],"name":"GlobalMintingDisabled","type":"error"},{"inputs":[],"name":"GlobalTransfersDisabled","type":"error"},{"inputs":[],"name":"ManagerRoleRequired","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"MintingRoleRequired","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ProductBurningDisabled","type":"error"},{"inputs":[],"name":"ProductDataContractNotConfigured","type":"error"},{"inputs":[],"name":"ProductDataNotAuthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"maximum","type":"uint256"}],"name":"ProductIdExceedsOffsetMaximum","type":"error"},{"inputs":[],"name":"ProductMintingDisabled","type":"error"},{"inputs":[],"name":"ProductMintsExceedsQuantity","type":"error"},{"inputs":[],"name":"ProductNotConfigured","type":"error"},{"inputs":[],"name":"ProductOffsetAfterMinting","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"minumum","type":"uint256"},{"internalType":"uint256","name":"maximum","type":"uint256"}],"name":"ProductOffsetOutsideRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"maximum","type":"uint256"}],"name":"ProductQuantityExceedsOffsetMaximum","type":"error"},{"inputs":[],"name":"ProductQueryForImpossibleToken","type":"error"},{"inputs":[],"name":"ProductQueryForNonexistantToken","type":"error"},{"inputs":[],"name":"ProductTransfersDisabled","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","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":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"BaseURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRoyaltyRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"newRoyaltyBps","type":"uint256"}],"name":"DefaultRoyalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"restricted","type":"bool"}],"name":"GlobalBurningRestricted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"restricted","type":"bool"}],"name":"GlobalMintingRestricted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"restricted","type":"bool"}],"name":"GlobalTransfersRestricted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isRestricted","type":"bool"}],"name":"ProductBurningRestricted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isRestricted","type":"bool"}],"name":"ProductMintingRestricted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"oldQuantity","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"newQuantity","type":"uint64"}],"name":"ProductQuantityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isRestricted","type":"bool"}],"name":"ProductTransfersRestricted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"string","name":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"ProductURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isUniquePerToken","type":"bool"}],"name":"ProductUniqueTokenMetadata","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"royaltyRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"royaltyBps","type":"uint256"}],"name":"RoyaltyForToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"string","name":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"TokenURIUpdated","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":[],"name":"BURNING_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ENV","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTING_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VER","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"batchMintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"batchMintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"string[]","name":"_uris","type":"string[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"batchMintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getArtistForToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDataContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDefaultRoyaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getOwnerData","outputs":[{"components":[{"internalType":"uint64","name":"balance","type":"uint64"},{"internalType":"uint64","name":"numberMinted","type":"uint64"},{"internalType":"uint64","name":"numberBurned","type":"uint64"},{"internalType":"uint64","name":"aux","type":"uint64"}],"internalType":"struct IERC721A.AddressData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"}],"name":"getProduct","outputs":[{"components":[{"internalType":"uint64","name":"quantity","type":"uint64"},{"internalType":"uint64","name":"numberMinted","type":"uint64"},{"internalType":"uint64","name":"numberBurned","type":"uint64"},{"internalType":"bool","name":"locked","type":"bool"},{"internalType":"bool","name":"frozen","type":"bool"},{"internalType":"bool","name":"burnable","type":"bool"},{"internalType":"bool","name":"uniqueMetadata","type":"bool"}],"internalType":"struct IERC721ArtistProduct.ProductData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"}],"name":"getProductArtist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"}],"name":"getProductCreators","outputs":[{"components":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"string","name":"creatorInfo","type":"string"}],"internalType":"struct IProductCreators.CreatorData[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getProductForToken","outputs":[{"components":[{"internalType":"uint64","name":"quantity","type":"uint64"},{"internalType":"uint64","name":"numberMinted","type":"uint64"},{"internalType":"uint64","name":"numberBurned","type":"uint64"},{"internalType":"bool","name":"locked","type":"bool"},{"internalType":"bool","name":"frozen","type":"bool"},{"internalType":"bool","name":"burnable","type":"bool"},{"internalType":"bool","name":"uniqueMetadata","type":"bool"}],"internalType":"struct IERC721ArtistProduct.ProductData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProductOffset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getRoyaltyInfoForToken","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getTokenData","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"}],"internalType":"struct IERC721A.TokenOwnership","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRoleWithSwitch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"isApprovedOrOwner","outputs":[{"internalType":"bool","name":"isApprovedOrOwnerOf","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_productId","type":"uint256"}],"name":"mintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"string","name":"_uri","type":"string"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"mintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"mintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","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":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"productId","type":"uint256"}],"name":"productBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"productId","type":"uint256"}],"name":"productSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_toRestrict","type":"bool"}],"name":"restrictBurning","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_toRestrict","type":"bool"}],"name":"restrictMinting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"bool","name":"_toRestrict","type":"bool"}],"name":"restrictProductBurning","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"bool","name":"_toRestrict","type":"bool"}],"name":"restrictProductMinting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"bool","name":"_toRestrict","type":"bool"}],"name":"restrictProductTransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_toRestrict","type":"bool"}],"name":"restrictTransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"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":"_uri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"dataContract_","type":"address"}],"name":"setDataContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_royaltyRecipient","type":"address"},{"internalType":"uint256","name":"_royaltyBps","type":"uint256"}],"name":"setDefaultRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint64","name":"aux","type":"uint64"}],"name":"setOwnerAux","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"uint64","name":"_quantity","type":"uint64"}],"name":"setProduct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"address","name":"_artist","type":"address"}],"name":"setProductArtist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offset","type":"uint256"}],"name":"setProductIdOffset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"string","name":"_uri","type":"string"}],"name":"setProductURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_productId","type":"uint256"},{"internalType":"bool","name":"_isUnique","type":"bool"}],"name":"setProductUniqueMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_bps","type":"uint256"}],"name":"setRoyaltyInfoForToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_uri","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"string[]","name":"_uris","type":"string[]"}],"name":"setTokenURIs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"string[]","name":"_uris","type":"string[]"}],"name":"setTokenURIs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]