// 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/ERC1155/IERC1155.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "../HasSignature.sol"; interface IMintableERC1155 is IERC1155 { function mintBatch( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) external; function mint( address to, uint256 id, uint256 amount, bytes memory data ) external; function burn( address owner, uint256 tokenId, uint256 amount ) external; function exists(uint256 id) external view returns (bool); } interface IBurnableERC721 is IERC721 { function burn(address owner, uint256 tokenId) external; } contract BEChipFactory is Ownable, Initializable, HasSignature { IMintableERC1155 public chip; IBurnableERC721 public chipOld; address public executor; mapping(bytes => bool) public usedSignatures; event Chip1155Minted( address contractAddress, address indexed to, uint256[] ids ); event Chip1155Activate( address indexed to, uint256 indexed nftOld, uint256 nftNew ); constructor() HasSignature("BEChipFactory", "1") {} function init(address _erc1155, address _erc721) external initializer onlyOwner { chip = IMintableERC1155(_erc1155); chipOld = IBurnableERC721(_erc721); } /** * @dev update executor */ function updateExecutor(address account) external onlyOwner { require(account != address(0), "address can not be zero"); executor = account; } function mintChipTo( address to, uint256[] memory ids ) external onlyOwner { require(to != address(0), "BEChipFactory: to address can not be zero"); require(ids.length > 0, "BEChipFactory: 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; } chip.mintBatch(to, ids, amounts, ""); emit Chip1155Minted(address(chip), to, ids); } function mintChipSelf( uint256[] memory ids, uint256 saltNonce, bytes calldata signature ) external{ require(ids.length > 0, "BEChipFactory: ids cannot be empty"); require( !usedSignatures[signature], "BEChipFactory:: mintChipSelf: signature used. please send another transaction with new signature" ); address to = _msgSender(); bytes32 criteriaMessageHash = getMessageHash( to, saltNonce, ids ); checkSigner(executor, criteriaMessageHash, signature); uint256[] memory amounts = new uint256[](ids.length); uint256 len = ids.length; for (uint256 i = 0; i < len; ++i) { amounts[i] = 1; } chip.mintBatch(to, ids, amounts, ""); usedSignatures[signature] = true; emit Chip1155Minted(address(chip), to, ids); } function activateOneChip( uint256[] memory ids, uint256 saltNonce, bytes calldata signature ) external{ require(ids.length == 2, "BEChipFactory: ids length mismatch"); require( !usedSignatures[signature], "BEChipFactory:: activateOneChip: signature used. please send another transaction with new signature" ); address to = _msgSender(); require( chipOld.ownerOf(ids[1]) == to, "BEChipFactory: only owner can activate this nft" ); require( !chip.exists(ids[0]), "BEChipFactory: 1155 nftid duplicated" ); bytes32 criteriaMessageHash = getMessageHash( to, saltNonce, ids ); checkSigner(executor, criteriaMessageHash, signature); usedSignatures[signature] = true; chip.mint(to, ids[0], 1, ""); chipOld.burn(to, ids[1]); emit Chip1155Activate(to, ids[1], ids[0]); } 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); } }