L1->L2通信


L1->L2通信

本节描述了从L1与zkSync交互的界面。它假定你已经熟悉了与优先级队列工作的基本概念。如果你是这个话题的新手,你可以阅读概念性介绍这里。如果你想直接钻研代码,那么你可以阅读跨链治理教程

Note

请注意,在新的0.13.0SDK中,API层用气体操作。ergs的概念只被VM使用。

结构

对于最常见的用例,有一个交易的 "baseFee",这基本上意味着用户必须向运营商支付的最低金额,以便他包括这项交易。它是根据交易的 "l2gasLimit "和L1的天然气价格得出的。 此外,无论用户在上面支付什么费用,都被称为layer2 tip,并将用于按提供的L2费用对交易进行排序。

目前,所有L1->L2的交易都以先入先出的方式提供服务,但在未来,我们将引入 "优先堆",这将允许对交易进行排序。 交易。 基本费用是以气体为单位,而不是以ETH为单位,所以提交交易的实际费用取决于 交易气体价格。一般来说,调用任何这些方法的流程应该是这样的。

  1. 获取你将用于发送交易的气体价格。
  2. 获取交易的基本成本。
  3. 发送包括所需 "值 "的交易。

在你的项目中使用合约接口

要使用 Solidity 与 zkSync 邮箱合约互动,您需要使用 zkSync 合约接口。有两种主要方式来获得它。

  • 通过从 @matterlabs/zksync-contracts npm 包中导入它(首选)。
  • 通过从[repo]下载合约(https://github.com/matter-labs/v2-testnet-contracts)。

@matterlabs/zksync-contracts包可以通过运行以下命令来安装。

yarn add -D @matterlabs/zksync-contracts

在下面的例子中,我们假设通过@matterlabs/zksync-contracts npm包访问该接口。

获取基本成本

下面的视图函数返回用户需要提供的ETH数量,以支付交易的基本成本。

function l2TransactionBaseCost(
    uint256 _gasPrice,
    uint256 _gasLimit,
    uint256 _l2GasPerPubdataByteLimit
) external view returns (uint256);
  • _gasPrice是一个参数,包含交易的天然气价格。
  • _gasLimit是一个参数,包含交易调用的气体限额。你可以了解更多关于气体和zkSync收费系统的信息这里
  • _l2GasPerPubdataByteLimit是一个参数,包含每个发布的L1 calldata字节的二级气体价格。

接口

下面的函数返回规范的哈希值或请求的交易,可用于跟踪交易在L2中的执行情况。

function requestL2Transaction(
    address _contractL2,
    uint256 _l2Value,
    bytes calldata _calldata,
    uint256 _l2GasLimit,
    uint256 _l2GasPerPubdataByteLimit,
    bytes[] calldata _factoryDeps,
    address _refundRecipient
) external payable returns (bytes32 txHash);
  • _contractL2是一个参数,定义了要调用的合约地址。

  • _l2Value是一个参数,它定义了你想在调用L2时传递的ETH的数量。这个数字将被用作交易的`msg.value'。

  • _calldata是一个参数,包含交易调用的calldata。它的编码方式与Ethereum上的相同。

  • _l2GasLimit是一个参数,包含交易调用的气体限制。你可以了解更多关于气体和zkSync收费系统的信息[这里](.../transactions/fee-model.md)。

  • _l2GasPerPubdataByteLimit是一个参数,包含每个发布到L1 calldata字节的L2气体价格。

  • _factoryDeps是一个字节码的列表。它应该包含被部署的合同的字节码。如果被部署的合同是一个工厂合同,即它可以部署其他合同,该数组还应该包含可以被它部署的合同的字节码。

  • _refundRecipient是一个在交易执行后接收剩余费用的地址。(如果指定的地址为零,那么将使用L2 msg.sender)

随着方法的调用,应该提供一定数量的ETH来支付交易的基本费用(包括_l2Value)+第二层操作员的小费。

Tips

A successful L1 -> L2 message produces an L2Log with key = l2TxHash, and value = bytes32(1) whereas a failed L1 -> L2 message produces an L2Log with key = l2TxHash, and value = bytes32(0).

实例

Solidity

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

// Importing zkSync contract interface
import "@matterlabs/zksync-contracts/l1/contracts/zksync/interfaces/IZkSync.sol";

contract Example {
    function callZkSync(
        // The address of the zkSync smart contract.
        // It is not recommended to hardcode it during the alpha testnet as regenesis may happen.
        address _zkSyncAddress
    ) external payable returns(bytes32 txHash) {
        IZkSync zksync = IZkSync(_zkSyncAddress);
        address someL2Contract = 0xDbA0833e8c4b37cecC177a665E9207962e337299;
        // calling L2 smart contract from L1 Example contract
        txHash = zksync.requestL2Transaction{value: msg.value}(
            // The address of the L2 contract to call
            someL2Contract,
            // We pass no ETH with the call
            0,
            // Encoding the calldata for the execute
            abi.encodeWithSignature("someMethod()"),
            // Gas limit
            10000,
            // gas price per pubdata byte
            800,
            // factory dependencies
            new bytes[](0),
            // refund address
            address(0)
        );
    }
}

zksync-web3。

import { Wallet, Provider } from "zksync-web3";
import { ethers, BigNumber } from "ethers";

const TEST_PRIVATE_KEY = "";

const zkSyncProvider = new Provider("https://zksync2-testnet.zksync.dev");
const ethereumProvider = ethers.getDefaultProvider("goerli");
const wallet = new Wallet(TEST_PRIVATE_KEY, zkSyncProvider, ethereumProvider);

const gasPrice = await wallet.providerL1!.getGasPrice();

// The calldata can be encoded the same way as for Ethereum
const calldata = "0x...";
const gasLimit = BigNumber.from(1000);
const gasPerPubdataByte = BigNumber.from(800);

const txCostPrice = await wallet.getBaseCost({
  gasPrice,
  gasLimit,
  gasPerPubdataByte
});

console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`);

// initiating L2 transfer via L1 execute from zksync wallet
const someL2Contract = "0x19a5bfcbe15f98aa073b9f81b58466521479df8d";
const executeTx = await wallet.requestExecute({
  calldata,
  l2GasLimit: gasLimit,
  gasPerPubdataByte,
  contractAddress: someL2Contract,
  overrides: {
    gasPrice,
  },
});

await executeTx.wait();