// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "../interfaces/IBEERC721.sol"; import "../interfaces/IBEERC1155.sol"; import "../core/HasSignature.sol"; contract MinterFactory is Ownable, Initializable, HasSignature { address public executor; // NFT contract IBEERC721 public hero; IBEERC721 public equip; IBEERC1155 public chip; IBEERC1155 public shard; event TokenMinted( address contractAddress, address to, uint256 indexed tokenId ); event TokenMintedBatch( address contractAddress, address indexed to, uint256[] ids, uint256[] amounts ); mapping(bytes => bool) public usedSignatures; constructor() HasSignature("MinterFactory", "1") {} function init(address[4] calldata _erc721s) external initializer onlyOwner { hero = IBEERC721(_erc721s[0]); equip = IBEERC721(_erc721s[1]); chip = IBEERC1155(_erc721s[2]); shard = IBEERC1155(_erc721s[3]); } /** * @dev update executor */ function updateExecutor(address account) external onlyOwner { require(account != address(0), "address can not be zero"); executor = account; } /** * @dev mint function to distribute Hero NFT to user */ function mintHeroTo(address to, uint256 tokenId) external onlyOwner { mint721NFT(to, tokenId, hero); } /** * @dev mint function to distribute Equipment NFT to user */ function mintEquipTo(address to, uint256 tokenId) external onlyOwner { mint721NFT(to, tokenId, equip); } /** * @dev mint function to distribute Chip NFT to user */ function mintChipTo(address to, uint256 tokenId) external onlyOwner { mint1155NFT(to, tokenId, 1, chip); } /** * @dev mint function to distribute Shard NFT to user */ function mintShardTo(address to, uint256 tokenId) external onlyOwner { mint1155NFT(to, tokenId, 1, shard); } /** * @dev batch mint 1155 Chip to user */ function mintChipBatch(address to, uint256[] memory ids) external onlyOwner { require( to != address(0), "MinterFactory::mintChipBatch: to address can not be zero" ); require( ids.length > 0, "MinterFactory::mintChipBatch: ids cannot be empty" ); uint256[] memory amounts = new uint256[](ids.length); uint256 len = ids.length; for (uint256 i = 0; i < len; ++i) { amounts[i] = 1; } mint1155NFTBatch(to, ids, amounts, chip); } /** * @dev batch mint 1155 Shard to user */ function mintShardBatch( address to, uint256[] memory ids, uint256[] memory amounts ) external onlyOwner { require(to != address(0), "MinterFactory: to address can not be zero"); require(ids.length > 0, "MinterFactory: ids cannot be empty"); require( ids.length == amounts.length, "MinterFactory: ids and amounts length mismatch" ); mint1155NFTBatch(to, ids, amounts, chip); } /** * @dev user mint hero */ function mintHeroUser( uint256 tokenId, uint256 saltNonce, bytes calldata signature ) external { mint721NFTUser(tokenId, saltNonce, signature, hero); } /** * @dev user mint equip */ function mintEquipUser( uint256 tokenId, uint256 saltNonce, bytes calldata signature ) external { mint721NFTUser(tokenId, saltNonce, signature, equip); } /** * @dev user batch mint 1155 chip */ function mintChipBatchUser( uint256[] memory ids, uint256 saltNonce, bytes calldata signature ) external { uint256[] memory amounts = new uint256[](ids.length); uint256 len = ids.length; for (uint256 i = 0; i < len; ++i) { amounts[i] = 1; } mint1155NFTBatchUser(ids, amounts, saltNonce, signature, chip); } /** * @dev user batch mint 1155 shard */ function mintShardBatchUser( uint256[] memory ids, uint256[] memory amounts, uint256 saltNonce, bytes calldata signature ) external { mint1155NFTBatchUser(ids, amounts, saltNonce, signature, shard); } function mint721NFTUser( uint256 id, uint256 saltNonce, bytes calldata signature, IBEERC721 nft ) internal { require( !usedSignatures[signature], "MinterFactory: signature used. please send another transaction with new signature" ); address to = _msgSender(); uint256[] memory signArray = new uint256[](1); signArray[0] = id; bytes32 criteriaMessageHash = getMessageHash(to, saltNonce, signArray); checkSigner(executor, criteriaMessageHash, signature); mint721NFT(to, id, nft); usedSignatures[signature] = true; } function mint1155NFTBatchUser( uint256[] memory ids, uint256[] memory amounts, uint256 saltNonce, bytes calldata signature, IBEERC1155 nft ) internal { uint256 len = ids.length; require(len > 0, "MinterFactory: ids cannot be empty"); require( len == amounts.length, "MinterFactory: ids and amounts length mismatch" ); require( !usedSignatures[signature], "MinterFactory: signature used. please send another transaction with new signature" ); address to = _msgSender(); uint256[] memory signArray = new uint256[](len * 2); for (uint256 i = 0; i < len; ++i) { signArray[i * 2] = ids[i]; signArray[i * 2 + 1] = amounts[i]; } bytes32 criteriaMessageHash = getMessageHash(to, saltNonce, signArray); checkSigner(executor, criteriaMessageHash, signature); mint1155NFTBatch(to, ids, amounts, nft); usedSignatures[signature] = true; } function mint721NFT( address to, uint256 tokenId, IBEERC721 nft ) internal { require(to != address(0), "MinterFactory: to address can not be zero"); nft.mint(to, tokenId); emit TokenMinted(address(nft), to, tokenId); } function mint1155NFT( address to, uint256 id, uint256 amount, IBEERC1155 nft ) internal { require(to != address(0), "MinterFactory: to address can not be zero"); nft.mint(to, id, amount, ""); emit TokenMinted(address(chip), to, id); } function mint1155NFTBatch( address to, uint256[] memory ids, uint256[] memory amounts, IBEERC1155 nft ) internal { nft.mintBatch(to, ids, amounts, ""); emit TokenMintedBatch(address(nft), to, ids, amounts); } function getMessageHash( address _to, uint256 _saltNonce, uint256[] memory _ids ) public pure returns (bytes32) { bytes memory encoded = abi.encodePacked(_to, _saltNonce); uint256 len = _ids.length; for (uint256 i = 0; i < len; ++i) { encoded = bytes.concat(encoded, abi.encodePacked(_ids[i])); } return keccak256(encoded); } }