@canister-software/consensus-cli 0.1.0-beta.2 → 0.1.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/consensus.js CHANGED
@@ -48,6 +48,25 @@ class ConsensusSDK {
48
48
  constructor() {
49
49
  this.configPath = path.join(process.cwd(), ".consensus-config.json");
50
50
  this.x402ProxyUrl = process.env.X402_PROXY_URL || "https://consensus.proxy.canister.software:3001";
51
+ this.extractPrivateKey = function extractPrivateKey(privateKeyData, keyType = "EVM") {
52
+ if (typeof privateKeyData === "string") {
53
+ if (keyType === "EVM") {
54
+ return privateKeyData.startsWith("0x") ? privateKeyData : `0x${privateKeyData}`;
55
+ }
56
+ return privateKeyData;
57
+ }
58
+
59
+ if (privateKeyData?.privateKey) {
60
+ if (keyType === "EVM") {
61
+ return privateKeyData.privateKey.startsWith("0x")
62
+ ? privateKeyData.privateKey
63
+ : `0x${privateKeyData.privateKey}`;
64
+ }
65
+ return privateKeyData.privateKey;
66
+ }
67
+
68
+ throw new Error(`Unexpected ${keyType} private key format from CDP`);
69
+ }
51
70
  }
52
71
 
53
72
  generateWalletName() {
@@ -116,46 +135,57 @@ class ConsensusSDK {
116
135
  }
117
136
 
118
137
  async checkExistingSetup(forceFlag) {
119
- const config = this.loadConfig();
138
+ const config = this.loadConfig();
139
+
140
+ if (config) {
141
+ console.log(chalk.yellow("⚠️ Existing Consensus setup found!"));
142
+ console.log(chalk.cyan("Wallet Name:"), config.wallet_name);
143
+
144
+ if (config.addresses?.evm) {
145
+ console.log(chalk.cyan("EVM Address:"), config.addresses.evm);
146
+ }
147
+ if (config.addresses?.solana) {
148
+ console.log(chalk.cyan("Solana Address:"), config.addresses.solana);
149
+ }
120
150
 
121
- if (config) {
122
- console.log(chalk.yellow("⚠️ Existing Consensus setup found!"));
123
- console.log(chalk.cyan("Account Name:"), config.wallet_name);
151
+ if (config.account_address && !config.addresses) {
124
152
  console.log(chalk.cyan("Account Address:"), config.account_address);
125
- console.log(chalk.cyan("Setup Date:"), config.setup_date);
126
-
127
- if (!forceFlag) {
128
- const { action } = await inquirer.prompt([
129
- {
130
- type: "list",
131
- name: "action",
132
- message: "What would you like to do?",
133
- choices: [
134
- { name: "Keep existing setup", value: "keep" },
135
- { name: "Create new setup (reset)", value: "reset" },
136
- { name: "Exit", value: "exit" },
137
- ],
138
- },
139
- ]);
140
-
141
- if (action === "keep") {
142
- console.log(chalk.green("Using existing setup"));
143
- return true;
144
- }
145
- if (action === "exit") {
146
- process.exit(0);
147
- }
148
- if (action === "reset") {
149
- return this.confirmReset();
150
- }
151
- } else {
153
+ }
154
+
155
+ console.log(chalk.cyan("Setup Date:"), config.setup_date);
156
+
157
+ if (!forceFlag) {
158
+ const { action } = await inquirer.prompt([
159
+ {
160
+ type: "list",
161
+ name: "action",
162
+ message: "What would you like to do?",
163
+ choices: [
164
+ { name: "Keep existing setup", value: "keep" },
165
+ { name: "Create new setup (reset)", value: "reset" },
166
+ { name: "Exit", value: "exit" },
167
+ ],
168
+ },
169
+ ]);
170
+
171
+ if (action === "keep") {
172
+ console.log(chalk.green("Using existing setup"));
173
+ return true;
174
+ }
175
+ if (action === "exit") {
176
+ process.exit(0);
177
+ }
178
+ if (action === "reset") {
152
179
  return this.confirmReset();
153
180
  }
181
+ } else {
182
+ return this.confirmReset();
154
183
  }
155
-
156
- return false;
157
184
  }
158
185
 
186
+ return false;
187
+ }
188
+
159
189
  async confirmReset() {
160
190
  console.log(
161
191
  chalk.red(
@@ -183,145 +213,152 @@ class ConsensusSDK {
183
213
  return false;
184
214
  }
185
215
 
186
- async createWallet() {
187
- const spinner = ora("Creating CDP wallet...").start();
216
+ async createWallets() {
217
+ const spinner = ora("Creating multi-chain CDP wallets...").start();
188
218
 
189
- try {
190
- const cdp = new CdpClient();
191
- const walletName = this.generateWalletName();
219
+ try {
220
+ const cdp = new CdpClient();
221
+ const walletName = this.generateWalletName();
192
222
 
193
- const cdpAccount = await cdp.evm.createAccount({ name: walletName });
194
- const account = toAccount(cdpAccount);
223
+ const [evmAccount, solanaAccount] = await Promise.all([
224
+ cdp.evm.createAccount({ name: `${walletName}-evm` }),
225
+ cdp.solana.createAccount({ name: `${walletName}-solana` })
226
+ ]);
195
227
 
196
- spinner.succeed("CDP wallet created");
228
+ const evmViemAccount = toAccount(evmAccount);
197
229
 
198
- return {
199
- wallet_name: walletName,
200
- account_address: account.address,
201
- cdpAccount: cdpAccount,
202
- };
203
- } catch (error) {
204
- spinner.fail("Failed to create CDP wallet");
205
- throw new Error(`Wallet creation failed: ${error.message}`);
206
- }
230
+ spinner.succeed("Multi-chain wallets created");
231
+
232
+ return {
233
+ wallet_name: walletName,
234
+ evm_account: evmAccount,
235
+ evm_address: evmViemAccount.address,
236
+ solana_account: solanaAccount,
237
+ solana_address: solanaAccount.address,
238
+ };
239
+ } catch (error) {
240
+ spinner.fail("Failed to create wallets");
241
+ throw new Error(`Wallet creation failed: ${error.message}`);
207
242
  }
243
+ }
208
244
 
209
- async registerWithProxy(walletName, accountAddress, cdpAccount) {
210
- const spinner = ora("Registering with x402 proxy...").start();
245
+ async registerWithProxy(walletName, evmAddress, solanaAddress) {
246
+ const spinner = ora("Registering with x402 proxy...").start();
211
247
 
212
- try {
213
- const cdp = new CdpClient();
214
- const privateKeyData = await cdp.evm.exportAccount({ name: walletName });
215
-
216
- let privateKey;
217
- if (typeof privateKeyData === "string") {
218
- privateKey = privateKeyData.startsWith("0x")
219
- ? privateKeyData
220
- : `0x${privateKeyData}`;
221
- } else if (privateKeyData && privateKeyData.privateKey) {
222
- privateKey = privateKeyData.privateKey.startsWith("0x")
223
- ? privateKeyData.privateKey
224
- : `0x${privateKeyData.privateKey}`;
225
- } else {
226
- throw new Error("Unexpected private key format from CDP");
227
- }
248
+ try {
249
+ const cdp = new CdpClient();
228
250
 
229
- const response = await fetch(`${this.x402ProxyUrl}/register-wallet`, {
230
- method: "POST",
231
- headers: {
232
- "Content-Type": "application/json",
233
- },
234
- body: JSON.stringify({
235
- wallet_name: walletName,
236
- account_address: accountAddress,
237
- private_key: privateKey,
238
- }),
239
- });
240
-
241
- if (!response.ok) {
242
- const error = await response
243
- .json()
244
- .catch(() => ({ error: "Unknown error" }));
245
- throw new Error(
246
- error.error || `Registration failed: ${response.status}`
247
- );
251
+ const [evmPrivateKeyData, solanaPrivateKeyData] = await Promise.all([
252
+ cdp.evm.exportAccount({ name: `${walletName}-evm` }),
253
+ cdp.solana.exportAccount({ name: `${walletName}-solana` })
254
+ ]);
255
+
256
+ const evmPrivateKey = this.extractPrivateKey(evmPrivateKeyData, "EVM");
257
+ const solanaPrivateKey = this.extractPrivateKey(solanaPrivateKeyData, "Solana");
258
+
259
+ const response = await fetch(`${this.x402ProxyUrl}/register-wallet`, {
260
+ method: "POST",
261
+ headers: { "Content-Type": "application/json" },
262
+ body: JSON.stringify({
263
+ wallet_name: walletName,
264
+ evm: { address: evmAddress, private_key: evmPrivateKey },
265
+ solana: { address: solanaAddress, private_key: solanaPrivateKey },
266
+ }),
267
+ });
268
+
269
+ if (!response.ok) {
270
+ const raw = await response.text();
271
+
272
+ let message = raw;
273
+ try {
274
+ const parsed = JSON.parse(raw);
275
+ message = parsed.error || parsed.message || raw;
276
+ } catch {
248
277
  }
249
278
 
250
- const data = await response.json();
251
- spinner.succeed("Registered with x402 proxy");
279
+ throw new Error(`HTTP ${response.status}: ${message}`);
280
+ }
252
281
 
253
- return data.api_key;
254
- } catch (error) {
255
- spinner.fail("Failed to register with x402 proxy");
256
- if (error.message.includes("ECONNREFUSED")) {
257
- throw new Error(
258
- "Cannot connect to x402 proxy. Is it running on " +
259
- this.x402ProxyUrl +
260
- "?"
261
- );
262
- }
263
- throw new Error(`Proxy registration failed: ${error.message}`);
282
+ const data = await response.json();
283
+ spinner.succeed("Registered with x402 proxy");
284
+
285
+ return data.api_key;
286
+
287
+ } catch (error) {
288
+ spinner.fail("Failed to register with x402 proxy");
289
+ if (error.message.includes("ECONNREFUSED")) {
290
+ throw new Error(
291
+ "Cannot connect to x402 proxy. Is it running on " +
292
+ this.x402ProxyUrl +
293
+ "?"
294
+ );
264
295
  }
296
+
297
+ throw error;
265
298
  }
299
+ }
300
+
266
301
 
267
302
  async setup() {
268
- try {
269
- console.log(chalk.blue.bold("Consensus SDK Setup\n"));
303
+ try {
304
+ console.log(chalk.blue.bold("Consensus SDK Setup\n"));
270
305
 
271
- if (!this.validateEnvironment()) {
272
- process.exit(1);
273
- }
306
+ if (!this.validateEnvironment()) {
307
+ process.exit(1);
308
+ }
274
309
 
275
- const forceFlag = process.argv.includes("--force");
276
- const shouldSkip = await this.checkExistingSetup(forceFlag);
310
+ const forceFlag = process.argv.includes("--force");
311
+ const shouldSkip = await this.checkExistingSetup(forceFlag);
277
312
 
278
- if (shouldSkip) {
279
- return;
280
- }
313
+ if (shouldSkip) {
314
+ return;
315
+ }
281
316
 
282
- const { wallet_name, account_address, cdpAccount } =
283
- await this.createWallet();
284
- const api_key = await this.registerWithProxy(
285
- wallet_name,
286
- account_address,
287
- cdpAccount
288
- );
317
+ const { wallet_name, evm_address, solana_address } = await this.createWallets();
289
318
 
290
- const config = {
291
- wallet_name,
292
- account_address,
293
- api_key,
294
- x402_proxy_url: this.x402ProxyUrl,
295
- setup_date: new Date().toISOString(),
296
- version: "1.0.0",
297
- };
298
-
299
- this.saveConfig(config);
300
-
301
- console.log(chalk.green.bold("\n✅ Setup Complete!\n"));
302
- console.log(chalk.cyan("Wallet Name:"), wallet_name);
303
- console.log(chalk.cyan("Account Address:"), account_address);
304
- console.log(chalk.cyan("API Key:"), api_key);
305
- console.log(chalk.cyan("x402 Proxy:"), this.x402ProxyUrl);
306
-
307
- console.log(chalk.yellow("\n📋 Next Steps:"));
308
- console.log("1. Fund your account with USDC on Base Sepolia");
309
- console.log(` Address: ${account_address}`);
310
- console.log("2. Get USDC: https://faucet.circle.com/");
311
- console.log("3. Make API calls using your API key");
312
-
313
- console.log(chalk.blue("\n🔧 Usage Example:"));
314
- console.log(`curl -X POST ${this.x402ProxyUrl}/proxy \\`);
315
- console.log(` -H "X-API-Key: ${api_key}" \\`);
316
- console.log(' -H "Content-Type: application/json" \\');
317
- console.log(
318
- ` -d '{"target_url": "https://api.example.com", "idempotency_key": "unique-key"}'`
319
- );
320
- } catch (error) {
321
- console.error(chalk.red("\n Setup failed:"), error.message);
322
- process.exit(1);
323
- }
319
+ const api_key = await this.registerWithProxy(wallet_name, evm_address, solana_address);
320
+
321
+ const config = {
322
+ wallet_name,
323
+ addresses: {
324
+ evm: evm_address,
325
+ solana: solana_address,
326
+ },
327
+ api_key,
328
+ x402_proxy_url: this.x402ProxyUrl,
329
+ setup_date: new Date().toISOString(),
330
+ version: "2.0.0",
331
+ };
332
+
333
+ this.saveConfig(config);
334
+
335
+ console.log(chalk.green.bold("\n✅ Setup Complete!\n"));
336
+ console.log(chalk.cyan("Wallet Name:"), wallet_name);
337
+ console.log(chalk.cyan("EVM Address:"), evm_address);
338
+ console.log(chalk.cyan("Solana Address:"), solana_address);
339
+ console.log(chalk.cyan("API Key:"), api_key);
340
+ console.log(chalk.cyan("x402 Proxy:"), this.x402ProxyUrl);
341
+
342
+ console.log(chalk.yellow("\n📋 Next Steps:"));
343
+ console.log("1. Fund your wallets:");
344
+ console.log(chalk.dim(" EVM (Base Sepolia):"), evm_address);
345
+ console.log(chalk.dim(" Get USDC: https://faucet.circle.com/"));
346
+ console.log(chalk.dim(" Solana (Devnet):"), solana_address);
347
+ console.log(chalk.dim(" Get SOL: https://faucet.solana.com/"));
348
+ console.log("2. Make API calls using your API key");
349
+
350
+ console.log(chalk.blue("\n🔧 Usage Example:"));
351
+ console.log(`curl -X POST ${this.x402ProxyUrl}/proxy \\`);
352
+ console.log(` -H "X-API-Key: ${api_key}" \\`);
353
+ console.log(' -H "Content-Type: application/json" \\');
354
+ console.log(
355
+ ` -d '{"target_url": "https://api.example.com", "chain": "base"}'`
356
+ );
357
+ } catch (error) {
358
+ console.error(chalk.red("\n❌ Setup failed:"), error.message);
359
+ process.exit(1);
324
360
  }
361
+ }
325
362
 
326
363
  showHelp() {
327
364
  console.log(chalk.blue.bold("Consensus SDK\n"));
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { ProxyClient } from "./proxy-client.js";
2
+ export { SocketClient } from "./socket-client.js";