Cover photo

Zksync Era: 如何部署智能合约

昨天 Zksync 上线了 Era 主网,在测试的时候想部署合约试试,结果发现直接使用 Remix 无法部署合约

查阅了文档才发现 Zksync Era 和 EVM 部署合约的流程不一样,甚至有自己的一套 sol 编译方法

https://era.zksync.io/docs/

先试了用 python 来部署发现不太行,python-sdk 和节点的 RPC 似乎还没有对齐,所以在使用的时候会报错。最后是用 Hardhat 部署上去了,踩坑一晚上,社区也还没有相关的提问所以分享一下。

环境准备

hardhat 需要在 yarn 中配置,需要预先配置 yarn 环境

https://yarnpkg.com/getting-started/install

然后创建一个目录作为工作目录,并且使用 yarn 配置好 zksync 的 hardhat环境

mkdir example
cd example
yarn init -y
yarn add -D typescript ts-node @types/node ethers@^5.7.2 zksync-web3 @ethersproject/hash @ethersproject/web hardhat @matterlabs/hardhat-zksync-solc @matterlabs/hardhat-zksync-deploy

最后输入 yarn命令初始化一下环境

在这个工作目录下创建 hardhat.config.ts 文件

import "@matterlabs/hardhat-zksync-deploy";
import "@matterlabs/hardhat-zksync-solc";

module.exports = {
  zksolc: {
    version: "1.3.5",
    compilerSource: "binary",
    settings: {},
  },
  defaultNetwork: "zkTestnet",
  networks: {
    zkTestnet: {
      url: "https://zksync2-testnet.zksync.dev", // URL of the zkSync network RPC
      ethNetwork: "goerli", // Can also be the RPC URL of the Ethereum network (e.g. `https://goerli.infura.io/v3/<API_KEY>`)
      zksync: true,
    },
  },
  solidity: {
    version: "0.8.17",
  },
};

国内环境下还需要在zksolc-setting中添加一个配置项,这个路径指向 zksync 的 zksolc 编译器。(也可以考虑设置代理,但是我这边代理一直下不了。)

    settings: {
      "compilerPath": "pathToCompile"
    },

同时,从下面的 github 中选取并下载 zksolc 编译器到对应的路径下

https://github.com/matter-labs/zksolc-bin

如果在主网部署,在 networks 中添加zkMainnet

    zkMainnet: {
      url: "https://zksync2-mainnet.zksync.io",
      ethNetwork: "mainnet",
      zksync: true
    }

至此,部署合约的环境准备就绪,如果需要切换到主网,可以在配置文件中修改defaultNetwork字段

合约部署

在工作目录下创建 contracts 文件夹,然后将写好的合约放入,因为是 zkEVM,所以合约同样是 solidity 语言,不同的只是合约部署的过程不一样

官方文档中的示例合约:

//SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.0;

contract Greeter {
    string private greeting;

    constructor(string memory _greeting) {
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        greeting = _greeting;
    }
}

然后在命令行中输入

 yarn hardhat compile

在编译完成后会在工作目录下生成两个目录:artifacts-zk 和 cache-zk

然后创建 deploy 文件夹,在这个文件夹下创建 deploy.ts文件,写入下面的内容,请根据自己合约的需求进行修改

注意:需要部署的合约的文件名务必和合约名一致

import { utils, Wallet } from "zksync-web3";
import * as ethers from "ethers";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";

// An example of a deploy script that will deploy and call a simple contract.
export default async function (hre: HardhatRuntimeEnvironment) {
  console.log(`Running deploy script for the Greeter contract`);

  // 初始化钱包,这里替换为字符串形式的私钥
  const wallet = new Wallet("<WALLET-PRIVATE-KEY>");

  // 创建 deployer 对象,并且从abi中初始化合约对象 artifact
  const deployer = new Deployer(hre, wallet);
  // 这里是官方示例中的名为 Greeter 合约,需要根据具体的合约名字修改
  // 注意,合约名字务必和合约文件名一样
  const artifact = await deployer.loadArtifact("Greeter");

  // 从水龙头请求一些 eth 用来进行部署,如果钱包中有代币,可以直接注释掉这一段代码
  const depositAmount = ethers.utils.parseEther("0.001");
  const depositHandle = await deployer.zkWallet.deposit({
    to: deployer.zkWallet.address,
    token: utils.ETH_ADDRESS,
    amount: depositAmount,
  });
  // 等待水龙头发送测试币?
  await depositHandle.wait();

  // 部署合约,这里的 greeting 是示例合约的构造参数,请根据需要进行修改
  const greeting = "Hi there!";
  const greeterContract = await deployer.deploy(artifact, [greeting]);

  // 输出合约的相关信息
  const contractAddress = greeterContract.address;
  console.log(`${artifact.contractName} was deployed to ${contractAddress}`);

  // 调用已经部署的合约
  const greetingFromContract = await greeterContract.greet();
  if (greetingFromContract == greeting) {
    console.log(`Contract greets us with ${greeting}!`);
  } else {
    console.error(`Contract said something unexpected: ${greetingFromContract}`);
  }

  // Edit the greeting of the contract
  const newGreeting = "Hey guys";
  const setNewGreetingHandle = await greeterContract.setGreeting(newGreeting);
  await setNewGreetingHandle.wait();

  const newGreetingFromContract = await greeterContract.greet();
  if (newGreetingFromContract == newGreeting) {
    console.log(`Contract greets us with ${newGreeting}!`);
  } else {
    console.error(`Contract said something unexpected: ${newGreetingFromContract}`);
  }
}

Zksync 官方的演示文档:

https://era.zksync.io/docs/api/hardhat/getting-started.html#write-and-deploy-a-contract