diff --git a/src/NFTMint.sol b/src/NFTMint.sol index 02497c0..fae205e 100644 --- a/src/NFTMint.sol +++ b/src/NFTMint.sol @@ -20,7 +20,7 @@ contract NFTMint is Ownable { error NFTMint_InvalidPerWalletLimit(); error NFTMint_InvalidMaxMints(); error NFTMint_InvalidOwner(); - error NFTMint_InvalidFeeRecipient(); + error NFTMint_InsufficientFee(); event MintCreated(MintERC1155 indexed mint, MintArgs args); event OrderPlaced( @@ -38,8 +38,6 @@ contract NFTMint is Ownable { uint96 feePerMint; // Address of the owner of the mint address payable owner; - // Address to receive the fee - address payable feeRecipient; // Timestamp when the mint expires uint40 mintExpiration; // Merkle root for the allowlist @@ -72,8 +70,6 @@ contract NFTMint is Ownable { uint32 perWalletLimit; // Timestamp when the mint expires uint40 mintExpiration; - // Address to receive the fee - address payable feeRecipient; // Merkle root for the allowlist bytes32 allowlistMerkleRoot; // Mapping of addresses to the number of mints they have made @@ -103,8 +99,15 @@ contract NFTMint is Ownable { /// @notice Array of all orders placed. Filled orders are deleted. Order[] public orders; - constructor(address owner_) Ownable(owner_) { + /// @notice Address of the mint fee recipient + address payable public immutable FEE_RECIPIENT; + + /// @notice Minimum fee per mint (approximately $0.05) + uint96 public constant MIN_FEE_PER_MINT = 0.00002 ether; + + constructor(address owner_, address feeRecipient_) Ownable(owner_) { MINT_NFT_LOGIC = address(new MintERC1155(address(this))); + FEE_RECIPIENT = payable(feeRecipient_); } /** @@ -124,8 +127,8 @@ contract NFTMint is Ownable { if (args.owner == address(0)) { revert NFTMint_InvalidOwner(); } - if (args.feeRecipient == address(0) && args.feePerMint != 0) { - revert NFTMint_InvalidFeeRecipient(); + if (args.feePerMint < MIN_FEE_PER_MINT) { + revert NFTMint_InsufficientFee(); } MintERC1155 newMint = MintERC1155( @@ -139,7 +142,6 @@ contract NFTMint is Ownable { mintInfo.remainingMints = args.maxMints; mintInfo.pricePerMint = args.pricePerMint; mintInfo.feePerMint = args.feePerMint; - mintInfo.feeRecipient = args.feeRecipient; mintInfo.perWalletLimit = args.perWalletLimit; mintInfo.allowlistMerkleRoot = args.allowlistMerkleRoot; mintInfo.mintExpiration = args.mintExpiration; @@ -203,11 +205,8 @@ contract NFTMint is Ownable { ); { - bool feeSuccess = true; - if (mintInfo.feePerMint > 0) { - (feeSuccess,) = - mintInfo.feeRecipient.call{ value: mintInfo.feePerMint * modifiedAmount, gas: 100_000 }(""); - } + (bool feeSuccess,) = FEE_RECIPIENT.call{ value: mintInfo.feePerMint * modifiedAmount, gas: 100_000 }(""); + bool mintProceedsSuccess = true; if (mintInfo.pricePerMint > 0) { (mintProceedsSuccess,) = diff --git a/test/NFTMint.t.sol b/test/NFTMint.t.sol index b7f8b81..fb1d30d 100644 --- a/test/NFTMint.t.sol +++ b/test/NFTMint.t.sol @@ -9,9 +9,10 @@ import { MockFailingRecipient } from "./util/MockFailingRecipient.sol"; contract NFTMintTest is TestBase { NFTMint nftMint; + address feeRecipient = vm.createWallet("feeRecipient").addr; function setUp() external { - nftMint = new NFTMint(address(this)); + nftMint = new NFTMint(address(this), feeRecipient); } function test_createMint() public returns (MintERC1155) { @@ -47,7 +48,6 @@ contract NFTMintTest is TestBase { perWalletLimit: 105, feePerMint: 0.001 ether, owner: payable(address(this)), - feeRecipient: payable(address(this)), name: "My Token Name", imageURI: "image here", description: "This is a description", @@ -78,7 +78,6 @@ contract NFTMintTest is TestBase { perWalletLimit: 105, feePerMint: 0.001 ether, owner: payable(address(this)), - feeRecipient: payable(address(this)), name: "My Token Name", imageURI: "image here", description: "This is a description", @@ -110,7 +109,6 @@ contract NFTMintTest is TestBase { perWalletLimit: 0, feePerMint: 0.001 ether, owner: payable(address(this)), - feeRecipient: payable(address(this)), name: "My Token Name", imageURI: "image here", description: "This is a description", @@ -142,7 +140,6 @@ contract NFTMintTest is TestBase { perWalletLimit: 1, feePerMint: 0.001 ether, owner: payable(address(this)), - feeRecipient: payable(address(this)), name: "My Token Name", imageURI: "image here", description: "This is a description", @@ -174,7 +171,6 @@ contract NFTMintTest is TestBase { perWalletLimit: 1, feePerMint: 0.001 ether, owner: payable(address(0)), - feeRecipient: payable(address(this)), name: "My Token Name", imageURI: "image here", description: "This is a description", @@ -185,38 +181,6 @@ contract NFTMintTest is TestBase { nftMint.createMint(mintArgs); } - function test_createMint_invalidFeeRecipient() external { - MintERC1155.Attribute[] memory attributes = new MintERC1155.Attribute[](1); - attributes[0] = MintERC1155.Attribute({ traitType: "traitType", value: "value" }); - - MintERC1155.Edition[] memory editions = new MintERC1155.Edition[](1); - editions[0] = MintERC1155.Edition({ - name: "Edition 1", - imageURI: "https://example.com/image1.png", - percentChance: 100, - attributes: attributes - }); - - NFTMint.MintArgs memory mintArgs = NFTMint.MintArgs({ - mintExpiration: uint40(block.timestamp + 1 days), - maxMints: 1, - editions: editions, - allowlistMerkleRoot: bytes32(0), - pricePerMint: 0.01 ether, - perWalletLimit: 1, - feePerMint: 0.001 ether, - owner: payable(address(this)), - feeRecipient: payable(address(0)), - name: "My Token Name", - imageURI: "image here", - description: "This is a description", - royaltyAmountBps: 150 - }); - - vm.expectRevert(NFTMint.NFTMint_InvalidFeeRecipient.selector); - nftMint.createMint(mintArgs); - } - event OrderPlaced( MintERC1155 indexed mint, uint256 indexed orderId, address indexed to, uint256 amount, string comment ); @@ -365,7 +329,6 @@ contract NFTMintTest is TestBase { perWalletLimit: 105, feePerMint: 0.001 ether, owner: payable(address(this)), - feeRecipient: payable(address(this)), name: "My Token Name", imageURI: "image here", description: "This is a description", @@ -394,7 +357,7 @@ contract NFTMintTest is TestBase { attributes: attributes }); - address minter = _randomAddress(); + address minter = address(new MockFailingRecipient()); vm.deal(minter, 10 ether); vm.prank(minter); @@ -409,7 +372,6 @@ contract NFTMintTest is TestBase { perWalletLimit: 105, feePerMint: 0.001 ether, owner: payable(address(this)), - feeRecipient: payable(address(new MockFailingRecipient())), name: "My Token Name", imageURI: "image here", description: "This is a description", @@ -420,7 +382,7 @@ contract NFTMintTest is TestBase { vm.expectRevert(NFTMint.NFTMint_FailedToTransferFunds.selector); vm.prank(minter); - nftMint.order{ value: 0.011 ether }(mint, 1, "", new bytes32[](0)); + nftMint.order{ value: 0.012 ether }(mint, 1, "", new bytes32[](0)); } event OrderFilled(