137 lines
3.9 KiB
Solidity
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);
|
|
}
|
|
}
|