{"content":{"title":"如何在Polygon zkEVM 测试网上部署合约","body":"> * 原文链接： https://medium.com/@codingwithmanny/how-to-deploy-a-contract-to-polygon-zkevm-testnet-385afc1fb1a5\r\n> * 译文出自：[登链翻译计划](https://github.com/lbc-team/Pioneer)\r\n> * 译者：[翻译小组](https://learnblockchain.cn/people/412)  校对：[Tiny 熊](https://learnblockchain.cn/people/15)\r\n> * 本文永久链接：[learnblockchain.cn/article…](https://learnblockchain.cn/article/5349)\r\n\r\n\r\n\r\n\r\n\r\n![img](https://img.learnblockchain.cn/2023/02/02/1_RJUR60-RSkwMaoL2ghu7og.png)\r\n\r\n## 什么是zkEVM？\r\n\r\n\r\n\r\n> Polygon zkEVM是第一个开源的zk-Rollup，以太坊提供安全性保证、 完整的EVM操作码等价，确保无摩擦的用户体验。\r\n> github: https://polygon.technology/solutions/polygon-zkevm\r\n\r\n-- 它是一个与Polygon Matic POS不同的网络吗？\r\n\r\n是的，它是一个完全不同的网络，有自己的代币和钱包配置。\r\n\r\n -- 这是否意味着它使用自己的代币？\r\n\r\n是的，它使用自己的原生代币，而不是Matic或Mumbai Testnet代币。\r\n\r\n-- EVM 等价（EVM-equivalence） 是什么意思？\r\n\r\n等价指的是Type2 ZK-EVM，[*Vitalik 博客：不同类型的 ZK-EVMs*](https://vitalik.eth.limo/general/2022/08/04/zkevm.html) 对其有更好的定义。\r\n\r\n> Type2 ZK-EVMs努力做到完全等同于EVM，但不完全等同于以太坊。也就是说，它们 \"从内部 \"看起来和以太坊完全一样，但它们在外部有一些差异，特别是在数据结构上，如块结构和[状态树](https://medium.com/@eiki1212/ethereum-state-tree-architecture-explained-a30237009d4e)。\r\n> https://vitalik.eth.limo/general/2022/08/04/zkevm.html\r\n\r\n-- 对于开发者来说\r\n\r\n这意味着你可以部署你现有的solidity代码，而不需要通过任何额外的步骤来编译你的代码，让它在这个网络上工作。与其他ZK-EVM解决方案相比，Type 2提供了一种更简单的方式与该ZK-EVM解决方案结合。\r\n\r\n> 目标是与现有的应用程序完全兼容，但对以太坊做一些小的修改，使开发更容易，并使证明生成更快。\r\n\r\n了解了这些， 让我们开始吧\r\n\r\n## 钱包配置\r\n\r\n需要注意的是，这些信息有很多已经存在于官方的[Polygon Wiki For zkEVM](https://wiki.polygon.technology/docs/zkEVM/develop)，当zkEVM主网可用时，这些设置可能会改变。\r\n\r\n**zkEVM的钱包配置在Chainlist.org上吗？** 很遗憾还没有，因为网络配置和端口号可能会改变。\r\n\r\n我们对zkEVM Testnet的配置设置如下：\r\n\r\n- **网络名称：** Polygon zkEVM Testnet\r\n- **rpc网址：** [https://rpc.public.zkevm-test.net](https://rpc.public.zkevm-test.net/)\r\n- **链的ID:** 1402\r\n- **货币符号:** ETH\r\n- **区块链浏览器网址:** [https://explorer.public.zkevm-test.net](https://explorer.public.zkevm-test.net/)\r\n\r\n你可以通过进入网络，手动添加一个网络，将其添加到当前的MetaMask钱包：\r\n\r\n![img](https://img.learnblockchain.cn/2023/02/02/1_QXwodwN0YzO02y0cYPGk3Q.png)\r\n\r\n>  MetaMask手动添加一个网络\r\n\r\n![img](https://img.learnblockchain.cn/2023/02/02/1__1mJ9CykHDBdBBs2UEDRHQ.png)\r\n\r\n> 使用Polygon zkEVM Testnet配置MetaMask\r\n\r\n让我们看看在zkEVM浏览器上的钱包信息：\r\n\r\n![img](https://img.learnblockchain.cn/2023/02/02/1_pIN_AMCL0t0-ogtGjPyPtw.png)\r\n\r\nhttps://explorer.public.zkevm-test.net/address/0xB3f03B93F0bd65B960EE950d9aFC6867D461C33f\r\n\r\n## 从水龙头获取测试代币\r\n\r\n与其他Testnet网络相比，zkEVM获得测试代币的方式有点不同。你需要先获得Goerli Testnet代币，然后将它们桥接到zkEVM。\r\n\r\n我们将使用QuickNode Goerli Faucet，但你也可以使用从以下任何一个链接获取：\r\n\r\n- [QuickNode Goerli Testnet Faucet](https://faucet.quicknode.com/ethereum/goerli)\r\n- [AlchemyGoerli Testnet Faucet](https://goerlifaucet.com/)\r\n\r\n![img](https://img.learnblockchain.cn/2023/02/02/1_ATi_Ye_owgbrgD1aiJ_RSA.png)\r\n\r\n\r\n\r\n一旦我们有了Goerli Testnet代币，我们需要通过使用[https://public.zkevm-test.net/](https://public.zkevm-test.net/)， 将它们桥接到zkEVM Testnet上。\r\n\r\n连接你喜欢的钱包，确保网络设置为以太坊 Goerli，输入需要桥接的金额，然后点击**继续**。\r\n\r\n![从Goerli配置Polygon zkEVM桥接](https://img.learnblockchain.cn/2023/02/02/1_4XQ-gRk94lFZMu9pUB7m-g.png)\r\n\r\n\r\n\r\n确认桥接交易:\r\n\r\n![确认zkEVM的桥接交易](https://img.learnblockchain.cn/2023/02/02/1_5B3yktis50ai7bfgrCj5tQ.png)\r\n\r\n\r\n\r\n通过切换到zkEVM，然后确认交易，最终完成交易。\r\n\r\n\r\n![zkEVM最终完成桥接交易](https://img.learnblockchain.cn/2023/02/02/1_5zgwT-lWWO2T8Y0wQz6d-Q.png)\r\n\r\n\r\n\r\n如果交易成功，你应该有一个确认屏幕，并在区块浏览器上看到结果。\r\n\r\n![从Goerli Testnet到zkEVM Testnet的成功桥接](https://img.learnblockchain.cn/2023/02/02/1_uF6-eIkvIy2fcuUbRuGeig.png)\r\n\r\n\r\n\r\n## 将ERC20合约部署到zkEVM Testnet上\r\n\r\n接下来，我们要用Hardhat来设置和部署ERC20合约到zkEVM。\r\n\r\n### 安装依赖\r\n\r\n请确保在你的电脑上事先安装好以下依赖：\r\n\r\n- nvm或node `v18.12.1`\r\n- pnpm `v7.15.0`\r\n\r\n### 设置Hardhat\r\n\r\n我们要做的第一件事是创建一个新的项目文件夹，启动pnpm，安装Hardhat，并对其进行配置：\r\n\r\n```bash\r\nmkdir zkevm-erc20;\r\ncd zkevm-erc20;\r\ngit init;\r\npnpx hardhat;\r\n\r\n# Expected Prompts\r\n# 888    888                      888 888               888\r\n# 888    888                      888 888               888\r\n# 888    888                      888 888               888\r\n# 8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888\r\n# 888    888     \"88b 888P\"  d88\" 888 888 \"88b     \"88b 888\r\n# 888    888 .d888888 888    888  888 888  888 .d888888 888\r\n# 888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.\r\n# 888    888 \"Y888888 888     \"Y88888 888  888 \"Y888888  \"Y888\r\n#\r\n# 👷 Welcome to Hardhat v2.12.3 👷‍\r\n#\r\n# ? What do you want to do? …\r\n#   Create a JavaScript project\r\n# ❯ Create a TypeScript project\r\n#   Create an empty hardhat.config.js\r\n#   Quit\r\n\r\n# ? Hardhat project root: › /path/to/zkevm-erc20\r\n\r\n# ? Do you want to add a .gitignore? (Y/n) › y\r\n\r\n# ? Do you want to install this sample project's dependencies with npm (@nomicfoundation/hardhat-toolbox)? (Y/n) › y\r\n\r\npnpm install;\r\n```\r\n\r\n让我们通过运行一个节点，部署默认的合约，然后测试该合约，来仔细检查我们的Hardhat设置是否按预期工作。\r\n\r\n**在终端1**\r\n\r\n```bash\r\n# FROM: ./zkevm-erc20\r\n\r\n./node_modules/.bin/hardhat node;\r\n\r\n# Expected Output:\r\n# Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/\r\n# \r\n# Accounts\r\n# ========\r\n# \r\n# WARNING: These accounts, and their private keys, are publicly known.\r\n# Any funds sent to them on Mainnet or any other live network WILL BE LOST.\r\n# ...\r\n```\r\n\r\n**在终端2**\r\n\r\n将 \"Lock.sol\" 合约部署到我们正在运行的本地节点：\r\n\r\n```bash\r\n# FROM: ./zkevm-erc20\r\n\r\n./node_modules/.bin/hardhat run scripts/deploy.ts\r\n\r\n# Expected Output:\r\n# Compiled 1 Solidity file successfully\r\n# Lock with 1 ETH and unlock timestamp 1701595951 deployed to 0x5FbDB2315678afecb367f032d93F642f64180aa3\r\n```\r\n\r\n运行由原始脚手架项目生成的测试：\r\n\r\n```bash\r\n# FROM: ./zkevm-erc20\r\n\r\n./node_modules/.bin/hardhat test;\r\n \r\n# Expected Output:\r\n#   Lock\r\n#     Deployment\r\n#       ✔ Should set the right unlockTime (894ms)\r\n#       ✔ Should set the right owner\r\n#       ✔ Should receive and store the funds to lock\r\n#       ✔ Should fail if the unlockTime is not in the future\r\n#     Withdrawals\r\n#       Validations\r\n#         ✔ Should revert with the right error if called too soon\r\n#         ✔ Should revert with the right error if called from another account\r\n#         ✔ Shouldn't fail if the unlockTime has arrived and the owner calls it\r\n#       Events\r\n#         ✔ Should emit an event on withdrawals\r\n#       Transfers\r\n#         ✔ Should transfer the funds to the owner\r\n#\r\n#  9 passing (1s)\r\n```\r\n\r\n### 创建一个ERC20合约\r\n\r\n我们将以OpenZeppelin的ERC20 Solidity合约为基础，它将创建初始10,000个代币的代币，并允许所有者铸造更多的代币。\r\n\r\n**添加依赖**\r\n\r\n```\r\n# FROM: ./zkevm-erc20\r\n\r\npnpm add -D @openzeppelin/contracts;\r\n```\r\n\r\n**配置ERC20**\r\n使用[*OpenZepplin Wizard/*](https://wizard.openzeppelin.com/)来配置ERC20代币：\r\n\r\n![img](https://img.learnblockchain.cn/2023/02/02/1_e44pWKkNM0J3i2zyRR6YSg.png)\r\n\r\n**编写新的合约**\r\n\r\n重命名现有的`Lock.sol`为`zkerc20.sol`，并用我们从OpenZeppeling向导中生成的代码替换它：\r\n\r\n```\r\n# FROM: ./zkevm-erc20\r\n\r\nmv ./contracts/Lock.sol ./contracts/zkERC20.sol;\r\n```\r\n\r\n**文件：** `./contracts/zkERC20.sol`：\r\n\r\n```\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.9;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\ncontract ZkERC20 is ERC20, Ownable {\r\n    constructor() ERC20(\"zkERC20\", \"ZK20\") {\r\n        _mint(msg.sender, 10000 * 10 ** decimals());\r\n    }\r\n\r\n    function mint(address to, uint256 amount) public onlyOwner {\r\n        _mint(to, amount);\r\n    }\r\n}\r\n```\r\n\r\n### 测试ERC20合约\r\n\r\n首先我们要为我们的ERC20合约做一个单一的测试，然后验证它是否正常工作。\r\n\r\n**部署脚本**\r\n首先，我们需要修改我们的部署脚本，以考虑到新的合约名称。\r\n\r\n**文件：** `./scripts/deploy.ts`。\r\n\r\n```typescript\r\n// Imports\r\n// ========================================================\r\nimport { ethers } from \"hardhat\";\r\n\r\n// Main Deployment Script\r\n// ========================================================\r\nasync function main() {\r\n  // Make sure in the contract factory that it mateches the contract name in the solidity file\r\n  // Ex: contract ZkERC20\r\n  const zkERC20Contract = await ethers.getContractFactory(\"ZkERC20\");\r\n  const contract = await zkERC20Contract.deploy();\r\n\r\n  await contract.deployed();\r\n\r\n  console.log(`ZkERC20 deployed to ${contract.address}`);\r\n};\r\n\r\n// Init\r\n// ========================================================\r\n// We recommend this pattern to be able to use async/await everywhere\r\n// and properly handle errors.\r\nmain().catch((error) => {\r\n  console.error(error);\r\n  process.exitCode = 1;\r\n});\r\n```\r\n\r\n**创建测试**\r\n\r\n接下来要把`Lock.ts`测试文件重命名为`zkERC20.test.ts`，并添加一个测试，确认铸造erc20代币的总余额：\r\n\r\n```bash\r\n# FROM: ./zkevm-erc20\r\n\r\nmv ./test/Lock.ts ./test/zkERC20.test.ts;\r\n```\r\n\r\n**文件：** `./test/zkERC20.test.ts`：\r\n\r\n```typescript\r\n// Imports\r\n// ========================================================\r\nimport { loadFixture } from \"@nomicfoundation/hardhat-network-helpers\";\r\nimport { expect } from \"chai\";\r\nimport { ethers } from \"hardhat\";\r\n\r\n// Tests\r\n// ========================================================\r\ndescribe(\"zkERC20\", function () {\r\n  // We define a fixture to reuse the same setup in every test.\r\n  // We use loadFixture to run this setup once, snapshot that state,\r\n  // and reset Hardhat Network to that snapshot in every test.\r\n  async function deployZkERC20() {\r\n    // Contracts are deployed using the first signer/account by default\r\n    const [owner, otherAccount] = await ethers.getSigners();\r\n    // Make sure in the contract factory that it mateches the contract name in the solidity file\r\n    // Ex: contract ZkERC20\r\n    const zkERC20Contract = await ethers.getContractFactory(\"ZkERC20\");\r\n    const zkERC20 = await zkERC20Contract.deploy();\r\n\r\n    return { zkERC20, owner, otherAccount };\r\n  };\r\n\r\n  /**\r\n   * \r\n   */\r\n  describe(\"Deployment\", function () {\r\n    /**\r\n     * \r\n     */\r\n    it(\"Should deploy with initial 10,000 supply\", async function () {\r\n      // Setup\r\n      const { zkERC20 } = await loadFixture(deployZkERC20);\r\n\r\n      // Init + Test\r\n      expect(await zkERC20.totalSupply()).to.equal(ethers.utils.parseEther(`10000`).toString());\r\n    });\r\n  });\r\n\r\n  /**\r\n   * \r\n   */\r\n   describe(\"Minting\", function () {\r\n    /**\r\n     * \r\n     */\r\n    it(\"Should mint and increase the supply by 137\", async function () {\r\n      // Setup\r\n      const { zkERC20, owner } = await loadFixture(deployZkERC20);\r\n\r\n      // Init\r\n      await zkERC20.connect(owner).mint(owner.address, ethers.utils.parseUnits('137', 18));\r\n\r\n      // Init + Test\r\n      expect(await zkERC20.totalSupply()).to.equal(ethers.utils.parseEther(`10137`).toString());\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n让我们运行Hardhat节点并测试这个合约。\r\n\r\n**在终端1**\r\n\r\n运行一个本地节点：\r\n\r\n```bash\r\n# FROM: ./zkevm-erc20\r\n\r\n./node_modules/.bin/hardhat node;\r\n\r\n# Expected Output:\r\n# Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/\r\n# \r\n# Accounts\r\n# ========\r\n# \r\n# WARNING: These accounts, and their private keys, are publicly known.\r\n# Any funds sent to them on Mainnet or any other live network WILL BE LOST.\r\n# ...\r\n```\r\n\r\n在**终端2**\r\n\r\n运行测试：\r\n\r\n```bash\r\n# FROM: ./zkevm-erc20\r\n\r\n./node_modules/.bin/hardhat test;\r\n\r\n# Expected Output:\r\n#   zkERC20\r\n#     Deployment\r\n#       ✔ Should deploy with initial 10,000 supply (803ms)\r\n#     Minting\r\n#       ✔ Should mint and increase the supply by 137\r\n#\r\n#  2 passing (819ms)\r\n```\r\n\r\n### 部署ERC20合约\r\n\r\n需要注意的是，目前Hardhat中不支持zkEVM的部署。为了部署你的合约，你需要使用[以太坊 Remix](https://remix.ethereum.org/)的Injected Provider配置。\r\n\r\n确保在remix中创建一个`zkERC20.sol`文件，其中包含上面的合约代码：\r\n\r\n![remix](https://img.learnblockchain.cn/2023/02/02/1_BNtYIYBfyPu2MbQcGMmhuw.png)\r\n\r\n切换到编译部分，点击“编译按钮”，得到绿色的复选标记，表示一切编译正确。\r\n\r\n![remix编译合约](https://img.learnblockchain.cn/2023/02/02/1_FSJrySR3pZWRCAM7xklXsw.png)\r\n\r\n\r\n\r\n切换到左侧导航栏的部署部分，将**环境**设置为 \"Injected Provider - Metamask\"。并确保你的钱包被设置为zkEVM网络。\r\n\r\n![remix环境zkEVM](https://img.learnblockchain.cn/2023/02/02/1_5BIVJJx7T16TO-T_qln6aw.png)\r\n\r\n\r\n\r\n准备好后，点击部署按钮，在你的钱包中确认交易。\r\n\r\n![Remix部署合约](https://img.learnblockchain.cn/2023/02/02/1_lgH5bGpLr3x0AAUEjZL3Mw.png)\r\n\r\n\r\n\r\n### 在MetaMask中查看代币\r\n\r\n打开MetaMask钱包，点击交易，在区块浏览器上查看该交易。在区块浏览器中点击合约地址，打开合约。在区块浏览器中加载合约后，复制合约地址。\r\n\r\n![zkEVM合约的部署](https://img.learnblockchain.cn/2023/02/02/1_Uj8wEsBPYgcvhSh7H0Bdtw.png)\r\n\r\n\r\n\r\n打开你的MetaMask，点击**Asset（资产）**，并点击**Import tokens（导入代币）**：\r\n\r\n![MetaMask导入代币](https://img.learnblockchain.cn/2023/02/02/1_YvVNa0vjboR70zENqMsQXw.png!/scale/40)\r\n\r\n粘贴合约地址，并根据需要填写其他字段。它们可能会自动弹出，然后点击**添加自定义代币**：\r\n\r\n![MetaMask添加自定义代币](https://img.learnblockchain.cn/2023/02/02/1_5k0Q3EZtWjhgwvTFkvlMFg.png!/scale/40)\r\n\r\n\r\n\r\n现在你应该能够按照提示操作，然后在你的钱包里看到新的ZK20代币，并有正确的初始金额。\r\n\r\n![使用新的ZK20 ERC20代币的MetaMask](https://img.learnblockchain.cn/2023/02/02/1_Y3CBf4TUw5an0VrFErR9PQ.png)\r\n\r\n\r\n\r\n🎉 🎉，你已经完全部署了一个ERC20合约到Polygon Hermes zkEVM 测试网上。\r\n\r\n## 完整的代码\r\n\r\nzkEVM ERC20 代币的完整代码。请记住，目前还不支持Hardhat部署。\r\n\r\n[GitHub - codingwithmanny/zkevm-erc20](https://github.com/codingwithmanny/zkevm-erc20)\r\n\r\n\r\n\r\n如果其他 zkEVM 教程，我们会及时更新，欢迎在 Twitter 关注 [@登链社区](https://twitter.com/NUpchain) 。"},"author":{"user":"https://learnblockchain.cn/people/412","address":null},"history":"QmYT8u4QnzRJnRE9RE7rD1ZLooNoPHisuvsE4zG1zt1Ytk","timestamp":1679989385,"version":1}