@veil-cash/sdk 0.4.0 → 0.5.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 +104 -467
- package/SDK.md +311 -0
- package/dist/cli/index.cjs +1438 -917
- package/dist/index.cjs +7 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/skills/veil/SKILL.md +526 -0
- package/skills/veil/reference.md +231 -0
- package/src/addresses.ts +6 -2
- package/src/balance.ts +4 -4
- package/src/cli/commands/balance.ts +126 -38
- package/src/cli/commands/deposit.ts +136 -63
- package/src/cli/commands/init.ts +95 -72
- package/src/cli/commands/keypair.ts +34 -16
- package/src/cli/commands/private-balance.ts +37 -35
- package/src/cli/commands/queue-balance.ts +48 -36
- package/src/cli/commands/register.ts +67 -53
- package/src/cli/commands/status.ts +196 -70
- package/src/cli/commands/transfer.ts +62 -53
- package/src/cli/commands/withdraw.ts +32 -30
- package/src/cli/config.ts +85 -5
- package/src/cli/errors.ts +4 -0
- package/src/cli/index.ts +23 -5
- package/src/cli/output.ts +87 -0
- package/src/cli/wallet.ts +75 -16
- package/src/index.ts +6 -1
- package/src/prover.ts +3 -0
|
@@ -6,26 +6,24 @@ import { Command } from 'commander';
|
|
|
6
6
|
import { Keypair } from '../../keypair.js';
|
|
7
7
|
import { transfer, mergeUtxos } from '../../transfer.js';
|
|
8
8
|
import { handleCLIError, CLIError, ErrorCode } from '../errors.js';
|
|
9
|
+
import { clearProgress, createProgressReporter, printFields, printHeader, printJson, printLine, txUrl } from '../output.js';
|
|
9
10
|
import type { RelayPool } from '../../types.js';
|
|
10
11
|
|
|
11
12
|
const SUPPORTED_ASSETS = ['ETH', 'USDC'];
|
|
12
13
|
|
|
13
|
-
// Progress helper - writes to stderr so JSON output stays clean
|
|
14
|
-
function progress(msg: string, quiet?: boolean) {
|
|
15
|
-
if (!quiet) {
|
|
16
|
-
process.stderr.write(`\r\x1b[K${msg}`);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
14
|
export function createTransferCommand(): Command {
|
|
21
15
|
const transferCmd = new Command('transfer')
|
|
22
16
|
.description('Transfer privately within the pool to another registered address')
|
|
23
17
|
.argument('<asset>', 'Asset to transfer (ETH or USDC)')
|
|
24
18
|
.argument('<amount>', 'Amount to transfer (e.g., 0.1)')
|
|
25
19
|
.argument('<recipient>', 'Recipient address (must be registered)')
|
|
26
|
-
.option('--
|
|
27
|
-
.
|
|
28
|
-
|
|
20
|
+
.option('--json', 'Output as JSON')
|
|
21
|
+
.addHelpText('after', `
|
|
22
|
+
Examples:
|
|
23
|
+
veil transfer ETH 0.02 0xRecipientAddress
|
|
24
|
+
veil transfer USDC 25 0xRecipientAddress
|
|
25
|
+
veil transfer ETH 0.02 0xRecipientAddress --json
|
|
26
|
+
`)
|
|
29
27
|
.action(async (asset: string, amount: string, recipient: string, options) => {
|
|
30
28
|
try {
|
|
31
29
|
const assetUpper = asset.toUpperCase();
|
|
@@ -41,24 +39,16 @@ export function createTransferCommand(): Command {
|
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
// Get keypair
|
|
44
|
-
const veilKey =
|
|
42
|
+
const veilKey = process.env.VEIL_KEY;
|
|
45
43
|
if (!veilKey) {
|
|
46
|
-
throw new CLIError(ErrorCode.VEIL_KEY_MISSING, 'VEIL_KEY required.
|
|
44
|
+
throw new CLIError(ErrorCode.VEIL_KEY_MISSING, 'VEIL_KEY required. Set VEIL_KEY env');
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
const senderKeypair = new Keypair(veilKey);
|
|
50
|
-
const rpcUrl =
|
|
48
|
+
const rpcUrl = process.env.RPC_URL;
|
|
51
49
|
const pool = assetUpper.toLowerCase() as RelayPool;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const onProgress = options.quiet
|
|
55
|
-
? undefined
|
|
56
|
-
: (stage: string, detail?: string) => {
|
|
57
|
-
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
58
|
-
progress(msg, options.quiet);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
progress(`Starting ${assetUpper} transfer...`, options.quiet);
|
|
50
|
+
const onProgress = createProgressReporter();
|
|
51
|
+
onProgress(`Starting ${assetUpper} transfer...`);
|
|
62
52
|
|
|
63
53
|
// Execute transfer
|
|
64
54
|
const result = await transfer({
|
|
@@ -70,11 +60,9 @@ export function createTransferCommand(): Command {
|
|
|
70
60
|
onProgress,
|
|
71
61
|
});
|
|
72
62
|
|
|
73
|
-
|
|
74
|
-
progress('', options.quiet);
|
|
63
|
+
clearProgress();
|
|
75
64
|
|
|
76
|
-
|
|
77
|
-
console.log(JSON.stringify({
|
|
65
|
+
const output = {
|
|
78
66
|
success: result.success,
|
|
79
67
|
transactionHash: result.transactionHash,
|
|
80
68
|
blockNumber: result.blockNumber,
|
|
@@ -82,10 +70,24 @@ export function createTransferCommand(): Command {
|
|
|
82
70
|
amount: result.amount,
|
|
83
71
|
recipient: result.recipient,
|
|
84
72
|
type: 'transfer',
|
|
85
|
-
}
|
|
86
|
-
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if (options.json) {
|
|
76
|
+
printJson(output);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
printHeader('Transfer Submitted');
|
|
81
|
+
printFields([
|
|
82
|
+
{ label: 'Asset', value: assetUpper },
|
|
83
|
+
{ label: 'Amount', value: result.amount },
|
|
84
|
+
{ label: 'Recipient', value: result.recipient },
|
|
85
|
+
{ label: 'Transaction', value: txUrl(result.transactionHash) },
|
|
86
|
+
{ label: 'Block', value: result.blockNumber },
|
|
87
|
+
]);
|
|
88
|
+
printLine();
|
|
87
89
|
} catch (error) {
|
|
88
|
-
|
|
90
|
+
clearProgress();
|
|
89
91
|
handleCLIError(error);
|
|
90
92
|
}
|
|
91
93
|
});
|
|
@@ -98,9 +100,13 @@ export function createMergeCommand(): Command {
|
|
|
98
100
|
.description('Merge UTXOs by self-transfer (consolidate small UTXOs)')
|
|
99
101
|
.argument('<asset>', 'Asset to merge (ETH or USDC)')
|
|
100
102
|
.argument('<amount>', 'Amount to merge (e.g., 0.5)')
|
|
101
|
-
.option('--
|
|
102
|
-
.
|
|
103
|
-
|
|
103
|
+
.option('--json', 'Output as JSON')
|
|
104
|
+
.addHelpText('after', `
|
|
105
|
+
Examples:
|
|
106
|
+
veil merge ETH 0.1
|
|
107
|
+
veil merge USDC 100
|
|
108
|
+
veil merge ETH 0.1 --json
|
|
109
|
+
`)
|
|
104
110
|
.action(async (asset: string, amount: string, options) => {
|
|
105
111
|
try {
|
|
106
112
|
const assetUpper = asset.toUpperCase();
|
|
@@ -111,24 +117,16 @@ export function createMergeCommand(): Command {
|
|
|
111
117
|
}
|
|
112
118
|
|
|
113
119
|
// Get keypair
|
|
114
|
-
const veilKey =
|
|
120
|
+
const veilKey = process.env.VEIL_KEY;
|
|
115
121
|
if (!veilKey) {
|
|
116
|
-
throw new CLIError(ErrorCode.VEIL_KEY_MISSING, 'VEIL_KEY required.
|
|
122
|
+
throw new CLIError(ErrorCode.VEIL_KEY_MISSING, 'VEIL_KEY required. Set VEIL_KEY env');
|
|
117
123
|
}
|
|
118
124
|
|
|
119
125
|
const keypair = new Keypair(veilKey);
|
|
120
|
-
const rpcUrl =
|
|
126
|
+
const rpcUrl = process.env.RPC_URL;
|
|
121
127
|
const pool = assetUpper.toLowerCase() as RelayPool;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const onProgress = options.quiet
|
|
125
|
-
? undefined
|
|
126
|
-
: (stage: string, detail?: string) => {
|
|
127
|
-
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
128
|
-
progress(msg, options.quiet);
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
progress(`Starting ${assetUpper} merge (self-transfer)...`, options.quiet);
|
|
128
|
+
const onProgress = createProgressReporter();
|
|
129
|
+
onProgress(`Starting ${assetUpper} merge (self-transfer)...`);
|
|
132
130
|
|
|
133
131
|
// Execute merge
|
|
134
132
|
const result = await mergeUtxos({
|
|
@@ -139,21 +137,32 @@ export function createMergeCommand(): Command {
|
|
|
139
137
|
onProgress,
|
|
140
138
|
});
|
|
141
139
|
|
|
142
|
-
|
|
143
|
-
progress('', options.quiet);
|
|
140
|
+
clearProgress();
|
|
144
141
|
|
|
145
|
-
|
|
146
|
-
console.log(JSON.stringify({
|
|
142
|
+
const output = {
|
|
147
143
|
success: result.success,
|
|
148
144
|
transactionHash: result.transactionHash,
|
|
149
145
|
blockNumber: result.blockNumber,
|
|
150
146
|
asset: assetUpper,
|
|
151
147
|
amount: result.amount,
|
|
152
148
|
type: 'merge',
|
|
153
|
-
}
|
|
154
|
-
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
if (options.json) {
|
|
152
|
+
printJson(output);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
printHeader('Merge Submitted');
|
|
157
|
+
printFields([
|
|
158
|
+
{ label: 'Asset', value: assetUpper },
|
|
159
|
+
{ label: 'Amount', value: result.amount },
|
|
160
|
+
{ label: 'Transaction', value: txUrl(result.transactionHash) },
|
|
161
|
+
{ label: 'Block', value: result.blockNumber },
|
|
162
|
+
]);
|
|
163
|
+
printLine();
|
|
155
164
|
} catch (error) {
|
|
156
|
-
|
|
165
|
+
clearProgress();
|
|
157
166
|
handleCLIError(error);
|
|
158
167
|
}
|
|
159
168
|
});
|
|
@@ -6,26 +6,24 @@ import { Command } from 'commander';
|
|
|
6
6
|
import { Keypair } from '../../keypair.js';
|
|
7
7
|
import { withdraw } from '../../withdraw.js';
|
|
8
8
|
import { handleCLIError, CLIError, ErrorCode } from '../errors.js';
|
|
9
|
+
import { clearProgress, createProgressReporter, printFields, printHeader, printJson, printLine, txUrl } from '../output.js';
|
|
9
10
|
import type { RelayPool } from '../../types.js';
|
|
10
11
|
|
|
11
12
|
const SUPPORTED_ASSETS = ['ETH', 'USDC'];
|
|
12
13
|
|
|
13
|
-
// Progress helper - writes to stderr so JSON output stays clean
|
|
14
|
-
function progress(msg: string, quiet?: boolean) {
|
|
15
|
-
if (!quiet) {
|
|
16
|
-
process.stderr.write(`\r\x1b[K${msg}`);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
14
|
export function createWithdrawCommand(): Command {
|
|
21
15
|
const withdrawCmd = new Command('withdraw')
|
|
22
16
|
.description('Withdraw from private pool to a public address')
|
|
23
17
|
.argument('<asset>', 'Asset to withdraw (ETH or USDC)')
|
|
24
18
|
.argument('<amount>', 'Amount to withdraw (e.g., 0.1)')
|
|
25
19
|
.argument('<recipient>', 'Recipient address (e.g., 0x...)')
|
|
26
|
-
.option('--
|
|
27
|
-
.
|
|
28
|
-
|
|
20
|
+
.option('--json', 'Output as JSON')
|
|
21
|
+
.addHelpText('after', `
|
|
22
|
+
Examples:
|
|
23
|
+
veil withdraw ETH 0.05 0xRecipientAddress
|
|
24
|
+
veil withdraw USDC 50 0xRecipientAddress
|
|
25
|
+
veil withdraw ETH 0.05 0xRecipientAddress --json
|
|
26
|
+
`)
|
|
29
27
|
.action(async (asset: string, amount: string, recipient: string, options) => {
|
|
30
28
|
try {
|
|
31
29
|
const assetUpper = asset.toUpperCase();
|
|
@@ -41,24 +39,16 @@ export function createWithdrawCommand(): Command {
|
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
// Get keypair
|
|
44
|
-
const veilKey =
|
|
42
|
+
const veilKey = process.env.VEIL_KEY;
|
|
45
43
|
if (!veilKey) {
|
|
46
|
-
throw new CLIError(ErrorCode.VEIL_KEY_MISSING, 'VEIL_KEY required.
|
|
44
|
+
throw new CLIError(ErrorCode.VEIL_KEY_MISSING, 'VEIL_KEY required. Set VEIL_KEY env');
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
const keypair = new Keypair(veilKey);
|
|
50
|
-
const rpcUrl =
|
|
48
|
+
const rpcUrl = process.env.RPC_URL;
|
|
51
49
|
const pool = assetUpper.toLowerCase() as RelayPool;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const onProgress = options.quiet
|
|
55
|
-
? undefined
|
|
56
|
-
: (stage: string, detail?: string) => {
|
|
57
|
-
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
58
|
-
progress(msg, options.quiet);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
progress(`Starting ${assetUpper} withdrawal...`, options.quiet);
|
|
50
|
+
const onProgress = createProgressReporter();
|
|
51
|
+
onProgress(`Starting ${assetUpper} withdrawal...`);
|
|
62
52
|
|
|
63
53
|
// Execute withdrawal
|
|
64
54
|
const result = await withdraw({
|
|
@@ -70,21 +60,33 @@ export function createWithdrawCommand(): Command {
|
|
|
70
60
|
onProgress,
|
|
71
61
|
});
|
|
72
62
|
|
|
73
|
-
|
|
74
|
-
progress('', options.quiet);
|
|
63
|
+
clearProgress();
|
|
75
64
|
|
|
76
|
-
|
|
77
|
-
console.log(JSON.stringify({
|
|
65
|
+
const output = {
|
|
78
66
|
success: result.success,
|
|
79
67
|
transactionHash: result.transactionHash,
|
|
80
68
|
blockNumber: result.blockNumber,
|
|
81
69
|
asset: assetUpper,
|
|
82
70
|
amount: result.amount,
|
|
83
71
|
recipient: result.recipient,
|
|
84
|
-
}
|
|
85
|
-
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
if (options.json) {
|
|
75
|
+
printJson(output);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
printHeader('Withdrawal Submitted');
|
|
80
|
+
printFields([
|
|
81
|
+
{ label: 'Asset', value: assetUpper },
|
|
82
|
+
{ label: 'Amount', value: result.amount },
|
|
83
|
+
{ label: 'Recipient', value: result.recipient },
|
|
84
|
+
{ label: 'Transaction', value: txUrl(result.transactionHash) },
|
|
85
|
+
{ label: 'Block', value: result.blockNumber },
|
|
86
|
+
]);
|
|
87
|
+
printLine();
|
|
86
88
|
} catch (error) {
|
|
87
|
-
|
|
89
|
+
clearProgress();
|
|
88
90
|
handleCLIError(error);
|
|
89
91
|
}
|
|
90
92
|
});
|
package/src/cli/config.ts
CHANGED
|
@@ -2,22 +2,50 @@
|
|
|
2
2
|
* CLI configuration handling
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { CLIError, ErrorCode } from './errors.js';
|
|
6
|
+
import { getAddress } from './wallet.js';
|
|
5
7
|
import type { WalletConfig } from './wallet.js';
|
|
6
8
|
|
|
7
9
|
export interface CLIOptions {
|
|
8
|
-
walletKey?: string;
|
|
9
10
|
rpcUrl?: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
export interface AddressOptions {
|
|
14
|
+
address?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ResolvedAddress {
|
|
18
|
+
address: `0x${string}`;
|
|
19
|
+
source: 'flag' | 'wallet-key' | 'signer-address';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function validateAddress(address: string, sourceLabel: string): `0x${string}` {
|
|
23
|
+
const normalized = address.trim();
|
|
24
|
+
if (!/^0x[a-fA-F0-9]{40}$/.test(normalized)) {
|
|
25
|
+
throw new CLIError(ErrorCode.INVALID_ADDRESS, `${sourceLabel} must be a valid 0x-prefixed Ethereum address.`);
|
|
26
|
+
}
|
|
27
|
+
return normalized as `0x${string}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function ensureAddressEnvConsistency(): void {
|
|
31
|
+
if (process.env.WALLET_KEY && process.env.SIGNER_ADDRESS) {
|
|
32
|
+
throw new CLIError(
|
|
33
|
+
ErrorCode.CONFIG_CONFLICT,
|
|
34
|
+
'WALLET_KEY and SIGNER_ADDRESS are mutually exclusive. Set only one.',
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
12
39
|
/**
|
|
13
40
|
* Get wallet configuration from CLI options and environment variables
|
|
14
41
|
*/
|
|
15
42
|
export function getConfig(options: CLIOptions): WalletConfig {
|
|
16
|
-
|
|
43
|
+
ensureAddressEnvConsistency();
|
|
44
|
+
const walletKey = process.env.WALLET_KEY;
|
|
17
45
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL || 'https://mainnet.base.org';
|
|
18
46
|
|
|
19
47
|
if (!walletKey) {
|
|
20
|
-
throw new Error('
|
|
48
|
+
throw new Error('WALLET_KEY env var required. Set it before running this command.');
|
|
21
49
|
}
|
|
22
50
|
|
|
23
51
|
// Validate wallet key format
|
|
@@ -38,6 +66,58 @@ export function getVeilKey(options: { veilKey?: string }): string | undefined {
|
|
|
38
66
|
return options.veilKey || process.env.VEIL_KEY;
|
|
39
67
|
}
|
|
40
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Resolve an address for query / unsigned flows.
|
|
71
|
+
* Prefers explicit --address, then derives from WALLET_KEY, then falls back to SIGNER_ADDRESS.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveAddress(
|
|
74
|
+
options: AddressOptions = {},
|
|
75
|
+
config: { required?: boolean; allowInvalidWalletKey?: boolean } = {},
|
|
76
|
+
): ResolvedAddress | null {
|
|
77
|
+
ensureAddressEnvConsistency();
|
|
78
|
+
|
|
79
|
+
if (options.address) {
|
|
80
|
+
return {
|
|
81
|
+
address: validateAddress(options.address, '--address'),
|
|
82
|
+
source: 'flag',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const walletKey = process.env.WALLET_KEY;
|
|
87
|
+
if (walletKey) {
|
|
88
|
+
try {
|
|
89
|
+
return {
|
|
90
|
+
address: getAddress(walletKey as `0x${string}`),
|
|
91
|
+
source: 'wallet-key',
|
|
92
|
+
};
|
|
93
|
+
} catch {
|
|
94
|
+
if (!config.allowInvalidWalletKey) {
|
|
95
|
+
throw new CLIError(
|
|
96
|
+
ErrorCode.WALLET_KEY_MISSING,
|
|
97
|
+
'Invalid WALLET_KEY format. Must be a 0x-prefixed 64-character hex string.',
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const signerAddress = process.env.SIGNER_ADDRESS;
|
|
104
|
+
if (signerAddress) {
|
|
105
|
+
return {
|
|
106
|
+
address: validateAddress(signerAddress, 'SIGNER_ADDRESS'),
|
|
107
|
+
source: 'signer-address',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (config.required) {
|
|
112
|
+
throw new CLIError(
|
|
113
|
+
ErrorCode.WALLET_KEY_MISSING,
|
|
114
|
+
'Must provide --address, set SIGNER_ADDRESS, or set WALLET_KEY env.',
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
41
121
|
/**
|
|
42
122
|
* Load environment variables from .env.veil and .env files
|
|
43
123
|
*/
|
|
@@ -46,10 +126,10 @@ export function loadEnv(): void {
|
|
|
46
126
|
// Dynamic import to avoid bundling issues
|
|
47
127
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
48
128
|
const dotenv = require('dotenv');
|
|
49
|
-
|
|
129
|
+
|
|
50
130
|
// Load .env.veil first (Veil-specific config)
|
|
51
131
|
dotenv.config({ path: '.env.veil', quiet: true });
|
|
52
|
-
|
|
132
|
+
|
|
53
133
|
// Then load .env (for WALLET_KEY, RPC_URL if not in .env.veil)
|
|
54
134
|
dotenv.config({ quiet: true });
|
|
55
135
|
} catch {
|
package/src/cli/errors.ts
CHANGED
|
@@ -9,6 +9,7 @@ export const ErrorCode = {
|
|
|
9
9
|
VEIL_KEY_MISSING: 'VEIL_KEY_MISSING',
|
|
10
10
|
WALLET_KEY_MISSING: 'WALLET_KEY_MISSING',
|
|
11
11
|
DEPOSIT_KEY_MISSING: 'DEPOSIT_KEY_MISSING',
|
|
12
|
+
CONFIG_CONFLICT: 'CONFIG_CONFLICT',
|
|
12
13
|
INVALID_ADDRESS: 'INVALID_ADDRESS',
|
|
13
14
|
INVALID_AMOUNT: 'INVALID_AMOUNT',
|
|
14
15
|
INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE',
|
|
@@ -51,6 +52,9 @@ function inferErrorCode(message: string): ErrorCodeType {
|
|
|
51
52
|
if (msg.includes('deposit_key') || msg.includes('deposit key')) {
|
|
52
53
|
return ErrorCode.DEPOSIT_KEY_MISSING;
|
|
53
54
|
}
|
|
55
|
+
if (msg.includes('mutually exclusive') || msg.includes('config conflict') || msg.includes('signer_address')) {
|
|
56
|
+
return ErrorCode.CONFIG_CONFLICT;
|
|
57
|
+
}
|
|
54
58
|
if (msg.includes('invalid') && msg.includes('address')) {
|
|
55
59
|
return ErrorCode.INVALID_ADDRESS;
|
|
56
60
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* veil register # Register on-chain
|
|
9
9
|
* veil deposit ETH 0.1 # Deposit ETH
|
|
10
10
|
* veil balance # Show all balances
|
|
11
|
-
* veil queue
|
|
12
|
-
* veil private
|
|
11
|
+
* veil balance queue # Show pending queue deposits
|
|
12
|
+
* veil balance private # Show private balance
|
|
13
13
|
* veil withdraw ETH 0.1 0x... # Withdraw to public address
|
|
14
14
|
* veil transfer ETH 0.1 0x... # Transfer privately
|
|
15
15
|
* veil merge ETH 0.5 # Merge UTXOs (self-transfer)
|
|
@@ -36,7 +36,14 @@ const program = new Command();
|
|
|
36
36
|
program
|
|
37
37
|
.name('veil')
|
|
38
38
|
.description('CLI for Veil Cash privacy pools on Base')
|
|
39
|
-
.version('0.
|
|
39
|
+
.version('0.5.0')
|
|
40
|
+
.addHelpText('after', `
|
|
41
|
+
Getting started:
|
|
42
|
+
veil init
|
|
43
|
+
veil register
|
|
44
|
+
veil deposit ETH 0.1
|
|
45
|
+
veil balance
|
|
46
|
+
`);
|
|
40
47
|
|
|
41
48
|
// Add commands
|
|
42
49
|
program.addCommand(createInitCommand());
|
|
@@ -44,12 +51,23 @@ program.addCommand(createKeypairCommand());
|
|
|
44
51
|
program.addCommand(createRegisterCommand());
|
|
45
52
|
program.addCommand(createDepositCommand());
|
|
46
53
|
program.addCommand(createBalanceCommand());
|
|
47
|
-
program.addCommand(createQueueBalanceCommand());
|
|
48
|
-
program.addCommand(createPrivateBalanceCommand());
|
|
54
|
+
program.addCommand(createQueueBalanceCommand(), { hidden: true });
|
|
55
|
+
program.addCommand(createPrivateBalanceCommand(), { hidden: true });
|
|
49
56
|
program.addCommand(createWithdrawCommand());
|
|
50
57
|
program.addCommand(createTransferCommand());
|
|
51
58
|
program.addCommand(createMergeCommand());
|
|
52
59
|
program.addCommand(createStatusCommand());
|
|
53
60
|
|
|
61
|
+
const knownTopLevelCommands = new Set([
|
|
62
|
+
...program.commands.map((command) => command.name()),
|
|
63
|
+
'help',
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
const firstArg = process.argv[2];
|
|
67
|
+
if (firstArg && !firstArg.startsWith('-') && !knownTopLevelCommands.has(firstArg)) {
|
|
68
|
+
console.error(`error: unknown command '${firstArg}'`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
54
72
|
// Parse and execute
|
|
55
73
|
program.parse();
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CLI output helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const DIM = '\x1b[2m';
|
|
6
|
+
const BOLD = '\x1b[1m';
|
|
7
|
+
const RESET = '\x1b[0m';
|
|
8
|
+
|
|
9
|
+
export interface JsonOutputOption {
|
|
10
|
+
json?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function printJson(value: unknown): void {
|
|
14
|
+
console.log(JSON.stringify(value, null, 2));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function printLine(value = ''): void {
|
|
18
|
+
console.log(value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function printHeader(title: string): void {
|
|
22
|
+
console.log();
|
|
23
|
+
console.log(`${BOLD}${title}${RESET}`);
|
|
24
|
+
console.log(`${DIM}${'─'.repeat(40)}${RESET}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function printSection(title: string): void {
|
|
28
|
+
console.log();
|
|
29
|
+
console.log(`${BOLD}${title}${RESET}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function printDivider(): void {
|
|
33
|
+
console.log();
|
|
34
|
+
console.log(`${DIM}${'─'.repeat(40)}${RESET}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function printFields(fields: Array<{ label: string; value: unknown }>): void {
|
|
38
|
+
const visibleFields = fields.filter((field) => field.value !== undefined);
|
|
39
|
+
const width = visibleFields.reduce((max, field) => Math.max(max, field.label.length), 0);
|
|
40
|
+
|
|
41
|
+
for (const field of visibleFields) {
|
|
42
|
+
const label = `${DIM}${field.label.padEnd(width)}${RESET}`;
|
|
43
|
+
console.log(` ${label} ${formatValue(field.value)}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function printList(items: string[]): void {
|
|
48
|
+
if (items.length === 0) {
|
|
49
|
+
console.log(` ${DIM}(none)${RESET}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
for (const item of items) {
|
|
54
|
+
console.log(` ${item}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function maskValue(value: string, start = 10, end = 8): string {
|
|
59
|
+
if (value.length <= start + end + 3) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return `${value.slice(0, start)}...${value.slice(-end)}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function txUrl(hash: string): string {
|
|
67
|
+
return `https://basescan.org/tx/${hash}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function clearProgress(): void {
|
|
71
|
+
process.stderr.write('\r\x1b[K');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function createProgressReporter(): (stage: string, detail?: string) => void {
|
|
75
|
+
return (stage: string, detail?: string) => {
|
|
76
|
+
const message = detail ? `${stage}: ${detail}` : stage;
|
|
77
|
+
process.stderr.write(`\r\x1b[K${message}`);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function formatValue(value: unknown): string {
|
|
82
|
+
if (value === null) return 'null';
|
|
83
|
+
if (value === undefined) return '';
|
|
84
|
+
if (typeof value === 'boolean') return value ? 'yes' : 'no';
|
|
85
|
+
if (typeof value === 'object') return JSON.stringify(value);
|
|
86
|
+
return String(value);
|
|
87
|
+
}
|