ERC721
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721URIStorage.sol)
pragma solidity ^0.8.20;
import {ERC721} from "../ERC721.sol";
import {Strings} from "../../../utils/Strings.sol";
import {IERC4906} from "../../../interfaces/IERC4906.sol";
import {IERC165} from "../../../interfaces/IERC165.sol";
/**
* @dev ERC721 token with storage based token URI management.
*/
abstract contract ERC721URIStorage is IERC4906, ERC721 {
using Strings for uint256;
// Interface ID as defined in ERC-4906. This does not correspond to a traditional interface ID as ERC-4906 only
// defines events and does not include any external function.
bytes4 private constant ERC4906_INTERFACE_ID = bytes4(0x49064906);
// Optional mapping for token URIs
mapping(uint256 tokenId => string) private _tokenURIs;
/**
* @dev See {IERC165-supportsInterface}
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) {
return interfaceId == ERC4906_INTERFACE_ID || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
_requireOwned(tokenId);
string memory _tokenURI = _tokenURIs[tokenId];
string memory base = _baseURI();
// If there is no base URI, return the token URI.
if (bytes(base).length == 0) {
return _tokenURI;
}
// If both are set, concatenate the baseURI and tokenURI (via string.concat).
if (bytes(_tokenURI).length > 0) {
return string.concat(base, _tokenURI);
}
return super.tokenURI(tokenId);
}
/**
* @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Emits {MetadataUpdate}.
*/
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
_tokenURIs[tokenId] = _tokenURI;
emit MetadataUpdate(tokenId);
}
}
NFT基础+计数器
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract GameItem is ERC721URIStorage {
// 引入计数器库中的函数
using Counters for Counters.Counter;
// 通过计数器生成私有的计数器变量,用于生成唯一的标识符
Counters.Counter private _tokenIds;
constructor() ERC721("GameItem", "USD") {}
function awardItem(address player, string memory tokenURI)
public
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(player, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
}
//使用Solidity5.9版本以下编译的智能合约才能部署在Xuperchain链上
pragma solidity ^0.5.0;
import "../.deps/node_modules/@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
import "../.deps/node_modules/@openzeppelin/contracts/drafts/Counters.sol";
import "../.deps/node_modules/@openzeppelin/contracts/ownership/Ownable.sol";
contract MyNFT is ERC721Full, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor()
public
ERC721Full("MyToken", "MTK")
{}
function safeMint(string memory uri) public onlyOwner {
uint256 tokenId = _tokenIds.current();
_tokenIds.increment();
_mint(msg.sender, tokenId);
_setTokenURI(tokenId, uri);
}
// The following functions are overrides required by Solidity.
function _transferFrom(address from, address to, uint256 tokenId)
internal
{
_transferFrom(from, to, tokenId);
}
function tokenURI(uint256 tokenId)
public
view
returns (string memory)
{
return tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
returns (bool)
{
return supportsInterface(interfaceId);
}
}
NFT基础合约
pragma solidity ^0.5.0;
import "../.deps/node_modules/@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
import "../.deps/node_modules/@openzeppelin/contracts/drafts/Counters.sol";
import "../.deps/node_modules/@openzeppelin/contracts/ownership/Ownable.sol";
contract MyNFT is ERC721Full, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
uint256 public MAX_AMOUNT = 3;
// 定义一个白名单 可以调用premint
mapping(address => bool) public whiteList;
// 定义一个变量 用于开放或者关闭提前铸造窗口
bool public preMintWindow = false;
bool public mintWindow = false;
constructor()
public
ERC721Full("Dogs", "DGS")
{}
// 为提前铸造NFT的提供内部优惠
function preMint(string memory uri) public payable {
require(preMintWindow, "Premint is not open yet!");
require(msg.value == 0.001 ether, "The price of dog nft is 0.005 ether.");
require(whiteList[msg.sender], "You are not in the whiteList.");
require(totalSupply() < MAX_AMOUNT, "Dog NFT is sold out!");
require(balanceOf(msg.sender) < 1, "Max amount of NFT minted by an adress is 1");
// 设置tokenid
uint256 tokenId = _tokenIds.current();
_tokenIds.increment();
// 铸造nft
_mint(msg.sender, tokenId);
// 设置该nft对应的tokenid对应的uri
_setTokenURI(tokenId, uri);
}
// NFT铸造代码
function safeMint(string memory uri) public payable onlyOwner {
require(mintWindow, "Mint is not open yet!");
require(msg.value == 0.005 ether, "The price of dog nft is 0.005 ether.");
require(totalSupply() < MAX_AMOUNT, "Dog NFT is sold out!");
uint256 tokenId = _tokenIds.current();
_tokenIds.increment();
_mint(msg.sender, tokenId);
_setTokenURI(tokenId, uri);
}
// 添加白名单 白名单的成员可以参与premint
function addToWhiteList(address[] memory addrs) public onlyOwner {
for (uint256 i = 0; i < addrs.length; i++) {
whiteList[addrs[i]] = true;
}
}
// 设置铸造窗口是否被打开
function setMintAndPreMintWindow(bool _preMint, bool _mint) public onlyOwner {
preMintWindow = _preMint;
mintWindow = _mint;
}
function _transferFrom(address from, address to, uint256 tokenId)
internal
{
_transferFrom(from, to, tokenId);
}
function tokenURI(uint256 tokenId)
public
view
returns (string memory)
{
return tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
returns (bool)
{
return supportsInterface(interfaceId);
}
}
NFT的Metadata
pragma solidity ^0.5.0;
import "../.deps/node_modules/@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
import "../.deps/node_modules/@openzeppelin/contracts/drafts/Counters.sol";
import "../.deps/node_modules/@openzeppelin/contracts/ownership/Ownable.sol";
contract MyNFT is ERC721Full, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
uint256 public MAX_AMOUNT = 3;
// 定义一个白名单 可以调用premint
mapping(address => bool) public whiteList;
// 定义一个变量 用于开放或者关闭提前铸造窗口
bool public preMintWindow = false;
bool public mintWindow = false;
event LogInt(uint message);
event LogString(string message);
// METADATA of NFT
string constant METADATA_SHIBAINU = "ipfs://QmXw7TEAJWKjKifvLE25Z9yjvowWk2NWY3WgnZPUto9XoA";
string constant METADATA_HUSKY = "ipfs://QmTFXZBmmnSANGRGhRVoahTTVPJyGaWum8D3YicJQmG97m";
string constant METADATA_BULLDOG = "ipfs://QmSM5h4WseQWATNhFWeCbqCTAGJCZc11Sa1P5gaXk38ybT";
string constant METADATA_SHEPHERD = "ipfs://QmRGryH7a1SLyTccZdnatjFpKeaydJcpvQKeQTzQgEp9eK";
constructor()
public
ERC721Full("Dogs", "DGS")
{}
// 为提前铸造NFT的提供内部优惠
function preMint() public payable {
require(preMintWindow, "Premint is not open yet!");
require(msg.value == 0.001 ether, "The price of dog nft is 0.005 ether.");
require(whiteList[msg.sender], "You are not in the whiteList.");
require(totalSupply() < MAX_AMOUNT, "Dog NFT is sold out!");
require(balanceOf(msg.sender) < 1, "Max amount of NFT minted by an adress is 1");
// 设置tokenid
uint256 tokenId = _tokenIds.current();
_tokenIds.increment();
// 铸造nft
_mint(msg.sender, tokenId);
// 设置该nft对应的tokenid对应的uri
uint256 randomNumber = random(4);
if (randomNumber == 0) {
_setTokenURI(tokenId, METADATA_SHIBAINU);
}
else if (randomNumber == 1) {
_setTokenURI(tokenId, METADATA_HUSKY);
}
else if (randomNumber == 2) {
_setTokenURI(tokenId, METADATA_BULLDOG);
}
else if (randomNumber == 3) {
_setTokenURI(tokenId, METADATA_SHEPHERD);
}
}
// NFT铸造代码
function safeMint() public payable onlyOwner {
require(mintWindow, "Mint is not open yet!");
require(msg.value == 0.005 ether, "The price of dog nft is 0.005 ether.");
require(totalSupply() < MAX_AMOUNT, "Dog NFT is sold out!");
uint256 tokenId = _tokenIds.current();
_tokenIds.increment();
_mint(msg.sender, tokenId);
// 设置该nft对应的tokenid对应的uri
uint256 randomNumber = random(4);
if (randomNumber == 0) {
_setTokenURI(tokenId, METADATA_SHIBAINU);
}
else if (randomNumber == 1) {
_setTokenURI(tokenId, METADATA_HUSKY);
}
else if (randomNumber == 2) {
_setTokenURI(tokenId, METADATA_BULLDOG);
}
else if (randomNumber == 3) {
_setTokenURI(tokenId, METADATA_SHEPHERD);
}
emit LogInt(tokenId);
}
// 添加白名单 白名单的成员可以参与premint
function addToWhiteList(address[] memory addrs) public onlyOwner {
for (uint256 i = 0; i < addrs.length; i++) {
whiteList[addrs[i]] = true;
}
}
// 设置铸造窗口是否被打开
function setMintAndPreMintWindow(bool _preMint, bool _mint) public onlyOwner {
preMintWindow = _preMint;
mintWindow = _mint;
}
// 取款函数
function withdraw(address payable addr) external onlyOwner {
addr.transfer(address(this).balance);
}
// 随机数
function random(uint number) public view returns(uint) {
return uint(keccak256(abi.encodePacked(block.timestamp,block.difficulty,
msg.sender))) % number;
}
function _transferFrom(address from, address to, uint256 tokenId)
internal
{
_transferFrom(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
returns (bool)
{
return supportsInterface(interfaceId);
}
}
添加NFT的一些基本功能,后续需要加上NFT管理合约
pragma solidity ^0.5.0;
import "../.deps/node_modules/@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
import "../.deps/node_modules/@openzeppelin/contracts/drafts/Counters.sol";
import "../.deps/node_modules/@openzeppelin/contracts/ownership/Ownable.sol";
contract NFT is ERC721Full, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
uint256 public MAX_AMOUNT = 3;
// 定义一个白名单 可以调用premint
mapping(address => bool) public whiteList;
// 记录铸造时间
mapping(uint256 => uint256) private mintTime;
// 定义枚举类型表示状态:审核中 / 预发行 / 发行中 / 已绝版 / 已销毁
enum Status { PendingReview, PreIssued, BeingIssued, OutOfPrint, Destroyed }
Status public nowStatus;
// NFT的价格(设定为ERC20同质化货币的数量)
uint256 public price;
// 版权信息结构体
struct Copyright {
// 作者
string author;
// 使用许可
string license;
}
// 将每一个拥有者映射到版权信息
mapping(address => Copyright) public copyright;
event LogInt(uint message);
event LogString(string message);
// METADATA of NFT
string constant METADATA_SHIBAINU = "ipfs://QmXw7TEAJWKjKifvLE25Z9yjvowWk2NWY3WgnZPUto9XoA";
string constant METADATA_HUSKY = "ipfs://QmTFXZBmmnSANGRGhRVoahTTVPJyGaWum8D3YicJQmG97m";
string constant METADATA_BULLDOG = "ipfs://QmSM5h4WseQWATNhFWeCbqCTAGJCZc11Sa1P5gaXk38ybT";
string constant METADATA_SHEPHERD = "ipfs://QmRGryH7a1SLyTccZdnatjFpKeaydJcpvQKeQTzQgEp9eK";
// 参数一:价格 / 参数二:nft被铸造的最大数量 / 参数三:
constructor(uint256 _price, uint256 _MAX_AMOUNT)
public
ERC721Full("Dogs", "DGS")
{
// 初始化nft的价格
setNFTValue(_price);
// 初始化产品发布的总数量
setMaxAmount(_MAX_AMOUNT);
// 初始化当前nft的状态
nowStatus = Status.PendingReview;
}
// 设置产品发布的总数量
function setMaxAmount(uint256 _MAX_AMOUNT) public {
MAX_AMOUNT = _MAX_AMOUNT;
}
// 设置当前的状态字段,通过后端审核然后更改状态,发行之后购买完变成已绝版
function setStatus(Status _nowStatus) public {
nowStatus = _nowStatus;
}
// 设置NFT的价格
function setNFTValue(uint256 _price) public {
price = _price;
}
// 获取当前区块的信息
function getBlockInfo() public view returns (
uint256 blockNumber,
address blockMiner,
uint256 blockParentHash
) {
blockNumber = block.number; // 当前区块号(区块哈希)
blockMiner = block.coinbase; // 当前区块的矿工地址(播报方)
// 当前区块的哈希值
// 区块被打包的时间
// 当前区块所包含的交易数量
blockParentHash = uint256(blockhash(block.number - 1)); // 当前区块的父区块的哈希值
}
// 溯源
// 得到指定tokenid的发行时间
function getMintTime(uint256 _tokenId) public view returns (uint256) {
return mintTime[_tokenId];
}
// 设置版权信息
function setCopyright(
string memory _author,
string memory _license
) public {
copyright[msg.sender] = Copyright({
author: _author,
license: _license
});
}
// 为提前铸造NFT的提供内部优惠
function preMint() public payable {
require(nowStatus == Status.PreIssued, "Premint is not open yet!");
require(msg.value == price / 5, "The price of dog nft is 0.005 ether.");
require(whiteList[msg.sender], "You are not in the whiteList.");
require(totalSupply() < MAX_AMOUNT, "Dog NFT is sold out!");
require(balanceOf(msg.sender) < 1, "Max amount of NFT minted by an adress is 1");
// 设置tokenid
uint256 tokenId = _tokenIds.current();
_tokenIds.increment();
// 铸造nft
_mint(msg.sender, tokenId);
// 设置该nft对应的tokenid对应的uri
uint256 randomNumber = random(4);
if (randomNumber == 0) {
_setTokenURI(tokenId, METADATA_SHIBAINU);
}
else if (randomNumber == 1) {
_setTokenURI(tokenId, METADATA_HUSKY);
}
else if (randomNumber == 2) {
_setTokenURI(tokenId, METADATA_BULLDOG);
}
else if (randomNumber == 3) {
_setTokenURI(tokenId, METADATA_SHEPHERD);
}
// 记录铸造时间
mintTime[tokenId] = block.timestamp;
// 统计totalSupply是不是已经到达最大值
if (totalSupply() == MAX_AMOUNT) {
nowStatus = Status.OutOfPrint;
}
}
// NFT铸造代码
function safeMint() public payable onlyOwner {
require(nowStatus == Status.BeingIssued, "Mint is not open yet!");
require(msg.value == price, "The price of dog nft is 0.005 ether.");
require(totalSupply() < MAX_AMOUNT, "Dog NFT is sold out!");
uint256 tokenId = _tokenIds.current();
_tokenIds.increment();
_mint(msg.sender, tokenId);
// 设置该nft对应的tokenid对应的uri
uint256 randomNumber = random(4);
if (randomNumber == 0) {
_setTokenURI(tokenId, METADATA_SHIBAINU);
}
else if (randomNumber == 1) {
_setTokenURI(tokenId, METADATA_HUSKY);
}
else if (randomNumber == 2) {
_setTokenURI(tokenId, METADATA_BULLDOG);
}
else if (randomNumber == 3) {
_setTokenURI(tokenId, METADATA_SHEPHERD);
}
// 记录铸造时间
mintTime[tokenId] = block.timestamp;
// 统计totalSupply是不是已经到达最大值
if (totalSupply() == MAX_AMOUNT) {
nowStatus = Status.OutOfPrint;
}
}
// 添加白名单 白名单的成员可以参与premint
function addToWhiteList(address[] memory addrs) public onlyOwner {
for (uint256 i = 0; i < addrs.length; i++) {
whiteList[addrs[i]] = true;
}
}
// 取款函数
function withdraw(address payable addr) external onlyOwner {
addr.transfer(address(this).balance);
}
// 随机数
function random(uint number) public view returns(uint) {
return uint(keccak256(abi.encodePacked(block.timestamp,block.difficulty,
msg.sender))) % number;
}
// function _transferFrom(address from, address to, uint256 tokenId)
// internal
// {
// _transferFrom(from, to, tokenId);
// }
// function supportsInterface(bytes4 interfaceId)
// public
// view
// returns (bool)
// {
// return supportsInterface(interfaceId);
// }
}