-
Notifications
You must be signed in to change notification settings - Fork 86
/
NFTMintDN404.sol
151 lines (131 loc) · 4.49 KB
/
NFTMintDN404.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
import {DN404} from "dn404/src/DN404.sol";
import {DN404Mirror} from "dn404/src/DN404Mirror.sol";
import {Ownable} from "solady/src/auth/Ownable.sol";
import {LibString} from "solady/src/utils/LibString.sol";
import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol";
import {MerkleProofLib} from "solady/src/utils/MerkleProofLib.sol";
/**
* @title NFTMintDN404
* @notice Sample DN404 contract that demonstrates the owner selling NFTs rather than the fungible token.
* The underlying call still mints ERC20 tokens, but to the end user it'll appear as a standard NFT mint.
* Each address is limited to MAX_PER_WALLET total mints.
*/
contract NFTMintDN404 is DN404, Ownable {
string private _name;
string private _symbol;
string private _baseURI;
bytes32 private _allowlistRoot;
uint96 public publicPrice; // uint96 is sufficient to represent all ETH in existence.
uint96 public allowlistPrice; // uint96 is sufficient to represent all ETH in existence.
uint32 public totalMinted; // DN404 only supports up to `2**32 - 2` tokens.
bool public live;
uint32 public constant MAX_PER_WALLET = 5;
uint32 public constant MAX_SUPPLY = 5000;
error InvalidProof();
error InvalidMint();
error InvalidPrice();
error TotalSupplyReached();
error NotLive();
constructor(
string memory name_,
string memory symbol_,
bytes32 allowlistRoot_,
uint96 publicPrice_,
uint96 allowlistPrice_,
uint96 initialTokenSupply,
address initialSupplyOwner
) {
_initializeOwner(msg.sender);
_name = name_;
_symbol = symbol_;
_allowlistRoot = allowlistRoot_;
publicPrice = publicPrice_;
allowlistPrice = allowlistPrice_;
address mirror = address(new DN404Mirror(msg.sender));
_initializeDN404(initialTokenSupply, initialSupplyOwner, mirror);
}
modifier onlyLive() {
if (!live) {
revert NotLive();
}
_;
}
modifier checkPrice(uint256 price, uint256 nftAmount) {
if (price * nftAmount != msg.value) {
revert InvalidPrice();
}
_;
}
modifier checkAndUpdateTotalMinted(uint256 nftAmount) {
uint256 newTotalMinted = uint256(totalMinted) + nftAmount;
if (newTotalMinted > MAX_SUPPLY) {
revert TotalSupplyReached();
}
totalMinted = uint32(newTotalMinted);
_;
}
modifier checkAndUpdateBuyerMintCount(uint256 nftAmount) {
uint256 currentMintCount = _getAux(msg.sender);
uint256 newMintCount = currentMintCount + nftAmount;
if (newMintCount > MAX_PER_WALLET) {
revert InvalidMint();
}
_setAux(msg.sender, uint88(newMintCount));
_;
}
function mint(
uint256 nftAmount
)
public
payable
onlyLive
checkPrice(publicPrice, nftAmount)
checkAndUpdateBuyerMintCount(nftAmount)
checkAndUpdateTotalMinted(nftAmount)
{
_mint(msg.sender, nftAmount * _unit());
}
function allowlistMint(
uint256 nftAmount,
bytes32[] calldata proof
)
public
payable
onlyLive
checkPrice(allowlistPrice, nftAmount)
checkAndUpdateBuyerMintCount(nftAmount)
checkAndUpdateTotalMinted(nftAmount)
{
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
if (!MerkleProofLib.verifyCalldata(proof, _allowlistRoot, leaf)) {
revert InvalidProof();
}
_mint(msg.sender, nftAmount * _unit());
}
function setBaseURI(string calldata baseURI_) public onlyOwner {
_baseURI = baseURI_;
}
function setPrices(uint96 publicPrice_, uint96 allowlistPrice_) public onlyOwner {
publicPrice = publicPrice_;
allowlistPrice = allowlistPrice_;
}
function toggleLive() public onlyOwner {
live = !live;
}
function withdraw() public onlyOwner {
SafeTransferLib.safeTransferAllETH(msg.sender);
}
function name() public view override returns (string memory) {
return _name;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function _tokenURI(uint256 tokenId) internal view override returns (string memory result) {
if (bytes(_baseURI).length != 0) {
result = string(abi.encodePacked(_baseURI, LibString.toString(tokenId)));
}
}
}