什么是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 对其有更好的定义。

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

-- 对于开发者来说
这意味着你可以部署你现有的solidity代码,而不需要通过任何额外的步骤来编译你的代码,让它在这个网络上工作。与其他ZK-EVM解决方案相比,Type 2提供了一种更简单的方式与该ZK-EVM解决方案结合。

目标是与现有的应用程序完全兼容,但对以太坊做一些小的修改,使开发更容易,并使证明生成更快。

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

钱包配置

需要注意的是,这些信息有很多已经存在于官方的Polygon Wiki For zkEVM,当zkEVM主网可用时,这些设置可能会改变。
zkEVM的钱包配置在Chainlist.org上吗?很遗憾还没有,因为网络配置和端口号可能会改变。

我们对zkEVM Testnet的配置设置如下:

你可以通过进入网络,手动添加一个网络,将其添加到当前的MetaMask钱包:
MetaMask手动添加一个网络

使用Polygon zkEVM Testnet配置MetaMask

让我们看看在zkEVM浏览器上的钱包信息:

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

从水龙头获取测试代币

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


一旦我们有了Goerli Testnet代币,我们需要通过使用https://public.zkevm-test.net/, 将它们桥接到zkEVM Testnet上。

连接你喜欢的钱包,确保网络设置为以太坊 Goerli,输入需要桥接的金额,然后点击继续。

确认桥接交易:

通过切换到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

# 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来配置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
// ========================================================
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
// ========================================================
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的Injected Provider配置。

确保在remix中创建一个zkERC20.sol文件,其中包含上面的合约代码:


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

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

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

在MetaMask中查看代币

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

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

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

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

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

完整的代码

zkEVM ERC20 代币的完整代码。请记住,目前还不支持Hardhat部署。
GitHub - codingwithmanny/zkevm-erc20

如果其他 zkEVM 教程,我们会及时更新,欢迎在 Twitter 关注 @登链社区

转载自:https://learnblockchain.cn/article/5349