如何在NFT(ERC721)中获取随机数
原文链接:https://blog.chain.link/random-numbers-nft-erc721/
(文中链接请复制至浏览器打开)
介绍
在遵循ERC721(http://erc721.org/)标准的非同质化代币(NFT)中生成随机数一直是智能合约开发者面临的难题。现在,Chainlink VRF已经在主网上线,基于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上阅读合约内容。
这样你就进入到可以与合约互动的页面。如果你进入角色部分,你可以输入我们刚刚生成的tokenId,0,然后就可以看到你的新D&D角色的统计信息了。
你可以查看Rinkeyby的这个合约的例子。其中有几个角色的名字很有意思!
总结
使用Chainlink VRF在NFT中随机数很容易,使用之后会有一个全新的世界可以探索。我们在这里只是触及到了表面,所以请期待下一篇关于在市场上销售它们、渲染图像和使用元数据的博客。我们很想看到一些使用Chainlink VRF创建的很棒的角色和游戏,为它们提供动力,做到真正公平。如果你打造了一款酷炫的NFT #PoweredByChainlink,一定要在推特上告诉我们!
如果你是一名开发者,并希望将你的智能合约连接到链外数据和系统,请访问开发者文档并加入Discord上的技术讨论。如果你想安排一个电话,更深入地讨论整合问题,请在这里联系我们。
智能合约开发者正在NFT中建设一个全新的随机世界。你会成为引领这一潮流的先驱者之一吗?
Chainlink 2.0白皮书中文版已于日前发布,想要了解更多关于Chainlink 2.0的内容细节,请扫描下方二维码▼
END
加入 Chainlink官方社区▼
QQ群: 6135525
点击“阅读原文” 进入 Chainlink中文官网