Socket
Socket
Sign inDemoInstall

zksync-web3

Package Overview
Dependencies
Maintainers
5
Versions
90
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zksync-web3 - npm Package Compare versions

Comparing version 0.15.0 to 0.15.1

12

build/src/adapters.d.ts
import { BigNumber, BigNumberish, BytesLike, ethers } from 'ethers';
import { Provider } from './provider';
import { Address, BalancesMap, BlockTag, Eip712Meta, PriorityOpResponse, TransactionResponse } from './types';
import { Address, BalancesMap, BlockTag, Eip712Meta, FullDepositFee, PriorityOpResponse, TransactionResponse } from './types';
type Constructor<T = {}> = new (...args: any[]) => T;

@@ -19,2 +19,3 @@ interface TxSender {

getBalanceL1(token?: Address, blockTag?: ethers.providers.BlockTag): Promise<BigNumber>;
getAllowanceL1(token: Address, bridgeAddress?: Address, blockTag?: ethers.providers.BlockTag): Promise<BigNumber>;
l2TokenAddress(token: Address): Promise<string>;

@@ -49,2 +50,3 @@ approveERC20(token: Address, amount: BigNumberish, overrides?: ethers.Overrides & {

bridgeAddress?: Address;
customBridgeData?: BytesLike;
l2GasLimit?: BigNumberish;

@@ -67,2 +69,10 @@ gasPerPubdataByte?: BigNumberish;

}): Promise<any>;
getFullRequiredDepositFee(transaction: {
token: Address;
to?: Address;
bridgeAddress?: Address;
customBridgeData?: BytesLike;
gasPerPubdataByte?: BigNumberish;
overrides?: ethers.PayableOverrides;
}): Promise<FullDepositFee>;
_getWithdrawalLog(withdrawalHash: BytesLike, index?: number): Promise<{

@@ -69,0 +79,0 @@ log: import("./types").Log;

@@ -38,2 +38,7 @@ "use strict";

}
async getAllowanceL1(token, bridgeAddress, blockTag) {
const erc20contract = typechain_1.IERC20MetadataFactory.connect(token, this._providerL1());
bridgeAddress !== null && bridgeAddress !== void 0 ? bridgeAddress : (bridgeAddress = (await this.getL1BridgeContracts()).erc20.address);
return await erc20contract.allowance(await this.getAddress(), bridgeAddress, { blockTag });
}
async l2TokenAddress(token) {

@@ -60,2 +65,3 @@ if (token == utils_1.ETH_ADDRESS) {

}
overrides !== null && overrides !== void 0 ? overrides : (overrides = {});
return await erc20contract.approve(bridgeAddress, amount, overrides);

@@ -72,4 +78,10 @@ }

async deposit(transaction) {
var _a, _b, _c;
var _d;
const depositTx = await this.getDepositTx(transaction);
if (transaction.token == utils_1.ETH_ADDRESS) {
const baseGasLimit = await this.estimateGasRequestExecute(depositTx);
const gasLimit = (0, utils_1.scaleGasLimit)(baseGasLimit);
(_a = depositTx.overrides) !== null && _a !== void 0 ? _a : (depositTx.overrides = {});
(_b = (_d = depositTx.overrides).gasLimit) !== null && _b !== void 0 ? _b : (_d.gasLimit = gasLimit);
return this.requestExecute(depositTx);

@@ -83,8 +95,15 @@ }

: bridgeContracts.erc20.address;
const approveTx = await this.approveERC20(transaction.token, transaction.amount, {
bridgeAddress,
...transaction.approveOverrides
});
await approveTx.wait();
// We only request the allowance if the current one is not enough.
const allowance = await this.getAllowanceL1(transaction.token, bridgeAddress);
if (allowance.lt(transaction.amount)) {
const approveTx = await this.approveERC20(transaction.token, transaction.amount, {
bridgeAddress,
...transaction.approveOverrides
});
await approveTx.wait();
}
}
const baseGasLimit = await this._providerL1().estimateGas(depositTx);
const gasLimit = (0, utils_1.scaleGasLimit)(baseGasLimit);
(_c = depositTx.gasLimit) !== null && _c !== void 0 ? _c : (depositTx.gasLimit = gasLimit);
return await this._providerL2().getPriorityOpResponse(await this._signerL1().sendTransaction(depositTx));

@@ -95,8 +114,10 @@ }

const depositTx = await this.getDepositTx(transaction);
let baseGasLimit;
if (transaction.token == utils_1.ETH_ADDRESS) {
return await this.estimateGasRequestExecute(depositTx);
baseGasLimit = await this.estimateGasRequestExecute(depositTx);
}
else {
return await this._providerL1().estimateGas(depositTx);
baseGasLimit = await this._providerL1().estimateGas(depositTx);
}
return (0, utils_1.scaleGasLimit)(baseGasLimit);
}

@@ -118,3 +139,3 @@ async getDepositTx(transaction) {

let l2Address = await bridge.l2Bridge();
(_f = tx.l2GasLimit) !== null && _f !== void 0 ? _f : (tx.l2GasLimit = await (0, utils_1.estimateCustomBridgeDepositL2Gas)(this._providerL1(), this._providerL2(), tx.bridgeAddress, l2Address, tx.token, tx.amount, tx.to, customBridgeData, await this.getAddress(), tx.gasPerPubdataByte));
(_f = tx.l2GasLimit) !== null && _f !== void 0 ? _f : (tx.l2GasLimit = await (0, utils_1.estimateCustomBridgeDepositL2Gas)(this._providerL2(), tx.bridgeAddress, l2Address, tx.token, tx.amount, tx.to, customBridgeData, await this.getAddress(), tx.gasPerPubdataByte));
}

@@ -153,8 +174,79 @@ else {

await (0, utils_1.checkBaseCost)(baseCost, overrides.value);
// TODO: compatibility layer: using the old API which uses msg.sender as the
// refund recipient, to make the SDK compatible with the old contracts.
// const contract = bridgeContracts.erc20 as ethers.Contract;
return await bridgeContracts.erc20.populateTransaction.deposit(...args, overrides);
}
}
// Retrieves the full needed ETH fee for the deposit.
// Returns the L1 fee and the L2 fee.
async getFullRequiredDepositFee(transaction) {
var _a, _b, _c, _d;
// It is assumed that the L2 fee for the transaction does not depend on its value.
const dummyAmount = '1';
const { ...tx } = transaction;
const zksyncContract = await this.getMainContract();
(_a = tx.overrides) !== null && _a !== void 0 ? _a : (tx.overrides = {});
await insertGasPrice(this._providerL1(), tx.overrides);
const gasPriceForMessages = (await tx.overrides.maxFeePerGas) || (await tx.overrides.gasPrice);
(_b = tx.to) !== null && _b !== void 0 ? _b : (tx.to = await this.getAddress());
(_c = tx.gasPerPubdataByte) !== null && _c !== void 0 ? _c : (tx.gasPerPubdataByte = utils_1.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT);
let l2GasLimit;
if (tx.bridgeAddress != null) {
const customBridgeData = (_d = tx.customBridgeData) !== null && _d !== void 0 ? _d : (await (0, utils_1.getERC20DefaultBridgeData)(tx.token, this._providerL1()));
let bridge = typechain_1.IL1BridgeFactory.connect(tx.bridgeAddress, this._signerL1());
let l2Address = await bridge.l2Bridge();
l2GasLimit !== null && l2GasLimit !== void 0 ? l2GasLimit : (l2GasLimit = await (0, utils_1.estimateCustomBridgeDepositL2Gas)(this._providerL2(), tx.bridgeAddress, l2Address, tx.token, dummyAmount, tx.to, customBridgeData, await this.getAddress(), tx.gasPerPubdataByte));
}
else {
l2GasLimit !== null && l2GasLimit !== void 0 ? l2GasLimit : (l2GasLimit = await (0, utils_1.estimateDefaultBridgeDepositL2Gas)(this._providerL1(), this._providerL2(), tx.token, dummyAmount, tx.to, await this.getAddress(), tx.gasPerPubdataByte));
}
const baseCost = await zksyncContract.l2TransactionBaseCost(gasPriceForMessages, l2GasLimit, tx.gasPerPubdataByte);
const selfBalanceETH = await this.getBalanceL1();
// We could 0 in, because the final fee will anyway be bigger than
if (baseCost.gte(selfBalanceETH.add(dummyAmount))) {
const recommendedETHBalance = ethers_1.BigNumber.from(tx.token == utils_1.ETH_ADDRESS
? utils_1.L1_RECOMMENDED_MIN_ETH_DEPOSIT_GAS_LIMIT
: utils_1.L1_RECOMMENDED_MIN_ERC20_DEPOSIT_GAS_LIMIT)
.mul(gasPriceForMessages)
.add(baseCost);
const formattedRecommendedBalance = ethers_1.ethers.utils.formatEther(recommendedETHBalance);
throw new Error(`Not enough balance for deposit. Under the provided gas price, the recommended balance to perform a deposit is ${formattedRecommendedBalance} ETH`);
}
// For ETH token the value that the user passes to the estimation is the one which has the
// value for the L2 comission substracted.
let amountForEstimate;
if ((0, utils_1.isETH)(tx.token)) {
amountForEstimate = ethers_1.BigNumber.from(dummyAmount);
}
else {
amountForEstimate = ethers_1.BigNumber.from(dummyAmount);
if ((await this.getAllowanceL1(tx.token)) < amountForEstimate) {
throw new Error('Not enough allowance to cover the deposit');
}
}
// Deleting the explicit gas limits in the fee estimation
// in order to prevent the situation where the transaction
// fails because the user does not have enough balance
const estimationOverrides = { ...tx.overrides };
delete estimationOverrides.gasPrice;
delete estimationOverrides.maxFeePerGas;
delete estimationOverrides.maxPriorityFeePerGas;
const l1GasLimit = await this.estimateGasDeposit({
...tx,
amount: amountForEstimate,
overrides: estimationOverrides,
l2GasLimit
});
const fullCost = {
baseCost,
l1GasLimit,
l2GasLimit
};
if (tx.overrides.gasPrice) {
fullCost.gasPrice = ethers_1.BigNumber.from(await tx.overrides.gasPrice);
}
else {
fullCost.maxFeePerGas = ethers_1.BigNumber.from(await tx.overrides.maxFeePerGas);
fullCost.maxPriorityFeePerGas = ethers_1.BigNumber.from(await tx.overrides.maxPriorityFeePerGas);
}
return fullCost;
}
async _getWithdrawalLog(withdrawalHash, index = 0) {

@@ -246,2 +338,5 @@ const hash = ethers_1.ethers.utils.hexlify(withdrawalHash);

const requestExecuteTx = await this.getRequestExecuteTx(transaction);
delete requestExecuteTx.gasPrice;
delete requestExecuteTx.maxFeePerGas;
delete requestExecuteTx.maxPriorityFeePerGas;
return this._providerL1().estimateGas(requestExecuteTx);

@@ -248,0 +343,0 @@ }

2

build/src/index.d.ts
export * as utils from './utils';
export * as types from './types';
export { EIP712Signer, Signer, L1Signer } from './signer';
export { EIP712Signer, Signer, L1Signer, L1VoidSigner, L2VoidSigner } from './signer';
export { Wallet } from './wallet';
export { Web3Provider, Provider } from './provider';
export { ContractFactory, Contract } from './contract';

@@ -26,3 +26,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.Contract = exports.ContractFactory = exports.Provider = exports.Web3Provider = exports.Wallet = exports.L1Signer = exports.Signer = exports.EIP712Signer = exports.types = exports.utils = void 0;
exports.Contract = exports.ContractFactory = exports.Provider = exports.Web3Provider = exports.Wallet = exports.L2VoidSigner = exports.L1VoidSigner = exports.L1Signer = exports.Signer = exports.EIP712Signer = exports.types = exports.utils = void 0;
exports.utils = __importStar(require("./utils"));

@@ -34,2 +34,4 @@ exports.types = __importStar(require("./types"));

Object.defineProperty(exports, "L1Signer", { enumerable: true, get: function () { return signer_1.L1Signer; } });
Object.defineProperty(exports, "L1VoidSigner", { enumerable: true, get: function () { return signer_1.L1VoidSigner; } });
Object.defineProperty(exports, "L2VoidSigner", { enumerable: true, get: function () { return signer_1.L2VoidSigner; } });
var wallet_1 = require("./wallet");

@@ -36,0 +38,0 @@ Object.defineProperty(exports, "Wallet", { enumerable: true, get: function () { return wallet_1.Wallet; } });

@@ -81,2 +81,3 @@ import { ethers } from 'ethers';

getBalanceL1(token?: string, blockTag?: ethers.providers.BlockTag): Promise<ethers.BigNumber>;
getAllowanceL1(token: string, bridgeAddress?: string, blockTag?: ethers.providers.BlockTag): Promise<ethers.BigNumber>;
l2TokenAddress(token: string): Promise<string>;

@@ -111,2 +112,3 @@ approveERC20(token: string, amount: ethers.BigNumberish, overrides?: ethers.Overrides & {

bridgeAddress?: string;
customBridgeData?: ethers.utils.BytesLike;
l2GasLimit?: ethers.BigNumberish;

@@ -129,2 +131,10 @@ gasPerPubdataByte?: ethers.BigNumberish;

}): Promise<any>;
getFullRequiredDepositFee(transaction: {
token: string;
to?: string;
bridgeAddress?: string;
customBridgeData?: ethers.utils.BytesLike;
gasPerPubdataByte?: ethers.BigNumberish;
overrides?: ethers.PayableOverrides;
}): Promise<import("./types").FullDepositFee>;
_getWithdrawalLog(withdrawalHash: ethers.utils.BytesLike, index?: number): Promise<{

@@ -194,2 +204,170 @@ log: import("./types").Log;

}
declare const L2VoidSigner_base: {
new (...args: any[]): {
_providerL2(): Provider;
_signerL2(): ethers.Signer;
getBalance(token?: string, blockTag?: BlockTag): Promise<ethers.BigNumber>;
getAllBalances(): Promise<import("./types").BalancesMap>;
getL2BridgeContracts(): Promise<{
erc20: import("../typechain").IL2Bridge;
}>;
_fillCustomData(data: import("./types").Eip712Meta): import("./types").Eip712Meta;
withdraw(transaction: {
token: string;
amount: ethers.BigNumberish;
to?: string;
bridgeAddress?: string;
overrides?: ethers.Overrides;
}): Promise<TransactionResponse>;
transfer(transaction: {
to: string;
amount: ethers.BigNumberish;
token?: string;
overrides?: ethers.Overrides;
}): Promise<TransactionResponse>;
sendTransaction(tx: ethers.providers.TransactionRequest): Promise<ethers.providers.TransactionResponse>;
getAddress(): Promise<string>;
};
} & typeof ethers.VoidSigner;
export declare class L2VoidSigner extends L2VoidSigner_base {
provider: Provider;
eip712: EIP712Signer;
_signerL2(): this;
_providerL2(): Provider;
static from(signer: ethers.VoidSigner & {
provider: Provider;
}): L2VoidSigner;
getNonce(blockTag?: BlockTag): Promise<number>;
sendTransaction(transaction: TransactionRequest): Promise<TransactionResponse>;
}
declare const L1VoidSigner_base: {
new (...args: any[]): {
_providerL2(): Provider;
_providerL1(): ethers.providers.Provider;
_signerL1(): ethers.Signer;
getMainContract(): Promise<import("../typechain").IZkSync>;
getL1BridgeContracts(): Promise<{
erc20: import("../typechain").IL1Bridge;
}>;
getBalanceL1(token?: string, blockTag?: ethers.providers.BlockTag): Promise<ethers.BigNumber>;
getAllowanceL1(token: string, bridgeAddress?: string, blockTag?: ethers.providers.BlockTag): Promise<ethers.BigNumber>;
l2TokenAddress(token: string): Promise<string>;
approveERC20(token: string, amount: ethers.BigNumberish, overrides?: ethers.Overrides & {
bridgeAddress?: string;
}): Promise<ethers.providers.TransactionResponse>;
getBaseCost(params: {
gasLimit: ethers.BigNumberish;
gasPerPubdataByte?: ethers.BigNumberish;
gasPrice?: ethers.BigNumberish;
}): Promise<ethers.BigNumber>;
deposit(transaction: {
token: string;
amount: ethers.BigNumberish;
to?: string;
operatorTip?: ethers.BigNumberish;
bridgeAddress?: string;
approveERC20?: boolean;
l2GasLimit?: ethers.BigNumberish;
gasPerPubdataByte?: ethers.BigNumberish;
refundRecipient?: string;
overrides?: ethers.PayableOverrides;
approveOverrides?: ethers.Overrides;
customBridgeData?: ethers.utils.BytesLike;
}): Promise<import("./types").PriorityOpResponse>;
estimateGasDeposit(transaction: {
token: string;
amount: ethers.BigNumberish;
to?: string;
operatorTip?: ethers.BigNumberish;
bridgeAddress?: string;
customBridgeData?: ethers.utils.BytesLike;
l2GasLimit?: ethers.BigNumberish;
gasPerPubdataByte?: ethers.BigNumberish;
refundRecipient?: string;
overrides?: ethers.PayableOverrides;
}): Promise<ethers.BigNumber>;
getDepositTx(transaction: {
token: string;
amount: ethers.BigNumberish;
to?: string;
operatorTip?: ethers.BigNumberish;
bridgeAddress?: string;
l2GasLimit?: ethers.BigNumberish;
gasPerPubdataByte?: ethers.BigNumberish;
customBridgeData?: ethers.utils.BytesLike;
refundRecipient?: string;
overrides?: ethers.PayableOverrides;
}): Promise<any>;
getFullRequiredDepositFee(transaction: {
token: string;
to?: string;
bridgeAddress?: string;
customBridgeData?: ethers.utils.BytesLike;
gasPerPubdataByte?: ethers.BigNumberish;
overrides?: ethers.PayableOverrides;
}): Promise<import("./types").FullDepositFee>;
_getWithdrawalLog(withdrawalHash: ethers.utils.BytesLike, index?: number): Promise<{
log: import("./types").Log;
l1BatchTxId: number;
}>;
_getWithdrawalL2ToL1Log(withdrawalHash: ethers.utils.BytesLike, index?: number): Promise<{
l2ToL1LogIndex: number;
l2ToL1Log: import("./types").L2ToL1Log;
}>;
finalizeWithdrawalParams(withdrawalHash: ethers.utils.BytesLike, index?: number): Promise<{
l1BatchNumber: number;
l2MessageIndex: number;
l2TxNumberInBlock: number;
message: any;
sender: string;
proof: string[];
}>;
finalizeWithdrawal(withdrawalHash: ethers.utils.BytesLike, index?: number, overrides?: ethers.Overrides): Promise<ethers.ContractTransaction>;
isWithdrawalFinalized(withdrawalHash: ethers.utils.BytesLike, index?: number): Promise<boolean>;
claimFailedDeposit(depositHash: ethers.utils.BytesLike, overrides?: ethers.Overrides): Promise<ethers.ContractTransaction>;
requestExecute(transaction: {
contractAddress: string;
calldata: ethers.utils.BytesLike;
l2GasLimit?: ethers.BigNumberish;
l2Value?: ethers.BigNumberish;
factoryDeps?: ethers.utils.BytesLike[];
operatorTip?: ethers.BigNumberish;
gasPerPubdataByte?: ethers.BigNumberish;
refundRecipient?: string;
overrides?: ethers.PayableOverrides;
}): Promise<import("./types").PriorityOpResponse>;
estimateGasRequestExecute(transaction: {
contractAddress: string;
calldata: ethers.utils.BytesLike;
l2GasLimit?: ethers.BigNumberish;
l2Value?: ethers.BigNumberish;
factoryDeps?: ethers.utils.BytesLike[];
operatorTip?: ethers.BigNumberish;
gasPerPubdataByte?: ethers.BigNumberish;
refundRecipient?: string;
overrides?: ethers.PayableOverrides;
}): Promise<ethers.BigNumber>;
getRequestExecuteTx(transaction: {
contractAddress: string;
calldata: ethers.utils.BytesLike;
l2GasLimit?: ethers.BigNumberish;
l2Value?: ethers.BigNumberish;
factoryDeps?: ethers.utils.BytesLike[];
operatorTip?: ethers.BigNumberish;
gasPerPubdataByte?: ethers.BigNumberish;
refundRecipient?: string;
overrides?: ethers.PayableOverrides;
}): Promise<ethers.PopulatedTransaction>;
sendTransaction(tx: ethers.providers.TransactionRequest): Promise<ethers.providers.TransactionResponse>;
getAddress(): Promise<string>;
};
} & typeof ethers.VoidSigner;
export declare class L1VoidSigner extends L1VoidSigner_base {
providerL2: Provider;
_providerL2(): Provider;
_providerL1(): ethers.providers.Provider;
_signerL1(): this;
static from(signer: ethers.VoidSigner, zksyncProvider: Provider): L1VoidSigner;
connectToL2(provider: Provider): this;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.L1Signer = exports.Signer = exports.EIP712Signer = exports.eip712Types = void 0;
exports.L1VoidSigner = exports.L2VoidSigner = exports.L1Signer = exports.Signer = exports.EIP712Signer = exports.eip712Types = void 0;
const ethers_1 = require("ethers");

@@ -153,1 +153,76 @@ const utils_1 = require("./utils");

exports.L1Signer = L1Signer;
class L2VoidSigner extends (0, adapters_1.AdapterL2)(ethers_1.ethers.VoidSigner) {
_signerL2() {
return this;
}
_providerL2() {
return this.provider;
}
static from(signer) {
const newSigner = Object.setPrototypeOf(signer, L2VoidSigner.prototype);
// @ts-ignore
newSigner.eip712 = new EIP712Signer(newSigner, newSigner.getChainId());
return newSigner;
}
// an alias with a better name
async getNonce(blockTag) {
return await this.getTransactionCount(blockTag);
}
async sendTransaction(transaction) {
var _a, _b, _c, _d, _e, _f, _g;
if (transaction.customData == null && transaction.type == null) {
// use legacy txs by default
transaction.type = 0;
}
if (transaction.customData == null && transaction.type != utils_1.EIP712_TX_TYPE) {
return (await super.sendTransaction(transaction));
}
else {
const address = await this.getAddress();
(_a = transaction.from) !== null && _a !== void 0 ? _a : (transaction.from = address);
if (transaction.from.toLowerCase() != address.toLowerCase()) {
throw new Error('Transaction `from` address mismatch');
}
transaction.type = utils_1.EIP712_TX_TYPE;
(_b = transaction.value) !== null && _b !== void 0 ? _b : (transaction.value = 0);
(_c = transaction.data) !== null && _c !== void 0 ? _c : (transaction.data = '0x');
(_d = transaction.nonce) !== null && _d !== void 0 ? _d : (transaction.nonce = await this.getNonce());
transaction.customData = this._fillCustomData(transaction.customData);
(_e = transaction.gasPrice) !== null && _e !== void 0 ? _e : (transaction.gasPrice = await this.provider.getGasPrice());
(_f = transaction.gasLimit) !== null && _f !== void 0 ? _f : (transaction.gasLimit = await this.provider.estimateGas(transaction));
(_g = transaction.chainId) !== null && _g !== void 0 ? _g : (transaction.chainId = (await this.provider.getNetwork()).chainId);
transaction.customData.customSignature = await this.eip712.sign(transaction);
const txBytes = (0, utils_1.serialize)(transaction);
return await this.provider.sendTransaction(txBytes);
}
}
}
exports.L2VoidSigner = L2VoidSigner;
// This class is to be used on the frontend with metamask injection.
// It only contains L1 operations. For L2 operations, see Signer.
// Sample usage:
// const provider = new ethers.Web3Provider(window.ethereum);
// const zksyncProvider = new zkweb3.Provider('<rpc_url>');
// const signer = zkweb3.L1Signer.from(provider.getSigner(), zksyncProvider);
// const tx = await signer.deposit({ ... });
class L1VoidSigner extends (0, adapters_1.AdapterL1)(ethers_1.ethers.VoidSigner) {
_providerL2() {
return this.providerL2;
}
_providerL1() {
return this.provider;
}
_signerL1() {
return this;
}
static from(signer, zksyncProvider) {
const newSigner = Object.setPrototypeOf(signer, L1VoidSigner.prototype);
newSigner.providerL2 = zksyncProvider;
return newSigner;
}
connectToL2(provider) {
this.providerL2 = provider;
return this;
}
}
exports.L1VoidSigner = L1VoidSigner;

@@ -179,1 +179,9 @@ import { BytesLike, BigNumberish, providers, BigNumber } from 'ethers';

}
export interface FullDepositFee {
maxFeePerGas?: BigNumber;
maxPriorityFeePerGas?: BigNumber;
gasPrice?: BigNumber;
baseCost: BigNumber;
l1GasLimit: BigNumber;
l2GasLimit: BigNumber;
}

@@ -24,2 +24,6 @@ import { utils, ethers, BigNumber, BigNumberish, BytesLike } from 'ethers';

export declare const MAX_BYTECODE_LEN_BYTES: number;
export declare const L1_FEE_ESTIMATION_COEF_NUMERATOR: ethers.BigNumber;
export declare const L1_FEE_ESTIMATION_COEF_DENOMINATOR: ethers.BigNumber;
export declare const L1_RECOMMENDED_MIN_ERC20_DEPOSIT_GAS_LIMIT = 400000;
export declare const L1_RECOMMENDED_MIN_ETH_DEPOSIT_GAS_LIMIT = 200000;
export declare const DEFAULT_GAS_PER_PUBDATA_LIMIT = 50000;

@@ -49,2 +53,3 @@ export declare const REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT = 800;

export declare function estimateDefaultBridgeDepositL2Gas(providerL1: ethers.providers.Provider, providerL2: Provider, token: Address, amount: BigNumberish, to: Address, from?: Address, gasPerPubdataByte?: BigNumberish): Promise<BigNumber>;
export declare function estimateCustomBridgeDepositL2Gas(providerL1: ethers.providers.Provider, providerL2: Provider, l1BridgeAddress: Address, l2BridgeAddress: Address, token: Address, amount: BigNumberish, to: Address, bridgeData: BytesLike, from?: Address, gasPerPubdataByte?: BigNumberish): Promise<BigNumber>;
export declare function scaleGasLimit(gasLimit: BigNumber): BigNumber;
export declare function estimateCustomBridgeDepositL2Gas(providerL2: Provider, l1BridgeAddress: Address, l2BridgeAddress: Address, token: Address, amount: BigNumberish, to: Address, bridgeData: BytesLike, from?: Address, gasPerPubdataByte?: BigNumberish): Promise<BigNumber>;

@@ -17,3 +17,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.estimateCustomBridgeDepositL2Gas = exports.estimateDefaultBridgeDepositL2Gas = exports.isTypedDataSignatureCorrect = exports.isMessageSignatureCorrect = exports.getERC20BridgeCalldata = exports.getERC20DefaultBridgeData = exports.undoL1ToL2Alias = exports.applyL1ToL2Alias = exports.getL2HashFromPriorityOp = exports.parseTransaction = exports.hashBytecode = exports.serialize = exports.checkBaseCost = exports.createAddress = exports.create2Address = exports.getDeployedContracts = exports.getHashedL2ToL1Msg = exports.layer1TxDefaults = exports.sleep = exports.isETH = exports.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT = exports.DEFAULT_GAS_PER_PUBDATA_LIMIT = exports.MAX_BYTECODE_LEN_BYTES = exports.PRIORITY_OPERATION_L2_TX_TYPE = exports.EIP712_TX_TYPE = exports.EIP1271_MAGIC_VALUE = exports.L1_TO_L2_ALIAS_OFFSET = exports.L2_ETH_TOKEN_ADDRESS = exports.L1_MESSENGER_ADDRESS = exports.CONTRACT_DEPLOYER_ADDRESS = exports.BOOTLOADER_FORMAL_ADDRESS = exports.L2_BRIDGE_ABI = exports.L1_BRIDGE_ABI = exports.IERC1271 = exports.IERC20 = exports.L1_MESSENGER = exports.CONTRACT_DEPLOYER = exports.ZKSYNC_MAIN_ABI = exports.ETH_ADDRESS = void 0;
exports.estimateCustomBridgeDepositL2Gas = exports.scaleGasLimit = exports.estimateDefaultBridgeDepositL2Gas = exports.isTypedDataSignatureCorrect = exports.isMessageSignatureCorrect = exports.getERC20BridgeCalldata = exports.getERC20DefaultBridgeData = exports.undoL1ToL2Alias = exports.applyL1ToL2Alias = exports.getL2HashFromPriorityOp = exports.parseTransaction = exports.hashBytecode = exports.serialize = exports.checkBaseCost = exports.createAddress = exports.create2Address = exports.getDeployedContracts = exports.getHashedL2ToL1Msg = exports.layer1TxDefaults = exports.sleep = exports.isETH = exports.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT = exports.DEFAULT_GAS_PER_PUBDATA_LIMIT = exports.L1_RECOMMENDED_MIN_ETH_DEPOSIT_GAS_LIMIT = exports.L1_RECOMMENDED_MIN_ERC20_DEPOSIT_GAS_LIMIT = exports.L1_FEE_ESTIMATION_COEF_DENOMINATOR = exports.L1_FEE_ESTIMATION_COEF_NUMERATOR = exports.MAX_BYTECODE_LEN_BYTES = exports.PRIORITY_OPERATION_L2_TX_TYPE = exports.EIP712_TX_TYPE = exports.EIP1271_MAGIC_VALUE = exports.L1_TO_L2_ALIAS_OFFSET = exports.L2_ETH_TOKEN_ADDRESS = exports.L1_MESSENGER_ADDRESS = exports.CONTRACT_DEPLOYER_ADDRESS = exports.BOOTLOADER_FORMAL_ADDRESS = exports.L2_BRIDGE_ABI = exports.L1_BRIDGE_ABI = exports.IERC1271 = exports.IERC20 = exports.L1_MESSENGER = exports.CONTRACT_DEPLOYER = exports.ZKSYNC_MAIN_ABI = exports.ETH_ADDRESS = void 0;
const ethers_1 = require("ethers");

@@ -42,2 +42,9 @@ const types_1 = require("./types");

exports.MAX_BYTECODE_LEN_BYTES = ((1 << 16) - 1) * 32;
// Currently, for some reason the SDK may return slightly smaller L1 gas limit than required for initiating L1->L2
// transaction. We use a coefficient to ensure that the transaction will be accepted.
exports.L1_FEE_ESTIMATION_COEF_NUMERATOR = ethers_1.BigNumber.from(12);
exports.L1_FEE_ESTIMATION_COEF_DENOMINATOR = ethers_1.BigNumber.from(10);
// This gas limit will be used for displaying the error messages when the users do not have enough fee.
exports.L1_RECOMMENDED_MIN_ERC20_DEPOSIT_GAS_LIMIT = 400000;
exports.L1_RECOMMENDED_MIN_ETH_DEPOSIT_GAS_LIMIT = 200000;
// The large L2 gas per pubdata to sign. This gas is enough to ensure that

@@ -426,7 +433,11 @@ // any reasonable limit will be accepted. Note, that the operator is NOT required to

const bridgeData = await getERC20DefaultBridgeData(token, providerL1);
return await estimateCustomBridgeDepositL2Gas(providerL1, providerL2, l1ERC20BridgeAddresses, erc20BridgeAddress, token, amount, to, bridgeData, from, gasPerPubdataByte);
return await estimateCustomBridgeDepositL2Gas(providerL2, l1ERC20BridgeAddresses, erc20BridgeAddress, token, amount, to, bridgeData, from, gasPerPubdataByte);
}
}
exports.estimateDefaultBridgeDepositL2Gas = estimateDefaultBridgeDepositL2Gas;
async function estimateCustomBridgeDepositL2Gas(providerL1, providerL2, l1BridgeAddress, l2BridgeAddress, token, amount, to, bridgeData, from, gasPerPubdataByte) {
function scaleGasLimit(gasLimit) {
return gasLimit.mul(exports.L1_FEE_ESTIMATION_COEF_NUMERATOR).div(exports.L1_FEE_ESTIMATION_COEF_DENOMINATOR);
}
exports.scaleGasLimit = scaleGasLimit;
async function estimateCustomBridgeDepositL2Gas(providerL2, l1BridgeAddress, l2BridgeAddress, token, amount, to, bridgeData, from, gasPerPubdataByte) {
const calldata = await getERC20BridgeCalldata(token, from, to, amount, bridgeData);

@@ -433,0 +444,0 @@ return await providerL2.estimateL1ToL2Execute({

@@ -42,2 +42,3 @@ import { EIP712Signer } from './signer';

getBalanceL1(token?: string, blockTag?: ethers.providers.BlockTag): Promise<ethers.BigNumber>;
getAllowanceL1(token: string, bridgeAddress?: string, blockTag?: ethers.providers.BlockTag): Promise<ethers.BigNumber>;
l2TokenAddress(token: string): Promise<string>;

@@ -72,2 +73,3 @@ approveERC20(token: string, amount: ethers.BigNumberish, overrides?: ethers.Overrides & {

bridgeAddress?: string;
customBridgeData?: ethers.utils.BytesLike;
l2GasLimit?: ethers.BigNumberish;

@@ -90,2 +92,10 @@ gasPerPubdataByte?: ethers.BigNumberish;

}): Promise<any>;
getFullRequiredDepositFee(transaction: {
token: string;
to?: string;
bridgeAddress?: string;
customBridgeData?: ethers.utils.BytesLike;
gasPerPubdataByte?: ethers.BigNumberish;
overrides?: ethers.PayableOverrides;
}): Promise<import("./types").FullDepositFee>;
_getWithdrawalLog(withdrawalHash: ethers.utils.BytesLike, index?: number): Promise<{

@@ -92,0 +102,0 @@ log: import("./types").Log;

# Changelog
## [0.15.1](https://github.com/matter-labs/zksync-2-dev/compare/zksync-web3-v0.15.0...zksync-web3-v0.15.1) (2023-04-24)
### Bug Fixes
* add coeficient to gas limit + method for full fee estimation ([#1622](https://github.com/matter-labs/zksync-2-dev/issues/1622)) ([229cda9](https://github.com/matter-labs/zksync-2-dev/commit/229cda977daa11a98a97515a2f75d709e2e8ed9a))
## [0.15.0](https://github.com/matter-labs/zksync-2-dev/compare/zksync-web3-v0.14.4...zksync-web3-v0.15.0) (2023-04-20)

@@ -4,0 +11,0 @@

{
"name": "zksync-web3",
"version": "0.15.0",
"version": "0.15.1",
"main": "build/src/index.js",

@@ -5,0 +5,0 @@ "types": "build/src/index.d.ts",

import { BigNumber, BigNumberish, BytesLike, ethers } from 'ethers';
import { IERC20MetadataFactory, IL1BridgeFactory, IL2BridgeFactory, IZkSyncFactory } from '../typechain';
import { Provider } from './provider';
import { Address, BalancesMap, BlockTag, Eip712Meta, PriorityOpResponse, TransactionResponse } from './types';
import {
Address,
BalancesMap,
BlockTag,
Eip712Meta,
FullDepositFee,
PriorityOpResponse,
TransactionResponse
} from './types';
import {
BOOTLOADER_FORMAL_ADDRESS,

@@ -16,2 +24,5 @@ checkBaseCost,

estimateDefaultBridgeDepositL2Gas,
scaleGasLimit,
L1_RECOMMENDED_MIN_ETH_DEPOSIT_GAS_LIMIT,
L1_RECOMMENDED_MIN_ERC20_DEPOSIT_GAS_LIMIT,
estimateCustomBridgeDepositL2Gas,

@@ -62,2 +73,12 @@ getERC20DefaultBridgeData

async getAllowanceL1(
token: Address,
bridgeAddress?: Address,
blockTag?: ethers.providers.BlockTag
): Promise<BigNumber> {
const erc20contract = IERC20MetadataFactory.connect(token, this._providerL1());
bridgeAddress ??= (await this.getL1BridgeContracts()).erc20.address;
return await erc20contract.allowance(await this.getAddress(), bridgeAddress, { blockTag });
}
async l2TokenAddress(token: Address) {

@@ -90,2 +111,4 @@ if (token == ETH_ADDRESS) {

overrides ??= {};
return await erc20contract.approve(bridgeAddress, amount, overrides);

@@ -128,3 +151,10 @@ }

const depositTx = await this.getDepositTx(transaction);
if (transaction.token == ETH_ADDRESS) {
const baseGasLimit = await this.estimateGasRequestExecute(depositTx);
const gasLimit = scaleGasLimit(baseGasLimit);
depositTx.overrides ??= {};
depositTx.overrides.gasLimit ??= gasLimit;
return this.requestExecute(depositTx);

@@ -137,8 +167,19 @@ } else {

: bridgeContracts.erc20.address;
const approveTx = await this.approveERC20(transaction.token, transaction.amount, {
bridgeAddress,
...transaction.approveOverrides
});
await approveTx.wait();
// We only request the allowance if the current one is not enough.
const allowance = await this.getAllowanceL1(transaction.token, bridgeAddress);
if (allowance.lt(transaction.amount)) {
const approveTx = await this.approveERC20(transaction.token, transaction.amount, {
bridgeAddress,
...transaction.approveOverrides
});
await approveTx.wait();
}
}
const baseGasLimit = await this._providerL1().estimateGas(depositTx);
const gasLimit = scaleGasLimit(baseGasLimit);
depositTx.gasLimit ??= gasLimit;
return await this._providerL2().getPriorityOpResponse(

@@ -156,2 +197,3 @@ await this._signerL1().sendTransaction(depositTx)

bridgeAddress?: Address;
customBridgeData?: BytesLike;
l2GasLimit?: BigNumberish;

@@ -163,7 +205,11 @@ gasPerPubdataByte?: BigNumberish;

const depositTx = await this.getDepositTx(transaction);
let baseGasLimit: BigNumber;
if (transaction.token == ETH_ADDRESS) {
return await this.estimateGasRequestExecute(depositTx);
baseGasLimit = await this.estimateGasRequestExecute(depositTx);
} else {
return await this._providerL1().estimateGas(depositTx);
baseGasLimit = await this._providerL1().estimateGas(depositTx);
}
return scaleGasLimit(baseGasLimit);
}

@@ -199,3 +245,2 @@

tx.l2GasLimit ??= await estimateCustomBridgeDepositL2Gas(
this._providerL1(),
this._providerL2(),

@@ -262,5 +307,2 @@ tx.bridgeAddress,

// TODO: compatibility layer: using the old API which uses msg.sender as the
// refund recipient, to make the SDK compatible with the old contracts.
// const contract = bridgeContracts.erc20 as ethers.Contract;
return await bridgeContracts.erc20.populateTransaction.deposit(...args, overrides);

@@ -270,2 +312,121 @@ }

// Retrieves the full needed ETH fee for the deposit.
// Returns the L1 fee and the L2 fee.
async getFullRequiredDepositFee(transaction: {
token: Address;
to?: Address;
bridgeAddress?: Address;
customBridgeData?: BytesLike;
gasPerPubdataByte?: BigNumberish;
overrides?: ethers.PayableOverrides;
}): Promise<FullDepositFee> {
// It is assumed that the L2 fee for the transaction does not depend on its value.
const dummyAmount = '1';
const { ...tx } = transaction;
const zksyncContract = await this.getMainContract();
tx.overrides ??= {};
await insertGasPrice(this._providerL1(), tx.overrides);
const gasPriceForMessages = (await tx.overrides.maxFeePerGas) || (await tx.overrides.gasPrice);
tx.to ??= await this.getAddress();
tx.gasPerPubdataByte ??= REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT;
let l2GasLimit;
if (tx.bridgeAddress != null) {
const customBridgeData =
tx.customBridgeData ?? (await getERC20DefaultBridgeData(tx.token, this._providerL1()));
let bridge = IL1BridgeFactory.connect(tx.bridgeAddress, this._signerL1());
let l2Address = await bridge.l2Bridge();
l2GasLimit ??= await estimateCustomBridgeDepositL2Gas(
this._providerL2(),
tx.bridgeAddress,
l2Address,
tx.token,
dummyAmount,
tx.to,
customBridgeData,
await this.getAddress(),
tx.gasPerPubdataByte
);
} else {
l2GasLimit ??= await estimateDefaultBridgeDepositL2Gas(
this._providerL1(),
this._providerL2(),
tx.token,
dummyAmount,
tx.to,
await this.getAddress(),
tx.gasPerPubdataByte
);
}
const baseCost = await zksyncContract.l2TransactionBaseCost(
gasPriceForMessages,
l2GasLimit,
tx.gasPerPubdataByte
);
const selfBalanceETH = await this.getBalanceL1();
// We could 0 in, because the final fee will anyway be bigger than
if (baseCost.gte(selfBalanceETH.add(dummyAmount))) {
const recommendedETHBalance = BigNumber.from(
tx.token == ETH_ADDRESS
? L1_RECOMMENDED_MIN_ETH_DEPOSIT_GAS_LIMIT
: L1_RECOMMENDED_MIN_ERC20_DEPOSIT_GAS_LIMIT
)
.mul(gasPriceForMessages)
.add(baseCost);
const formattedRecommendedBalance = ethers.utils.formatEther(recommendedETHBalance);
throw new Error(
`Not enough balance for deposit. Under the provided gas price, the recommended balance to perform a deposit is ${formattedRecommendedBalance} ETH`
);
}
// For ETH token the value that the user passes to the estimation is the one which has the
// value for the L2 comission substracted.
let amountForEstimate: BigNumber;
if (isETH(tx.token)) {
amountForEstimate = BigNumber.from(dummyAmount);
} else {
amountForEstimate = BigNumber.from(dummyAmount);
if ((await this.getAllowanceL1(tx.token)) < amountForEstimate) {
throw new Error('Not enough allowance to cover the deposit');
}
}
// Deleting the explicit gas limits in the fee estimation
// in order to prevent the situation where the transaction
// fails because the user does not have enough balance
const estimationOverrides = { ...tx.overrides };
delete estimationOverrides.gasPrice;
delete estimationOverrides.maxFeePerGas;
delete estimationOverrides.maxPriorityFeePerGas;
const l1GasLimit = await this.estimateGasDeposit({
...tx,
amount: amountForEstimate,
overrides: estimationOverrides,
l2GasLimit
});
const fullCost: FullDepositFee = {
baseCost,
l1GasLimit,
l2GasLimit
};
if (tx.overrides.gasPrice) {
fullCost.gasPrice = BigNumber.from(await tx.overrides.gasPrice);
} else {
fullCost.maxFeePerGas = BigNumber.from(await tx.overrides.maxFeePerGas);
fullCost.maxPriorityFeePerGas = BigNumber.from(await tx.overrides.maxPriorityFeePerGas);
}
return fullCost;
}
async _getWithdrawalLog(withdrawalHash: BytesLike, index: number = 0) {

@@ -429,2 +590,7 @@ const hash = ethers.utils.hexlify(withdrawalHash);

const requestExecuteTx = await this.getRequestExecuteTx(transaction);
delete requestExecuteTx.gasPrice;
delete requestExecuteTx.maxFeePerGas;
delete requestExecuteTx.maxPriorityFeePerGas;
return this._providerL1().estimateGas(requestExecuteTx);

@@ -431,0 +597,0 @@ }

export * as utils from './utils';
export * as types from './types';
export { EIP712Signer, Signer, L1Signer } from './signer';
export { EIP712Signer, Signer, L1Signer, L1VoidSigner, L2VoidSigner } from './signer';
export { Wallet } from './wallet';
export { Web3Provider, Provider } from './provider';
export { ContractFactory, Contract } from './contract';

@@ -171,1 +171,87 @@ import { ethers } from 'ethers';

}
export class L2VoidSigner extends AdapterL2(ethers.VoidSigner) {
public override provider: Provider;
public eip712: EIP712Signer;
override _signerL2() {
return this;
}
override _providerL2() {
return this.provider;
}
static from(signer: ethers.VoidSigner & { provider: Provider }): L2VoidSigner {
const newSigner: L2VoidSigner = Object.setPrototypeOf(signer, L2VoidSigner.prototype);
// @ts-ignore
newSigner.eip712 = new EIP712Signer(newSigner, newSigner.getChainId());
return newSigner;
}
// an alias with a better name
async getNonce(blockTag?: BlockTag) {
return await this.getTransactionCount(blockTag);
}
override async sendTransaction(transaction: TransactionRequest): Promise<TransactionResponse> {
if (transaction.customData == null && transaction.type == null) {
// use legacy txs by default
transaction.type = 0;
}
if (transaction.customData == null && transaction.type != EIP712_TX_TYPE) {
return (await super.sendTransaction(transaction)) as TransactionResponse;
} else {
const address = await this.getAddress();
transaction.from ??= address;
if (transaction.from.toLowerCase() != address.toLowerCase()) {
throw new Error('Transaction `from` address mismatch');
}
transaction.type = EIP712_TX_TYPE;
transaction.value ??= 0;
transaction.data ??= '0x';
transaction.nonce ??= await this.getNonce();
transaction.customData = this._fillCustomData(transaction.customData);
transaction.gasPrice ??= await this.provider.getGasPrice();
transaction.gasLimit ??= await this.provider.estimateGas(transaction);
transaction.chainId ??= (await this.provider.getNetwork()).chainId;
transaction.customData.customSignature = await this.eip712.sign(transaction);
const txBytes = serialize(transaction);
return await this.provider.sendTransaction(txBytes);
}
}
}
// This class is to be used on the frontend with metamask injection.
// It only contains L1 operations. For L2 operations, see Signer.
// Sample usage:
// const provider = new ethers.Web3Provider(window.ethereum);
// const zksyncProvider = new zkweb3.Provider('<rpc_url>');
// const signer = zkweb3.L1Signer.from(provider.getSigner(), zksyncProvider);
// const tx = await signer.deposit({ ... });
export class L1VoidSigner extends AdapterL1(ethers.VoidSigner) {
public providerL2: Provider;
override _providerL2() {
return this.providerL2;
}
override _providerL1() {
return this.provider;
}
override _signerL1() {
return this;
}
static from(signer: ethers.VoidSigner, zksyncProvider: Provider): L1VoidSigner {
const newSigner: L1VoidSigner = Object.setPrototypeOf(signer, L1VoidSigner.prototype);
newSigner.providerL2 = zksyncProvider;
return newSigner;
}
connectToL2(provider: Provider): this {
this.providerL2 = provider;
return this;
}
}

@@ -221,1 +221,10 @@ import { BytesLike, BigNumberish, providers, BigNumber } from 'ethers';

}
export interface FullDepositFee {
maxFeePerGas?: BigNumber;
maxPriorityFeePerGas?: BigNumber;
gasPrice?: BigNumber;
baseCost: BigNumber;
l1GasLimit: BigNumber;
l2GasLimit: BigNumber;
}

@@ -44,2 +44,11 @@ import { utils, ethers, BigNumber, BigNumberish, BytesLike } from 'ethers';

// Currently, for some reason the SDK may return slightly smaller L1 gas limit than required for initiating L1->L2
// transaction. We use a coefficient to ensure that the transaction will be accepted.
export const L1_FEE_ESTIMATION_COEF_NUMERATOR = BigNumber.from(12);
export const L1_FEE_ESTIMATION_COEF_DENOMINATOR = BigNumber.from(10);
// This gas limit will be used for displaying the error messages when the users do not have enough fee.
export const L1_RECOMMENDED_MIN_ERC20_DEPOSIT_GAS_LIMIT = 400000;
export const L1_RECOMMENDED_MIN_ETH_DEPOSIT_GAS_LIMIT = 200000;
// The large L2 gas per pubdata to sign. This gas is enough to ensure that

@@ -531,3 +540,2 @@ // any reasonable limit will be accepted. Note, that the operator is NOT required to

return await estimateCustomBridgeDepositL2Gas(
providerL1,
providerL2,

@@ -546,4 +554,7 @@ l1ERC20BridgeAddresses,

export function scaleGasLimit(gasLimit: BigNumber): BigNumber {
return gasLimit.mul(L1_FEE_ESTIMATION_COEF_NUMERATOR).div(L1_FEE_ESTIMATION_COEF_DENOMINATOR);
}
export async function estimateCustomBridgeDepositL2Gas(
providerL1: ethers.providers.Provider,
providerL2: Provider,

@@ -550,0 +561,0 @@ l1BridgeAddress: Address,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc