从0开始打造自己的第一个NFT,并将元数据上传到IPFS
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface INFT {
function setContractURI(string memory _contractURI) external returns(bool);
function createToken(string memory _tokenURI) external returns(uint256 tokenId);
function getInfo(uint256 _nftTokenId) external view returns (address, string memory, string memory, string memory);
function getTokens(address _user) external returns(uint256[] memory);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import './interfaces/INFT.sol';
contract NFT is INFT, ERC721Enumerable, ERC721URIStorage {
address public owner; // 记录合约发布者
uint256 public lastTokenId = 100000; // 记录最后1个tokenId,初始tokenId为100000
string public contractURI; // 如果上opensea会用到此参数
// 发布合约时,传入name和symbol两个参数
constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) {
owner = _msgSender();
}
// 设置contractURI参数
function setContractURI(string memory _contractURI) external override virtual returns(bool) {
require(msg.sender == owner, 'NFT: 4001');
contractURI = _contractURI;
return true;
}
// 创建token接口,传入tokenURI
function createToken(string memory _tokenURI) external override virtual returns(uint256 tokenId) {
// 此处要求只有合约发布者可以创建
require(_msgSender() == owner, "NFT: 4002");
tokenId = mint(owner, _tokenURI);
// 如果没有设置过contractURI,将第一个tokenURI设置给contractURI
if(bytes(contractURI).length == 0 ){
contractURI = _tokenURI;
}
}
// 传入tokenId,获取token详情(返回owner、symbol、name、tokenURI)
function getInfo(uint256 _tokenId) external view virtual override returns (address ownerAddress, string memory name, string memory symbol, string memory _tokenURI) {
ownerAddress = super.ownerOf(_tokenId);
name = super.name();
symbol = super.symbol();
_tokenURI = tokenURI(_tokenId);
}
// 私有函数,用于打造NFT
function mint(address _to, string memory _tokenURI) private returns (uint256) {
lastTokenId++; // tokenId加1
_mint(_to, lastTokenId); // 将token打造给_to
_setTokenURI(lastTokenId, _tokenURI); // 设置tokenURI
return lastTokenId;
}
// 根据tokenId获取tokenURI
function tokenURI(uint256 tokenId) public view virtual override (ERC721, ERC721URIStorage) returns (string memory) {
return super.tokenURI(tokenId);
}
// 燃烧token
function _burn(uint256 tokenId) internal virtual override (ERC721, ERC721URIStorage) {
require(tokenId > 0, "GoShard: 4003");
super._burn(tokenId);
}
// 在转赠NFT前执行的操作
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override(ERC721, ERC721Enumerable) {
// TODO 此处可以加入自己的逻辑
super._beforeTokenTransfer(from, to, tokenId);
}
// 判断支持的接口
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
// 获取指定地址拥有的全部token
function getTokens(address _user) external view override virtual returns(uint256[] memory) {
// 第一次遍历所有token,找到属于_user的token,记录到_userTokens数组
uint256[] memory _userTokens = new uint256[](lastTokenId);
uint256 idx = 0;
for(uint256 tokenId = 100000 + 1; tokenId <= lastTokenId; tokenId++){
if(super.ownerOf(tokenId) == _user){
_userTokens[idx] = tokenId;
idx++;
}
}
// idx为_userTokens数组长度,再次遍历,将值赋给新的数组userTokens
// 遍历两次是因为_userTokens的长度为lastTokenId,中间会有0值,第二次遍历实现将0值排除,保留有效的tokenId并返回
uint256[] memory userTokens = new uint256[](idx);
for(uint256 i = 0; i < idx; i++){
userTokens[i] = _userTokens[i];
}
return userTokens;
}
}
首先复制以上的NFT合约代码到Remix,新建一个openzeppelin erc721项目模板。在左侧项目结构的contracts目录下新建一个NFT.sol合约文件,粘贴以上代码到文件中。然后进行编译。如图: 编译成功后,选择Injected Web3,连接到自己的钱包。 在CONTRACT下拉列表中选择NFT.sol,填写name和symbol,点击deploy部署合约
部署成功后如下图所示,会生成合约地址:
这样我们的NFT合约就部署完成了。
视频讲解:https://www.bilibili.com/video/BV1D34y1p7Gt?share_source=copy_web
下一节,讲解如何创建元数据,并上传元数据到IPFS。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!