@sip-protocol/cli 0.1.0 → 0.2.1
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/dist/index.js +1402 -53
- package/dist/index.mjs +1436 -54
- package/package.json +14 -10
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/index.ts
|
|
27
|
-
var
|
|
27
|
+
var import_commander14 = require("commander");
|
|
28
28
|
|
|
29
29
|
// src/commands/init.ts
|
|
30
30
|
var import_commander = require("commander");
|
|
@@ -32,25 +32,24 @@ var import_types = require("@sip-protocol/types");
|
|
|
32
32
|
|
|
33
33
|
// src/utils/config.ts
|
|
34
34
|
var import_conf = __toESM(require("conf"));
|
|
35
|
-
var schema = {
|
|
36
|
-
network: {
|
|
37
|
-
type: "string",
|
|
38
|
-
default: "testnet"
|
|
39
|
-
},
|
|
40
|
-
defaultPrivacy: {
|
|
41
|
-
type: "string",
|
|
42
|
-
default: "transparent"
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
35
|
var store = new import_conf.default({
|
|
46
36
|
projectName: "sip-protocol",
|
|
47
|
-
|
|
37
|
+
defaults: {
|
|
38
|
+
network: "testnet",
|
|
39
|
+
defaultPrivacy: "transparent"
|
|
40
|
+
}
|
|
48
41
|
});
|
|
49
|
-
function getConfig() {
|
|
42
|
+
function getConfig(key) {
|
|
43
|
+
if (key) {
|
|
44
|
+
return store.get(key);
|
|
45
|
+
}
|
|
50
46
|
return {
|
|
51
47
|
network: store.get("network"),
|
|
52
48
|
defaultPrivacy: store.get("defaultPrivacy"),
|
|
53
49
|
defaultChain: store.get("defaultChain"),
|
|
50
|
+
primaryChain: store.get("primaryChain"),
|
|
51
|
+
metaAddress: store.get("metaAddress"),
|
|
52
|
+
viewingKeys: store.get("viewingKeys"),
|
|
54
53
|
rpcEndpoints: store.get("rpcEndpoints")
|
|
55
54
|
};
|
|
56
55
|
}
|
|
@@ -87,6 +86,13 @@ ${message}
|
|
|
87
86
|
function keyValue(key, value) {
|
|
88
87
|
console.log(import_chalk.default.gray(` ${key}:`), import_chalk.default.white(String(value)));
|
|
89
88
|
}
|
|
89
|
+
function json(data) {
|
|
90
|
+
console.log(JSON.stringify(
|
|
91
|
+
data,
|
|
92
|
+
(_, value) => typeof value === "bigint" ? value.toString() : value,
|
|
93
|
+
2
|
|
94
|
+
));
|
|
95
|
+
}
|
|
90
96
|
function spinner(text) {
|
|
91
97
|
return (0, import_ora.default)(text).start();
|
|
92
98
|
}
|
|
@@ -115,6 +121,9 @@ function formatHash(hash, length = 8) {
|
|
|
115
121
|
if (hash.length <= length * 2) return hash;
|
|
116
122
|
return `${hash.slice(0, length)}...${hash.slice(-length)}`;
|
|
117
123
|
}
|
|
124
|
+
function divider() {
|
|
125
|
+
console.log(import_chalk.default.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
126
|
+
}
|
|
118
127
|
|
|
119
128
|
// src/commands/init.ts
|
|
120
129
|
function createInitCommand() {
|
|
@@ -145,35 +154,85 @@ function createInitCommand() {
|
|
|
145
154
|
// src/commands/keygen.ts
|
|
146
155
|
var import_commander2 = require("commander");
|
|
147
156
|
var import_sdk = require("@sip-protocol/sdk");
|
|
157
|
+
var fs = __toESM(require("fs"));
|
|
158
|
+
var path = __toESM(require("path"));
|
|
159
|
+
function formatKeysAsText(data) {
|
|
160
|
+
return [
|
|
161
|
+
`# SIP Stealth Meta-Address Keys`,
|
|
162
|
+
`# Generated: ${data.generatedAt}`,
|
|
163
|
+
`# Chain: ${data.chain}`,
|
|
164
|
+
``,
|
|
165
|
+
`## Public Keys (safe to share)`,
|
|
166
|
+
`SPENDING_PUBLIC_KEY=${data.spendingPublicKey}`,
|
|
167
|
+
`VIEWING_PUBLIC_KEY=${data.viewingPublicKey}`,
|
|
168
|
+
`META_ADDRESS=${data.metaAddress}`,
|
|
169
|
+
``,
|
|
170
|
+
`## Private Keys (KEEP SECRET!)`,
|
|
171
|
+
`SPENDING_PRIVATE_KEY=${data.spendingPrivateKey}`,
|
|
172
|
+
`VIEWING_PRIVATE_KEY=${data.viewingPrivateKey}`,
|
|
173
|
+
``,
|
|
174
|
+
`# WARNING: Delete this file after securely storing the keys!`
|
|
175
|
+
].join("\n");
|
|
176
|
+
}
|
|
148
177
|
function createKeygenCommand() {
|
|
149
|
-
return new import_commander2.Command("keygen").description("Generate stealth meta-address").option("-c, --chain <chain>", "Target chain (ethereum, solana, near)", "ethereum").option("--spending-key <key>", "Spending private key (hex)").option("--viewing-key <key>", "Viewing private key (hex)").action(async (options) => {
|
|
178
|
+
return new import_commander2.Command("keygen").description("Generate stealth meta-address").option("-c, --chain <chain>", "Target chain (ethereum, solana, near)", "ethereum").option("--spending-key <key>", "Spending private key (hex)").option("--viewing-key <key>", "Viewing private key (hex)").option("-o, --output-file <path>", "Output file for keys (enables secure export)").option("-f, --format <format>", "Output format: json or text", "json").action(async (options) => {
|
|
150
179
|
try {
|
|
151
180
|
heading("Generate Stealth Meta-Address");
|
|
152
181
|
const chain = options.chain;
|
|
153
182
|
const useEd25519 = (0, import_sdk.isEd25519Chain)(chain);
|
|
154
|
-
|
|
183
|
+
const format = options.format || "json";
|
|
184
|
+
let result;
|
|
155
185
|
if (useEd25519) {
|
|
156
186
|
if (options.spendingKey || options.viewingKey) {
|
|
157
187
|
warning("Ed25519 chains do not support custom keys in CLI yet");
|
|
158
188
|
}
|
|
159
|
-
|
|
189
|
+
result = (0, import_sdk.generateEd25519StealthMetaAddress)(chain);
|
|
160
190
|
} else {
|
|
161
|
-
|
|
191
|
+
result = (0, import_sdk.generateStealthMetaAddress)(chain);
|
|
162
192
|
}
|
|
163
193
|
success("Stealth meta-address generated");
|
|
164
194
|
keyValue("Chain", chain);
|
|
165
|
-
const spendingPubKey =
|
|
166
|
-
const viewingPubKey =
|
|
167
|
-
const spendingPrivKey =
|
|
168
|
-
const viewingPrivKey =
|
|
195
|
+
const spendingPubKey = result.metaAddress.spendingKey;
|
|
196
|
+
const viewingPubKey = result.metaAddress.viewingKey;
|
|
197
|
+
const spendingPrivKey = result.spendingPrivateKey;
|
|
198
|
+
const viewingPrivKey = result.viewingPrivateKey;
|
|
199
|
+
const encoded = (0, import_sdk.encodeStealthMetaAddress)(result.metaAddress);
|
|
169
200
|
keyValue("Spending Public Key", spendingPubKey);
|
|
170
201
|
keyValue("Viewing Public Key", viewingPubKey);
|
|
171
|
-
const encoded = (0, import_sdk.encodeStealthMetaAddress)(metaAddress.metaAddress);
|
|
172
202
|
keyValue("Encoded Address", encoded);
|
|
173
203
|
console.log();
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
204
|
+
if (options.outputFile) {
|
|
205
|
+
const outputPath = path.resolve(options.outputFile);
|
|
206
|
+
const dir = path.dirname(outputPath);
|
|
207
|
+
if (dir !== "." && dir !== "/") {
|
|
208
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
209
|
+
}
|
|
210
|
+
const exportData = {
|
|
211
|
+
chain,
|
|
212
|
+
spendingPublicKey: spendingPubKey,
|
|
213
|
+
viewingPublicKey: viewingPubKey,
|
|
214
|
+
spendingPrivateKey: spendingPrivKey,
|
|
215
|
+
viewingPrivateKey: viewingPrivKey,
|
|
216
|
+
metaAddress: encoded,
|
|
217
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
218
|
+
};
|
|
219
|
+
const content = format === "json" ? JSON.stringify(exportData, null, 2) : formatKeysAsText(exportData);
|
|
220
|
+
fs.writeFileSync(outputPath, content, {
|
|
221
|
+
mode: 384,
|
|
222
|
+
encoding: "utf-8"
|
|
223
|
+
});
|
|
224
|
+
success(`Keys exported to: ${outputPath}`);
|
|
225
|
+
warning("SECURITY: File permissions set to 600 (owner only)");
|
|
226
|
+
warning("SECURITY: Delete this file after securely storing the keys!");
|
|
227
|
+
info("Private keys NOT displayed in terminal for security");
|
|
228
|
+
} else {
|
|
229
|
+
warning("PRIVATE KEYS - Keep these secure!");
|
|
230
|
+
keyValue("Spending Private Key", spendingPrivKey);
|
|
231
|
+
keyValue("Viewing Private Key", viewingPrivKey);
|
|
232
|
+
console.log();
|
|
233
|
+
info("TIP: Use --output-file for secure key export:");
|
|
234
|
+
info(" sip keygen --chain solana --output-file ./keys.json");
|
|
235
|
+
}
|
|
177
236
|
} catch (err) {
|
|
178
237
|
console.error("Failed to generate keys:", err);
|
|
179
238
|
process.exit(1);
|
|
@@ -356,8 +415,8 @@ function createQuoteCommand() {
|
|
|
356
415
|
const quotes = await sip.getQuotes(intent);
|
|
357
416
|
spin.succeed(`Found ${quotes.length} quote(s)`);
|
|
358
417
|
if (quotes.length === 0) {
|
|
359
|
-
console.
|
|
360
|
-
|
|
418
|
+
console.error("\nNo quotes available");
|
|
419
|
+
process.exit(1);
|
|
361
420
|
}
|
|
362
421
|
console.log();
|
|
363
422
|
const headers = ["Solver", "Output Amount", "Fee", "Time (s)"];
|
|
@@ -385,7 +444,7 @@ function createQuoteCommand() {
|
|
|
385
444
|
var import_commander7 = require("commander");
|
|
386
445
|
var import_sdk6 = require("@sip-protocol/sdk");
|
|
387
446
|
function createSwapCommand() {
|
|
388
|
-
return new import_commander7.Command("swap").description("Execute swap").argument("<from-chain>", "Source chain (e.g., ethereum, solana)").argument("<to-chain>", "Destination chain").argument("<amount>", "Amount to swap").option("-t, --token <symbol>", "Token symbol (default: native token)").option("-p, --privacy <level>", "Privacy level (transparent|shielded|compliant)").option("-r, --recipient <address>", "Recipient address (optional)").option("--solver <id>", "Specific solver to use").action(async (fromChain, toChain, amountStr, options) => {
|
|
447
|
+
return new import_commander7.Command("swap").description("Execute swap").argument("<from-chain>", "Source chain (e.g., ethereum, solana)").argument("<to-chain>", "Destination chain").argument("<amount>", "Amount to swap").option("-t, --token <symbol>", "Token symbol (default: native token)").option("-p, --privacy <level>", "Privacy level (transparent|shielded|compliant)").option("-r, --recipient <address>", "Recipient address (optional)").option("-s, --slippage <percent>", "Slippage tolerance in percent (default: 5)", parseFloat).option("--solver <id>", "Specific solver to use").action(async (fromChain, toChain, amountStr, options) => {
|
|
389
448
|
try {
|
|
390
449
|
heading("Execute Swap");
|
|
391
450
|
const config = getConfig();
|
|
@@ -404,7 +463,10 @@ function createSwapCommand() {
|
|
|
404
463
|
address: null,
|
|
405
464
|
decimals: 18
|
|
406
465
|
};
|
|
466
|
+
const slippagePercent = Math.min(Math.max(options.slippage ?? 5, 0), 100);
|
|
467
|
+
const slippageTolerance = slippagePercent / 100;
|
|
407
468
|
info("Creating shielded intent...");
|
|
469
|
+
info(`Slippage tolerance: ${slippagePercent}%`);
|
|
408
470
|
const intent = await sip.createIntent({
|
|
409
471
|
input: {
|
|
410
472
|
asset: inputAsset,
|
|
@@ -414,8 +476,8 @@ function createSwapCommand() {
|
|
|
414
476
|
asset: outputAsset,
|
|
415
477
|
minAmount: 0n,
|
|
416
478
|
// Accept any amount
|
|
417
|
-
maxSlippage:
|
|
418
|
-
//
|
|
479
|
+
maxSlippage: slippageTolerance
|
|
480
|
+
// User-configurable slippage
|
|
419
481
|
},
|
|
420
482
|
privacy,
|
|
421
483
|
recipientMetaAddress: options.recipient
|
|
@@ -458,8 +520,31 @@ Solver not found: ${options.solver}`);
|
|
|
458
520
|
// src/commands/scan.ts
|
|
459
521
|
var import_commander8 = require("commander");
|
|
460
522
|
var import_sdk7 = require("@sip-protocol/sdk");
|
|
523
|
+
var import_ed25519 = require("@noble/curves/ed25519");
|
|
524
|
+
var import_secp256k1 = require("@noble/curves/secp256k1");
|
|
525
|
+
var import_utils = require("@noble/hashes/utils");
|
|
526
|
+
var fs2 = __toESM(require("fs"));
|
|
527
|
+
var path2 = __toESM(require("path"));
|
|
528
|
+
function formatScanResultsAsText(results, exportedAt) {
|
|
529
|
+
const lines = [
|
|
530
|
+
`# SIP Scan Results`,
|
|
531
|
+
`# Exported: ${exportedAt}`,
|
|
532
|
+
`# Found: ${results.length} stealth payment(s)`,
|
|
533
|
+
``
|
|
534
|
+
];
|
|
535
|
+
for (const r of results) {
|
|
536
|
+
lines.push(`## Address: ${r.address}`);
|
|
537
|
+
lines.push(`CHAIN=${r.chain}`);
|
|
538
|
+
if (r.privateKey) {
|
|
539
|
+
lines.push(`PRIVATE_KEY=${r.privateKey}`);
|
|
540
|
+
}
|
|
541
|
+
lines.push(``);
|
|
542
|
+
}
|
|
543
|
+
lines.push(`# WARNING: Delete this file after importing keys to your wallet!`);
|
|
544
|
+
return lines.join("\n");
|
|
545
|
+
}
|
|
461
546
|
function createScanCommand() {
|
|
462
|
-
return new import_commander8.Command("scan").description("Scan for stealth payments").requiredOption("-c, --chain <chain>", "Chain to scan (ethereum, solana, near)").requiredOption("-s, --spending-key <key>", "Your spending private key (hex)").requiredOption("-v, --viewing-key <key>", "Your viewing private key (hex)").option("-a, --addresses <addresses...>", "Specific addresses to check").action(async (options) => {
|
|
547
|
+
return new import_commander8.Command("scan").description("Scan for stealth payments").requiredOption("-c, --chain <chain>", "Chain to scan (ethereum, solana, near)").requiredOption("-s, --spending-key <key>", "Your spending private key (hex)").requiredOption("-v, --viewing-key <key>", "Your viewing private key (hex)").option("-a, --addresses <addresses...>", "Specific addresses to check").option("-o, --output-file <path>", "Output file for private keys (required to export keys)").option("-f, --format <format>", "Output format: json or text", "json").action(async (options) => {
|
|
463
548
|
try {
|
|
464
549
|
heading("Scan for Stealth Payments");
|
|
465
550
|
const chain = options.chain;
|
|
@@ -467,31 +552,35 @@ function createScanCommand() {
|
|
|
467
552
|
info(`Scanning ${chain} for stealth payments...`);
|
|
468
553
|
info(`Using ${useEd25519 ? "ed25519" : "secp256k1"} curve`);
|
|
469
554
|
if (!options.addresses || options.addresses.length === 0) {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
555
|
+
console.error("No addresses provided. Specify addresses with -a flag.");
|
|
556
|
+
console.error("Example: sip scan -c ethereum -s 0x... -v 0x... -a 0xabc... 0xdef...");
|
|
557
|
+
process.exit(1);
|
|
473
558
|
}
|
|
474
559
|
const results = [];
|
|
475
560
|
for (const address of options.addresses) {
|
|
476
561
|
try {
|
|
562
|
+
const stealthAddr = (0, import_sdk7.parseStealthAddress)(address);
|
|
477
563
|
let result;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
)
|
|
564
|
+
const spendingPubKey = useEd25519 ? `0x${(0, import_utils.bytesToHex)(import_ed25519.ed25519.getPublicKey((0, import_utils.hexToBytes)(options.spendingKey.slice(2))))}` : `0x${(0, import_utils.bytesToHex)(import_secp256k1.secp256k1.getPublicKey((0, import_utils.hexToBytes)(options.spendingKey.slice(2)), true))}`;
|
|
565
|
+
let isMine = (0, import_sdk7.checkStealthAddress)(stealthAddr, options.viewingKey, spendingPubKey);
|
|
566
|
+
let isLegacy = false;
|
|
567
|
+
if (!isMine) {
|
|
568
|
+
const legacyMatch = useEd25519 ? (0, import_sdk7.checkEd25519StealthAddressV1)(stealthAddr, options.spendingKey, options.viewingKey) : (0, import_sdk7.checkSecp256k1StealthAddressV1)(stealthAddr, options.spendingKey, options.viewingKey);
|
|
569
|
+
if (legacyMatch) {
|
|
570
|
+
isMine = true;
|
|
571
|
+
isLegacy = true;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (isMine) {
|
|
575
|
+
const derivedKey = isLegacy ? (0, import_sdk7.deriveStealthPrivateKeyV1)(stealthAddr, options.spendingKey, options.viewingKey) : (0, import_sdk7.deriveStealthPrivateKey)(stealthAddr, options.spendingKey, options.viewingKey);
|
|
576
|
+
result = { isMine: true, stealthPrivateKey: derivedKey.privateKey };
|
|
484
577
|
} else {
|
|
485
|
-
result =
|
|
486
|
-
address,
|
|
487
|
-
options.spendingKey,
|
|
488
|
-
options.viewingKey
|
|
489
|
-
);
|
|
578
|
+
result = { isMine: false };
|
|
490
579
|
}
|
|
491
580
|
results.push({
|
|
492
581
|
address,
|
|
493
582
|
isMine: result.isMine,
|
|
494
|
-
privateKey: result.
|
|
583
|
+
privateKey: result.stealthPrivateKey
|
|
495
584
|
});
|
|
496
585
|
} catch (err) {
|
|
497
586
|
results.push({
|
|
@@ -505,15 +594,34 @@ function createScanCommand() {
|
|
|
505
594
|
success(`Scanned ${results.length} address(es), found ${foundCount} stealth payment(s)`);
|
|
506
595
|
if (foundCount > 0) {
|
|
507
596
|
console.log();
|
|
508
|
-
const headers = ["Address", "Match"
|
|
597
|
+
const headers = ["Address", "Match"];
|
|
509
598
|
const rows = results.filter((r) => r.isMine).map((r) => [
|
|
510
|
-
r.address.slice(0,
|
|
511
|
-
"Yes"
|
|
512
|
-
r.privateKey ? r.privateKey.slice(0, 10) + "..." : "N/A"
|
|
599
|
+
r.address.slice(0, 16) + "..." + r.address.slice(-8),
|
|
600
|
+
"Yes"
|
|
513
601
|
]);
|
|
514
602
|
table(headers, rows);
|
|
515
603
|
console.log();
|
|
516
|
-
|
|
604
|
+
if (options.outputFile) {
|
|
605
|
+
const outputPath = path2.resolve(options.outputFile);
|
|
606
|
+
const format = options.format || "json";
|
|
607
|
+
const exportedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
608
|
+
const exportData = results.filter((r) => r.isMine).map((r) => ({
|
|
609
|
+
address: r.address,
|
|
610
|
+
privateKey: r.privateKey,
|
|
611
|
+
chain: options.chain
|
|
612
|
+
}));
|
|
613
|
+
const content = format === "json" ? JSON.stringify(exportData.map((d) => ({ ...d, exportedAt })), null, 2) : formatScanResultsAsText(exportData, exportedAt);
|
|
614
|
+
fs2.writeFileSync(outputPath, content, {
|
|
615
|
+
mode: 384,
|
|
616
|
+
encoding: "utf-8"
|
|
617
|
+
});
|
|
618
|
+
success(`Private keys exported to: ${outputPath}`);
|
|
619
|
+
warning("SECURITY: Delete this file after importing keys to your wallet!");
|
|
620
|
+
warning("SECURITY: File permissions set to 600 (owner only)");
|
|
621
|
+
} else {
|
|
622
|
+
info("Private keys not exported (use --output-file to export securely)");
|
|
623
|
+
warning("Keys are NOT displayed in terminal for security reasons");
|
|
624
|
+
}
|
|
517
625
|
} else {
|
|
518
626
|
info("No stealth payments found");
|
|
519
627
|
}
|
|
@@ -524,15 +632,1256 @@ function createScanCommand() {
|
|
|
524
632
|
});
|
|
525
633
|
}
|
|
526
634
|
|
|
635
|
+
// src/commands/setup.ts
|
|
636
|
+
var import_commander9 = require("commander");
|
|
637
|
+
var import_prompts = __toESM(require("prompts"));
|
|
638
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
639
|
+
var import_ora2 = __toESM(require("ora"));
|
|
640
|
+
var import_sdk8 = require("@sip-protocol/sdk");
|
|
641
|
+
var import_types2 = require("@sip-protocol/types");
|
|
642
|
+
var CHAINS = [
|
|
643
|
+
{ title: "Solana", value: "solana", description: "Fast, low-cost transactions" },
|
|
644
|
+
{ title: "Ethereum", value: "ethereum", description: "EVM mainnet" },
|
|
645
|
+
{ title: "NEAR", value: "near", description: "Sharded, scalable" },
|
|
646
|
+
{ title: "Arbitrum", value: "arbitrum", description: "Ethereum L2" },
|
|
647
|
+
{ title: "Base", value: "base", description: "Coinbase L2" }
|
|
648
|
+
];
|
|
649
|
+
var PRIVACY_LEVELS = [
|
|
650
|
+
{
|
|
651
|
+
title: "Transparent",
|
|
652
|
+
value: import_types2.PrivacyLevel.TRANSPARENT,
|
|
653
|
+
description: "No privacy (like standard transactions)"
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
title: "Shielded",
|
|
657
|
+
value: import_types2.PrivacyLevel.SHIELDED,
|
|
658
|
+
description: "Full privacy - hidden sender, amount, recipient"
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
title: "Compliant",
|
|
662
|
+
value: import_types2.PrivacyLevel.COMPLIANT,
|
|
663
|
+
description: "Privacy with viewing keys for auditors"
|
|
664
|
+
}
|
|
665
|
+
];
|
|
666
|
+
function createSetupCommand() {
|
|
667
|
+
return new import_commander9.Command("setup").description("Interactive setup wizard for SIP Protocol").option("--quick", "Quick setup with defaults").action(async (options) => {
|
|
668
|
+
console.clear();
|
|
669
|
+
console.log();
|
|
670
|
+
console.log(import_chalk2.default.bold.magenta(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
671
|
+
console.log(import_chalk2.default.bold.magenta(" \u2551 \u2551"));
|
|
672
|
+
console.log(import_chalk2.default.bold.magenta(" \u2551") + import_chalk2.default.bold.white(" \u{1F6E1}\uFE0F SIP Protocol Setup Wizard \u{1F6E1}\uFE0F ") + import_chalk2.default.bold.magenta("\u2551"));
|
|
673
|
+
console.log(import_chalk2.default.bold.magenta(" \u2551 \u2551"));
|
|
674
|
+
console.log(import_chalk2.default.bold.magenta(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
|
|
675
|
+
console.log();
|
|
676
|
+
console.log(import_chalk2.default.gray(" Privacy layer for cross-chain transactions"));
|
|
677
|
+
console.log();
|
|
678
|
+
if (options.quick) {
|
|
679
|
+
await quickSetup();
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
console.log(import_chalk2.default.cyan.bold(" Step 1 of 4: ") + import_chalk2.default.white("Network Configuration"));
|
|
683
|
+
console.log();
|
|
684
|
+
const networkResponse = await (0, import_prompts.default)([
|
|
685
|
+
{
|
|
686
|
+
type: "select",
|
|
687
|
+
name: "network",
|
|
688
|
+
message: "Which network do you want to use?",
|
|
689
|
+
choices: [
|
|
690
|
+
{ title: "Testnet / Devnet", value: "testnet", description: "For development and testing" },
|
|
691
|
+
{ title: "Mainnet", value: "mainnet", description: "Production network" }
|
|
692
|
+
],
|
|
693
|
+
initial: 0
|
|
694
|
+
}
|
|
695
|
+
]);
|
|
696
|
+
if (!networkResponse.network) {
|
|
697
|
+
console.log(import_chalk2.default.yellow("\n Setup cancelled."));
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
console.log();
|
|
701
|
+
console.log(import_chalk2.default.cyan.bold(" Step 2 of 4: ") + import_chalk2.default.white("Primary Chain"));
|
|
702
|
+
console.log();
|
|
703
|
+
const chainResponse = await (0, import_prompts.default)([
|
|
704
|
+
{
|
|
705
|
+
type: "select",
|
|
706
|
+
name: "chain",
|
|
707
|
+
message: "Which chain will you use primarily?",
|
|
708
|
+
choices: CHAINS,
|
|
709
|
+
initial: 0
|
|
710
|
+
}
|
|
711
|
+
]);
|
|
712
|
+
if (!chainResponse.chain) {
|
|
713
|
+
console.log(import_chalk2.default.yellow("\n Setup cancelled."));
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
console.log();
|
|
717
|
+
console.log(import_chalk2.default.cyan.bold(" Step 3 of 4: ") + import_chalk2.default.white("Default Privacy Level"));
|
|
718
|
+
console.log();
|
|
719
|
+
const privacyResponse = await (0, import_prompts.default)([
|
|
720
|
+
{
|
|
721
|
+
type: "select",
|
|
722
|
+
name: "privacy",
|
|
723
|
+
message: "What privacy level do you want by default?",
|
|
724
|
+
choices: PRIVACY_LEVELS,
|
|
725
|
+
initial: 1
|
|
726
|
+
// Default to shielded
|
|
727
|
+
}
|
|
728
|
+
]);
|
|
729
|
+
if (!privacyResponse.privacy) {
|
|
730
|
+
console.log(import_chalk2.default.yellow("\n Setup cancelled."));
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
console.log();
|
|
734
|
+
console.log(import_chalk2.default.cyan.bold(" Step 4 of 4: ") + import_chalk2.default.white("Key Generation"));
|
|
735
|
+
console.log();
|
|
736
|
+
const keyResponse = await (0, import_prompts.default)([
|
|
737
|
+
{
|
|
738
|
+
type: "confirm",
|
|
739
|
+
name: "generateKeys",
|
|
740
|
+
message: "Generate stealth meta-address now?",
|
|
741
|
+
initial: true
|
|
742
|
+
}
|
|
743
|
+
]);
|
|
744
|
+
const spinner2 = (0, import_ora2.default)("Saving configuration...").start();
|
|
745
|
+
try {
|
|
746
|
+
setConfig("network", networkResponse.network);
|
|
747
|
+
setConfig("primaryChain", chainResponse.chain);
|
|
748
|
+
setConfig("defaultPrivacy", privacyResponse.privacy);
|
|
749
|
+
spinner2.succeed("Configuration saved");
|
|
750
|
+
} catch (err) {
|
|
751
|
+
spinner2.fail("Failed to save configuration");
|
|
752
|
+
console.error(err);
|
|
753
|
+
process.exit(1);
|
|
754
|
+
}
|
|
755
|
+
if (keyResponse.generateKeys) {
|
|
756
|
+
console.log();
|
|
757
|
+
const keySpinner = (0, import_ora2.default)("Generating stealth meta-address...").start();
|
|
758
|
+
try {
|
|
759
|
+
const chain = chainResponse.chain;
|
|
760
|
+
const useEd25519 = (0, import_sdk8.isEd25519Chain)(chain);
|
|
761
|
+
const metaAddress = useEd25519 ? (0, import_sdk8.generateEd25519StealthMetaAddress)(chain) : (0, import_sdk8.generateStealthMetaAddress)(chain);
|
|
762
|
+
keySpinner.succeed("Keys generated");
|
|
763
|
+
console.log();
|
|
764
|
+
console.log(import_chalk2.default.bold.green(" \u2713 Stealth Meta-Address Generated"));
|
|
765
|
+
console.log();
|
|
766
|
+
console.log(import_chalk2.default.gray(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
|
|
767
|
+
console.log(import_chalk2.default.gray(" \u2502 ") + import_chalk2.default.cyan("Chain: ") + import_chalk2.default.white(chain.padEnd(30)) + import_chalk2.default.gray(" \u2502"));
|
|
768
|
+
console.log(import_chalk2.default.gray(" \u2502 ") + import_chalk2.default.cyan("Curve: ") + import_chalk2.default.white((useEd25519 ? "ed25519" : "secp256k1").padEnd(30)) + import_chalk2.default.gray(" \u2502"));
|
|
769
|
+
console.log(import_chalk2.default.gray(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
|
|
770
|
+
console.log();
|
|
771
|
+
const encoded = (0, import_sdk8.encodeStealthMetaAddress)(metaAddress.metaAddress);
|
|
772
|
+
console.log(import_chalk2.default.bold(" Encoded Meta-Address (share this):"));
|
|
773
|
+
console.log(import_chalk2.default.green(` ${encoded}`));
|
|
774
|
+
console.log();
|
|
775
|
+
console.log(import_chalk2.default.bold.yellow(" \u26A0\uFE0F PRIVATE KEYS - Store securely!"));
|
|
776
|
+
console.log();
|
|
777
|
+
console.log(import_chalk2.default.gray(" Spending Key: ") + import_chalk2.default.dim(metaAddress.spendingPrivateKey));
|
|
778
|
+
console.log(import_chalk2.default.gray(" Viewing Key: ") + import_chalk2.default.dim(metaAddress.viewingPrivateKey));
|
|
779
|
+
console.log();
|
|
780
|
+
setConfig("metaAddress", encoded);
|
|
781
|
+
} catch (err) {
|
|
782
|
+
keySpinner.fail("Failed to generate keys");
|
|
783
|
+
console.error(err instanceof Error ? err.message : err);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
console.log();
|
|
787
|
+
divider();
|
|
788
|
+
console.log();
|
|
789
|
+
console.log(import_chalk2.default.bold.green(" \u{1F389} Setup Complete!"));
|
|
790
|
+
console.log();
|
|
791
|
+
console.log(import_chalk2.default.gray(" Configuration:"));
|
|
792
|
+
console.log(import_chalk2.default.gray(" \u251C\u2500 Network: ") + import_chalk2.default.white(networkResponse.network));
|
|
793
|
+
console.log(import_chalk2.default.gray(" \u251C\u2500 Chain: ") + import_chalk2.default.white(chainResponse.chain));
|
|
794
|
+
console.log(import_chalk2.default.gray(" \u251C\u2500 Privacy: ") + import_chalk2.default.white(privacyResponse.privacy));
|
|
795
|
+
console.log(import_chalk2.default.gray(" \u2514\u2500 Config: ") + import_chalk2.default.dim(getConfigPath()));
|
|
796
|
+
console.log();
|
|
797
|
+
console.log(import_chalk2.default.cyan(" Next steps:"));
|
|
798
|
+
console.log(import_chalk2.default.gray(" 1. ") + import_chalk2.default.white("sip keygen") + import_chalk2.default.gray(" - Generate more stealth addresses"));
|
|
799
|
+
console.log(import_chalk2.default.gray(" 2. ") + import_chalk2.default.white("sip quote") + import_chalk2.default.gray(" - Get a swap quote"));
|
|
800
|
+
console.log(import_chalk2.default.gray(" 3. ") + import_chalk2.default.white("sip scan") + import_chalk2.default.gray(" - Scan for incoming payments"));
|
|
801
|
+
console.log();
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
async function quickSetup() {
|
|
805
|
+
const spinner2 = (0, import_ora2.default)("Quick setup with defaults...").start();
|
|
806
|
+
try {
|
|
807
|
+
setConfig("network", "testnet");
|
|
808
|
+
setConfig("primaryChain", "solana");
|
|
809
|
+
setConfig("defaultPrivacy", import_types2.PrivacyLevel.SHIELDED);
|
|
810
|
+
const metaAddress = (0, import_sdk8.generateEd25519StealthMetaAddress)("solana");
|
|
811
|
+
const encoded = (0, import_sdk8.encodeStealthMetaAddress)(metaAddress.metaAddress);
|
|
812
|
+
setConfig("metaAddress", encoded);
|
|
813
|
+
spinner2.succeed("Quick setup complete");
|
|
814
|
+
console.log();
|
|
815
|
+
console.log(import_chalk2.default.green(" \u2713 Network: testnet"));
|
|
816
|
+
console.log(import_chalk2.default.green(" \u2713 Chain: solana"));
|
|
817
|
+
console.log(import_chalk2.default.green(" \u2713 Privacy: shielded"));
|
|
818
|
+
console.log(import_chalk2.default.green(" \u2713 Keys generated"));
|
|
819
|
+
console.log();
|
|
820
|
+
console.log(import_chalk2.default.bold(" Meta-Address:"));
|
|
821
|
+
console.log(import_chalk2.default.cyan(` ${encoded}`));
|
|
822
|
+
console.log();
|
|
823
|
+
console.log(import_chalk2.default.yellow(" \u26A0\uFE0F Run ") + import_chalk2.default.white("sip setup") + import_chalk2.default.yellow(" for full interactive setup"));
|
|
824
|
+
console.log();
|
|
825
|
+
} catch (err) {
|
|
826
|
+
spinner2.fail("Quick setup failed");
|
|
827
|
+
console.error(err);
|
|
828
|
+
process.exit(1);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// src/commands/stealth.ts
|
|
833
|
+
var import_commander10 = require("commander");
|
|
834
|
+
var import_prompts2 = __toESM(require("prompts"));
|
|
835
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
836
|
+
var import_ora3 = __toESM(require("ora"));
|
|
837
|
+
var import_sdk9 = require("@sip-protocol/sdk");
|
|
838
|
+
function createStealthCommand() {
|
|
839
|
+
const cmd = new import_commander10.Command("stealth").description("Generate one-time stealth addresses");
|
|
840
|
+
cmd.command("generate").alias("gen").description("Generate a one-time stealth address from a meta-address").option("-m, --meta <address>", "Recipient meta-address (or use saved)").option("-c, --chain <chain>", "Target chain (auto-detected from meta-address)").option("-i, --interactive", "Interactive mode").action(async (options) => {
|
|
841
|
+
heading("Generate Stealth Address");
|
|
842
|
+
let metaAddressStr = options.meta;
|
|
843
|
+
if (options.interactive || !metaAddressStr) {
|
|
844
|
+
const savedMeta = getConfig("metaAddress");
|
|
845
|
+
const response = await (0, import_prompts2.default)([
|
|
846
|
+
{
|
|
847
|
+
type: "text",
|
|
848
|
+
name: "meta",
|
|
849
|
+
message: "Enter recipient meta-address:",
|
|
850
|
+
initial: savedMeta || "",
|
|
851
|
+
validate: (value) => value.startsWith("sip:") ? true : "Must be a valid SIP meta-address (sip:...)"
|
|
852
|
+
}
|
|
853
|
+
]);
|
|
854
|
+
if (!response.meta) {
|
|
855
|
+
console.log(import_chalk3.default.yellow("Cancelled."));
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
metaAddressStr = response.meta;
|
|
859
|
+
}
|
|
860
|
+
const spinner2 = (0, import_ora3.default)("Generating stealth address...").start();
|
|
861
|
+
try {
|
|
862
|
+
const metaAddress = (0, import_sdk9.decodeStealthMetaAddress)(metaAddressStr);
|
|
863
|
+
const chain = metaAddress.chain;
|
|
864
|
+
const useEd25519 = (0, import_sdk9.isEd25519Chain)(chain);
|
|
865
|
+
const result = useEd25519 ? (0, import_sdk9.generateEd25519StealthAddress)(metaAddress) : (0, import_sdk9.generateStealthAddress)(metaAddress);
|
|
866
|
+
const stealthPubKey = result.stealthAddress.address;
|
|
867
|
+
const ephemeralPubKey = result.stealthAddress.ephemeralPublicKey;
|
|
868
|
+
let chainAddress;
|
|
869
|
+
if (useEd25519) {
|
|
870
|
+
if (chain === "solana") {
|
|
871
|
+
chainAddress = (0, import_sdk9.ed25519PublicKeyToSolanaAddress)(stealthPubKey);
|
|
872
|
+
} else if (chain === "near") {
|
|
873
|
+
chainAddress = (0, import_sdk9.ed25519PublicKeyToNearAddress)(stealthPubKey);
|
|
874
|
+
} else {
|
|
875
|
+
chainAddress = stealthPubKey;
|
|
876
|
+
}
|
|
877
|
+
} else {
|
|
878
|
+
chainAddress = (0, import_sdk9.publicKeyToEthAddress)(stealthPubKey);
|
|
879
|
+
}
|
|
880
|
+
spinner2.succeed("Stealth address generated");
|
|
881
|
+
console.log();
|
|
882
|
+
keyValue("Chain", chain);
|
|
883
|
+
keyValue("Curve", useEd25519 ? "ed25519" : "secp256k1");
|
|
884
|
+
console.log();
|
|
885
|
+
console.log(import_chalk3.default.bold.green(" One-Time Address (send funds here):"));
|
|
886
|
+
console.log(import_chalk3.default.cyan(` ${chainAddress}`));
|
|
887
|
+
console.log();
|
|
888
|
+
console.log(import_chalk3.default.bold(" Ephemeral Public Key (publish for recipient):"));
|
|
889
|
+
console.log(import_chalk3.default.gray(` ${ephemeralPubKey}`));
|
|
890
|
+
console.log();
|
|
891
|
+
warning("The ephemeral key must be published so the recipient can find and claim funds.");
|
|
892
|
+
} catch (err) {
|
|
893
|
+
spinner2.fail("Failed to generate stealth address");
|
|
894
|
+
console.error(err instanceof Error ? err.message : err);
|
|
895
|
+
process.exit(1);
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
cmd.command("derive").description("Derive spending key from stealth address (to claim funds)").requiredOption("-a, --stealth-address <address>", "Stealth address where funds were sent").requiredOption("-e, --ephemeral <key>", "Ephemeral public key from sender announcement").requiredOption("-s, --spending-key <key>", "Your spending private key (hex)").requiredOption("-v, --viewing-key <key>", "Your viewing private key (hex)").option("-c, --chain <chain>", "Chain (solana, ethereum, near)", "solana").action(async (options) => {
|
|
899
|
+
heading("Derive Stealth Spending Key");
|
|
900
|
+
warning("This is for advanced users. Keep your derived private key secure!");
|
|
901
|
+
console.log();
|
|
902
|
+
const spinner2 = (0, import_ora3.default)("Deriving stealth private key...").start();
|
|
903
|
+
try {
|
|
904
|
+
const chain = options.chain;
|
|
905
|
+
const useEd25519 = (0, import_sdk9.isEd25519Chain)(chain);
|
|
906
|
+
const spendingKey = normalizeHexKey(options.spendingKey);
|
|
907
|
+
const viewingKey = normalizeHexKey(options.viewingKey);
|
|
908
|
+
const ephemeralKey = normalizeHexKey(options.ephemeral);
|
|
909
|
+
let stealthPubKeyHex;
|
|
910
|
+
if (useEd25519 && chain === "solana") {
|
|
911
|
+
stealthPubKeyHex = (0, import_sdk9.solanaAddressToEd25519PublicKey)(options.stealthAddress);
|
|
912
|
+
} else if (options.stealthAddress.startsWith("0x")) {
|
|
913
|
+
stealthPubKeyHex = options.stealthAddress;
|
|
914
|
+
} else {
|
|
915
|
+
throw new Error("Stealth address must be base58 (Solana) or hex (0x...)");
|
|
916
|
+
}
|
|
917
|
+
const stealthAddressObj = {
|
|
918
|
+
address: stealthPubKeyHex,
|
|
919
|
+
ephemeralPublicKey: ephemeralKey,
|
|
920
|
+
viewTag: 0
|
|
921
|
+
// Not needed for derivation
|
|
922
|
+
};
|
|
923
|
+
const recovery = useEd25519 ? (0, import_sdk9.deriveEd25519StealthPrivateKey)(
|
|
924
|
+
stealthAddressObj,
|
|
925
|
+
spendingKey,
|
|
926
|
+
viewingKey
|
|
927
|
+
) : (0, import_sdk9.deriveStealthPrivateKey)(
|
|
928
|
+
stealthAddressObj,
|
|
929
|
+
spendingKey,
|
|
930
|
+
viewingKey
|
|
931
|
+
);
|
|
932
|
+
spinner2.succeed("Stealth private key derived");
|
|
933
|
+
console.log();
|
|
934
|
+
keyValue("Chain", chain);
|
|
935
|
+
keyValue("Curve", useEd25519 ? "ed25519" : "secp256k1");
|
|
936
|
+
console.log();
|
|
937
|
+
console.log(import_chalk3.default.bold.green(" Derived Private Key (use to claim funds):"));
|
|
938
|
+
console.log(import_chalk3.default.cyan(` ${recovery.privateKey}`));
|
|
939
|
+
console.log();
|
|
940
|
+
console.log(import_chalk3.default.bold(" Stealth Address:"));
|
|
941
|
+
console.log(import_chalk3.default.gray(` ${recovery.stealthAddress}`));
|
|
942
|
+
console.log();
|
|
943
|
+
warning("Never share your private key! Use it to sign transactions claiming your funds.");
|
|
944
|
+
console.log();
|
|
945
|
+
info3("Next steps:");
|
|
946
|
+
console.log(import_chalk3.default.gray(" 1. Import this key into a wallet or use SDK to claim"));
|
|
947
|
+
console.log(import_chalk3.default.gray(" 2. Transfer funds from stealth address to your main wallet"));
|
|
948
|
+
console.log(import_chalk3.default.gray(" 3. Securely delete this private key after claiming"));
|
|
949
|
+
console.log();
|
|
950
|
+
} catch (err) {
|
|
951
|
+
spinner2.fail("Failed to derive stealth key");
|
|
952
|
+
console.error(err instanceof Error ? err.message : err);
|
|
953
|
+
process.exit(1);
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
return cmd;
|
|
957
|
+
}
|
|
958
|
+
function info3(message) {
|
|
959
|
+
console.log(import_chalk3.default.blue("\u2139"), message);
|
|
960
|
+
}
|
|
961
|
+
function normalizeHexKey(key) {
|
|
962
|
+
if (key.startsWith("0x")) {
|
|
963
|
+
return key;
|
|
964
|
+
}
|
|
965
|
+
return `0x${key}`;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/commands/viewing-key.ts
|
|
969
|
+
var import_commander11 = require("commander");
|
|
970
|
+
var import_prompts3 = __toESM(require("prompts"));
|
|
971
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
972
|
+
var import_ora4 = __toESM(require("ora"));
|
|
973
|
+
var import_sdk10 = require("@sip-protocol/sdk");
|
|
974
|
+
function createViewingKeyCommand() {
|
|
975
|
+
const cmd = new import_commander11.Command("viewing-key").alias("vk").description("Manage viewing keys for selective disclosure");
|
|
976
|
+
cmd.command("generate").alias("gen").description("Generate a new viewing key").option("-p, --path <path>", 'Key derivation path (e.g., "payments/2024")').option("-i, --interactive", "Interactive mode").action(async (options) => {
|
|
977
|
+
heading("Generate Viewing Key");
|
|
978
|
+
let path3 = options.path;
|
|
979
|
+
if (options.interactive || !path3) {
|
|
980
|
+
const response = await (0, import_prompts3.default)([
|
|
981
|
+
{
|
|
982
|
+
type: "text",
|
|
983
|
+
name: "path",
|
|
984
|
+
message: "Enter a label or path for this viewing key:",
|
|
985
|
+
initial: `audit/${Date.now()}`,
|
|
986
|
+
validate: (value) => value.length > 0 ? true : "Path is required"
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
type: "text",
|
|
990
|
+
name: "description",
|
|
991
|
+
message: "Description (optional):"
|
|
992
|
+
}
|
|
993
|
+
]);
|
|
994
|
+
if (!response.path) {
|
|
995
|
+
console.log(import_chalk4.default.yellow("Cancelled."));
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
path3 = response.path;
|
|
999
|
+
}
|
|
1000
|
+
const spinner2 = (0, import_ora4.default)("Generating viewing key...").start();
|
|
1001
|
+
try {
|
|
1002
|
+
const viewingKey = (0, import_sdk10.generateViewingKey)(path3);
|
|
1003
|
+
spinner2.succeed("Viewing key generated");
|
|
1004
|
+
console.log();
|
|
1005
|
+
keyValue("Path", viewingKey.path);
|
|
1006
|
+
keyValue("Hash", viewingKey.hash);
|
|
1007
|
+
console.log();
|
|
1008
|
+
console.log(import_chalk4.default.bold.green(" Viewing Key (share with auditors):"));
|
|
1009
|
+
console.log(import_chalk4.default.cyan(` ${viewingKey.key}`));
|
|
1010
|
+
console.log();
|
|
1011
|
+
console.log(import_chalk4.default.bold(" Key Hash (for verification):"));
|
|
1012
|
+
console.log(import_chalk4.default.gray(` ${viewingKey.hash}`));
|
|
1013
|
+
console.log();
|
|
1014
|
+
warning("Share the viewing key with authorized parties only.");
|
|
1015
|
+
console.log(import_chalk4.default.gray(" They can view transactions but cannot spend funds."));
|
|
1016
|
+
console.log();
|
|
1017
|
+
const saveResponse = await (0, import_prompts3.default)([
|
|
1018
|
+
{
|
|
1019
|
+
type: "confirm",
|
|
1020
|
+
name: "save",
|
|
1021
|
+
message: "Save this viewing key to config?",
|
|
1022
|
+
initial: false
|
|
1023
|
+
}
|
|
1024
|
+
]);
|
|
1025
|
+
if (saveResponse.save) {
|
|
1026
|
+
const existingKeys = getConfig("viewingKeys") || {};
|
|
1027
|
+
existingKeys[path3] = viewingKey.key;
|
|
1028
|
+
setConfig("viewingKeys", existingKeys);
|
|
1029
|
+
success("Viewing key saved to config");
|
|
1030
|
+
}
|
|
1031
|
+
} catch (err) {
|
|
1032
|
+
spinner2.fail("Failed to generate viewing key");
|
|
1033
|
+
console.error(err instanceof Error ? err.message : err);
|
|
1034
|
+
process.exit(1);
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
cmd.command("list").alias("ls").description("List saved viewing keys").action(async () => {
|
|
1038
|
+
heading("Saved Viewing Keys");
|
|
1039
|
+
const keys = getConfig("viewingKeys") || {};
|
|
1040
|
+
const entries = Object.entries(keys);
|
|
1041
|
+
if (entries.length === 0) {
|
|
1042
|
+
console.log(import_chalk4.default.gray(" No viewing keys saved."));
|
|
1043
|
+
console.log(import_chalk4.default.gray(" Run: sip viewing-key generate -i"));
|
|
1044
|
+
console.log();
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
console.log();
|
|
1048
|
+
entries.forEach(([path3, key]) => {
|
|
1049
|
+
console.log(import_chalk4.default.cyan(` ${path3}`));
|
|
1050
|
+
console.log(import_chalk4.default.gray(` ${key.slice(0, 20)}...${key.slice(-10)}`));
|
|
1051
|
+
console.log();
|
|
1052
|
+
});
|
|
1053
|
+
});
|
|
1054
|
+
cmd.command("share").description("Create a shareable viewing key disclosure").option("-p, --path <path>", "Viewing key path to share").option("-e, --expires <date>", "Expiration date (ISO format)").option("-s, --scope <scope>", "Scope of disclosure (all, treasury, payments)").action(async (options) => {
|
|
1055
|
+
heading("Create Viewing Key Disclosure");
|
|
1056
|
+
const keys = getConfig("viewingKeys") || {};
|
|
1057
|
+
const entries = Object.entries(keys);
|
|
1058
|
+
if (entries.length === 0) {
|
|
1059
|
+
console.log(import_chalk4.default.yellow(" No viewing keys saved."));
|
|
1060
|
+
console.log(import_chalk4.default.gray(" Run: sip viewing-key generate -i first"));
|
|
1061
|
+
console.log();
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
const response = await (0, import_prompts3.default)([
|
|
1065
|
+
{
|
|
1066
|
+
type: "select",
|
|
1067
|
+
name: "path",
|
|
1068
|
+
message: "Select viewing key to share:",
|
|
1069
|
+
choices: entries.map(([path3]) => ({ title: path3, value: path3 }))
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
type: "select",
|
|
1073
|
+
name: "scope",
|
|
1074
|
+
message: "Disclosure scope:",
|
|
1075
|
+
choices: [
|
|
1076
|
+
{ title: "All transactions", value: "all" },
|
|
1077
|
+
{ title: "Treasury only", value: "treasury" },
|
|
1078
|
+
{ title: "Payments only", value: "payments" },
|
|
1079
|
+
{ title: "Custom time range", value: "custom" }
|
|
1080
|
+
]
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
type: "text",
|
|
1084
|
+
name: "recipient",
|
|
1085
|
+
message: "Recipient (auditor, regulator, etc.):"
|
|
1086
|
+
}
|
|
1087
|
+
]);
|
|
1088
|
+
if (!response.path) {
|
|
1089
|
+
console.log(import_chalk4.default.yellow("Cancelled."));
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
const key = keys[response.path];
|
|
1093
|
+
console.log();
|
|
1094
|
+
console.log(import_chalk4.default.bold.green(" \u{1F4CB} Viewing Key Disclosure"));
|
|
1095
|
+
console.log();
|
|
1096
|
+
console.log(import_chalk4.default.gray(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
|
|
1097
|
+
console.log(import_chalk4.default.gray(" \u2502 ") + import_chalk4.default.cyan("Path: ") + import_chalk4.default.white(response.path.padEnd(36)) + import_chalk4.default.gray(" \u2502"));
|
|
1098
|
+
console.log(import_chalk4.default.gray(" \u2502 ") + import_chalk4.default.cyan("Scope: ") + import_chalk4.default.white(response.scope.padEnd(36)) + import_chalk4.default.gray(" \u2502"));
|
|
1099
|
+
console.log(import_chalk4.default.gray(" \u2502 ") + import_chalk4.default.cyan("Recipient: ") + import_chalk4.default.white((response.recipient || "Not specified").padEnd(36)) + import_chalk4.default.gray(" \u2502"));
|
|
1100
|
+
console.log(import_chalk4.default.gray(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
|
|
1101
|
+
console.log();
|
|
1102
|
+
console.log(import_chalk4.default.bold(" Viewing Key:"));
|
|
1103
|
+
console.log(import_chalk4.default.cyan(` ${key}`));
|
|
1104
|
+
console.log();
|
|
1105
|
+
console.log(import_chalk4.default.gray(" The recipient can use this key to view transactions"));
|
|
1106
|
+
console.log(import_chalk4.default.gray(" matching the specified scope, but cannot spend funds."));
|
|
1107
|
+
console.log();
|
|
1108
|
+
});
|
|
1109
|
+
return cmd;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// src/commands/backends.ts
|
|
1113
|
+
var import_commander12 = require("commander");
|
|
1114
|
+
var import_sdk11 = require("@sip-protocol/sdk");
|
|
1115
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
1116
|
+
function createDefaultRegistry() {
|
|
1117
|
+
const registry = new import_sdk11.PrivacyBackendRegistry({ enableHealthTracking: true });
|
|
1118
|
+
registry.register(new import_sdk11.SIPNativeBackend());
|
|
1119
|
+
return registry;
|
|
1120
|
+
}
|
|
1121
|
+
function collectBackendInfo(registry) {
|
|
1122
|
+
const entries = registry.getAllEntries();
|
|
1123
|
+
const healthTracker = registry.getHealthTracker();
|
|
1124
|
+
const results = [];
|
|
1125
|
+
for (const entry of entries) {
|
|
1126
|
+
const backend = entry.backend;
|
|
1127
|
+
const caps = backend.getCapabilities();
|
|
1128
|
+
let healthy = true;
|
|
1129
|
+
let failures = 0;
|
|
1130
|
+
if (healthTracker) {
|
|
1131
|
+
const health = healthTracker.getHealth(backend.name);
|
|
1132
|
+
if (health) {
|
|
1133
|
+
healthy = health.isHealthy;
|
|
1134
|
+
failures = health.consecutiveFailures;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
results.push({
|
|
1138
|
+
name: backend.name,
|
|
1139
|
+
type: backend.type,
|
|
1140
|
+
chains: [...backend.chains],
|
|
1141
|
+
healthy,
|
|
1142
|
+
failures,
|
|
1143
|
+
enabled: entry.enabled,
|
|
1144
|
+
compliance: caps.complianceSupport
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
return results;
|
|
1148
|
+
}
|
|
1149
|
+
function createBackendsCommand() {
|
|
1150
|
+
const cmd = new import_commander12.Command("backends").description("Manage and list privacy backends");
|
|
1151
|
+
cmd.command("list").description("List all registered privacy backends").option("--health", "Show health status").option("--metrics", "Show detailed metrics").option("--json", "Output as JSON").option("--type <type>", "Filter by type (transaction, compute, both)").option("--chain <chain>", "Filter by chain support").action(async (options) => {
|
|
1152
|
+
try {
|
|
1153
|
+
const registry = createDefaultRegistry();
|
|
1154
|
+
let backends = collectBackendInfo(registry);
|
|
1155
|
+
if (options.type) {
|
|
1156
|
+
backends = backends.filter((b) => b.type === options.type || b.type === "both");
|
|
1157
|
+
}
|
|
1158
|
+
if (options.chain) {
|
|
1159
|
+
backends = backends.filter((b) => b.chains.includes(options.chain));
|
|
1160
|
+
}
|
|
1161
|
+
if (options.json) {
|
|
1162
|
+
json({
|
|
1163
|
+
backends: backends.map((b) => ({
|
|
1164
|
+
...b,
|
|
1165
|
+
chains: b.chains
|
|
1166
|
+
})),
|
|
1167
|
+
total: backends.length,
|
|
1168
|
+
healthy: backends.filter((b) => b.healthy).length
|
|
1169
|
+
});
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
heading("Privacy Backends");
|
|
1173
|
+
if (backends.length === 0) {
|
|
1174
|
+
warning("No backends match the specified filters");
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
const headers = ["NAME", "TYPE", "CHAINS", "COMPLIANCE"];
|
|
1178
|
+
if (options.health || options.metrics) {
|
|
1179
|
+
headers.push("HEALTHY", "FAILURES");
|
|
1180
|
+
}
|
|
1181
|
+
const rows = backends.map((b) => {
|
|
1182
|
+
const row = [
|
|
1183
|
+
b.enabled ? b.name : import_chalk5.default.gray(b.name + " (disabled)"),
|
|
1184
|
+
b.type,
|
|
1185
|
+
b.chains.join(", "),
|
|
1186
|
+
b.compliance ? import_chalk5.default.green("\u2713") : import_chalk5.default.gray("\u2717")
|
|
1187
|
+
];
|
|
1188
|
+
if (options.health || options.metrics) {
|
|
1189
|
+
row.push(
|
|
1190
|
+
b.healthy ? import_chalk5.default.green("\u2713") : import_chalk5.default.red("\u2717"),
|
|
1191
|
+
b.failures
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
1194
|
+
return row;
|
|
1195
|
+
});
|
|
1196
|
+
table(headers, rows);
|
|
1197
|
+
console.log();
|
|
1198
|
+
const healthyCount = backends.filter((b) => b.healthy).length;
|
|
1199
|
+
const complianceCount = backends.filter((b) => b.compliance).length;
|
|
1200
|
+
success(`${backends.length} backend(s) registered`);
|
|
1201
|
+
if (options.health || options.metrics) {
|
|
1202
|
+
if (healthyCount === backends.length) {
|
|
1203
|
+
info(`All backends healthy`);
|
|
1204
|
+
} else {
|
|
1205
|
+
warning(`${healthyCount}/${backends.length} backends healthy`);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
info(`${complianceCount} backend(s) support compliance (viewing keys)`);
|
|
1209
|
+
} catch (err) {
|
|
1210
|
+
console.error("Failed to list backends:", err);
|
|
1211
|
+
process.exit(1);
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
cmd.command("info <name>").description("Show detailed information about a specific backend").option("--json", "Output as JSON").action(async (name, options) => {
|
|
1215
|
+
try {
|
|
1216
|
+
const registry = createDefaultRegistry();
|
|
1217
|
+
const backend = registry.get(name);
|
|
1218
|
+
if (!backend) {
|
|
1219
|
+
console.error(`Backend '${name}' not found`);
|
|
1220
|
+
console.error("Available backends:", registry.getNames().join(", "));
|
|
1221
|
+
process.exit(1);
|
|
1222
|
+
}
|
|
1223
|
+
const caps = backend.getCapabilities();
|
|
1224
|
+
const healthTracker = registry.getHealthTracker();
|
|
1225
|
+
const health = healthTracker?.getHealth(name);
|
|
1226
|
+
const metrics = healthTracker?.getMetrics(name);
|
|
1227
|
+
const backendInfo = {
|
|
1228
|
+
name: backend.name,
|
|
1229
|
+
type: backend.type,
|
|
1230
|
+
chains: [...backend.chains],
|
|
1231
|
+
capabilities: {
|
|
1232
|
+
complianceSupport: caps.complianceSupport,
|
|
1233
|
+
anonymitySet: caps.anonymitySet,
|
|
1234
|
+
latency: caps.latencyEstimate,
|
|
1235
|
+
setupRequired: caps.setupRequired
|
|
1236
|
+
},
|
|
1237
|
+
health: health ? {
|
|
1238
|
+
state: health.circuitState,
|
|
1239
|
+
isHealthy: health.isHealthy,
|
|
1240
|
+
consecutiveFailures: health.consecutiveFailures,
|
|
1241
|
+
consecutiveSuccesses: health.consecutiveSuccesses,
|
|
1242
|
+
lastFailureTime: health.lastFailureTime ? new Date(health.lastFailureTime).toISOString() : null,
|
|
1243
|
+
lastFailureReason: health.lastFailureReason ?? null
|
|
1244
|
+
} : null,
|
|
1245
|
+
metrics: metrics ? {
|
|
1246
|
+
totalRequests: metrics.totalRequests,
|
|
1247
|
+
successfulRequests: metrics.successfulRequests,
|
|
1248
|
+
failedRequests: metrics.failedRequests,
|
|
1249
|
+
averageLatencyMs: Math.round(metrics.averageLatencyMs),
|
|
1250
|
+
successRate: metrics.totalRequests > 0 ? Math.round(metrics.successfulRequests / metrics.totalRequests * 100) : 0
|
|
1251
|
+
} : null
|
|
1252
|
+
};
|
|
1253
|
+
if (options.json) {
|
|
1254
|
+
json(backendInfo);
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
heading(`Backend: ${backend.name}`);
|
|
1258
|
+
console.log(import_chalk5.default.bold("General"));
|
|
1259
|
+
console.log(` Type: ${backend.type}`);
|
|
1260
|
+
console.log(` Chains: ${backend.chains.join(", ")}`);
|
|
1261
|
+
console.log();
|
|
1262
|
+
console.log(import_chalk5.default.bold("Capabilities"));
|
|
1263
|
+
console.log(` Compliance: ${caps.complianceSupport ? import_chalk5.default.green("Yes") : import_chalk5.default.gray("No")}`);
|
|
1264
|
+
console.log(` Anonymity Set: ${caps.anonymitySet ?? "N/A"}`);
|
|
1265
|
+
console.log(` Est. Latency: ${caps.latencyEstimate}`);
|
|
1266
|
+
console.log(` Setup Required: ${caps.setupRequired ? "Yes" : "No"}`);
|
|
1267
|
+
if (health) {
|
|
1268
|
+
console.log();
|
|
1269
|
+
console.log(import_chalk5.default.bold("Health"));
|
|
1270
|
+
console.log(` State: ${health.circuitState === "closed" ? import_chalk5.default.green("Healthy") : import_chalk5.default.red(health.circuitState)}`);
|
|
1271
|
+
console.log(` Healthy: ${health.isHealthy ? import_chalk5.default.green("Yes") : import_chalk5.default.red("No")}`);
|
|
1272
|
+
console.log(` Failures: ${health.consecutiveFailures}`);
|
|
1273
|
+
console.log(` Successes: ${health.consecutiveSuccesses}`);
|
|
1274
|
+
if (health.lastFailureReason) {
|
|
1275
|
+
console.log(` Last Error: ${health.lastFailureReason}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
if (metrics) {
|
|
1279
|
+
console.log();
|
|
1280
|
+
console.log(import_chalk5.default.bold("Metrics"));
|
|
1281
|
+
console.log(` Total Requests: ${metrics.totalRequests}`);
|
|
1282
|
+
console.log(` Success Rate: ${backendInfo.metrics?.successRate}%`);
|
|
1283
|
+
console.log(` Avg Latency: ${backendInfo.metrics?.averageLatencyMs}ms`);
|
|
1284
|
+
}
|
|
1285
|
+
} catch (err) {
|
|
1286
|
+
console.error("Failed to get backend info:", err);
|
|
1287
|
+
process.exit(1);
|
|
1288
|
+
}
|
|
1289
|
+
});
|
|
1290
|
+
return cmd;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
// src/commands/proof.ts
|
|
1294
|
+
var import_commander13 = require("commander");
|
|
1295
|
+
var import_fs = require("fs");
|
|
1296
|
+
var import_sdk12 = require("@sip-protocol/sdk");
|
|
1297
|
+
function readProofFile(path3) {
|
|
1298
|
+
if (!(0, import_fs.existsSync)(path3)) {
|
|
1299
|
+
throw new Error(`File not found: ${path3}`);
|
|
1300
|
+
}
|
|
1301
|
+
const content = (0, import_fs.readFileSync)(path3, "utf-8");
|
|
1302
|
+
return JSON.parse(content);
|
|
1303
|
+
}
|
|
1304
|
+
function writeProofFile(path3, data) {
|
|
1305
|
+
(0, import_fs.writeFileSync)(path3, JSON.stringify(data, null, 2));
|
|
1306
|
+
}
|
|
1307
|
+
function readFromStdin() {
|
|
1308
|
+
return new Promise((resolve3, reject) => {
|
|
1309
|
+
let data = "";
|
|
1310
|
+
process.stdin.setEncoding("utf8");
|
|
1311
|
+
process.stdin.on("data", (chunk) => {
|
|
1312
|
+
data += chunk;
|
|
1313
|
+
});
|
|
1314
|
+
process.stdin.on("end", () => resolve3(data));
|
|
1315
|
+
process.stdin.on("error", reject);
|
|
1316
|
+
setTimeout(() => {
|
|
1317
|
+
if (data === "") {
|
|
1318
|
+
reject(new Error("No input received from stdin"));
|
|
1319
|
+
}
|
|
1320
|
+
}, 1e3);
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
var PROOF_SYSTEM_NAMES = {
|
|
1324
|
+
noir: "Noir (Aztec)",
|
|
1325
|
+
halo2: "Halo2 (Zcash)",
|
|
1326
|
+
kimchi: "Kimchi (Mina)",
|
|
1327
|
+
groth16: "Groth16",
|
|
1328
|
+
plonk: "PLONK",
|
|
1329
|
+
stark: "STARK"
|
|
1330
|
+
};
|
|
1331
|
+
function formatProofSystem(system) {
|
|
1332
|
+
return PROOF_SYSTEM_NAMES[system] || system;
|
|
1333
|
+
}
|
|
1334
|
+
function getSystemFromProof(proof) {
|
|
1335
|
+
return proof.metadata.system;
|
|
1336
|
+
}
|
|
1337
|
+
function createProofCommand() {
|
|
1338
|
+
const proof = new import_commander13.Command("proof").description("Proof composition operations (M20)");
|
|
1339
|
+
proof.command("generate").description("Generate a ZK proof").requiredOption("-s, --system <system>", "Proof system (noir|halo2|kimchi|mock)").requiredOption("-c, --circuit <id>", "Circuit identifier").option("-i, --inputs <json>", "Public inputs as JSON string").option("-f, --inputs-file <path>", "Public inputs from JSON file").option("-w, --witness <json>", "Private witness as JSON string").option("--witness-file <path>", "Private witness from JSON file").option("-o, --output <path>", "Output file path (default: stdout)").option("--json", "Output as JSON", false).action(async (options) => {
|
|
1340
|
+
const format = options.json ? "json" : "human";
|
|
1341
|
+
try {
|
|
1342
|
+
if (format === "human") {
|
|
1343
|
+
heading("Generate ZK Proof");
|
|
1344
|
+
}
|
|
1345
|
+
let publicInputs = {};
|
|
1346
|
+
if (options.inputs) {
|
|
1347
|
+
publicInputs = JSON.parse(options.inputs);
|
|
1348
|
+
} else if (options.inputsFile) {
|
|
1349
|
+
publicInputs = JSON.parse((0, import_fs.readFileSync)(options.inputsFile, "utf-8"));
|
|
1350
|
+
}
|
|
1351
|
+
const spin = format === "human" ? spinner(`Generating ${options.system} proof...`) : null;
|
|
1352
|
+
const systemLower = options.system.toLowerCase();
|
|
1353
|
+
const provider = new import_sdk12.MockProofProvider({ silent: true });
|
|
1354
|
+
await provider.initialize();
|
|
1355
|
+
const result = await provider.generateFundingProof({
|
|
1356
|
+
balance: BigInt(publicInputs.balance || "1000000"),
|
|
1357
|
+
minimumRequired: BigInt(publicInputs.minimum || "100"),
|
|
1358
|
+
blindingFactor: new Uint8Array(32),
|
|
1359
|
+
assetId: publicInputs.asset || "ETH",
|
|
1360
|
+
userAddress: publicInputs.user || "0x0000000000000000000000000000000000000000",
|
|
1361
|
+
ownershipSignature: new Uint8Array(64)
|
|
1362
|
+
});
|
|
1363
|
+
spin?.succeed("Proof generated");
|
|
1364
|
+
const proofMetadata = {
|
|
1365
|
+
system: systemLower,
|
|
1366
|
+
systemVersion: "1.0.0",
|
|
1367
|
+
circuitId: options.circuit,
|
|
1368
|
+
circuitVersion: "1.0.0",
|
|
1369
|
+
generatedAt: Date.now(),
|
|
1370
|
+
proofSizeBytes: result.proof.proof.length / 2
|
|
1371
|
+
// hex string to bytes
|
|
1372
|
+
};
|
|
1373
|
+
const proofData = {
|
|
1374
|
+
proof: {
|
|
1375
|
+
id: `proof_${Date.now()}`,
|
|
1376
|
+
proof: result.proof.proof,
|
|
1377
|
+
publicInputs: result.publicInputs.map(String),
|
|
1378
|
+
metadata: proofMetadata
|
|
1379
|
+
},
|
|
1380
|
+
metadata: {
|
|
1381
|
+
system: options.system,
|
|
1382
|
+
circuit: options.circuit,
|
|
1383
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
if (options.output) {
|
|
1387
|
+
writeProofFile(options.output, proofData);
|
|
1388
|
+
if (format === "human") {
|
|
1389
|
+
success(`Proof written to ${options.output}`);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
if (format === "json") {
|
|
1393
|
+
json(proofData);
|
|
1394
|
+
} else if (!options.output) {
|
|
1395
|
+
keyValue("System", formatProofSystem(systemLower));
|
|
1396
|
+
keyValue("Circuit", options.circuit);
|
|
1397
|
+
keyValue("Proof", formatHash(result.proof.proof, 16));
|
|
1398
|
+
keyValue("Public Inputs", JSON.stringify(result.publicInputs));
|
|
1399
|
+
}
|
|
1400
|
+
} catch (err) {
|
|
1401
|
+
if (format === "json") {
|
|
1402
|
+
json({ error: String(err) });
|
|
1403
|
+
} else {
|
|
1404
|
+
error(`Failed to generate proof: ${err}`);
|
|
1405
|
+
}
|
|
1406
|
+
process.exit(1);
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
proof.command("compose").description("Compose multiple proofs together").requiredOption("-p, --proofs <paths...>", "Proof file paths to compose").option("-t, --template <name>", "Composition template (sequential|parallel|recursive)", "sequential").option("-o, --output <path>", "Output file path (default: stdout)").option("--json", "Output as JSON", false).option("--validate", "Validate compatibility before composing", true).action(async (options) => {
|
|
1410
|
+
const format = options.json ? "json" : "human";
|
|
1411
|
+
try {
|
|
1412
|
+
if (format === "human") {
|
|
1413
|
+
heading("Compose Proofs");
|
|
1414
|
+
}
|
|
1415
|
+
const proofs = [];
|
|
1416
|
+
for (const path3 of options.proofs) {
|
|
1417
|
+
const proofFile = readProofFile(path3);
|
|
1418
|
+
proofs.push(proofFile.proof);
|
|
1419
|
+
}
|
|
1420
|
+
if (format === "human") {
|
|
1421
|
+
info(`Loaded ${proofs.length} proofs`);
|
|
1422
|
+
proofs.forEach((p, i) => {
|
|
1423
|
+
keyValue(` Proof ${i + 1}`, `${formatProofSystem(getSystemFromProof(p))} - ${formatHash(p.id)}`);
|
|
1424
|
+
});
|
|
1425
|
+
divider();
|
|
1426
|
+
}
|
|
1427
|
+
if (options.validate) {
|
|
1428
|
+
const validator = (0, import_sdk12.createCrossSystemValidator)();
|
|
1429
|
+
const systems = [...new Set(proofs.map((p) => getSystemFromProof(p)))];
|
|
1430
|
+
if (systems.length > 1) {
|
|
1431
|
+
const spin2 = format === "human" ? spinner("Validating cross-system compatibility...") : null;
|
|
1432
|
+
const report = validator.validate(proofs, {
|
|
1433
|
+
skipFieldCheck: false,
|
|
1434
|
+
skipCurveCheck: false
|
|
1435
|
+
});
|
|
1436
|
+
const errors = report.checks.filter((c) => !c.passed && c.severity === "error");
|
|
1437
|
+
if (errors.length > 0) {
|
|
1438
|
+
spin2?.fail("Compatibility check failed");
|
|
1439
|
+
if (format === "json") {
|
|
1440
|
+
json({ error: "Incompatible proof systems", report });
|
|
1441
|
+
} else {
|
|
1442
|
+
error("Proof systems are not compatible for composition");
|
|
1443
|
+
errors.forEach((e) => {
|
|
1444
|
+
error(` - ${e.name}: ${e.message}`);
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
process.exit(1);
|
|
1448
|
+
}
|
|
1449
|
+
spin2?.succeed("Compatibility validated");
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
const spin = format === "human" ? spinner(`Composing proofs (${options.template})...`) : null;
|
|
1453
|
+
const startTime = Date.now();
|
|
1454
|
+
const aggregator = (0, import_sdk12.createProofAggregator)();
|
|
1455
|
+
const mockProvider = new import_sdk12.MockProofProvider({ silent: true });
|
|
1456
|
+
await mockProvider.initialize();
|
|
1457
|
+
const getProvider = (_system) => {
|
|
1458
|
+
return mockProvider;
|
|
1459
|
+
};
|
|
1460
|
+
let result;
|
|
1461
|
+
if (options.template === "parallel") {
|
|
1462
|
+
result = await aggregator.aggregateParallel({
|
|
1463
|
+
proofs,
|
|
1464
|
+
getProvider,
|
|
1465
|
+
verifyBefore: options.validate,
|
|
1466
|
+
maxConcurrent: 4,
|
|
1467
|
+
onProgress: (event) => {
|
|
1468
|
+
if (format === "human" && spin) {
|
|
1469
|
+
const progress = Math.round(event.step / event.totalSteps * 100);
|
|
1470
|
+
spin.text = `${event.operation} (${progress}%)`;
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
} else {
|
|
1475
|
+
result = await aggregator.aggregateSequential({
|
|
1476
|
+
proofs,
|
|
1477
|
+
getProvider,
|
|
1478
|
+
verifyBefore: options.validate,
|
|
1479
|
+
onProgress: (event) => {
|
|
1480
|
+
if (format === "human" && spin) {
|
|
1481
|
+
const progress = Math.round(event.step / event.totalSteps * 100);
|
|
1482
|
+
spin.text = `${event.operation} (${progress}%)`;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
const timeMs = Date.now() - startTime;
|
|
1488
|
+
if (!result.success || !result.composedProof) {
|
|
1489
|
+
spin?.fail("Composition failed");
|
|
1490
|
+
if (format === "json") {
|
|
1491
|
+
json({ error: result.error || "Unknown error" });
|
|
1492
|
+
} else {
|
|
1493
|
+
error(`Composition failed: ${result.error || "Unknown error"}`);
|
|
1494
|
+
}
|
|
1495
|
+
process.exit(1);
|
|
1496
|
+
}
|
|
1497
|
+
spin?.succeed("Composition complete");
|
|
1498
|
+
const outputData = {
|
|
1499
|
+
proof: result.composedProof,
|
|
1500
|
+
metadata: {
|
|
1501
|
+
template: options.template,
|
|
1502
|
+
inputProofs: proofs.map((p) => p.id),
|
|
1503
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1504
|
+
timeMs
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
if (options.output) {
|
|
1508
|
+
writeProofFile(options.output, outputData);
|
|
1509
|
+
if (format === "human") {
|
|
1510
|
+
success(`Composed proof written to ${options.output}`);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
if (format === "json") {
|
|
1514
|
+
json(outputData);
|
|
1515
|
+
} else if (!options.output) {
|
|
1516
|
+
keyValue("Composed Proof ID", result.composedProof.id);
|
|
1517
|
+
keyValue("Component Proofs", result.composedProof.proofs.length.toString());
|
|
1518
|
+
keyValue("Strategy", result.composedProof.strategy);
|
|
1519
|
+
keyValue("Time", `${timeMs}ms`);
|
|
1520
|
+
}
|
|
1521
|
+
} catch (err) {
|
|
1522
|
+
if (format === "json") {
|
|
1523
|
+
json({ error: String(err) });
|
|
1524
|
+
} else {
|
|
1525
|
+
error(`Failed to compose proofs: ${err}`);
|
|
1526
|
+
}
|
|
1527
|
+
process.exit(1);
|
|
1528
|
+
}
|
|
1529
|
+
});
|
|
1530
|
+
proof.command("verify").description("Verify a proof or composed proof").argument("<path>", "Proof file path (or - for stdin)").option("--strict", "Enable strict verification mode", false).option("--json", "Output as JSON", false).action(async (path3, options) => {
|
|
1531
|
+
const format = options.json ? "json" : "human";
|
|
1532
|
+
try {
|
|
1533
|
+
if (format === "human") {
|
|
1534
|
+
heading("Verify Proof");
|
|
1535
|
+
}
|
|
1536
|
+
let proofData;
|
|
1537
|
+
if (path3 === "-") {
|
|
1538
|
+
const stdinData = await readFromStdin();
|
|
1539
|
+
proofData = JSON.parse(stdinData);
|
|
1540
|
+
} else {
|
|
1541
|
+
proofData = readProofFile(path3);
|
|
1542
|
+
}
|
|
1543
|
+
const spin = format === "human" ? spinner("Verifying proof...") : null;
|
|
1544
|
+
const pipeline = (0, import_sdk12.createVerificationPipeline)();
|
|
1545
|
+
const isComposed = "proofs" in proofData.proof && Array.isArray(proofData.proof.proofs);
|
|
1546
|
+
const mockProvider = new import_sdk12.MockProofProvider({ silent: true });
|
|
1547
|
+
await mockProvider.initialize();
|
|
1548
|
+
const getProvider = (_system) => {
|
|
1549
|
+
return mockProvider;
|
|
1550
|
+
};
|
|
1551
|
+
let result;
|
|
1552
|
+
if (isComposed) {
|
|
1553
|
+
result = await pipeline.verify(proofData.proof, {
|
|
1554
|
+
getProvider,
|
|
1555
|
+
config: {}
|
|
1556
|
+
});
|
|
1557
|
+
} else {
|
|
1558
|
+
result = await pipeline.verifySingle(proofData.proof, getProvider);
|
|
1559
|
+
}
|
|
1560
|
+
if (result.valid) {
|
|
1561
|
+
spin?.succeed("Proof is valid");
|
|
1562
|
+
} else {
|
|
1563
|
+
spin?.fail("Proof verification failed");
|
|
1564
|
+
}
|
|
1565
|
+
if (format === "json") {
|
|
1566
|
+
json({
|
|
1567
|
+
valid: result.valid,
|
|
1568
|
+
isComposed,
|
|
1569
|
+
details: result
|
|
1570
|
+
});
|
|
1571
|
+
} else {
|
|
1572
|
+
keyValue("Valid", result.valid ? "Yes" : "No");
|
|
1573
|
+
keyValue("Type", isComposed ? "Composed" : "Single");
|
|
1574
|
+
if (isComposed) {
|
|
1575
|
+
const composed = proofData.proof;
|
|
1576
|
+
keyValue("Component Proofs", composed.proofs.length.toString());
|
|
1577
|
+
}
|
|
1578
|
+
if (!result.valid && "error" in result) {
|
|
1579
|
+
error(`Reason: ${result.error}`);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
if (!result.valid) {
|
|
1583
|
+
process.exit(1);
|
|
1584
|
+
}
|
|
1585
|
+
} catch (err) {
|
|
1586
|
+
if (format === "json") {
|
|
1587
|
+
json({ valid: false, error: String(err) });
|
|
1588
|
+
} else {
|
|
1589
|
+
error(`Failed to verify proof: ${err}`);
|
|
1590
|
+
}
|
|
1591
|
+
process.exit(1);
|
|
1592
|
+
}
|
|
1593
|
+
});
|
|
1594
|
+
proof.command("inspect").description("Analyze and display proof details").argument("<path>", "Proof file path (or - for stdin)").option("--json", "Output as JSON", false).option("--full", "Show full proof data (not truncated)", false).action(async (path3, options) => {
|
|
1595
|
+
const format = options.json ? "json" : "human";
|
|
1596
|
+
try {
|
|
1597
|
+
if (format === "human") {
|
|
1598
|
+
heading("Proof Inspection");
|
|
1599
|
+
}
|
|
1600
|
+
let proofData;
|
|
1601
|
+
if (path3 === "-") {
|
|
1602
|
+
const stdinData = await readFromStdin();
|
|
1603
|
+
proofData = JSON.parse(stdinData);
|
|
1604
|
+
} else {
|
|
1605
|
+
proofData = readProofFile(path3);
|
|
1606
|
+
}
|
|
1607
|
+
const proof2 = proofData.proof;
|
|
1608
|
+
const isComposed = "proofs" in proof2 && Array.isArray(proof2.proofs);
|
|
1609
|
+
if (format === "json") {
|
|
1610
|
+
json({
|
|
1611
|
+
type: isComposed ? "composed" : "single",
|
|
1612
|
+
...proofData
|
|
1613
|
+
});
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
keyValue("Type", isComposed ? "Composed Proof" : "Single Proof");
|
|
1617
|
+
keyValue("ID", proof2.id);
|
|
1618
|
+
divider();
|
|
1619
|
+
if (isComposed) {
|
|
1620
|
+
const composed = proof2;
|
|
1621
|
+
keyValue("Strategy", composed.strategy);
|
|
1622
|
+
keyValue("Status", composed.status);
|
|
1623
|
+
keyValue("Component Proofs", composed.proofs.length.toString());
|
|
1624
|
+
info("\nComponent Proofs:");
|
|
1625
|
+
table(
|
|
1626
|
+
["#", "System", "ID", "Public Inputs"],
|
|
1627
|
+
composed.proofs.map((p, i) => [
|
|
1628
|
+
(i + 1).toString(),
|
|
1629
|
+
formatProofSystem(getSystemFromProof(p)),
|
|
1630
|
+
formatHash(p.id),
|
|
1631
|
+
p.publicInputs.length.toString()
|
|
1632
|
+
])
|
|
1633
|
+
);
|
|
1634
|
+
if (composed.compositionMetadata) {
|
|
1635
|
+
divider();
|
|
1636
|
+
info("Composition Metadata:");
|
|
1637
|
+
keyValue(" Proof Count", composed.compositionMetadata.proofCount.toString());
|
|
1638
|
+
keyValue(" Systems", composed.compositionMetadata.systems.join(", "));
|
|
1639
|
+
keyValue(" Composition Time", `${composed.compositionMetadata.compositionTimeMs}ms`);
|
|
1640
|
+
}
|
|
1641
|
+
} else {
|
|
1642
|
+
const single = proof2;
|
|
1643
|
+
keyValue("System", formatProofSystem(getSystemFromProof(single)));
|
|
1644
|
+
if (single.metadata) {
|
|
1645
|
+
keyValue("Circuit ID", single.metadata.circuitId || "N/A");
|
|
1646
|
+
keyValue("Circuit Version", single.metadata.circuitVersion || "N/A");
|
|
1647
|
+
keyValue("System Version", single.metadata.systemVersion || "N/A");
|
|
1648
|
+
keyValue("Proof Size", `${single.metadata.proofSizeBytes} bytes`);
|
|
1649
|
+
if (single.metadata.generatedAt) {
|
|
1650
|
+
keyValue("Generated At", new Date(single.metadata.generatedAt).toISOString());
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
divider();
|
|
1654
|
+
info("Proof Data:");
|
|
1655
|
+
if (options.full) {
|
|
1656
|
+
keyValue("Proof", single.proof);
|
|
1657
|
+
} else {
|
|
1658
|
+
keyValue("Proof", formatHash(single.proof, 32));
|
|
1659
|
+
}
|
|
1660
|
+
info("\nPublic Inputs:");
|
|
1661
|
+
if (single.publicInputs && single.publicInputs.length > 0) {
|
|
1662
|
+
single.publicInputs.forEach((input, i) => {
|
|
1663
|
+
keyValue(` [${i}]`, formatHash(input, 16));
|
|
1664
|
+
});
|
|
1665
|
+
} else {
|
|
1666
|
+
info(" (none)");
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
if (proofData.metadata) {
|
|
1670
|
+
divider();
|
|
1671
|
+
info("File Metadata:");
|
|
1672
|
+
Object.entries(proofData.metadata).forEach(([key, value]) => {
|
|
1673
|
+
keyValue(` ${key}`, typeof value === "object" ? JSON.stringify(value) : String(value));
|
|
1674
|
+
});
|
|
1675
|
+
}
|
|
1676
|
+
} catch (err) {
|
|
1677
|
+
if (format === "json") {
|
|
1678
|
+
json({ error: String(err) });
|
|
1679
|
+
} else {
|
|
1680
|
+
error(`Failed to inspect proof: ${err}`);
|
|
1681
|
+
}
|
|
1682
|
+
process.exit(1);
|
|
1683
|
+
}
|
|
1684
|
+
});
|
|
1685
|
+
proof.command("convert").description("Convert proof between formats").argument("<path>", "Source proof file path (or - for stdin)").requiredOption("-t, --to <format>", "Target format (sip|noir|halo2|kimchi|json)").option("-o, --output <path>", "Output file path (default: stdout)").option("--json", "Output as JSON", false).action(async (path3, options) => {
|
|
1686
|
+
const format = options.json ? "json" : "human";
|
|
1687
|
+
try {
|
|
1688
|
+
if (format === "human") {
|
|
1689
|
+
heading("Convert Proof Format");
|
|
1690
|
+
}
|
|
1691
|
+
let proofData;
|
|
1692
|
+
if (path3 === "-") {
|
|
1693
|
+
const stdinData = await readFromStdin();
|
|
1694
|
+
proofData = JSON.parse(stdinData);
|
|
1695
|
+
} else {
|
|
1696
|
+
proofData = readProofFile(path3);
|
|
1697
|
+
}
|
|
1698
|
+
const spin = format === "human" ? spinner(`Converting to ${options.to} format...`) : null;
|
|
1699
|
+
const converter = new import_sdk12.UnifiedProofConverter();
|
|
1700
|
+
const targetFormat = options.to.toLowerCase();
|
|
1701
|
+
const single = proofData.proof;
|
|
1702
|
+
let result;
|
|
1703
|
+
if (targetFormat === "json") {
|
|
1704
|
+
result = proofData;
|
|
1705
|
+
} else if (targetFormat === "sip") {
|
|
1706
|
+
result = proofData;
|
|
1707
|
+
} else {
|
|
1708
|
+
const converted = converter.fromSIP(single);
|
|
1709
|
+
if (!converted.success || !converted.result) {
|
|
1710
|
+
throw new Error(converted.error || "Conversion failed");
|
|
1711
|
+
}
|
|
1712
|
+
result = converted.result;
|
|
1713
|
+
}
|
|
1714
|
+
spin?.succeed("Conversion complete");
|
|
1715
|
+
const outputData = {
|
|
1716
|
+
originalFormat: getSystemFromProof(single),
|
|
1717
|
+
targetFormat,
|
|
1718
|
+
proof: result,
|
|
1719
|
+
convertedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1720
|
+
};
|
|
1721
|
+
if (options.output) {
|
|
1722
|
+
(0, import_fs.writeFileSync)(options.output, JSON.stringify(outputData, null, 2));
|
|
1723
|
+
if (format === "human") {
|
|
1724
|
+
success(`Converted proof written to ${options.output}`);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
if (format === "json" || !options.output) {
|
|
1728
|
+
json(outputData);
|
|
1729
|
+
}
|
|
1730
|
+
} catch (err) {
|
|
1731
|
+
if (format === "json") {
|
|
1732
|
+
json({ error: String(err) });
|
|
1733
|
+
} else {
|
|
1734
|
+
error(`Failed to convert proof: ${err}`);
|
|
1735
|
+
}
|
|
1736
|
+
process.exit(1);
|
|
1737
|
+
}
|
|
1738
|
+
});
|
|
1739
|
+
proof.command("systems").description("List supported proof systems and their capabilities").option("--json", "Output as JSON", false).action(async (options) => {
|
|
1740
|
+
const format = options.json ? "json" : "human";
|
|
1741
|
+
const systems = [
|
|
1742
|
+
{
|
|
1743
|
+
id: "noir",
|
|
1744
|
+
name: "Noir (Aztec)",
|
|
1745
|
+
curve: "BN254",
|
|
1746
|
+
features: ["SNARK", "Universal Setup", "Browser Support"],
|
|
1747
|
+
status: "Production"
|
|
1748
|
+
},
|
|
1749
|
+
{
|
|
1750
|
+
id: "halo2",
|
|
1751
|
+
name: "Halo2 (Zcash)",
|
|
1752
|
+
curve: "Pallas/Vesta",
|
|
1753
|
+
features: ["SNARK", "No Trusted Setup", "Recursive"],
|
|
1754
|
+
status: "Production"
|
|
1755
|
+
},
|
|
1756
|
+
{
|
|
1757
|
+
id: "kimchi",
|
|
1758
|
+
name: "Kimchi (Mina)",
|
|
1759
|
+
curve: "Pasta",
|
|
1760
|
+
features: ["SNARK", "Recursive", "Succinct"],
|
|
1761
|
+
status: "Production"
|
|
1762
|
+
},
|
|
1763
|
+
{
|
|
1764
|
+
id: "groth16",
|
|
1765
|
+
name: "Groth16",
|
|
1766
|
+
curve: "BN254",
|
|
1767
|
+
features: ["SNARK", "Smallest Proofs", "Fastest Verification"],
|
|
1768
|
+
status: "Supported"
|
|
1769
|
+
},
|
|
1770
|
+
{
|
|
1771
|
+
id: "plonk",
|
|
1772
|
+
name: "PLONK",
|
|
1773
|
+
curve: "BN254",
|
|
1774
|
+
features: ["SNARK", "Universal Setup", "Flexible"],
|
|
1775
|
+
status: "Supported"
|
|
1776
|
+
},
|
|
1777
|
+
{
|
|
1778
|
+
id: "stark",
|
|
1779
|
+
name: "STARK",
|
|
1780
|
+
curve: "None (Hash-based)",
|
|
1781
|
+
features: ["No Trusted Setup", "Post-Quantum", "Large Proofs"],
|
|
1782
|
+
status: "Experimental"
|
|
1783
|
+
}
|
|
1784
|
+
];
|
|
1785
|
+
if (format === "json") {
|
|
1786
|
+
json({ systems });
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1789
|
+
heading("Supported Proof Systems");
|
|
1790
|
+
table(
|
|
1791
|
+
["System", "Curve", "Status"],
|
|
1792
|
+
systems.map((s) => [s.name, s.curve, s.status])
|
|
1793
|
+
);
|
|
1794
|
+
divider();
|
|
1795
|
+
info("Features by System:");
|
|
1796
|
+
systems.forEach((s) => {
|
|
1797
|
+
keyValue(` ${s.name}`, s.features.join(", "));
|
|
1798
|
+
});
|
|
1799
|
+
});
|
|
1800
|
+
proof.command("compat").description("Check compatibility between proof systems").argument("<systems...>", "Proof systems to check (e.g., noir halo2)").option("--json", "Output as JSON", false).action(async (systems, options) => {
|
|
1801
|
+
const format = options.json ? "json" : "human";
|
|
1802
|
+
try {
|
|
1803
|
+
if (format === "human") {
|
|
1804
|
+
heading("Proof System Compatibility");
|
|
1805
|
+
}
|
|
1806
|
+
const mockProofs = systems.map((sys, i) => ({
|
|
1807
|
+
id: `mock_${sys}_${i}`,
|
|
1808
|
+
proof: "0x00",
|
|
1809
|
+
publicInputs: ["0x01"],
|
|
1810
|
+
metadata: {
|
|
1811
|
+
system: sys,
|
|
1812
|
+
systemVersion: "1.0.0",
|
|
1813
|
+
circuitId: "test",
|
|
1814
|
+
circuitVersion: "1.0.0",
|
|
1815
|
+
generatedAt: Date.now(),
|
|
1816
|
+
proofSizeBytes: 1
|
|
1817
|
+
}
|
|
1818
|
+
}));
|
|
1819
|
+
const validator = (0, import_sdk12.createCrossSystemValidator)();
|
|
1820
|
+
const report = validator.validate(mockProofs, {
|
|
1821
|
+
skipFieldCheck: false,
|
|
1822
|
+
skipCurveCheck: false
|
|
1823
|
+
});
|
|
1824
|
+
const errors = report.checks.filter((c) => !c.passed && c.severity === "error");
|
|
1825
|
+
const warnings = report.checks.filter((c) => !c.passed && c.severity === "warning");
|
|
1826
|
+
const compatible = errors.length === 0;
|
|
1827
|
+
if (format === "json") {
|
|
1828
|
+
json({
|
|
1829
|
+
systems,
|
|
1830
|
+
compatible,
|
|
1831
|
+
errors: errors.map((e) => ({ check: e.name, message: e.message })),
|
|
1832
|
+
warnings: warnings.map((w) => ({ check: w.name, message: w.message })),
|
|
1833
|
+
report
|
|
1834
|
+
});
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
keyValue("Systems", systems.join(", "));
|
|
1838
|
+
keyValue("Compatible", compatible ? "Yes" : "No");
|
|
1839
|
+
if (compatible) {
|
|
1840
|
+
success("These proof systems can be composed together");
|
|
1841
|
+
} else {
|
|
1842
|
+
error("These proof systems are not directly compatible");
|
|
1843
|
+
divider();
|
|
1844
|
+
info("Issues:");
|
|
1845
|
+
errors.forEach((e) => {
|
|
1846
|
+
error(` - ${e.name}: ${e.message}`);
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
if (warnings.length > 0) {
|
|
1850
|
+
divider();
|
|
1851
|
+
info("Warnings:");
|
|
1852
|
+
warnings.forEach((w) => {
|
|
1853
|
+
info(` \u26A0 ${w.name}: ${w.message}`);
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
if (!compatible) {
|
|
1857
|
+
process.exit(1);
|
|
1858
|
+
}
|
|
1859
|
+
} catch (err) {
|
|
1860
|
+
if (format === "json") {
|
|
1861
|
+
json({ error: String(err) });
|
|
1862
|
+
} else {
|
|
1863
|
+
error(`Failed to check compatibility: ${err}`);
|
|
1864
|
+
}
|
|
1865
|
+
process.exit(1);
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
return proof;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
527
1871
|
// src/index.ts
|
|
528
|
-
var program = new
|
|
529
|
-
program.name("sip").description("Shielded Intents Protocol (SIP) - Privacy layer for cross-chain transactions").version("0.
|
|
1872
|
+
var program = new import_commander14.Command();
|
|
1873
|
+
program.name("sip").description("Shielded Intents Protocol (SIP) - Privacy layer for cross-chain transactions").version("0.2.0");
|
|
1874
|
+
program.addCommand(createSetupCommand());
|
|
530
1875
|
program.addCommand(createInitCommand());
|
|
531
1876
|
program.addCommand(createKeygenCommand());
|
|
1877
|
+
program.addCommand(createStealthCommand());
|
|
1878
|
+
program.addCommand(createViewingKeyCommand());
|
|
532
1879
|
program.addCommand(createCommitCommand());
|
|
533
1880
|
program.addCommand(createProveCommand());
|
|
534
1881
|
program.addCommand(createVerifyCommand());
|
|
535
1882
|
program.addCommand(createQuoteCommand());
|
|
536
1883
|
program.addCommand(createSwapCommand());
|
|
537
1884
|
program.addCommand(createScanCommand());
|
|
1885
|
+
program.addCommand(createBackendsCommand());
|
|
1886
|
+
program.addCommand(createProofCommand());
|
|
538
1887
|
program.parse();
|