DreamEssenceNodeUpgradeable.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/common/ERC2981Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

/**
 * @title DreamEssenceNodeUpgradeable
 * @dev Upgradeable version of DreamEssenceNode NFT contract with UUPS proxy pattern
 */
contract DreamEssenceNodeUpgradeable is 
    Initializable, 
    ERC721Upgradeable, 
    ERC2981Upgradeable, 
    OwnableUpgradeable, 
    PausableUpgradeable,
    UUPSUpgradeable
{
    // using StringsUpgradeable for uint256; // Removed as it's unused

    uint96 private _nextTokenId;
    uint96 public constant MAX_SUPPLY = 10000;
    uint256 public mintPrice;  // Mint price in ETH
    
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }
    
    /**
     * @dev Initializes the contract replacing the constructor
     * @param initialOwner The initial owner of the contract.
     */
    function initialize(address initialOwner) public initializer {
        __ERC721_init("DreamEssenceNode", "DEN"); // Changed symbol to DEN
        __ERC2981_init();
        __Ownable_init(initialOwner);
        __Pausable_init();
        __UUPSUpgradeable_init();
        
        _setDefaultRoyalty(initialOwner, 250); // 2.5% royalty
        mintPrice = 0.01 ether;  // Default mint price: 0.01 ETH
    }
    
    /**
     * @dev Authorizes contract upgrade through the UUPS proxy pattern
     * Only callable by the owner
     */
    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}

    /**
     * @dev Mint a batch of NFTs
     * @param quantity Number of NFTs to mint (max 20)
     */
    function mint(uint96 quantity) public payable whenNotPaused {
        require(quantity > 0 && quantity <= 20, "Invalid quantity");
        require(msg.value >= mintPrice * quantity, "Insufficient payment");
        require(_nextTokenId + quantity <= MAX_SUPPLY, "Would exceed max supply");

        uint96 startTokenId = _nextTokenId;
        unchecked {
            for(uint96 i = 0; i < quantity; i++) {
                _safeMint(msg.sender, startTokenId + i);
            }
            _nextTokenId = startTokenId + quantity;
        }
    }

    /**
     * @dev Allow owner to withdraw contract funds
     */
    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        require(balance > 0, "No balance to withdraw");
        
        (bool success, ) = payable(owner()).call{value: balance}("");
        require(success, "Transfer failed");
    }

    /**
     * @dev Allow owner to update the mint price
     * @param newPrice New mint price in wei
     */
    function setMintPrice(uint256 newPrice) external onlyOwner {
        mintPrice = newPrice;
    }

    /**
     * @dev Emergency pause function
     */
    function pause() external onlyOwner {
        _pause();
    }

    /**
     * @dev Unpause the contract
     */
    function unpause() external onlyOwner {
        _unpause();
    }

    /**
     * @dev IERC165 override for ERC721 and ERC2981 compatibility
     */
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC721Upgradeable, ERC2981Upgradeable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}