最近几年NFT火的一塌糊涂,各种数藏层出不穷。
多数都是采用了盲盒模式来玩,即购买的时候并不知道里面是什么,等到了一定的时间后,盲盒开启才会知道你买的 NFT 的具体属性,是否稀有等。
今天不讨论营销的模式,单纯从技术角度出发,如何制作出盲盒模式的NFT。
编写智能合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
/// @custom:security-contact bluequin@163.com
contract FdfNFT is ERC721, ERC721URIStorage, ERC721Burnable, AccessControl {
using Counters for Counters.Counter;
//是否开启盲盒
bool private _blindBoxOpened = false;
//设置盲盒uri
string baseUri;
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
Counters.Counter private _tokenIdCounter;
constructor() ERC721("FDF20220325FNFT", "FDF20220325FNFT") {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
}
function setBaseUri(string memory _baseUri) public {
require(
hasRole(DEFAULT_ADMIN_ROLE, _msgSender()),
"BaseERC721Uri: only admin can do this action"
);
baseUri = _baseUri;
}
function setBlindBoxOpened(bool _status) public {
require(
hasRole(DEFAULT_ADMIN_ROLE, _msgSender()),
"BaseERC721BlindBox: only admin can do this action"
);
_blindBoxOpened = _status;
}
function safeMint(address to, string memory uri) public onlyRole(MINTER_ROLE) {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
virtual
override(ERC721, ERC721URIStorage)
returns (string memory)
{
if(_blindBoxOpened){
return super.tokenURI(tokenId);
}else {
return baseUri;
}
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, AccessControl)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
发布合约到 rinkeby 测试环境
这里直接用 remix 发布就行
在浏览器中查看合约部署情况。 这里看到合约已经创建成功,合约地址 0x5a501c079DB0BeB9A50aCA810be9d7277080E1B4
编写图片服务器接口
图片可以上传到 ipfs,但考虑到需要收额外的手续费,以及更加灵活的和前端调用,所以这里采用自己编写服务器接口
接口代码,这里使用 java 编写
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`image` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `test` (`id`, `name`, `description`, `image`) VALUES (1, '开启盲盒,单车变摩托', '开启盲盒,单车变摩托', 'https://lh3.googleusercontent.com/Op-cRm7h8p34PvxvzZbHh5nAmkS2rVZYil1lUYfyKrI4WuEOTG9X3_C1KvtlXGdyfwG_5wyfyOBwIytw9JZVcAkPtXq4PAdLOsmS=w340');
INSERT INTO `test` (`id`, `name`, `description`, `image`) VALUES (2, '111', '朋克汽车', 'https://img01.jituwang.com/190326/256609-1Z326042P376.jpg');
INSERT INTO `test` (`id`, `name`, `description`, `image`) VALUES (3, '222', '朋克', 'https://img01.jituwang.com/190330/256613-1Z33016444621.jpg');
INSERT INTO `test` (`id`, `name`, `description`, `image`) VALUES (4, '333', '朋克', 'https://pic.ntimg.cn/file/20220107/32652940_141026506103_2.jpg');
INSERT INTO `test` (`id`, `name`, `description`, `image`) VALUES (5, '444', '金克斯', 'https://pic.ntimg.cn/file/20220218/33805678_164928525106_2.jpg');
INSERT INTO `test` (`id`, `name`, `description`, `image`) VALUES (6, '555', '源计划', 'https://img0.baidu.com/it/u=2501200624,302351145&fm=253&fmt=auto&app=138&f=PNG');
INSERT INTO `test` (`id`, `name`, `description`, `image`) VALUES (7, '666', '源计划', 'https://img2.baidu.com/it/u=2016764601,1618302265&fm=253&fmt=auto&app=138&f=PNG');
INSERT INTO `test` (`id`, `name`, `description`, `image`) VALUES (8, '777', '未来战士', 'https://img0.baidu.com/it/u=718823970,501814686&fm=253&fmt=auto&app=138&f=PNG');
接口返回 json 结构数据。包含三个字段
image:图片真实地址
name:图片名称
description:图片描述
铸造 NFT
1.调用 setBaseUri 方法,设置 baseUri 为盲盒图片
2.调用 safeMint 方法铸造 nft
这里多创建几个
进入 opensea 测试网查看
https://testnets.opensea.io/
可以看到 nft 盲盒如下
开启盲盒
调用 setBlindBoxOpened 方法开启盲盒
refresh metadata
可以看到所有图片都已经展示出来了。(两张图片依然为盲盒,是因为我铸造 NFT 的时候,图片就是盲盒图片,尴尬一下 😓)