// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; // Remix resolves this from npm automatically. Unlike the ERC-20 lesson, this // one inherits rather than reimplements: ERC-721 has enough edge cases around // safe transfers and receiver checks that hand-rolling it teaches the wrong // lesson. Read the standard, inherit the implementation. import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; /// @title SimpleNFT /// @notice A minimal ERC-721 that mints its first token while it is being /// deployed, so one transaction leaves you owning an NFT rather than /// an empty collection. /// /// Deploy it with a name and a ticker. The address that sends the deployment /// owns token 1 the moment it confirms. `mint` is there for the second one. /// /// Deployed in "Your First NFT" at /// https://litvm-academy.pro/build/your-first-nft contract SimpleNFT is ERC721 { /// @notice Id given to the next token minted. Starts at 1, because 0 reads /// as "no token" in far too much downstream code. uint256 public nextTokenId = 1; /// @param name_ Collection name, shown by wallets and explorers. /// @param symbol_ Short ticker for the collection. constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) { _mintNext(msg.sender); } /// @notice Mint another token to yourself. /// @dev No access control at all, so anyone can mint. That is deliberate /// for a teaching contract and would be a critical bug in a real one. function mint() external returns (uint256 tokenId) { return _mintNext(msg.sender); } function _mintNext(address to) private returns (uint256 tokenId) { tokenId = nextTokenId; // The counter moves before the mint, never after: `_safeMint` hands // control to a contract recipient, and a half-updated counter is how // the classic NFT drop exploit gets its second token for free. nextTokenId = tokenId + 1; // `_safeMint` rather than `_mint`: it checks that a contract recipient // knows how to receive an ERC-721, so tokens cannot be sent into a // contract that has no way to move them again. Deploying from a normal // wallet always passes that check. _safeMint(to, tokenId); } }