文件 1 的 13:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 13:ApemoArmyOperator.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./interfaces/IApemoArmy.sol";
import "./utils/Operatorable.sol";
import "./helpers/DateHelper.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contract ApemoArmyOperator is Operatorable, ReentrancyGuard {
IApemoArmy public apemoArmyContract;
address payable public svEthAddr =
payable(0x981268bF660454e24DBEa9020D57C2504a538C57);
enum AllowLists {
APELIST,
CREWMEN_LIST,
TREVOR_JONES,
HACKATAO,
PUBLIC_SALE_LIST
}
mapping(AllowLists => bytes32) public allowListMerkleRoots;
bytes32 public freeClaimMerkleRoot;
uint256 currentPhase = 0;
uint16 mintIndex = 1;
uint16 public apemoArmySold = 0;
uint256 public trevorTexturesSold = 0;
uint256 public hackataoTexturesSold = 0;
uint256 MAX_SUPPLY = 10000;
uint256 MAX_SUPPLY_SALES = 5000;
uint256 MAX_SUPPLY_SPECIAL_TEXTURES = 100;
uint256 publicSalePrice = .1 ether;
bool public claimState = true;
bool public purchaseState = true;
mapping(address => uint8) public claimedAmount;
mapping(address => bool) public claimedAddresses;
mapping(AllowLists => mapping(address => uint8)) public allowListPurchases;
constructor(address _operator, address _apemoArmyContract) {
apemoArmyContract = IApemoArmy(_apemoArmyContract);
addOperator(_operator);
}
function setPaymentAddress(address _svEthAddr) external onlyOwner {
svEthAddr = payable(_svEthAddr);
}
function setFreeClaimMerkleRoot(bytes32 _freeClaimMerkleRoot)
external
onlyOperator
{
freeClaimMerkleRoot = _freeClaimMerkleRoot;
}
function setAllowListMerkleRoot(AllowLists allowList, bytes32 merkleRoot)
external
onlyOperator
{
allowListMerkleRoots[allowList] = merkleRoot;
}
function toggleClaim() external onlyOperator {
claimState = !claimState;
}
function togglePurchase() external onlyOperator {
purchaseState = !purchaseState;
}
function claim(
uint256 claimCount,
uint256 allotment,
bytes32[] calldata merkleProof
) external nonReentrant {
require(claimState, "Claim is disabled");
require(currentPhase == 4, "Claim period has not yet begun.");
require(
!claimedAddresses[msg.sender],
"You have already claimed your full allotment."
);
require(
claimCount + claimedAmount[msg.sender] <= allotment,
"Claiming this many would exceed your allotment."
);
require(
MerkleProof.verify(
merkleProof,
freeClaimMerkleRoot,
keccak256(abi.encodePacked(msg.sender, allotment))
),
"Sender address is not on the free claim list"
);
if (claimedAmount[msg.sender] + claimCount == allotment) {
claimedAddresses[msg.sender] = true;
claimedAmount[msg.sender] = (uint8)(
claimedAmount[msg.sender] + claimCount
);
} else {
claimedAmount[msg.sender] = (uint8)(
claimedAmount[msg.sender] + claimCount
);
}
uint256 i = 0;
uint256 tokenId;
while (i < claimCount) {
tokenId = mintIndex;
mintIndex++;
apemoArmyContract.operatorMint(msg.sender, tokenId);
i++;
}
}
function purchase(uint256 count) external payable nonReentrant {
require(purchaseState, "Purchase is disabled");
require(count <= 10, "Can only purchase up to 10 per transaction");
require(
currentPhase == 3,
"Public sale has not begun yet or has already ended"
);
require(msg.value >= count * publicSalePrice, "Not enough ether");
require(
apemoArmySold + count <= MAX_SUPPLY_SALES,
"No Apemo Army avatars left for public sale"
);
uint256 tokenId;
for (uint256 i = 0; i < count; i++) {
tokenId = mintIndex;
mintIndex++;
apemoArmySold++;
apemoArmyContract.operatorMint(msg.sender, tokenId);
}
(bool sent, ) = svEthAddr.call{value: count * publicSalePrice}("");
require(sent, "Failed to send Ether");
if (msg.value > count * publicSalePrice) {
(sent, ) = payable(msg.sender).call{
value: msg.value - count * publicSalePrice
}("");
require(sent, "Failed to send change back to user");
}
}
function allowListPurchase(
uint256 count,
uint256 allotment,
AllowLists list,
bytes32[] calldata merkleProof
) external payable nonReentrant {
require(purchaseState, "Purchase is disabled");
require(
allowListPurchases[list][msg.sender] + count <= allotment,
"Purchasing would exceed allotment."
);
require(currentPhase >= 1, "Allowlist sale has not begun yet");
require(currentPhase < 3, "Allowlist sale has already ended");
if (list == AllowLists.PUBLIC_SALE_LIST) {
require(
currentPhase == 2,
"Public Allowlist sales cannot be performed at this time"
);
} else if (list == AllowLists.TREVOR_JONES) {
require(
trevorTexturesSold + count <= MAX_SUPPLY_SPECIAL_TEXTURES,
"Bitcoin Angel Clothing textures are sold out"
);
trevorTexturesSold += count;
}
else if (list == AllowLists.HACKATAO) {
require(
hackataoTexturesSold + count <= MAX_SUPPLY_SPECIAL_TEXTURES,
"Hackatao Clothing textures are sold out"
);
hackataoTexturesSold += count;
}
require(count <= allotment, "Cannot mint more than allotment.");
uint256 price = publicSalePrice;
if (list == AllowLists.APELIST) {
price = (price) / 2;
} else if (
list == AllowLists.CREWMEN_LIST ||
list == AllowLists.TREVOR_JONES ||
list == AllowLists.HACKATAO
) {
price = (price * 8) / 10;
}
require(msg.value >= count * price, "Not enough ether");
require(
apemoArmySold + count <= MAX_SUPPLY_SALES,
"No Apemo Army avatars left for public sale"
);
require(
MerkleProof.verify(
merkleProof,
allowListMerkleRoots[list],
keccak256(abi.encodePacked(msg.sender, allotment))
),
"Sender address is not in that allowlist"
);
allowListPurchases[list][msg.sender] += uint8(count);
uint256 tokenId;
for (uint256 i = 0; i < count; i++) {
tokenId = mintIndex;
mintIndex++;
apemoArmySold++;
apemoArmyContract.operatorMint(msg.sender, tokenId);
}
(bool sent, ) = svEthAddr.call{value: count * price}("");
require(sent, "Failed to send Ether");
if (msg.value > count * price) {
(sent, ) = payable(msg.sender).call{
value: msg.value - count * price
}("");
require(sent, "Failed to send change back to user");
}
}
function safeBatchMintAndTransfer(address holder, uint16 batchSize)
external
onlyOperator
{
require(
mintIndex + batchSize <= MAX_SUPPLY + 1,
"No Apemo Army avatars left for public sale"
);
for (uint256 i = mintIndex; i < mintIndex + batchSize; i++) {
apemoArmyContract.operatorMint(holder, i);
}
mintIndex = uint16(mintIndex + batchSize);
}
function setMaxLimit(uint256 maxLimit) external onlyOwner {
require(maxLimit < 10001, "Max supply can never exceed 10000");
MAX_SUPPLY = maxLimit;
}
function setPhase(uint8 _currentPhase) external onlyOperator {
require(
_currentPhase <= 5 && _currentPhase >= 0,
"Phase must be between 0 and 5"
);
currentPhase = _currentPhase;
}
}
文件 3 的 13: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;
}
}
文件 4 的 13:DateHelper.sol
pragma solidity ^0.8.0;
library DateHelper {
function getPhase(uint256 _activeDateTime, uint256 _interval) internal view returns (uint256) {
unchecked {
uint256 passedTimeInHours = (block.timestamp - _activeDateTime) / _interval;
if( passedTimeInHours < 24) {
return 1;
} else if( passedTimeInHours < 48 ) {
return 2;
} else if( passedTimeInHours < 72 ) {
return 3;
} else if( passedTimeInHours < 96 ) {
return 4;
} else if( passedTimeInHours < 120 ) {
return 5;
} else if( passedTimeInHours < 144 ) {
return 6;
} else if( passedTimeInHours < 168 ) {
return 7;
} else {
return 8;
}
}
}
}
文件 5 的 13:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 6 的 13:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 7 的 13:IApemoArmy.sol
pragma solidity ^0.8.0;
interface IApemoArmy {
function setTokenURI(uint256 tokenId, string memory _tokenURI) external;
function operatorMint(address to, uint256 tokenId) external;
}
文件 8 的 13:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 9 的 13:MerkleProof.sol
pragma solidity ^0.8.0;
library MerkleProof {
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
bytes32 proofElement = proof[i];
if (computedHash <= proofElement) {
computedHash = _efficientHash(computedHash, proofElement);
} else {
computedHash = _efficientHash(proofElement, computedHash);
}
}
return computedHash;
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
文件 10 的 13:Operatorable.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
contract Operatorable is Ownable, AccessControl {
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
modifier onlyOperator() {
require(hasRole(OPERATOR_ROLE, msg.sender), "Operatorable: CALLER_NO_OPERATOR_ROLE");
_;
}
constructor() {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(OPERATOR_ROLE, msg.sender);
}
function addOperator(address _account) public onlyOwner {
grantRole(OPERATOR_ROLE, _account);
}
function removeOperator(address _account) public onlyOwner {
revokeRole(OPERATOR_ROLE, _account);
}
function isOperator(address _account) public view returns (bool) {
return hasRole(OPERATOR_ROLE, _account);
}
}
文件 11 的 13: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() {
_transferOwnership(_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 {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 12 的 13:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 13 的 13:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
{
"compilationTarget": {
"contracts/ApemoArmyOperator.sol": "ApemoArmyOperator"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_apemoArmyContract","type":"address"}],"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ApemoArmyOperator.AllowLists","name":"","type":"uint8"}],"name":"allowListMerkleRoots","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"uint256","name":"allotment","type":"uint256"},{"internalType":"enum ApemoArmyOperator.AllowLists","name":"list","type":"uint8"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"allowListPurchase","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"enum ApemoArmyOperator.AllowLists","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"}],"name":"allowListPurchases","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apemoArmyContract","outputs":[{"internalType":"contract IApemoArmy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apemoArmySold","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"claimCount","type":"uint256"},{"internalType":"uint256","name":"allotment","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimedAddresses","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimedAmount","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"freeClaimMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"hackataoTexturesSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"purchase","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"purchaseState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint16","name":"batchSize","type":"uint16"}],"name":"safeBatchMintAndTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ApemoArmyOperator.AllowLists","name":"allowList","type":"uint8"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"setAllowListMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_freeClaimMerkleRoot","type":"bytes32"}],"name":"setFreeClaimMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxLimit","type":"uint256"}],"name":"setMaxLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_svEthAddr","type":"address"}],"name":"setPaymentAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_currentPhase","type":"uint8"}],"name":"setPhase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"svEthAddr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"togglePurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trevorTexturesSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]