becrypto/contracts/luckybox/LuckyBoxProxy.sol
2022-04-17 12:33:29 +08:00

165 lines
4.3 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/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "../HasSignature.sol";
interface IMintableERC1155 is IERC1155 {
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external;
function burn(address owner, uint256 tokenId, uint256 amount) external;
}
interface IMintableERC721 is IERC721 {
function mint(address to, uint256 tokenId) external;
}
contract LuckyBoxProxy is Ownable, Initializable, HasSignature {
IMintableERC1155 public box;
IMintableERC721 public hero;
IMintableERC721 public equip;
IMintableERC721 public chip;
address public executor;
mapping(bytes => bool) public usedSignatures;
event BoxMinted(
address contractAddress,
address indexed to,
uint256[] ids,
uint256[] amounts
);
event BoxOpened(
address indexed to,
uint256 indexed boxId,
uint256[] ids,
uint256[] types
);
constructor()
HasSignature("LuckyBoxProxy", "1"){
}
function init(address _erc1155, address[3] calldata _erc721s) external initializer onlyOwner {
box = IMintableERC1155(_erc1155);
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 mintBoxTo(address to, uint256[] memory ids, uint256[] memory amounts) external onlyOwner{
require(to != address(0), 'to address can not be zero');
box.mintBatch(to, ids, amounts, "");
emit BoxMinted(address(box), to, ids, amounts);
}
function openBox(
uint256 boxId,
uint256[3] memory ids,
uint256[3] memory types,
uint256 saltNonce,
bytes calldata signature
) external {
require(ids.length == types.length, "LuckyBoxProxy: ids and types length mismatch");
require(
!usedSignatures[signature],
"LuckyBoxProxy: signature used. please send another transaction with new signature"
);
bytes32 criteriaMessageHash = getMessageHash(
boxId,
ids[0],
ids[1],
ids[2],
types[0],
types[1],
types[2],
saltNonce
);
checkSigner(executor, criteriaMessageHash, signature);
usedSignatures[signature] = true;
address owner = msg.sender;
// open box
box.burn(owner, boxId, 1);
// random count
uint256 val = rand(owner, saltNonce, 100);
// mint nft
uint256[] memory results;
uint256[] memory resultTypes;
mint721WithType(owner, ids[0], types[0]);
results[0] = ids[0];
resultTypes[0] = types[0];
if (val > 80) {
mint721WithType(owner, ids[1], types[1]);
results[1] = ids[1];
resultTypes[1] = types[1];
}
if (val > 90) {
mint721WithType(owner, ids[2], types[2]);
results[2] = ids[2];
resultTypes[2] = types[2];
}
emit BoxOpened(
owner,
boxId,
results,
resultTypes
);
}
function mint721WithType(address to, uint256 tokenId, uint256 typeNum) private {
if (typeNum == 0) {
hero.mint(to, tokenId);
} else if (typeNum == 1) {
equip.mint(to, tokenId);
} else {
chip.mint(to, tokenId);
}
}
function rand(
address owner,
uint256 nonce,
uint256 _length
) internal view returns(uint256) {
uint256 random = uint256(keccak256(abi.encodePacked(owner, nonce, block.difficulty, block.timestamp)));
return random%_length;
}
function getMessageHash(
uint256 _boxId,
uint256 _firstToken,
uint256 _secondToken,
uint256 _thirdToken,
uint256 _type1,
uint256 _type2,
uint256 _type3,
uint256 _saltNonce
) public pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
_boxId,
_firstToken,
_secondToken,
_thirdToken,
_type1,
_type2,
_type3,
_saltNonce
)
);
}
}