UNPKG

zksync-cli

Version:

CLI tool that simplifies the process of developing applications and interacting with the ZKsync network

119 lines 6.06 kB
import { Option } from "commander"; import inquirer from "inquirer"; import Program from "./command.js"; import { chainWithL1Option, l1RpcUrlOption, l2RpcUrlOption, privateKeyOption, zeekOption, } from "../../common/options.js"; import { l2Chains } from "../../data/chains.js"; import { ETH_TOKEN } from "../../utils/constants.js"; import { useDecimals } from "../../utils/formatters.js"; import { getAddressFromPrivateKey, getL1Provider, getL2Provider, getL2Wallet, optionNameToParam, } from "../../utils/helpers.js"; import Logger from "../../utils/logger.js"; import { getBalance } from "../../utils/token.js"; import { isPrivateKey, isTransactionHash } from "../../utils/validators.js"; import zeek from "../../utils/zeek.js"; import { getChains } from "../config/chains.js"; const transactionHashOption = new Option("--hash <transaction_hash>", "L2 withdrawal transaction hash to finalize"); export const handler = async (options) => { try { Logger.debug(`Initial withdraw-finalize options: ${JSON.stringify({ ...options, ...(options.privateKey ? { privateKey: "<hidden>" } : {}) }, null, 2)}`); const chains = [...l2Chains, ...getChains()]; const answers = await inquirer.prompt([ { message: chainWithL1Option.description, name: optionNameToParam(chainWithL1Option.long), type: "list", choices: chains.filter((e) => e.l1Chain).map((e) => ({ name: e.name, value: e.network })), required: true, when(answers) { return !(answers.l1Rpc && answers.rpc); }, }, { message: transactionHashOption.description, name: optionNameToParam(transactionHashOption.long), type: "input", required: true, validate: (input) => isTransactionHash(input), }, { message: privateKeyOption.description, name: optionNameToParam(privateKeyOption.long), type: "password", required: true, validate: (input) => isPrivateKey(input), }, ], options); options = { ...options, ...answers, }; Logger.debug(`Final withdraw-finalize options: ${JSON.stringify({ ...options, privateKey: "<hidden>" }, null, 2)}`); const fromChain = chains.find((e) => e.network === options.chain); const fromChainLabel = fromChain && !options.rpc ? fromChain.name : (options.rpc ?? "Unknown chain"); const toChain = chains.find((e) => e.network === options.chain)?.l1Chain; const toChainLabel = toChain && !options.l1Rpc ? toChain.name : (options.l1Rpc ?? "Unknown chain"); Logger.info("\nWithdraw finalize:"); Logger.info(` From chain: ${fromChainLabel}`); Logger.info(` To chain: ${toChainLabel}`); Logger.info(` Withdrawal transaction (L2): ${options.hash}`); Logger.info(` Finalizer address (L1): ${getAddressFromPrivateKey(options.privateKey)}`); const l1Provider = getL1Provider(options.l1Rpc ?? toChain.rpcUrl); const l2Provider = getL2Provider(options.rpc ?? fromChain.rpcUrl); const zkWallet = getL2Wallet(options.privateKey, l2Provider, l1Provider); Logger.info("\nChecking status of the transaction..."); try { const alreadyFinalized = await zkWallet.isWithdrawalFinalized(options.hash); if (alreadyFinalized) { Logger.error(`\nWithdrawal with specified hash is already finalized on ${toChainLabel}`); return; } } catch (err) { Logger.error("Withdrawal is not ready to be finalized yet: ", err); } const l2Details = await l2Provider.getTransactionDetails(options.hash); if (!l2Details) { Logger.error("Transaction with specified hash wasn't found on L2"); return; } if (!l2Details.ethExecuteTxHash) { Logger.error(`\nTransaction is still being processed on ${fromChainLabel}. Please try again later.`); Logger.info(`L2 Transaction Details: ${JSON.stringify(l2Details, null, 2)}`); return; } const finalizationHandle = await zkWallet.finalizeWithdrawal(options.hash); Logger.info("\nWithdrawal finalized:"); Logger.info(` Finalization transaction hash: ${finalizationHandle.hash}`); Logger.info("\nWithdrawal finalization tx sent:"); Logger.info(` Finalization transaction hash: ${finalizationHandle.hash}`); if (toChain?.explorerUrl) { Logger.info(` Transaction link: ${toChain.explorerUrl}/tx/${finalizationHandle.hash}`); } Logger.info("\nWaiting for finalization transaction to be mined..."); const receipt = await finalizationHandle.wait(); if (!receipt) { Logger.error("Transaction was not mined - unknown error"); return; } Logger.info(` Finalization transaction was mined in block ${receipt.blockNumber}`); const token = ETH_TOKEN; const { bigNumberToDecimal } = useDecimals(token.decimals); const senderBalance = await getBalance(token.l1Address, zkWallet.address, l1Provider); Logger.info(`\nSender L1 balance after transaction: ${bigNumberToDecimal(senderBalance)} ${token.symbol} ${token.name ? `(${token.name})` : ""}`); if (options.zeek) zeek(); } catch (error) { Logger.error("There was an error while finalizing withdrawal:"); Logger.error(error); } }; Program.command("withdraw-finalize") .description("Finalize withdrawal of funds") .addOption(transactionHashOption) .addOption(chainWithL1Option) .addOption(l1RpcUrlOption) .addOption(l2RpcUrlOption) .addOption(privateKeyOption) .addOption(zeekOption) .action(handler); //# sourceMappingURL=withdraw-finalize.js.map