不可替代的代幣或NFT 是區塊鏈上的數字代幣,每個代幣都代表獨特的東西,例如數字藝術品、特殊的遊戲內物品、稀有的交易卡收藏品或任何其他獨特的數字/實物資產。 NFT 與可替代代幣形成鮮明對比:每一個都是獨一無二的,不能交換為它自己的另一個版本。持有者關心他們持有的代幣而不是數量。
在本技術教程中,您將學習如何開發NFT 集合併將其部署到OpenSea 市場。您的NFT 將是具有不同背景顏色的單個表情符號。每個NFT 的表情符號和背景顏色的組合將使用來自的可驗證隨機數生成 Chainlink VRF.
讓我們開始吧。
克隆回購
第一步是繼續克隆 Chainlink 智能合約示例存儲庫. 完成此操作後,導航到Random SVG NFT 目錄並安裝必要的依賴項。
git clone https://github.com/smartcontractkit/smart-contract-examples.git cd smart-contract-examples/random-svg-nft 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>
NFT 元數據
鏈接到NFT 的元數據提供了描述性信息,使市場和dApp 能夠顯示該代幣的可視化表示。開發人員要做的第一個決定是如何以及在哪裡存儲這些數據:它可以完全寫入智能合約本身(鏈上),也可以託管在IPFS 或Filecoin 等去中心化存儲解決方案上(鏈下)。在本教程中,我們將通過基於隨機值生成NFT 藝術並將這些值的SVG 表示存儲在智能合約中來將元數據存儲在鏈上。
開發NFT 智能合約
創建一個名為的新Solidity 文件 EmojiNFT.sol
. 我們將從OpenZeppelin 庫中繼承幾個智能合約,並使用Chainlink VRF。
讓我們也初始化存儲變量並填充一個 emojis
陣列與您最喜愛的表情符號。為什麼不使用您在手機上使用的最後十個表情符號?
//SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/utils/Base64.sol"; contract EmojiNFT is ERC721URIStorage, VRFConsumerBaseV2 { using Counters for Counters.Counter; Counters.Counter private tokenIds; string[] private emojis = [ unicode"😁", unicode"😂", unicode"😍", unicode"😭", unicode"😴", unicode"😎", unicode"🤑", unicode"🥳", unicode"😱", unicode"🙄" ]; VRFCoordinatorV2Interface internal immutable vrfCoordinator; bytes32 internal immutable keyHash; uint64 internal immutable subscriptionId; uint32 internal immutable callbackGasLimit; uint32 internal immutable numWords; uint16 internal immutable requestConfirmations; mapping(uint256 => address) requestToSender; event RandomnessRequested(uint256 indexed requestId);
為了確保智能合約能夠正確部署,讓我們添加一個 constructor
功能並使用“EmojiNFT”作為集合名稱,使用“EMOJI”作為代碼。隨意更改這些值並隨意命名您的收藏。
constructor( address _vrfCoordinator, bytes32 _keyHash, uint64 _subscriptionId, uint32 _callbackGasLimit, uint16 _requestConfirmations ) VRFConsumerBaseV2(_vrfCoordinator) ERC721("EmojiNFT", "EMOJI") { vrfCoordinator = VRFCoordinatorV2Interface(_vrfCoordinator); keyHash = _keyHash; subscriptionId = _subscriptionId; callbackGasLimit = _callbackGasLimit; numWords = 4; requestConfirmations = _requestConfirmations; }
現在讓我們添加一種鑄造新NFT 的方法。我們的方法將從Chainlink VRF 請求四個隨機值,然後在 fulfillRandomWords
函數,根據第一個隨機值從數組中抓取表情符號,根據其餘三個隨機值生成隨機顏色,生成鏈上SVG 文件,創建一個OpenSea 兼容的令牌URL,並創建一個新的NFT。由於Chainlink VRF 是異步的,我們將使用 requestToSender
將所有Chainlink VRF 請求映射到代幣的鑄造者。
function mint() public returns (uint256 requestId) { requestId = vrfCoordinator.requestRandomWords( keyHash, subscriptionId, requestConfirmations, callbackGasLimit, numWords ); requestToSender[requestId] = msg.sender; emit RandomnessRequested(requestId); } function fulfillRandomWords(uint256 requestId, uint256[] memory randomNumbers) internal override { uint256 tokenId = tokenIds.current(); uint256 emojiIndex = (randomNumbers[0] % emojis.length) + 1; string memory emoji = emojis[emojiIndex]; string memory color = pickRandomColor(randomNumbers[1], randomNumbers[2], randomNumbers[3]); string memory svg = createOnChainSvg(emoji, color); string memory tokenUri = createTokenUri(emoji, svg); _safeMint(requestToSender[requestId], tokenId); _setTokenURI(tokenId, tokenUri); tokenIds.increment(); } }
最後一步是為缺失的部分添加代碼 pickRandomColor
, createOnChainSvg
和 createTokenUri
職能。
我們將使用Chainlink VRF 通過請求三個不同的隨機值來為我們的NFT 藝術生成隨機背景顏色,每個值代表RGB 格式的顏色。 RGB是一種顏色模型,其中三基色組合產生另一種顏色。 RGB 常用於計算機科學以及電視、攝像機和顯示器中。
每個參數(紅色、綠色和藍色)將顏色的強度定義為介於0 和255 之間的整數。例如,rgb(0, 0, 255) 呈現為藍色,因為藍色參數設置為最高值(255) 和其他設置為0。類似地,rgb(255, 0, 0) 呈現為紅色。
由於VRF 提供的值可能遠大於255,因此我們需要執行模除法來計算r、g 和b 參數。
function pickRandomColor(uint256 firstRandomNumber, uint256 secondRandomNumber, uint256 thirdRandomNumber) internal pure returns (string memory) { uint256 r = firstRandomNumber % 256; uint256 g = secondRandomNumber % 256; uint256 b = thirdRandomNumber % 256; return string( abi.encodePacked( "rgb(", Strings.toString(r), ", ", Strings.toString(g), ", ", Strings.toString(b), ");" ) ); }
SVG (Scalable Vector Graphics) 是一種基於XML 的標記語言,用於描述基於二維的矢量圖形。在基本層面上,SVG 是一個圖像,但是一個用代碼構建的圖像。這些圖像可以在任何分辨率下以高質量打印,並且在調整大小時不會丟失任何質量。這就是為什麼SVG 是我們用例的完美格式,我們將NFT 元數據完全存儲在鏈上並創建真正永久的令牌——我們的SVG 可以從令牌元數據生成,不依賴於外部託管。
function createOnChainSvg(string memory emoji, string memory color) internal pure returns(string memory svg) { string memory baseSvg = "<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio='xMinYMin meet' viewBox='0 0 350 350'><style>.base { font-size: 100px; }</style><rect width="100%" height="100%" style="fill:"; string memory afterColorSvg = "" /><text x='50%' y='50%' class="base" dominant-baseline="middle" text-anchor="middle">"; svg = string(abi.encodePacked(baseSvg, color, afterColorSvg, emoji, "</text></svg>")); }
令牌URL 是令牌元數據的鏈接。在我們的例子中,它將包含帶有“name”、“description”和“image”屬性的JSON,看起來像這樣:
{"name": "😍", "description": "Random Emoji NFT Collection Powered by Chainlink VRF", "image": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHByZXNlcnZlQXNwZWN0UmF0aW89J3hNaW5ZTWluIG1lZXQnIHZpZXdCb3g9JzAgMCAzNTAgMzUwJz48c3R5bGU+LmJhc2UgeyBmb250LXNpemU6IDEwMHB4OyB9PC9zdHlsZT48cmVjdCB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJyBzdHlsZT0nZmlsbDpyZ2IoNDcsIDIyNCwgNzYpOycgLz48dGV4dCB4PSc1MCUnIHk9JzUwJScgY2xhc3M9J2Jhc2UnIGRvbWluYW50LWJhc2VsaW5lPSdtaWRkbGUnIHRleHQtYW5jaG9yPSdtaWRkbGUnPvCfmI08L3RleHQ+PC9zdmc+"} Notice that the SVG image representation is Base64 encoded to match OpenSea’s requirements.
function createTokenUri(string memory emoji, string memory svg) internal pure returns(string memory tokenUri) { string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "', emoji, '", "description": "Random Emoji NFT Collection Powered by Chainlink VRF", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(svg)), '"}' ) ) ) ); tokenUri = string( abi.encodePacked("data:application/json;base64,", json) ); }
VRF v2
為了獲得區塊鏈的隨機值,我們將使用最近發布的Chainlink VRF v2。新版本的VRF 對您為智能合約提供資金和請求隨機性的方式進行了多項改進。
首先,導航到 VRF 訂閱頁面,選擇Rinkeby網絡,連接你的錢包,然後點擊“創建訂閱”。然後,保存您的 subscriptionId
作為 SUBSCRIPTION_ID
環境變量。通過鍵入以下內容部署EmojiNFT 智能合約:
yarn deploy
或者
SUBSCRIPTION_ID=<your_subscription_id> yarn deploy
部署後,返回VRF 訂閱頁面,導航到您的訂閱,單擊“添加消費者”按鈕,然後粘貼最近部署的合約的地址。
最後,用幾個Rinkeby 測試LINK 代幣為您的訂閱提供資金。你可以在 水龍頭.chain.link.
鑄造您的代幣並在OpenSea 上進行交易
現在,您可以通過將您的錢包連接到Etherscan 並單擊“鑄幣”功能,或者通過創建一個用於與您的智能合約交互的dApp UI 來輕鬆鑄幣。鑄幣後,前往 林克比的OpenSea 並蒐索您的NFT 收藏或錢包地址。
概括
在本文中,您學習瞭如何編寫NFT 智能合約、鏈上和鏈下NFT 元數據之間的區別、如何使用Chainlink VRF,以及如何在Solidity 中生成SVG 圖像並在NFT 市場上正確顯示它們像OpenSea。要了解更多信息,請前往 Chainlink 智能合約示例存儲庫 並開始試驗這個和其他示例項目。
通過訪問了解有關Chainlink 的更多信息 鏈環 或閱讀文檔 docs.chain.link. 要討論集成, 聯繫專家.