Monorepo for Aesthetic.Computer
aesthetic.computer
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});