UNPKG

zksync-cli

Version:

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

290 lines 9.36 kB
import chalk from "chalk"; import inquirer from "inquirer"; import slugify from "slugify"; import Program from "./command.js"; import { configHandler } from "../../common/ConfigHandler.js"; import { l2Chains } from "../../data/chains.js"; import Logger from "../../utils/logger.js"; import { isUrl } from "../../utils/validators.js"; export const getChains = () => { return configHandler.getConfigValue("chains") || []; }; const saveChains = (chains) => { configHandler.setConfigValue("chains", chains); }; const validateChainId = (value) => { if (isNaN(parseInt(value))) { return "Chain id must be a number"; } if (parseInt(value).toString() !== value.toString()) { return "Chain id must be an integer"; } if (parseInt(value) < 0) { return "Chain id must be a positive integer"; } return true; }; export const promptAddNewChain = async (defaults) => { const chains = getChains(); const { id, name } = await inquirer.prompt([ { message: "Chain id", name: "id", type: "input", default: defaults?.id, required: true, validate: validateChainId, }, { message: "Chain name", name: "name", type: "input", default: defaults?.name, required: true, validate: (value) => { if (!value) { return "Chain name is required"; } if (defaults?.name === value) { return true; } if ([...getChains(), ...l2Chains].find((chain) => chain.name === value)) { return "Chain name already exists"; } return true; }, }, ]); const { network, rpcUrl, explorerUrl } = await inquirer.prompt([ { message: "Chain key", default: defaults?.network || slugify.default(name, { lower: true, replacement: "-", strict: true, }), name: "network", type: "input", required: true, validate: (value) => { if (!value) { return "Chain key is required"; } if (defaults?.network === value) { return true; } if ([...getChains(), ...l2Chains].find((chain) => chain.network === value)) { return "Chain key already exists"; } return true; }, }, { message: "Chain RPC URL", name: "rpcUrl", type: "input", default: defaults?.rpcUrl, required: true, validate: (input) => isUrl(input), }, { message: "Chain explorer URL" + chalk.gray(" (optional)"), name: "explorerUrl", type: "input", default: defaults?.explorerUrl, required: false, validate: (input) => { if (input) { return isUrl(input); } return true; }, }, ]); const newChain = { id: parseInt(id), name, network, rpcUrl, explorerUrl: explorerUrl || undefined, }; const { hasL1Chain } = await inquirer.prompt([ { message: "Is this chain connected to L1", name: "hasL1Chain", type: "list", default: defaults?.l1Chain ? "yes" : "no", choices: [ { name: `No ${chalk.gray("- skip adding L1 chain info")}`, short: "No", value: "no", }, { name: `Yes ${chalk.gray("- add L1 chain info")}`, short: "Yes", value: "yes", }, ], required: true, }, ]); if (hasL1Chain === "yes") { const { l1_id, l1_name } = await inquirer.prompt([ { message: "L1 Chain id", name: "l1_id", type: "input", default: defaults?.l1Chain?.id, required: true, validate: validateChainId, }, { message: "L1 Chain name", name: "l1_name", type: "input", default: defaults?.l1Chain?.name, required: true, validate: (value) => { if (!value) { return "Chain name is required"; } return true; }, }, ]); const { l1_network, l1_rpcUrl, l1_explorerUrl } = await inquirer.prompt([ { message: "L1 Chain key", default: defaults?.l1Chain?.network || slugify.default(l1_name, { lower: true, replacement: "-", strict: true, }), name: "l1_network", type: "input", required: true, validate: (value) => { if (!value) { return "Chain key is required"; } return true; }, }, { message: "L1 Chain RPC URL", name: "l1_rpcUrl", type: "input", default: defaults?.l1Chain?.rpcUrl, required: true, validate: (input) => isUrl(input), }, { message: "L1 Chain explorer URL" + chalk.gray(" (optional)"), name: "l1_explorerUrl", type: "input", default: defaults?.l1Chain?.explorerUrl, required: false, validate: (input) => { if (input) { return isUrl(input); } return true; }, }, ]); const l1Chain = { id: parseInt(l1_id), name: l1_name, network: l1_network, rpcUrl: l1_rpcUrl, explorerUrl: l1_explorerUrl || undefined, }; newChain.l1Chain = l1Chain; } saveChains([newChain, ...chains.filter((e) => e.network !== defaults?.network)]); Logger.info(`${chalk.greenBright("✔")} Chain "${name}" saved`); return newChain; }; const promptDeleteChain = async (chain) => { const { confirm } = await inquirer.prompt([ { message: `Are you sure you want to delete chain - "${chain.name}"?`, name: "confirm", type: "confirm", required: true, }, ]); if (confirm) { saveChains(getChains().filter((e) => e.network !== chain.network)); Logger.info(`${chalk.greenBright("✔")} Chain "${chain.name}" deleted`); } }; const promptAskChainAction = async (chain) => { // ask delete or edit const { action } = await inquirer.prompt([ { message: "What do you want to do?", name: "action", type: "list", choices: [ { name: "Edit", value: "edit", }, { name: "Delete", value: "delete", }, ], required: true, }, ]); if (action === "edit") { await promptAddNewChain(chain); } else if (action === "delete") { await promptDeleteChain(chain); } }; export const handler = async () => { try { const chains = getChains(); const { chain } = await inquirer.prompt([ { message: "Select a chain", name: "chain", type: "list", choices: [ ...chains.map((chain) => ({ name: chain.name + chalk.gray(` - ${chain.network}`), short: chain.network, value: chain.network, })), ...(chains.length > 0 ? [{ type: "separator" }] : []), { name: chalk.greenBright("+") + " Add new chain", short: "Add new chain", value: "add-new-chain", }, ], required: true, }, ]); if (chain === "add-new-chain") { await promptAddNewChain(); } else { const selectedChain = chains.find((c) => c.network === chain); await promptAskChainAction(selectedChain); } } catch (error) { Logger.error("There was an error while configuring chains:"); Logger.error(error); } }; Program.command("chains").description("Add or edit available CLI chains").action(handler); //# sourceMappingURL=chains.js.map