如何在NFT(ERC721)中获取随机数

  • Chainlink
  • 更新于 2022-04-25 09:50
  • 阅读 1638

在遵循ERC721(http://erc721.org/) 标准的非同质化代币(NFT)中生成随机数一直是智能合约开发者面临的难题。现在,Chainlink VRF 已经在主网上线,基于Solidity的智能合约可以无缝生成防篡改的链上随机数,这些随机数可以证明是公平的,并且有密码学证明支持。

1.png

介绍

在遵循ERC721(http://erc721.org/)标准的非同质化代币(NFT)中生成随机数一直是智能合约开发者面临的难题。现在,[Chainlink VRF](http://mp.weixin.qq.com/s?__biz=MzU0MTgyMDQwNQ==&mid=2247484649&idx=1&sn=97028622cec3dab6b8bdf12087377ddf&chksm=fb255073cc52d965457097cf9fdbbd5c056dab23f90f208a75f259c7d1b0a5bd58f4b1daf411&scene=21#wechat_redirect)已经在主网上线,基于Solidity的智能合约可以无缝生成防篡改的链上随机数,这些随机数可以证明是公平的,并且有密码学证明支持。有了Chainlink VRF,创建需要安全随机性来源的动态NFT变得非常简单、安全。虽然Chainlink也可以使用链外数据源为NFT实现任何类型的动态属性,但我们将专注于使用ERC721的随机数,或NFT。

在本教程中,我们将在以太坊区块链上构建一个龙与地下城角色!D&D(Dungeons and Dragons)是一款流行的角色扮演游戏(RPG),人们在游戏中创建角色并进行冒险。创建角色的重要环节之一是给他们赋予属性或统计数据,以显示他们的力量、敏捷、智力等。为了在区块链上为他们的统计数据创建真正的随机数,我们将展示如何使用Chainlink VRF给你的角色随机属性。使用Chainlink VRF,区块链中的随机数生成很简单!

什么是NFT?

NFT(遵循ERC721标准)定义了一个框架,用于制作独一无二且彼此不同的代币(因此被称为非同质化),而流行的ERC20标准则定义了 "同质化 "的代币,这意味着代币都可以互换,并保证具有相同的价值。"同质化 "货币的例子是美元、欧元和日元,而可互换区块链代币的例子是AAVE、SNX和YFI。在这些情况下,1个同质化的代币等于1个同类的另一个代币,就像1美元等于1美元,1LINK等于1LINK一样。然而,NFT/ ERC721是不同的,因为每个代币都是独一无二的,并不代表相同的价值或可互换的项目。

由于所有的NFT都是独一无二的,它们可以代表现实世界资产的代币化所有权要求,如一块特定的土地,或数字资产的实际所有权,如稀有的数字交易卡。而且它们越来越受欢迎。你可以参考OpenSea的NFT圣经来阅读更多内容。

构建你的随机角色

我们要看的是创造一个具有D&D角色六大属性的角色,即:

uint256 strength;
uint256 dexterity;
uint256 constitution;
uint256 intelligence;
uint256 wisdom;
uint256 charisma;

角色还包含:

uint256 experience;
string name;

所以我们可以把它们的等级提高,并给它们起一个有趣的名字。

我们在这里采取了一些自由的做法,并没有100%遵循龙与地下城的指导,但如果你想更准确地表现游戏,这可以很容易地修改。

这份合约应该确立以下内容:

  1. 允许你转让NFT的所有权 和所有其他NFT标准。
  2. 给这个角色一个名字和随机属性。

我们不去制作合约的动态,但请继续关注未来的一篇文章,它将在我们在这里学到的知识的基础上构建!

我们已经为你建立了代码仓库,我们将介绍如何使用代码仓库开始工作!

克隆代码

git clone https://github.com/PatrickAlphaC/dungeons-and-dragons-nft
cd dungeons-and-dragons-nft
npm install

设置环境变量

你需要一个MNEMONIC和一个rinkeby网络的 RINKEBY_RPC_URL环境变量。MNEMONIC是你的钱包的助记词。你可以从节点提供者服务中找到一个RINKEBY_RPC_URL,比如Infura(https://infura.io/)。

然后,要么在bash_profile文件中设置它们,要么将它们导出到你的终端,比如:

export MNEMONIC='cat dog frog....'
export RINKEBY_RPC_URL='www.infura.io/YOUR_PROJECT_ID_HERE'

代码目录中有什么

目录中有我们所有的模板代码,但真正的魔法是在DungeonsAndDragonsCharacter.sol文件中。我们可以看到它开始时是一个普通的Solidity文件,但我们在顶部有一些导入:

pragma solidity ^0.6.6;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract DungeonsAndDragonsCharacter is ERC721, VRFConsumerBase, Ownable {

OpenZepplin是一个包的集合,它让Solidity和智能合约工程师的开发工作变得更轻松。如果你之前没有用过它,那就准备好多用它吧!由于ERC721只是一个代币标准,每一个ERC721应该都差不多,所以我们知道我们可以用一个模板就可以了。我们导入的ERC721.sol文件定义了一个NFT的所有标准。我们只要在合同中继承它,定义contract DungeonsAndDragonsCharacter is ERC721。我们需要VRFConsumerBase.sol来与Chainlink VRF交互,并获得随机数。最后两个导入只是帮助我们处理权限和与字符串的工作。

角色结构体和构造函数

在Character结构体中定义了我们的角色将具有的属性,并且制作了一个角色列表,这样就可以跟踪每一个被创建的角色。由于我们使用数组来存储字符列表,每个字符在数组中都会有一个唯一的 ID 来定义它。这就是所谓的tokenId,我们将更多地引用它。

struct Character {
    uint256 strength;
    uint256 dexterity;
    uint256 constitution;
    uint256 intelligence;
    uint256 wisdom;
    uint256 charisma;
    uint256 experience;
    string name;
   }

Character[] public characters;

定义好之后,我们可以创建构造函数。

constructor()
       public
       VRFConsumerBase(VRFCoordinator, LinkToken)
       ERC721("DungeonsAndDragonsCharacter", "D&D")
   {
       keyHash = 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311;
       fee = 0.1 * 10**18; // 0.1 LINK
   }

对应传入VRFConsumerBase和ERC721参数。Chainlink VRF需要VRF协调器地址和LinkToken地址。我们已经在Rinkeby网络中硬编码这些地址了。还有一些其他变量为Chainlink VRF定义,比如keyHash和fee。你可以在Chainlink VRF文档(https://docs.chain.link/docs/chainlink-vrf/)中阅读更多关于这些变量的作用。`ERC721("DungeonsAndDragonsCharacter", "D&D")这一行定义了NFT的名称,然后是它的代币符号。"D&D"`将是MetaMask和NFT市场中显示的内容。

生成你的随机字符

我们希望角色的六个属性中的每一个都有随机统计,但我们希望能够自己决定角色的名字!一个简单的调用Chainlink VRF允许我们在这个NFT / ERC721中生成随机数。在我们的请求函数中,不需要做太多的事情,只需要给新的角色一个名字,和一个userProvidedSeed。我们给它的种子是用来给VRF协调器验证所提供的数字是否真的是随机的。你可以选择任何你喜欢的种子,你可以阅读关于选择随机种子的文章来了解更多。

function requestNewRandomCharacter(
     uint256 userProvidedSeed,
     string memory name

) 
     public returns (bytes32) 
{
     require(
           LINK.balanceOf(address(this)) >= fee,
"Not enough LINK - fill contract with faucet"
       );
       bytes32 requestId = requestRandomness(keyHash, fee, userProvidedSeed);
       requestToCharacterName[requestId] = name;
       requestToSender[requestId] = msg.sender;
return requestId;
   }

我们要跟踪requestId,这样当随机数获取到时,我们就可以把它映射到我们正在创建的角色上。这将启动Chainlink Job,需要等待Chainlink节点回调到我们的合约即可!你可以在Chainlink文档中阅读更多关于请求模型(https://docs.chain.link/docs/architecture-request-model/)的内容,了解更多关于发送Chainlink请求的工作原理

Chainlink节点完成了对请求的处理,它就会通过调用 fulfillRandomness 函数来响应。这个函数包含了给出属性的计算,将角色添加到列表中,以及铸造NFT。

function fulfillRandomness(bytes32 requestId, uint256 randomNumber)
     internal
     override
{
     uint256 newId = characters.length;
     uint256 strength = ((randomNumber % 100) % 18);
     uint256 dexterity = (((randomNumber % 10000) / 100) % 18);
     uint256 constitution = (((randomNumber % 1000000) / 10000) % 18);
     uint256 intelligence = (((randomNumber % 100000000) / 1000000) % 18);
     uint256 wisdom = (((randomNumber % 10000000000) / 100000000) % 18);
     uint256 charisma = (((randomNumber % 1000000000000) / 10000000000) %18);
     uint256 experience = 0;

     characters.push(
         Character(
               strength,
               dexterity,
               constitution,
               intelligence,
               wisdom,
               charisma,
               experience,
               requestToCharacterName[requestId]
      )
);
_safeMint(requestToSender[requestId], newId);
}

可以看到,只是用一次随机数来创建所有六个属性。使用取模运算对返回的大随机数取一个子集。如果我们不想这样做,我们也可以直接调用Chainlink VRF六次,但这种方式的效果是一样的。返回的随机数的最后两位数字用于强度,前面的两位数字用于敏捷,以此类推。这与CryptoKitties使用基因给猫咪赋值的方式类似。

需要注意的是:做位操作会比我们这里的方式更有效率,但这样更容易理解,所以我们不必去研究位操作的工作原理。

_safeMint是继承自ERC721.sol的函数,它允许我们跟踪ERC721的所有者。这一点很重要,特别是当你希望你的NFT采取一些行动,但你不希望其他人能够采取这种行动。我们将在下一篇NFT文章中了解更多的信息。

我们将使用Truffle和Chainlink,所以如果你不熟悉Truffle,这篇关于[如何使用Chainlink With Truffle的博文](将给你一个复习的机会,但我们也会在这篇博文中介绍所有的命令!

部署和快速启动

现在我们知道是怎么回事了,让我们来部署我们的随机NFT吧!你需要一些Rinkeby LINK(https://faucets.chain.link/)和Rinkeby ETH(https://faucet.rinkeby.io/)来运行这些脚本

truffle migrate --reset --network rinkeby
truffle exec scripts/fund-contract.js --network rinkeby
truffle exec scripts/generate-character.js --network rinkeby
truffle exec scripts/get-character.js --network rinkeby

上述命令做了下面这些事情:

  1. 部署NFT合约
  2. 向合约注资以便可以发起Chainlink VRF调用
  3. 用Chainlink VRF调用生成角色
  4. 返回NFT值

部署完毕,你还可以验证合约,甚至可以使用etherscan插件在Etherscan上阅读合约。你需要获得一个Etherscan API密钥(https://etherscan.io/apis),并设置环境变量`ETHSCAN_API_KEY`。之后运行

truffle run verify DungeonsAndDragonsCharacter --network rinkeby --license MIT

然后它会给你一个Etherscan上的NFT链接。你可以在Etherscan上阅读合约内容。

2.png

这样你就进入到可以与合约互动的页面。如果你进入角色部分,你可以输入我们刚刚生成的tokenId,0,然后就可以看到你的新D&D角色的统计信息了。

3.png

你可以查看Rinkeyby的这个合约的例子。其中有几个角色的名字很有意思!

总结

使用Chainlink VRF在NFT中随机数很容易,使用之后会有一个全新的世界可以探索。我们在这里只是触及到了表面,所以请期待下一篇关于在市场上销售它们、渲染图像和使用元数据的博客。我们很想看到一些使用Chainlink VRF创建的很棒的角色和游戏,为它们提供动力,做到真正公平。如果你打造了一款酷炫的NFT #PoweredByChainlink,一定要在推特上告诉我们!

如果你是一名开发者,并希望将你的智能合约连接到链外数据和系统,请访问开发者文档并加入Discord上的技术讨论。如果你想安排一个电话,更深入地讨论整合问题,请在这里联系我们。

智能合约开发者正在NFT中建设一个全新的随机世界。你会成为引领这一潮流的先驱者之一吗?

原文链接: https://blog.chain.link/random-numbers-nft-erc721/

本文首发于:https://mp.weixin.qq.com/s/NlmKGDtcxkNMu1bb6-vj8A

点赞 0
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Chainlink
Chainlink
顶尖的智能合约去中心化预言机网络解决方案 https://chain.link/