Cover photo

手把手教程 ——Alchemy Week3

Alchemy 教程目录

Week1: How to Develop an NFT Smart Contract (ERC721) with Alchemy 教程

Week2: How to Build “Buy Me a Coffee“ Defi dapp with Alchemy 教程

Week3: How to Make NFTs with On-Chain Metadata - HardHat and JavaScript 教程

官方教程在此,也可以看 youtube 视频链接,不想看我啰嗦的可以移步。

Play Video

step0 环境配置

  • 系统环境:

    Window10 X64

  • 编程环境:

    nodeJS v16.15.0

    NPM v8.5.5

    nodeJS 安装回头写一篇教程吧,最简单的方法可以 google nvm,比去官网下载 nodeJS 的安装包好用多了。另外 windows 系统下需要配置环境变量,不明白的可以先百度。

  • 编程IDE:

    VS Code

    VS code 下载官网,exe 的安装程序,按照提示即可

step1 部署 web3 环境

1. 新建文件夹 ChainBattles,在文件夹内启动 cmd,npm init -y初始化项目,获得文件 package.json。

2. 安装 hardhat,在 cmd 中输入

post image

根据提示依次

选择Create a basic sample project

选择默认路径

3. 复制下列代码,安装需要的库

npm install --save-dev "hardhat@^2.9.3" "@nomiclabs/hardhat-waffle@^2.0.0" "ethereum-waffle@^3.0.0" "chai@^4.2.0" "@nomiclabs/hardhat-ethers@^2.0.0" "ethers@^5.0.0" "@nomiclabs/hardhat-etherscan@^3.0.1"
post image

4. 安装 dotenv 库

5. 安装 OpenZeppelin

npm install @openzeppelin/contracts

可以看下文件夹内的各文件,如果和以下树形图一致,那就表示环境部署没有问题了。

.
├── README.md 
├── contracts 
├── hardhat.config.js 
├── node_modules 
├── package-lock.json 
├── package.json
├── scripts 
└── test

接下来的step2,step4 需使用 VScode 打开文件夹进行编辑。

step2 编写智能合约

在 ./contracts/ 文件夹下新建 ChainBattles.sol,复制以下代码,然后保存。

// 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 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 = tokenIdToLevels[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();
        _safeMint(msg.sender, newItemId);
        tokenIdToLevels[newItemId] = 0;
        _setTokenURI(newItemId, getTokenURI(newItemId));
    }

    function train(uint256 tokenId) public {
        require(_exists(tokenId));
        require(ownerOf(tokenId) == msg.sender, "You must own this NFT to train it!");
        uint256 currentLevel = tokenIdToLevels[tokenId];
        tokenIdToLevels[tokenId] = currentLevel + 1;
        _setTokenURI(tokenId, getTokenURI(tokenId));
    }
}

step3 申请 Alchemy 帐号并配置小狐狸钱包

1. 注册 alchemy 帐号详细步骤可以回看 week1 教程的 step3。

https://www.alchemy.com/

2. 进入 Dashboard,点击 create app。

post image

3. 依次填入 Name, Description,Chain 选择 Polygon,Network 选择 Polygon Mumbai,然后点击 CREATE APP。

post image

4. 点击 VIEW KEY,复制 HTTPS 和 API KEY 的内容

post image

5. 查看小狐狸钱包中是否有 Mumbai 测试网,如果没有可以去 chainlink.org 上添加一个,并保存私钥,第六步要用到。

6. 因为交互需要消耗 gas,所以还需通过 chainlink faucet 获取测试代币 MATIC。通过 faucet 的链接,进入申请代币即可。

https://faucets.chain.link/

step4 在 Mumbai 测试网络部署合约

1. 在 ./scripts/ 文件夹下新建 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();

2. 编辑 ./hardhat.config.js,复制以下代码,然后保存。

require("dotenv").config();
require("@nomiclabs/hardhat-waffle");
require("@nomiclabs/hardhat-etherscan");

const MUMBAI_URL = process.env.MUMBAI_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const POLYSCAN_API_KEY = process.env.POLYSCAN_API_KEY

module.exports = {
  solidity: "0.8.10",
  networks: {
    mumbai: {
      url: MUMBAI_URL,
      accounts: [PRIVATE_KEY]
    },
  },
  etherscan: {
    apiKey: POLYSCAN_API_KEY
  }
};

3. 新建 ./.env 文件,复制以下代码,然后保存。

MUMBAI_URL=输入你的MUMBAI_URL
POLYSCAN_API_KEY=输入你的POLYSCAN_API_KEY
PRIVATE_KEY=输入你的私钥

4. 在 cmd 中运行 npx hardhat run scripts/deploy.js --network mumbai,返回

Contract deployed to: 合约地址

至此,合约已经部署到了 Mumbai 测试网,还可以在浏览器中查看。

post image

但是合约没有开源,还没有 verify。

post image

5. 在 cmd 中运行 npx hardhat verify --network mumbai [合约地址],返回

Nothing to compile
Successfully submitted source code for contract
contracts/ChainBattles.sol:ChainBattles at 合约地址 
for verification on the block explorer. Waiting for verification result...

Successfully verified contract ChainBattles on Etherscan.
https://mumbai.polygonscan.com/address/合约地址#code

看到 successfully 即 verify 成功,再回到 mumbai polygonscan 上看,已经有绿勾了。

post image

step5 通过合约Mint NFT

1. 在合约页面中,选择 Contract —> Write Contract —> Connect to Web3,在弹出的 Metamask 窗口点击下一步,最后连接。

post image

2. 在 mint 方法下,点击 write 并在弹出的 Metamask 窗口内确认。

post image

3. 在 testnet.opensea.io 中可以查看 NFT 已经在钱包中。

post image

step6 通过合约train NFT

这是一个动态的 NFT,回到合约页面中,找到 train 方法,输入自己所持有 NFT 的 tokenId(第一个输入1),再点击 write 并在弹出的 Metamask 窗口内确认。

post image

在 testnet.opensea.io 中可以查看 NFT ,点击 refresh metadata 按钮后,再刷新页面,Levels 变成了 1。

post image
post image

step7 在官网提交任务并 claim NFT

在官方申请网址中提交对应的信息。

https://alchemyapi.typeform.com/roadtoweekthree

在 mintkudos 网址中 claim Alchemy 的 NFT,通常需要一天至一周可以获得 allowlist 资格。

https://mintkudos.xyz/claim/674

post image