UNPKG

zksync-ethers

Version:

A Web3 library for interacting with the ZkSync Layer 2 scaling solution.

1,642 lines (1,589 loc) 60 kB
import { BigNumberish, BlockTag, BytesLike, ContractTransactionResponse, ethers, Overrides, copyRequest, } from 'ethers'; import {Provider} from './provider'; import { DEFAULT_GAS_PER_PUBDATA_LIMIT, EIP712_TX_TYPE, hashBytecode, isAddressEq, serializeEip712, } from './utils'; import { Address, BalancesMap, FinalizeWithdrawalParams, FullDepositFee, PaymasterParams, PriorityOpResponse, Signature, TransactionLike, TransactionRequest, TransactionResponse, } from './types'; import {AdapterL1, AdapterL2} from './adapters'; import { IBridgehub, IL1ERC20Bridge, IL1SharedBridge, IL2Bridge, IL2SharedBridge, IZkSyncHyperchain, } from './typechain'; /** * All typed data conforming to the EIP712 standard within ZKsync Era. */ export const EIP712_TYPES = { Transaction: [ {name: 'txType', type: 'uint256'}, {name: 'from', type: 'uint256'}, {name: 'to', type: 'uint256'}, {name: 'gasLimit', type: 'uint256'}, {name: 'gasPerPubdataByteLimit', type: 'uint256'}, {name: 'maxFeePerGas', type: 'uint256'}, {name: 'maxPriorityFeePerGas', type: 'uint256'}, {name: 'paymaster', type: 'uint256'}, {name: 'nonce', type: 'uint256'}, {name: 'value', type: 'uint256'}, {name: 'data', type: 'bytes'}, {name: 'factoryDeps', type: 'bytes32[]'}, {name: 'paymasterInput', type: 'bytes'}, ], }; /** * A `EIP712Signer` provides support for signing EIP712-typed ZKsync Era transactions. */ export class EIP712Signer { private eip712Domain: Promise<ethers.TypedDataDomain>; /** * @example * * import { Provider, types, EIP712Signer } from "zksync-ethers"; * import { ethers } from "ethers"; * * const PRIVATE_KEY = "<PRIVATE_KEY>"; * * const provider = Provider.getDefaultProvider(types.Network.Sepolia); * const signer = new EIP712Signer(new ethers.Wallet(PRIVATE_KEY), Number((await provider.getNetwork()).chainId)); */ constructor( private ethSigner: ethers.Signer, chainId: number | Promise<number> ) { this.eip712Domain = Promise.resolve(chainId).then(chainId => ({ name: 'zkSync', version: '2', chainId, })); } /** * Generates the EIP712 typed data from provided transaction. Optional fields are populated by zero values. * * @param transaction The transaction request that needs to be populated. * * @example * * import { EIP712Signer } from "zksync-ethers"; * * const tx = EIP712Signer.getSignInput({ * type: utils.EIP712_TX_TYPE, * to: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", * value: 7_000_000n, * from: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", * nonce: 0n, * chainId: 270n, * gasPrice: 250_000_000n, * gasLimit: 21_000n, * customData: {}, * }); */ static getSignInput(transaction: TransactionRequest) { const maxFeePerGas = transaction.maxFeePerGas || transaction.gasPrice || 0n; const maxPriorityFeePerGas = transaction.maxPriorityFeePerGas || maxFeePerGas; const gasPerPubdataByteLimit = transaction.customData?.gasPerPubdata || DEFAULT_GAS_PER_PUBDATA_LIMIT; return { txType: transaction.type || EIP712_TX_TYPE, from: transaction.from, to: transaction.to, gasLimit: transaction.gasLimit || 0n, gasPerPubdataByteLimit: gasPerPubdataByteLimit, maxFeePerGas, maxPriorityFeePerGas, paymaster: transaction.customData?.paymasterParams?.paymaster || ethers.ZeroAddress, nonce: transaction.nonce || 0, value: transaction.value || 0n, data: transaction.data || '0x', factoryDeps: transaction.customData?.factoryDeps?.map((dep: any) => hashBytecode(dep) ) || [], paymasterInput: transaction.customData?.paymasterParams?.paymasterInput || '0x', }; } /** * Signs a transaction request using EIP712. * * @param transaction The transaction request that needs to be signed. * @returns A promise that resolves to the signature of the transaction. * * @example * * import { Provider, types, EIP712Signer } from "zksync-ethers"; * import { ethers } from "ethers"; * * const PRIVATE_KEY = "<PRIVATE_KEY>"; * * const provider = Provider.getDefaultProvider(types.Network.Sepolia); * const signer = new EIP712Signer(new ethers.Wallet(PRIVATE_KEY, Number(await provider.getNetwork())); * const signature = signer.sign({ * type: utils.EIP712_TX_TYPE, * to: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", * value: 7_000_000n, * nonce: 0n, * chainId: 270n, * gasPrice: 250_000_000n, * gasLimit: 21_000n, * }) */ async sign(transaction: TransactionRequest): Promise<Signature> { return await this.ethSigner.signTypedData( await this.eip712Domain, EIP712_TYPES, EIP712Signer.getSignInput(transaction) ); } /** * Hashes the transaction request using EIP712. * * @param transaction The transaction request that needs to be hashed. * @returns A hash (digest) of the transaction request. * * @throws {Error} If `transaction.chainId` is not set. * * @example * * import { EIP712Signer } from "zksync-ethers"; * * const hash = EIP712Signer.getSignedDigest({ * type: utils.EIP712_TX_TYPE, * to: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", * value: 7_000_000n, * from: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", * nonce: 0n, * chainId: 270n, * gasPrice: 250_000_000n, * gasLimit: 21_000n, * customData: {}, * }); */ static getSignedDigest(transaction: TransactionRequest): ethers.BytesLike { if (!transaction.chainId) { throw Error("Transaction chainId isn't set!"); } const domain = { name: 'zkSync', version: '2', chainId: transaction.chainId, }; return ethers.TypedDataEncoder.hash( domain, EIP712_TYPES, EIP712Signer.getSignInput(transaction) ); } /** * Returns ZKsync Era EIP712 domain. * * @example * * import { Provider, types, EIP712Signer } from "zksync-ethers"; * import { ethers } from "ethers"; * * const PRIVATE_KEY = "<PRIVATE_KEY>"; * * const provider = Provider.getDefaultProvider(types.Network.Sepolia); * const signer = new EIP712Signer(new ethers.Wallet(PRIVATE_KEY, Number(await provider.getNetwork())); * const domain = await signer.getDomain(); */ async getDomain(): Promise<ethers.TypedDataDomain> { return await this.eip712Domain; } } /* c8 ignore start */ /** * A `Signer` is designed for frontend use with browser wallet injection (e.g., MetaMask), * providing only L2 operations. * * @see {@link L1Signer} for L1 operations. */ export class Signer extends AdapterL2(ethers.JsonRpcSigner) { public override provider!: Provider; public eip712!: EIP712Signer; protected providerL2?: Provider; override _signerL2() { return this; } override _providerL2() { // Make it compatible when singer is created with BrowserProvider.getSigner() return this.providerL2 ? this.providerL2 : this.provider; } /** * @inheritDoc * * @example Get ETH balance. * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * console.log(`ETH balance: ${await signer.getBalance()}`); * * @example Get token balance. * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const token = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1"; * * console.log(`Token balance: ${await signer.getBalance(token)}`); */ override async getBalance( token?: Address, blockTag: BlockTag = 'committed' ): Promise<bigint> { return super.getBalance(token, blockTag); } /** * @inheritDoc * * @example * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const allBalances = await signer.getAllBalances(); */ override async getAllBalances(): Promise<BalancesMap> { return super.getAllBalances(); } /** * @inheritDoc * * @example * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * console.log(`Nonce: ${await signer.getDeploymentNonce()}`); */ override async getDeploymentNonce(): Promise<bigint> { return super.getDeploymentNonce(); } /** * @inheritDoc * * @example * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const l2BridgeContracts = await signer.getL2BridgeContracts(); */ override async getL2BridgeContracts(): Promise<{ erc20: IL2Bridge; weth: IL2Bridge; shared: IL2SharedBridge; }> { return super.getL2BridgeContracts(); } /** * @inheritDoc * * @example Withdraw token. * * import { BrowserProvider, Provider, types, utils } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1"; * const withdrawTx = await signer.withdraw({ * token: utils.ETH_ADDRESS, * amount: 10_000_000n, * }); * * @example Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token. * * import { BrowserProvider, Provider, types, utils } from "zksync-ethers"; * * const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free * const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const withdrawTx = await signer.withdraw({ * token: utils.ETH_ADDRESS, * amount: 10_000_000n, * paymasterParams: utils.getPaymasterParams(paymaster, { * type: "ApprovalBased", * token: token, * minimalAllowance: 1, * innerInput: new Uint8Array(), * }), * }); * * @example Withdraw token. * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1"; * const withdrawTx = await signer.withdraw({ * token: tokenL2, * amount: 10_000_000n, * }); * * @example Withdraw token using paymaster to facilitate fee payment with an ERC20 token. * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * * const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free * const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1"; * const withdrawTx = await signer.withdraw({ * token: tokenL2, * amount: 10_000_000n, * paymasterParams: utils.getPaymasterParams(paymaster, { * type: "ApprovalBased", * token: token, * minimalAllowance: 1, * innerInput: new Uint8Array(), * }), * }); */ override async withdraw(transaction: { token: Address; amount: BigNumberish; to?: Address; bridgeAddress?: Address; paymasterParams?: PaymasterParams; overrides?: Overrides; }): Promise<TransactionResponse> { return super.withdraw(transaction); } /** * @inheritDoc * * @example Transfer ETH. * * import { BrowserProvider, Provider, Wallet, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const transferTx = await signer.transfer({ * to: Wallet.createRandom().address, * amount: ethers.parseEther("0.01"), * }); * * const receipt = await transferTx.wait(); * * console.log(`The sum of ${receipt.value} ETH was transferred to ${receipt.to}`); * * @example Transfer ETH using paymaster to facilitate fee payment with an ERC20 token. * * import { BrowserProvider, Provider, Wallet, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free * const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = await Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const transferTx = signer.transfer({ * to: Wallet.createRandom().address, * amount: ethers.parseEther("0.01"), * paymasterParams: utils.getPaymasterParams(paymaster, { * type: "ApprovalBased", * token: token, * minimalAllowance: 1, * innerInput: new Uint8Array(), * }), * }); * * const receipt = await transferTx.wait(); * * console.log(`The sum of ${receipt.value} ETH was transferred to ${receipt.to}`); * * @example Transfer token. * * import { BrowserProvider, Provider, Wallet, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1"; * const transferTx = await signer.transfer({ * token: tokenL2, * to: Wallet.createRandom().address, * amount: ethers.parseEther("0.01"), * }); * * const receipt = await transferTx.wait(); * * console.log(`The sum of ${receipt.value} token was transferred to ${receipt.to}`); * * @example Transfer token using paymaster to facilitate fee payment with an ERC20 token. * * import { BrowserProvider, Provider, Wallet, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free * const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = await Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1"; * const transferTx = signer.transfer({ * token: tokenL2, * to: Wallet.createRandom().address, * amount: ethers.parseEther("0.01"), * paymasterParams: utils.getPaymasterParams(paymaster, { * type: "ApprovalBased", * token: token, * minimalAllowance: 1, * innerInput: new Uint8Array(), * }), * }); * * const receipt = await transferTx.wait(); * * console.log(`The sum of ${receipt.value} token was transferred to ${receipt.to}`); */ override async transfer(transaction: { to: Address; amount: BigNumberish; token?: Address; paymasterParams?: PaymasterParams; overrides?: Overrides; }): Promise<TransactionResponse> { return super.transfer(transaction); } /** * Creates a new Singer with provided `signer` and `chainId`. * * @param signer The signer from browser wallet. * @param chainId The chain ID of the network. * @param [zksyncProvider] The provider instance for connecting to a L2 network. If not provided, * the methods from the `zks` namespace are not supported, and interaction with them will result in an error. * * @example * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); */ static from( signer: ethers.JsonRpcSigner & {provider: Provider}, chainId: number, zksyncProvider?: Provider ): Signer { const newSigner: Signer = Object.setPrototypeOf(signer, Signer.prototype); newSigner.eip712 = new EIP712Signer(newSigner, chainId); newSigner.providerL2 = zksyncProvider; return newSigner; } /** * Get the number of transactions ever sent for account, which is used as the `nonce` when sending a transaction. * * @param [blockTag] The block tag to query. If provided, the transaction count is as of that block. * * import { BrowserProvider, Provider, types } from "zksync-ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const nonce = await signer.getNonce(); */ override async getNonce(blockTag?: BlockTag): Promise<number> { return super.getNonce(blockTag); } /** * Broadcast the transaction to the network. * * @param transaction The transaction request that needs to be broadcast to the network. * * @throws {Error} If `transaction.from` is mismatched from the private key. * * @example * * import { BrowserProvider, Provider, Wallet, types } from "zksync-ethers"; * * const browserProvider = new BrowserProvider(window.ethereum); * const signer = Signer.from( * await browserProvider.getSigner(), * Number((await browserProvider.getNetwork()).chainId), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * signer.sendTransaction({ * to: Wallet.createRandom().address, * value: 10_000_000n * }); */ override async sendTransaction( transaction: TransactionRequest ): Promise<TransactionResponse> { if (!transaction.type) { transaction.type = EIP712_TX_TYPE; } const address = await this.getAddress(); transaction.from ??= address; const tx = await this.populateFeeData(transaction); if (!isAddressEq(await ethers.resolveAddress(tx.from!), address)) { throw new Error('Transaction `from` address mismatch!'); } if ( tx.type === null || tx.type === undefined || tx.type === EIP712_TX_TYPE || tx.customData ) { const zkTx: TransactionLike = { type: tx.type ?? EIP712_TX_TYPE, value: tx.value ?? 0, data: tx.data ?? '0x', nonce: tx.nonce ?? (await this.getNonce('pending')), maxFeePerGas: tx.gasPrice ?? tx.maxFeePerGas, maxPriorityFeePerGas: tx.maxPriorityFeePerGas, gasLimit: tx.gasLimit, chainId: tx.chainId ?? (await this.provider.getNetwork()).chainId, to: await ethers.resolveAddress(tx.to!), customData: this._fillCustomData(tx.customData ?? {}), from: address, }; zkTx.customData ??= {}; zkTx.customData.customSignature = await this.eip712.sign(zkTx); const txBytes = serializeEip712(zkTx); return await this.provider.broadcastTransaction(txBytes); } return (await super.sendTransaction(tx)) as TransactionResponse; } protected async populateFeeData( transaction: TransactionRequest ): Promise<ethers.PreparedTransactionRequest> { const tx = copyRequest(transaction); if (tx.gasPrice && (tx.maxFeePerGas || tx.maxPriorityFeePerGas)) { throw new Error( 'Provide combination of maxFeePerGas and maxPriorityFeePerGas or provide gasPrice. Not both!' ); } if (!this.providerL2) { throw new Error('Initialize provider L2'); } if ( !tx.gasLimit || (!tx.gasPrice && (!tx.maxFeePerGas || tx.maxPriorityFeePerGas === null || tx.maxPriorityFeePerGas === undefined)) ) { const fee = await this.providerL2!.estimateFee(tx); tx.gasLimit ??= fee.gasLimit; if (!tx.gasPrice && tx.type === 0) { tx.gasPrice = fee.maxFeePerGas; } else if (!tx.gasPrice && tx.type !== 0) { tx.maxFeePerGas ??= fee.maxFeePerGas; tx.maxPriorityFeePerGas ??= fee.maxPriorityFeePerGas; } if ( tx.type === null || tx.type === undefined || tx.type === EIP712_TX_TYPE || tx.customData ) { tx.customData ??= {}; tx.customData.gasPerPubdata = fee.gasPerPubdataLimit; } } return tx; } } /** * A `L1Signer` is designed for frontend use with browser wallet injection (e.g., MetaMask), * providing only L1 operations. * * @see {@link Signer} for L2 operations. */ export class L1Signer extends AdapterL1(ethers.JsonRpcSigner) { public providerL2!: Provider; override _providerL2() { return this.providerL2; } override _providerL1() { return this.provider; } override _signerL1() { return this; } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const mainContract = await signer.getMainContract(); */ override async getMainContract(): Promise<IZkSyncHyperchain> { return super.getMainContract(); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const bridgehub = await signer.getBridgehubContract(); */ override async getBridgehubContract(): Promise<IBridgehub> { return super.getBridgehubContract(); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const l1BridgeContracts = await signer.getL1BridgeContracts(); */ override async getL1BridgeContracts(): Promise<{ erc20: IL1ERC20Bridge; weth: IL1ERC20Bridge; shared: IL1SharedBridge; }> { return super.getL1BridgeContracts(); } /** * @inheritDoc * * @example Get ETH balance. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * console.log(await signer.getBalanceL1()); * * @example Get token balance. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be"; * * console.log(await signer.getBalanceL1(tokenL1)); */ override async getBalanceL1( token?: Address, blockTag?: BlockTag ): Promise<bigint> { return super.getBalanceL1(token, blockTag); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B"; * console.log(`Token allowance: ${await signer.getAllowanceL1(tokenL1)}`); */ override async getAllowanceL1( token: Address, bridgeAddress?: Address, blockTag?: BlockTag ): Promise<bigint> { return super.getAllowanceL1(token, bridgeAddress, blockTag); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B"; * * console.log(`Token L2 address: ${await signer.l2TokenAddress(tokenL1)}`); */ override async l2TokenAddress(token: Address): Promise<string> { return super.l2TokenAddress(token); } /** * @inheritDoc * * @example * * import { Wallet, Provider, types, utils } from "zksync-ethers"; * import { ethers } from "ethers"; * * const PRIVATE_KEY = "<WALLET_PRIVATE_KEY>"; * * const provider = Provider.getDefaultProvider(types.Network.Sepolia); * const ethProvider = ethers.getDefaultProvider("sepolia"); * const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); * * const tokenL2 = "0xe1134444211593Cfda9fc9eCc7B43208615556E2"; * * console.log(`Token L1 address: ${await wallet.l1TokenAddress(tokenL1)}`); */ override async l1TokenAddress(token: Address): Promise<string> { return super.l1TokenAddress(token); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B"; * await signer.approveERC20(tokenL1, 5); */ override async approveERC20( token: Address, amount: BigNumberish, overrides?: Overrides & { bridgeAddress?: Address; } ): Promise<ethers.TransactionResponse> { return super.approveERC20(token, amount, overrides); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * console.log(`Base cost: ${await signer.getBaseCost({ gasLimit: 100_000 })}`); */ override async getBaseCost(params: { gasLimit: BigNumberish; gasPerPubdataByte?: BigNumberish; gasPrice?: BigNumberish; }): Promise<bigint> { return super.getBaseCost(params); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * console.log(`Base token: ${await signer.getBaseToken()}`); */ override async getBaseToken(): Promise<string> { return super.getBaseToken(); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * console.log(`Is ETH-based chain: ${await signer.isETHBasedChain()}`); */ override async isETHBasedChain(): Promise<boolean> { return super.isETHBasedChain(); } /** * @inheritDoc * * @example Get allowance parameters for depositing ETH on ETH-based chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const token = "<L1_TOKEN>"; * const amount = 5; * const approveParams = await signer.getDepositAllowanceParams(token, amount); * * await ( * await signer.approveERC20( * approveParams[0].token, * approveParams[0].allowance * ) * ).wait(); * * @example Get allowance parameters for depositing ETH on non-ETH-based chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const token = utils.LEGACY_ETH_ADDRESS; * const amount = 5; * const approveParams = await signer.getDepositAllowanceParams(token, amount); * await ( * await signer.approveERC20( * approveParams[0].token, * approveParams[0].allowance * ) * ).wait(); * * @example Get allowance parameters for depositing base token on non-ETH-based chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const token = await signer.getBaseToken(); * const amount = 5; * const approveParams = await signer.getDepositAllowanceParams(token, amount); * await ( * await signer.approveERC20( * approveParams[0].token, * approveParams[0].allowance * ) * ).wait(); * * @example Get allowance parameters for depositing non-base token on non-ETH-based chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const token = "<L1_TOKEN>"; * const amount = 5; * const approveParams = await signer.getDepositAllowanceParams(token, amount); * * await ( * await signer.approveERC20( * approveParams[0].token, * approveParams[0].allowance * ) * ).wait(); * * await ( * await signer.approveERC20( * approveParams[1].token, * approveParams[1].allowance * ) * ).wait(); */ override async getDepositAllowanceParams( token: Address, amount: BigNumberish, overrides?: ethers.Overrides ): Promise< { token: Address; allowance: BigNumberish; }[] > { return super.getDepositAllowanceParams(token, amount, overrides); } /** * @inheritDoc * * @example Deposit ETH on ETH-based chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * await signer.deposit({ * token: utils.ETH_ADDRESS, * amount: 10_000_000n, * }); * * @example Deposit token on ETH-based chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be"; * await signer.deposit({ * token: tokenL1, * amount: 10_000_000n, * approveERC20: true, * }); * * @example Deposit ETH on non-ETH-chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * await signer.deposit({ * token: utils.ETH_ADDRESS, * amount: 10_000_000, * approveBaseERC20: true, * }); * * @example Deposit base token on non-ETH-based chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * await signer.deposit({ * token: await signer.getBaseToken(), * amount: 10_000_000, * approveERC20: true, // or approveBaseERC20: true * }); * * @example Deposit non-base token on non-ETH-based chain. * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be"; * await signer.deposit({ * token: tokenL1, * amount: 10_000_000, * approveERC20: true, * approveBaseERC20: true, * }); */ override async deposit(transaction: { token: Address; amount: BigNumberish; to?: Address; operatorTip?: BigNumberish; bridgeAddress?: Address; approveERC20?: boolean; approveBaseERC20?: boolean; l2GasLimit?: BigNumberish; gasPerPubdataByte?: BigNumberish; refundRecipient?: Address; overrides?: Overrides; approveOverrides?: Overrides; approveBaseOverrides?: Overrides; customBridgeData?: BytesLike; }): Promise<PriorityOpResponse> { return super.deposit(transaction); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B"; * const gas = await signer.estimateGasDeposit({ * token: tokenL1, * amount: 10_000_000n, * }); * console.log(`Gas: ${gas}`); */ override async estimateGasDeposit(transaction: { token: Address; amount: BigNumberish; to?: Address; operatorTip?: BigNumberish; bridgeAddress?: Address; customBridgeData?: BytesLike; l2GasLimit?: BigNumberish; gasPerPubdataByte?: BigNumberish; refundRecipient?: Address; overrides?: Overrides; }): Promise<bigint> { return super.estimateGasDeposit(transaction); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be"; * const tx = await signer.getDepositTx({ * token: tokenL1, * amount: 10_000_000n, * }); */ override async getDepositTx(transaction: { token: Address; amount: BigNumberish; to?: Address; operatorTip?: BigNumberish; bridgeAddress?: Address; l2GasLimit?: BigNumberish; gasPerPubdataByte?: BigNumberish; customBridgeData?: BytesLike; refundRecipient?: Address; overrides?: Overrides; }): Promise<any> { return super.getDepositTx(transaction); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, Wallet, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be"; * const fee = await signer.getFullRequiredDepositFee({ * token: tokenL1, * to: Wallet.createRandom().address, * }); * console.log(`Fee: ${fee}`); */ override async getFullRequiredDepositFee(transaction: { token: Address; to?: Address; bridgeAddress?: Address; customBridgeData?: BytesLike; gasPerPubdataByte?: BigNumberish; overrides?: Overrides; }): Promise<FullDepositFee> { return super.getFullRequiredDepositFee(transaction); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const WITHDRAWAL_HASH = "<WITHDRAWAL_TX_HASH>"; * const params = await signer.finalizeWithdrawalParams(WITHDRAWAL_HASH); */ override async finalizeWithdrawalParams( withdrawalHash: BytesLike, index = 0 ): Promise<FinalizeWithdrawalParams> { return super.finalizeWithdrawalParams(withdrawalHash, index); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const WITHDRAWAL_HASH = "<WITHDRAWAL_TX_HASH>"; * const params = await signer.getFinalizeWithdrawalParams(WITHDRAWAL_HASH); */ override async getFinalizeWithdrawalParams( withdrawalHash: BytesLike, index = 0 ): Promise<FinalizeWithdrawalParams> { return super.getFinalizeWithdrawalParams(withdrawalHash, index); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const WITHDRAWAL_HASH = "<WITHDRAWAL_TX_HASH>"; * const finalizeWithdrawTx = await signer.finalizeWithdrawal(WITHDRAWAL_HASH); */ override async finalizeWithdrawal( withdrawalHash: BytesLike, index = 0, overrides?: Overrides ): Promise<ContractTransactionResponse> { return super.finalizeWithdrawal(withdrawalHash, index, overrides); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const WITHDRAWAL_HASH = "<WITHDRAWAL_TX_HASH>"; * const isFinalized = await signer.isWithdrawalFinalized(WITHDRAWAL_HASH); */ override async isWithdrawalFinalized( withdrawalHash: BytesLike, index = 0 ): Promise<boolean> { return super.isWithdrawalFinalized(withdrawalHash, index); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const FAILED_DEPOSIT_HASH = "<FAILED_DEPOSIT_TX_HASH>"; * const claimFailedDepositTx = await signer.claimFailedDeposit(FAILED_DEPOSIT_HASH); */ override async claimFailedDeposit( depositHash: BytesLike, overrides?: Overrides ): Promise<ContractTransactionResponse> { return super.claimFailedDeposit(depositHash, overrides); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tx = { * contractAddress: await signer.getAddress(), * calldata: '0x', * l2Value: 7_000_000_000, * }; * * const approveParams = await signer.getRequestExecuteAllowanceParams(tx); * await ( * await signer.approveERC20( * approveParams.token, * approveParams.allowance * ) * ).wait(); */ override async getRequestExecuteAllowanceParams(transaction: { contractAddress: Address; calldata: string; l2GasLimit?: BigNumberish; l2Value?: BigNumberish; factoryDeps?: BytesLike[]; operatorTip?: BigNumberish; gasPerPubdataByte?: BigNumberish; refundRecipient?: Address; overrides?: Overrides; }): Promise<{token: Address; allowance: BigNumberish}> { return super.getRequestExecuteAllowanceParams(transaction); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * await signer.requestExecute({ * contractAddress: await signer.providerL2.getMainContractAddress(), * calldata: "0x", * l2Value: 7_000_000_000, * }); */ override async requestExecute(transaction: { contractAddress: Address; calldata: string; l2GasLimit?: BigNumberish; mintValue?: BigNumberish; l2Value?: BigNumberish; factoryDeps?: BytesLike[]; operatorTip?: BigNumberish; gasPerPubdataByte?: BigNumberish; refundRecipient?: Address; overrides?: Overrides; }): Promise<PriorityOpResponse> { return super.requestExecute(transaction); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const gas = await signer.estimateGasRequestExecute({ * contractAddress: await signer.providerL2.getMainContractAddress(), * calldata: "0x", * l2Value: 7_000_000_000, * }); * console.log(`Gas: ${gas}`); */ override async estimateGasRequestExecute(transaction: { contractAddress: Address; calldata: string; l2GasLimit?: BigNumberish; mintValue?: BigNumberish; l2Value?: BigNumberish; factoryDeps?: BytesLike[]; operatorTip?: BigNumberish; gasPerPubdataByte?: BigNumberish; refundRecipient?: Address; overrides?: Overrides; }): Promise<bigint> { return super.estimateGasRequestExecute(transaction); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * const tx = await signer.getRequestExecuteTx({ * contractAddress: await signer.providerL2.getMainContractAddress(), * calldata: "0x", * l2Value: 7_000_000_000, * }); */ override async getRequestExecuteTx(transaction: { contractAddress: Address; calldata: string; l2GasLimit?: BigNumberish; mintValue?: BigNumberish; l2Value?: BigNumberish; factoryDeps?: BytesLike[]; operatorTip?: BigNumberish; gasPerPubdataByte?: BigNumberish; refundRecipient?: Address; overrides?: Overrides; }): Promise<TransactionRequest> { return super.getRequestExecuteTx(transaction); } /** * @inheritDoc * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import { ethers } from "ethers"; * * const browserProvider = new ethers.BrowserProvider(window.ethereum); * const signer = L1Signer.from( * await browserProvider.getSigner(), * Provider.getDefaultProvider(types.Network.Sepolia) * ); * * // Any L2 -> L1 transaction can be used. * // In this case, withdrawal transaction is used. * const tx = "0x2a1c6c74b184965c0cb015aae9ea134fd96215d2e4f4979cfec12563295f610e"; * console.log(`Confirmation data: ${utils.toJSON(await signer.getPriorityOpConfirmation(tx, 0))}`); */ override async getPriorityOpConfirmation( txHash: string, index = 0 ): Promise<{ l1BatchNumber: number; l2MessageIndex: number; l2TxNumberInBlock: number | null; proof: string[]; }> { return super.getPriorityOpConfirmation(txHash, index); } /** * Creates a new L1Singer with provided `signer` and `zksyncProvider`. * * @param signer The signer from browser wallet. * @param zksyncProvider The provider instance for connecting to a L2 network. * * @example * * import { Provider, L1Signer, types } from "zksync-ethers"; * import