solscript-cli 0.1.1

CLI for SolScript - compile Solidity-style contracts to Solana
// NFT - Non-Fungible Token collection
// Demonstrates ERC721-style NFT with metadata

contract NFT {
    // Token metadata
    string public name;
    string public symbol;
    string public baseURI;

    // Token state
    uint256 public totalSupply;
    uint256 public maxSupply;
    uint256 public mintPrice;

    mapping(uint256 => address) public ownerOf;
    mapping(address => uint256) public balanceOf;
    mapping(uint256 => address) public getApproved;
    mapping(address => mapping(address => bool)) public isApprovedForAll;
    mapping(uint256 => string) private _tokenURIs;

    // Ownership
    address public owner;
    bool public mintingEnabled;

    // Events
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    event Minted(address indexed to, uint256 indexed tokenId);

    // Errors
    error Unauthorized();
    error TokenNotFound();
    error MaxSupplyReached();
    error MintingDisabled();
    error InsufficientPayment();
    error InvalidAddress();
    error NotApproved();

    // Modifiers
    modifier onlyOwner() {
        if (msg.sender != owner) revert Unauthorized();
        _;
    }

    modifier tokenExists(uint256 tokenId) {
        if (ownerOf[tokenId] == address(0)) revert TokenNotFound();
        _;
    }

    // Constructor
    constructor(
        string memory _name,
        string memory _symbol,
        uint256 _maxSupply,
        uint256 _mintPrice
    ) {
        name = _name;
        symbol = _symbol;
        maxSupply = _maxSupply;
        mintPrice = _mintPrice;
        owner = msg.sender;
        mintingEnabled = true;
    }

    // Mint a new NFT
    function mint() public payable returns (uint256) {
        if (!mintingEnabled) revert MintingDisabled();
        if (totalSupply >= maxSupply) revert MaxSupplyReached();
        if (msg.value < mintPrice) revert InsufficientPayment();

        totalSupply++;
        uint256 tokenId = totalSupply;

        ownerOf[tokenId] = msg.sender;
        balanceOf[msg.sender]++;

        emit Transfer(address(0), msg.sender, tokenId);
        emit Minted(msg.sender, tokenId);

        return tokenId;
    }

    // Owner can mint for free
    function ownerMint(address to) public onlyOwner returns (uint256) {
        if (to == address(0)) revert InvalidAddress();
        if (totalSupply >= maxSupply) revert MaxSupplyReached();

        totalSupply++;
        uint256 tokenId = totalSupply;

        ownerOf[tokenId] = to;
        balanceOf[to]++;

        emit Transfer(address(0), to, tokenId);
        emit Minted(to, tokenId);

        return tokenId;
    }

    // Transfer NFT
    function transferFrom(address from, address to, uint256 tokenId)
        public
        tokenExists(tokenId)
    {
        if (to == address(0)) revert InvalidAddress();

        address tokenOwner = ownerOf[tokenId];
        if (from != tokenOwner) revert Unauthorized();

        // Check authorization
        if (msg.sender != tokenOwner &&
            getApproved[tokenId] != msg.sender &&
            !isApprovedForAll[tokenOwner][msg.sender]) {
            revert NotApproved();
        }

        // Clear approval
        getApproved[tokenId] = address(0);

        // Transfer
        balanceOf[from]--;
        balanceOf[to]++;
        ownerOf[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    // Approve single token
    function approve(address to, uint256 tokenId) public tokenExists(tokenId) {
        address tokenOwner = ownerOf[tokenId];
        if (msg.sender != tokenOwner && !isApprovedForAll[tokenOwner][msg.sender]) {
            revert Unauthorized();
        }

        getApproved[tokenId] = to;
        emit Approval(tokenOwner, to, tokenId);
    }

    // Approve all tokens
    function setApprovalForAll(address operator, bool approved) public {
        if (operator == address(0)) revert InvalidAddress();
        isApprovedForAll[msg.sender][operator] = approved;
        emit ApprovalForAll(msg.sender, operator, approved);
    }

    // Toggle minting
    function setMintingEnabled(bool enabled) public onlyOwner {
        mintingEnabled = enabled;
    }

    // Update mint price
    function setMintPrice(uint256 _price) public onlyOwner {
        mintPrice = _price;
    }

    // Set base URI
    function setBaseURI(string memory _baseURI) public onlyOwner {
        baseURI = _baseURI;
    }
}