NFT-20200202

NFT Intermediate February 2, 2020

Back to All Tasks

Problem Statement

You are tasked with creating a simple ERC-721 compliant non-fungible token (NFT) smart contract on the Ethereum blockchain. Your NFT will represent unique digital art pieces that can be bought, sold, or traded by users in a decentralized manner. The smart contract should allow an artist to mint new tokens and set individual metadata URLs for each NFT, which contain information about the art piece such as title, description, and image URL.

Implement the following functionalities:
1. A function to mint a new NFT with a specified token URI that contains the metadata of the art piece.
2. A method to transfer ownership of an NFT from one user to another.
3. A mechanism to ensure only the artist (contract owner) can mint new tokens.

Considerations:
- Ensure proper event emission for all critical actions like minting and transferring NFTs.
- Implement basic error handling to prevent unauthorized access or incorrect operations.

Concepts

  • ERC-721 standard
  • Smart Contracts
  • Minting NFTs

Constraints

  • The contract must follow ERC-721 standards.
  • Only the contract owner can mint new tokens.
  • Each token should have a unique URI that stores its metadata.

Security Notes

  • Ensure proper input validation to avoid reentrancy attacks when transferring ownership.
  • Use safe math operations provided by OpenZeppelin or similar libraries to prevent overflow and underflow vulnerabilities in your smart contract.

Solutions

C Solution

pragma solidity ^0.8.0;

import \"@openzeppelin/contracts/token/ERC721/ERC721.sol\";
import \"@openzeppelin/contracts/utils/math/SafeMath.sol\";
import \"@openzeppelin/contracts/access/Ownable.sol\";

/// @title Simple ERC-721 NFT Contract
/// @author Your Name
/// @notice This contract allows an artist to mint new tokens and set individual metadata URLs for each NFT.
contract DigitalArtNFT is ERC721, Ownable {
    using SafeMath for uint256;

    /// @dev Initializes the contract with a name and symbol
    constructor() ERC721(\"DigitalArtNFT\", \"DAN\") {}

    /// @notice Mints a new NFT to the specified address with given token URI.
    /// @param _to The recipient of the minted NFT.
    /// @param _tokenURI The metadata URL for the NFT.
    function mintNFT(address _to, string memory _tokenURI) public onlyOwner {
        uint256 tokenId = totalSupply().add(1);
        _safeMint(_to, tokenId);
        _setTokenURI(tokenId, _tokenURI);

        // Emitting an event to signal successful minting.
        emit MintedNFT(_to, tokenId, _tokenURI);
    }

    /// @notice Transfers ownership of an NFT from one user to another.
    /// @param _from The current owner of the NFT.
    /// @param _to The recipient of the NFT.
    /// @param _tokenId The ID of the token being transferred.
    function transferNFT(address _from, address _to, uint256 _tokenId) public {
        require(_isApprovedOrOwner(_msgSender(), _tokenId), \"ERC721: transfer caller is not owner nor approved\);
        safeTransferFrom(_from, _to, _tokenId);

        // Emitting an event to signal successful transfer.
        emit TransferredNFT(_from, _to, _tokenId);
    }

    /// @dev Event emitted when a new NFT is minted.
    /// @param to The recipient of the minted NFT.
    /// @param tokenId The ID of the minted NFT.
    /// @param tokenURI The metadata URL for the NFT.
    event MintedNFT(address indexed to, uint256 indexed tokenId, string tokenURI);

    /// @dev Event emitted when an NFT is transferred from one address to another.
    /// @param from The original owner of the NFT.
    /// @param to The new owner of the NFT.
    /// @param tokenId The ID of the transferred NFT.
    event TransferredNFT(address indexed from, address indexed to, uint256 indexed tokenId);
}

This Solidity smart contract implements a simple ERC-721 compliant Non-Fungible Token (NFT) system for representing unique digital art pieces. It leverages OpenZeppelin's ERC721 and Ownable libraries to ensure adherence to the ERC-721 standard and manage ownership permissions, respectively.

The contract starts by importing necessary libraries: SafeMath for safe arithmetic operations, ERC721 for implementing the NFT functionality, and Ownable for managing the owner of the contract. The constructor initializes the token with a name \"DigitalArtNFT\" and symbol \"DAN\".
The mintNFT function allows only the contract owner to create new tokens by specifying the recipient's address and the metadata URI containing details about the digital art. It uses safeMint to ensure that the operation complies with ERC-721 standards, emits a MintedNFT event upon successful creation, and sets the token URI using _setTokenURI.
The transferNFT function enables transferring an NFT from one user to another, ensuring that only the owner of the NFT or someone approved by the owner can perform this action. It uses safeTransferFrom for secure transfers and emits a TransferredNFT event upon successful completion.
Events are crucial in blockchain development as they allow off-chain applications to react to smart contract actions efficiently without needing to continuously poll the blockchain state.