becrypto/contracts/luckybox/LuckyBoxProxy.sol
2022-04-18 17:23:42 +08:00

189 lines
5.1 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;
uint8 public constant TYPE_NONE = 0;
uint8 public constant TYPE_HERO = 1;
uint8 public constant TYPE_EQUIP = 2;
uint8 public constant TYPE_CHIP = 3;
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 val,
uint256[3] ids,
uint8[3] 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 saltNonce,
bytes calldata signature
) external {
require(
!usedSignatures[signature],
"LuckyBoxProxy: signature used. please send another transaction with new signature"
);
address owner = msg.sender;
bytes32 criteriaMessageHash = getMessageHash(
boxId,
ids[0],
ids[1],
ids[2],
saltNonce
);
checkSigner(executor, criteriaMessageHash, signature);
usedSignatures[signature] = true;
// open box
box.burn(owner, boxId, 1);
uint256[3] memory results = [ids[0], 0, 0];
uint8[3] memory types = [TYPE_HERO, TYPE_NONE, TYPE_NONE];
mint721WithType(owner, ids[0], types[0]);
results[0] = ids[0];
uint256 val = rand(owner, saltNonce, 100);
if (val >= 70 && val < 90) {
types[1] = TYPE_CHIP;
mint721WithType(owner, ids[1], types[1]);
results[1] = ids[1];
} else if (val >= 90 && val < 98) {
types[1] = TYPE_EQUIP;
mint721WithType(owner, ids[1], types[1]);
results[1] = ids[1];
} else if (val >= 98) {
types[1] = TYPE_EQUIP;
mint721WithType(owner, ids[1], types[1]);
results[1] = ids[1];
types[2] = TYPE_CHIP;
mint721WithType(owner, ids[2], types[2]);
results[2] = ids[2];
}
emit BoxOpened(owner, boxId, val, results, types);
}
function mint721WithType(
address to,
uint256 tokenId,
uint256 typeNum
) private {
if (typeNum == 1) {
hero.mint(to, tokenId);
} else if (typeNum == 2) {
equip.mint(to, tokenId);
} else if (typeNum == 3) {
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 _saltNonce
) public pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
_boxId,
_firstToken,
_secondToken,
_thirdToken,
_saltNonce
)
);
}
}