编译器
0.8.17+commit.8df45f5f
文件 1 的 8: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 的 8:IERC721AQueryableUpgradeable.sol
pragma solidity ^0.8.4;
import '../extensions/IERC721AQueryableUpgradeable.sol';
文件 3 的 8:IERC721AUpgradeable.sol
pragma solidity ^0.8.4;
interface IERC721AUpgradeable {
error ApprovalCallerNotOwnerNorApproved();
error ApprovalQueryForNonexistentToken();
error ApproveToCaller();
error BalanceQueryForZeroAddress();
error MintToZeroAddress();
error MintZeroQuantity();
error OwnerQueryForNonexistentToken();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TransferToNonERC721ReceiverImplementer();
error TransferToZeroAddress();
error URIQueryForNonexistentToken();
error MintERC2309QuantityExceedsLimit();
error OwnershipNotInitializedForExtraData();
struct TokenOwnership {
address addr;
uint64 startTimestamp;
bool burned;
uint24 extraData;
}
function totalSupply() external view returns (uint256);
function supportsInterface(bytes4 interfaceId) external view returns (bool);
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}
文件 4 的 8:ISloth.sol
pragma solidity ^0.8.17;
import { IERC721AQueryableUpgradeable } from "erc721a-upgradeable/contracts/interfaces/IERC721AQueryableUpgradeable.sol";
interface ISloth is IERC721AQueryableUpgradeable {
function mint(address sender, uint8 quantity) external;
function numberMinted(address sender) external view returns (uint256);
}
文件 5 的 8:ISlothItemV2.sol
pragma solidity ^0.8.17;
import { IERC721AQueryableUpgradeable } from "erc721a-upgradeable/contracts/interfaces/IERC721AQueryableUpgradeable.sol";
interface ISlothItemV2 is IERC721AQueryableUpgradeable {
enum ItemType { CLOTHES, HEAD, HAND, FOOT, STAMP }
function getItemType(uint256 tokenId) external view returns (ItemType);
function getItemMintCount(address sender) external view returns (uint256);
function exists(uint256 tokenId) external view returns (bool);
function clothesMint(address sender, uint256 quantity) external;
function itemMint(address sender, uint256 quantity) external;
}
文件 6 的 8: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 verifyCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProofCalldata(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++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
文件 7 的 8: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());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
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);
}
}
文件 8 的 8:SlothMintV2.sol
pragma solidity ^0.8.17;
import "./interfaces/ISloth.sol";
import "./interfaces/ISlothItemV2.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contract SlothMintV2 is Ownable {
address private _slothAddr;
address private _slothItemAddr;
bool public publicSale;
uint256 public immutable maxPerAddressDuringMint;
uint256 public immutable maxPerAddressDuringItemMint;
uint256 public immutable collectionSize;
uint256 public immutable itemCollectionSize;
uint256 public immutable clothesSize;
uint256 public immutable itemSize;
uint256 public currentItemCount;
uint256 public currentClothesCount;
bytes32 public merkleRoot;
bytes32 public secondMerkleRoot;
uint256 private constant _MINT_WITH_CLOTHES_PRICE = 0.021 ether;
address private _treasuryAddress = 0x452Ccc6d4a818D461e20837B417227aB70C72B56;
mapping(bytes => bool) public coupons;
constructor(uint256 newMaxPerAddressDuringMint, uint256 newMaxPerAddressDuringItemMint, uint256 newCollectionSize, uint256 newItemCollectionSize, uint256 newClothesSize, uint256 newItemSize, uint256 newCurrentClothesCount, uint256 newCurrentItemCount) {
maxPerAddressDuringMint = newMaxPerAddressDuringMint;
maxPerAddressDuringItemMint = newMaxPerAddressDuringItemMint;
collectionSize = newCollectionSize;
itemCollectionSize = newItemCollectionSize;
clothesSize = newClothesSize;
itemSize = newItemSize;
currentClothesCount = newCurrentClothesCount;
currentItemCount = newCurrentItemCount;
}
function setSlothAddr(address newSlothAddr) external onlyOwner {
_slothAddr = newSlothAddr;
}
function setSlothItemAddr(address newSlothItemAddr) external onlyOwner {
_slothItemAddr = newSlothItemAddr;
}
function _itemMint(uint256 quantity) private {
require(currentItemCount + quantity <= itemSize, "exceeds item size");
ISlothItemV2(_slothItemAddr).itemMint(msg.sender, quantity);
currentItemCount += quantity;
}
function publicMintWithClothes() payable external {
uint8 quantity = 1;
require(msg.value == _MINT_WITH_CLOTHES_PRICE * quantity, "wrong price");
require(ISloth(_slothAddr).numberMinted(msg.sender) + quantity <= maxPerAddressDuringMint, "wrong num");
_publicMint(quantity);
}
function publicMintWithClothesWithProof(uint8 quantity, bytes32[] calldata merkleProof) payable external {
require(1 <= quantity && quantity <= 2, "wrong quantity");
require(msg.value == _MINT_WITH_CLOTHES_PRICE * quantity, "wrong price");
require(isMintAllowed(merkleProof), "invalid proof");
require(ISloth(_slothAddr).numberMinted(msg.sender) + quantity <= maxPerAddressDuringMint + 1, "wrong num");
_publicMint(quantity);
}
function _publicMint(uint8 quantity) private {
require(publicSale, "inactive");
require(ISloth(_slothAddr).totalSupply() + quantity <= collectionSize, "exceeds collection size");
require(currentClothesCount + quantity <= clothesSize, "exceeds clothes size");
ISloth(_slothAddr).mint(msg.sender, quantity);
ISlothItemV2(_slothItemAddr).clothesMint(msg.sender, quantity);
currentClothesCount += quantity;
}
function publicMintWithClothesAndItem(uint8 itemQuantity) payable external {
uint8 quantity = 1;
require(1 <= itemQuantity && itemQuantity <= 9, "wrong item quantity");
require(msg.value == itemPrice(itemQuantity) + _MINT_WITH_CLOTHES_PRICE * quantity, "wrong price");
require(ISlothItemV2(_slothItemAddr).totalSupply() + (quantity + itemQuantity) <= itemCollectionSize, "exceeds item collection size");
require(ISloth(_slothAddr).numberMinted(msg.sender) + quantity <= maxPerAddressDuringMint, "wrong num");
_publicMint(quantity);
_itemMint(itemQuantity);
}
function publicMintWithClothesAndItemWithProof(uint8 quantity, uint8 itemQuantity, bytes32[] calldata merkleProof) payable external {
require(1 <= quantity && quantity <= 2, "wrong quantity");
require(1 <= itemQuantity && itemQuantity <= 9, "wrong item quantity");
require(isMintAllowed(merkleProof), "invalid proof");
require(msg.value == itemPrice(itemQuantity) + _MINT_WITH_CLOTHES_PRICE * quantity, "wrong price");
require(ISlothItemV2(_slothItemAddr).totalSupply() + (quantity + itemQuantity) <= itemCollectionSize, "exceeds item collection size");
require(ISloth(_slothAddr).numberMinted(msg.sender) + quantity <= maxPerAddressDuringMint + 1, "wrong num");
_publicMint(quantity);
_itemMint(itemQuantity);
}
function publicItemMint(uint8 quantity) payable external {
require(publicSale, "inactive");
require(msg.value == itemPrice(quantity), "wrong price");
require(ISlothItemV2(_slothItemAddr).totalSupply() + quantity <= itemCollectionSize, "exceeds item collection size");
require(ISlothItemV2(_slothItemAddr).getItemMintCount(msg.sender) + quantity <= maxPerAddressDuringItemMint, "wrong item num");
_itemMint(quantity);
}
function setPublicSale(bool newPublicSale) external onlyOwner {
publicSale = newPublicSale;
}
function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner {
merkleRoot = newMerkleRoot;
}
function setSecondMerkleRoot(bytes32 newSecondMerkleRoot) external onlyOwner {
secondMerkleRoot = newSecondMerkleRoot;
}
function isMintAllowed(bytes32[] calldata merkleProof) public view returns(bool) {
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(msg.sender))));
return MerkleProof.verify(merkleProof, merkleRoot, leaf) || MerkleProof.verify(merkleProof, secondMerkleRoot, leaf);
}
function itemPrice(uint8 quantity) internal view returns(uint256) {
require(0 < quantity && quantity <= maxPerAddressDuringItemMint, "wrong quantity");
if (quantity == 1) {
return 0.02 ether;
} else if (quantity == 2) {
return 0.039 ether;
} else if (quantity == 3) {
return 0.056 ether;
} else if (quantity == 4) {
return 0.072 ether;
} else if (quantity == 5) {
return 0.088 ether;
} else if (quantity == 6) {
return 0.1 ether;
} else if (quantity == 7) {
return 0.115 ether;
} else if (quantity == 8) {
return 0.125 ether;
} else if (quantity == 9) {
return 0.135 ether;
} else {
revert("invalid quantity");
}
}
function withdraw() external onlyOwner {
(bool sent,) = _treasuryAddress.call{value: address(this).balance}("");
require(sent, "Failed to send Ether");
}
function ownerMint(uint8 quantity, uint256 itemQuantity) external onlyOwner {
require(ISlothItemV2(_slothItemAddr).totalSupply() + (quantity + itemQuantity) <= itemCollectionSize, "exceeds item collection size");
if (quantity > 0) {
_publicMint(quantity);
}
if (itemQuantity > 0) {
_itemMint(itemQuantity);
}
}
function ownerClothesMint(uint256 quantity) external onlyOwner {
require(ISlothItemV2(_slothItemAddr).totalSupply() + quantity <= itemCollectionSize, "exceeds item collection size");
require(currentClothesCount + quantity <= clothesSize, "exceeds clothes size");
ISlothItemV2(_slothItemAddr).clothesMint(msg.sender, quantity);
}
}
{
"compilationTarget": {
"contracts/SlothMintV2.sol": "SlothMintV2"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"newMaxPerAddressDuringMint","type":"uint256"},{"internalType":"uint256","name":"newMaxPerAddressDuringItemMint","type":"uint256"},{"internalType":"uint256","name":"newCollectionSize","type":"uint256"},{"internalType":"uint256","name":"newItemCollectionSize","type":"uint256"},{"internalType":"uint256","name":"newClothesSize","type":"uint256"},{"internalType":"uint256","name":"newItemSize","type":"uint256"},{"internalType":"uint256","name":"newCurrentClothesCount","type":"uint256"},{"internalType":"uint256","name":"newCurrentItemCount","type":"uint256"}],"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":"clothesSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectionSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"coupons","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentClothesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentItemCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"isMintAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"itemCollectionSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"itemSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPerAddressDuringItemMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPerAddressDuringMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"ownerClothesMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"quantity","type":"uint8"},{"internalType":"uint256","name":"itemQuantity","type":"uint256"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"quantity","type":"uint8"}],"name":"publicItemMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"publicMintWithClothes","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"itemQuantity","type":"uint8"}],"name":"publicMintWithClothesAndItem","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"quantity","type":"uint8"},{"internalType":"uint8","name":"itemQuantity","type":"uint8"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"publicMintWithClothesAndItemWithProof","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"quantity","type":"uint8"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"publicMintWithClothesWithProof","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"publicSale","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"secondMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newMerkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"newPublicSale","type":"bool"}],"name":"setPublicSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newSecondMerkleRoot","type":"bytes32"}],"name":"setSecondMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSlothAddr","type":"address"}],"name":"setSlothAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSlothItemAddr","type":"address"}],"name":"setSlothItemAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]