189 lines
5.1 KiB
Solidity
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
|
|
)
|
|
);
|
|
}
|
|
}
|