L1->L2通信
L1->L2通信
本节描述了从L1与zkSync交互的界面。它假定你已经熟悉了与优先级队列工作的基本概念。如果你是这个话题的新手,你可以阅读概念性介绍这里。如果你想直接钻研代码,那么你可以阅读跨链治理教程。
Note
请注意,在新的0.13.0
SDK中,API层用气体操作。ergs的概念只被VM使用。
结构
对于最常见的用例,有一个交易的 "baseFee",这基本上意味着用户必须向运营商支付的最低金额,以便他包括这项交易。它是根据交易的 "l2gasLimit "和L1的天然气价格得出的。 此外,无论用户在上面支付什么费用,都被称为layer2 tip,并将用于按提供的L2费用对交易进行排序。
目前,所有L1->L2的交易都以先入先出的方式提供服务,但在未来,我们将引入 "优先堆",这将允许对交易进行排序。 交易。 基本费用是以气体为单位,而不是以ETH为单位,所以提交交易的实际费用取决于 交易气体价格。一般来说,调用任何这些方法的流程应该是这样的。
- 获取你将用于发送交易的气体价格。
- 获取交易的基本成本。
- 发送包括所需 "值 "的交易。
在你的项目中使用合约接口
要使用 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
是一个在交易执行后接收剩余费用的地址。(如果指定的地址为零,那么将使用L2msg.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();