// 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 "../HasSignature.sol"; interface IMintableERC721 is IERC721 { function mint(address to, uint256 tokenId) external; function burn(address owner, uint256 tokenId) external; } contract NFTActivateProxy is Ownable, Initializable, HasSignature { uint256 private constant MINI_GEN_NFT_ID = 1e17; uint256 private constant MAX_GAME_NFT_ID = 9 * 1e15; IMintableERC721 public hero; IMintableERC721 public equip; IMintableERC721 public chip; uint256 public constant TYPE_NONE = 0; uint256 public constant TYPE_HERO = 1; uint256 public constant TYPE_EQUIP = 2; uint256 public constant TYPE_CHIP = 3; address public executor; mapping(bytes => bool) public usedSignatures; event LogNFTActivate( address indexed to, uint256 indexed nftOld, uint256 nftNew, uint256 nftType ); constructor() HasSignature("NFTActivateProxy", "1") {} function init(address[3] calldata _erc721s) external initializer onlyOwner { hero = IMintableERC721(_erc721s[0]); equip = IMintableERC721(_erc721s[1]); chip = IMintableERC721(_erc721s[2]); } /** * @dev update executor */ function updateExecutor(address account) external onlyOwner { require(account != address(0), "address can not be zero"); executor = account; } function activateOne( uint256 nftOld, uint256 nftNew, uint256 nftType, uint256 saltNonce, bytes calldata signature ) external { require( nftOld >= MINI_GEN_NFT_ID, "NFTActivateProxy: GEN nftid must greater than 1e18" ); require( nftNew < MAX_GAME_NFT_ID, "NFTActivateProxy: Game nftid must less than 9 * 1e15" ); require(nftType > 0, "NFTActivateProxy: nft type must greater than 0"); require(nftType < 4, "NFTActivateProxy: nft type must less than 4"); require( !usedSignatures[signature], "NFTActivateProxy: signature used. please send another transaction with new signature" ); address owner = msg.sender; IMintableERC721 nft721 = getIMintableERC721ByType(nftType); require( nft721.ownerOf(nftOld) == owner, "NFTActivateProxy: only owner can activate this nft" ); bytes32 criteriaMessageHash = getMessageHash( owner, nftOld, nftNew, nftType, saltNonce ); checkSigner(executor, criteriaMessageHash, signature); // activate the old nft nft721.burn(owner, nftOld); usedSignatures[signature] = true; nft721.mint(owner, nftNew); emit LogNFTActivate(owner, nftOld, nftNew, nftType); } function getIMintableERC721ByType(uint256 nftType) private view returns (IMintableERC721) { if (nftType == TYPE_HERO) { return hero; } else if (nftType == TYPE_EQUIP) { return equip; } else { return chip; } } function getMessageHash( address _owner, uint256 _nftOld, uint256 _nftNew, uint256 _nftType, uint256 _saltNonce ) public pure returns (bytes32) { return keccak256( abi.encodePacked(_owner, _nftOld, _nftNew, _nftType, _saltNonce) ); } }