• 将ERC20合约部署到 zkEVM Testnet 上
  • 发布于 2个月前
  • 554 热度
    0 评论
什么是 zkEVM?
Polygon zkEVM 是第一个开源的 zk-Rollup,以太坊提供安全性保证、 完整的 EVM 操作码等价,确保无摩擦的用户体验。github: https://polygon.technology/solutions/polygon-zkevm

-- 它是一个与 Polygon Matic POS 不同的网络吗?
是的,它是一个完全不同的网络,有自己的代币和钱包配置。
-- 这是否意味着它使用自己的代币?
是的,它使用自己的原生代币,而不是 Matic 或 Mumbai Testnet 代币。
-- EVM 等价(EVM-equivalence) 是什么意思?
等价指的是 Type2 ZK-EVM,_Vitalik 博客:不同类型的 ZK-EVMs_[4] 对其有更好的定义。

Type2 ZK-EVMs 努力做到完全等同于 EVM,但不完全等同于以太坊。也就是说,它们 "从内部 "看起来和以太坊完全一样,但它们在外部有一些差异,特别是在数据结构上,如块结构和状态树。

-- 对于开发者来说
这意味着你可以部署你现有的 solidity 代码,而不需要通过任何额外的步骤来编译你的代码,让它在这个网络上工作。与其他 ZK-EVM 解决方案相比,Type 2 提供了一种更简单的方式与该 ZK-EVM 解决方案结合。目标是与现有的应用程序完全兼容,但对以太坊做一些小的修改,使开发更容易,并使证明生成更快。

了解了这些, 让我们开始吧

钱包配置
需要注意的是,这些信息有很多已经存在于官方的Polygon Wiki For zkEVM[6],当 zkEVM 主网可用时,这些设置可能会改变。zkEVM 的钱包配置在 Chainlist.org 上吗?很遗憾还没有,因为网络配置和端口号可能会改变。
我们对 zkEVM Testnet 的配置设置如下:
网络名称: Polygon zkEVM Testnet
rpc 网址: https://rpc.public.zkevm-test.net[7]
链的 ID: 1402
货币符号: ETH
区块链浏览器网址: https://explorer.public.zkevm-test.net[8]
你可以通过进入网络,手动添加一个网络,将其添加到当前的 MetaMask 钱包:

MetaMask 手动添加一个网络

使用 Polygon zkEVM Testnet 配置 MetaMask
让我们看看在 zkEVM 浏览器上的钱包信息:

https://explorer.public.zkevm-test.net/address/0xB3f03B93F0bd65B960EE950d9aFC6867D461C33f

从水龙头获取测试代币
与其他 Testnet 网络相比,zkEVM 获得测试代币的方式有点不同。你需要先获得 Goerli Testnet 代币,然后将它们桥接到 zkEVM。我们将使用 QuickNode Goerli Faucet,但你也可以使用从以下任何一个链接获取:
.QuickNode Goerli Testnet Faucet[9]
.AlchemyGoerli Testnet Faucet[10]

一旦我们有了 Goerli Testnet 代币,我们需要通过使用https://public.zkevm-test.net/[11], 将它们桥接到 zkEVM Testnet 上。连接你喜欢的钱包,确保网络设置为以太坊 Goerli,输入需要桥接的金额,然后点击继续。

从Goerli配置Polygon zkEVM桥接
确认桥接交易:

通过切换到 zkEVM,然后确认交易,最终完成交易。

如果交易成功,你应该有一个确认屏幕,并在区块浏览器上看到结果。


将 ERC20 合约部署到 zkEVM Testnet 上
接下来,我们要用 Hardhat 来设置和部署 ERC20 合约到 zkEVM。
安装依赖
请确保在你的电脑上事先安装好以下依赖:
nvm 或 node v18.12.1
pnpm v7.15.0
设置 Hardhat
我们要做的第一件事是创建一个新的项目文件夹,启动 pnpm,安装 Hardhat,并对其进行配置:
mkdir zkevm-erc20;
cd zkevm-erc20;
git init;
pnpx hardhat;

# Expected Prompts
# 888    888                      888 888               888
# 888    888                      888 888               888
# 888    888                      888 888               888
# 8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
# 888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
# 888    888 .d888888 888    888  888 888  888 .d888888 888
# 888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
# 888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888
#
# 👷 Welcome to Hardhat v2.12.3 👷‍
#
# ? What do you want to do? …
#   Create a JavaScript project
# ❯ Create a TypeScript project
#   Create an empty hardhat.config.js
#   Quit

# ? Hardhat project root: › /path/to/zkevm-erc20

# ? Do you want to add a .gitignore? (Y/n) › y

# ? Do you want to install this sample project's dependencies with npm (@nomicfoundation/hardhat-toolbox)? (Y/n) › y

pnpm install;
让我们通过运行一个节点,部署默认的合约,然后测试该合约,来仔细检查我们的 Hardhat 设置是否按预期工作。

在终端 1
# 堆代码 www.duidaima.com
# FROM: ./zkevm-erc20

./node_modules/.bin/hardhat node;

# Expected Output:
# Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
#
# Accounts
# ========
#
# WARNING: These accounts, and their private keys, are publicly known.
# Any funds sent to them on Mainnet or any other live network WILL BE LOST.
# ...
在终端 2
将 "Lock.sol" 合约部署到我们正在运行的本地节点:
# FROM: ./zkevm-erc20

./node_modules/.bin/hardhat run scripts/deploy.ts

# Expected Output:
# Compiled 1 Solidity file successfully
# Lock with 1 ETH and unlock timestamp 1701595951 deployed to 0x5FbDB2315678afecb367f032d93F642f64180aa3
运行由原始脚手架项目生成的测试:
# FROM: ./zkevm-erc20

./node_modules/.bin/hardhat test;

# Expected Output:
#   Lock
#     Deployment
#       ✔ Should set the right unlockTime (894ms)
#       ✔ Should set the right owner
#       ✔ Should receive and store the funds to lock
#       ✔ Should fail if the unlockTime is not in the future
#     Withdrawals
#       Validations
#         ✔ Should revert with the right error if called too soon
#         ✔ Should revert with the right error if called from another account
#         ✔ Shouldn't fail if the unlockTime has arrived and the owner calls it
#       Events
#         ✔ Should emit an event on withdrawals
#       Transfers
#         ✔ Should transfer the funds to the owner
#
#  9 passing (1s)

创建一个 ERC20 合约
我们将以 OpenZeppelin 的 ERC20 Solidity 合约为基础,它将创建初始 10,000 个代币的代币,并允许所有者铸造更多的代币。
添加依赖
# FROM: ./zkevm-erc20

pnpm add -D @openzeppelin/contracts;
配置 ERC20使用_OpenZepplin Wizard/_[12]来配置 ERC20 代币:

编写新的合约
重命名现有的Lock.sol为zkerc20.sol,并用我们从 OpenZeppeling 向导中生成的代码替换它:
# FROM: ./zkevm-erc20

mv ./contracts/Lock.sol ./contracts/zkERC20.sol;
文件: ./contracts/zkERC20.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract ZkERC20 is ERC20, Ownable {
    constructor() ERC20("zkERC20", "ZK20") {
        _mint(msg.sender, 10000 * 10 ** decimals());
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}
测试 ERC20 合约
首先我们要为我们的 ERC20 合约做一个单一的测试,然后验证它是否正常工作。部署脚本首先,我们需要修改我们的部署脚本,以考虑到新的合约名称。
文件: ./scripts/deploy.ts。
// Imports
// =====堆代码 www.duidaima.com =================================
import { ethers } from "hardhat";

// Main Deployment Script
// ========================================================
async function main() {
  // Make sure in the contract factory that it mateches the contract name in the solidity file
  // Ex: contract ZkERC20
  const zkERC20Contract = await ethers.getContractFactory("ZkERC20");
  const contract = await zkERC20Contract.deploy();

  await contract.deployed();

  console.log(`ZkERC20 deployed to ${contract.address}`);
};

// Init
// ========================================================
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

创建测试
接下来要把Lock.ts测试文件重命名为zkERC20.test.ts,并添加一个测试,确认铸造 erc20 代币的总余额:
# FROM: ./zkevm-erc20

mv ./test/Lock.ts ./test/zkERC20.test.ts;
文件: ./test/zkERC20.test.ts:

// Imports
// ==========堆代码 www.duidaima.com ============================
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { expect } from "chai";
import { ethers } from "hardhat";

// Tests
// ========================================================
describe("zkERC20", function () {
  // We define a fixture to reuse the same setup in every test.
  // We use loadFixture to run this setup once, snapshot that state,
  // and reset Hardhat Network to that snapshot in every test.
  async function deployZkERC20() {
    // Contracts are deployed using the first signer/account by default
    const [owner, otherAccount] = await ethers.getSigners();
    // Make sure in the contract factory that it mateches the contract name in the solidity file
    // Ex: contract ZkERC20
    const zkERC20Contract = await ethers.getContractFactory("ZkERC20");
    const zkERC20 = await zkERC20Contract.deploy();

    return { zkERC20, owner, otherAccount };
  };

  /**
   *
   */
  describe("Deployment", function () {
    /**
     *
     */
    it("Should deploy with initial 10,000 supply", async function () {
      // Setup
      const { zkERC20 } = await loadFixture(deployZkERC20);

      // Init + Test
      expect(await zkERC20.totalSupply()).to.equal(ethers.utils.parseEther(`10000`).toString());
    });
  });

  /**
   *
   */
   describe("Minting", function () {
    /**
     *
     */
    it("Should mint and increase the supply by 137", async function () {
      // Setup
      const { zkERC20, owner } = await loadFixture(deployZkERC20);

      // Init
      await zkERC20.connect(owner).mint(owner.address, ethers.utils.parseUnits('137', 18));

      // Init + Test
      expect(await zkERC20.totalSupply()).to.equal(ethers.utils.parseEther(`10137`).toString());
    });
  });
});
让我们运行 Hardhat 节点并测试这个合约。

在终端 1
运行一个本地节点:
# FROM: ./zkevm-erc20

./node_modules/.bin/hardhat node;

# Expected Output:
# Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
#
# Accounts
# ========
#
# WARNING: These accounts, and their private keys, are publicly known.
# Any funds sent to them on Mainnet or any other live network WILL BE LOST.
# ...

在终端 2
运行测试:
# FROM: ./zkevm-erc20

./node_modules/.bin/hardhat test;

# Expected Output:
#   zkERC20
#     Deployment
#       ✔ Should deploy with initial 10,000 supply (803ms)
#     Minting
#       ✔ Should mint and increase the supply by 137
#
#  2 passing (819ms)

部署 ERC20 合约
需要注意的是,目前 Hardhat 中不支持 zkEVM 的部署。为了部署你的合约,你需要使用以太坊 Remix[13]的 Injected Provider 配置。确保在 remix 中创建一个zkERC20.sol文件,其中包含上面的合约代码:

remix
切换到编译部分,点击“编译按钮”,得到绿色的复选标记,表示一切编译正确。

remix编译合约
切换到左侧导航栏的部署部分,将环境设置为 "Injected Provider - Metamask"。并确保你的钱包被设置为 zkEVM 网络。

remix环境zkEVM
准备好后,点击部署按钮,在你的钱包中确认交易。

Remix部署合约
在 MetaMask 中查看代币
打开 MetaMask 钱包,点击交易,在区块浏览器上查看该交易。在区块浏览器中点击合约地址,打开合约。在区块浏览器中加载合约后,复制合约地址。

打开你的 MetaMask,点击Asset(资产),并点击Import tokens(导入代币):

粘贴合约地址,并根据需要填写其他字段。它们可能会自动弹出,然后点击添加自定义代币:

现在你应该能够按照提示操作,然后在你的钱包里看到新的 ZK20 代币,并有正确的初始金额。

你已经完全部署了一个 ERC20 合约到 Polygon Hermes zkEVM 测试网上。


参考资料
[1]登链翻译计划: https://github.com/lbc-team/Pioneer
[2]翻译小组: https://learnblockchain.cn/people/412
[3]Tiny 熊: https://learnblockchain.cn/people/15
[4]Vitalik 博客:不同类型的 ZK-EVMs: https://vitalik.eth.limo/general/2022/08/04/zkevm.html
[5]状态树: https://medium.com/@eiki1212/ethereum-state-tree-architecture-explained-a30237009d4e
[6]Polygon Wiki For zkEVM: https://wiki.polygon.technology/docs/zkEVM/develop
[7]https://rpc.public.zkevm-test.net: https://rpc.public.zkevm-test.net/
[8]https://explorer.public.zkevm-test.net: https://explorer.public.zkevm-test.net/
[9]QuickNode Goerli Testnet Faucet: https://faucet.quicknode.com/ethereum/goerli
[10]AlchemyGoerli Testnet Faucet: https://goerlifaucet.com/
[11]https://public.zkevm-test.net/: https://public.zkevm-test.net/
[12]OpenZepplin Wizard/: https://wizard.openzeppelin.com/
[13]以太坊 Remix: https://remix.ethereum.org/
[14]GitHub - codingwithmanny/zkevm-erc20: https://github.com/codingwithmanny/zkevm-erc20
[15]@登链社区: https://twitter.com/NUpchain


用户评论