// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../contracts/access/AccessControlEnumerable.sol"; import "../contracts/utils/Context.sol"; import "../contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "../contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "../contracts/access/Ownable.sol"; import "../contracts/token/ERC1155/ERC1155.sol"; import "../contracts/utils/math/SafeMath.sol"; import "../contracts/utils/Strings.sol"; //import "./ERC721TransferRole.sol"; interface IMetaRareERC721Collection { function initialize(string memory, string memory, string memory, address, address) external; } contract MetaRareERC721Collection is Context, AccessControlEnumerable, ERC721Enumerable, ERC721URIStorage { address public collectionFactory; address public MetaRareOperator; bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); string private _internalBaseURI; string private _customName; string private _customSymbol; constructor() public ERC721("initName", "initSymbol") { collectionFactory = msg.sender; } function initialize( string memory initName, string memory initSymbol, string memory baseURI, address collectionOwner, address operatorContract ) external { require(msg.sender == collectionFactory, 'ERC721: INITIALIZE FORBIDDEN'); _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); _setupRole(MINTER_ROLE, _msgSender()); _setupRole(MINTER_ROLE, collectionOwner); _setupRole(MINTER_ROLE, operatorContract); _internalBaseURI = baseURI; _customName = initName; _customSymbol = initSymbol; MetaRareOperator = operatorContract; } function burn(uint256 tokenId) public virtual { require( _isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved" ); _burn(tokenId); } function transferOnlyOperator( address from, address to, uint256 tokenId ) public virtual { require(msg.sender == MetaRareOperator, "Operatron only can use this function"); _transferOnlyOperator(from, to, tokenId); } function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, AccessControlEnumerable, ERC721) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } function setBaseURI(string memory newBaseUri) public { require( hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "ERC721: must have admin role to change baseUri" ); _internalBaseURI = newBaseUri; } function mint(address to, uint256 tokenId) public virtual { require( hasRole(MINTER_ROLE, _msgSender()), "ERC721: must have minter role to mint" ); _mint(to, tokenId); } function tokenURI(uint256 tokenId) public view virtual override(ERC721URIStorage, ERC721) returns (string memory) { return super.tokenURI(tokenId); } function _transferOnlyOperator( address from, address to, uint256 tokenId ) internal virtual { super._safeTransfer(from, to, tokenId, ""); } function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual override(ERC721, ERC721Enumerable) { super._beforeTokenTransfer(from, to, tokenId); } function _burn(uint256 tokenId) internal virtual override(ERC721, ERC721URIStorage) { super._burn(tokenId); } function _baseURI() internal view override returns (string memory) { return _internalBaseURI; } function setTokenURI(uint256 tokenId, string memory _tokenURI) public { require( hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "ERC721: must have admin role to set Token URIs" ); super._setTokenURI(tokenId, _tokenURI); } function setName(string memory newName) public { require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must have Admin role"); _customName = newName; } function setSymbol(string memory newSymbol) public { require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must have Admin role"); _customSymbol = newSymbol; } function name() public view override returns (string memory) { return _customName; } function symbol() public view override returns (string memory) { return _customSymbol; } } interface IMetaRareERC1155Collection { function initialize(string memory, string memory, string memory, address, address) external; } contract MetaRareERC1155Collection is ERC1155, Ownable { using Strings for string; using SafeMath for uint256; address public collectionFactory; address public MetaRareOperator; mapping (uint256 => address) public creators; mapping (uint256 => uint256) public tokenSupply; mapping (uint256 => string) public customUri; string public name; string public symbol; modifier creatorOnly(uint256 _id) { require(creators[_id] == _msgSender(), "ERC1155Tradable#creatorOnly: ONLY_CREATOR_ALLOWED"); _; } modifier ownersOnly(uint256 _id) { require(balanceOf(_msgSender(), _id) > 0, "ERC1155Tradable#ownersOnly: ONLY_OWNERS_ALLOWED"); _; } constructor() public ERC1155("_uri") { collectionFactory = msg.sender; } function initialize( string memory _name, string memory _symbol, string memory _uri, address collectionOwner, address operatorContract ) external { require(msg.sender == collectionFactory, 'ERC1155: INITIALIZE FORBIDDEN'); name = _name; symbol = _symbol; _setURI(_uri); MetaRareOperator = operatorContract; transferOwnership(collectionOwner); ERC1155.setApprovalForAll(operatorContract, true); } function transferOnlyOperator( address from, address to, uint256 tokenId, uint256 amount ) public virtual { require(msg.sender == MetaRareOperator, "Operatron only can use this function"); _transferOnlyOperator(from, to, tokenId, amount); } function uri( uint256 _id ) override public view returns (string memory) { require(_exists(_id), "ERC1155Tradable#uri: NONEXISTENT_TOKEN"); bytes memory customUriBytes = bytes(customUri[_id]); if (customUriBytes.length > 0) { return customUri[_id]; } else { return super.uri(_id); } } function totalSupply( uint256 _id ) public view returns (uint256) { return tokenSupply[_id]; } function setURI( string memory _newURI ) public onlyOwner { _setURI(_newURI); } function setCustomURI( uint256 _tokenId, string memory _newURI ) public creatorOnly(_tokenId) { customUri[_tokenId] = _newURI; emit URI(_newURI, _tokenId); } function create( address _initialOwner, uint256 _id, uint256 _initialSupply, string memory _uri, bytes memory _data ) public onlyOwner returns (uint256) { require(!_exists(_id), "token _id already exists"); creators[_id] = _msgSender(); if (bytes(_uri).length > 0) { customUri[_id] = _uri; emit URI(_uri, _id); } _mint(_initialOwner, _id, _initialSupply, _data); tokenSupply[_id] = _initialSupply; return _id; } function createByOperator( address _initialOwner, uint256 _id, uint256 _initialSupply, string memory _uri, bytes memory _data ) public returns (uint256) { require(msg.sender == MetaRareOperator, "Cannot called by not operator"); require(!_exists(_id), "token _id already exists"); creators[_id] = _initialOwner; if (bytes(_uri).length > 0) { customUri[_id] = _uri; emit URI(_uri, _id); } _mint(_initialOwner, _id, _initialSupply, _data); tokenSupply[_id] = _initialSupply; return _id; } function mint( address _to, uint256 _id, uint256 _quantity, bytes memory _data ) virtual public creatorOnly(_id) { _mint(_to, _id, _quantity, _data); tokenSupply[_id] = tokenSupply[_id].add(_quantity); } function batchMint( address _to, uint256[] memory _ids, uint256[] memory _quantities, bytes memory _data ) public { for (uint256 i = 0; i < _ids.length; i++) { uint256 _id = _ids[i]; require(creators[_id] == _msgSender(), "ERC1155Tradable#batchMint: ONLY_CREATOR_ALLOWED"); uint256 quantity = _quantities[i]; tokenSupply[_id] = tokenSupply[_id].add(quantity); } _mintBatch(_to, _ids, _quantities, _data); } function setCreator( address _to, uint256[] memory _ids ) public { require(_to != address(0), "ERC1155Tradable#setCreator: INVALID_ADDRESS."); for (uint256 i = 0; i < _ids.length; i++) { uint256 id = _ids[i]; _setCreator(_to, id); } } function isApprovedForAll( address _owner, address _operator ) override public view returns (bool isOperator) { return ERC1155.isApprovedForAll(_owner, _operator); } function _setCreator(address _to, uint256 _id) internal creatorOnly(_id) { creators[_id] = _to; } function _transferOnlyOperator( address from, address to, uint256 tokenId, uint256 amount ) internal virtual { super._safeTransferFrom(from, to, tokenId, amount, ""); } function _exists( uint256 _id ) internal view returns (bool) { return creators[_id] != address(0); } function exists( uint256 _id ) external view returns (bool) { return _exists(_id); } function _msgSender() internal override view returns (address sender) { return msg.sender; } } contract MetaRareCollectionFactory { uint256 private nonce; event CreateERC721Collection(address collection); event CreateERC1155Collection(address collection); constructor() { nonce = 0; } function CreateMetaRareERC721Collection(string memory name, string memory symbol, string memory baseURI, address OperatorContract) public { address addr = createERC721Contract(name, symbol, baseURI); IMetaRareERC721Collection(addr).initialize(name, symbol, baseURI, msg.sender, OperatorContract); emit CreateERC721Collection(addr); } function createERC721Contract(string memory name, string memory symbol, string memory baseURI) internal returns(address newAddr) { bytes memory bytecode = type(MetaRareERC721Collection).creationCode; bytes32 salt = keccak256(abi.encodePacked(name, symbol, baseURI, nonce)); nonce += 1; assembly { newAddr := create2(0, add(bytecode, 0x20), mload(bytecode), salt) if iszero(extcodesize(newAddr)) { revert(0, 0) } } } function CreateMetaRareERC1155Collection(string memory name, string memory symbol, string memory uri, address OperatorContract) public { address addr = createERC1155Contract(name, symbol, uri); IMetaRareERC1155Collection(addr).initialize(name, symbol, uri, msg.sender, OperatorContract); emit CreateERC1155Collection(addr); } function createERC1155Contract(string memory name, string memory symbol, string memory uri) internal returns(address newAddr) { bytes memory bytecode = type(MetaRareERC1155Collection).creationCode; bytes32 salt = keccak256(abi.encodePacked(name, symbol, uri, nonce)); nonce += 1; assembly { newAddr := create2(0, add(bytecode, 0x20), mload(bytecode), salt) if iszero(extcodesize(newAddr)) { revert(0, 0) } } } }