// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; contract SafeERC721Drop is ERC721, Ownable { uint256 public immutable cap; address payable public immutable treasury; uint256 public immutable mintPrice; uint256 public immutable perWalletCap; uint256 public totalMinted; mapping(address => uint256) public mintedBy; event Withdrawal(address indexed treasury, uint256 amount); constructor( string memory name_, string memory symbol_, uint256 cap_, address treasury_, uint256 mintPrice_, uint256 perWalletCap_, address initialOwner ) ERC721(name_, symbol_) Ownable(initialOwner) { require(cap_ > 0, "cap zero"); require(treasury_ != address(0), "treasury zero"); require(mintPrice_ > 0, "price zero"); require(perWalletCap_ > 0 && perWalletCap_ <= cap_, "wallet cap invalid"); cap = cap_; treasury = payable(treasury_); mintPrice = mintPrice_; perWalletCap = perWalletCap_; } function mint(uint256 quantity) external payable { require(quantity > 0, "quantity zero"); require(totalMinted + quantity <= cap, "collection cap"); require(mintedBy[msg.sender] + quantity <= perWalletCap, "wallet cap"); require(msg.value == mintPrice * quantity, "wrong payment"); mintedBy[msg.sender] += quantity; uint256 first = totalMinted + 1; totalMinted += quantity; for (uint256 tokenId = first; tokenId < first + quantity; tokenId++) { _safeMint(msg.sender, tokenId); } } function withdraw() external onlyOwner { uint256 amount = address(this).balance; (bool ok,) = treasury.call{value: amount}(""); require(ok, "withdraw failed"); emit Withdrawal(treasury, amount); } }