Skip to content

Instantly share code, notes, and snippets.

@Vectorized
Last active October 21, 2023 00:38
Show Gist options
  • Save Vectorized/0263fb6c943aeb9cfc7dd93e17f54ffa to your computer and use it in GitHub Desktop.
Save Vectorized/0263fb6c943aeb9cfc7dd93e17f54ffa to your computer and use it in GitHub Desktop.
MiladyRaveMaker
// 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