不可替代的代幣或NFT 是區塊鏈上的數字代幣,每個代幣都代表獨特的東西,例如一件數字藝術品、一個特殊的遊戲內物品、一個稀有的交易卡收藏品或任何其他獨特的數字/實物資產。 NFT 與可替代的代幣形成鮮明對比:每一個都是獨一無二的,不能換成另一個版本的自己。持有者關心他們持有的代幣而不是數量。
在本技術教程中,您將學習如何開發生成藝術NFT 集合併將其託管在IPFS 上。您的NFT 將是不同的犬種。 NFT 的生成藝術將使用可驗證的隨機數生成 Chainlink VRF.
讓我們開始吧。
克隆回購
第一步是克隆 Chainlink 智能合約示例存儲庫. 完成此操作後,導航到“The Ultimate NFT Repo”目錄並安裝必要的依賴項。
git clone https://github.com/smartcontractkit/smart-contract-examples.git cd smart-contract-examples/ultimate-nft-repo yarn
然後,繼續並在您選擇的代碼編輯器中打開項目。按照說明在項目的“Readme”文件中設置所需的環境變量(您需要免費註冊 煉金術 帳戶和免費 Etherscan API 密鑰)。在本教程中,我們將部署到以太坊上的Rinkeby 測試網。
ETHERSCAN_API_KEY=<YOUR ETHERSCAN API> RINKEBY_URL=https://eth-rinkeby.alchemyapi.io/v2/<YOUR ALCHEMY KEY> PRIVATE_KEY=<YOUR PRIVATE KEY>
使用Chainlink VRF v2
為了獲得隨機值,我們需要將生成藝術NFT 提供給區塊鏈,我們將使用最近發布的Chainlink VRF v2。新版本的VRF 包括對如何請求和資助智能合約隨機性的多項改進。
首先,導航到 VRF 訂閱頁面,選擇Rinkeby網絡,連接你的錢包,然後點擊“創建訂閱”。然後,保存您的 subscriptionId
——我們稍後需要將它作為構造函數參數傳遞。
完成開發並將智能合約部署到Rinkeby 後,返回VRF 訂閱頁面,導航到您的訂閱,單擊“添加消費者”按鈕,然後粘貼最近部署的合約的地址。
最後,用幾個Rinkeby 測試LINK 代幣為您的訂閱提供資金。你可以在 水龍頭.chain.link.
開發NFT 智能合約
創建一個名為的新Solidity 文件 RandomIpfsNft.sol
. 我們將從OpenZeppelin 庫中繼承幾個智能合約,並使用Chainlink VRF。
Solidity 0.8.4 版引入了所謂的“自定義錯誤”,這是一種從代碼庫報告錯誤的更高效的方式。雖然已經可以使用字符串來提供有關故障的更多信息,但這相當昂貴,並且很難在其中使用動態信息。
自定義錯誤的語法類似於 events
. 它們是使用定義的 error
聲明並且必須與 revert
陳述。 require
不支持。
//SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; error AlreadyInitialized(); error NeedMoreETHSent(); error RangeOutOfBounds(); contract RandomIpfsNft is ERC721URIStorage, VRFConsumerBaseV2, Ownable { // Types enum Breed { PUG, SHIBA_INU, ST_BERNARD } // Chainlink VRF Variables VRFCoordinatorV2Interface private immutable i_vrfCoordinator; uint64 private immutable i_subscriptionId; bytes32 private immutable i_gasLane; uint32 private immutable i_callbackGasLimit; uint16 private constant REQUEST_CONFIRMATIONS = 3; uint32 private constant NUM_WORDS = 1; // NFT Variables uint256 private i_mintFee; uint256 public s_tokenCounter; mapping(uint256 => Breed) private s_tokenIdToBreed; uint256 internal constant MAX_CHANCE_VALUE = 100; string[] internal s_dogTokenUris; bool private s_initialized; // VRF Helpers mapping(uint256 => address) public s_requestIdToSender; // Events event NftRequested(uint256 indexed requestId, address requester); event NftMinted(Breed breed, address minter);
我們還需要將狗圖像部署到IPFS 並將它們的URL 存儲在合約中。為此,請導航至 皮納塔,並註冊免費帳戶。然後轉到您的文件選項卡,單擊“上傳”,然後選擇要上傳的文件或文件夾。
為了確保智能合約能夠正確部署,讓我們添加一個 constructor
函數並使用“Random IPFS NFT”作為集合名稱,使用“RIN”作為代碼。隨意更改這些值並隨意命名您的收藏。
現在我們需要 subscriptionId
,我們在註冊後保存的 VRF 訂閱頁面,以及狗圖像的IPFS URL。最後,從 官方文檔.
constructor( address vrfCoordinatorV2, uint64 subscriptionId, bytes32 gasLane, // keyHash uint256 mintFee, uint32 callbackGasLimit, string[3] memory dogTokenUris ) VRFConsumerBaseV2(vrfCoordinatorV2) ERC721("Random IPFS NFT", "RIN") { i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2); i_gasLane = gasLane; i_subscriptionId = subscriptionId; i_mintFee = mintFee; i_callbackGasLimit = callbackGasLimit; _initializeContract(dogTokenUris); } function _initializeContract(string[3] memory dogTokenUris) private { if (s_initialized) { revert AlreadyInitialized(); } s_dogTokenUris = dogTokenUris; s_initialized = true; }
現在讓我們添加一種鑄造新NFT 的方法。用戶至少需要提供一個 i_mintFee
本地幣的數量,否則交易將恢復。然後,我們的方法將從Chainlink VRF 請求一個隨機值。由於Chainlink VRF 是異步的,我們將使用 s_requestIdToSender
將所有Chainlink VRF 請求映射到代幣的鑄造者。
在Chainlink 去中心化預言機網絡回調後, fulfillRandomWords
函數將確定狗的品種和所有者,並創建一個新的NFT。
function requestNft() public payable returns (uint256 requestId) { if (msg.value < i_mintFee) { revert NeedMoreETHSent(); } requestId = i_vrfCoordinator.requestRandomWords( i_gasLane, i_subscriptionId, REQUEST_CONFIRMATIONS, i_callbackGasLimit, NUM_WORDS ); s_requestIdToSender[requestId] = msg.sender; emit NftRequested(requestId, msg.sender); } function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { address dogOwner = s_requestIdToSender[requestId]; uint256 newItemId = s_tokenCounter; s_tokenCounter = s_tokenCounter + 1; uint256 moddedRng = randomWords[0] % MAX_CHANCE_VALUE; Breed dogBreed = getBreedFromModdedRng(moddedRng); _safeMint(dogOwner, newItemId); _setTokenURI(newItemId, s_dogTokenUris[uint256(dogBreed)]); emit NftMinted(dogBreed, dogOwner); } function getBreedFromModdedRng(uint256 moddedRng) public pure returns (Breed) { uint256 cumulativeSum = 0; uint256[3] memory chanceArracy = getChanceArray(); for (uint256 i = 0; i < chanceArracy.length; i++) { if (moddedRng >= cumulativeSum && moddedRng < cumulativeSum + chanceArracy[i]) { return Breed(i); } cumulativeSum = cumulativeSum + chanceArracy[i]; } revert RangeOutOfBounds(); } function getChanceArray() public pure returns (uint256[3] memory) { return [10, 30, MAX_CHANCE_VALUE]; }
最好將存儲和不可變變量設為私有,用前綴“i_”和“s_”標記它們,並編寫getter 函數。這種方法將使您的代碼更加簡潔和高效。所以讓我們這樣做:
function getMintFee() public view returns (uint256) { return i_mintFee; } function getDogTokenUris(uint256 index) public view returns (string memory) { return s_dogTokenUris[index]; } function getInitialized() public view returns (bool) { return s_initialized; } function getTokenCounter() public view returns (uint256) { return s_tokenCounter; }
由於鑄造這個系列需要花費本地硬幣,我們將其指定為 i_mintFee
構造函數中的變量,最後要實現的功能實際上是一種使管理員DAO 多重簽名錢包能夠提取這些鎖定資金的方法。
自2019 年以來, call
方法一直是在Solidity 中發送原生代幣的首選方式。該過程如下所述。出於安全原因,請避免使用 transfer
和 send
.
function withdraw() public onlyOwner { uint256 amount = address(this).balance; (bool success, ) = payable(msg.sender).call{value: amount}(""); require(success, "Transfer failed"); }
就是這樣,我們的NFT 已經準備好部署了!不要忘記在部署後將此智能合約添加為您的VRF 訂閱的消費者。
鑄造您的代幣並在OpenSea 上進行交易
現在,您可以通過將您的錢包連接到Etherscan 並單擊“requestNft”功能或通過創建一個dApp UI 與您的智能合約進行交互來輕鬆地鑄造您的代幣。鑄幣後,前往 林克比的OpenSea 並蒐索您的NFT 收藏或錢包地址。
概括
在本文中,您學習瞭如何創建生成藝術NFT 智能合約,我們還介紹了Solidity 自定義錯誤、使用Chainlink VRF、將文件部署到IPFS 以及在Solidity 中安全地發送原生代幣。
要了解更多信息,請前往 Chainlink 智能合約示例存儲庫 並開始試驗這個和其他示例項目。
通過訪問了解有關Chainlink 的更多信息 鏈環 或閱讀文檔 docs.chain.link. 要討論集成,請聯繫專家。