becrypto/contracts/logic/EvolveFactory.sol
2022-11-01 10:28:59 +08:00

137 lines
3.9 KiB
Solidity

// 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 "../utils/UInt.sol";
import "../utils/TimeChecker.sol";
import "../core/HasSignature.sol";
// this contract will transfer ownership to BETimelockController after deployed
// all onlyowner method would add timelock
contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature {
using UInt for uint256;
IBEERC1155 public chip;
address public executor;
mapping(address => bool) public nftTokenSupported;
event TokenEvolved(
address indexed owner,
uint256 indexed nonce,
uint256[] tokenIds
);
constructor() HasSignature("EvolveFactory", "1") {}
function init(address chipAddress) external initializer onlyOwner {
chip = IBEERC1155(chipAddress);
}
/**
* @dev update executor
*/
function updateExecutor(address account) external onlyOwner {
require(account != address(0), "address can not be zero");
executor = account;
}
function addNFTTokenSupport(address nftToken) external onlyOwner {
nftTokenSupported[nftToken] = true;
}
function removeNFTTokenSupport(address nftToken) external onlyOwner {
nftTokenSupported[nftToken] = false;
}
function evolve721NFT(
address to,
address nftAddress,
uint256[2] calldata tokenIds,
uint256 startTime,
uint256 saltNonce,
bytes calldata signature
) external signatureValid(signature) timeValid(startTime) {
require(
tokenIds[0] > 0 && tokenIds[1] > 0,
"EvolveFactory: token to evolve and burn can not be 0"
);
require(
tokenIds[0] != tokenIds[1],
"EvolveFactory: token to evolve and burn can not be same"
);
require(nftTokenSupported[nftAddress], "EvolveFactory: Unsupported NFT");
IBEERC721 nft = IBEERC721(nftAddress);
require(
nft.ownerOf(tokenIds[0]) == to && nft.ownerOf(tokenIds[1]) == to,
"EvolveFactory: current address is not owner of this nft now"
);
uint256[] memory signArray = new uint256[](2);
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]);
_useSignature(signature);
emit TokenEvolved(to, saltNonce, signArray);
}
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, saltNonce, 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);
}
}