@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/README.md +247 -40
- package/assets/dark-logo.png +0 -0
- package/assets/logo-dark.svg +73 -0
- package/assets/logo-light.svg +73 -0
- package/bin/consensus.js +188 -151
- package/dist/index.js +2 -0
- package/dist/proxy-client.js +297 -0
- package/dist/socket-client.js +317 -0
- package/index.d.ts +134 -0
- package/package.json +23 -3
- package/assets/setup.gif +0 -0
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
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
187
|
-
|
|
216
|
+
async createWallets() {
|
|
217
|
+
const spinner = ora("Creating multi-chain CDP wallets...").start();
|
|
188
218
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
219
|
+
try {
|
|
220
|
+
const cdp = new CdpClient();
|
|
221
|
+
const walletName = this.generateWalletName();
|
|
192
222
|
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
228
|
+
const evmViemAccount = toAccount(evmAccount);
|
|
197
229
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
210
|
-
|
|
245
|
+
async registerWithProxy(walletName, evmAddress, solanaAddress) {
|
|
246
|
+
const spinner = ora("Registering with x402 proxy...").start();
|
|
211
247
|
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
251
|
-
|
|
279
|
+
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
280
|
+
}
|
|
252
281
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
269
|
-
|
|
303
|
+
try {
|
|
304
|
+
console.log(chalk.blue.bold("Consensus SDK Setup\n"));
|
|
270
305
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
306
|
+
if (!this.validateEnvironment()) {
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
274
309
|
|
|
275
|
-
|
|
276
|
-
|
|
310
|
+
const forceFlag = process.argv.includes("--force");
|
|
311
|
+
const shouldSkip = await this.checkExistingSetup(forceFlag);
|
|
277
312
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
313
|
+
if (shouldSkip) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
281
316
|
|
|
282
|
-
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
this.
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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