大家好,我是帝哥(@CoinmanLabs),前面的两个教程,我们把Alchemy的前两周的任务完成了,今天帝哥带大家一起来看看第三周的任务。
我们都知道创建 NFT 时,最好将元数据存储在集中式对象存储或IPFS等分散式解决方案中,以避免直接在链上存储大量数据(如图像和 JSON 对象)产生的巨额 Gas 费用。
但这有一个问题:
不将元数据存储在区块链上将使您无法通过智能合约与之交互,因为区块链**无法与“外部世界”通信。**如果我们想直接从我们的智能合约更新我们的元数据,我们需要将其存储在链上,但是汽油费呢?幸运的是,像 Polygon 这样的 L2 链可以提供帮助,大大降低了 Gas 成本,并引入了许多优势,使开发人员能够扩展其应用程序的功能。
在本教程中,学习如何创建区块链游戏的基础知识,开发一个完全动态的 NFT,其链上元数据会根据您与它的交互而变化,并将其部署在Polygon Mumbai上以降低汽油费。
更准确地说,您将学习:
Polygon 是一个去中心化的 EVM 兼容扩展平台,使开发人员能够在不牺牲安全性的情况下以低交易费用构建可扩展的用户友好型 DApp。
它属于被描述为**第 2 层链 (L2)**的一组链,这意味着它建立在以太坊之上,以解决一些表征它的问题 - 同时依赖它来运行。
众所周知,以太坊既不快也不便宜,在其上部署智能合约可能会迅速变得非常昂贵,这就是Polygon或Optimism等 L2 解决方案发挥作用的地方。
例如,多边形有两个主要优点:
第二个正是我们在 Polygon 上部署带有链上元数据的 NFT 智能合约的原因。一方面,如果在以太坊上存储我们的元数据时,我们可以预期每笔交易花费数百美元,那么在 Polygon 上它的成本不会超过几美分。
首先,让我们将 Polygon Mumbai 添加到我们的 Metamask 钱包中。
导航测试polygon网络并向下滚动到页面底部。您将看到**“添加多边形网络”按钮**,单击它并确认您要将其添加到 Metamask:
我们去到mumbaifaucet.com获取测试币,输入我们的地址获取测试币即可
10-20 秒后,会看到 MATIC 出现在 Metamask 钱包中。
# 新建一个文件夹用于此次项目的搭建
mkdir ChainBattled
cd ChainBattled
# 安装yarn并查看版本
npm install -g yarn
yarn --version
yarn add hardhat
# 初始化项目
npx hardhat init
现在我们需要安装OpenZeppelin包来访问ERC721 智能合约我们将使用该标准作为模板来构建我们的 NFT 智能合约。
yarn add @openzeppelin/contracts
将我们的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
}
};
在 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 个不同的功能:
首先,让我们在项目的根文件夹中新建一个 .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 ”值。最终结果如下:
在部署我们的智能合约之前的最后一步,我们需要创建部署脚本。
首先安装依赖
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();
当我们把脚本写好后,编译智能合约,只需在项目内的终端中运行以下命令:
npx hardhat compile
如果一切按预期进行,你将在 artifacts 文件夹中看到已编译的智能合约。
现在,让我们在运行的 Polygon Mumbai 链上部署智能合约
npx hardhat run scripts/deploy.js --network mumbai
如果一切正常你将在页面看到合约的地址
复制刚刚部署的智能合约的地址,去测试polygon网络,然后**在搜索栏中粘贴智能合约的地址。**进入智能合约页面后,单击“合约”选项卡。你会注意到合约代码不可读:
这是因为我们还没有验证我们的代码。
为了验证我们的智能合约,我们需要回到我们的项目,并在终端中运行以下代码:
# npx hardhat verify --network mumbai 合约地址
npx hardhat verify --network mumbai 0x2A9C54F7711d12aE72b9ECefEA2ce4c497595b9b
这里帝哥一直没有执行成功,后续是通过测试polygon网络提供的验证过的,如果你解决了下面的报错,可以和帝哥一起交流下
报错信息:
Error in plugin @nomiclabs/hardhat-etherscan: Failed to send contract verification request.
Endpoint URL: https://api-testnet.polygonscan.com/api
Reason: read ECONNRESET
通过网站添加方法,点击立即验证即可:
现在智能合约已经通过验证,mumbai.polygonscan.com 将在其附近显示一个绿色小勾:
然后寻找“mint”函数并点击Write:
这将打开一个 Metamask 弹出窗口,要求支付 gas 费用,单击签名按钮。恭喜!您刚刚铸造了您的第一个动态 NFT - 让我们转移到 OpenSea 测试网来现场查看它。
复制智能合约地址,前往testnet.opensea.com,并将其粘贴到搜索栏中:
如果一切正常,现在应该会看到您的 NFT 显示在 OpenSea 上,其中包含动态图像、标题和描述。
导航回测试.polygons网络,点击合约标签 > 写合约并寻找“train”功能。
插入您的 NFT 的 ID - 在这种情况下为“1”,因为我们只铸造了一个,然后单击写入:
然后回到testnets.opensea.com并刷新页面:
以上就是第三周的任务了,大家别忘记了填写表格完成哦,表格页面在下方:
我是懂币帝,用技术带你领略区块链魅力,第一时间获取行业最新资讯:
推特:@CoinmanLabs
微信:CoinmanLabs(社群客服微信进群)