diff --git a/l1-contracts/contracts/bridge/L1ERC20Bridge.sol b/l1-contracts/contracts/bridge/L1ERC20Bridge.sol index aa0e77e60..6f83c2dcf 100644 --- a/l1-contracts/contracts/bridge/L1ERC20Bridge.sol +++ b/l1-contracts/contracts/bridge/L1ERC20Bridge.sol @@ -87,12 +87,18 @@ contract L1ERC20Bridge is IL1Bridge, IL1BridgeLegacy, ReentrancyGuard { uint256 _deployBridgeProxyFee, uint256 _amount ) external payable reentrancyGuardInitializer { + bool nativeErc20 = _amount != 0; + require(_l2TokenBeacon != address(0), "nf"); require(_governor != address(0), "nh"); // We are expecting to see the exact three bytecodes that are needed to initialize the bridge require(_factoryDeps.length == 3, "mk"); // The caller miscalculated deploy transactions fees - require(_amount == _deployBridgeImplementationFee + _deployBridgeProxyFee, "fee"); + if (nativeErc20) { + require(_amount == _deployBridgeImplementationFee + _deployBridgeProxyFee, "fee"); + } else { + require(msg.value == _deployBridgeImplementationFee + _deployBridgeProxyFee, "fee"); + } l2TokenProxyBytecodeHash = L2ContractHelper.hashL2Bytecode(_factoryDeps[2]); l2TokenBeacon = _l2TokenBeacon; @@ -149,9 +155,18 @@ contract L1ERC20Bridge is IL1Bridge, IL1BridgeLegacy, ReentrancyGuard { address _l1Token, uint256 _amount, uint256 _l2TxGasLimit, - uint256 _l2TxGasPerPubdataByte + uint256 _l2TxGasPerPubdataByte, + uint256 _l2MaxFee ) external payable returns (bytes32 l2TxHash) { - l2TxHash = deposit(_l2Receiver, _l1Token, _amount, _l2TxGasLimit, _l2TxGasPerPubdataByte, address(0)); + l2TxHash = deposit( + _l2Receiver, + _l1Token, + _amount, + _l2TxGasLimit, + _l2TxGasPerPubdataByte, + address(0), + _l2MaxFee + ); } /// @notice Initiates a deposit by locking funds on the contract and sending the request @@ -164,6 +179,7 @@ contract L1ERC20Bridge is IL1Bridge, IL1BridgeLegacy, ReentrancyGuard { /// @param _l2TxGasLimit The L2 gas limit to be used in the corresponding L2 transaction /// @param _l2TxGasPerPubdataByte The gasPerPubdataByteLimit to be used in the corresponding L2 transaction /// @param _refundRecipient The address on L2 that will receive the refund for the transaction. + /// @param _l2MaxFee The max fee to be paid in L2. /// @dev If the L2 deposit finalization transaction fails, the `_refundRecipient` will receive the `_l2Value`. /// Please note, the contract may change the refund recipient's address to eliminate sending funds to addresses /// out of control. @@ -184,35 +200,44 @@ contract L1ERC20Bridge is IL1Bridge, IL1BridgeLegacy, ReentrancyGuard { uint256 _amount, uint256 _l2TxGasLimit, uint256 _l2TxGasPerPubdataByte, - address _refundRecipient + address _refundRecipient, + uint256 _l2MaxFee ) public payable nonReentrant returns (bytes32 l2TxHash) { require(_amount != 0, "2T"); // empty deposit amount uint256 amount = _depositFunds(msg.sender, IERC20(_l1Token), _amount); require(amount == _amount, "1T"); // The token has non-standard transfer logic + l2TxHash = _getRefundRecipientAndRequestL2Transaction(_refundRecipient, _l2MaxFee, _l2Receiver, _l1Token, _l2TxGasLimit, _l2TxGasPerPubdataByte, amount); + // Save the deposited amount to claim funds on L1 if the deposit failed on L2 + depositAmount[msg.sender][_l1Token][l2TxHash] = amount; + emit DepositInitiated(l2TxHash, msg.sender, _l2Receiver, _l1Token, amount); + } + + function _getRefundRecipientAndRequestL2Transaction(address _refundRecipient, uint256 _l2MaxFee, address _l2Receiver, address _l1Token, uint256 _l2TxGasLimit, uint256 _l2TxGasPerPubdataByte, uint256 amount) internal returns (bytes32) { bytes memory l2TxCalldata = _getDepositL2Calldata(msg.sender, _l2Receiver, _l1Token, amount); // If the refund recipient is not specified, the refund will be sent to the sender of the transaction. // Otherwise, the refund will be sent to the specified address. // If the recipient is a contract on L1, the address alias will be applied. - address refundRecipient = _refundRecipient; - if (_refundRecipient == address(0)) { - refundRecipient = msg.sender != tx.origin ? AddressAliasHelper.applyL1ToL2Alias(msg.sender) : msg.sender; - } - l2TxHash = zkSync.requestL2Transaction{value: msg.value}( + address refundRecipient = _getRefundRecipient(_refundRecipient); + + return zkSync.requestL2Transaction{value: msg.value}( l2Bridge, 0, // L2 msg.value - 0, + _l2MaxFee, l2TxCalldata, _l2TxGasLimit, _l2TxGasPerPubdataByte, new bytes[](0), refundRecipient ); + } - // Save the deposited amount to claim funds on L1 if the deposit failed on L2 - depositAmount[msg.sender][_l1Token][l2TxHash] = amount; - - emit DepositInitiated(l2TxHash, msg.sender, _l2Receiver, _l1Token, amount); + // Refund recipient logic + function _getRefundRecipient(address _refundRecipient) internal view returns (address) { + return + _refundRecipient == address(0) + ? (msg.sender != tx.origin ? AddressAliasHelper.applyL1ToL2Alias(msg.sender) : msg.sender) + : _refundRecipient; } /// @dev Transfers tokens from the depositor address to the smart contract address diff --git a/l1-contracts/contracts/bridge/L1WethBridge.sol b/l1-contracts/contracts/bridge/L1WethBridge.sol index ec9747bec..8a8c8d979 100644 --- a/l1-contracts/contracts/bridge/L1WethBridge.sol +++ b/l1-contracts/contracts/bridge/L1WethBridge.sol @@ -85,13 +85,20 @@ contract L1WethBridge is IL1Bridge, ReentrancyGuard { uint256 _deployBridgeProxyFee, uint256 _amount ) external payable reentrancyGuardInitializer { + bool nativeErc20 = _amount != 0; + require(_l2WethAddress != address(0), "L2 WETH address cannot be zero"); require(_governor != address(0), "Governor address cannot be zero"); require(_factoryDeps.length == 2, "Invalid factory deps length provided"); - require( - _amount == _deployBridgeImplementationFee + _deployBridgeProxyFee, - "Miscalculated deploy transactions fees" - ); + + if (nativeErc20) { + require( + _amount == _deployBridgeImplementationFee + _deployBridgeProxyFee, + "Miscalculated deploy transactions fees" + ); + } else { + require(msg.value == _deployBridgeImplementationFee + _deployBridgeProxyFee, "Miscalculated deploy transactions fees"); + } l2WethAddress = _l2WethAddress; @@ -164,7 +171,8 @@ contract L1WethBridge is IL1Bridge, ReentrancyGuard { uint256 _amount, uint256 _l2TxGasLimit, uint256 _l2TxGasPerPubdataByte, - address _refundRecipient + address _refundRecipient, + uint256 _l2MaxFee ) external payable nonReentrant returns (bytes32 txHash) { require(_l1Token == l1WethAddress, "Invalid L1 token address"); require(_amount != 0, "Amount cannot be zero"); @@ -187,7 +195,7 @@ contract L1WethBridge is IL1Bridge, ReentrancyGuard { txHash = zkSync.requestL2Transaction{value: _amount + msg.value}( l2Bridge, _amount, - 0, + _l2MaxFee, l2TxCalldata, _l2TxGasLimit, _l2TxGasPerPubdataByte, diff --git a/l1-contracts/contracts/bridge/interfaces/IL1Bridge.sol b/l1-contracts/contracts/bridge/interfaces/IL1Bridge.sol index 2cb38c448..1e823e2b2 100644 --- a/l1-contracts/contracts/bridge/interfaces/IL1Bridge.sol +++ b/l1-contracts/contracts/bridge/interfaces/IL1Bridge.sol @@ -26,7 +26,8 @@ interface IL1Bridge { uint256 _amount, uint256 _l2TxGasLimit, uint256 _l2TxGasPerPubdataByte, - address _refundRecipient + address _refundRecipient, + uint256 _l2MaxFee ) external payable returns (bytes32 txHash); function claimFailedDeposit( diff --git a/l1-contracts/contracts/bridge/interfaces/IL1BridgeLegacy.sol b/l1-contracts/contracts/bridge/interfaces/IL1BridgeLegacy.sol index b8185061f..e6522fb05 100644 --- a/l1-contracts/contracts/bridge/interfaces/IL1BridgeLegacy.sol +++ b/l1-contracts/contracts/bridge/interfaces/IL1BridgeLegacy.sol @@ -11,6 +11,7 @@ interface IL1BridgeLegacy { address _l1Token, uint256 _amount, uint256 _l2TxGasLimit, - uint256 _l2TxGasPerPubdataByte + uint256 _l2TxGasPerPubdataByte, + uint256 _l2MaxFee ) external payable returns (bytes32 txHash); } diff --git a/l1-contracts/contracts/zksync/facets/Mailbox.sol b/l1-contracts/contracts/zksync/facets/Mailbox.sol index 8f127356a..5d81dd625 100644 --- a/l1-contracts/contracts/zksync/facets/Mailbox.sol +++ b/l1-contracts/contracts/zksync/facets/Mailbox.sol @@ -22,6 +22,8 @@ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol // While formally the following import is not used, it is needed to inherit documentation from it import {IBase} from "../interfaces/IBase.sol"; +bool constant NATIVE_ERC20 = $(NATIVE_ERC20); + /// @title zkSync Mailbox contract providing interfaces for L1 <-> L2 interaction. /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -173,8 +175,7 @@ contract MailboxFacet is Base, IMailbox { bytes calldata _message, bytes32[] calldata _merkleProof ) external nonReentrant { - // #def TOKEN_TYPE 'ERC20' - // #if TOKEN_TYPE == 'ETH' + // #if NATIVE_ERC20 == false require(!s.isEthWithdrawalFinalized[_l2BatchNumber][_l2MessageIndex], "jj"); L2Message memory l2ToL1Message = L2Message({ @@ -183,16 +184,16 @@ contract MailboxFacet is Base, IMailbox { data: _message }); - (address _l1WithdrawReceiver, address _t, uint256 _amount) = _parseL2WithdrawalMessage(_message); + (address _l1WithdrawReceiver, uint256 _amount) = _parseL2WithdrawalMessage(_message); { bool proofValid = proveL2MessageInclusion(_l2BatchNumber, _l2MessageIndex, l2ToL1Message, _merkleProof); require(proofValid, "pi"); // Failed to verify that withdrawal was actually initialized on L2 } s.isEthWithdrawalFinalized[_l2BatchNumber][_l2MessageIndex] = true; _withdrawFunds(_l1WithdrawReceiver, _amount); - + emit EthWithdrawalFinalized(_l1WithdrawReceiver, _amount); - // #elif TOKEN_TYPE == 'ERC20' + // #elif NATIVE_ERC20 == true require(!s.isEthWithdrawalFinalized[_l2BatchNumber][_l2MessageIndex], "pw"); L2Message memory l2ToL1Message = L2Message({ @@ -230,10 +231,10 @@ contract MailboxFacet is Base, IMailbox { ) external payable nonReentrant returns (bytes32 canonicalTxHash) { // Change the sender address if it is a smart contract to prevent address collision between L1 and L2. // Please note, currently zkSync address derivation is different from Ethereum one, but it may be changed in the future. - // address sender = msg.sender; - // if (sender != tx.origin) { - // sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender); - // } + address sender = msg.sender; + if (sender != tx.origin) { + sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender); + } // Enforcing that `_l2GasPerPubdataByteLimit` equals to a certain constant number. This is needed // to ensure that users do not get used to using "exotic" numbers for _l2GasPerPubdataByteLimit, e.g. 1-2, etc. @@ -243,7 +244,7 @@ contract MailboxFacet is Base, IMailbox { require(_l2GasPerPubdataByteLimit == REQUIRED_L2_GAS_PRICE_PER_PUBDATA, "qp"); canonicalTxHash = _requestL2Transaction( - msg.sender, + sender, _contractL2, _l2Value, _amount, @@ -273,12 +274,15 @@ contract MailboxFacet is Base, IMailbox { // Here we manually assign fields for the struct to prevent "stack too deep" error WritePriorityOpParams memory params; + uint256 amount = _amount != 0 ? _amount : msg.value; + // uint256 amount = msg.value; + // Checking that the user provided enough ether to pay for the transaction. // Using a new scope to prevent "stack too deep" error { params.l2GasPrice = _isFree ? 0 : _deriveL2GasPrice(tx.gasprice, _l2GasPerPubdataByteLimit); uint256 baseCost = params.l2GasPrice * _l2GasLimit; - require(_amount >= baseCost + _l2Value, "mv"); // The `msg.value` doesn't cover the transaction cost + require(amount >= baseCost + _l2Value, "mv"); // The `amount` doesn't cover the transaction cost } // If the `_refundRecipient` is not provided, we use the `_sender` as the recipient. @@ -288,14 +292,17 @@ contract MailboxFacet is Base, IMailbox { refundRecipient = AddressAliasHelper.applyL1ToL2Alias(refundRecipient); } - // The address of the token that is used in the L2 as native. - address nativeTokenAddress = address($(L1_NATIVE_TOKEN_ADDRESS)); - // Check balance and allowance. - require(IERC20(nativeTokenAddress).balanceOf(tx.origin) >= _amount, "Not enough balance"); - require(IERC20(nativeTokenAddress).allowance(tx.origin, address(this)) >= _amount, "Not enough allowance"); + // Check if we are operating with native tokens. + if (_amount != 0) { + // The address of the token that is used in the L2 as native. + address nativeTokenAddress = address($(L1_NATIVE_TOKEN_ADDRESS)); + // Check balance and allowance. + require(IERC20(nativeTokenAddress).balanceOf(tx.origin) >= amount, "Not enough balance"); + require(IERC20(nativeTokenAddress).allowance(tx.origin, address(this)) >= amount, "Not enough allowance"); - // Transfer tokens to the contract. - IERC20(nativeTokenAddress).safeTransferFrom(tx.origin, address(this), _amount); + // Transfer tokens to the contract. + IERC20(nativeTokenAddress).safeTransferFrom(tx.origin, address(this), amount); + } params.sender = _sender; params.txId = s.priorityQueue.getTotalPriorityTxs(); @@ -303,7 +310,7 @@ contract MailboxFacet is Base, IMailbox { params.contractAddressL2 = _contractAddressL2; params.expirationTimestamp = uint64(block.timestamp + PRIORITY_EXPIRATION); params.l2GasLimit = _l2GasLimit; - params.valueToMint = _amount; + params.valueToMint = amount; params.l2GasPricePerPubdata = _l2GasPerPubdataByteLimit; params.refundRecipient = refundRecipient; diff --git a/l1-contracts/hardhat.config.ts b/l1-contracts/hardhat.config.ts index 393a86d74..039e5bae3 100644 --- a/l1-contracts/hardhat.config.ts +++ b/l1-contracts/hardhat.config.ts @@ -116,6 +116,7 @@ export default { } return { + NATIVE_ERC20: process.env.NATIVE_ERC20, NATIVE_ERC20_ADDRESS: address, ...systemParams, ...defs, diff --git a/l1-contracts/scripts/initialize-bridges.ts b/l1-contracts/scripts/initialize-bridges.ts index 9be442cb5..90156f267 100644 --- a/l1-contracts/scripts/initialize-bridges.ts +++ b/l1-contracts/scripts/initialize-bridges.ts @@ -61,6 +61,7 @@ async function main() { .option("--gas-price ") .option("--nonce ") .option("--erc20-bridge ") + .option("--native-erc20") .action(async (cmd) => { const deployWallet = cmd.privateKey ? new Wallet(cmd.privateKey, provider) @@ -68,6 +69,10 @@ async function main() { process.env.MNEMONIC ? process.env.MNEMONIC : ethTestConfig.mnemonic, "m/44'/60'/0'/0/0" ).connect(provider); + + const nativeErc20impl = cmd.nativeErc20 ? true : false; + console.log(`Using native erc20: ${nativeErc20impl}`); + console.log(`Using deployer wallet: ${deployWallet.address}`); const gasPrice = cmd.gasPrice ? parseUnits(cmd.gasPrice, "gwei") : await provider.getGasPrice(); @@ -152,7 +157,7 @@ async function main() { zkSync.requestL2Transaction( ethers.constants.AddressZero, 0, - requiredValueToPublishBytecodes, + nativeErc20impl ? requiredValueToPublishBytecodes : 0, "0x", priorityTxMaxGasLimit, SYSTEM_CONFIG.requiredL2GasPricePerPubdata, @@ -166,7 +171,7 @@ async function main() { l2GovernorAddress, requiredValueToInitializeBridge, requiredValueToInitializeBridge, - requiredValueToInitializeBridge.mul(2), + nativeErc20impl ? requiredValueToInitializeBridge.mul(2) : 0, { gasPrice, nonce: nonce + 1, @@ -174,7 +179,6 @@ async function main() { } ), ]; - const txs = await Promise.all(independentInitialization); for (const tx of txs) { console.log(`Transaction sent with hash ${tx.hash} and nonce ${tx.nonce}. Waiting for receipt...`); diff --git a/l1-contracts/scripts/initialize-l2-weth-token.ts b/l1-contracts/scripts/initialize-l2-weth-token.ts index cecffae63..00f4af323 100644 --- a/l1-contracts/scripts/initialize-l2-weth-token.ts +++ b/l1-contracts/scripts/initialize-l2-weth-token.ts @@ -124,6 +124,7 @@ async function main() { .option("--private-key ") .option("--gas-price ") .option("--nonce ") + .option('--native-erc20') .action(async (cmd) => { if (!l1WethTokenAddress) { console.log("Base Layer WETH address not provided. Skipping."); @@ -136,6 +137,10 @@ async function main() { process.env.MNEMONIC ? process.env.MNEMONIC : ethTestConfig.mnemonic, "m/44'/60'/0'/0/1" ).connect(provider); + + const nativeErc20impl = cmd.nativeErc20 ? true : false; + console.log(`Using native erc20: ${nativeErc20impl}`); + console.log(`Using deployer wallet: ${deployWallet.address}`); const gasPrice = cmd.gasPrice ? parseUnits(cmd.gasPrice, "gwei") : await provider.getGasPrice(); @@ -160,7 +165,7 @@ async function main() { const tx = await zkSync.requestL2Transaction( l2WethTokenProxyAddress, 0, - requiredValueToInitializeBridge, + nativeErc20impl? requiredValueToInitializeBridge : 0, calldata, DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT, SYSTEM_CONFIG.requiredL2GasPricePerPubdata, diff --git a/l1-contracts/scripts/initialize-weth-bridges.ts b/l1-contracts/scripts/initialize-weth-bridges.ts index 13b6a6af2..2157b61a3 100644 --- a/l1-contracts/scripts/initialize-weth-bridges.ts +++ b/l1-contracts/scripts/initialize-weth-bridges.ts @@ -39,6 +39,7 @@ async function main() { .option("--private-key ") .option("--gas-price ") .option("--nonce ") + .option("--native-erc20") .action(async (cmd) => { const deployWallet = cmd.privateKey ? new Wallet(cmd.privateKey, provider) @@ -46,6 +47,10 @@ async function main() { process.env.MNEMONIC ? process.env.MNEMONIC : ethTestConfig.mnemonic, "m/44'/60'/0'/0/0" ).connect(provider); + + const nativeErc20impl = cmd.nativeErc20 ? true : false; + console.log(`Using native erc20: ${nativeErc20impl}`); + console.log(`Using deployer wallet: ${deployWallet.address}`); const gasPrice = cmd.gasPrice ? parseUnits(cmd.gasPrice, "gwei") : await provider.getGasPrice(); @@ -82,7 +87,7 @@ async function main() { l2GovernorAddress, requiredValueToInitializeBridge, requiredValueToInitializeBridge, - requiredValueToInitializeBridge.mul(2), + nativeErc20impl ? requiredValueToInitializeBridge.mul(2) : 0, { gasPrice, value: requiredValueToInitializeBridge.mul(2), diff --git a/l1-contracts/test/unit_tests/l1_erc20_bridge_test.spec.ts b/l1-contracts/test/unit_tests/l1_erc20_bridge_test.spec.ts index ab3335294..e8d4db5ae 100644 --- a/l1-contracts/test/unit_tests/l1_erc20_bridge_test.spec.ts +++ b/l1-contracts/test/unit_tests/l1_erc20_bridge_test.spec.ts @@ -106,7 +106,8 @@ describe("L1ERC20Bridge tests", function () { 0, 0, 0, - ethers.constants.AddressZero + ethers.constants.AddressZero, + 0 ) ); expect(revertReason).equal("2T"); @@ -206,6 +207,7 @@ async function depositERC20( l2GasLimit, REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT, l2RefundRecipient, + 0, // l2MaxFee is only used for native token deposits { value: neededValue, } diff --git a/l1-contracts/test/unit_tests/l1_weth_bridge_test.spec.ts b/l1-contracts/test/unit_tests/l1_weth_bridge_test.spec.ts index 2b73b3a40..14820137a 100644 --- a/l1-contracts/test/unit_tests/l1_weth_bridge_test.spec.ts +++ b/l1-contracts/test/unit_tests/l1_weth_bridge_test.spec.ts @@ -94,7 +94,7 @@ describe("WETH Bridge tests", () => { priorityTxMaxGasLimit: 10000000, initialProtocolVersion: 0, feeParams: defaultFeeParams(), - }, + }, ]); const facetCuts = [ @@ -126,6 +126,7 @@ describe("WETH Bridge tests", () => { await owner.getAddress(), ethers.constants.WeiPerEther, ethers.constants.WeiPerEther, + 0 ]); const _bridgeProxy = await ( await hardhat.ethers.getContractFactory("ERC1967Proxy") @@ -144,7 +145,8 @@ describe("WETH Bridge tests", () => { 0, 0, 0, - ethers.constants.AddressZero + ethers.constants.AddressZero, + 0 ) ); @@ -163,6 +165,7 @@ describe("WETH Bridge tests", () => { 1000000, REQUIRED_L2_GAS_PRICE_PER_PUBDATA, await randomSigner.getAddress(), + 0, { value: ethers.constants.WeiPerEther } ); }); diff --git a/l2-contracts/src/deployTestnetPaymaster.ts b/l2-contracts/src/deployTestnetPaymaster.ts index d1f35e0ee..daf5f4378 100644 --- a/l2-contracts/src/deployTestnetPaymaster.ts +++ b/l2-contracts/src/deployTestnetPaymaster.ts @@ -20,7 +20,7 @@ async function main() { program.version("0.1.0").name("deploy-testnet-paymaster").description("Deploys the testnet paymaster to L2"); - program.option("--private-key ").action(async (cmd) => { + program.option("--private-key ").option("--native-erc20").action(async (cmd) => { const deployWallet = cmd.privateKey ? new Wallet(cmd.privateKey, provider) : Wallet.fromMnemonic( @@ -32,10 +32,11 @@ async function main() { const testnetPaymasterBytecode = hre.artifacts.readArtifactSync("TestnetPaymaster").bytecode; const create2Salt = ethers.constants.HashZero; const paymasterAddress = computeL2Create2Address(deployWallet, testnetPaymasterBytecode, "0x", create2Salt); + const nativeErc20impl = cmd.nativeErc20 ? true : false; // TODO: request from API how many L2 gas needs for the transaction. await ( - await create2DeployFromL1(deployWallet, testnetPaymasterBytecode, "0x", create2Salt, priorityTxMaxGasLimit) + await create2DeployFromL1(deployWallet, testnetPaymasterBytecode, "0x", create2Salt, priorityTxMaxGasLimit, undefined, nativeErc20impl) ).wait(); console.log(`CONTRACTS_L2_TESTNET_PAYMASTER_ADDR=${paymasterAddress}`); diff --git a/l2-contracts/src/utils.ts b/l2-contracts/src/utils.ts index 23ce8ae08..b57688496 100644 --- a/l2-contracts/src/utils.ts +++ b/l2-contracts/src/utils.ts @@ -84,7 +84,8 @@ export async function create2DeployFromL1( constructor: ethers.BytesLike, create2Salt: ethers.BytesLike, l2GasLimit: ethers.BigNumberish, - gasPrice?: ethers.BigNumberish + gasPrice?: ethers.BigNumberish, + nativeToken?: boolean ) { const zkSyncAddress = deployedAddressesFromEnv().ZkSync.DiamondProxy; const zkSync = IZkSyncFactory.connect(zkSyncAddress, wallet); @@ -101,7 +102,7 @@ export async function create2DeployFromL1( return await zkSync.requestL2Transaction( DEPLOYER_SYSTEM_CONTRACT_ADDRESS, 0, - expectedCost, + nativeToken? expectedCost : 0, calldata, l2GasLimit, REQUIRED_L2_GAS_PRICE_PER_PUBDATA,