Road2Web3
Road2Web3
Share Dialog
Share Dialog

Subscribe to LaiLai

Subscribe to LaiLai
本教程只介绍操作步骤,代码含义等不做解释,下面是官方英文详细教程链接:
https://docs.alchemy.com/docs/how-to-make-nfts-with-on-chain-metadata-hardhat-and-javascript
1.打开链接 Polygon Mumbai,然后滑动到网页底部,点击右下角按钮完成Polygon Mumbai的添加

2.在水龙头( mumbaifaucet.com 或 faucet.polygon.technology )获取测试币,用于支付部 署需要的Gas Fee

等待10~20秒,可以收到测试币
1.创建项目文件夹,并导入到VSStudio
1.1 创建文件夹 “ChainBattled”,使用VSStudio的“打开文件夹” 功能

1.2 选择对应文件夹并打开

2.项目依赖库配置
2.1 在VSStudio打开终端

2.2 在终端输入如下命令 , 安装hardhat
yarn add hardhat

2.3 在终端输入如下命令 , 初始化hardhat
nxp hardhat init
选择 “Create a JavaScript project”,键盘点击回车确认

终端弹出相关hardhat初始化配置的提示,全点击“回车”

至此,hardhat 初始化结束

2.4 输入如下命令安装 OpenZeppelin 库,这个库可以方便我们创建接下来的合约。
yarn add @openzeppelin/contracts

3.在项目中配置Polygon Mumbai网络环境
3.1 终端输入如下命令 安装 dotenv
3.2 终端输入如下命令创建 .env 文件
touch .env

3.3 获取 Polygon Mumbai 的 TESTNET_RPC
进入 Alchemy创建app的界面 创建一个 Polygon Mumbai 网络的app,创建app的时候注意网络需要选择 Polygon Mumbai

进入app详情界面,点击 VIEW KEY 按钮,图中的HTTPS就是我们需要的 TESTNET_RPC

3.4 获取 Polygon Mumbai 的 POLYGONSCAN_API_KEY
打开 Polygon注册界面,创建一个账号

账号注册成功后,进入 API KEY配置界面 ,创建API KEY

下图Api Key Token就是我们需要的POLYGONSCAN_API_KEY

3.5 打开 .env文件,配置对应的值

3.6 打开 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

下面是文件源码
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 toknenIdToLevels;
constructor() ERC721("Chain Battles", "CBTLS") {}
function generateCharacter(uint256 tokenId)
public
view
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 = toknenIdToLevels[_tokenId];
return levels.toString();
}
function getTokenURI(uint256 tokenId) public view 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();
_mint(msg.sender, newItemId);
toknenIdToLevels[newItemId] = 0;
_setTokenURI(newItemId, getTokenURI((newItemId)));
}
function raiseLevel(uint256 _tokenId) public {
require(_exists(_tokenId), "error, the tokenId not exists");
require(
ownerOf(_tokenId) == msg.sender,
"error, you are not the owner"
);
toknenIdToLevels[_tokenId] = toknenIdToLevels[_tokenId] + 1;
_setTokenURI(_tokenId, getTokenURI(_tokenId));
}
}
打开scripts目录下的deploy.js 文件,复制下面的源码到文件

// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// You can also run a script with `npx hardhat run <script>`. If you do that, Hardhat
// will compile your contracts, add the Hardhat Runtime Environment's members to the
// global scope, and execute the script.
const hre = require("hardhat");
const main = async () => {
try {
const contractFactory = await hre.ethers.getContractFactory("ChainBattles");
const contract = await contractFactory.deploy();
await contract.deployed();
console.log("Contract deployed to:", contract.address);
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
main();
3.1 在终端输入以下命令编译合约
npx hardhat compile

3.2 输入以下命令在mumbai网络发布合约

npx hardhat run scripts/deploy.js --network mumbai
部署成功后可以在终端看到部署的合约地址 打开区块浏览器并输入对应合约地址可以看到部署的合约

4.1在终端输入以下命令,其中合约地址需要替换为在步骤3.2中生成的合约地址
npx hardhat verify --network mumbai 0x660842E5eD720264ccC9f70002e78200d58a26b8
按照官方文档的说法,输入上面的命令就能直接成功,然而我在这一步却遇到了下图的网络问题,导致始终无法verify成功。

于是我只能手动在区块浏览器去验证合约,如果你输入verify命令后直接成功了,可以忽略接下来的步骤,直接跳到 Step5.
4.2 打开 artifacts/build-info 文件夹中的文件,文件名和我不一样不用管

复制该文件中如下部分
"input": {
"language": "Solidity",
"sources": {
"contracts/ChainBattles.sol": {
<<中间部分太长,不展示到这里>>
"settings": {
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata"
],
"": [
"ast"
]
}
}
}
}
整个代码部分我没有复制完全,你只需注意从下图的 ”{“ 开始复制,

复制到下图的 “}” 结束

4.3在contracts目录下创建一个文件 verify.json , 将4.2复制内容拷贝进去并保存

4.4 在区块浏览器进入到刚才创建的合约,合约地址注意使用你生成的合约地址,然后点击图中标注的 “Verify and Publish”

按下图配置相应的选项,然后点击 “continue” 按钮

在下图的界面点击 “选择文件” 按钮,选择 4.3种创建的文件 “verify.json”,然后点击”Click to Upload selected file“

上传成功后出现如下提示

最后滑动到界面底部,点击 “Verify and Publish” 按钮
等待一会儿出现下图界面,就表示认证成功

5.1 进入合约浏览器查看我们创建的合约,点击如图的mint按钮,通过 MetaMask 签名并执行操作

5.2 进入 OpenSea的个人中心,就可以看到你创建的NFT

至此,Week3的任务完成,接下来就打开任务提交链接,
等官方快照完成后在这里Claim 第三周的NFT
后续几周的教程会更新到下面的我的推特,对第三周教程有什么疑问也可以在推特问我。
本教程只介绍操作步骤,代码含义等不做解释,下面是官方英文详细教程链接:
https://docs.alchemy.com/docs/how-to-make-nfts-with-on-chain-metadata-hardhat-and-javascript
1.打开链接 Polygon Mumbai,然后滑动到网页底部,点击右下角按钮完成Polygon Mumbai的添加

2.在水龙头( mumbaifaucet.com 或 faucet.polygon.technology )获取测试币,用于支付部 署需要的Gas Fee

等待10~20秒,可以收到测试币
1.创建项目文件夹,并导入到VSStudio
1.1 创建文件夹 “ChainBattled”,使用VSStudio的“打开文件夹” 功能

1.2 选择对应文件夹并打开

2.项目依赖库配置
2.1 在VSStudio打开终端

2.2 在终端输入如下命令 , 安装hardhat
yarn add hardhat

2.3 在终端输入如下命令 , 初始化hardhat
nxp hardhat init
选择 “Create a JavaScript project”,键盘点击回车确认

终端弹出相关hardhat初始化配置的提示,全点击“回车”

至此,hardhat 初始化结束

2.4 输入如下命令安装 OpenZeppelin 库,这个库可以方便我们创建接下来的合约。
yarn add @openzeppelin/contracts

3.在项目中配置Polygon Mumbai网络环境
3.1 终端输入如下命令 安装 dotenv
3.2 终端输入如下命令创建 .env 文件
touch .env

3.3 获取 Polygon Mumbai 的 TESTNET_RPC
进入 Alchemy创建app的界面 创建一个 Polygon Mumbai 网络的app,创建app的时候注意网络需要选择 Polygon Mumbai

进入app详情界面,点击 VIEW KEY 按钮,图中的HTTPS就是我们需要的 TESTNET_RPC

3.4 获取 Polygon Mumbai 的 POLYGONSCAN_API_KEY
打开 Polygon注册界面,创建一个账号

账号注册成功后,进入 API KEY配置界面 ,创建API KEY

下图Api Key Token就是我们需要的POLYGONSCAN_API_KEY

3.5 打开 .env文件,配置对应的值

3.6 打开 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

下面是文件源码
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 toknenIdToLevels;
constructor() ERC721("Chain Battles", "CBTLS") {}
function generateCharacter(uint256 tokenId)
public
view
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 = toknenIdToLevels[_tokenId];
return levels.toString();
}
function getTokenURI(uint256 tokenId) public view 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();
_mint(msg.sender, newItemId);
toknenIdToLevels[newItemId] = 0;
_setTokenURI(newItemId, getTokenURI((newItemId)));
}
function raiseLevel(uint256 _tokenId) public {
require(_exists(_tokenId), "error, the tokenId not exists");
require(
ownerOf(_tokenId) == msg.sender,
"error, you are not the owner"
);
toknenIdToLevels[_tokenId] = toknenIdToLevels[_tokenId] + 1;
_setTokenURI(_tokenId, getTokenURI(_tokenId));
}
}
打开scripts目录下的deploy.js 文件,复制下面的源码到文件

// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// You can also run a script with `npx hardhat run <script>`. If you do that, Hardhat
// will compile your contracts, add the Hardhat Runtime Environment's members to the
// global scope, and execute the script.
const hre = require("hardhat");
const main = async () => {
try {
const contractFactory = await hre.ethers.getContractFactory("ChainBattles");
const contract = await contractFactory.deploy();
await contract.deployed();
console.log("Contract deployed to:", contract.address);
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
main();
3.1 在终端输入以下命令编译合约
npx hardhat compile

3.2 输入以下命令在mumbai网络发布合约

npx hardhat run scripts/deploy.js --network mumbai
部署成功后可以在终端看到部署的合约地址 打开区块浏览器并输入对应合约地址可以看到部署的合约

4.1在终端输入以下命令,其中合约地址需要替换为在步骤3.2中生成的合约地址
npx hardhat verify --network mumbai 0x660842E5eD720264ccC9f70002e78200d58a26b8
按照官方文档的说法,输入上面的命令就能直接成功,然而我在这一步却遇到了下图的网络问题,导致始终无法verify成功。

于是我只能手动在区块浏览器去验证合约,如果你输入verify命令后直接成功了,可以忽略接下来的步骤,直接跳到 Step5.
4.2 打开 artifacts/build-info 文件夹中的文件,文件名和我不一样不用管

复制该文件中如下部分
"input": {
"language": "Solidity",
"sources": {
"contracts/ChainBattles.sol": {
<<中间部分太长,不展示到这里>>
"settings": {
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata"
],
"": [
"ast"
]
}
}
}
}
整个代码部分我没有复制完全,你只需注意从下图的 ”{“ 开始复制,

复制到下图的 “}” 结束

4.3在contracts目录下创建一个文件 verify.json , 将4.2复制内容拷贝进去并保存

4.4 在区块浏览器进入到刚才创建的合约,合约地址注意使用你生成的合约地址,然后点击图中标注的 “Verify and Publish”

按下图配置相应的选项,然后点击 “continue” 按钮

在下图的界面点击 “选择文件” 按钮,选择 4.3种创建的文件 “verify.json”,然后点击”Click to Upload selected file“

上传成功后出现如下提示

最后滑动到界面底部,点击 “Verify and Publish” 按钮
等待一会儿出现下图界面,就表示认证成功

5.1 进入合约浏览器查看我们创建的合约,点击如图的mint按钮,通过 MetaMask 签名并执行操作

5.2 进入 OpenSea的个人中心,就可以看到你创建的NFT

至此,Week3的任务完成,接下来就打开任务提交链接,
等官方快照完成后在这里Claim 第三周的NFT
后续几周的教程会更新到下面的我的推特,对第三周教程有什么疑问也可以在推特问我。
<100 subscribers
<100 subscribers
No activity yet