Nft智能合约发行,盲盒,公开发售技术实战--合约篇

这篇文章主要是从技术视角来给大家介绍一下nft主流的玩法-发行,盲盒,公开发售等流程步骤,这也是目前市场上大部分项目的玩法。

本次文章nft开发主要分为两部分: 1. 合约部分 2. 拼图部分。

本次Nft开发系列我也准备分为两篇文章进行讲解,今天主要讲解合约部分。

  合约部分主要是以下功能:
  • 建立和eth测试网互动的智能合约

  • Nft要能够被mint

  • Nft能够设定总量

  • Nft设定每个地址最大持有量

  • Nft要能够限定单次的mint的量

  • Nft要能够设定开关去公开发售

    拼图部分主要是以下功能:

  • 如何快速制作多种拼图以及meta资料

  • 如何上传ipfs星际网络系统(测试网)

    以上就是本次文章需要讲解的技术点。

开发之前,你需要准备好以下工具和环境。

  1. metamask钱包插件

    The crypto wallet for Defi, Web3 Dapps and NFTs | MetaMask

  2. remix在线编译环境

    Remix - Ethereum IDE

具体钱包的安装以及remix的使用,就不再这边讲解。

合约部分

首先将本次合约部分的源码直接粘贴在remix中进行编译。源码如下:

 
  1. // SPDX-License-Identifier: MIT

  2. pragma solidity ^0.8.10;

  3. import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

  4. import "@openzeppelin/contracts/access/Ownable.sol";

  5. import "@openzeppelin/contracts/utils/Strings.sol";

  6. contract NftMeta is ERC721Enumerable, Ownable {

  7. using Strings for uint256;

  8. // 是否准许nft开卖-开关

  9. bool public _isSaleActive = false;

  10. // 初始化盲盒,等到一定时机可以随机开箱,变成true

  11. bool public _revealed = false;

  12. // nft的总数量

  13. uint256 public constant MAX_SUPPLY = 10;

  14. // 铸造Nft的价格

  15. uint256 public mintPrice = 0.3 ether;

  16. // 铸造的钱包最多只能有一个nft数量

  17. uint256 public maxBalance = 1;

  18. // 一次mint的nft的数量

  19. uint256 public maxMint = 1;

  20. // 盲盒开关打开后,需要显示开箱的图片的base地址

  21. string baseURI;

  22. // 盲盒图片的meta,json地址,后文会提到

  23. string public notRevealedUri;

  24. // 默认地址的扩展类型

  25. string public baseExtension = ".json";

  26. mapping(uint256 => string) private _tokenURIs;

  27. // 构造器

  28. constructor(string memory initBaseURI, string memory initNotRevealedUri)

  29. ERC721("Nft Meta", "NM") // 实现了ERC721的父类构造器,是子类继承的一种实现方式

  30. {

  31. setBaseURI(initBaseURI);

  32. setNotRevealedURI(initNotRevealedUri);

  33. }

  34. // 外部地址进行铸造nft的函数调用

  35. function mintNftMeta(uint256 tokenQuantity) public payable {

  36. // 校验总供应量+每次铸造的数量<= nft的总数量

  37. require(

  38. totalSupply() + tokenQuantity <= MAX_SUPPLY,

  39. "Sale would exceed max supply"

  40. );

  41. // 校验是否开启开卖状态

  42. require(_isSaleActive, "Sale must be active to mint NicMetas");

  43. // 校验铸造的钱包地址中的nft的数量 + 本次铸造的数量 <= 该钱包最大拥有的nft的数量

  44. require(

  45. balanceOf(msg.sender) + tokenQuantity <= maxBalance,

  46. "Sale would exceed max balance"

  47. );

  48. // 校验本次铸造的数量*铸造的价格 <= 本次消息附带的eth的数量

  49. require(

  50. tokenQuantity * mintPrice <= msg.value,

  51. "Not enough ether sent"

  52. );

  53. // 校验本次铸造的数量 <= 本次铸造的最大数量

  54. require(tokenQuantity <= maxMint, "Can only mint 1 tokens at a time");

  55. // 以上校验条件满足,进行nft的铸造

  56. _mintNftMeta(tokenQuantity);

  57. }

  58. // 进行铸造

  59. function _mintNftMeta(uint256 tokenQuantity) internal {

  60. for (uint256 i = 0; i < tokenQuantity; i++) {

  61. // mintIndex是铸造nft的序号,按照总供应量从0开始累加

  62. uint256 mintIndex = totalSupply();

  63. if (totalSupply() < MAX_SUPPLY) {

  64. // 调用erc721的安全铸造方法进行调用

  65. _safeMint(msg.sender, mintIndex);

  66. }

  67. }

  68. }

  69. // 返回每个nft地址的Uri,这里包含了nft的整个信息,包括名字,描述,属性等

  70. function tokenURI(uint256 tokenId)

  71. public

  72. view

  73. virtual

  74. override

  75. returns (string memory)

  76. {

  77. require(

  78. _exists(tokenId),

  79. "ERC721Metadata: URI query for nonexistent token"

  80. );

  81. // 盲盒还没开启,那么默认是一张黑色背景图片或者其他图片

  82. if (_revealed == false) {

  83. return notRevealedUri;

  84. }

  85. string memory _tokenURI = _tokenURIs[tokenId];

  86. string memory base = _baseURI();

  87. // If there is no base URI, return the token URI.

  88. if (bytes(base).length == 0) {

  89. return _tokenURI;

  90. }

  91. // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).

  92. if (bytes(_tokenURI).length > 0) {

  93. return string(abi.encodePacked(base, _tokenURI));

  94. }

  95. // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.

  96. return

  97. string(abi.encodePacked(base, tokenId.toString(), baseExtension));

  98. }

  99. // internal

  100. function _baseURI() internal view virtual override returns (string memory) {

  101. return baseURI;

  102. }

  103. //only owner

  104. function flipSaleActive() public onlyOwner {

  105. _isSaleActive = !_isSaleActive;

  106. }

  107. function flipReveal() public onlyOwner {

  108. _revealed = !_revealed;

  109. }

  110. function setMintPrice(uint256 _mintPrice) public onlyOwner {

  111. mintPrice = _mintPrice;

  112. }

  113. function setNotRevealedURI(string memory _notRevealedURI) public onlyOwner {

  114. notRevealedUri = _notRevealedURI;

  115. }

  116. function setBaseURI(string memory _newBaseURI) public onlyOwner {

  117. baseURI = _newBaseURI;

  118. }

  119. function setBaseExtension(string memory _newBaseExtension)

  120. public

  121. onlyOwner

  122. {

  123. baseExtension = _newBaseExtension;

  124. }

  125. function setMaxBalance(uint256 _maxBalance) public onlyOwner {

  126. maxBalance = _maxBalance;

  127. }

  128. function setMaxMint(uint256 _maxMint) public onlyOwner {

  129. maxMint = _maxMint;

  130. }

  131. function withdraw(address to) public onlyOwner {

  132. uint256 balance = address(this).balance;

  133. payable(to).transfer(balance);

  134. }

  135. }

以上就是合约源码。

 对erc721的扩展部分和权限部分进行引用,同时进行继承,重写erc721的部分方法,下文会提到。

这些状态变量主要是用来对Nft的一些属性进行设置,包括总量,每个地址最多mint的数量等。

上面是铸造方法的实现,先进行铸造前的条件校验,然后调用erc721的_safemint安全方法进行铸造。

将合约代码进行部署,其中有几个注意的点

同时将测试网络切到Rinkeby测试网,同时需要提前通过faucet进行测试币的领取。领取地址:

Faucets | ChainlinkGet testnet LINK for an account on one of the supported blockchain testnets so you can create and test your own oracle and Chainlinked smart contract.正在上传…重新上传取消https://faucets.chain.link/FaucETH正在上传…重新上传取消https://fauceth.komputing.org/

Rinkeby: Authenticated Faucet正在上传…重新上传取消https://faucet.rinkeby.io/部署完成之后,会出现

在我们mint之前,需要进行开启铸造开关(红色框内),点击将状态变量变成true.

红色函数是铸造方法,填入数量1,同时因为我们在合约的状态变量设置了最小Mint的价格是0.3ether,因此我们需要在msg.value中附带ether数量从而完成mint。

因为红色框中是不允许输入小数的,因此,通过ether网站进行费用单位转换

Ethereum Unit Converter | Ether to Gwei, Wei, Finney, Szabo, Shannon etc.正在上传…重新上传取消https://eth-converter.com/

 将0.3ether输入,从而得到Gwei的数量,将该数量赋值到以上红框中进行mint。成功之后,就会在ipfs测试网看到一张编号为0的图片。ipfs测试网地址:

至此,我们nft开发中的合约部分已经完成。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于带版税的NFT智能合约的编写,我可以给您提供以下的建议: 首先,在智能合约的代码实现上,需要定义一个“版税”的变量或常量,用于记录每次NFT转移时需要支付给版权方的费用比例。下面是一个示例的Solidity智能合约实现: ``` pragma solidity ^0.8.0; contract NFTWithRoyalties { uint256 public royaltiesPercent = 10; // 设定版税比例,此处为10% struct Item { address owner; // 当前拥有者 uint256 price; // 当前价格 address payable[] royaltyReceivers; // 版税接收方,可以是多个账户 } // 定义NFT的拥有关系表 mapping(uint256 => Item) public items; // 转移NFT时触发的函数,将版税转账给版权方 function transfer( uint256 tokenId, address payable to ) public payable { Item storage item = items[tokenId]; address from = item.owner; require( from == msg.sender, "transfer: caller is not owner" ); require( to != address(0), "transfer: invalid recipient" ); uint256 price = item.price; uint256 royalties = price * royaltiesPercent / 100; uint256 transferAmount = price - royalties; item.owner = to; item.price = 0; // 将交易款项转账给卖家 (bool success, ) = to.call{value: transferAmount}(""); require(success, "transfer: transfer failed"); // 将版税转账给版权方 for (uint i = 0; i < item.royaltyReceivers.length; i++) { (bool success, ) = item.royaltyReceivers[i].call{value: royalties / item.royaltyReceivers.length}(""); require(success, "transfer: transfer failed"); } } // 改变NFT价格 function setPrice(uint256 tokenId, uint256 price) public { Item storage item = items[tokenId]; address owner = item.owner; require( owner == msg.sender, "setPrice: caller is not owner" ); item.price = price; } // 添加版权方 function addRoyaltyReceiver(uint256 tokenId, address payable receiver) public { Item storage item = items[tokenId]; address owner = item.owner; require( owner == msg.sender, "addRoyaltyReceiver: caller is not owner" ); item.royaltyReceivers.push(receiver); } } ``` 上面的示例代码实现了一个基本的NFT智能合约,并对NFT转移、价格设置和版权方管理等功能进行了实现。其中,版税比例设定为10%,而版权方可以是多个账户。在每次NFT转移时,智能合约会将版税的总额平均分配给每个版权方账户。 另外,在应用场景上,您可以将这个智能合约用于一些具有版权保护需求的数字艺术品、音乐或视频等领域,在用户购买版权时,您可以根据合约规则自动进行版权费用的分配和转账等操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值