컴파일러
0.8.10+commit.fc410830
파일 1 / 5 : AlphaKidsSale.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
interface NFT {
function mint(address to, uint256 quantity) external;
}
enum SaleStage {
None,
WhiteList,
Auction
}
contract AlphaKidsSale is Ownable, ReentrancyGuard {
using MerkleProof for bytes32[];
uint256 public whiteListSaleStartTime = 1649988000;
uint256 public whiteListSaleEndTime = 1650078000;
uint256 public whiteListSaleMintPrice = 0.26 ether;
uint256 public auctionStartTime = 1650087000;
uint256 public auctionEndTime = 1650094200;
uint256 public auctionTimeStep = 10 minutes;
uint256 public totalAuctionTimeSteps = 2;
uint256 public auctionStartPrice = 0.36 ether;
uint256 public auctionEndPrice = 0.30 ether;
uint256 public auctionPriceStep = 0.03 ether;
uint256 public auctionMaxPurchaseQuantityPerTx = 1;
uint256 public remainingCount = 369;
address public alphaKids;
bytes32 public whiteListMerkleRoot;
mapping(address => bool) public whiteListPurchased;
constructor(address _alphaKids) {
alphaKids = _alphaKids;
}
function getAuctionPrice() public view returns (uint256) {
require(auctionStartTime != 0, "auctionStartTime not set");
require(auctionEndTime != 0, "auctionEndTime not set");
if (block.timestamp < auctionStartTime) {
return auctionStartPrice;
}
uint256 timeSteps = (block.timestamp - auctionStartTime) /
auctionTimeStep;
if (timeSteps > totalAuctionTimeSteps) {
timeSteps = totalAuctionTimeSteps;
}
uint256 discount = timeSteps * auctionPriceStep;
return
auctionStartPrice > discount
? auctionStartPrice - discount
: auctionEndPrice;
}
function getCurrentActiveSaleStage() public view returns (SaleStage) {
bool whiteListSaleIsActive = (block.timestamp >
whiteListSaleStartTime) && (block.timestamp < whiteListSaleEndTime);
if (whiteListSaleIsActive) {
return SaleStage.WhiteList;
}
bool auctionIsActive = (block.timestamp > auctionStartTime) &&
(block.timestamp < auctionEndTime);
if (auctionIsActive) {
return SaleStage.Auction;
}
return SaleStage.None;
}
function mint(bytes32[] calldata proof, uint256 numberOfTokens)
external
payable
nonReentrant
{
require(tx.origin == msg.sender, "contract not allowed");
SaleStage currentActiveSaleStage = getCurrentActiveSaleStage();
require(
currentActiveSaleStage != SaleStage.None,
"no active sale right now"
);
require(numberOfTokens > 0, "numberOfTokens cannot be 0");
if (currentActiveSaleStage == SaleStage.WhiteList) {
_mintWhiteList(proof, numberOfTokens);
} else if (currentActiveSaleStage == SaleStage.Auction) {
_mintAuction(numberOfTokens);
}
}
function _mintWhiteList(bytes32[] calldata proof, uint256 numberOfTokens)
internal
{
require(
msg.value == whiteListSaleMintPrice * numberOfTokens,
"sent ether value incorrect"
);
require(!whiteListPurchased[msg.sender], "whiteListPurchased already");
require(
proof.verify(
whiteListMerkleRoot,
keccak256(abi.encodePacked(msg.sender, numberOfTokens))
),
"failed to verify first WL merkle root"
);
require(numberOfTokens <= remainingCount, "whiteList sold out");
whiteListPurchased[msg.sender] = true;
remainingCount -= 1;
NFT(alphaKids).mint(msg.sender, numberOfTokens);
}
function _mintAuction(uint256 numberOfTokens) internal {
require(
msg.value >= getAuctionPrice() * numberOfTokens,
"sent ether value incorrect"
);
require(numberOfTokens <= remainingCount, "auction sold out");
require(
numberOfTokens <= auctionMaxPurchaseQuantityPerTx,
"numberOfTokens exceeds auctionMaxPurchaseQuantityPerTx"
);
remainingCount -= 1;
NFT(alphaKids).mint(msg.sender, numberOfTokens);
}
function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
whiteListMerkleRoot = _merkleRoot;
}
function setSaleData(
uint256 _whiteListSaleStartTime,
uint256 _whiteListSaleEndTime,
uint256 _whiteListSaleMintPrice,
uint256 _auctionStartTime,
uint256 _auctionEndTime,
uint256 _auctionTimeStep,
uint256 _totalAuctionTimeSteps,
uint256 _auctionStartPrice,
uint256 _auctionEndPrice,
uint256 _auctionPriceStep,
uint256 _auctionMaxPurchaseQuantityPerTx,
uint256 _remainingCount
) external onlyOwner {
whiteListSaleStartTime = _whiteListSaleStartTime;
whiteListSaleEndTime = _whiteListSaleEndTime;
whiteListSaleMintPrice = _whiteListSaleMintPrice;
auctionStartTime = _auctionStartTime;
auctionEndTime = _auctionEndTime;
auctionTimeStep = _auctionTimeStep;
totalAuctionTimeSteps = _totalAuctionTimeSteps;
auctionStartPrice = _auctionStartPrice;
auctionEndPrice = _auctionEndPrice;
auctionPriceStep = _auctionPriceStep;
auctionMaxPurchaseQuantityPerTx = _auctionMaxPurchaseQuantityPerTx;
remainingCount = _remainingCount;
}
function withdraw() public onlyOwner {
(bool sent, ) = msg.sender.call{value: address(this).balance}("");
require(sent, "sent value failed");
}
}
파일 2 / 5 : 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;
}
}
파일 3 / 5 : 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)
}
}
}
파일 4 / 5 : 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);
}
}
파일 5 / 5 : 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;
}
}
{
"compilationTarget": {
"contracts/AlphaKidsSale.sol": "AlphaKidsSale"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_alphaKids","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"},{"inputs":[],"name":"alphaKids","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionEndPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionMaxPurchaseQuantityPerTx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionPriceStep","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionStartPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionTimeStep","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAuctionPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentActiveSaleStage","outputs":[{"internalType":"enum SaleStage","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"numberOfTokens","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"remainingCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_whiteListSaleStartTime","type":"uint256"},{"internalType":"uint256","name":"_whiteListSaleEndTime","type":"uint256"},{"internalType":"uint256","name":"_whiteListSaleMintPrice","type":"uint256"},{"internalType":"uint256","name":"_auctionStartTime","type":"uint256"},{"internalType":"uint256","name":"_auctionEndTime","type":"uint256"},{"internalType":"uint256","name":"_auctionTimeStep","type":"uint256"},{"internalType":"uint256","name":"_totalAuctionTimeSteps","type":"uint256"},{"internalType":"uint256","name":"_auctionStartPrice","type":"uint256"},{"internalType":"uint256","name":"_auctionEndPrice","type":"uint256"},{"internalType":"uint256","name":"_auctionPriceStep","type":"uint256"},{"internalType":"uint256","name":"_auctionMaxPurchaseQuantityPerTx","type":"uint256"},{"internalType":"uint256","name":"_remainingCount","type":"uint256"}],"name":"setSaleData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalAuctionTimeSteps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"whiteListMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whiteListPurchased","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whiteListSaleEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whiteListSaleMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whiteListSaleStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]