# Alchemy第三周任务-使用Polygon链上元数据制作 NFT **Published by:** [KnowYourself](https://paragraph.com/@knowyourself-2/) **Published on:** 2022-10-14 **URL:** https://paragraph.com/@knowyourself-2/alchemy-polygon-nft ## Content 我们都知道创建 NFT 时,最好将元数据存储在集中式对象存储或IPFS等分散式解决方案中,以避免直接在链上存储大量数据(如图像和 JSON 对象)产生的巨额 Gas 费用。 但这有一个问题: 不将元数据存储在区块链上将使您无法通过智能合约与之交互,因为区块无法与“外部世界”通信。**如果我们想直接从我们的智能合约更新我们的元数据,我们需要将其存储在链上,但是汽油费呢?幸运的是,像 Polygon 这样的 L2 链可以提供帮助,大大降低了 Gas 成本,并引入了许多优势,使开发人员能够扩展其应用程序的功能。 在本教程中,学习如何创建区块链游戏的基础知识,开发一个完全动态的 NFT,其链上元数据会根据您与它的交互而变化,并将其部署在Polygon Mumbai上以降低汽油费。 更准确地说,您将学习:如何在链上存储 NFT 元数据什么是 Polygon 以及为什么降低 Gas 费用很重要。如何在 Polygon Mumbai 上部署如何处理和存储链上 SVG 图像和 JSON 对象如何根据您与 NFT 的交互来修改元数据1.Polygon PoS - 更低的 Gas 费用和更快的交易Polygon 是一个去中心化的 EVM 兼容扩展平台,使开发人员能够在不牺牲安全性的情况下以低交易费用构建可扩展的用户友好型 DApp。 它属于被描述为**第 2 层链 (L2)**的一组链,这意味着它建立在以太坊之上,以解决一些表征它的问题 - 同时依赖它来运行。 众所周知,以太坊既不快也不便宜,在其上部署智能合约可能会迅速变得非常昂贵,这就是Polygon或Optimism等 L2 解决方案发挥作用的地方。 例如,多边形有两个主要优点:更快的交易(65,000 tx/秒 vs ~14)每笔交易的gas 成本比以太坊低约 10,000 倍第二个正是我们在 Polygon 上部署带有链上元数据的 NFT 智能合约的原因。一方面,如果在以太坊上存储我们的元数据时,我们可以预期每笔交易花费数百美元,那么在 Polygon 上它的成本不会超过几美分。1.1将 Polygon Mumbai 添加到您的 Metamask 钱包首先,让我们将 Polygon Mumbai 添加到我们的 Metamask 钱包中。 导航测试polygon网络并向下滚动到页面底部。您将看到**“添加多边形网络”按钮**,单击它并确认您要将其添加到 Metamask:1.2获取免费的 Matic 以部署NFT 智能合约我们去到mumbaifaucet.com获取测试币,输入我们的地址获取测试币即可10-20 秒后,会看到 MATIC 出现在 Metamask 钱包中。2.1项目设置# 新建一个文件夹用于此次项目的搭建 mkdir ChainBattled cd ChainBattled # 安装yarn并查看版本 npm install -g yarn yarn --version yarn add hardhat # 初始化项目 npx hardhat init 现在我们需要安装OpenZeppelin包来访问ERC721 智能合约我们将使用该标准作为模板来构建我们的 NFT 智能合约。yarn add @openzeppelin/contracts 2.2修改 hardhat.config.js 文件将我们的hardhat.config.js 文件修改如下:require("dotenv").config(); require("@nomiclabs/hardhat-waffle"); require("@nomiclabs/hardhat-etherscan"); module.exports = { solidity: "0.8.10", networks: { mumbai: { url: process.env.TESTNET_RPC, accounts: [process.env.PRIVATE_KEY] }, }, etherscan: { apiKey: process.env.POLYGONSCAN_API_KEY } }; 2.3开发智能合约在 contracts 文件夹中,创建一个新文件并将其命名为“ChainBattles.sol”。 与往常一样,我们需要指定SPDX-Licence-Identifier、pragma ,并从OpenZeppelin导入几个库,我们将用作智能合约的基础,合约内容如下:// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; 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 ChainBattles is ERC721URIStorage { using Strings for uint256; using Counters for Counters.Counter; Counters.Counter private _tokenIds; mapping(uint256 => uint256) public tokenIdToLevels; constructor() ERC721 ("Chain Battles", "CBTLS"){ } function generateCharacter(uint256 tokenId) public returns(string memory){ bytes memory svg = abi.encodePacked( '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350">', '<style>.base { fill: white; font-family: serif; font-size: 14px; }</style>', '<rect width="100%" height="100%" fill="black" />', '<text x="50%" y="40%" class="base" dominant-baseline="middle" text-anchor="middle">',"Warrior",'</text>', '<text x="50%" y="50%" class="base" dominant-baseline="middle" text-anchor="middle">', "Levels: ",getLevels(tokenId),'</text>', '</svg>' ); return string( abi.encodePacked( "data:image/svg+xml;base64,", Base64.encode(svg) ) ); } function getLevels(uint256 tokenId) public view returns (string memory) { uint256 levels = tokenIdToLevels[tokenId]; return levels.toString(); } function getTokenURI(uint256 tokenId) public returns (string memory){ bytes memory dataURI = abi.encodePacked( '{', '"name": "Chain Battles #', tokenId.toString(), '",', '"description": "Battles on chain",', '"image": "', generateCharacter(tokenId), '"', '}' ); return string( abi.encodePacked( "data:application/json;base64,", Base64.encode(dataURI) ) ); } function mint() public { _tokenIds.increment(); uint256 newItemId = _tokenIds.current(); _safeMint(msg.sender, newItemId); tokenIdToLevels[newItemId] = 0; _setTokenURI(newItemId, getTokenURI(newItemId)); } function train(uint256 tokenId) public{ require(_exists(tokenId),"The tokenId does not exist"); require(_isApprovedOrOwner(msg.sender, tokenId),"You are not the owner of the NFT"); tokenIdToLevels[tokenId] += 1; _setTokenURI(tokenId, getTokenURI(tokenId)); } } 我们在上面将合约全部完善了,也新增了 4 个不同的功能:**generateCharacter:**生成和更新我们 NFT 的 SVG 图像**getLevels:**获取 NFT 的当前级别**getTokenURI :**获取 NFT 的 TokenURI**mint:**到 mint - 当然**train:**训练 NFT 并提高其等级首先,让我们在项目的根文件夹中新建一个 .env 文件,并添加以下变量:TESTNET_RPC="" PRIVATE_KEY="" POLYGONSCAN_API_KEY="" 然后,导航到alchemy.com并创建一个新的 Polygon Mumbai 应用程序: 单击新创建的应用程序,复制 API HTTP URL,并将 API 作为“ TESTNET_RPC ”值粘贴到我们在上面创建的 .env 文件中。 打开您的Metamask钱包,点击三个点菜单 > 帐户详细信息 > 并将您的私钥复制粘贴为..env 最后,继续Polygon,并创建一个新帐户,登录后,进入个人资料菜单并单击 API Keys,如果没有则需要新建一个:现在将 Api-Key 令牌复制粘贴为 .env 中的“ POLYGONSCAN API_KEY ”值。最终结果如下:在部署我们的智能合约之前的最后一步,我们需要创建部署脚本。3.1创建部署脚本首先安装依赖npm install dotenv npm install @nomiclabs/hardhat-waffle 我们将deploy.js的脚本替换如下:const main = async () => { try { const nftContractFactory = await hre.ethers.getContractFactory( "ChainBattles" ); const nftContract = await nftContractFactory.deploy(); await nftContract.deployed(); console.log("Contract deployed to:", nftContract.address); process.exit(0); } catch (error) { console.log(error); process.exit(1); } }; main(); 3.2编译和部署智能合约当我们把脚本写好后,编译智能合约,只需在项目内的终端中运行以下命令:npx hardhat compile 如果一切按预期进行,你将在 artifacts 文件夹中看到已编译的智能合约。 现在,让我们在运行的 Polygon Mumbai 链上部署智能合约npx hardhat run scripts/deploy.js --network mumbai 如果一切正常你将在页面看到合约的地址3.3在 Polygon Scan 上检查智能合约复制刚刚部署的智能合约的地址,去测试polygon网络,然后**在搜索栏中粘贴智能合约的地址。**进入智能合约页面后,单击“合约”选项卡。你会注意到合约代码不可读:这是因为我们还没有验证我们的代码。 为了验证我们的智能合约,我们需要回到我们的项目,并在终端中运行以下代码:# npx hardhat verify --network mumbai 合约地址 npx hardhat verify --network mumbai 0x99299c6B27eBB1B6dAf4BD3016CBd58D9656A37d 报错信息:Error in plugin @nomiclabs/hardhat-etherscan: Failed to send contract verification request. Endpoint URL: https://api-testnet.polygonscan.com/api Reason: read ECONNRESET 通过网站添加方法,点击立即验证即可:3.4通过多边形扫描与您的智能合约交互现在智能合约已经通过验证,mumbai.polygonscan.com 将在其附近显示一个绿色小勾:然后寻找“min​​t”函数并点击Write:这将打开一个 Metamask 弹出窗口,要求支付 gas 费用,单击签名按钮。恭喜!您刚刚铸造了您的第一个动态 NFT - 让我们转移到 OpenSea 测试网来现场查看它。4.在 OpenSea 上查看您的动态 NFT复制智能合约地址,前往testnet.opensea.com,并将其粘贴到搜索栏中:如果一切正常,现在应该会看到您的 NFT 显示在 OpenSea 上,其中包含动态图像、标题和描述。4.1更新动态 NFT 图像训练 NFT导航回测试.polygons网络,点击合约标签 > 写合约并寻找“train”功能。 插入您的 NFT 的 ID - 在这种情况下为“1”,因为我们只铸造了一个,然后单击写入:然后回到testnets.opensea.com并刷新页面: ## Publication Information - [KnowYourself](https://paragraph.com/@knowyourself-2/): Publication homepage - [All Posts](https://paragraph.com/@knowyourself-2/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@knowyourself-2): Subscribe to updates