Bitget: haz trading inteligente. Lionel Messi, Official Partner. Regístrate

Patrick Collins .- 按照 ERC721 标准在非同质化代币(NFT)中生成随机数,一直是智能合约开发者面临的难题。

如今 Chainlink VRF 已在主网上线,基于 Solidity 的智能合约可以顺畅地在链上生成防篡改的随机数,这些随机数可证明是公平的,并有密码学证明作为支撑。

借助 Chainlink VRF,创建需要安全随机源的动态NFT变得前所未有地简单和安全。虽然 Chainlink 也能利用链下数据源为 NFT 实现任意类型的动态属性,但本文将重点介绍 ERC721 或 NFT 中的随机数。

在本教程中,我们将了解如何在以太坊区块链上构建一个 Dungeons & Dragons(龙与地下城)角色。D&D(Dungeons and Dragons)是一款流行的角色扮演游戏(RPG),玩家在其中创建角色并展开冒险。

创建角色的重要环节之一,是赋予角色属性或数值,以体现其力量、敏捷、智力等。

为了在区块链上为这些数值生成真正的随机数,我们将展示如何使用 Chainlink VRF 为你的角色赋予随机属性。有了 Chainlink VRF,在区块链上生成随机数轻而易举!

什么是NFT?

NFT(遵循 ERC721 标准)定义了一个框架,用于创建彼此独一无二、互不相同的代币(因此称为非同质化),而流行的 ERC20 标准定义的则是“同质化”代币,即所有代币都可以互换,并保证具有相同的价值。

“同质化”货币的例子有美元、欧元和日元,而同质化区块链代币的例子有 AAVE、SNX 和 YFI。

在这些情况下,1 枚同质化代币等于另 1 枚同类代币,就像 1 美元等于 1 美元,1 LINK 等于 1 LINK。然而,NFT / ERC721 的不同之处在于,每个代币都是独一无二的,并不代表相同的价值或可互换的物品。

由于所有 NFT 都是独一无二的,它们可以代表对现实世界资产的代币化所有权主张,例如一块特定的土地,也可以代表数字资产的实际所有权,例如一张稀有的数字交易卡。 而且它们正越来越受欢迎。 你可以参阅 OpenSea 的 NFT 圣经了解更多。

构建你的随机角色

我们将介绍如何创建一个拥有 D&D 角色六大主要属性的角色,即:

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

我们还会赋予它们:

uint256 experience;
       string name;

这样我们就可以升级,并给它们取一个有趣的名字。

我们在这里做了一些自由发挥,并未百分之百遵循 Dungeons & Dragons 的规则,但如果你希望更准确地还原游戏,也可以轻松修改。

该合约需要实现以下内容:

  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 就是你钱包的助记词。你可以从 Infura 等节点服务提供商处获取 RINKEBY_RPC_URL。

然后,将它们设置在 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 结构体中定义角色将拥有的属性,并创建一个角色列表,以便跟踪所有已创建的角色。 由于我们使用数组存储角色列表,因此每个角色在该数组中都会有一个唯一的标识符来定义它。 这被称为 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 文档中进一步了解它们的作用。

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 任务,我们只需等待 Chainlink 节点回调我们的合约!

你可以阅读 Chainlink 文档中的请求模型,进一步了解 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 与 Truffle 结合使用的博客文章 可以帮你快速复习,不过我们也会在本文中逐一讲解所有命令!

部署与快速入门

现在我们已经了解了其中的原理,来部署我们的随机 NFT 吧! 你需要 Rinkeby LINK 和 Rinkeby ETH 来运行这些脚本。

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 密钥 并设置环境变量 ETHERSCAN_API_KEY.完成后,即可运行:

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

它会给你一个指向 Etherscan 上你的 NFT 的链接。 进入后,你可以前往合约部分,点击“读取合约”。

chainlink

这会将你带到可以与合约交互的页面。 如果进入 characters 部分,你可以输入我们刚刚生成的 tokenId,即 0,然后查看你的新 D&D 角色的数值!

你可以在 这里的 Rinkeby 上 查看该合约示例。 其中一些角色的名字非常有趣!

总结

借助 Chainlink VRF,在 NFT 中使用随机数非常简单,而在托管和使用它们方面,还有一个全新的世界等待探索。 本文只是浅尝辄止,请关注下一篇博客,了解如何在市场上出售它们、渲染图像以及处理元数据。 我们非常期待看到更多使用 Chainlink VRF 打造的精彩角色和游戏,让它们真正实现公平。 如果你创建了很酷的 #PoweredByChainlink NFT,一定要发推文告诉我们!

如果你是开发者,并希望将智能合约连接到链下数据和系统,请访问 开发者 文档 ,并加入 Discord 上的技术讨论。 如果你想预约通话以深入讨论集成事宜,请点击 这里 联系。

智能合约开发者正借助 NFT 中的随机属性开创一个全新的世界。你会成为引领潮流的先驱之一吗?

点击此处查看 Patrick Collins 的原文

官网 | Twitter | Reddit | YouTube | Telegram | 活动 | GitHub | 价格喂价 | DeFi

更多关于 CHAINLINK 的内容