// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "@manifoldxyz/libraries-solidity/contracts/access/AdminControlUpgradeable.sol"; import "./core/ERC1155CreatorCore.sol"; import "./token/ERC1155/ERC1155Upgradeable.sol"; /** * @dev ERC1155Creator implementation */ contract ERC1155CreatorImplementation is AdminControlUpgradeable, ERC1155Upgradeable, ERC1155CreatorCore { using EnumerableSet for EnumerableSet.AddressSet; mapping(uint256 => uint256) private _totalSupply; /** * Initializer */ function initialize(string memory _name, string memory _symbol) public initializer { __ERC1155_init(_name, _symbol); __Ownable_init(); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155Core, ERC1155CreatorCore, AdminControlUpgradeable) returns (bool) { return ERC1155CreatorCore.supportsInterface(interfaceId) || ERC1155Core.supportsInterface(interfaceId) || AdminControlUpgradeable.supportsInterface(interfaceId); } function _beforeTokenTransfer(address, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory) internal virtual override { _approveTransfer(from, to, ids, amounts); } /** * @dev See {ICreatorCore-registerExtension}. */ function registerExtension(address extension, string calldata baseURI) external override adminRequired { requireNonBlacklist(extension); _registerExtension(extension, baseURI, false); } /** * @dev See {ICreatorCore-registerExtension}. */ function registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) external override adminRequired { requireNonBlacklist(extension); _registerExtension(extension, baseURI, baseURIIdentical); } /** * @dev See {ICreatorCore-unregisterExtension}. */ function unregisterExtension(address extension) external override adminRequired { _unregisterExtension(extension); } /** * @dev See {ICreatorCore-blacklistExtension}. */ function blacklistExtension(address extension) external override adminRequired { _blacklistExtension(extension); } /** * @dev See {ICreatorCore-setBaseTokenURIExtension}. */ function setBaseTokenURIExtension(string calldata uri_) external override { requireExtension(); _setBaseTokenURIExtension(uri_, false); } /** * @dev See {ICreatorCore-setBaseTokenURIExtension}. */ function setBaseTokenURIExtension(string calldata uri_, bool identical) external override { requireExtension(); _setBaseTokenURIExtension(uri_, identical); } /** * @dev See {ICreatorCore-setTokenURIPrefixExtension}. */ function setTokenURIPrefixExtension(string calldata prefix) external override { requireExtension(); _setTokenURIPrefixExtension(prefix); } /** * @dev See {ICreatorCore-setTokenURIExtension}. */ function setTokenURIExtension(uint256 tokenId, string calldata uri_) external override { requireExtension(); _setTokenURIExtension(tokenId, uri_); } /** * @dev See {ICreatorCore-setTokenURIExtension}. */ function setTokenURIExtension(uint256[] calldata tokenIds, string[] calldata uris) external override { requireExtension(); require(tokenIds.length == uris.length, "Invalid input"); for (uint i; i < tokenIds.length;) { _setTokenURIExtension(tokenIds[i], uris[i]); unchecked { ++i; } } } /** * @dev See {ICreatorCore-setBaseTokenURI}. */ function setBaseTokenURI(string calldata uri_) external override adminRequired { _setBaseTokenURI(uri_); } /** * @dev See {ICreatorCore-setTokenURIPrefix}. */ function setTokenURIPrefix(string calldata prefix) external override adminRequired { _setTokenURIPrefix(prefix); } /** * @dev See {ICreatorCore-setTokenURI}. */ function setTokenURI(uint256 tokenId, string calldata uri_) external override adminRequired { _setTokenURI(tokenId, uri_); } /** * @dev See {ICreatorCore-setTokenURI}. */ function setTokenURI(uint256[] calldata tokenIds, string[] calldata uris) external override adminRequired { require(tokenIds.length == uris.length, "Invalid input"); for (uint i; i < tokenIds.length;) { _setTokenURI(tokenIds[i], uris[i]); unchecked { ++i; } } } /** * @dev See {ICreatorCore-setMintPermissions}. */ function setMintPermissions(address extension, address permissions) external override adminRequired { _setMintPermissions(extension, permissions); } /** * @dev See {IERC1155CreatorCore-mintBaseNew}. */ function mintBaseNew(address[] calldata to, uint256[] calldata amounts, string[] calldata uris) public virtual override nonReentrant adminRequired returns(uint256[] memory) { return _mintNew(address(0), to, amounts, uris); } /** * @dev See {IERC1155CreatorCore-mintBaseExisting}. */ function mintBaseExisting(address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) public virtual override nonReentrant adminRequired { for (uint i; i < tokenIds.length;) { uint256 tokenId = tokenIds[i]; require(tokenId > 0 && tokenId <= _tokenCount, "Invalid token"); require(_tokenExtension(tokenId) == address(0), "Token created by extension"); unchecked { ++i; } } _mintExisting(address(0), to, tokenIds, amounts); } /** * @dev See {IERC1155CreatorCore-mintExtensionNew}. */ function mintExtensionNew(address[] calldata to, uint256[] calldata amounts, string[] calldata uris) public virtual override nonReentrant returns(uint256[] memory tokenIds) { requireExtension(); return _mintNew(msg.sender, to, amounts, uris); } /** * @dev See {IERC1155CreatorCore-mintExtensionExisting}. */ function mintExtensionExisting(address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) public virtual override nonReentrant { requireExtension(); for (uint i; i < tokenIds.length;) { require(_tokenExtension(tokenIds[i]) == address(msg.sender), "Token not created by this extension"); unchecked { ++i; } } _mintExisting(msg.sender, to, tokenIds, amounts); } /** * @dev Mint new tokens */ function _mintNew(address extension, address[] calldata to, uint256[] calldata amounts, string[] calldata uris) internal returns(uint256[] memory tokenIds) { if (to.length > 1) { // Multiple receiver. Give every receiver the same new token tokenIds = new uint256[](1); require(uris.length <= 1 && (amounts.length == 1 || to.length == amounts.length), "Invalid input"); } else { // Single receiver. Generating multiple tokens tokenIds = new uint256[](amounts.length); require(uris.length == 0 || amounts.length == uris.length, "Invalid input"); } // Assign tokenIds for (uint i; i < tokenIds.length;) { ++_tokenCount; tokenIds[i] = _tokenCount; // Track the extension that minted the token _tokensExtension[_tokenCount] = extension; unchecked { ++i; } } if (extension != address(0)) { _checkMintPermissions(to, tokenIds, amounts); } if (to.length == 1 && tokenIds.length == 1) { // Single mint _mint(to[0], tokenIds[0], amounts[0], new bytes(0)); } else if (to.length > 1) { // Multiple receivers. Receiving the same token if (amounts.length == 1) { // Everyone receiving the same amount for (uint i; i < to.length;) { _mint(to[i], tokenIds[0], amounts[0], new bytes(0)); unchecked { ++i; } } } else { // Everyone receiving different amounts for (uint i; i < to.length;) { _mint(to[i], tokenIds[0], amounts[i], new bytes(0)); unchecked { ++i; } } } } else { _mintBatch(to[0], tokenIds, amounts, new bytes(0)); } for (uint i; i < tokenIds.length;) { if (i < uris.length && bytes(uris[i]).length > 0) { _tokenURIs[tokenIds[i]] = uris[i]; } unchecked { ++i; } } } /** * @dev Mint existing tokens */ function _mintExisting(address extension, address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) internal { if (extension != address(0)) { _checkMintPermissions(to, tokenIds, amounts); } if (to.length == 1 && tokenIds.length == 1 && amounts.length == 1) { // Single mint _mint(to[0], tokenIds[0], amounts[0], new bytes(0)); } else if (to.length == 1 && tokenIds.length == amounts.length) { // Batch mint to same receiver _mintBatch(to[0], tokenIds, amounts, new bytes(0)); } else if (tokenIds.length == 1 && amounts.length == 1) { // Mint of the same token/token amounts to various receivers for (uint i; i < to.length;) { _mint(to[i], tokenIds[0], amounts[0], new bytes(0)); unchecked { ++i; } } } else if (tokenIds.length == 1 && to.length == amounts.length) { // Mint of the same token with different amounts to different receivers for (uint i; i < to.length;) { _mint(to[i], tokenIds[0], amounts[i], new bytes(0)); unchecked { ++i; } } } else if (to.length == tokenIds.length && to.length == amounts.length) { // Mint of different tokens and different amounts to different receivers for (uint i; i < to.length;) { _mint(to[i], tokenIds[i], amounts[i], new bytes(0)); unchecked { ++i; } } } else { revert("Invalid input"); } } /** * @dev See {IERC1155CreatorCore-tokenExtension}. */ function tokenExtension(uint256 tokenId) public view virtual override returns (address extension) { extension = _tokenExtension(tokenId); require(extension != address(0), "No extension for token"); require(!_blacklistedExtensions.contains(extension), "Extension blacklisted"); } /** * @dev See {IERC1155CreatorCore-burn}. */ function burn(address account, uint256[] calldata tokenIds, uint256[] calldata amounts) public virtual override nonReentrant { require(account == msg.sender || isApprovedForAll(account, msg.sender), "Caller is not owner or approved"); require(tokenIds.length == amounts.length, "Invalid input"); if (tokenIds.length == 1) { _burn(account, tokenIds[0], amounts[0]); } else { _burnBatch(account, tokenIds, amounts); } _postBurn(account, tokenIds, amounts); } /** * @dev See {ICreatorCore-setRoyalties}. */ function setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired { _setRoyaltiesExtension(address(0), receivers, basisPoints); } /** * @dev See {ICreatorCore-setRoyalties}. */ function setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired { _setRoyalties(tokenId, receivers, basisPoints); } /** * @dev See {ICreatorCore-setRoyaltiesExtension}. */ function setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired { _setRoyaltiesExtension(extension, receivers, basisPoints); } /** * @dev See {ICreatorCore-getRoyalties}. */ function getRoyalties(uint256 tokenId) external view virtual override returns (address payable[] memory, uint256[] memory) { return _getRoyalties(tokenId); } /** * @dev See {ICreatorCore-getFees}. */ function getFees(uint256 tokenId) external view virtual override returns (address payable[] memory, uint256[] memory) { return _getRoyalties(tokenId); } /** * @dev See {ICreatorCore-getFeeRecipients}. */ function getFeeRecipients(uint256 tokenId) external view virtual override returns (address payable[] memory) { return _getRoyaltyReceivers(tokenId); } /** * @dev See {ICreatorCore-getFeeBps}. */ function getFeeBps(uint256 tokenId) external view virtual override returns (uint[] memory) { return _getRoyaltyBPS(tokenId); } /** * @dev See {ICreatorCore-royaltyInfo}. */ function royaltyInfo(uint256 tokenId, uint256 value) external view virtual override returns (address, uint256) { return _getRoyaltyInfo(tokenId, value); } /** * @dev See {IERC1155MetadataURI-uri}. */ function uri(uint256 tokenId) public view virtual override returns (string memory) { return _tokenURI(tokenId); } /** * @dev Total amount of tokens in with a given id. */ function totalSupply(uint256 tokenId) external view virtual override returns (uint256) { return _totalSupply[tokenId]; } /** * @dev See {ERC1155-_mint}. */ function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual override { super._mint(account, id, amount, data); _totalSupply[id] += amount; } /** * @dev See {ERC1155-_mintBatch}. */ function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual override { super._mintBatch(to, ids, amounts, data); for (uint i; i < ids.length;) { _totalSupply[ids[i]] += amounts[i]; unchecked { ++i; } } } /** * @dev See {ERC1155-_burn}. */ function _burn(address account, uint256 id, uint256 amount) internal virtual override { super._burn(account, id, amount); _totalSupply[id] -= amount; } /** * @dev See {ERC1155-_burnBatch}. */ function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual override { super._burnBatch(account, ids, amounts); for (uint i; i < ids.length;) { _totalSupply[ids[i]] -= amounts[i]; unchecked { ++i; } } } /** * @dev See {ICreatorCore-setApproveTransfer}. */ function setApproveTransfer(address extension) external override adminRequired { _setApproveTransferBase(extension); } }