@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.
- package/README.md +119 -0
- package/dist/cli/commands.d.ts +54 -0
- package/dist/cli/commands.js +1229 -0
- package/dist/cli/config.d.ts +50 -0
- package/dist/cli/config.js +247 -0
- package/dist/cli/devnet.d.ts +81 -0
- package/dist/cli/devnet.js +106 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +155 -0
- package/dist/cli/output.d.ts +102 -0
- package/dist/cli/output.js +251 -0
- package/dist/client.d.ts +121 -0
- package/dist/client.js +691 -0
- package/dist/constants.d.ts +30 -0
- package/dist/constants.js +61 -0
- package/dist/encryption.d.ts +24 -0
- package/dist/encryption.js +90 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +45 -0
- package/dist/idl/shuffle_protocol.json +6333 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +42 -0
- package/dist/pda.d.ts +7 -0
- package/dist/pda.js +59 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.js +7 -0
- package/package.json +58 -0
|
@@ -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,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
|
+
});
|