diff --git a/contracts/interfaces/IBEERC1155.sol b/contracts/interfaces/IBEERC1155.sol index 1bc4524..a120830 100644 --- a/contracts/interfaces/IBEERC1155.sol +++ b/contracts/interfaces/IBEERC1155.sol @@ -17,5 +17,7 @@ interface IBEERC1155 is IERC1155 { uint256[] memory values ) external; + function balanceOf(address account, uint256 id) external view returns (uint256); + function canMint(uint256 id) external view returns (bool); } diff --git a/contracts/interfaces/IBEERC721.sol b/contracts/interfaces/IBEERC721.sol index ab9fbf7..2887012 100644 --- a/contracts/interfaces/IBEERC721.sol +++ b/contracts/interfaces/IBEERC721.sol @@ -8,4 +8,5 @@ import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; interface IBEERC721 is IERC721 { function mint(address to, uint256 tokenId) external; function burn(address owner, uint256 tokenId) external; -} \ No newline at end of file + function ownerOf(uint256 tokenId) external view returns (address owner); +} diff --git a/contracts/interfaces/IEvolveFactory.sol b/contracts/interfaces/IEvolveFactory.sol new file mode 100644 index 0000000..af350ca --- /dev/null +++ b/contracts/interfaces/IEvolveFactory.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.10; +import "../interfaces/IBEERC721.sol"; +import "../interfaces/IBEERC1155.sol"; + +interface IEvolveFactory { + function evolve721NFT( + address to, + uint256[3] calldata tokenIds, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature, + IBEERC721 nft + ) external; + + function evolveChip( + address to, + uint256[] memory tokenIds, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature + ) external; + + function useSignature( + bytes calldata signature + ) external; +} diff --git a/contracts/logic/EvolveFactory.sol b/contracts/logic/EvolveFactory.sol index 4776df3..5526211 100644 --- a/contracts/logic/EvolveFactory.sol +++ b/contracts/logic/EvolveFactory.sol @@ -13,110 +13,134 @@ import "../core/HasSignature.sol"; // all onlyowner method would add timelock contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature { - using UInt for uint256; - IBEERC721 public hero; - IBEERC721 public equip; - IBEERC1155 public chip; - uint256 private _duration; + using UInt for uint256; + IBEERC721 public hero; + IBEERC721 public equip; + IBEERC1155 public chip; - address public executor; + address public executor; - event TokenEvolved( - address indexed owner, - uint256[3] tokenIds + event TokenEvolved( + address indexed owner, + uint256[] tokenIds + ); + + constructor() + HasSignature("EvolveFactory", "1"){ + } + + function init(address[3] calldata _erc721s) external initializer onlyOwner { + hero = IBEERC721(_erc721s[0]); + equip = IBEERC721(_erc721s[1]); + chip = IBEERC1155(_erc721s[2]); + } + + /** + * @dev update executor + */ + function updateExecutor(address account) external onlyOwner { + require(account != address(0), 'address can not be zero'); + executor = account; + } + + function evolve721NFT( + address to, + uint256[3] calldata tokenIds, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature, + IBEERC721 nft + ) external signatureValid(signature) timeValid(startTime){ + require( + tokenIds[0] > 0 && tokenIds[1] > 0, + "EvolveFactory: token to evolve and burn can not be 0" ); - constructor() - HasSignature("EvolveFactory", "1"){ + require( + tokenIds[0] != tokenIds[1], + "EvolveFactory: token to evolve and burn can not be same" + ); + + require( + nft.ownerOf(tokenIds[0]) == to && nft.ownerOf(tokenIds[1]) == to, + "EvolveFactory: current address is not owner of this nft now" + ); + if (tokenIds[2] > 0) { + require( + chip.balanceOf(to, tokenIds[2]) > 0, + "EvolveFactory: not enough chip" + ); } - function init(address[3] calldata _erc721s) external initializer onlyOwner { - hero = IBEERC721(_erc721s[0]); - equip = IBEERC721(_erc721s[1]); - chip = IBEERC1155(_erc721s[2]); + uint256[] memory signArray = new uint256[](3); + for (uint256 i = 0; i < tokenIds.length; ++ i) { + uint256 _id = tokenIds[i]; + signArray[i] = _id; } - - /** - * @dev update executor - */ - function updateExecutor(address account) external onlyOwner { - require(account != address(0), 'address can not be zero'); - executor = account; + bytes32 criteriaMessageHash = getMessageHash( + to, + startTime, + saltNonce, + signArray + ); + checkSigner(executor, criteriaMessageHash, signature); + nft.burn(to, tokenIds[1]); + if (tokenIds[2] > 0) { + uint256 amount = 1; + chip.burnBatch(to, + tokenIds[2].asSingletonArray(), + amount.asSingletonArray()); } + useSignature(signature); + emit TokenEvolved( + to, + signArray + ); + } - function evolve721NFT( - address to, - uint256[3] calldata tokenIds, - uint256 startTime, - uint256 saltNonce, - bytes calldata signature, - IBEERC721 nft - ) internal signatureValid(signature) timeValid(startTime){ - require( - tokenIds[0] > 0 && tokenIds[1] > 0, - "EvolveFactory: equip to evolve and burn can not be 0" - ); - - require( - tokenIds[0] != tokenIds[1], - "EvolveFactory: equip to evolve and burn can not be same" - ); - - require( - nft.ownerOf(tokenIds[0]) == to, - "EvolveFactory: current address is not owner of this nft now" - ); - - require( - nft.ownerOf(tokenIds[1]) == to, - "EvolveFactory: current address is not owner of this nft now" - ); - if (tokenIds[2] > 0) { - require( - nft.ownerOf(tokenIds[2]) == to, - "EvolveFactory: current address is not owner of this nft now" - ); - } - - uint256[] memory signArray = new uint256[](3); - for (uint256 i = 0; i < tokenIds.length; ++ i) { - signArray[i] = tokenIds[i]; - } - bytes32 criteriaMessageHash = getMessageHash( - to, - startTime, - saltNonce, - signArray - ); - checkSigner(executor, criteriaMessageHash, signature); - nft.burn(to, tokenIds[1]); - if (tokenIds[2] > 0) { - uint256 amount = 1; - chip.burnBatch(to, - tokenIds[2].asSingletonArray(), - amount.asSingletonArray()); - } - useSignature(signature); - emit TokenEvolved( - to, - tokenIds - ); + function evolveChip( + address to, + uint256[] memory tokenIds, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature + ) external signatureValid(signature) timeValid(startTime){ + require(to != address(0), "EvolveFacrory: address is zero address"); + uint256 len = tokenIds.length; + uint256[] memory amounts = new uint256[](len -1); + uint256[] memory idsForBurn = new uint256[](len - 1); + for (uint256 i = 0; i < len; ++ i) { + require( + chip.balanceOf(to, tokenIds[i]) > 0, + "EvolveFacrory: Chip specified not exists" + ); + if (i > 0) { + idsForBurn[i - 1] = tokenIds[i]; + amounts[i - 1] = 1; + } } + bytes32 criteriaMessageHash = getMessageHash(to, startTime, saltNonce, tokenIds); + checkSigner(executor, criteriaMessageHash, signature); + chip.burnBatch(to, idsForBurn, amounts); + useSignature(signature); + emit TokenEvolved( + to, + tokenIds + ); + } - - - function getMessageHash( - address _to, - uint256 _startTime, - uint256 _saltNonce, - uint256[] memory _ids - ) public pure returns (bytes32) { - bytes memory encoded = abi.encodePacked(_to, _startTime, _saltNonce); - uint256 len = _ids.length; - for (uint256 i = 0; i < len; ++i) { - encoded = bytes.concat(encoded, abi.encodePacked(_ids[i])); - } - return keccak256(encoded); + function getMessageHash( + address _to, + uint256 _startTime, + uint256 _saltNonce, + uint256[] memory _ids + ) public pure returns (bytes32) { + bytes memory encoded = abi.encodePacked(_to, _startTime, _saltNonce); + uint256 len = _ids.length; + for (uint256 i = 0; i < len; ++i) { + encoded = bytes.concat(encoded, abi.encodePacked(_ids[i])); } + return keccak256(encoded); + } } diff --git a/contracts/logic/UserEvolveFactory.sol b/contracts/logic/UserEvolveFactory.sol index 9a76563..176d82e 100644 --- a/contracts/logic/UserEvolveFactory.sol +++ b/contracts/logic/UserEvolveFactory.sol @@ -2,47 +2,138 @@ pragma solidity 0.8.10; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import "../interfaces/INFTFactory.sol"; +import "../interfaces/IEvolveFactory.sol"; import "../interfaces/IBEERC721.sol"; import "../interfaces/IBEERC1155.sol"; contract UserEvolveFactory is Ownable, Initializable { + IEvolveFactory factory; IBEERC721 public hero; IBEERC721 public equip; IBEERC1155 public chip; - IBEERC1155 public shard; event TokenEvolveFail ( address indexed to, - uint256 mainToken, bytes signature, string reason, bytes byteReason ); - function init() external initializer onlyOwner { + function init(address[3] calldata _nfts) external initializer onlyOwner { + hero = IBEERC721(_nfts[0]); + equip = IBEERC721(_nfts[1]); + chip = IBEERC1155(_nfts[2]); } /** - * @dev evolve function to Blissful Elites Hero NFT + * @dev evolve function Hero NFT * tokenIds: [hero_to_evolve, hero_for_burn, chip] */ function evolveHero( uint256[3] calldata tokenIds, + uint256 startTime, uint256 saltNonce, bytes calldata signature - ) external { - + ) external returns (bool success){ + address to = _msgSender(); + try factory.evolve721NFT(to, tokenIds, startTime, saltNonce, signature, hero) { + return true; + } catch Error(string memory reason) { + bytes memory by; + factory.useSignature(signature); + emit TokenEvolveFail( + to, + signature, + reason, + by + ); + return false; + } catch (bytes memory lowLevelData) { + factory.useSignature(signature); + string memory reason; + emit TokenEvolveFail( + to, + signature, + reason, + lowLevelData + ); + return false; + } } /** - * @dev evolve function to Blissful Elites Equip NFT + * @dev evolve function for equip NFT * tokenIds: [equip_to_evolve, equip_for_burn, chip] */ function evolveEquip( uint256[3] calldata tokenIds, + uint256 startTime, uint256 saltNonce, bytes calldata signature - ) external{ + ) external returns (bool success){ + address to = _msgSender(); + try factory.evolve721NFT(to, tokenIds, startTime, saltNonce, signature, equip) { + return true; + } catch Error(string memory reason) { + bytes memory by; + factory.useSignature(signature); + emit TokenEvolveFail( + to, + signature, + reason, + by + ); + return false; + } catch (bytes memory lowLevelData) { + factory.useSignature(signature); + string memory reason; + emit TokenEvolveFail( + to, + signature, + reason, + lowLevelData + ); + return false; + } } + /** + * @dev evolve function for chip + */ + function evolveChip( + uint256[] memory ids, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature + ) external returns (bool success){ + address to = _msgSender(); + try factory.evolveChip( + to, + ids, + startTime, + saltNonce, + signature + ) { + return true; + } catch Error(string memory reason) { + bytes memory by; + factory.useSignature(signature); + emit TokenEvolveFail( + to, + signature, + reason, + by + ); + return false; + } catch (bytes memory lowLevelData) { + factory.useSignature(signature); + string memory reason; + emit TokenEvolveFail( + to, + signature, + reason, + lowLevelData + ); + return false; + } + } } diff --git a/contracts/logic/UserMinterFactory.sol b/contracts/logic/UserMinterFactory.sol index d717492..c024ec0 100644 --- a/contracts/logic/UserMinterFactory.sol +++ b/contracts/logic/UserMinterFactory.sol @@ -174,7 +174,18 @@ contract UserMinterFactory is Ownable, Initializable { ); return false; } - } + /** + * @dev mint hero or equip with shard + */ + function shardMixByUser( + uint256[] memory ids, + uint256[] memory amounts, + uint256 startTime, + uint256 saltNonce, + bytes calldata signature + ) external returns (bool success) { + return true; + } }