@sip-protocol/cli 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 RECTOR Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # @sip-protocol/cli
2
+
3
+ Command-line tool for Shielded Intents Protocol (SIP) operations.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @sip-protocol/cli
9
+ ```
10
+
11
+ Or use directly with npx:
12
+
13
+ ```bash
14
+ npx @sip-protocol/cli --help
15
+ ```
16
+
17
+ ## Commands
18
+
19
+ ### Initialize Configuration
20
+
21
+ ```bash
22
+ sip init [options]
23
+
24
+ Options:
25
+ -n, --network <network> Network (mainnet|testnet) (default: "testnet")
26
+ -p, --privacy <level> Default privacy level (default: "transparent")
27
+ --reset Reset configuration to defaults
28
+ ```
29
+
30
+ ### Generate Stealth Meta-Address
31
+
32
+ ```bash
33
+ sip keygen [options]
34
+
35
+ Options:
36
+ -c, --chain <chain> Target chain (ethereum, solana, near) (default: "ethereum")
37
+ --spending-key <key> Spending private key (hex)
38
+ --viewing-key <key> Viewing private key (hex)
39
+ ```
40
+
41
+ ### Create Pedersen Commitment
42
+
43
+ ```bash
44
+ sip commit <amount> [options]
45
+
46
+ Arguments:
47
+ amount Amount to commit
48
+
49
+ Options:
50
+ -b, --blinding <factor> Blinding factor (hex, optional)
51
+ --verify Verify the commitment after creation
52
+ ```
53
+
54
+ ### Generate ZK Proof
55
+
56
+ ```bash
57
+ # Funding proof
58
+ sip prove funding [options]
59
+
60
+ Options:
61
+ -b, --balance <amount> Current balance (required)
62
+ -m, --minimum <amount> Minimum required (required)
63
+ -c, --commitment <hex> Balance commitment
64
+
65
+ # Validity proof
66
+ sip prove validity [options]
67
+
68
+ Options:
69
+ -i, --intent <hash> Intent hash (required)
70
+ -s, --sender <address> Sender address (required)
71
+ -c, --commitment <hex> Amount commitment
72
+ ```
73
+
74
+ ### Verify ZK Proof
75
+
76
+ ```bash
77
+ sip verify <proof> [options]
78
+
79
+ Arguments:
80
+ proof Proof to verify (hex string)
81
+
82
+ Options:
83
+ -t, --type <type> Proof type (funding|validity|fulfillment) (default: "funding")
84
+ -p, --public-inputs <json> Public inputs (JSON array)
85
+ ```
86
+
87
+ ### Get Swap Quote
88
+
89
+ ```bash
90
+ sip quote <from-chain> <to-chain> <amount> [options]
91
+
92
+ Arguments:
93
+ from-chain Source chain (e.g., ethereum, solana)
94
+ to-chain Destination chain
95
+ amount Amount to swap
96
+
97
+ Options:
98
+ -t, --token <symbol> Token symbol (default: native token)
99
+ -p, --privacy <level> Privacy level (transparent|shielded|compliant)
100
+ ```
101
+
102
+ ### Execute Swap
103
+
104
+ ```bash
105
+ sip swap <from-chain> <to-chain> <amount> [options]
106
+
107
+ Arguments:
108
+ from-chain Source chain (e.g., ethereum, solana)
109
+ to-chain Destination chain
110
+ amount Amount to swap
111
+
112
+ Options:
113
+ -t, --token <symbol> Token symbol (default: native token)
114
+ -p, --privacy <level> Privacy level (transparent|shielded|compliant)
115
+ -r, --recipient <address> Recipient address (optional)
116
+ --solver <id> Specific solver to use
117
+ ```
118
+
119
+ ### Scan for Stealth Payments
120
+
121
+ ```bash
122
+ sip scan [options]
123
+
124
+ Options:
125
+ -c, --chain <chain> Chain to scan (ethereum, solana, near) (required)
126
+ -s, --spending-key <key> Your spending private key (hex) (required)
127
+ -v, --viewing-key <key> Your viewing private key (hex) (required)
128
+ -a, --addresses <addresses...> Specific addresses to check
129
+ ```
130
+
131
+ ## Examples
132
+
133
+ ```bash
134
+ # Initialize with testnet
135
+ sip init --network testnet --privacy shielded
136
+
137
+ # Generate stealth keys for Ethereum
138
+ sip keygen --chain ethereum
139
+
140
+ # Create commitment
141
+ sip commit 1000000000000000000 --verify
142
+
143
+ # Generate funding proof
144
+ sip prove funding --balance 5000000 --minimum 1000000
145
+
146
+ # Get quote for ETH to SOL swap
147
+ sip quote ethereum solana 1000000000000000000 --privacy shielded
148
+
149
+ # Execute swap
150
+ sip swap ethereum solana 1000000000000000000 --privacy shielded
151
+
152
+ # Scan for stealth payments
153
+ sip scan --chain ethereum -s 0xYOUR_SPENDING_KEY -v 0xYOUR_VIEWING_KEY -a 0xADDRESS1 0xADDRESS2
154
+ ```
155
+
156
+ ## Development
157
+
158
+ ```bash
159
+ # Install dependencies
160
+ pnpm install
161
+
162
+ # Build
163
+ pnpm build
164
+
165
+ # Test locally
166
+ node bin/sip.js --help
167
+
168
+ # Link globally for testing
169
+ npm link
170
+ sip --help
171
+ ```
172
+
173
+ ## License
174
+
175
+ MIT
package/bin/sip.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Import the compiled CLI from dist
4
+ require('../dist/index.js')
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,538 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/index.ts
27
+ var import_commander9 = require("commander");
28
+
29
+ // src/commands/init.ts
30
+ var import_commander = require("commander");
31
+ var import_types = require("@sip-protocol/types");
32
+
33
+ // src/utils/config.ts
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
+ var store = new import_conf.default({
46
+ projectName: "sip-protocol",
47
+ schema
48
+ });
49
+ function getConfig() {
50
+ return {
51
+ network: store.get("network"),
52
+ defaultPrivacy: store.get("defaultPrivacy"),
53
+ defaultChain: store.get("defaultChain"),
54
+ rpcEndpoints: store.get("rpcEndpoints")
55
+ };
56
+ }
57
+ function setConfig(key, value) {
58
+ store.set(key, value);
59
+ }
60
+ function resetConfig() {
61
+ store.clear();
62
+ }
63
+ function getConfigPath() {
64
+ return store.path;
65
+ }
66
+
67
+ // src/utils/output.ts
68
+ var import_chalk = __toESM(require("chalk"));
69
+ var import_ora = __toESM(require("ora"));
70
+ function success(message) {
71
+ console.log(import_chalk.default.green("\u2713"), message);
72
+ }
73
+ function error(message) {
74
+ console.error(import_chalk.default.red("\u2717"), message);
75
+ }
76
+ function warning(message) {
77
+ console.warn(import_chalk.default.yellow("\u26A0"), message);
78
+ }
79
+ function info(message) {
80
+ console.log(import_chalk.default.blue("\u2139"), message);
81
+ }
82
+ function heading(message) {
83
+ console.log(import_chalk.default.bold.cyan(`
84
+ ${message}
85
+ `));
86
+ }
87
+ function keyValue(key, value) {
88
+ console.log(import_chalk.default.gray(` ${key}:`), import_chalk.default.white(String(value)));
89
+ }
90
+ function spinner(text) {
91
+ return (0, import_ora.default)(text).start();
92
+ }
93
+ function table(headers, rows) {
94
+ const colWidths = headers.map(
95
+ (h, i) => Math.max(h.length, ...rows.map((r) => String(r[i] || "").length))
96
+ );
97
+ console.log(
98
+ headers.map((h, i) => import_chalk.default.bold(h.padEnd(colWidths[i]))).join(" ")
99
+ );
100
+ console.log(colWidths.map((w) => "\u2500".repeat(w)).join(" "));
101
+ rows.forEach((row) => {
102
+ console.log(
103
+ row.map((cell, i) => String(cell).padEnd(colWidths[i])).join(" ")
104
+ );
105
+ });
106
+ }
107
+ function formatAmount(amount, decimals = 18) {
108
+ const divisor = 10n ** BigInt(decimals);
109
+ const integer = amount / divisor;
110
+ const fraction = amount % divisor;
111
+ const fractionStr = fraction.toString().padStart(decimals, "0").slice(0, 6);
112
+ return `${integer}.${fractionStr}`;
113
+ }
114
+ function formatHash(hash, length = 8) {
115
+ if (hash.length <= length * 2) return hash;
116
+ return `${hash.slice(0, length)}...${hash.slice(-length)}`;
117
+ }
118
+
119
+ // src/commands/init.ts
120
+ function createInitCommand() {
121
+ return new import_commander.Command("init").description("Initialize SIP configuration").option("-n, --network <network>", "Network (mainnet|testnet)", "testnet").option("-p, --privacy <level>", "Default privacy level", "transparent").option("--reset", "Reset configuration to defaults").action(async (options) => {
122
+ try {
123
+ heading("Initialize SIP Protocol");
124
+ if (options.reset) {
125
+ resetConfig();
126
+ success("Configuration reset to defaults");
127
+ }
128
+ const privacy = options.privacy;
129
+ if (!Object.values(import_types.PrivacyLevel).includes(privacy)) {
130
+ throw new Error(`Invalid privacy level: ${privacy}`);
131
+ }
132
+ setConfig("network", options.network);
133
+ setConfig("defaultPrivacy", privacy);
134
+ success("SIP initialized successfully");
135
+ info(`Network: ${options.network}`);
136
+ info(`Default Privacy: ${privacy}`);
137
+ info(`Config file: ${getConfigPath()}`);
138
+ } catch (err) {
139
+ console.error("Failed to initialize:", err);
140
+ process.exit(1);
141
+ }
142
+ });
143
+ }
144
+
145
+ // src/commands/keygen.ts
146
+ var import_commander2 = require("commander");
147
+ var import_sdk = require("@sip-protocol/sdk");
148
+ 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) => {
150
+ try {
151
+ heading("Generate Stealth Meta-Address");
152
+ const chain = options.chain;
153
+ const useEd25519 = (0, import_sdk.isEd25519Chain)(chain);
154
+ let metaAddress;
155
+ if (useEd25519) {
156
+ if (options.spendingKey || options.viewingKey) {
157
+ warning("Ed25519 chains do not support custom keys in CLI yet");
158
+ }
159
+ metaAddress = (0, import_sdk.generateEd25519StealthMetaAddress)(chain);
160
+ } else {
161
+ metaAddress = (0, import_sdk.generateStealthMetaAddress)(chain);
162
+ }
163
+ success("Stealth meta-address generated");
164
+ keyValue("Chain", chain);
165
+ const spendingPubKey = metaAddress.metaAddress.spendingKey;
166
+ const viewingPubKey = metaAddress.metaAddress.viewingKey;
167
+ const spendingPrivKey = metaAddress.spendingPrivateKey;
168
+ const viewingPrivKey = metaAddress.viewingPrivateKey;
169
+ keyValue("Spending Public Key", spendingPubKey);
170
+ keyValue("Viewing Public Key", viewingPubKey);
171
+ const encoded = (0, import_sdk.encodeStealthMetaAddress)(metaAddress.metaAddress);
172
+ keyValue("Encoded Address", encoded);
173
+ console.log();
174
+ warning("PRIVATE KEYS - Keep these secure!");
175
+ keyValue("Spending Private Key", spendingPrivKey);
176
+ keyValue("Viewing Private Key", viewingPrivKey);
177
+ } catch (err) {
178
+ console.error("Failed to generate keys:", err);
179
+ process.exit(1);
180
+ }
181
+ });
182
+ }
183
+
184
+ // src/commands/commit.ts
185
+ var import_commander3 = require("commander");
186
+ var import_sdk2 = require("@sip-protocol/sdk");
187
+ function createCommitCommand() {
188
+ return new import_commander3.Command("commit").description("Create Pedersen commitment").argument("<amount>", "Amount to commit").option("-b, --blinding <factor>", "Blinding factor (hex, optional)").option("--verify", "Verify the commitment after creation").action(async (amountStr, options) => {
189
+ try {
190
+ heading("Create Pedersen Commitment");
191
+ const amount = BigInt(amountStr);
192
+ info(`Committing amount: ${amount}`);
193
+ const commitment = options.blinding ? (0, import_sdk2.commit)(amount, options.blinding) : (0, import_sdk2.commit)(amount);
194
+ success("Commitment created");
195
+ keyValue("Commitment", commitment.commitment);
196
+ keyValue("Blinding Factor", commitment.blinding);
197
+ keyValue("Amount", amount.toString());
198
+ if (options.verify) {
199
+ console.log();
200
+ info("Verifying commitment...");
201
+ const isValid = (0, import_sdk2.verifyOpening)(commitment.commitment, amount, commitment.blinding);
202
+ if (isValid) {
203
+ success("Commitment verified successfully");
204
+ } else {
205
+ console.error("Commitment verification failed");
206
+ process.exit(1);
207
+ }
208
+ }
209
+ } catch (err) {
210
+ console.error("Failed to create commitment:", err);
211
+ process.exit(1);
212
+ }
213
+ });
214
+ }
215
+
216
+ // src/commands/prove.ts
217
+ var import_commander4 = require("commander");
218
+ var import_sdk3 = require("@sip-protocol/sdk");
219
+ function createProveCommand() {
220
+ const prove = new import_commander4.Command("prove").description("Generate ZK proof");
221
+ prove.command("funding").description("Generate funding proof").requiredOption("-b, --balance <amount>", "Current balance").requiredOption("-m, --minimum <amount>", "Minimum required").option("-a, --asset <id>", "Asset identifier", "ETH").option("-u, --user <address>", "User address", "0x0000000000000000000000000000000000000000").action(async (options) => {
222
+ try {
223
+ heading("Generate Funding Proof");
224
+ const blindingFactor = new Uint8Array(32);
225
+ const ownershipSignature = new Uint8Array(64);
226
+ const params = {
227
+ balance: BigInt(options.balance),
228
+ minimumRequired: BigInt(options.minimum),
229
+ blindingFactor,
230
+ assetId: options.asset,
231
+ userAddress: options.user,
232
+ ownershipSignature
233
+ };
234
+ const spin = spinner("Generating proof...");
235
+ const provider = new import_sdk3.MockProofProvider({ silent: true });
236
+ await provider.initialize();
237
+ const result = await provider.generateFundingProof(params);
238
+ spin.succeed("Proof generated");
239
+ success("Funding proof created");
240
+ keyValue("Proof", result.proof.proof);
241
+ keyValue("Public Inputs", JSON.stringify(result.publicInputs));
242
+ keyValue("Type", result.proof.type);
243
+ } catch (err) {
244
+ console.error("Failed to generate proof:", err);
245
+ process.exit(1);
246
+ }
247
+ });
248
+ prove.command("validity").description("Generate validity proof").requiredOption("-i, --intent <hash>", "Intent hash").requiredOption("-s, --sender <address>", "Sender address").action(async (options) => {
249
+ try {
250
+ heading("Generate Validity Proof");
251
+ const senderBlinding = new Uint8Array(32);
252
+ const senderSecret = new Uint8Array(32);
253
+ const authorizationSignature = new Uint8Array(64);
254
+ const nonce = new Uint8Array(32);
255
+ const now = Math.floor(Date.now() / 1e3);
256
+ const params = {
257
+ intentHash: options.intent,
258
+ senderAddress: options.sender,
259
+ senderBlinding,
260
+ senderSecret,
261
+ authorizationSignature,
262
+ nonce,
263
+ timestamp: now,
264
+ expiry: now + 300
265
+ // 5 minutes from now
266
+ };
267
+ const spin = spinner("Generating proof...");
268
+ const provider = new import_sdk3.MockProofProvider({ silent: true });
269
+ await provider.initialize();
270
+ const result = await provider.generateValidityProof(params);
271
+ spin.succeed("Proof generated");
272
+ success("Validity proof created");
273
+ keyValue("Proof", result.proof.proof);
274
+ keyValue("Public Inputs", JSON.stringify(result.publicInputs));
275
+ keyValue("Type", result.proof.type);
276
+ } catch (err) {
277
+ console.error("Failed to generate proof:", err);
278
+ process.exit(1);
279
+ }
280
+ });
281
+ return prove;
282
+ }
283
+
284
+ // src/commands/verify.ts
285
+ var import_commander5 = require("commander");
286
+ var import_sdk4 = require("@sip-protocol/sdk");
287
+ function createVerifyCommand() {
288
+ return new import_commander5.Command("verify").description("Verify ZK proof").argument("<proof>", "Proof to verify (hex string)").option("-t, --type <type>", "Proof type (funding|validity|fulfillment)", "funding").option("-p, --public-inputs <json>", "Public inputs (JSON array)").action(async (proofHex, options) => {
289
+ try {
290
+ heading("Verify ZK Proof");
291
+ info(`Proof type: ${options.type}`);
292
+ info(`Proof: ${proofHex.slice(0, 20)}...`);
293
+ const publicInputs = options.publicInputs ? JSON.parse(options.publicInputs) : [];
294
+ const proofHexStr = proofHex.startsWith("0x") ? proofHex : `0x${proofHex}`;
295
+ const zkProof = {
296
+ type: options.type,
297
+ proof: proofHexStr,
298
+ publicInputs
299
+ };
300
+ const spin = spinner("Verifying proof...");
301
+ const provider = new import_sdk4.MockProofProvider({ silent: true });
302
+ await provider.initialize();
303
+ const isValid = await provider.verifyProof(zkProof);
304
+ spin.stop();
305
+ if (isValid) {
306
+ success(`Proof is valid (type: ${options.type})`);
307
+ } else {
308
+ error("Proof is invalid");
309
+ process.exit(1);
310
+ }
311
+ } catch (err) {
312
+ console.error("Failed to verify proof:", err);
313
+ process.exit(1);
314
+ }
315
+ });
316
+ }
317
+
318
+ // src/commands/quote.ts
319
+ var import_commander6 = require("commander");
320
+ var import_sdk5 = require("@sip-protocol/sdk");
321
+ function createQuoteCommand() {
322
+ return new import_commander6.Command("quote").description("Get swap quote").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)").action(async (fromChain, toChain, amountStr, options) => {
323
+ try {
324
+ heading("Get Swap Quote");
325
+ const config = getConfig();
326
+ const amount = BigInt(amountStr);
327
+ const privacy = options.privacy || config.defaultPrivacy;
328
+ const sip = (0, import_sdk5.createSIP)(config.network);
329
+ const spin = spinner("Fetching quotes...");
330
+ const inputAsset = import_sdk5.NATIVE_TOKENS[fromChain] || {
331
+ chain: fromChain,
332
+ symbol: options.token || "native",
333
+ address: null,
334
+ decimals: 18
335
+ };
336
+ const outputAsset = import_sdk5.NATIVE_TOKENS[toChain] || {
337
+ chain: toChain,
338
+ symbol: options.token || "native",
339
+ address: null,
340
+ decimals: 18
341
+ };
342
+ const intent = await sip.createIntent({
343
+ input: {
344
+ asset: inputAsset,
345
+ amount
346
+ },
347
+ output: {
348
+ asset: outputAsset,
349
+ minAmount: 0n,
350
+ // Accept any amount for quote discovery
351
+ maxSlippage: 0.05
352
+ // 5% slippage tolerance
353
+ },
354
+ privacy
355
+ });
356
+ const quotes = await sip.getQuotes(intent);
357
+ spin.succeed(`Found ${quotes.length} quote(s)`);
358
+ if (quotes.length === 0) {
359
+ console.log("\nNo quotes available");
360
+ return;
361
+ }
362
+ console.log();
363
+ const headers = ["Solver", "Output Amount", "Fee", "Time (s)"];
364
+ const rows = quotes.map((q) => [
365
+ q.solverId,
366
+ formatAmount(q.outputAmount),
367
+ formatAmount(q.fee),
368
+ q.estimatedTime.toString()
369
+ ]);
370
+ table(headers, rows);
371
+ const best = quotes[0];
372
+ console.log();
373
+ success("Best quote:");
374
+ keyValue("Solver", best.solverId);
375
+ keyValue("Output Amount", formatAmount(best.outputAmount));
376
+ keyValue("Estimated Time", `${best.estimatedTime}s`);
377
+ } catch (err) {
378
+ console.error("Failed to get quote:", err);
379
+ process.exit(1);
380
+ }
381
+ });
382
+ }
383
+
384
+ // src/commands/swap.ts
385
+ var import_commander7 = require("commander");
386
+ var import_sdk6 = require("@sip-protocol/sdk");
387
+ 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) => {
389
+ try {
390
+ heading("Execute Swap");
391
+ const config = getConfig();
392
+ const amount = BigInt(amountStr);
393
+ const privacy = options.privacy || config.defaultPrivacy;
394
+ const sip = (0, import_sdk6.createSIP)(config.network);
395
+ const inputAsset = import_sdk6.NATIVE_TOKENS[fromChain] || {
396
+ chain: fromChain,
397
+ symbol: options.token || "native",
398
+ address: null,
399
+ decimals: 18
400
+ };
401
+ const outputAsset = import_sdk6.NATIVE_TOKENS[toChain] || {
402
+ chain: toChain,
403
+ symbol: options.token || "native",
404
+ address: null,
405
+ decimals: 18
406
+ };
407
+ info("Creating shielded intent...");
408
+ const intent = await sip.createIntent({
409
+ input: {
410
+ asset: inputAsset,
411
+ amount
412
+ },
413
+ output: {
414
+ asset: outputAsset,
415
+ minAmount: 0n,
416
+ // Accept any amount
417
+ maxSlippage: 0.05
418
+ // 5% slippage tolerance
419
+ },
420
+ privacy,
421
+ recipientMetaAddress: options.recipient
422
+ });
423
+ success("Intent created");
424
+ keyValue("Intent ID", formatHash(intent.intentId));
425
+ const spin = spinner("Fetching quotes...");
426
+ const quotes = await sip.getQuotes(intent);
427
+ spin.succeed(`Found ${quotes.length} quote(s)`);
428
+ if (quotes.length === 0) {
429
+ console.error("\nNo quotes available");
430
+ process.exit(1);
431
+ }
432
+ const selectedQuote = options.solver ? quotes.find((q) => q.solverId === options.solver) : quotes[0];
433
+ if (!selectedQuote) {
434
+ console.error(`
435
+ Solver not found: ${options.solver}`);
436
+ process.exit(1);
437
+ }
438
+ info(`Using solver: ${selectedQuote.solverId}`);
439
+ keyValue("Output Amount", formatAmount(selectedQuote.outputAmount));
440
+ const executeSpin = spinner("Executing swap...");
441
+ const result = await sip.execute(intent, selectedQuote);
442
+ executeSpin.succeed("Swap executed");
443
+ success("Swap completed successfully");
444
+ if (result.txHash) {
445
+ keyValue("Transaction Hash", formatHash(result.txHash));
446
+ }
447
+ if (result.outputAmount) {
448
+ keyValue("Output Amount", formatAmount(result.outputAmount));
449
+ }
450
+ keyValue("Status", result.status);
451
+ } catch (err) {
452
+ console.error("Failed to execute swap:", err);
453
+ process.exit(1);
454
+ }
455
+ });
456
+ }
457
+
458
+ // src/commands/scan.ts
459
+ var import_commander8 = require("commander");
460
+ var import_sdk7 = require("@sip-protocol/sdk");
461
+ 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) => {
463
+ try {
464
+ heading("Scan for Stealth Payments");
465
+ const chain = options.chain;
466
+ const useEd25519 = (0, import_sdk7.isEd25519Chain)(chain);
467
+ info(`Scanning ${chain} for stealth payments...`);
468
+ info(`Using ${useEd25519 ? "ed25519" : "secp256k1"} curve`);
469
+ if (!options.addresses || options.addresses.length === 0) {
470
+ warning("No addresses provided. Specify addresses with -a flag.");
471
+ info("Example: sip scan -c ethereum -s 0x... -v 0x... -a 0xabc... 0xdef...");
472
+ return;
473
+ }
474
+ const results = [];
475
+ for (const address of options.addresses) {
476
+ try {
477
+ let result;
478
+ if (useEd25519) {
479
+ result = (0, import_sdk7.checkEd25519StealthAddress)(
480
+ address,
481
+ options.spendingKey,
482
+ options.viewingKey
483
+ );
484
+ } else {
485
+ result = (0, import_sdk7.checkStealthAddress)(
486
+ address,
487
+ options.spendingKey,
488
+ options.viewingKey
489
+ );
490
+ }
491
+ results.push({
492
+ address,
493
+ isMine: result.isMine,
494
+ privateKey: result.isMine ? result.stealthPrivateKey : void 0
495
+ });
496
+ } catch (err) {
497
+ results.push({
498
+ address,
499
+ isMine: false
500
+ });
501
+ }
502
+ }
503
+ console.log();
504
+ const foundCount = results.filter((r) => r.isMine).length;
505
+ success(`Scanned ${results.length} address(es), found ${foundCount} stealth payment(s)`);
506
+ if (foundCount > 0) {
507
+ console.log();
508
+ const headers = ["Address", "Match", "Private Key"];
509
+ const rows = results.filter((r) => r.isMine).map((r) => [
510
+ r.address.slice(0, 10) + "...",
511
+ "Yes",
512
+ r.privateKey ? r.privateKey.slice(0, 10) + "..." : "N/A"
513
+ ]);
514
+ table(headers, rows);
515
+ console.log();
516
+ warning("Store the private keys securely to access these funds");
517
+ } else {
518
+ info("No stealth payments found");
519
+ }
520
+ } catch (err) {
521
+ console.error("Failed to scan:", err);
522
+ process.exit(1);
523
+ }
524
+ });
525
+ }
526
+
527
+ // src/index.ts
528
+ var program = new import_commander9.Command();
529
+ program.name("sip").description("Shielded Intents Protocol (SIP) - Privacy layer for cross-chain transactions").version("0.1.0");
530
+ program.addCommand(createInitCommand());
531
+ program.addCommand(createKeygenCommand());
532
+ program.addCommand(createCommitCommand());
533
+ program.addCommand(createProveCommand());
534
+ program.addCommand(createVerifyCommand());
535
+ program.addCommand(createQuoteCommand());
536
+ program.addCommand(createSwapCommand());
537
+ program.addCommand(createScanCommand());
538
+ program.parse();
package/dist/index.mjs ADDED
@@ -0,0 +1,520 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command as Command9 } from "commander";
5
+
6
+ // src/commands/init.ts
7
+ import { Command } from "commander";
8
+ import { PrivacyLevel } from "@sip-protocol/types";
9
+
10
+ // src/utils/config.ts
11
+ import Conf from "conf";
12
+ var schema = {
13
+ network: {
14
+ type: "string",
15
+ default: "testnet"
16
+ },
17
+ defaultPrivacy: {
18
+ type: "string",
19
+ default: "transparent"
20
+ }
21
+ };
22
+ var store = new Conf({
23
+ projectName: "sip-protocol",
24
+ schema
25
+ });
26
+ function getConfig() {
27
+ return {
28
+ network: store.get("network"),
29
+ defaultPrivacy: store.get("defaultPrivacy"),
30
+ defaultChain: store.get("defaultChain"),
31
+ rpcEndpoints: store.get("rpcEndpoints")
32
+ };
33
+ }
34
+ function setConfig(key, value) {
35
+ store.set(key, value);
36
+ }
37
+ function resetConfig() {
38
+ store.clear();
39
+ }
40
+ function getConfigPath() {
41
+ return store.path;
42
+ }
43
+
44
+ // src/utils/output.ts
45
+ import chalk from "chalk";
46
+ import ora from "ora";
47
+ function success(message) {
48
+ console.log(chalk.green("\u2713"), message);
49
+ }
50
+ function error(message) {
51
+ console.error(chalk.red("\u2717"), message);
52
+ }
53
+ function warning(message) {
54
+ console.warn(chalk.yellow("\u26A0"), message);
55
+ }
56
+ function info(message) {
57
+ console.log(chalk.blue("\u2139"), message);
58
+ }
59
+ function heading(message) {
60
+ console.log(chalk.bold.cyan(`
61
+ ${message}
62
+ `));
63
+ }
64
+ function keyValue(key, value) {
65
+ console.log(chalk.gray(` ${key}:`), chalk.white(String(value)));
66
+ }
67
+ function spinner(text) {
68
+ return ora(text).start();
69
+ }
70
+ function table(headers, rows) {
71
+ const colWidths = headers.map(
72
+ (h, i) => Math.max(h.length, ...rows.map((r) => String(r[i] || "").length))
73
+ );
74
+ console.log(
75
+ headers.map((h, i) => chalk.bold(h.padEnd(colWidths[i]))).join(" ")
76
+ );
77
+ console.log(colWidths.map((w) => "\u2500".repeat(w)).join(" "));
78
+ rows.forEach((row) => {
79
+ console.log(
80
+ row.map((cell, i) => String(cell).padEnd(colWidths[i])).join(" ")
81
+ );
82
+ });
83
+ }
84
+ function formatAmount(amount, decimals = 18) {
85
+ const divisor = 10n ** BigInt(decimals);
86
+ const integer = amount / divisor;
87
+ const fraction = amount % divisor;
88
+ const fractionStr = fraction.toString().padStart(decimals, "0").slice(0, 6);
89
+ return `${integer}.${fractionStr}`;
90
+ }
91
+ function formatHash(hash, length = 8) {
92
+ if (hash.length <= length * 2) return hash;
93
+ return `${hash.slice(0, length)}...${hash.slice(-length)}`;
94
+ }
95
+
96
+ // src/commands/init.ts
97
+ function createInitCommand() {
98
+ return new Command("init").description("Initialize SIP configuration").option("-n, --network <network>", "Network (mainnet|testnet)", "testnet").option("-p, --privacy <level>", "Default privacy level", "transparent").option("--reset", "Reset configuration to defaults").action(async (options) => {
99
+ try {
100
+ heading("Initialize SIP Protocol");
101
+ if (options.reset) {
102
+ resetConfig();
103
+ success("Configuration reset to defaults");
104
+ }
105
+ const privacy = options.privacy;
106
+ if (!Object.values(PrivacyLevel).includes(privacy)) {
107
+ throw new Error(`Invalid privacy level: ${privacy}`);
108
+ }
109
+ setConfig("network", options.network);
110
+ setConfig("defaultPrivacy", privacy);
111
+ success("SIP initialized successfully");
112
+ info(`Network: ${options.network}`);
113
+ info(`Default Privacy: ${privacy}`);
114
+ info(`Config file: ${getConfigPath()}`);
115
+ } catch (err) {
116
+ console.error("Failed to initialize:", err);
117
+ process.exit(1);
118
+ }
119
+ });
120
+ }
121
+
122
+ // src/commands/keygen.ts
123
+ import { Command as Command2 } from "commander";
124
+ import {
125
+ generateStealthMetaAddress,
126
+ generateEd25519StealthMetaAddress,
127
+ isEd25519Chain,
128
+ encodeStealthMetaAddress
129
+ } from "@sip-protocol/sdk";
130
+ function createKeygenCommand() {
131
+ return new Command2("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) => {
132
+ try {
133
+ heading("Generate Stealth Meta-Address");
134
+ const chain = options.chain;
135
+ const useEd25519 = isEd25519Chain(chain);
136
+ let metaAddress;
137
+ if (useEd25519) {
138
+ if (options.spendingKey || options.viewingKey) {
139
+ warning("Ed25519 chains do not support custom keys in CLI yet");
140
+ }
141
+ metaAddress = generateEd25519StealthMetaAddress(chain);
142
+ } else {
143
+ metaAddress = generateStealthMetaAddress(chain);
144
+ }
145
+ success("Stealth meta-address generated");
146
+ keyValue("Chain", chain);
147
+ const spendingPubKey = metaAddress.metaAddress.spendingKey;
148
+ const viewingPubKey = metaAddress.metaAddress.viewingKey;
149
+ const spendingPrivKey = metaAddress.spendingPrivateKey;
150
+ const viewingPrivKey = metaAddress.viewingPrivateKey;
151
+ keyValue("Spending Public Key", spendingPubKey);
152
+ keyValue("Viewing Public Key", viewingPubKey);
153
+ const encoded = encodeStealthMetaAddress(metaAddress.metaAddress);
154
+ keyValue("Encoded Address", encoded);
155
+ console.log();
156
+ warning("PRIVATE KEYS - Keep these secure!");
157
+ keyValue("Spending Private Key", spendingPrivKey);
158
+ keyValue("Viewing Private Key", viewingPrivKey);
159
+ } catch (err) {
160
+ console.error("Failed to generate keys:", err);
161
+ process.exit(1);
162
+ }
163
+ });
164
+ }
165
+
166
+ // src/commands/commit.ts
167
+ import { Command as Command3 } from "commander";
168
+ import { commit, verifyOpening } from "@sip-protocol/sdk";
169
+ function createCommitCommand() {
170
+ return new Command3("commit").description("Create Pedersen commitment").argument("<amount>", "Amount to commit").option("-b, --blinding <factor>", "Blinding factor (hex, optional)").option("--verify", "Verify the commitment after creation").action(async (amountStr, options) => {
171
+ try {
172
+ heading("Create Pedersen Commitment");
173
+ const amount = BigInt(amountStr);
174
+ info(`Committing amount: ${amount}`);
175
+ const commitment = options.blinding ? commit(amount, options.blinding) : commit(amount);
176
+ success("Commitment created");
177
+ keyValue("Commitment", commitment.commitment);
178
+ keyValue("Blinding Factor", commitment.blinding);
179
+ keyValue("Amount", amount.toString());
180
+ if (options.verify) {
181
+ console.log();
182
+ info("Verifying commitment...");
183
+ const isValid = verifyOpening(commitment.commitment, amount, commitment.blinding);
184
+ if (isValid) {
185
+ success("Commitment verified successfully");
186
+ } else {
187
+ console.error("Commitment verification failed");
188
+ process.exit(1);
189
+ }
190
+ }
191
+ } catch (err) {
192
+ console.error("Failed to create commitment:", err);
193
+ process.exit(1);
194
+ }
195
+ });
196
+ }
197
+
198
+ // src/commands/prove.ts
199
+ import { Command as Command4 } from "commander";
200
+ import { MockProofProvider } from "@sip-protocol/sdk";
201
+ function createProveCommand() {
202
+ const prove = new Command4("prove").description("Generate ZK proof");
203
+ prove.command("funding").description("Generate funding proof").requiredOption("-b, --balance <amount>", "Current balance").requiredOption("-m, --minimum <amount>", "Minimum required").option("-a, --asset <id>", "Asset identifier", "ETH").option("-u, --user <address>", "User address", "0x0000000000000000000000000000000000000000").action(async (options) => {
204
+ try {
205
+ heading("Generate Funding Proof");
206
+ const blindingFactor = new Uint8Array(32);
207
+ const ownershipSignature = new Uint8Array(64);
208
+ const params = {
209
+ balance: BigInt(options.balance),
210
+ minimumRequired: BigInt(options.minimum),
211
+ blindingFactor,
212
+ assetId: options.asset,
213
+ userAddress: options.user,
214
+ ownershipSignature
215
+ };
216
+ const spin = spinner("Generating proof...");
217
+ const provider = new MockProofProvider({ silent: true });
218
+ await provider.initialize();
219
+ const result = await provider.generateFundingProof(params);
220
+ spin.succeed("Proof generated");
221
+ success("Funding proof created");
222
+ keyValue("Proof", result.proof.proof);
223
+ keyValue("Public Inputs", JSON.stringify(result.publicInputs));
224
+ keyValue("Type", result.proof.type);
225
+ } catch (err) {
226
+ console.error("Failed to generate proof:", err);
227
+ process.exit(1);
228
+ }
229
+ });
230
+ prove.command("validity").description("Generate validity proof").requiredOption("-i, --intent <hash>", "Intent hash").requiredOption("-s, --sender <address>", "Sender address").action(async (options) => {
231
+ try {
232
+ heading("Generate Validity Proof");
233
+ const senderBlinding = new Uint8Array(32);
234
+ const senderSecret = new Uint8Array(32);
235
+ const authorizationSignature = new Uint8Array(64);
236
+ const nonce = new Uint8Array(32);
237
+ const now = Math.floor(Date.now() / 1e3);
238
+ const params = {
239
+ intentHash: options.intent,
240
+ senderAddress: options.sender,
241
+ senderBlinding,
242
+ senderSecret,
243
+ authorizationSignature,
244
+ nonce,
245
+ timestamp: now,
246
+ expiry: now + 300
247
+ // 5 minutes from now
248
+ };
249
+ const spin = spinner("Generating proof...");
250
+ const provider = new MockProofProvider({ silent: true });
251
+ await provider.initialize();
252
+ const result = await provider.generateValidityProof(params);
253
+ spin.succeed("Proof generated");
254
+ success("Validity proof created");
255
+ keyValue("Proof", result.proof.proof);
256
+ keyValue("Public Inputs", JSON.stringify(result.publicInputs));
257
+ keyValue("Type", result.proof.type);
258
+ } catch (err) {
259
+ console.error("Failed to generate proof:", err);
260
+ process.exit(1);
261
+ }
262
+ });
263
+ return prove;
264
+ }
265
+
266
+ // src/commands/verify.ts
267
+ import { Command as Command5 } from "commander";
268
+ import { MockProofProvider as MockProofProvider2 } from "@sip-protocol/sdk";
269
+ function createVerifyCommand() {
270
+ return new Command5("verify").description("Verify ZK proof").argument("<proof>", "Proof to verify (hex string)").option("-t, --type <type>", "Proof type (funding|validity|fulfillment)", "funding").option("-p, --public-inputs <json>", "Public inputs (JSON array)").action(async (proofHex, options) => {
271
+ try {
272
+ heading("Verify ZK Proof");
273
+ info(`Proof type: ${options.type}`);
274
+ info(`Proof: ${proofHex.slice(0, 20)}...`);
275
+ const publicInputs = options.publicInputs ? JSON.parse(options.publicInputs) : [];
276
+ const proofHexStr = proofHex.startsWith("0x") ? proofHex : `0x${proofHex}`;
277
+ const zkProof = {
278
+ type: options.type,
279
+ proof: proofHexStr,
280
+ publicInputs
281
+ };
282
+ const spin = spinner("Verifying proof...");
283
+ const provider = new MockProofProvider2({ silent: true });
284
+ await provider.initialize();
285
+ const isValid = await provider.verifyProof(zkProof);
286
+ spin.stop();
287
+ if (isValid) {
288
+ success(`Proof is valid (type: ${options.type})`);
289
+ } else {
290
+ error("Proof is invalid");
291
+ process.exit(1);
292
+ }
293
+ } catch (err) {
294
+ console.error("Failed to verify proof:", err);
295
+ process.exit(1);
296
+ }
297
+ });
298
+ }
299
+
300
+ // src/commands/quote.ts
301
+ import { Command as Command6 } from "commander";
302
+ import { createSIP, NATIVE_TOKENS } from "@sip-protocol/sdk";
303
+ function createQuoteCommand() {
304
+ return new Command6("quote").description("Get swap quote").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)").action(async (fromChain, toChain, amountStr, options) => {
305
+ try {
306
+ heading("Get Swap Quote");
307
+ const config = getConfig();
308
+ const amount = BigInt(amountStr);
309
+ const privacy = options.privacy || config.defaultPrivacy;
310
+ const sip = createSIP(config.network);
311
+ const spin = spinner("Fetching quotes...");
312
+ const inputAsset = NATIVE_TOKENS[fromChain] || {
313
+ chain: fromChain,
314
+ symbol: options.token || "native",
315
+ address: null,
316
+ decimals: 18
317
+ };
318
+ const outputAsset = NATIVE_TOKENS[toChain] || {
319
+ chain: toChain,
320
+ symbol: options.token || "native",
321
+ address: null,
322
+ decimals: 18
323
+ };
324
+ const intent = await sip.createIntent({
325
+ input: {
326
+ asset: inputAsset,
327
+ amount
328
+ },
329
+ output: {
330
+ asset: outputAsset,
331
+ minAmount: 0n,
332
+ // Accept any amount for quote discovery
333
+ maxSlippage: 0.05
334
+ // 5% slippage tolerance
335
+ },
336
+ privacy
337
+ });
338
+ const quotes = await sip.getQuotes(intent);
339
+ spin.succeed(`Found ${quotes.length} quote(s)`);
340
+ if (quotes.length === 0) {
341
+ console.log("\nNo quotes available");
342
+ return;
343
+ }
344
+ console.log();
345
+ const headers = ["Solver", "Output Amount", "Fee", "Time (s)"];
346
+ const rows = quotes.map((q) => [
347
+ q.solverId,
348
+ formatAmount(q.outputAmount),
349
+ formatAmount(q.fee),
350
+ q.estimatedTime.toString()
351
+ ]);
352
+ table(headers, rows);
353
+ const best = quotes[0];
354
+ console.log();
355
+ success("Best quote:");
356
+ keyValue("Solver", best.solverId);
357
+ keyValue("Output Amount", formatAmount(best.outputAmount));
358
+ keyValue("Estimated Time", `${best.estimatedTime}s`);
359
+ } catch (err) {
360
+ console.error("Failed to get quote:", err);
361
+ process.exit(1);
362
+ }
363
+ });
364
+ }
365
+
366
+ // src/commands/swap.ts
367
+ import { Command as Command7 } from "commander";
368
+ import { createSIP as createSIP2, NATIVE_TOKENS as NATIVE_TOKENS2 } from "@sip-protocol/sdk";
369
+ function createSwapCommand() {
370
+ return new Command7("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) => {
371
+ try {
372
+ heading("Execute Swap");
373
+ const config = getConfig();
374
+ const amount = BigInt(amountStr);
375
+ const privacy = options.privacy || config.defaultPrivacy;
376
+ const sip = createSIP2(config.network);
377
+ const inputAsset = NATIVE_TOKENS2[fromChain] || {
378
+ chain: fromChain,
379
+ symbol: options.token || "native",
380
+ address: null,
381
+ decimals: 18
382
+ };
383
+ const outputAsset = NATIVE_TOKENS2[toChain] || {
384
+ chain: toChain,
385
+ symbol: options.token || "native",
386
+ address: null,
387
+ decimals: 18
388
+ };
389
+ info("Creating shielded intent...");
390
+ const intent = await sip.createIntent({
391
+ input: {
392
+ asset: inputAsset,
393
+ amount
394
+ },
395
+ output: {
396
+ asset: outputAsset,
397
+ minAmount: 0n,
398
+ // Accept any amount
399
+ maxSlippage: 0.05
400
+ // 5% slippage tolerance
401
+ },
402
+ privacy,
403
+ recipientMetaAddress: options.recipient
404
+ });
405
+ success("Intent created");
406
+ keyValue("Intent ID", formatHash(intent.intentId));
407
+ const spin = spinner("Fetching quotes...");
408
+ const quotes = await sip.getQuotes(intent);
409
+ spin.succeed(`Found ${quotes.length} quote(s)`);
410
+ if (quotes.length === 0) {
411
+ console.error("\nNo quotes available");
412
+ process.exit(1);
413
+ }
414
+ const selectedQuote = options.solver ? quotes.find((q) => q.solverId === options.solver) : quotes[0];
415
+ if (!selectedQuote) {
416
+ console.error(`
417
+ Solver not found: ${options.solver}`);
418
+ process.exit(1);
419
+ }
420
+ info(`Using solver: ${selectedQuote.solverId}`);
421
+ keyValue("Output Amount", formatAmount(selectedQuote.outputAmount));
422
+ const executeSpin = spinner("Executing swap...");
423
+ const result = await sip.execute(intent, selectedQuote);
424
+ executeSpin.succeed("Swap executed");
425
+ success("Swap completed successfully");
426
+ if (result.txHash) {
427
+ keyValue("Transaction Hash", formatHash(result.txHash));
428
+ }
429
+ if (result.outputAmount) {
430
+ keyValue("Output Amount", formatAmount(result.outputAmount));
431
+ }
432
+ keyValue("Status", result.status);
433
+ } catch (err) {
434
+ console.error("Failed to execute swap:", err);
435
+ process.exit(1);
436
+ }
437
+ });
438
+ }
439
+
440
+ // src/commands/scan.ts
441
+ import { Command as Command8 } from "commander";
442
+ import { checkStealthAddress, checkEd25519StealthAddress, isEd25519Chain as isEd25519Chain2 } from "@sip-protocol/sdk";
443
+ function createScanCommand() {
444
+ return new Command8("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) => {
445
+ try {
446
+ heading("Scan for Stealth Payments");
447
+ const chain = options.chain;
448
+ const useEd25519 = isEd25519Chain2(chain);
449
+ info(`Scanning ${chain} for stealth payments...`);
450
+ info(`Using ${useEd25519 ? "ed25519" : "secp256k1"} curve`);
451
+ if (!options.addresses || options.addresses.length === 0) {
452
+ warning("No addresses provided. Specify addresses with -a flag.");
453
+ info("Example: sip scan -c ethereum -s 0x... -v 0x... -a 0xabc... 0xdef...");
454
+ return;
455
+ }
456
+ const results = [];
457
+ for (const address of options.addresses) {
458
+ try {
459
+ let result;
460
+ if (useEd25519) {
461
+ result = checkEd25519StealthAddress(
462
+ address,
463
+ options.spendingKey,
464
+ options.viewingKey
465
+ );
466
+ } else {
467
+ result = checkStealthAddress(
468
+ address,
469
+ options.spendingKey,
470
+ options.viewingKey
471
+ );
472
+ }
473
+ results.push({
474
+ address,
475
+ isMine: result.isMine,
476
+ privateKey: result.isMine ? result.stealthPrivateKey : void 0
477
+ });
478
+ } catch (err) {
479
+ results.push({
480
+ address,
481
+ isMine: false
482
+ });
483
+ }
484
+ }
485
+ console.log();
486
+ const foundCount = results.filter((r) => r.isMine).length;
487
+ success(`Scanned ${results.length} address(es), found ${foundCount} stealth payment(s)`);
488
+ if (foundCount > 0) {
489
+ console.log();
490
+ const headers = ["Address", "Match", "Private Key"];
491
+ const rows = results.filter((r) => r.isMine).map((r) => [
492
+ r.address.slice(0, 10) + "...",
493
+ "Yes",
494
+ r.privateKey ? r.privateKey.slice(0, 10) + "..." : "N/A"
495
+ ]);
496
+ table(headers, rows);
497
+ console.log();
498
+ warning("Store the private keys securely to access these funds");
499
+ } else {
500
+ info("No stealth payments found");
501
+ }
502
+ } catch (err) {
503
+ console.error("Failed to scan:", err);
504
+ process.exit(1);
505
+ }
506
+ });
507
+ }
508
+
509
+ // src/index.ts
510
+ var program = new Command9();
511
+ program.name("sip").description("Shielded Intents Protocol (SIP) - Privacy layer for cross-chain transactions").version("0.1.0");
512
+ program.addCommand(createInitCommand());
513
+ program.addCommand(createKeygenCommand());
514
+ program.addCommand(createCommitCommand());
515
+ program.addCommand(createProveCommand());
516
+ program.addCommand(createVerifyCommand());
517
+ program.addCommand(createQuoteCommand());
518
+ program.addCommand(createSwapCommand());
519
+ program.addCommand(createScanCommand());
520
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@sip-protocol/cli",
3
+ "version": "0.1.0",
4
+ "description": "Command-line tool for Shielded Intents Protocol (SIP) operations",
5
+ "author": "SIP Protocol <hello@sip-protocol.org>",
6
+ "homepage": "https://sip-protocol.org",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/sip-protocol/sip-protocol.git",
10
+ "directory": "packages/cli"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/sip-protocol/sip-protocol/issues"
14
+ },
15
+ "bin": {
16
+ "sip": "./bin/sip.js"
17
+ },
18
+ "main": "./dist/index.js",
19
+ "module": "./dist/index.mjs",
20
+ "types": "./dist/index.d.ts",
21
+ "files": [
22
+ "bin",
23
+ "dist"
24
+ ],
25
+ "dependencies": {
26
+ "@sip-protocol/sdk": "^0.6.0",
27
+ "@sip-protocol/types": "^0.2.0",
28
+ "commander": "^12.0.0",
29
+ "chalk": "^4.1.2",
30
+ "ora": "^5.4.1",
31
+ "conf": "^10.2.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^20.10.0",
35
+ "tsup": "^8.0.0",
36
+ "typescript": "^5.3.0",
37
+ "vitest": "^1.1.0"
38
+ },
39
+ "keywords": [
40
+ "sip",
41
+ "cli",
42
+ "privacy",
43
+ "intents",
44
+ "cross-chain",
45
+ "stealth-addresses",
46
+ "zcash"
47
+ ],
48
+ "license": "MIT",
49
+ "scripts": {
50
+ "build": "tsup src/index.ts --format cjs,esm --dts && chmod +x bin/sip.js",
51
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
52
+ "lint": "eslint --ext .ts src/",
53
+ "typecheck": "tsc --noEmit",
54
+ "clean": "rm -rf dist",
55
+ "test": "vitest --passWithNoTests"
56
+ }
57
+ }