solidity实现智能合约教程(2)-ERC721合约

猛戳订阅学习专栏🍁🍁 👉 solidity系列合约源码+解析 👈 🍁🍁

在这里插入图片描述

1 介绍

和ERC20一样,ERC721同样是一个以太坊代币标准,此代币英文是Non-Fungible Tokens,简写为NFT,即非同质化代币

非同质代币(NFT)是一种具有唯一性识别的代币 ,ERC-20 Token可以无限细分为10^18份,而ERC721的Token最小的单位为1,无法再分割。

由于ERC721代币具有唯一性,不可分割的特点,所以很容易和一些具体的物品关联起来,通过这样一个标准,可以更广泛的应用到实际场景中。

2 主要功能

该标准定义了开发者可以按照标准要求使用一些简单的功能如:

  • 设定NFT名称
  • 设定NFT总量
  • 设定NFT元数据资源url
  • 查看地址中NFT数量
  • 查看NFT的归属地址
  • 规范如何批准NFT转移
  • 一定条件下,允许第三方地址使用某地址中的NFT
  • 允许NFT和兼容ETH的智能合约兼容
    以及一些简单的函数功能等等。

我们先来看一下标准的 ERC721 接口:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IERC721 {

    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);

   function name() external view returns (string _name);
   
   function symbol() external view returns (string _symbol);
   
   function tokenURI(uint256 _tokenId) external view returns (string);

    function balanceOf(address owner) external view returns (uint256 balance);

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function approve(address to, uint256 tokenId) external;

    function setApprovalForAll(address operator, bool _approved) external;

    function getApproved(uint256 tokenId) external view returns (address operator);

    function isApprovedForAll(address owner, address operator) external view returns (bool);
}


下面我们解释一下上述每个接口函数的作用:

  • event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) 当任何NFT的所有权更改时(不管哪种方式),就会触发此事件。

  • event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); 当更改或确认NFT的授权地址时触发。零地址表示没有授权的地址。发生 Transfer 事件时,同样表示该NFT的授权地址(如果有)被重置为“无”(零地址)。

  • event ApprovalForAll(address indexed owner, address indexed operator, bool approved); 所有者启用或禁用操作员时触发。(操作员可管理所有者所持有的NFTs)

  • function name() external view returns (string _name); NFTs 集合的名字

  • function symbol() external view returns (string _symbol); NFTs 缩写代号

  • function tokenURI(uint256 _tokenId) external view returns (string); 一个给定资产的唯一的统一资源标识符(URI),一般为1个JSON文件。

  • function balanceOf(address owner) external view returns (uint256 balance); 统计owner 地址所持有的NFTs数量

  • function ownerOf(uint256 tokenId) external view returns (address owner); 返回指定NFT的所有者

  • function safeTransferFrom(address from,address to,uint256 tokenId,bytes calldata data) external; 将NFT的所有权从一个地址转移到另一个地址,data : 附加额外的参数(没有指定格式),传递给接收者。

  • function safeTransferFrom(address from,address to,uint256 tokenId) external; 将NFT的所有权从一个地址转移到另一个地址,功能同上,不带data参数。

  • function transferFrom(address from,address to,uint256 tokenId) external; 转移所有权 – 调用者负责确认_to是否有能力接收NFTs,否则可能永久丢失。一般不建议使用该方法转移NFT

  • function approve(address to, uint256 tokenId) external; 更改或确认NFT的授权地址

  • function setApprovalForAll(address operator, bool _approved) external; 启用或禁用第三方(操作员)管理 msg.sender 所有NFT,触发 ApprovalForAll 事件。

  • function getApproved(uint256 tokenId) external view returns (address operator); 获取单个NFT的授权地址

  • function isApprovedForAll(address owner, address operator) external view returns (bool); 查询一个地址是否是另一个地址的授权操作员

3 代码示例

下面我们借助openzeppelin智能合约库来写一个ERC721合约,来实现NFT的铸造、销毁和URL设定等功能。

// SPDX-License-Identifier: MIT;

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";


contract TestNFT is ERC721,ERC721Enumerable, ERC721URIStorage {

    using Counters for Counters.Counter;
    Counters.Counter private _tokenId;

    constructor() ERC721("The First NFT","FFT") {}

    function mint(address _recipient, string memory _tokenUrl) public returns(uint _mintTokenId){
        require(bytes(_tokenUrl).length > 0,"The _tokenUrl must be have");
        _tokenId.increment();
        uint newTokenId = _tokenId.current();
        _mint(_recipient, newTokenId);
        _setTokenURI(newTokenId, _tokenUrl);
        return newTokenId;
    }


    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}

下面解释一下上面用到的合约和方法:

  • @openzeppelin/contracts/token/ERC721/ERC721.sol 该合约实现了我们上面列出的IERC721接口中的方法

  • @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol 该合约为一个枚举合约,包含了按索引获取到对应的NFT,可以提供NFTs的完整列表,以便NFT可被发现。

  • @openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol 该合约帮我们实现了TOKEN的URI的设定和读取方法

  • @openzeppelin/contracts/utils/Counters.sol 该合约帮我们实现了Token的自增ID

  • constructor() 我们在构造方法中实现了设定该合约生成的NFT的名称的设定(The First NFT)、简写的设定(FFT)

  • mint() 为_recipient地址铸造一个NFT,并将其元数据URL设置为_tokenUrl

  • _beforeTokenTransfer() 重写_beforeTokenTransfer方法

  • _burn() 销毁某个NFT

  • tokenURI() 获取指定NFT的URL信息

  • supportsInterface() 重写supportsInterface方法

4 部署测试

在这里插入图片描述
我们选择要部署的合约为 TestNFT ,点击 Deploy 进行部署,可以看到部署后的合约地址和相应的合约方法

在这里插入图片描述
分别查看 name 和symbol为我们为合约设置的 名称 和 简写

在这里插入图片描述
我们选择一个地址,并设置一个URL,为其mint 1个NFT,可以看到output中输出的tokenid为 1 ,代表着我们成功为该地址铸造了一个tokenid为1的NFT,下面让我们查看一下:

在这里插入图片描述
我们可以查询到该地址的NFT数量为1,其token的URL为我们为其设定的URL,这样一个NFT的铸造就完成了~

如果我们部署时选择的链是测试链或者主链,那么我们就可以在opensea中看到我们刚才铸造的NFT啦!!!

如果有小伙伴想了解怎么把NFT的图片存储到IPFS上去的,可以先参考我之前的一篇文章,后面我们会展开详解关于IPFS的内容和教程:https://blog.csdn.net/qq_36228377/article/details/123154404

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值