NFT盲盒是什么意思?
正如玩家所说,你永远猜不到盒子里面是什么。这就是魅力所在。迎合了大众的心理,追求未知的刺激。现在盲盒也开始转移到线上,再次掀起浪潮。
就拿现在的NFT项目与盲盒结合举例来说,盲盒与挖矿的结合保证了项目的稳定发展和社区的持续活力。项目通过DeFi生态系统上流动性、产量矿池和NFT的独特性将其与盲盒游戏模式结合。
盲盒游戏软件开发的最大特点是写在智能合约上,保证公开透明,盲盒一旦满足相应的开奖条件后,点击立即开奖,开奖结果便已经生成,无法纂改。因为智能合约本身与其执行过程都是可观察的,支持监管和可信,智能合约中涉及的所有各方都确信该合同是以100%中立和无偏见的方式执行的,不会有欺诈、操纵或未经授权的修改风险。
合约部分
首先将本次合约部分的源码直接粘贴在remix中进行编译。源码如下:
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
contract NftMeta is ERC721Enumerable, Ownable {
using Strings for uint256;
// 是否准许nft开卖-开关
bool public _isSaleActive = false;
// 初始化盲盒,等到一定时机可以随机开箱,变成true
bool public _revealed = false;
// nft的总数量
uint256 public constant MAX_SUPPLY = 10;
// 铸造Nft的价格
uint256 public mintPrice = 0.3 ether;
// 铸造的钱包最多只能有一个nft数量
uint256 public maxBalance = 1;
// 一次mint的nft的数量
uint256 public maxMint = 1;
// 盲盒开关打开后,需要显示开箱的图片的base地址
string baseURI;
// 盲盒图片的meta,json地址,后文会提到
string public notRevealedUri;
// 默认地址的扩展类型
string public baseExtension = ".json";
mapping(uint256 => string) private _tokenURIs;
// 构造器
constructor(string memory initBaseURI, string memory initNotRevealedUri)
ERC721("Nft Meta", "NM") // 实现了ERC721的父类构造器,是子类继承的一种实现方式
{
setBaseURI(initBaseURI);
setNotRevealedURI(initNotRevealedUri);
}
// 外部地址进行铸造nft的函数调用
function mintNftMeta(uint256 tokenQuantity) public payable {
// 校验总供应量+每次铸造的数量<= nft的总数量
require(
totalSupply() + tokenQuantity <= MAX_SUPPLY,
"Sale would exceed max supply"
);
// 校验是否开启开卖状态
require(_isSaleActive, "Sale must be active to mint NicMetas");
// 校验铸造的钱包地址中的nft的数量 + 本次铸造的数量 <= 该钱包最大拥有的nft的数量
require(
balanceOf(msg.sender) + tokenQuantity <= maxBalance,
"Sale would exceed max balance"
);
// 校验本次铸造的数量*铸造的价格 <= 本次消息附带的eth的数量
require(
tokenQuantity * mintPrice <= msg.value,
"Not enough ether sent"
);
// 校验本次铸造的数量 <= 本次铸造的最大数量
require(tokenQuantity <= maxMint, "Can only mint 1 tokens at a time");
// 以上校验条件满足,进行nft的铸造
_mintNftMeta(tokenQuantity);
}
// 进行铸造
function _mintNftMeta(uint256 tokenQuantity) internal {
for (uint256 i = 0; i < tokenQuantity; i++) {
// mintIndex是铸造nft的序号,按照总供应量从0开始累加
uint256 mintIndex = totalSupply();
if (totalSupply() < MAX_SUPPLY) {
// 调用erc721的安全铸造方法进行调用
_safeMint(msg.sender, mintIndex);
}
}
}
// 返回每个nft地址的Uri,这里包含了nft的整个信息,包括名字,描述,属性等
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
require(
_exists(tokenId),
"ERC721Metadata: URI query for nonexistent token"
);
// 盲盒还没开启,那么默认是一张黑色背景图片或者其他图片
if (_revealed == false) {
return notRevealedUri;
}
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 abi.encodePacked).
if (bytes(_tokenURI).length > 0) {
return string(abi.encodePacked(base, _tokenURI));
}
// If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
return
string(abi.encodePacked(base, tokenId.toString(), baseExtension));
}
// internal
function _baseURI() internal view virtual override returns (string memory) {
return baseURI;
}
//only owner
function flipSaleActive() public onlyOwner {
_isSaleActive = !_isSaleActive;
}
function flipReveal() public onlyOwner {
_revealed = !_revealed;
}
function setMintPrice(uint256 _mintPrice) public onlyOwner {
mintPrice = _mintPrice;
}
function setNotRevealedURI(string memory _notRevealedURI) public onlyOwner {
notRevealedUri = _notRevealedURI;
}
function setBaseURI(string memory _newBaseURI) public onlyOwner {
baseURI = _newBaseURI;
}
function setBaseExtension(string memory _newBaseExtension)
public
onlyOwner
{
baseExtension = _newBaseExtension;
}
function setMaxBalance(uint256 _maxBalance) public onlyOwner {
maxBalance = _maxBalance;
}
function setMaxMint(uint256 _maxMint) public onlyOwner {
maxMint = _maxMint;
}
function withdraw(address to) public onlyOwner {
uint256 balance = address(this).balance;
payable(to).transfer(balance);
}
}