Last active
October 21, 2023 00:38
-
-
Save Vectorized/0263fb6c943aeb9cfc7dd93e17f54ffa to your computer and use it in GitHub Desktop.
MiladyRaveMaker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.4; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
import "erc721a/contracts/ERC721A.sol"; | |
import "erc721a/contracts/extensions/ERC721AQueryable.sol"; | |
import "solady/src/utils/ECDSA.sol"; | |
import "solady/src/utils/LibString.sol"; | |
import "solady/src/utils/SafeTransferLib.sol"; | |
contract MiladyRaveMaker is ERC721A, ERC721AQueryable, Ownable { | |
using ECDSA for bytes32; | |
uint256 public constant PRICE_UNIT = 0.001 ether; | |
string private _tokenURI; | |
address public signer; | |
uint16 public maxSupply; | |
uint16 private _miladyPriceUnits; | |
uint16 private _publicPriceUnits; | |
bool public paused; | |
bool public mintLocked; | |
bool public maxSupplyLocked; | |
bool public tokenURILocked; | |
constructor() ERC721A("MiladyRave", "MIR") { | |
maxSupply = 5000; | |
_miladyPriceUnits = _toPriceUnits(0.03 ether); | |
_publicPriceUnits = _toPriceUnits(0.06 ether); | |
paused = true; // Must be initialized to true. | |
} | |
function _startTokenId() internal view virtual override returns (uint256) { | |
return 1; | |
} | |
function tokenURI(uint256 tokenId) public view override returns (string memory) { | |
return LibString.replace(_tokenURI, "{id}", _toString(tokenId)); | |
} | |
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | |
/* MINTING FUNCTIONS */ | |
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | |
function publicMint(uint256 quantity) | |
external | |
payable | |
mintNotPaused | |
requireMintable(quantity) | |
requireExactPayment(_publicPriceUnits, quantity) | |
{ | |
_mint(msg.sender, quantity); | |
} | |
function miladyMint(uint256 quantity, bytes calldata signature) | |
external | |
payable | |
mintNotPaused | |
requireMintable(quantity) | |
requireSignature(signature) | |
requireExactPayment(_miladyPriceUnits, quantity) | |
{ | |
_mint(msg.sender, quantity); | |
} | |
function claimGiveaway(bytes calldata signature) | |
external | |
payable | |
mintNotPaused | |
requireMintable(1) | |
requireSignature(signature) | |
{ | |
require(_getAux(msg.sender) == 0, "Already claimed."); | |
_setAux(msg.sender, 1); | |
_mint(msg.sender, 1); | |
} | |
function hasClaimedGiveaway(address claimer) external view returns (bool) { | |
return _getAux(claimer) != 0; | |
} | |
function miladyPrice() external view returns (uint256) { | |
return _toPrice(_miladyPriceUnits); | |
} | |
function publicPrice() external view returns (uint256) { | |
return _toPrice(_publicPriceUnits); | |
} | |
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | |
/* HELPERS */ | |
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | |
function _toPriceUnits(uint256 price) private pure returns (uint16) { | |
unchecked { | |
require(price % PRICE_UNIT == 0, "Price must be a multiple of PRICE_UNIT."); | |
require((price /= PRICE_UNIT) <= type(uint16).max, "Overflow."); | |
return uint16(price); | |
} | |
} | |
function _toPrice(uint16 priceUnits) private pure returns (uint256) { | |
return uint256(priceUnits) * PRICE_UNIT; | |
} | |
modifier requireMintable(uint256 quantity) { | |
unchecked { | |
require(mintLocked == false, "Locked."); | |
require(_totalMinted() + quantity <= maxSupply, "Out of stock!"); | |
} | |
_; | |
} | |
modifier requireExactPayment(uint16 priceUnits, uint256 quantity) { | |
unchecked { | |
require(quantity <= 100, "Quantity too high."); | |
require(msg.value == _toPrice(priceUnits) * quantity, "Wrong Ether value."); | |
} | |
_; | |
} | |
modifier requireSignature(bytes calldata signature) { | |
require( | |
keccak256(abi.encode(msg.sender)).toEthSignedMessageHash().recover(signature) == signer, | |
"Invalid signature." | |
); | |
_; | |
} | |
modifier mintNotPaused() { | |
require(paused == false, "Paused."); | |
_; | |
} | |
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | |
/* ADMIN FUNCTIONS */ | |
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | |
function forceMint(address[] calldata to, uint256 quantity) | |
external | |
onlyOwner | |
requireMintable(quantity * to.length) | |
{ | |
unchecked { | |
for (uint256 i; i != to.length; ++i) { | |
_mint(to[i], quantity); | |
} | |
} | |
} | |
function selfMint(uint256 quantity) external onlyOwner requireMintable(quantity) { | |
unchecked { | |
uint256 miniBatchSize = 8; | |
uint256 i = quantity % miniBatchSize; | |
_mint(msg.sender, i); | |
while (i != quantity) { | |
_mint(msg.sender, miniBatchSize); | |
i += miniBatchSize; | |
} | |
} | |
} | |
function setTokenURI(string calldata value) external onlyOwner { | |
require(tokenURILocked == false, "Locked."); | |
_tokenURI = value; | |
} | |
function setMaxSupply(uint16 value) external onlyOwner { | |
require(maxSupplyLocked == false, "Locked."); | |
maxSupply = value; | |
} | |
function setPaused(bool value) external onlyOwner { | |
if (value == false) { | |
require(maxSupply != 0, "Max supply not set."); | |
require(signer != address(0), "Signer not set."); | |
} | |
paused = value; | |
} | |
function setSigner(address value) external onlyOwner { | |
require(value != address(0), "Signer must not be the zero address."); | |
signer = value; | |
} | |
function lockMint() external onlyOwner { | |
mintLocked = true; | |
} | |
function lockMaxSupply() external onlyOwner { | |
maxSupplyLocked = true; | |
} | |
function lockTokenURI() external onlyOwner { | |
tokenURILocked = true; | |
} | |
function setMiladyPrice(uint256 value) external onlyOwner { | |
_miladyPriceUnits = _toPriceUnits(value); | |
} | |
function setPublicPrice(uint256 value) external onlyOwner { | |
_publicPriceUnits = _toPriceUnits(value); | |
} | |
function withdraw() external payable onlyOwner { | |
SafeTransferLib.safeTransferETH(msg.sender, address(this).balance); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment