文件 1 的 12:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 12:ECDSA.sol
pragma solidity ^0.8.0;
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
return tryRecover(hash, v, r, s);
}
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
文件 3 的 12:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 4 的 12:IAvatar.sol
pragma solidity >=0.8.0;
pragma abicoder v2;
struct Part {
address collection;
uint96 id;
}
interface IAvatar {
function dress(Part[] calldata partsOn, bytes32[] calldata partsOff)
external;
function version() external view returns (string memory);
function dava() external view returns (address);
function davaId() external view returns (uint256);
function part(bytes32 categoryId) external view returns (Part memory);
function allParts() external view returns (Part[] memory parts);
function getPFP() external view returns (string memory);
function getMetadata() external view returns (string memory);
function externalImgUri() external view returns (string memory);
}
文件 5 的 12:IDava.sol
pragma solidity >=0.8.0;
pragma abicoder v2;
import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol";
import {IHost} from "../interfaces/IHost.sol";
import {Part} from "../interfaces/IAvatar.sol";
interface IDava is IERC721, IHost {
function mint(address to, uint256 id) external returns (address);
function registerCollection(address collection) external;
function registerCategory(bytes32 categoryId) external;
function registerFrameCollection(address collection) external;
function deregisterCollection(address collection) external;
function deregisterCategory(bytes32 categoryId) external;
function zap(
uint256 tokenId,
Part[] calldata partsOn,
bytes32[] calldata partsOff
) external;
function frameCollection() external view returns (address);
function isRegisteredCollection(address collection)
external
view
returns (bool);
function isSupportedCategory(bytes32 categoryId)
external
view
returns (bool);
function isDavaPart(address collection, bytes32 categoryId)
external
view
returns (bool);
function getAvatar(uint256 id) external view returns (address);
function getAllSupportedCategories()
external
view
returns (bytes32[] memory);
function getRegisteredCollections()
external
view
returns (address[] memory);
function getPFP(uint256 id) external view returns (string memory);
}
文件 6 的 12:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 7 的 12:IERC721.sol
pragma solidity ^0.8.0;
import "../token/ERC721/IERC721.sol";
文件 8 的 12:IHost.sol
pragma solidity >=0.8.0;
pragma abicoder v2;
interface IHost {
function baseURI() external view returns (string memory);
}
文件 9 的 12:IRandomBox.sol
pragma solidity >=0.8.0;
interface IRandomBox {
function getPartIds(uint256 index)
external
view
returns (uint256[] memory partIds);
}
文件 10 的 12:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_setOwner(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 11 的 12:Sale.sol
pragma solidity >=0.8.0;
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IAvatar, Part} from "../interfaces/IAvatar.sol";
import {IDava} from "../interfaces/IDava.sol";
import {IRandomBox} from "./IRandomBox.sol";
interface IPartCollection {
function unsafeMintBatch(
address account,
uint256[] calldata partIds,
uint256[] calldata amounts
) external;
}
contract Sale is EIP712, Ownable {
using EnumerableSet for EnumerableSet.UintSet;
bytes32 public constant WHITELIST_TYPE_HASH =
keccak256("Whitelist(uint256 ticketAmount,address beneficiary)");
bytes32 public constant RESERVED_TYPE_HASH =
keccak256("Reserved(uint256 amount,address beneficiary)");
uint16 public constant PARTS_PER_AVATAR = 3;
uint16 public constant MAX_MINT_PER_TICKET = 3;
uint16 public constant PRE_ALLOCATED_AMOUNT = 500;
uint16 public constant MAX_MINT_PER_ACCOUNT = 100;
uint16 private constant MAX_TOTAL_SUPPLY = 10000;
uint16 public totalClaimedAmount = 0;
uint16 public totalPreSaleAmount = 0;
uint16 public totalPublicSaleAmount = 0;
uint32 public immutable PRE_SALE_OPENING_TIME;
uint32 public immutable PRE_SALE_CLOSING_TIME;
uint32 public immutable PUBLIC_SALE_OPENING_TIME;
uint32 public publicSaleClosingTime;
uint56 public constant PRICE = 0.05 ether;
IDava public dava;
IPartCollection public davaOfficial;
IRandomBox private _randomBox;
mapping(address => uint256) public preSaleMintAmountOf;
mapping(address => uint256) public mainSaleMintAmountOf;
mapping(address => uint256) public claimedAmountOf;
struct Reserved {
uint256 amount;
address beneficiary;
}
struct ClaimReq {
uint8 vSig;
bytes32 rSig;
bytes32 sSig;
Reserved reserved;
}
struct Whitelist {
uint256 ticketAmount;
address beneficiary;
}
struct PreSaleReq {
uint8 vSig;
bytes32 rSig;
bytes32 sSig;
Whitelist whitelist;
}
constructor(
IDava dava_,
IPartCollection davaOfficial_,
IRandomBox randomBox_,
uint32 presaleStart,
uint32 presaleEnd,
uint32 publicStart
) EIP712("AvatarSale", "V1") {
dava = dava_;
davaOfficial = davaOfficial_;
_randomBox = randomBox_;
PRE_SALE_OPENING_TIME = presaleStart;
PRE_SALE_CLOSING_TIME = presaleEnd;
PUBLIC_SALE_OPENING_TIME = publicStart;
publicSaleClosingTime = 2**32 - 1;
}
modifier onlyDuringPreSale() {
require(
block.timestamp >= PRE_SALE_OPENING_TIME,
"Sale: preSale has not started yet"
);
require(
block.timestamp <= PRE_SALE_CLOSING_TIME,
"Sale: preSale has ended"
);
_;
}
modifier onlyDuringPublicSale() {
require(
block.timestamp >= PUBLIC_SALE_OPENING_TIME,
"Sale: publicSale has not started yet"
);
require(
block.timestamp <= publicSaleClosingTime,
"Sale: publicSale has ended"
);
_;
}
function setPublicSaleClosingTime(uint32 closingTime_) external onlyOwner {
publicSaleClosingTime = closingTime_;
}
function claim(ClaimReq calldata claimReq, uint16 claimedAmount) external {
require(
msg.sender == claimReq.reserved.beneficiary,
"Sale: not authorized"
);
require(
claimedAmount <=
claimReq.reserved.amount - claimedAmountOf[msg.sender],
"Sale: exceeds assigned amount"
);
require(
totalClaimedAmount + claimedAmount <= PRE_ALLOCATED_AMOUNT,
"Sale: exceeds PRE_ALLOCATED_AMOUNT"
);
_verifyClaimSig(claimReq);
claimedAmountOf[msg.sender] += claimedAmount;
for (uint16 i = 0; i < claimedAmount; i++) {
_mintAvatarWithParts(totalClaimedAmount + i);
}
totalClaimedAmount += claimedAmount;
}
function mint(uint16 purchaseAmount) external payable onlyDuringPublicSale {
require(!soldOut(), "Sale: sold out");
mainSaleMintAmountOf[msg.sender] += purchaseAmount;
require(
mainSaleMintAmountOf[msg.sender] <= MAX_MINT_PER_ACCOUNT,
"Sale: can not purchase more than MAX_MINT_PER_ACCOUNT"
);
_checkEthAmount(purchaseAmount, msg.value);
uint16 davaId = _getMintableId();
for (uint16 i = 0; i < purchaseAmount; i += 1) {
_mintAvatarWithParts(davaId + i);
}
totalPublicSaleAmount += purchaseAmount;
}
function mintWithWhitelist(
PreSaleReq calldata preSaleReq,
uint16 purchaseAmount
) external payable onlyDuringPreSale {
require(
msg.sender == preSaleReq.whitelist.beneficiary,
"Sale: msg.sender is not whitelisted"
);
require(
purchaseAmount <=
(preSaleReq.whitelist.ticketAmount * MAX_MINT_PER_TICKET) -
preSaleMintAmountOf[msg.sender],
"Sale: exceeds assigned amount"
);
_checkEthAmount(purchaseAmount, msg.value);
_verifyWhitelistSig(preSaleReq);
preSaleMintAmountOf[msg.sender] += purchaseAmount;
uint16 davaId = _getMintableId();
for (uint16 i = 0; i < purchaseAmount; i += 1) {
_mintAvatarWithParts(davaId + i);
}
totalPreSaleAmount += purchaseAmount;
}
function withdrawFunds(address payable receiver) external onlyOwner {
uint256 amount = address(this).balance;
receiver.transfer(amount);
}
function _mintAvatarWithParts(uint16 avatarId) internal {
address avatar = dava.mint(address(this), uint256(avatarId));
uint256[] memory partIds = _randomBox.getPartIds(avatarId);
uint256[] memory amounts = new uint256[](3);
amounts[0] = 1;
amounts[1] = 1;
amounts[2] = 1;
davaOfficial.unsafeMintBatch(avatar, partIds, amounts);
Part[] memory parts = new Part[](PARTS_PER_AVATAR);
for (uint16 i = 0; i < PARTS_PER_AVATAR; i += 1) {
parts[i] = Part(address(davaOfficial), uint96(partIds[i]));
}
IAvatar(avatar).dress(parts, new bytes32[](0));
dava.transferFrom(address(this), msg.sender, avatarId);
}
function soldOut() public view returns (bool) {
return (totalPreSaleAmount +
totalPublicSaleAmount +
PRE_ALLOCATED_AMOUNT ==
MAX_TOTAL_SUPPLY);
}
function _verifyClaimSig(ClaimReq calldata claimReq) internal view {
bytes32 digest = _hashTypedDataV4(
keccak256(
abi.encode(
RESERVED_TYPE_HASH,
claimReq.reserved.amount,
msg.sender
)
)
);
address signer = ecrecover(
digest,
claimReq.vSig,
claimReq.rSig,
claimReq.sSig
);
require(signer == owner(), "Sale: invalid signature");
}
function _verifyWhitelistSig(PreSaleReq calldata preSaleReq) internal view {
bytes32 digest = _hashTypedDataV4(
keccak256(
abi.encode(
WHITELIST_TYPE_HASH,
preSaleReq.whitelist.ticketAmount,
msg.sender
)
)
);
address signer = ecrecover(
digest,
preSaleReq.vSig,
preSaleReq.rSig,
preSaleReq.sSig
);
require(signer == owner(), "Sale: invalid signature");
}
function _getMintableId() private view returns (uint16) {
uint16 id = PRE_ALLOCATED_AMOUNT +
totalPreSaleAmount +
totalPublicSaleAmount;
require(id < MAX_TOTAL_SUPPLY, "Sale: exceeds max supply");
return id;
}
function _checkEthAmount(uint16 purchaseAmount, uint256 paidEth)
private
pure
{
require(
paidEth >= uint256(purchaseAmount) * uint256(PRICE),
"Sale: not enough eth"
);
}
}
文件 12 的 12:draft-EIP712.sol
pragma solidity ^0.8.0;
import "./ECDSA.sol";
abstract contract EIP712 {
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
constructor(string memory name, string memory version) {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
bytes32 typeHash = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_TYPE_HASH = typeHash;
}
function _domainSeparatorV4() internal view returns (bytes32) {
if (block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}
{
"compilationTarget": {
"contracts/sales/Sale.sol": "Sale"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IDava","name":"dava_","type":"address"},{"internalType":"contract IPartCollection","name":"davaOfficial_","type":"address"},{"internalType":"contract IRandomBox","name":"randomBox_","type":"address"},{"internalType":"uint32","name":"presaleStart","type":"uint32"},{"internalType":"uint32","name":"presaleEnd","type":"uint32"},{"internalType":"uint32","name":"publicStart","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"MAX_MINT_PER_ACCOUNT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_MINT_PER_TICKET","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PARTS_PER_AVATAR","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRE_ALLOCATED_AMOUNT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRE_SALE_CLOSING_TIME","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRE_SALE_OPENING_TIME","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE","outputs":[{"internalType":"uint56","name":"","type":"uint56"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PUBLIC_SALE_OPENING_TIME","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESERVED_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WHITELIST_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"vSig","type":"uint8"},{"internalType":"bytes32","name":"rSig","type":"bytes32"},{"internalType":"bytes32","name":"sSig","type":"bytes32"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"}],"internalType":"struct Sale.Reserved","name":"reserved","type":"tuple"}],"internalType":"struct Sale.ClaimReq","name":"claimReq","type":"tuple"},{"internalType":"uint16","name":"claimedAmount","type":"uint16"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimedAmountOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dava","outputs":[{"internalType":"contract IDava","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"davaOfficial","outputs":[{"internalType":"contract IPartCollection","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mainSaleMintAmountOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"purchaseAmount","type":"uint16"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"vSig","type":"uint8"},{"internalType":"bytes32","name":"rSig","type":"bytes32"},{"internalType":"bytes32","name":"sSig","type":"bytes32"},{"components":[{"internalType":"uint256","name":"ticketAmount","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"}],"internalType":"struct Sale.Whitelist","name":"whitelist","type":"tuple"}],"internalType":"struct Sale.PreSaleReq","name":"preSaleReq","type":"tuple"},{"internalType":"uint16","name":"purchaseAmount","type":"uint16"}],"name":"mintWithWhitelist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"preSaleMintAmountOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicSaleClosingTime","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"closingTime_","type":"uint32"}],"name":"setPublicSaleClosingTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"soldOut","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalClaimedAmount","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPreSaleAmount","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPublicSaleAmount","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]