# zkSync Era、Linea、Scroll合约部署避坑实录

By [zero](https://paragraph.com/@zero-13) · 2023-08-09

---

![](https://storage.googleapis.com/papyrus_images/b31b4db4e5ceeeadce5a3ef05af5d6ebc25a758415b782513945e7b396f25672.jpg)

最近搞了个小项目，在各种L2链上进行部署，部署的过程中发现了各种坑，因此记录下来，也许可以帮助到一些有心人。

**一、zkSync Era**
----------------

zksync era部署合约和其他Evm网络不同，不能直接使用remix进行部署，官方出的解决方案是使用hardhat插件，但是，坑实在是太多了，为什么不提供Docker呢？这样是真的可以一劳永逸，node，npm的兼容性也是一言难尽，花了太多的时间。

很遗憾，本文也没有提供有效的Docker，因为我本地搭建好了，也许以后会有更新，望见谅。但是本文会比官网的doc更为细致，适合初学者使用。

### **本地环境：**

1.  `系统：Centos7，内核5.4`
    
2.  `使用yarn编译，yum update, yum install yarn即可`
    
3.  `node版本：v16.18.1`
    
4.  `npm版本：8.19.2`
    

### **执行依赖安装：**

    创建项目文件夹，并进入后执行下面的命令
    mkdir TestToken
    cd TestToken
    yarn add -D cpu-features typescript ts-node hardhat ethers@~5.7.2 zksync-web3@^0.14.3 @matterlabs/hardhat-zksync-solc @matterlabs/hardhat-zksync-deploy 
    
    注意：这里多了个cpu-features，如果不先安装cpu-features，会报gpy安装失败
    

### **下载编译工具**

    从下面网址选择最新的最适合你cpu的编译工具，并把它保存在计算机的某个文件夹里，下面hardhat.config.js里面会用上，例如我下载的是：zksolc-linux-amd64-musl-v1.3.13，并放在/root/env/文件夹下面
    https://github.com/matter-labs/zksolc-bin
    
    给zksolc添加可执行权限：
    chmod a+x zksolc-linux-amd64-musl-v1.3.13
    

### **创建空项目**

    npm init --yes
    

会在当前目录下面生成contracts文件夹，hardhat.config.js等文件

### **编辑hardhat.config.js文件**

    /** @type import('hardhat/config').HardhatUserConfig */
    import "@matterlabs/hardhat-zksync-deploy";
    import "@matterlabs/hardhat-zksync-solc";
    import "@matterlabs/hardhat-zksync-verify";
    
    module.exports = {
        zksolc: {
            version: "latest", // 默认即可，也可以填1.3.13，就是zksolc的版本
            compilerSource: "binary", // 默认即可
            settings: {
                compilerPath: "/root/env/zksolc-linux-amd64-musl-v1.3.13",  // 这里一定放之前下载的zksolc-linux-amd64-musl-v1.3.13路径
                libraries:{}, // 我没有使用任何library，如果有的话可能需要填，具体怎么填我也不知道
                isSystem: false, // optional.  Enables Yul instructions available only for zkSync system contracts and libraries
                forceEvmla: false, // optional. Falls back to EVM legacy assembly if there is a bug with Yul
                optimizer: { // 是否使用编译优化，一般都要使用的，因为这可以降低部署的gas
                    enabled: true, // optional. True by default
                    mode: '3' // optional. 3 by default, z to optimize bytecode size
                }
            },
        },
        defaultNetwork: "zkSyncTestnet", // 如果部署测试网，那么就填zkSyncTestnet，如果是主网，那么填zkSync，与下面networks中内容一一对应
    
        networks: {
            mainnet: {
                url: "https://mainnet.infura.io/v3/一串16进制字符", // 主网rpc节点，请填入自己在infura申请的goerli节点
                zksync: false, // 默认是false
            },
            goerli: {
                url: "https://goerli.infura.io/v3/一串16进制字符", // Goerli网rpc节点，请填入自己在infura申请的goerli节点
                zksync: false, // 默认是false
            },
            zkSyncTestnet: {
                url: "https://zksync2-testnet.zksync.dev", // zkSync测试网的节点
                ethNetwork: "goerli", // zkSync是L2需要有对应的L1，测试网对应goerli
                zksync: true, // 默认是true
                verifyURL: "https://zksync2-testnet-explorer.zksync.dev/contract_verification", // 这个是合约开源的验证URL
            },
            zkSync: {
                url: "https://mainnet.era.zksync.io", // zkSync正式网的节点
                ethNetwork: "mainnet", // zkSync是L2需要有对应的L1，era正式网对应mainnet
                zksync: true,  // 默认是true
                verifyURL: "https://zksync2-mainnet-explorer.zksync.io/contract_verification", // 这个是合约开源的验证URL
            }
        },
        solidity: {
            version: "0.8.20", // 合约编译的solidity版本号，这个一定要与sol合约文件的版本号一致
        },
    };
    

### **编辑合约文件**

合约文件比较简单，直接将你的合约文件全部丢到contracts文件夹中即可，注意合约文件的文件名，最好与你要部署的合约的class名保持一致，后面写Deploy文件时会比较简单直观一些

### **编辑Deploy文件**

    在项目根目录创建deploy文件夹：
    mkdir deploy
    cd deploy
    vi deploy.ts
    

deploy.ts文件内容解说

    import { Wallet, utils } from "zksync-web3";
    import * as ethers from "ethers";
    import { HardhatRuntimeEnvironment } from "hardhat/types";
    import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
    
    export default async function (hre: HardhatRuntimeEnvironment) {
      console.log(`Running deploy script for the Test contract`);
    
      // 初始化钱包 填入私钥
      const wallet = new Wallet("这里填私钥，不要带0x，有人说助记词怎么办？自行google吧，我也没用过");
    
      // 创建deployer
      const deployer = new Deployer(hre, wallet);
      // 设置部署的合约名，TestToken是我的sol文件名也是我要部署的合约名（class name）
      const artifactTestToken = await deployer.loadArtifact("TestToken");
    
      // 计算gas fee
      // 参数为合约中construct的参数, 这个就看具体合约怎么写的了
      // uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol
      const initialAmount = 10000000000000000; // 1亿币，8位有效数字
      const tokenName = "TestToken";
      const tokenDecimal = 8;
      const tokenSymbol = "TT";
      const deploymentFee = await deployer.estimateDeployFee(artifactTestToken, [initialAmount,tokenName,tokenDecimal,tokenSymbol]);
    
      // 部署合约之前，先查看eth需要消耗多少
      const parsedFee = ethers.utils.formatEther(deploymentFee.toString());
      console.log(`The deployment is estimated to cost ${parsedFee} ETH`);
    
      // 同步执行合约部署
      const testTokenContract = await deployer.deploy(artifactTestToken, [initialAmount,tokenName,tokenDecimal,tokenSymbol]);
    
      console.log("constructor args:" + testTokenContract.interface.encodeDeploy([initialAmount,tokenName,tokenDecimal,tokenSymbol]));
    
      // 获得合约部署后的合约地址，有些多个合约，可能会用到前面合约的地址，那么这里就可以拿到地址，下面可以继续部署其他合约
      const contractAddress = testTokenContract.address;
      console.log(`${artifactTestToken.contractName} was deployed to ${contractAddress}`);
    }
    

### **执行编译，部署**

    编译：yarn hardhat compile
    部署：yarn hardhat deploy-zksync
    

### **开源**

开源稍微有点复杂，而且zkSync的开源连一个注释都不能错，即之前用什么sol文件编译部署的，那么开源也必须是那个sol文件，注释都不能改。 开源需要三个数据： 1. 部署后的合约地址, 很好获取 2. 部署的合约文件地址与合约名, 很好获取 3. 合约部署时提供的参数, 稍微有点复杂

    合约部署时提供的参数说明
    先在根目录创建文件夹args
    mkdir args
    创建参数文件，参数需要放在文件中
    vi args/TestToken.js
    

args/TestToken.js文件说明

    module.exports = [
      10000000000000000, // 第一个参数
      "TestToken", // 第二个参数
      8, // 第三个参数
      "TT", // 第四个参数
    ];
    

执行开源：

    yarn hardhat verify --network zkSync 合约地址 --contract contracts/TestToken.sol:TestToken --constructor-args args/TestToken.js
    

### **zkSync总结**

zkSync的合约编译与hardhat的正常使用大差不差，主要区别在于那个zksolc的下载，官网文档也没有写清楚，各种查资料才发现，自己下载编译好的zksolc然后设置路径是最方便的。

**二、其他L2网络，Linea、Scroll与Taiko**
-------------------------------

### **表彰大会**

这四个L2里面最赞的是Taiko，因为Taiko无缝对接了Remix，合约可以直接在Remix上不做任何修改与主网一样的方式进行部署。太赞了。

### **Linea与Scroll**

这两个L2虽然也可以在Remix部署，但是需要做一点修改。

Linea与Scroll在Remix编译时，Evm Version均不能使用最新版本，必须改成paris，即shanghai升级的部分不支持。

**三、值得一提的事情**
-------------

我特意去本地部署了一下Linea的编译环境，Linea官网提供的所有部署方式我都试过了，最后用Docker+truffle的方式编译成功，而且耗时8小时，我就不明白了，搞个docker会死吗。项目方肯定是多条链部署，不同的链都有不同的依赖包，各种相互依赖，Docker才是正解。

有需要Linera Truffle编译Docker的可以留言，我可以考虑开放出来。

---

*Originally published on [zero](https://paragraph.com/@zero-13/zksync-era-linea-scroll)*
