317 lines
8.6 KiB
Solidity
317 lines
8.6 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/ERC20/utils/SafeERC20.sol";
|
|
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import "../interfaces/IBEERC721.sol";
|
|
import "../interfaces/IBEERC1155.sol";
|
|
import "../utils/UInt.sol";
|
|
import "../utils/TimeChecker.sol";
|
|
import "../core/HasSignature.sol";
|
|
import "./FactoryBase.sol";
|
|
|
|
contract MinterFactory is
|
|
Ownable,
|
|
FactoryBase,
|
|
TimeChecker,
|
|
Initializable,
|
|
HasSignature
|
|
{
|
|
using UInt for uint256;
|
|
using SafeERC20 for IERC20;
|
|
address public executor;
|
|
// NFT contract
|
|
IBEERC721 public hero;
|
|
IBEERC721 public equip;
|
|
IBEERC1155 public chip;
|
|
IBEERC1155 public shard;
|
|
|
|
address public feeToAddress;
|
|
|
|
event TokenMinted(
|
|
address contractAddress,
|
|
address indexed to,
|
|
uint256 indexed nonce,
|
|
uint256 indexed tokenId
|
|
);
|
|
|
|
event TokenMintedBatch(
|
|
address contractAddress,
|
|
address indexed to,
|
|
uint256 indexed nonce,
|
|
uint256[] ids,
|
|
uint256[] amounts
|
|
);
|
|
|
|
constructor() HasSignature("MinterFactory", "1") {}
|
|
|
|
function init(address[4] calldata _erc721s) external initializer onlyOwner {
|
|
hero = IBEERC721(_erc721s[0]);
|
|
equip = IBEERC721(_erc721s[1]);
|
|
chip = IBEERC1155(_erc721s[2]);
|
|
shard = IBEERC1155(_erc721s[3]);
|
|
}
|
|
|
|
/**
|
|
* @dev update executor
|
|
*/
|
|
function updateExecutor(address account) external onlyOwner {
|
|
require(account != address(0), "address can not be zero");
|
|
executor = account;
|
|
}
|
|
|
|
function setFeeToAddress(address _feeToAddress) external onlyOwner {
|
|
require(
|
|
_feeToAddress != address(0),
|
|
"fee received address can not be zero"
|
|
);
|
|
feeToAddress = _feeToAddress;
|
|
}
|
|
|
|
/**
|
|
* @dev mint function to distribute Hero NFT to user
|
|
*/
|
|
function mintHeroTo(address to, uint256 tokenId, uint256 nonce) external onlyOwner {
|
|
mint721NFT(to, tokenId, nonce, hero);
|
|
}
|
|
|
|
/**
|
|
* @dev mint function to distribute Equipment NFT to user
|
|
*/
|
|
function mintEquipTo(address to, uint256 tokenId, uint256 nonce) external onlyOwner {
|
|
mint721NFT(to, tokenId, nonce, equip);
|
|
}
|
|
|
|
/**
|
|
* @dev mint function to distribute Chip NFT to user
|
|
*/
|
|
function mintChipTo(address to, uint256 tokenId, uint256 nonce) external onlyOwner {
|
|
mint1155NFT(to, tokenId, nonce, 1, chip);
|
|
}
|
|
|
|
/**
|
|
* @dev mint function to distribute Shard NFT to user
|
|
*/
|
|
function mintShardTo(address to, uint256 tokenId, uint256 nonce) external onlyOwner {
|
|
mint1155NFT(to, tokenId, nonce, 1, shard);
|
|
}
|
|
|
|
/**
|
|
* @dev batch mint 1155 Chip to user
|
|
*/
|
|
function mintChipBatch(address to, uint256[] memory ids, uint256 nonce) external onlyOwner {
|
|
require(
|
|
to != address(0),
|
|
"MinterFactory::mintChipBatch: to address can not be zero"
|
|
);
|
|
require(
|
|
ids.length > 0,
|
|
"MinterFactory::mintChipBatch: 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;
|
|
}
|
|
mint1155NFTBatch(to, nonce, ids, amounts, chip);
|
|
}
|
|
|
|
/**
|
|
* @dev batch mint 1155 Shard to user
|
|
*/
|
|
function mintShardBatch(
|
|
address to,
|
|
uint256 nonce,
|
|
uint256[] memory ids,
|
|
uint256[] memory amounts
|
|
) external onlyOwner {
|
|
require(to != address(0), "MinterFactory: to address can not be zero");
|
|
require(ids.length > 0, "MinterFactory: ids cannot be empty");
|
|
require(
|
|
ids.length == amounts.length,
|
|
"MinterFactory: ids and amounts length mismatch"
|
|
);
|
|
mint1155NFTBatch(to, nonce, ids, amounts, shard);
|
|
}
|
|
|
|
function mint721ByUser(
|
|
address to,
|
|
uint256 id,
|
|
uint256 startTime,
|
|
uint256 saltNonce,
|
|
bytes calldata signature,
|
|
IBEERC721 nft
|
|
) external signatureValid(signature) timeValid(startTime) {
|
|
uint256[] memory signArray = new uint256[](1);
|
|
signArray[0] = id;
|
|
bytes32 criteriaMessageHash = getMessageHash(
|
|
to,
|
|
address(nft),
|
|
startTime,
|
|
saltNonce,
|
|
signArray
|
|
);
|
|
checkSigner(executor, criteriaMessageHash, signature);
|
|
mint721NFT(to, id, saltNonce, nft);
|
|
_useSignature(signature);
|
|
}
|
|
|
|
function mint1155BatchByUser(
|
|
address to,
|
|
uint256[] memory ids,
|
|
uint256[] memory amounts,
|
|
uint256 startTime,
|
|
uint256 saltNonce,
|
|
bytes calldata signature,
|
|
IBEERC1155 nft
|
|
) external signatureValid(signature) timeValid(startTime) {
|
|
uint256 len = ids.length;
|
|
require(len > 0, "MinterFactory: ids cannot be empty");
|
|
require(
|
|
len == amounts.length,
|
|
"MinterFactory: ids and amounts length mismatch"
|
|
);
|
|
uint256[] memory signArray = new uint256[](len * 2);
|
|
for (uint256 i = 0; i < len; ++i) {
|
|
require(
|
|
nft.canMint(ids[i]),
|
|
"MinterFactory: can not mint for current nft rule setting"
|
|
);
|
|
signArray[i * 2] = ids[i];
|
|
signArray[i * 2 + 1] = amounts[i];
|
|
}
|
|
bytes32 criteriaMessageHash = getMessageHash(
|
|
to,
|
|
address(nft),
|
|
startTime,
|
|
saltNonce,
|
|
signArray
|
|
);
|
|
checkSigner(executor, criteriaMessageHash, signature);
|
|
mint1155NFTBatch(to, saltNonce, ids, amounts, nft);
|
|
_useSignature(signature);
|
|
}
|
|
|
|
function shardMixByUser(
|
|
ShardParam memory param,
|
|
uint256[] memory ids,
|
|
uint256[] memory amounts,
|
|
bytes calldata signature,
|
|
IBEERC721 nft
|
|
) external signatureValid(signature) timeValid(param.startTime) {
|
|
require(ids.length > 0, "MinterFactory: ids cannot be empty");
|
|
require(
|
|
ids.length == amounts.length,
|
|
"MinterFactory: ids and amounts length mismatch"
|
|
);
|
|
|
|
uint256[] memory signArray = new uint256[](ids.length * 2);
|
|
for (uint256 i = 0; i < ids.length; ++i) {
|
|
require(
|
|
shard.balanceOf(param.to, ids[i]) > 0,
|
|
"MinterFactory: not enough shard"
|
|
);
|
|
signArray[i * 2] = ids[i];
|
|
signArray[i * 2 + 1] = amounts[i];
|
|
}
|
|
bytes32 criteriaMessageHash = getShardMixHash(
|
|
param,
|
|
address(nft),
|
|
signArray
|
|
);
|
|
checkSigner(executor, criteriaMessageHash, signature);
|
|
// Check payment approval and buyer balance
|
|
IERC20 paymentContract = IERC20(param.payToken);
|
|
require(
|
|
paymentContract.balanceOf(param.to) >= param.payAmount,
|
|
"MinterFactory: doesn't have enough token to mix shard"
|
|
);
|
|
require(
|
|
paymentContract.allowance(param.to, address(this)) >= param.payAmount,
|
|
"MinterFactory: doesn't approve MinterFactory to spend payment amount"
|
|
);
|
|
// transfer money to address
|
|
paymentContract.safeTransferFrom(param.to, feeToAddress, param.payAmount);
|
|
shard.burnBatch(param.to, ids, amounts);
|
|
mint721NFT(param.to, param.nftId, param.saltNonce, nft);
|
|
_useSignature(signature);
|
|
}
|
|
|
|
function mint721NFT(
|
|
address to,
|
|
uint256 tokenId,
|
|
uint256 nonce,
|
|
IBEERC721 nft
|
|
) internal {
|
|
require(to != address(0), "MinterFactory: to address can not be zero");
|
|
nft.mint(to, tokenId);
|
|
emit TokenMinted(address(nft), to, nonce, tokenId);
|
|
}
|
|
|
|
function mint1155NFT(
|
|
address to,
|
|
uint256 id,
|
|
uint256 nonce,
|
|
uint256 amount,
|
|
IBEERC1155 nft
|
|
) internal {
|
|
require(to != address(0), "MinterFactory: to address can not be zero");
|
|
nft.mintBatch(to, id.asSingletonArray(), amount.asSingletonArray(), "");
|
|
emit TokenMinted(address(chip), to, nonce, id);
|
|
}
|
|
|
|
function mint1155NFTBatch(
|
|
address to,
|
|
uint256 nonce,
|
|
uint256[] memory ids,
|
|
uint256[] memory amounts,
|
|
IBEERC1155 nft
|
|
) internal {
|
|
nft.mintBatch(to, ids, amounts, "");
|
|
emit TokenMintedBatch(address(nft), to, nonce, ids, amounts);
|
|
}
|
|
|
|
function getMessageHash(
|
|
address _to,
|
|
address _nftAddress,
|
|
uint256 _startTime,
|
|
uint256 _saltNonce,
|
|
uint256[] memory _ids
|
|
) public pure returns (bytes32) {
|
|
bytes memory encoded = abi.encodePacked(
|
|
_to,
|
|
_nftAddress,
|
|
_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 getShardMixHash(
|
|
ShardParam memory param,
|
|
address nftAddress,
|
|
uint256[] memory _ids
|
|
) internal pure returns (bytes32) {
|
|
bytes memory encoded = abi.encodePacked(
|
|
param.to,
|
|
nftAddress,
|
|
param.nftId,
|
|
param.payToken,
|
|
param.payAmount,
|
|
param.startTime,
|
|
param.saltNonce
|
|
);
|
|
uint256 len = _ids.length;
|
|
for (uint256 i = 0; i < len; ++i) {
|
|
encoded = bytes.concat(encoded, abi.encodePacked(_ids[i]));
|
|
}
|
|
return keccak256(encoded);
|
|
}
|
|
}
|