caravan-x
Version:
A terminal-based utility for managing Caravan multisig wallets in regtest mode. This tool simplifies development and testing with Caravan by providing an easy-to-use interface
864 lines (862 loc) ⢠36.6 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MainMenu = void 0;
const prompts_1 = require("@inquirer/prompts");
const chalk_1 = __importDefault(require("chalk"));
const figlet_1 = __importDefault(require("figlet"));
const fs = __importStar(require("fs-extra"));
const gradient_string_1 = __importDefault(require("gradient-string"));
const ora_1 = __importDefault(require("ora"));
// Define a consistent color scheme
const colors = {
primary: chalk_1.default.hex("#F7931A"), // Bitcoin orange
secondary: chalk_1.default.hex("#1C2C5B"), // Dark blue
accent: chalk_1.default.hex("#00ACED"), // Light blue
success: chalk_1.default.hex("#28a745"), // Green
warning: chalk_1.default.hex("#ffc107"), // Yellow
error: chalk_1.default.hex("#dc3545"), // Red
info: chalk_1.default.hex("#17a2b8"), // Teal
muted: chalk_1.default.hex("#6c757d"), // Gray
header: chalk_1.default.bold.hex("#F7931A"), // Bold orange for headers
commandName: chalk_1.default.bold.hex("#0095d5"), // Bold dark blue for command names
};
/**
* Main menu interface
*/
class MainMenu {
constructor(app) {
// Menu categories
this.mainMenuCategories = [
{ name: colors.header("š¦ Bitcoin Wallets"), value: "bitcoin-wallets" },
{ name: colors.header("š Caravan Multisig"), value: "caravan-multisig" },
{ name: colors.header("šø Transactions"), value: "transactions" },
{ name: colors.header("š Blockchain Scripts"), value: "scripts" },
{ name: colors.header("āæ Visualization"), value: "visualization" },
{ name: colors.header("āļø System"), value: "system" },
{ name: colors.header("ā Help"), value: "help" },
{ name: colors.header("šŖ Exit"), value: "exit" },
];
// Submenu items
this.subMenus = {
"bitcoin-wallets": [
{ name: colors.commandName("List all wallets"), value: "list-wallets" },
{ name: colors.commandName("Create new wallet"), value: "create-wallet" },
// {
// name: colors.commandName("Create wallet with private key"),
// value: "create-key-wallet",
// },
{
name: colors.commandName("View wallet details"),
value: "wallet-details",
},
{
name: colors.commandName("Send funds between wallets"),
value: "send-funds",
},
{
name: colors.commandName("Fund wallet with regtest coins"),
value: "fund-wallet",
},
{ name: colors.muted("Back to main menu"), value: "back" },
],
"caravan-multisig": [
{
name: colors.commandName("List Caravan wallets"),
value: "list-caravan",
},
{
name: colors.commandName("Create new Caravan multisig wallet"),
value: "create-caravan",
},
{
name: colors.commandName("Spend from Caravan multisig wallet"),
value: "spend-caravan",
},
{
name: colors.commandName("Sign Caravan PSBT for import"),
value: "sign-caravan-psbt",
},
{
name: colors.commandName("Fund Caravan multisig wallet"),
value: "fund-caravan",
},
{
name: colors.commandName("View Caravan wallet details"),
value: "caravan-details",
},
{
name: colors.commandName("Create watch-only wallet for Caravan"),
value: "create-watch",
},
// {
// name: colors.commandName("Configure private keys for Caravan wallet"),
// value: "configure-keys",
// },
{ name: colors.muted("Back to main menu"), value: "back" },
],
transactions: [
{ name: colors.commandName("Create new PSBT"), value: "create-psbt" },
{
name: colors.commandName("Sign PSBT with wallet"),
value: "sign-psbt-wallet",
},
{
name: colors.commandName("Sign PSBT with private key"),
value: "sign-psbt-key",
},
{
name: colors.commandName("Analyze and decode PSBT"),
value: "analyze-psbt",
},
{
name: colors.commandName("Finalize and broadcast PSBT"),
value: "finalize-psbt",
},
{ name: colors.muted("Back to main menu"), value: "back" },
],
scripts: [
{
name: colors.commandName("Browse script templates"),
value: "list-templates",
},
{
name: colors.commandName("Create a new script"),
value: "create-script",
},
{ name: colors.commandName("Run a script"), value: "run-script" },
{
name: colors.commandName("Manage saved scripts"),
value: "manage-scripts",
},
{ name: colors.muted("Back to main menu"), value: "back" },
],
visualization: [
{
name: colors.commandName("Start blockchain visualization"),
value: "start-visualization",
},
{
name: colors.commandName("Stop blockchain visualization"),
value: "stop-visualization",
},
{
name: colors.commandName("Simulate blockchain activity"),
value: "simulate-blockchain",
},
{ name: colors.muted("Back to main menu"), value: "back" },
],
system: [
{
name: colors.commandName("Mining and block generation"),
value: "mining",
},
{ name: colors.commandName("Export data"), value: "export" },
{ name: colors.commandName("Import data"), value: "import" },
{ name: colors.commandName("Settings"), value: "settings" },
{ name: colors.muted("Back to main menu"), value: "back" },
],
};
// Add this as a backup
this.originalCaravanLogo = `
${colors.primary(" ______ ")}
${colors.primary(" / ____/___ __________ __ _____ ____ ")}
${colors.primary(" / / / __ \`/ ___/ __ \`/ | / / _ \\/ __ \\ ")}
${colors.primary("/ /___/ /_/ / / / /_/ /| |/ / /_/ / / / / ")}
${colors.primary("\\____/\\__,_/_/ \\__,_/ |___/\\__,_/_/ /_/ ")}
${colors.accent("========== R E G T E S T M O D E ==========")}
`;
this.app = app;
}
/**
* Centralized error handling method
* Displays error to user and provides option to return to main menu
*/
async handleError(error, context) {
console.clear();
console.log(this.getErrorBox(error, context));
await (0, prompts_1.input)({ message: "Press Enter to return to main menu..." });
}
/**
* Create a formatted error box
*/
getErrorBox(error, context) {
const errorMessage = error.message || String(error);
const lines = [
colors.error(`ā ļø Error in ${context}`),
"",
colors.error(errorMessage),
"",
colors.muted("Check your inputs and Bitcoin Core connection"),
colors.muted("Press Enter to return to the main menu"),
];
// Calculate box width based on the longest line
const width = Math.max(...lines.map((line) => line.length)) + 4;
// Create the box
let box = "\n" + "ā" + "ā".repeat(width) + "ā\n";
// Add each line to the box
lines.forEach((line) => {
const padding = " ".repeat(Math.floor((width - line.length) / 2));
box +=
"ā" +
padding +
line +
" ".repeat(width - line.length - padding.length) +
"ā\n";
});
// Close the box
box += "ā" + "ā".repeat(width) + "ā\n";
return box;
}
/**
* Display the Caravan logo
*/
displayLogo() {
try {
// Create a gradient using Bitcoin orange to blue
const logoGradient = (0, gradient_string_1.default)(["#F7931A", "#F7931A", "#00ACED"]);
// Generate the figlet text
const figletText = figlet_1.default.textSync("Caravan", {
font: "Big",
horizontalLayout: "default",
verticalLayout: "default",
width: 80,
whitespaceBreak: true,
});
// Apply the gradient to the figlet text
const gradientText = logoGradient(figletText);
// Output the gradient text
console.log(gradientText);
// Add the subtitle with accent color
console.log(colors.accent("========== R E G T E S T M O D E =========="));
console.log(colors.muted("A terminal-based utility for Caravan in regtest mode\n"));
}
catch (error) {
// If figlet fails, fall back to the original ASCII art
console.log(this.originalCaravanLogo);
}
}
/**
* Execute an async task with a loading spinner
*/
async withSpinner(message, task, context = "operation") {
const spinner = (0, ora_1.default)({
text: message,
color: "yellow",
}).start();
try {
const result = await task();
spinner.succeed(colors.success(message + " - Complete"));
return result;
}
catch (error) {
spinner.fail(colors.error(message + " - Failed"));
await this.handleError(error, context);
throw error;
}
}
/**
* Handle paginated output display
*/
async displayPaginatedOutput(text, pageSize = 15) {
const lines = text.split("\n");
const pages = [];
for (let i = 0; i < lines.length; i += pageSize) {
pages.push(lines.slice(i, i + pageSize).join("\n"));
}
if (pages.length <= 1) {
console.log(text);
return;
}
let currentPage = 0;
while (currentPage < pages.length) {
console.clear();
console.log(pages[currentPage]);
console.log(colors.muted(`\nPage ${currentPage + 1}/${pages.length}`));
if (currentPage < pages.length - 1) {
const action = await (0, prompts_1.select)({
message: "Navigation:",
choices: [
{ name: "Next page", value: "next" },
{
name: "Previous page",
value: "prev",
disabled: currentPage === 0,
},
{ name: "Exit", value: "exit" },
],
});
if (action === "exit")
break;
if (action === "next")
currentPage++;
if (action === "prev")
currentPage--;
}
else {
await (0, prompts_1.input)({ message: "Press Enter to continue..." });
break;
}
}
}
/**
* Show the main menu and process user selection
*/
async showMainMenu() {
let exit = false;
while (!exit) {
console.clear(); // Clear the console before displaying the menu
this.displayLogo();
try {
const category = await (0, prompts_1.select)({
message: "What would you like to do?",
pageSize: 10,
choices: this.mainMenuCategories,
});
if (category === "exit") {
console.log(colors.success("\nThank you for using Caravan Regtest Manager. Goodbye!"));
process.exit(0);
}
if (category === "help") {
await this.showHelp();
await (0, prompts_1.input)({ message: "Press Enter to continue..." });
continue;
}
// Show submenu for selected category
await this.showSubMenu(category);
}
catch (error) {
await this.handleError(error, "main menu");
}
}
}
/**
* Show submenu for a selected category
*/
async showSubMenu(category) {
try {
//@ts-ignore
const subMenu = this.subMenus[category];
if (!subMenu)
return;
console.clear();
this.displayLogo();
console.log(colors.header(`\n=== ${this.getCategoryTitle(category)} ===\n`));
const action = await (0, prompts_1.select)({
message: "Select an action:",
pageSize: 10,
choices: subMenu,
});
if (action === "back")
return;
//@ts-ignore
await this.processAction(action, category);
// Wait for user to press Enter before showing the menu again
await (0, prompts_1.input)({ message: "Press Enter to continue..." });
}
catch (error) {
await this.handleError(error, this.getCategoryTitle(category));
}
}
/**
* Get readable title for a category
*/
getCategoryTitle(category) {
switch (category) {
case "bitcoin-wallets":
return "Bitcoin Wallets";
case "caravan-multisig":
return "Caravan Multisig";
case "transactions":
return "Transactions";
case "system":
return "System";
default:
return category;
}
}
/**
* Process the selected menu action
*/
async processAction(action, category) {
try {
switch (action) {
// Bitcoin Wallets
case "list-wallets":
await this.withSpinner("Listing wallets", async () => {
const result = await this.app.walletCommands.listWallets();
return result;
});
break;
case "create-wallet":
await this.app.walletCommands.createWallet();
break;
// case "create-key-wallet":
// await this.app.walletCommands.createPrivateKeyWallet();
// break;
case "wallet-details":
await this.app.walletCommands.showWalletDetails();
break;
case "send-funds":
await this.app.walletCommands.sendFunds();
break;
case "fund-wallet":
await this.app.walletCommands.fundWallet();
break;
// Caravan Multisig
case "list-caravan":
await this.withSpinner("Listing Caravan wallets", async () => {
const result = await this.app.multisigCommands.listCaravanWallets();
return result;
});
break;
case "create-caravan":
await this.app.multisigCommands.createCaravanWallet();
break;
case "spend-caravan":
await this.app.multisigCommands.spendFromCaravanWallet();
break;
case "sign-caravan-psbt":
await this.app.multisigCommands.signCaravanPSBT();
break;
case "caravan-details":
await this.app.multisigCommands.showCaravanWalletDetails();
break;
case "create-watch":
await this.app.multisigCommands.createWatchWallet();
break;
case "fund-caravan":
await this.app.multisigCommands.fundCaravanWallet();
break;
// Transactions
case "create-psbt":
await this.app.transactionCommands.createPSBT();
break;
case "sign-psbt-wallet":
await this.app.transactionCommands.signPSBTWithWallet();
break;
case "sign-psbt-key":
await this.app.transactionCommands.signPSBTWithPrivateKey();
break;
case "analyze-psbt":
await this.app.transactionCommands.analyzePSBT();
break;
case "finalize-psbt":
await this.app.transactionCommands.finalizeAndBroadcastPSBT();
break;
// Blockchain Scripts
case "list-templates":
await this.app.scriptCommands.listScriptTemplates();
break;
case "create-script":
await this.app.scriptCommands.createNewScript();
break;
case "run-script":
await this.app.scriptCommands.runCustomScript();
break;
case "manage-scripts":
await this.app.scriptCommands.manageScripts();
break;
// Visualization
case "start-visualization":
await this.app.visualizationCommands.startVisualization();
break;
case "stop-visualization":
await this.app.visualizationCommands.stopVisualization();
break;
case "simulate-blockchain":
await this.app.visualizationCommands.simulateBlockchain();
break;
// System
case "mining":
await this.miningMenu();
break;
case "export":
await this.exportMenu();
break;
case "import":
await this.importMenu();
break;
case "settings":
await this.settingsMenu();
break;
default:
console.log(colors.warning(`Action '${action}' not implemented yet.`));
}
}
catch (error) {
// Make sure all spinners are stopped here too
(0, ora_1.default)().stop();
process.stdout.write("\r\x1b[K");
await this.handleError(error, `${this.getCategoryTitle(category)} > ${action}`);
}
}
/**
* Mining options menu
*/
async miningMenu() {
console.clear();
this.displayLogo();
console.log(colors.header("\n=== Mining Options ===\n"));
const action = await (0, prompts_1.select)({
message: "Select mining action:",
choices: [
{
name: colors.commandName("Generate blocks to a wallet"),
value: "mine-to-wallet",
},
{
name: colors.commandName("Generate blocks to an address"),
value: "mine-to-address",
},
{ name: colors.muted("Back to main menu"), value: "back" },
],
});
if (action === "back") {
return;
}
if (action === "mine-to-wallet") {
// List wallets to select from
const walletsResult = await this.withSpinner("Loading wallets", async () => {
return await this.app.walletCommands.listWallets();
});
// Check if we got a valid array of wallets
const wallets = Array.isArray(walletsResult) ? walletsResult : [];
if (wallets.length === 0) {
console.log(colors.warning("\nNo wallets found. Create a wallet first."));
return;
}
const wallet = await (0, prompts_1.select)({
message: "Select a wallet to mine to:",
choices: wallets.map((w) => ({ name: w, value: w })),
});
const blocks = await (0, prompts_1.number)({
message: "How many blocks do you want to mine?",
default: 1,
validate: (input) => input > 0 ? true : "Please enter a positive number",
});
await this.withSpinner(`Mining ${blocks} blocks to ${wallet}`, async () => {
return await this.app.walletCommands.fundWallet(wallet);
});
}
else if (action === "mine-to-address") {
const address = await (0, prompts_1.input)({
message: "Enter destination address:",
validate: (input) => input.trim() !== "" ? true : "Please enter a valid address",
});
const blocks = await (0, prompts_1.number)({
message: "How many blocks do you want to mine?",
default: 1,
validate: (input) => input > 0 ? true : "Please enter a positive number",
});
console.log(colors.info(`\nMining ${blocks} block(s) to address ${address}...`));
try {
const minedBlocks = await this.withSpinner(`Mining ${blocks} blocks`, async () => {
return await this.app.bitcoinService.generateToAddress(blocks, address);
});
console.log(colors.success(`\nSuccessfully mined ${minedBlocks.length} block(s)!`));
console.log(colors.success(`Latest block hash: ${minedBlocks[minedBlocks.length - 1]}`));
}
catch (error) {
await this.handleError(error, "mining menu");
}
}
}
/**
* Export menu
*/
async exportMenu() {
try {
console.clear();
this.displayLogo();
console.log(colors.header("\n=== Export Options ===\n"));
const action = await (0, prompts_1.select)({
message: "Select export option:",
choices: [
{
name: colors.commandName("Export Caravan wallet configuration"),
value: "export-caravan",
},
{ name: colors.commandName("Export key data"), value: "export-keys" },
{ name: colors.muted("Back to main menu"), value: "back" },
],
});
if (action === "back") {
return;
}
if (action === "export-caravan") {
const wallets = await this.withSpinner("Loading Caravan wallets", async () => {
return await this.app.multisigCommands.listCaravanWallets();
});
if (wallets.length === 0) {
console.log(colors.warning("\nNo Caravan wallets found."));
return;
}
const walletIndex = await (0, prompts_1.select)({
message: "Select a Caravan wallet to export:",
choices: wallets.map((w, i) => ({ name: w.name, value: i })),
});
const selectedWallet = wallets[walletIndex];
const filename = await (0, prompts_1.input)({
message: "Enter export file name:",
default: `${selectedWallet.name.replace(/\s+/g, "_")}_export.json`,
});
await this.withSpinner(`Exporting wallet to ${filename}`, async () => {
await fs.writeJson(filename, selectedWallet, { spaces: 2 });
return true;
});
console.log(colors.success(`\nCaravan wallet exported to ${filename}`));
}
}
catch (error) {
await this.handleError(error, "export menu");
}
}
/**
* Import menu
*/
async importMenu() {
try {
console.clear();
this.displayLogo();
console.log(colors.header("\n=== Import Options ===\n"));
const action = await (0, prompts_1.select)({
message: "Select import option:",
choices: [
{
name: colors.commandName("Import Caravan wallet configuration"),
value: "import-caravan",
},
{ name: colors.commandName("Import key data"), value: "import-keys" },
{ name: colors.muted("Back to main menu"), value: "back" },
],
});
if (action === "back") {
return;
}
if (action === "import-caravan") {
const filename = await (0, prompts_1.input)({
message: "Enter path to Caravan wallet JSON file:",
validate: (input) => fs.existsSync(input) ? true : "File does not exist",
});
const config = await this.withSpinner("Reading wallet configuration", async () => {
return await fs.readJson(filename);
});
if (!config.name || !config.quorum || !config.extendedPublicKeys) {
console.log(colors.error("\nInvalid Caravan wallet configuration."));
return;
}
console.log(colors.info(`\nImporting Caravan wallet "${config.name}"...`));
const savedFileName = await this.withSpinner("Saving wallet configuration", async () => {
return await this.app.caravanService.saveCaravanWalletConfig(config);
});
console.log(colors.success(`\nCaravan wallet imported successfully as ${savedFileName}!`));
// Ask if user wants to create a watch-only wallet
const createWatch = await (0, prompts_1.confirm)({
message: "Create a watch-only wallet for this multisig wallet?",
default: true,
});
if (createWatch) {
await this.app.multisigCommands.createWatchWallet(config);
}
}
else if (action === "import-keys") {
const filename = await (0, prompts_1.input)({
message: "Enter path to key data JSON file:",
validate: (input) => fs.existsSync(input) ? true : "File does not exist",
});
const keyData = await this.withSpinner("Reading key data", async () => {
return await fs.readJson(filename);
});
if (!keyData.caravanName || !keyData.keyData) {
console.log(colors.error("\nInvalid key data file."));
return;
}
console.log(colors.info(`\nImporting key data for wallet "${keyData.caravanName}"...`));
// Check if the wallet exists
const wallets = await this.withSpinner("Checking wallets", async () => {
return await this.app.multisigCommands.listCaravanWallets();
});
const caravanWallet = wallets.find((w) => w.name === keyData.caravanName);
if (!caravanWallet) {
console.log(colors.warning(`\nWallet "${keyData.caravanName}" not found.`));
console.log(colors.warning("Import the wallet configuration first."));
return;
}
}
}
catch (error) {
await this.handleError(error, "import menu");
}
}
/**
* Settings menu
*/
async settingsMenu() {
try {
console.clear();
this.displayLogo();
console.log(colors.header("\n=== Settings ===\n"));
const action = await (0, prompts_1.select)({
message: "Settings options:",
choices: [
{
name: colors.commandName("Update Bitcoin Core connection settings"),
value: "update-bitcoin",
},
{
name: colors.commandName("Change application directories"),
value: "update-dirs",
},
{
name: colors.commandName("View current configuration"),
value: "view-config",
},
{ name: colors.muted("Back to main menu"), value: "back" },
],
});
if (action === "back")
return;
if (action === "update-bitcoin") {
await this.app.setupBitcoinConfig();
}
else if (action === "update-dirs") {
await this.updateAppDirectories();
}
else if (action === "view-config") {
this.displayCurrentConfig();
}
}
catch (error) {
await this.handleError(error, "settings menu");
}
}
async updateAppDirectories() {
try {
const config = this.app.configManager.getConfig();
console.log(colors.header("\n=== Update Application Directories ===\n"));
const appDir = await (0, prompts_1.input)({
message: "Enter application directory:",
default: config.appDir,
});
const caravanDir = await (0, prompts_1.input)({
message: "Enter Caravan wallets directory:",
default: config.caravanDir,
});
const keysDir = await (0, prompts_1.input)({
message: "Enter keys directory:",
default: config.keysDir,
});
await this.withSpinner("Updating directories", async () => {
await this.app.configManager.updateDirectories({
appDir,
caravanDir,
keysDir,
});
return true;
});
console.log(colors.success("\nDirectories updated successfully!"));
}
catch (error) {
await this.handleError(error, "directory update");
}
}
displayCurrentConfig() {
const config = this.app.configManager.getConfig();
console.clear();
this.displayLogo();
console.log(colors.header("\n=== Current Configuration ===\n"));
console.log(colors.header("\nBitcoin RPC Settings:"));
console.log(colors.info(`Protocol: ${config.bitcoin.protocol}`));
console.log(colors.info(`Host: ${config.bitcoin.host}`));
console.log(colors.info(`Port: ${config.bitcoin.port}`));
console.log(colors.info(`User: ${config.bitcoin.user}`));
console.log(colors.info(`Data Directory: ${config.bitcoin.dataDir}`));
console.log(colors.header("\nApplication Directories:"));
console.log(colors.info(`App Directory: ${config.appDir}`));
console.log(colors.info(`Caravan Directory: ${config.caravanDir}`));
console.log(colors.info(`Keys Directory: ${config.keysDir}`));
}
/**
* Show help information
*/
async showHelp() {
try {
console.clear();
this.displayLogo();
console.log(colors.header("\n=== Caravan Regtest Manager Help ===\n"));
console.log(colors.header("\nš¦ Bitcoin Wallets:"));
console.log(colors.info("- Manage regular Bitcoin wallets in regtest mode"));
console.log(colors.info("- Create wallets, check balances, send funds"));
console.log(colors.info("- Fund wallets by mining new blocks"));
console.log(colors.header("\nš Caravan Multisig:"));
console.log(colors.info("- Create and manage Caravan multisig wallet configurations"));
console.log(colors.info("- Set up watch-only wallets for multisig addresses"));
console.log(colors.info("- Configure private keys for signing"));
console.log(colors.header("\nšø Transactions:"));
console.log(colors.info("- Create, sign, and broadcast transactions"));
console.log(colors.info("- Work with PSBTs (Partially Signed Bitcoin Transactions)"));
console.log(colors.info("- Sign with wallets or individual private keys"));
console.log(colors.header("\nā ļø Important Notes:"));
console.log(colors.warning("1. This tool is designed for regtest mode only (not for mainnet)"));
console.log(colors.warning("2. Bitcoin Core must be running in regtest mode"));
console.log(colors.warning("3. Private keys should be kept secure"));
console.log(colors.warning("4. Use Caravan for real multisig wallet management"));
console.log(colors.header("\nš Useful Resources:"));
console.log(colors.info("- Caravan: https://github.com/caravan-bitcoin/caravan"));
console.log(colors.info("- Bitcoin Core: https://bitcoin.org/en/bitcoin-core/"));
console.log(colors.info("- Bitcoin Development: https://bitcoin.org/en/development"));
}
catch (error) {
await this.handleError(error, "help menu");
}
}
/**
* Start the main menu interface
*/
async start() {
try {
await this.showMainMenu();
}
catch (error) {
await this.handleError(error, "application startup");
process.exit(1);
}
}
}
exports.MainMenu = MainMenu;