Monorepo for Aesthetic.Computer aesthetic.computer
at main 204 lines 6.1 kB view raw
1#!/usr/bin/env node 2/** 3 * wallet-pair.mjs - Unified Tezos wallet pairing CLI 4 * 5 * Supports two wallet connection methods: 6 * 1. Temple Wallet (Beacon P2P via Matrix relay) 7 * 2. Kukai Wallet (WalletConnect 2.0) 8 * 9 * Usage: 10 * node wallet-pair.mjs # Interactive menu 11 * node wallet-pair.mjs --temple # Direct Temple pairing 12 * node wallet-pair.mjs --kukai # Direct Kukai pairing 13 */ 14 15import { spawn } from "child_process"; 16import { fileURLToPath } from "url"; 17import { dirname, join } from "path"; 18import readline from "readline"; 19 20const __dirname = dirname(fileURLToPath(import.meta.url)); 21 22// ANSI colors 23const GREEN = "\x1b[32m"; 24const YELLOW = "\x1b[33m"; 25const RED = "\x1b[31m"; 26const CYAN = "\x1b[36m"; 27const DIM = "\x1b[2m"; 28const BOLD = "\x1b[1m"; 29const RESET = "\x1b[0m"; 30 31// Wallet configuration 32const WALLETS = { 33 temple: { 34 name: "Temple Wallet", 35 protocol: "Beacon P2P", 36 script: "beacon-node.mjs", 37 args: ["--pair"], 38 description: "Most popular Tezos browser & mobile wallet" 39 }, 40 kukai: { 41 name: "Kukai Wallet", 42 protocol: "WalletConnect", 43 script: "walletconnect-node.mjs", 44 args: ["--pair"], 45 envRequired: "WALLETCONNECT_PROJECT_ID", 46 description: "Tezos wallet with social login support" 47 } 48}; 49 50/** 51 * Ask a question and return the answer 52 */ 53function askQuestion(query) { 54 const rl = readline.createInterface({ 55 input: process.stdin, 56 output: process.stdout 57 }); 58 59 return new Promise(resolve => { 60 rl.question(query, answer => { 61 rl.close(); 62 resolve(answer.trim()); 63 }); 64 }); 65} 66 67/** 68 * Run a wallet pairing script 69 */ 70function runWalletScript(walletType) { 71 return new Promise((resolve, reject) => { 72 const wallet = WALLETS[walletType]; 73 if (!wallet) { 74 reject(new Error(`Unknown wallet type: ${walletType}`)); 75 return; 76 } 77 78 // Check for required environment variables 79 if (wallet.envRequired && !process.env[wallet.envRequired]) { 80 console.log(`\n${RED}✗ Missing required: ${wallet.envRequired}${RESET}`); 81 if (walletType === "kukai") { 82 console.log(`\n${CYAN}To use WalletConnect (Kukai):${RESET}`); 83 console.log(` 1. Get a free project ID at ${BOLD}https://cloud.walletconnect.com${RESET}`); 84 console.log(` 2. Run: ${DIM}export WALLETCONNECT_PROJECT_ID=your_id_here${RESET}`); 85 console.log(` 3. Try again\n`); 86 } 87 reject(new Error(`Missing ${wallet.envRequired}`)); 88 return; 89 } 90 91 console.log(`\n${CYAN}Starting ${wallet.name} pairing (${wallet.protocol})...${RESET}\n`); 92 93 const scriptPath = join(__dirname, wallet.script); 94 const child = spawn("node", [scriptPath, ...wallet.args], { 95 stdio: "inherit", 96 cwd: __dirname, 97 env: process.env 98 }); 99 100 child.on("close", code => { 101 if (code === 0) { 102 resolve(); 103 } else { 104 reject(new Error(`Pairing exited with code ${code}`)); 105 } 106 }); 107 108 child.on("error", reject); 109 }); 110} 111 112/** 113 * Show interactive menu 114 */ 115async function showMenu() { 116 console.clear(); 117 console.log(`\n${BOLD}════════════════════════════════════════════════════════════════════${RESET}`); 118 console.log(`${BOLD} 🎨 Aesthetic Computer - Tezos Wallet Pairing${RESET}`); 119 console.log(`${BOLD}════════════════════════════════════════════════════════════════════${RESET}\n`); 120 121 console.log(`${CYAN}Choose your wallet:${RESET}\n`); 122 console.log(` ${BOLD}1${RESET} - ${WALLETS.temple.name} ${DIM}(${WALLETS.temple.protocol})${RESET}`); 123 console.log(` ${DIM}${WALLETS.temple.description}${RESET}`); 124 console.log(); 125 console.log(` ${BOLD}2${RESET} - ${WALLETS.kukai.name} ${DIM}(${WALLETS.kukai.protocol})${RESET}`); 126 console.log(` ${DIM}${WALLETS.kukai.description}${RESET}`); 127 console.log(); 128 console.log(` ${BOLD}q${RESET} - Quit\n`); 129 130 const choice = await askQuestion(`${GREEN}Enter choice (1/2/q): ${RESET}`); 131 132 switch (choice.toLowerCase()) { 133 case '1': 134 return 'temple'; 135 case '2': 136 return 'kukai'; 137 case 'q': 138 console.log(`\n${DIM}Goodbye!${RESET}\n`); 139 process.exit(0); 140 default: 141 console.log(`\n${YELLOW}Invalid choice. Please enter 1, 2, or q.${RESET}\n`); 142 return null; 143 } 144} 145 146/** 147 * Main entry point 148 */ 149async function main() { 150 const args = process.argv.slice(2); 151 152 // Handle direct wallet selection via CLI args 153 if (args.includes("--temple") || args.includes("-t")) { 154 await runWalletScript("temple"); 155 return; 156 } 157 158 if (args.includes("--kukai") || args.includes("-k")) { 159 await runWalletScript("kukai"); 160 return; 161 } 162 163 if (args.includes("--help") || args.includes("-h")) { 164 console.log(` 165${BOLD}Tezos Wallet Pairing Tool${RESET} 166 167${CYAN}Usage:${RESET} 168 node wallet-pair.mjs Interactive wallet selection 169 node wallet-pair.mjs --temple Pair with Temple Wallet (Beacon) 170 node wallet-pair.mjs --kukai Pair with Kukai Wallet (WalletConnect) 171 172${CYAN}Supported Wallets:${RESET} 173 ${BOLD}Temple${RESET} - Uses Beacon P2P protocol (Matrix relay) 174 Works with Temple browser extension and mobile app 175 176 ${BOLD}Kukai${RESET} - Uses WalletConnect 2.0 protocol 177 Requires WALLETCONNECT_PROJECT_ID environment variable 178 Get one free at https://cloud.walletconnect.com 179 180${CYAN}Environment Variables:${RESET} 181 WALLETCONNECT_PROJECT_ID Required for Kukai pairing 182 TEZOS_NETWORK Network to use (ghostnet/mainnet) 183`); 184 return; 185 } 186 187 // Interactive menu 188 let walletType = null; 189 while (!walletType) { 190 walletType = await showMenu(); 191 } 192 193 await runWalletScript(walletType); 194} 195 196// Run 197main().catch(err => { 198 // Don't show error for expected exits 199 if (err.message?.includes('Missing')) { 200 process.exit(1); 201 } 202 console.error(`${RED}Error: ${err.message}${RESET}`); 203 process.exit(1); 204});