账户:L1->L2交易


账户:L1->L2交易

本节探讨了允许account类从L1向L2发送交易的方法。

如果你想了解一些关于L1->L2交互在zkSync上如何工作的背景,请查阅introductionguide

支持的类

以下账户类别支持从L1向L2发送交易。

  • Wallet (如果连接到L1提供者)
  • L1Signer

批准代币的存款

从以太坊桥接ERC20代币需要批准代币到zkSync以太坊智能合约。

async approveERC20(
    token: Address,
    amount: BigNumberish,
    overrides?: ethers.Overrides & { bridgeAddress?: Address }
): Promise<ethers.providers.TransactionResponse>

输入和输出

名称说明
token代币的Ethereum地址。
amount待批准的代币金额。
overrides?以太坊交易覆盖物。可用于传递gasLimitgasPrice等。你也可以提供一个要使用的L1桥的自定义地址(默认使用Matter Labs团队提供的桥)。
returnethers.providers.TransactionResponse对象。

Example

import * as zksync from "zksync-web3";
import { ethers } from "ethers";

const PRIVATE_KEY = "0xc8acb475bb76a4b8ee36ea4d0e516a755a17fad2e84427d5559b37b544d9ba5a";

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

const USDC_ADDRESS = "0xd35cceead182dcee0f148ebac9447da2c4d449c4";
const txHandle = await wallet.approveERC20(
  USDC_ADDRESS,
  "10000000" // 10.0 USDC
);

await txHandle.wait();

向zkSync存入代币

async deposit(transaction: {
  token: Address;
  amount: BigNumberish;
  to?: Address;
  operatorTip?: BigNumberish;
  bridgeAddress?: Address;
  approveERC20?: boolean;
  overrides?: ethers.PayableOverrides;
  approveOverrides?: ethers.Overrides;
}): Promise<PriorityOpResponse>

输入和输出

名称说明
transaction.token要存入代币的地址。
transaction.amount要存入的代币的金额。
Transaction.to?将在L2上接收存入的代币的地址。
transaction.operatorTip?(目前不使用) 如果交易中传递的ETH值在重写中没有明确说明,这个字段将等于操作员在交易的基本费用之外将收到的小费。
transaction.bridgeAddress?要使用的桥接合同的地址。默认为默认的zkSync网桥(L1EthBridgeL1Erc20Bridge)。
transaction.approveERC20?是否应该在引擎盖下进行代币审批。如果你桥接了ERC20令牌,并且没有事先调用 "approveERC20 "函数,将此标志设置为 "true"。
transaction.overrides?以太坊交易覆盖物。可用于传递gasLimitgasPrice等。
transaction.approvedOverrides?以太坊交易的批准交易的重写。可用于传递gasLimit', gasPrice'等。
return返回 PriorityOpResponse对象。

Example

import * as zksync from "zksync-web3";
import { ethers } from "ethers";

const PRIVATE_KEY = "0xc8acb475bb76a4b8ee36ea4d0e516a755a17fad2e84427d5559b37b544d9ba5a";

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

const USDC_ADDRESS = "0xd35cceead182dcee0f148ebac9447da2c4d449c4";
const usdcDepositHandle = await wallet.deposit({
  token: USDC_ADDRESS,
  amount: "10000000",
  approveERC20: true,
});
// Note that we wait not only for the L1 transaction to complete but also for it to be
// processed by zkSync. If we want to wait only for the transaction to be processed on L1,
// we can use `await usdcDepositHandle.waitL1Commit()`
await usdcDepositHandle.wait();

const ethDepositHandle = await wallet.deposit({
  token: zksync.utils.ETH_ADDRESS,
  amount: "10000000",
});
// Note that we wait not only for the L1 transaction to complete but also for it to be
// processed by zkSync. If we want to wait only for the transaction to be processed on L1,
// we can use `await ethDepositHandle.waitL1Commit()`
await ethDepositHandle.wait();

向zkSync添加本地令牌

新的代币在第一次存入时就会自动添加。

最终确定提款

提款分两步执行--在L2启动,在L1完成。

async finalizeWithdrawal(withdrawalHash: BytesLike, index: number = 0): Promise<ethers.TransactionResponse>

Inputs and outputs

NameDescription
withdrawalHash启动提款的L2交易的哈希值。
index?如果一个交易中有多个提款,你可以传递一个你想最终确定的提款的索引(默认为0)。

在L2上强制执行交易

获取L2交易的基本成本

async getBaseCost(params: {
    gasLimit: BigNumberish;
    gasPerPubdataByte?: BigNumberish;
    gasPrice?: BigNumberish;
}): Promise<BigNumber>

Inputs and outputs

NameDescription
params.gasLimitThe gasLimit for the the L2 contract call.
params.gasPerPubdataByteThe L2 gas price for each published L1 calldata byte.
params.gasPrice?The L1 gas price of the L1 transaction that will send the request for an execute call
returnsThe base cost in ETH for requesting the L2 contract call.

申领失败的存款

claimFailedDeposit方法从发起的存款中提取资金,该存款在L2上最终确定时失败。 如果存款的L2交易失败,它将发送一个L1交易,调用L1桥的claimFailedDeposit方法,结果是将L1令牌返回给存款人,否则就会抛出错误。

async claimFailedDeposit(depositHash: BytesLike): Promise<ethers.ContractTransaction>

输入参数

参数类型描述
depositHashbytes32失败存款的二级交易哈希值。

Requesting transaction execution

async requestExecute(transaction: {
    contractAddress: Address;
    calldata: BytesLike;
    l2GasLimit: BigNumberish;
    l2Value?: BigNumberish;
    factoryDeps?: ethers.BytesLike[];
    operatorTip?: BigNumberish;
    gasPerPubdataByte?: BigNumberish;
    refundRecipient?: Address;
    overrides?: ethers.PayableOverrides;
}): Promise<PriorityOpResponse>

输入和输出

名称说明
transaction.contractAddress要调用的二级合同。
transaction.calldata二级交易的输入。
transaction.l2GasLimit交易在L2上执行时可消耗的最大L2气体量。
transaction.l2Value?L2事务的msg.value
transaction.factoryDeps?L2字节码的数组,这些字节码将被标记为L2上的已知代码。
transaction.operatorTip?(目前不使用) 如果交易中传递的ETH值在重写中没有明确说明,这个字段将等于操作员在交易的基本成本之外将收到的小费。
transaction.gasPerPubdataByte?每个公布的L1 calldata字节的二级气体价格。
transaction.refundRecipient?L2上将收到交易退款的地址。如果交易失败,它也将是接收l2Value的地址。
transaction.overrides以太坊交易覆盖。可用于传递gasLimitgasPricevalue等。
returns返回 PriorityOpResponse对象。

Example

import * as zksync from "zksync-web3";
import { BigNumber, ethers } from "ethers";

const PRIVATE_KEY = "0xc8acb475bb76a4b8ee36ea4d0e516a755a17fad2e84427d5559b37b544d9ba5a";

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

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

// The calldata can be encoded the same way as for Ethereum.
// Here is an example on how to get the calldata from an ABI:
const abi = [
  {
    inputs: [],
    name: "increment",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
];
const contractInterface = new ethers.utils.Interface(abi);
const calldata = contractInterface.encodeFunctionData("increment", []);
const l2GasLimit = BigNumber.from(1000);

const txCostPrice = await wallet.getBaseCost({
  gasPrice,
  calldataLength: ethers.utils.arrayify(calldata).length,
  l2GasLimit,
});

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

const executeTx = await wallet.requestExecute({
  contractAddress: "0x19a5bfcbe15f98aa073b9f81b58466521479df8d",
  calldata,
  l2Value: 1,
  l2GasLimit,
  overrides: {
    gasPrice,
    value: txCostPrice,
  },
});

await executeTx.wait();
Last update:
Contributors: Blessing Krofegha,Stanislav Bezkorovainyi,Newbee740,Antonio,AnastasiiaVashchuk,botdad,Roman Brodetski,barakshani