@shuffle-protocol/sdk 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.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * CLI Configuration Management
3
+ *
4
+ * Handles loading Solana wallet from CLI config, network selection,
5
+ * and encryption keypair management.
6
+ */
7
+ import { Connection } from "@solana/web3.js";
8
+ import * as anchor from "@coral-xyz/anchor";
9
+ import { ShuffleClient } from "../client";
10
+ export interface CLIConfig {
11
+ network: "devnet" | "localnet";
12
+ connection: Connection;
13
+ wallet: anchor.Wallet;
14
+ keypairPath: string;
15
+ mockMode: boolean;
16
+ shuffleClient: ShuffleClient | null;
17
+ encryptionPrivateKey: Uint8Array;
18
+ userProfile?: string;
19
+ }
20
+ /**
21
+ * Load saved config from ~/.shuffle/config.json
22
+ */
23
+ export declare function loadSavedConfig(): {
24
+ network?: "devnet" | "localnet";
25
+ };
26
+ /**
27
+ * Save config to ~/.shuffle/config.json
28
+ */
29
+ export declare function saveConfig(key: string, value: string): void;
30
+ /**
31
+ * Get a saved config value
32
+ */
33
+ export declare function getSavedConfig(key: string): string | undefined;
34
+ /**
35
+ * Initialize CLI configuration
36
+ */
37
+ export declare function loadConfig(opts: {
38
+ network?: string;
39
+ keypair?: string;
40
+ mock?: boolean;
41
+ user?: string;
42
+ }): Promise<CLIConfig>;
43
+ /**
44
+ * Get current config (must call loadConfig first)
45
+ */
46
+ export declare function getConfig(): CLIConfig;
47
+ /**
48
+ * Get CLI version from package.json
49
+ */
50
+ export declare function getVersion(): string;
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ /**
3
+ * CLI Configuration Management
4
+ *
5
+ * Handles loading Solana wallet from CLI config, network selection,
6
+ * and encryption keypair management.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.loadSavedConfig = loadSavedConfig;
43
+ exports.saveConfig = saveConfig;
44
+ exports.getSavedConfig = getSavedConfig;
45
+ exports.loadConfig = loadConfig;
46
+ exports.getConfig = getConfig;
47
+ exports.getVersion = getVersion;
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const os = __importStar(require("os"));
51
+ const web3_js_1 = require("@solana/web3.js");
52
+ const anchor = __importStar(require("@coral-xyz/anchor"));
53
+ const client_1 = require("../client");
54
+ const devnet_1 = require("./devnet");
55
+ const encryption_1 = require("../encryption");
56
+ let config = null;
57
+ /**
58
+ * Get the base shuffle directory
59
+ */
60
+ function getShuffleDir() {
61
+ return path.join(os.homedir(), ".shuffle");
62
+ }
63
+ /**
64
+ * Get the directory for a user profile (null = default user)
65
+ */
66
+ function getUserDir(profile) {
67
+ const shuffleDir = getShuffleDir();
68
+ if (!profile || profile === "default") {
69
+ return shuffleDir;
70
+ }
71
+ return path.join(shuffleDir, "users", profile);
72
+ }
73
+ /**
74
+ * Load Solana keypair from profile or custom path
75
+ */
76
+ function loadKeypair(customPath, profile) {
77
+ // Try custom path first
78
+ if (customPath && fs.existsSync(customPath)) {
79
+ const raw = JSON.parse(fs.readFileSync(customPath, "utf-8"));
80
+ return { keypair: web3_js_1.Keypair.fromSecretKey(Uint8Array.from(raw)), path: customPath };
81
+ }
82
+ // For named profiles, use profile-specific keypair
83
+ if (profile && profile !== "default") {
84
+ const userDir = getUserDir(profile);
85
+ const profileKeypairPath = path.join(userDir, "keypair.json");
86
+ if (fs.existsSync(profileKeypairPath)) {
87
+ const raw = JSON.parse(fs.readFileSync(profileKeypairPath, "utf-8"));
88
+ return { keypair: web3_js_1.Keypair.fromSecretKey(Uint8Array.from(raw)), path: profileKeypairPath };
89
+ }
90
+ // Create new keypair for this profile
91
+ if (!fs.existsSync(userDir)) {
92
+ fs.mkdirSync(userDir, { recursive: true });
93
+ }
94
+ const newKeypair = web3_js_1.Keypair.generate();
95
+ fs.writeFileSync(profileKeypairPath, JSON.stringify(Array.from(newKeypair.secretKey)));
96
+ console.log(`Created new keypair for profile '${profile}': ${newKeypair.publicKey.toBase58()}`);
97
+ return { keypair: newKeypair, path: profileKeypairPath };
98
+ }
99
+ // Try Solana CLI default path
100
+ const defaultPath = path.join(os.homedir(), ".config", "solana", "id.json");
101
+ if (fs.existsSync(defaultPath)) {
102
+ const raw = JSON.parse(fs.readFileSync(defaultPath, "utf-8"));
103
+ return { keypair: web3_js_1.Keypair.fromSecretKey(Uint8Array.from(raw)), path: defaultPath };
104
+ }
105
+ throw new Error("No Solana keypair found!\n" +
106
+ "Run: solana-keygen new\n" +
107
+ "Or specify: shuffle --keypair /path/to/keypair.json <command>");
108
+ }
109
+ /**
110
+ * Load or create encryption keypair (profile-specific if profile is set)
111
+ */
112
+ function loadOrCreateEncryptionKey(profile) {
113
+ const userDir = getUserDir(profile);
114
+ const encryptionPath = path.join(userDir, "encryption.json");
115
+ if (fs.existsSync(encryptionPath)) {
116
+ const raw = JSON.parse(fs.readFileSync(encryptionPath, "utf-8"));
117
+ return Uint8Array.from(raw.privateKey);
118
+ }
119
+ // Create new keypair
120
+ const keypair = (0, encryption_1.generateEncryptionKeypair)();
121
+ if (!fs.existsSync(userDir)) {
122
+ fs.mkdirSync(userDir, { recursive: true });
123
+ }
124
+ fs.writeFileSync(encryptionPath, JSON.stringify({
125
+ privateKey: Array.from(keypair.privateKey),
126
+ publicKey: Array.from(keypair.publicKey),
127
+ }));
128
+ return keypair.privateKey;
129
+ }
130
+ /**
131
+ * Get RPC URL for network
132
+ */
133
+ function getRpcUrl(network) {
134
+ if (network === "localnet") {
135
+ return "http://127.0.0.1:8899";
136
+ }
137
+ return (0, web3_js_1.clusterApiUrl)("devnet");
138
+ }
139
+ /**
140
+ * Path to persistent config file
141
+ */
142
+ function getConfigPath() {
143
+ return path.join(os.homedir(), ".shuffle", "config.json");
144
+ }
145
+ /**
146
+ * Load saved config from ~/.shuffle/config.json
147
+ */
148
+ function loadSavedConfig() {
149
+ try {
150
+ const configPath = getConfigPath();
151
+ if (fs.existsSync(configPath)) {
152
+ return JSON.parse(fs.readFileSync(configPath, "utf-8"));
153
+ }
154
+ }
155
+ catch {
156
+ // Ignore errors, return empty config
157
+ }
158
+ return {};
159
+ }
160
+ /**
161
+ * Save config to ~/.shuffle/config.json
162
+ */
163
+ function saveConfig(key, value) {
164
+ const shuffleDir = path.join(os.homedir(), ".shuffle");
165
+ const configPath = getConfigPath();
166
+ if (!fs.existsSync(shuffleDir)) {
167
+ fs.mkdirSync(shuffleDir, { recursive: true });
168
+ }
169
+ const existing = loadSavedConfig();
170
+ const updated = { ...existing, [key]: value };
171
+ fs.writeFileSync(configPath, JSON.stringify(updated, null, 2));
172
+ }
173
+ /**
174
+ * Get a saved config value
175
+ */
176
+ function getSavedConfig(key) {
177
+ const saved = loadSavedConfig();
178
+ return saved[key];
179
+ }
180
+ /**
181
+ * Initialize CLI configuration
182
+ */
183
+ async function loadConfig(opts) {
184
+ // Use saved config as defaults if --network/--mock not provided
185
+ const savedConfig = loadSavedConfig();
186
+ const network = opts.network || savedConfig.network || "devnet";
187
+ const savedMock = savedConfig.mock === "true";
188
+ const mockMode = opts.mock !== undefined ? opts.mock : savedMock || devnet_1.MOCK_MODE;
189
+ const userProfile = opts.user;
190
+ const { keypair, path: keypairPath } = loadKeypair(opts.keypair, userProfile);
191
+ const wallet = new anchor.Wallet(keypair);
192
+ const connection = new web3_js_1.Connection(getRpcUrl(network), "confirmed");
193
+ const encryptionPrivateKey = loadOrCreateEncryptionKey(userProfile);
194
+ let shuffleClient = null;
195
+ // Select program ID based on network
196
+ const programId = network === "localnet"
197
+ ? devnet_1.LOCALNET_CONFIG.programId
198
+ : devnet_1.DEVNET_CONFIG.programId;
199
+ if (!mockMode) {
200
+ try {
201
+ shuffleClient = await client_1.ShuffleClient.create({
202
+ connection,
203
+ wallet,
204
+ programId,
205
+ clusterOffset: 0,
206
+ });
207
+ shuffleClient.initEncryption(encryptionPrivateKey);
208
+ }
209
+ catch (e) {
210
+ // Will use mock mode if client creation fails
211
+ console.warn(`Failed to connect to Shuffle protocol: ${e.message?.slice(0, 50)}`);
212
+ }
213
+ }
214
+ config = {
215
+ network,
216
+ connection,
217
+ wallet,
218
+ keypairPath,
219
+ mockMode: mockMode || !shuffleClient,
220
+ shuffleClient,
221
+ encryptionPrivateKey,
222
+ userProfile,
223
+ };
224
+ return config;
225
+ }
226
+ /**
227
+ * Get current config (must call loadConfig first)
228
+ */
229
+ function getConfig() {
230
+ if (!config) {
231
+ throw new Error("Config not loaded. This is a bug.");
232
+ }
233
+ return config;
234
+ }
235
+ /**
236
+ * Get CLI version from package.json
237
+ */
238
+ function getVersion() {
239
+ try {
240
+ const pkgPath = path.join(__dirname, "..", "..", "package.json");
241
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
242
+ return pkg.version || "0.1.0";
243
+ }
244
+ catch {
245
+ return "0.1.0";
246
+ }
247
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Devnet Configuration and Mock Mode
3
+ *
4
+ * Contains easily-updatable constants for devnet deployment.
5
+ * When MOCK_MODE is true, all operations simulate responses.
6
+ */
7
+ import { PublicKey } from "@solana/web3.js";
8
+ /**
9
+ * Set to false for live blockchain interaction
10
+ */
11
+ export declare const MOCK_MODE = false;
12
+ /**
13
+ * Localnet program configuration (from arcium test)
14
+ * UPDATE THIS when network restarts!
15
+ */
16
+ export declare const LOCALNET_CONFIG: {
17
+ programId: PublicKey;
18
+ rpcUrl: string;
19
+ };
20
+ /**
21
+ * Devnet program and token configuration
22
+ */
23
+ export declare const DEVNET_CONFIG: {
24
+ programId: PublicKey;
25
+ rpcUrl: string;
26
+ clusterOffset: number;
27
+ mints: {
28
+ USDC: PublicKey;
29
+ TSLA: PublicKey;
30
+ SPY: PublicKey;
31
+ AAPL: PublicKey;
32
+ };
33
+ faucetAuthority: PublicKey | null;
34
+ };
35
+ /**
36
+ * Simulated delay for mock operations (milliseconds)
37
+ */
38
+ export declare const MOCK_DELAY: {
39
+ fast: number;
40
+ medium: number;
41
+ slow: number;
42
+ };
43
+ /**
44
+ * Mock state for simulating operations
45
+ */
46
+ export interface MockState {
47
+ accountExists: boolean;
48
+ balances: {
49
+ usdc: bigint;
50
+ tsla: bigint;
51
+ spy: bigint;
52
+ aapl: bigint;
53
+ };
54
+ pendingOrder: {
55
+ batchId: number;
56
+ pairId: number;
57
+ direction: number;
58
+ amount: bigint;
59
+ } | null;
60
+ batchId: number;
61
+ }
62
+ /**
63
+ * Get current mock state
64
+ */
65
+ export declare function getMockState(): MockState;
66
+ /**
67
+ * Update mock state
68
+ */
69
+ export declare function updateMockState(updates: Partial<MockState>): void;
70
+ /**
71
+ * Reset mock state
72
+ */
73
+ export declare function resetMockState(): void;
74
+ /**
75
+ * Simulate async delay
76
+ */
77
+ export declare function mockDelay(type: keyof typeof MOCK_DELAY): Promise<void>;
78
+ /**
79
+ * Generate a fake transaction signature
80
+ */
81
+ export declare function mockSignature(): string;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /**
3
+ * Devnet Configuration and Mock Mode
4
+ *
5
+ * Contains easily-updatable constants for devnet deployment.
6
+ * When MOCK_MODE is true, all operations simulate responses.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.MOCK_DELAY = exports.DEVNET_CONFIG = exports.LOCALNET_CONFIG = exports.MOCK_MODE = void 0;
10
+ exports.getMockState = getMockState;
11
+ exports.updateMockState = updateMockState;
12
+ exports.resetMockState = resetMockState;
13
+ exports.mockDelay = mockDelay;
14
+ exports.mockSignature = mockSignature;
15
+ const web3_js_1 = require("@solana/web3.js");
16
+ // ============================================================================
17
+ // DEVNET CONSTANTS - Update these when contracts are deployed
18
+ // ============================================================================
19
+ /**
20
+ * Set to false for live blockchain interaction
21
+ */
22
+ exports.MOCK_MODE = false;
23
+ /**
24
+ * Localnet program configuration (from arcium test)
25
+ * UPDATE THIS when network restarts!
26
+ */
27
+ exports.LOCALNET_CONFIG = {
28
+ programId: new web3_js_1.PublicKey("BzaakuSahkVtEXKqZnD9tSPBoiJCMLa1nzQHUjtY1xRM"),
29
+ rpcUrl: "http://127.0.0.1:8899",
30
+ };
31
+ /**
32
+ * Devnet program and token configuration
33
+ */
34
+ exports.DEVNET_CONFIG = {
35
+ // Program ID from successful devnet deployment (2026-02-01)
36
+ programId: new web3_js_1.PublicKey("BzaakuSahkVtEXKqZnD9tSPBoiJCMLa1nzQHUjtY1xRM"),
37
+ rpcUrl: "https://devnet.helius-rpc.com/?api-key=a8e1a5ce-29c6-4356-b3f9-54c1c650ac08",
38
+ // Arcium cluster offset for v0.6.3 (required for account derivations)
39
+ clusterOffset: 456,
40
+ // Token mints - deployed 2026-02-01
41
+ mints: {
42
+ USDC: new web3_js_1.PublicKey("2rGgkS8piPnFbJxLhyyfXnTuLqPW8zPoM7YXnovjBK9s"),
43
+ TSLA: new web3_js_1.PublicKey("EmRuN3yRqizBKwVSahm6bPW4YEUZ4iGcP95SQg1MdDfZ"),
44
+ SPY: new web3_js_1.PublicKey("HgaWt2CGQLT3RTNt4HQpCFhMpeo8amadH6KcQ5gVCDvQ"),
45
+ AAPL: new web3_js_1.PublicKey("7JohqPXEVJ3Mm8TrHf7KQ7F4Nq4JnxvfTLQFn4D5nghj"),
46
+ },
47
+ // Faucet authority - update with deployed faucet program or mint authority
48
+ faucetAuthority: null,
49
+ };
50
+ // ============================================================================
51
+ // MOCK RESPONSES - Used when MOCK_MODE is true
52
+ // ============================================================================
53
+ /**
54
+ * Simulated delay for mock operations (milliseconds)
55
+ */
56
+ exports.MOCK_DELAY = {
57
+ fast: 800, // Balance queries
58
+ medium: 2000, // Deposits, withdrawals
59
+ slow: 4000, // MPC operations (orders, settlements)
60
+ };
61
+ let mockState = {
62
+ accountExists: true, // Pre-initialized for smooth demo
63
+ balances: { usdc: 0n, tsla: 0n, spy: 0n, aapl: 0n },
64
+ pendingOrder: null,
65
+ batchId: 1,
66
+ };
67
+ /**
68
+ * Get current mock state
69
+ */
70
+ function getMockState() {
71
+ return mockState;
72
+ }
73
+ /**
74
+ * Update mock state
75
+ */
76
+ function updateMockState(updates) {
77
+ mockState = { ...mockState, ...updates };
78
+ }
79
+ /**
80
+ * Reset mock state
81
+ */
82
+ function resetMockState() {
83
+ mockState = {
84
+ accountExists: false,
85
+ balances: { usdc: 0n, tsla: 0n, spy: 0n, aapl: 0n },
86
+ pendingOrder: null,
87
+ batchId: 1,
88
+ };
89
+ }
90
+ /**
91
+ * Simulate async delay
92
+ */
93
+ function mockDelay(type) {
94
+ return new Promise((resolve) => setTimeout(resolve, exports.MOCK_DELAY[type]));
95
+ }
96
+ /**
97
+ * Generate a fake transaction signature
98
+ */
99
+ function mockSignature() {
100
+ const chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
101
+ let sig = "";
102
+ for (let i = 0; i < 88; i++) {
103
+ sig += chars[Math.floor(Math.random() * chars.length)];
104
+ }
105
+ return sig;
106
+ }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Shuffle CLI - Command Line Interface for Shuffle Privacy Protocol
4
+ *
5
+ * This CLI wraps the ShuffleClient SDK to provide terminal-based
6
+ * interaction with the Shuffle protocol on Solana.
7
+ */
8
+ export {};
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Shuffle CLI - Command Line Interface for Shuffle Privacy Protocol
5
+ *
6
+ * This CLI wraps the ShuffleClient SDK to provide terminal-based
7
+ * interaction with the Shuffle protocol on Solana.
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ // Suppress punycode deprecation warning from dependencies
14
+ process.removeAllListeners('warning');
15
+ const originalEmit = process.emit;
16
+ // @ts-ignore
17
+ process.emit = function (event, warning) {
18
+ if (event === 'warning' && warning?.name === 'DeprecationWarning' &&
19
+ warning?.message?.includes('punycode')) {
20
+ return false;
21
+ }
22
+ return originalEmit.apply(process, arguments);
23
+ };
24
+ const commander_1 = require("commander");
25
+ const chalk_1 = __importDefault(require("chalk"));
26
+ const commands_1 = require("./commands");
27
+ const config_1 = require("./config");
28
+ const program = new commander_1.Command();
29
+ program
30
+ .name("shuffle")
31
+ .description(chalk_1.default.cyan("šŸƒ Shuffle Protocol CLI - Private DeFi on Solana"))
32
+ .version((0, config_1.getVersion)())
33
+ .option("-n, --network <network>", "Network to use (devnet|localnet)")
34
+ .option("-k, --keypair <path>", "Path to keypair file")
35
+ .option("-u, --user <name>", "User profile name (creates separate keys)")
36
+ .option("--mock", "Run in mock mode (no blockchain interaction)")
37
+ .hook("preAction", async (thisCommand) => {
38
+ // Skip config loading for the config command itself
39
+ if (thisCommand.args[0] === "config")
40
+ return;
41
+ // Load config before any command runs
42
+ const opts = thisCommand.opts();
43
+ await (0, config_1.loadConfig)(opts);
44
+ });
45
+ // Config command (doesn't need preAction hook)
46
+ const configCmd = program
47
+ .command("config")
48
+ .description("Manage CLI configuration");
49
+ configCmd
50
+ .command("set <key> <value>")
51
+ .description("Set a config value (e.g., 'shuffle config set network localnet' or 'shuffle config set mock true')")
52
+ .action((key, value) => {
53
+ if (key === "network") {
54
+ if (!["devnet", "localnet"].includes(value)) {
55
+ console.log(chalk_1.default.red(`āŒ Invalid network: ${value}. Use 'devnet' or 'localnet'.`));
56
+ return;
57
+ }
58
+ }
59
+ if (key === "mock") {
60
+ if (!["true", "false"].includes(value.toLowerCase())) {
61
+ console.log(chalk_1.default.red(`āŒ Invalid value: ${value}. Use 'true' or 'false'.`));
62
+ return;
63
+ }
64
+ value = value.toLowerCase();
65
+ }
66
+ (0, config_1.saveConfig)(key, value);
67
+ console.log(chalk_1.default.green(`āœ“ Set ${key} = ${value}`));
68
+ console.log(chalk_1.default.gray(` Saved to ~/.shuffle/config.json`));
69
+ });
70
+ configCmd
71
+ .command("get [key]")
72
+ .description("Get a config value or show all config")
73
+ .action((key) => {
74
+ if (key) {
75
+ const value = (0, config_1.getSavedConfig)(key);
76
+ if (value) {
77
+ console.log(`${key}: ${chalk_1.default.cyan(value)}`);
78
+ }
79
+ else {
80
+ console.log(chalk_1.default.gray(`${key}: (not set)`));
81
+ }
82
+ }
83
+ else {
84
+ // Show all config
85
+ const network = (0, config_1.getSavedConfig)("network") || "(default: devnet)";
86
+ const mock = (0, config_1.getSavedConfig)("mock") || "false";
87
+ console.log(chalk_1.default.cyan("\nšŸƒ Shuffle Config\n"));
88
+ console.log(` network: ${chalk_1.default.white(network)}`);
89
+ console.log(` mock: ${chalk_1.default.white(mock)}`);
90
+ console.log(chalk_1.default.gray(`\n Config file: ~/.shuffle/config.json\n`));
91
+ }
92
+ });
93
+ // Account Management
94
+ program
95
+ .command("init")
96
+ .description("Create a new privacy account")
97
+ .action(commands_1.initCommand);
98
+ program
99
+ .command("balance")
100
+ .description("View your encrypted balances")
101
+ .action(commands_1.balanceCommand);
102
+ // Token Operations
103
+ program
104
+ .command("deposit <asset> <amount>")
105
+ .alias("shield")
106
+ .description("Deposit (shield) tokens into your privacy account")
107
+ .action(commands_1.depositCommand);
108
+ program
109
+ .command("withdraw <asset> <amount>")
110
+ .alias("unshield")
111
+ .description("Withdraw (unshield) tokens from your privacy account")
112
+ .action(commands_1.withdrawCommand);
113
+ program
114
+ .command("transfer <address> <amount>")
115
+ .description("Send USDC privately to another user")
116
+ .action(commands_1.transferCommand);
117
+ // Trading
118
+ program
119
+ .command("order [pair] [direction] [amount]")
120
+ .description("Place an encrypted order (interactive if no args, or: shuffle order TSLA_USDC buy 100)")
121
+ .action(commands_1.orderCommand);
122
+ program
123
+ .command("execute")
124
+ .description("Trigger batch execution (requires 8+ orders)")
125
+ .action(commands_1.executeCommand);
126
+ program
127
+ .command("settle")
128
+ .description("Settle your pending order after batch execution")
129
+ .action(commands_1.settleCommand);
130
+ program
131
+ .command("status")
132
+ .description("View batch info and pending order status")
133
+ .action(commands_1.statusCommand);
134
+ // Devnet Utilities
135
+ program
136
+ .command("faucet <amount>")
137
+ .description("Mint devnet USDC to your wallet")
138
+ .action(commands_1.faucetCommand);
139
+ program
140
+ .command("airdrop [amount]")
141
+ .description("Airdrop SOL to your wallet (default: 2 SOL)")
142
+ .action(commands_1.airdropCommand);
143
+ // History
144
+ program
145
+ .command("history")
146
+ .description("View all executed batch logs")
147
+ .action(commands_1.historyCommand);
148
+ // Parse and run, then exit to avoid hanging from open connections
149
+ program.parseAsync().then(() => {
150
+ // Give a moment for any final I/O to flush
151
+ setTimeout(() => process.exit(0), 100);
152
+ }).catch((e) => {
153
+ console.error(e);
154
+ process.exit(1);
155
+ });