Skip to content

Commit

Permalink
chore: rename from drop to mint (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
arr00 authored Jul 25, 2024
1 parent f8946d6 commit 6e56da7
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 70 deletions.
8 changes: 4 additions & 4 deletions src/DropERC1155.sol → src/MintERC1155.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/O
import { ERC2981Upgradeable } from "@openzeppelin/contracts-upgradeable/token/common/ERC2981Upgradeable.sol";
import { LibString } from "solady/src/utils/LibString.sol";

contract DropERC1155 is ERC1155Upgradeable, OwnableUpgradeable, ERC2981Upgradeable {
contract MintERC1155 is ERC1155Upgradeable, OwnableUpgradeable, ERC2981Upgradeable {
error Unauthorized();

/// @notice Contract level name for `contractURI`
Expand Down Expand Up @@ -46,7 +46,7 @@ contract DropERC1155 is ERC1155Upgradeable, OwnableUpgradeable, ERC2981Upgradeab
totalPercentChance += editions[i].percentChance = editions_[i].percentChance;

if (editions_[i].percentChance == 0) {
revert("DropERC1155: percent chance must be greater than 0");
revert("MintERC1155: percent chance must be greater than 0");
}

for (uint256 j = 0; j < editions_[i].attributes.length; j++) {
Expand All @@ -55,7 +55,7 @@ contract DropERC1155 is ERC1155Upgradeable, OwnableUpgradeable, ERC2981Upgradeab
}

if (totalPercentChance != 100) {
revert("DropERC1155: total percent chance must equal 100");
revert("MintERC1155: total percent chance must equal 100");
}
}

Expand All @@ -71,7 +71,7 @@ contract DropERC1155 is ERC1155Upgradeable, OwnableUpgradeable, ERC2981Upgradeab
revert Unauthorized();
}
if (ids.length != amounts.length) {
revert("DropERC1155: ids and amounts length mismatch");
revert("MintERC1155: ids and amounts length mismatch");
}
_mintBatch(to, ids, amounts, "");
}
Expand Down
87 changes: 44 additions & 43 deletions src/NFTMint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerklePr
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { DropERC1155 } from "./DropERC1155.sol";
import { MintERC1155 } from "./MintERC1155.sol";

contract NFTMint is Ownable {
struct DropArgs {
struct MintArgs {
uint256 maxMints;
DropERC1155.Edition[] editions;
MintERC1155.Edition[] editions;
bytes32 allowlistMerkleRoot;
uint256 pricePerMint;
uint256 perWalletLimit;
Expand All @@ -19,7 +19,7 @@ contract NFTMint is Ownable {
address payable feeRecipient;
}

struct DropInfo {
struct MintInfo {
uint256 pricePerMint;
uint256 feePerMint;
address payable owner;
Expand All @@ -32,69 +32,70 @@ contract NFTMint is Ownable {

struct Order {
address to;
DropERC1155 drop;
MintERC1155 mint;
uint256 amount;
}

address public immutable DROP_NFT_LOGIC;
address public immutable MINT_NFT_LOGIC;

mapping(DropERC1155 => DropInfo) public drops;
mapping(MintERC1155 => MintInfo) public mints;
Order[] public orders;
uint256 public nextOrderIdToFill;

event DropCreated(DropERC1155 indexed drop, DropArgs args);
event NFTMinted(DropERC1155 indexed drop, address indexed to, uint256 indexed tokenId);
event NFTRevealed(DropERC1155 indexed drop, uint256 indexed tokenId, uint256 indexed editionId);
event DropClaimed(DropERC1155 indexed drop, address indexed to, uint256 amount);
event MintCreated(MintERC1155 indexed mint, MintArgs args);
event NFTMinted(MintERC1155 indexed mint, address indexed to, uint256 indexed tokenId);
event NFTRevealed(MintERC1155 indexed mint, uint256 indexed tokenId, uint256 indexed editionId);
event MintClaimed(MintERC1155 indexed mint, address indexed to, uint256 amount);

constructor(address owner_) Ownable(owner_) {
DROP_NFT_LOGIC = address(new DropERC1155(address(this)));
MINT_NFT_LOGIC = address(new MintERC1155(address(this)));
}

function createDrop(DropArgs memory args) external returns (DropERC1155 drop) {
drop = DropERC1155(Clones.clone(DROP_NFT_LOGIC));
drop.initialize(address(this), args.editions);

DropInfo storage dropInfo = drops[drop];
dropInfo.owner = args.owner;
dropInfo.remainingMints = args.maxMints;
dropInfo.pricePerMint = args.pricePerMint;
dropInfo.feePerMint = args.feePerMint;
dropInfo.feeRecipient = args.feeRecipient;
dropInfo.perWalletLimit = args.perWalletLimit;
dropInfo.allowlistMerkleRoot = args.allowlistMerkleRoot;

emit DropCreated(drop, args);
function createMint(MintArgs memory args) external returns (MintERC1155) {
MintERC1155 newMint = MintERC1155(Clones.clone(MINT_NFT_LOGIC));
newMint.initialize(address(this), args.editions);

MintInfo storage mintInfo = mints[newMint];
mintInfo.owner = args.owner;
mintInfo.remainingMints = args.maxMints;
mintInfo.pricePerMint = args.pricePerMint;
mintInfo.feePerMint = args.feePerMint;
mintInfo.feeRecipient = args.feeRecipient;
mintInfo.perWalletLimit = args.perWalletLimit;
mintInfo.allowlistMerkleRoot = args.allowlistMerkleRoot;

emit MintCreated(newMint, args);
return newMint;
}

function mint(DropERC1155 drop, uint256 amount, bytes32[] calldata merkleProof) external payable {
function order(MintERC1155 mint, uint256 amount, bytes32[] calldata merkleProof) external payable {
if (amount > 100) {
revert("Exceeds max mint amount per tx");
revert("Exceeds max order amount per tx");
}

DropInfo storage dropInfo = drops[drop];
MintInfo storage mintInfo = mints[mint];

uint256 modifiedAmount = Math.min(amount, dropInfo.remainingMints);
dropInfo.remainingMints -= modifiedAmount;
uint256 totalCost = (dropInfo.pricePerMint + dropInfo.feePerMint) * modifiedAmount;
uint256 modifiedAmount = Math.min(amount, mintInfo.remainingMints);
mintInfo.remainingMints -= modifiedAmount;
uint256 totalCost = (mintInfo.pricePerMint + mintInfo.feePerMint) * modifiedAmount;

if (drops[drop].mintedPerWallet[msg.sender] + modifiedAmount > dropInfo.perWalletLimit) {
if (mints[mint].mintedPerWallet[msg.sender] + modifiedAmount > mintInfo.perWalletLimit) {
revert("Exceeds wallet limit");
}
drops[drop].mintedPerWallet[msg.sender] += modifiedAmount;
mints[mint].mintedPerWallet[msg.sender] += modifiedAmount;

require(msg.value >= totalCost, "Incorrect payment amount");

if (dropInfo.allowlistMerkleRoot != bytes32(0)) {
if (mintInfo.allowlistMerkleRoot != bytes32(0)) {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
require(MerkleProof.verify(merkleProof, dropInfo.allowlistMerkleRoot, leaf), "Invalid merkle proof");
require(MerkleProof.verify(merkleProof, mintInfo.allowlistMerkleRoot, leaf), "Invalid merkle proof");
}

orders.push(Order({ to: msg.sender, drop: drop, amount: modifiedAmount }));
orders.push(Order({ to: msg.sender, mint: mint, amount: modifiedAmount }));

(bool feeSuccess,) = dropInfo.feeRecipient.call{ value: dropInfo.feePerMint * modifiedAmount, gas: 100_000 }("");
(bool feeSuccess,) = mintInfo.feeRecipient.call{ value: mintInfo.feePerMint * modifiedAmount, gas: 100_000 }("");
(bool mintProceedsSuccess,) =
dropInfo.owner.call{ value: dropInfo.pricePerMint * modifiedAmount, gas: 100_000 }("");
mintInfo.owner.call{ value: mintInfo.pricePerMint * modifiedAmount, gas: 100_000 }("");

bool refundSuccess = true;
if (msg.value > totalCost) {
Expand All @@ -113,8 +114,8 @@ contract NFTMint is Ownable {
numOrdersToFill == 0 ? orders.length : Math.min(orders.length, nextOrderIdToFill_ + numOrdersToFill);

while (nextOrderIdToFill_ < finalNextOrderToFill) {
Order storage order = orders[nextOrderIdToFill_];
DropERC1155.Edition[] memory editions = order.drop.getAllEditions();
Order storage currentOrder = orders[nextOrderIdToFill_];
MintERC1155.Edition[] memory editions = currentOrder.mint.getAllEditions();

uint256[] memory ids = new uint256[](editions.length);
uint256[] memory amounts = new uint256[](editions.length);
Expand All @@ -123,7 +124,7 @@ contract NFTMint is Ownable {
ids[i] = i + 1;
}

for (uint256 i = 0; i < order.amount; i++) {
for (uint256 i = 0; i < currentOrder.amount; i++) {
uint256 roll = uint256(keccak256(abi.encodePacked(nonce++, blockhash(block.number - 1)))) % 100;

uint256 cumulativeChance = 0;
Expand All @@ -137,7 +138,7 @@ contract NFTMint is Ownable {
}

// If the mint fails with 500_000 gas, the order is still marked as filled.
try order.drop.mintBatch{ gas: 500_000 }(order.to, ids, amounts) { } catch { }
try currentOrder.mint.mintBatch{ gas: 500_000 }(currentOrder.to, ids, amounts) { } catch { }
delete orders[nextOrderIdToFill_];
nextOrderIdToFill_++;
}
Expand Down
22 changes: 11 additions & 11 deletions test/DropERC1155.t.sol → test/MintERC1155.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@
pragma solidity ^0.8.0;

import { TestBase } from "./util/TestBase.t.sol";
import { DropERC1155 } from "src/DropERC1155.sol";
import { MintERC1155 } from "src/MintERC1155.sol";
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
import { LintJSON } from "./util/LintJSON.t.sol";

contract DropERC1155Test is TestBase, LintJSON {
DropERC1155 token;
contract MintERC1155Test is TestBase, LintJSON {
MintERC1155 token;

function setUp() external {
DropERC1155 impl = new DropERC1155(address(this));
MintERC1155 impl = new MintERC1155(address(this));

DropERC1155.Attribute[] memory attributes = new DropERC1155.Attribute[](1);
attributes[0] = DropERC1155.Attribute({ traitType: "traitType", value: "value" });
MintERC1155.Attribute[] memory attributes = new MintERC1155.Attribute[](1);
attributes[0] = MintERC1155.Attribute({ traitType: "traitType", value: "value" });

DropERC1155.Edition[] memory editions = new DropERC1155.Edition[](2);
editions[0] = DropERC1155.Edition({
MintERC1155.Edition[] memory editions = new MintERC1155.Edition[](2);
editions[0] = MintERC1155.Edition({
name: "Edition 1",
imageURI: "https://example.com/image1.png",
percentChance: 80,
attributes: attributes
});
editions[1] = DropERC1155.Edition({
editions[1] = MintERC1155.Edition({
name: "Edition 2",
imageURI: "https://example.com/image2.png",
percentChance: 20,
attributes: new DropERC1155.Attribute[](0)
attributes: new MintERC1155.Attribute[](0)
});

token = DropERC1155(Clones.clone(address(impl)));
token = MintERC1155(Clones.clone(address(impl)));
token.initialize(address(this), editions);
}

Expand Down
24 changes: 12 additions & 12 deletions test/NFTMint.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.0;

import { TestBase } from "./util/TestBase.t.sol";
import { NFTMint } from "src/NFTMint.sol";
import { DropERC1155 } from "src/DropERC1155.sol";
import { MintERC1155 } from "src/MintERC1155.sol";

contract NFTMintTest is TestBase {
NFTMint nftMint;
Expand All @@ -12,25 +12,25 @@ contract NFTMintTest is TestBase {
nftMint = new NFTMint(address(this));
}

function test_createDrop() public returns (DropERC1155) {
DropERC1155.Attribute[] memory attributes = new DropERC1155.Attribute[](1);
attributes[0] = DropERC1155.Attribute({ traitType: "traitType", value: "value" });
function test_createMint() public returns (MintERC1155) {
MintERC1155.Attribute[] memory attributes = new MintERC1155.Attribute[](1);
attributes[0] = MintERC1155.Attribute({ traitType: "traitType", value: "value" });

DropERC1155.Edition[] memory editions = new DropERC1155.Edition[](2);
editions[0] = DropERC1155.Edition({
MintERC1155.Edition[] memory editions = new MintERC1155.Edition[](2);
editions[0] = MintERC1155.Edition({
name: "Edition 1",
imageURI: "https://example.com/image1.png",
percentChance: 80,
attributes: attributes
});
editions[1] = DropERC1155.Edition({
editions[1] = MintERC1155.Edition({
name: "Edition 2",
imageURI: "https://example.com/image2.png",
percentChance: 20,
attributes: new DropERC1155.Attribute[](0)
attributes: new MintERC1155.Attribute[](0)
});

NFTMint.DropArgs memory dropArgs = NFTMint.DropArgs({
NFTMint.MintArgs memory mintArgs = NFTMint.MintArgs({
maxMints: 100,
editions: editions,
allowlistMerkleRoot: bytes32(0),
Expand All @@ -41,16 +41,16 @@ contract NFTMintTest is TestBase {
feeRecipient: payable(address(this))
});

return nftMint.createDrop(dropArgs);
return nftMint.createMint(mintArgs);
}

function test_mint() public {
DropERC1155 drop = test_createDrop();
MintERC1155 mint = test_createMint();
address minter = _randomAddress();

vm.deal(minter, 10 ether);
vm.prank(minter);
nftMint.mint{ value: 1.1 ether }(drop, 100, new bytes32[](0));
nftMint.order{ value: 1.1 ether }(mint, 100, new bytes32[](0));

vm.roll(block.number + 1);
nftMint.fillOrders(0);
Expand Down

0 comments on commit 6e56da7

Please sign in to comment.