@veil-cash/sdk 0.1.1 → 0.2.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 +77 -29
- package/dist/cli/index.cjs +94 -4
- package/package.json +1 -1
- package/src/cli/commands/deposit.ts +7 -1
- package/src/cli/commands/status.ts +129 -0
- package/src/cli/commands/transfer.ts +14 -2
- package/src/cli/commands/withdraw.ts +7 -1
- package/src/cli/index.ts +13 -10
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
SDK and CLI for interacting with [Veil Cash](https://veil.cash) privacy pools on Base.
|
|
8
8
|
|
|
9
|
-
Generate keypairs, register, deposit, withdraw, and
|
|
9
|
+
Generate keypairs, register, deposit, withdraw, transfer, and merge ETH privately.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -35,17 +35,23 @@ export WALLET_KEY=0x...
|
|
|
35
35
|
# 3. Register your deposit key (one-time)
|
|
36
36
|
veil register
|
|
37
37
|
|
|
38
|
-
# 4.
|
|
39
|
-
veil
|
|
38
|
+
# 4. Check your setup
|
|
39
|
+
veil status
|
|
40
40
|
|
|
41
|
-
# 5.
|
|
41
|
+
# 5. Deposit ETH
|
|
42
|
+
veil deposit ETH 0.1
|
|
43
|
+
|
|
44
|
+
# 6. Check your balance
|
|
42
45
|
veil balance
|
|
43
46
|
|
|
44
|
-
#
|
|
45
|
-
veil withdraw 0.05 0xRecipientAddress
|
|
47
|
+
# 7. Withdraw to any address
|
|
48
|
+
veil withdraw ETH 0.05 0xRecipientAddress
|
|
49
|
+
|
|
50
|
+
# 8. Transfer privately to another registered user
|
|
51
|
+
veil transfer ETH 0.02 0xRecipientAddress
|
|
46
52
|
|
|
47
|
-
#
|
|
48
|
-
veil
|
|
53
|
+
# 9. Merge small UTXOs (consolidate balances)
|
|
54
|
+
veil merge ETH 0.1
|
|
49
55
|
```
|
|
50
56
|
|
|
51
57
|
## CLI Commands
|
|
@@ -64,13 +70,43 @@ veil init --no-save # Print keypair without saving
|
|
|
64
70
|
|
|
65
71
|
### `veil keypair`
|
|
66
72
|
|
|
67
|
-
|
|
73
|
+
Show current Veil keypair as JSON (from VEIL_KEY env).
|
|
68
74
|
|
|
69
75
|
```bash
|
|
70
76
|
veil keypair
|
|
71
77
|
# {"veilPrivateKey":"0x...","depositKey":"0x..."}
|
|
72
78
|
```
|
|
73
79
|
|
|
80
|
+
### `veil status`
|
|
81
|
+
|
|
82
|
+
Check configuration and service status.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
veil status
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Output:
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"walletKey": { "found": true, "address": "0x..." },
|
|
92
|
+
"veilKey": { "found": true },
|
|
93
|
+
"depositKey": { "found": true, "key": "0x1234...abcd" },
|
|
94
|
+
"rpcUrl": { "found": false, "url": "https://mainnet.base.org" },
|
|
95
|
+
"registration": {
|
|
96
|
+
"checked": true,
|
|
97
|
+
"registered": true,
|
|
98
|
+
"matches": true,
|
|
99
|
+
"onChainKey": "0x..."
|
|
100
|
+
},
|
|
101
|
+
"relay": {
|
|
102
|
+
"checked": true,
|
|
103
|
+
"healthy": true,
|
|
104
|
+
"status": "ok",
|
|
105
|
+
"network": "mainnet"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
74
110
|
### `veil register`
|
|
75
111
|
|
|
76
112
|
Register your deposit key on-chain (one-time per address).
|
|
@@ -81,14 +117,14 @@ veil register --json # JSON output
|
|
|
81
117
|
veil register --unsigned --address 0x... # Unsigned payload for agents
|
|
82
118
|
```
|
|
83
119
|
|
|
84
|
-
### `veil deposit <amount>`
|
|
120
|
+
### `veil deposit ETH <amount>`
|
|
85
121
|
|
|
86
122
|
Deposit ETH into the privacy pool.
|
|
87
123
|
|
|
88
124
|
```bash
|
|
89
|
-
veil deposit 0.1 # Signs & sends (JSON output)
|
|
90
|
-
veil deposit 0.1 --unsigned # Unsigned payload for agents
|
|
91
|
-
veil deposit 0.1 --quiet # Suppress progress output
|
|
125
|
+
veil deposit ETH 0.1 # Signs & sends (JSON output)
|
|
126
|
+
veil deposit ETH 0.1 --unsigned # Unsigned payload for agents
|
|
127
|
+
veil deposit ETH 0.1 --quiet # Suppress progress output
|
|
92
128
|
```
|
|
93
129
|
|
|
94
130
|
Output:
|
|
@@ -138,13 +174,13 @@ Output:
|
|
|
138
174
|
}
|
|
139
175
|
```
|
|
140
176
|
|
|
141
|
-
### `veil withdraw <amount> <recipient>`
|
|
177
|
+
### `veil withdraw ETH <amount> <recipient>`
|
|
142
178
|
|
|
143
179
|
Withdraw from the privacy pool to any public address.
|
|
144
180
|
|
|
145
181
|
```bash
|
|
146
|
-
veil withdraw 0.05 0xRecipientAddress
|
|
147
|
-
veil withdraw 0.05 0xRecipientAddress --quiet
|
|
182
|
+
veil withdraw ETH 0.05 0xRecipientAddress
|
|
183
|
+
veil withdraw ETH 0.05 0xRecipientAddress --quiet
|
|
148
184
|
```
|
|
149
185
|
|
|
150
186
|
Output:
|
|
@@ -159,13 +195,13 @@ Output:
|
|
|
159
195
|
}
|
|
160
196
|
```
|
|
161
197
|
|
|
162
|
-
### `veil transfer <amount> <recipient>`
|
|
198
|
+
### `veil transfer ETH <amount> <recipient>`
|
|
163
199
|
|
|
164
200
|
Transfer privately to another registered Veil user.
|
|
165
201
|
|
|
166
202
|
```bash
|
|
167
|
-
veil transfer 0.02 0xRecipientAddress
|
|
168
|
-
veil transfer 0.02 0xRecipientAddress --quiet
|
|
203
|
+
veil transfer ETH 0.02 0xRecipientAddress
|
|
204
|
+
veil transfer ETH 0.02 0xRecipientAddress --quiet
|
|
169
205
|
```
|
|
170
206
|
|
|
171
207
|
Output:
|
|
@@ -180,13 +216,24 @@ Output:
|
|
|
180
216
|
}
|
|
181
217
|
```
|
|
182
218
|
|
|
183
|
-
### `veil merge <amount>`
|
|
219
|
+
### `veil merge ETH <amount>`
|
|
184
220
|
|
|
185
221
|
Consolidate multiple small UTXOs into one (self-transfer).
|
|
186
222
|
|
|
187
223
|
```bash
|
|
188
|
-
veil merge 0.1 # Merge UTXOs totaling 0.1 ETH
|
|
189
|
-
veil merge 0.1 --quiet
|
|
224
|
+
veil merge ETH 0.1 # Merge UTXOs totaling 0.1 ETH
|
|
225
|
+
veil merge ETH 0.1 --quiet
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Output:
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"success": true,
|
|
232
|
+
"transactionHash": "0x...",
|
|
233
|
+
"blockNumber": 12345678,
|
|
234
|
+
"amount": "0.1",
|
|
235
|
+
"type": "merge"
|
|
236
|
+
}
|
|
190
237
|
```
|
|
191
238
|
|
|
192
239
|
## Environment Variables
|
|
@@ -391,11 +438,11 @@ veil init --json
|
|
|
391
438
|
|
|
392
439
|
# Get unsigned transaction payloads for agent signing
|
|
393
440
|
veil register --unsigned --address 0x...
|
|
394
|
-
veil deposit 0.1 --unsigned
|
|
441
|
+
veil deposit ETH 0.1 --unsigned
|
|
395
442
|
|
|
396
443
|
# Suppress progress output for clean JSON
|
|
397
444
|
veil balance --quiet
|
|
398
|
-
veil withdraw 0.05 0xRecipient --quiet
|
|
445
|
+
veil withdraw ETH 0.05 0xRecipient --quiet
|
|
399
446
|
```
|
|
400
447
|
|
|
401
448
|
### Bankr Integration
|
|
@@ -403,7 +450,7 @@ veil withdraw 0.05 0xRecipient --quiet
|
|
|
403
450
|
Use `--unsigned` to get Bankr-compatible transaction payloads:
|
|
404
451
|
|
|
405
452
|
```bash
|
|
406
|
-
veil deposit 0.1 --unsigned
|
|
453
|
+
veil deposit ETH 0.1 --unsigned
|
|
407
454
|
# {"to":"0x...","data":"0x...","value":"100000000000000000","chainId":8453}
|
|
408
455
|
```
|
|
409
456
|
|
|
@@ -435,14 +482,15 @@ const result = await withdraw({
|
|
|
435
482
|
|
|
436
483
|
1. **Generate Keypair**: Run `veil init` to create and save your Veil keypair
|
|
437
484
|
2. **Register**: Run `veil register` to link your deposit key on-chain (one-time)
|
|
438
|
-
3. **
|
|
439
|
-
4. **
|
|
440
|
-
5. **
|
|
485
|
+
3. **Check Status**: Run `veil status` to verify your setup
|
|
486
|
+
4. **Deposit**: Run `veil deposit ETH <amount>` to send ETH
|
|
487
|
+
5. **Wait**: The Veil deposit engine processes your deposit
|
|
488
|
+
6. **Done**: Your deposit is accepted into the privacy pool
|
|
441
489
|
|
|
442
490
|
## Withdrawal Flow
|
|
443
491
|
|
|
444
492
|
1. **Check Balance**: Run `veil balance` to see your private balance
|
|
445
|
-
2. **Withdraw**: Run `veil withdraw <amount> <recipient>`
|
|
493
|
+
2. **Withdraw**: Run `veil withdraw ETH <amount> <recipient>`
|
|
446
494
|
3. **Done**: The SDK builds ZK proofs and submits via the relayer
|
|
447
495
|
|
|
448
496
|
## License
|
package/dist/cli/index.cjs
CHANGED
|
@@ -5170,8 +5170,11 @@ function progress(msg, quiet) {
|
|
|
5170
5170
|
}
|
|
5171
5171
|
}
|
|
5172
5172
|
function createDepositCommand() {
|
|
5173
|
-
const deposit = new Command("deposit").description("Deposit ETH into Veil").argument("<amount>", "Amount to deposit (e.g., 0.1)").option("--deposit-key <key>", "Your Veil deposit key (or set DEPOSIT_KEY env)").option("--wallet-key <key>", "Ethereum wallet key for signing (or set WALLET_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--unsigned", "Output unsigned transaction payload (Bankr-compatible format)").option("--quiet", "Suppress progress output").action(async (amount, options) => {
|
|
5173
|
+
const deposit = new Command("deposit").description("Deposit ETH into Veil").argument("<asset>", "Asset to deposit (ETH)").argument("<amount>", "Amount to deposit (e.g., 0.1)").option("--deposit-key <key>", "Your Veil deposit key (or set DEPOSIT_KEY env)").option("--wallet-key <key>", "Ethereum wallet key for signing (or set WALLET_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--unsigned", "Output unsigned transaction payload (Bankr-compatible format)").option("--quiet", "Suppress progress output").action(async (asset, amount, options) => {
|
|
5174
5174
|
try {
|
|
5175
|
+
if (asset.toUpperCase() !== "ETH") {
|
|
5176
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, "Only ETH is supported");
|
|
5177
|
+
}
|
|
5175
5178
|
const amountNum = parseFloat(amount);
|
|
5176
5179
|
if (amountNum < MINIMUM_DEPOSIT_WITH_FEE) {
|
|
5177
5180
|
throw new CLIError(
|
|
@@ -5847,6 +5850,14 @@ async function submitRelay(options) {
|
|
|
5847
5850
|
}
|
|
5848
5851
|
return data;
|
|
5849
5852
|
}
|
|
5853
|
+
async function checkRelayHealth(relayUrl) {
|
|
5854
|
+
const url = getRelayUrl();
|
|
5855
|
+
const response = await fetch(`${url}/health`);
|
|
5856
|
+
if (!response.ok) {
|
|
5857
|
+
throw new RelayError("Relay service health check failed", response.status);
|
|
5858
|
+
}
|
|
5859
|
+
return response.json();
|
|
5860
|
+
}
|
|
5850
5861
|
|
|
5851
5862
|
// src/withdraw.ts
|
|
5852
5863
|
function selectUtxosForWithdraw(utxos, amount, decimals = 18) {
|
|
@@ -6018,8 +6029,11 @@ function progress2(msg, quiet) {
|
|
|
6018
6029
|
}
|
|
6019
6030
|
}
|
|
6020
6031
|
function createWithdrawCommand() {
|
|
6021
|
-
const withdrawCmd = new Command("withdraw").description("Withdraw from private pool to a public address").argument("<amount>", "Amount to withdraw (e.g., 0.1)").argument("<recipient>", "Recipient address (e.g., 0x...)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (amount, recipient, options) => {
|
|
6032
|
+
const withdrawCmd = new Command("withdraw").description("Withdraw from private pool to a public address").argument("<asset>", "Asset to withdraw (ETH)").argument("<amount>", "Amount to withdraw (e.g., 0.1)").argument("<recipient>", "Recipient address (e.g., 0x...)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, recipient, options) => {
|
|
6022
6033
|
try {
|
|
6034
|
+
if (asset.toUpperCase() !== "ETH") {
|
|
6035
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, "Only ETH is supported");
|
|
6036
|
+
}
|
|
6023
6037
|
if (!/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
|
|
6024
6038
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, "Invalid recipient address format");
|
|
6025
6039
|
}
|
|
@@ -6337,8 +6351,11 @@ function progress3(msg, quiet) {
|
|
|
6337
6351
|
}
|
|
6338
6352
|
}
|
|
6339
6353
|
function createTransferCommand() {
|
|
6340
|
-
const transferCmd = new Command("transfer").description("Transfer privately within the pool to another registered address").argument("<amount>", "Amount to transfer (e.g., 0.1)").argument("<recipient>", "Recipient address (must be registered)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (amount, recipient, options) => {
|
|
6354
|
+
const transferCmd = new Command("transfer").description("Transfer privately within the pool to another registered address").argument("<asset>", "Asset to transfer (ETH)").argument("<amount>", "Amount to transfer (e.g., 0.1)").argument("<recipient>", "Recipient address (must be registered)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, recipient, options) => {
|
|
6341
6355
|
try {
|
|
6356
|
+
if (asset.toUpperCase() !== "ETH") {
|
|
6357
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, "Only ETH is supported");
|
|
6358
|
+
}
|
|
6342
6359
|
if (!/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
|
|
6343
6360
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, "Invalid recipient address format");
|
|
6344
6361
|
}
|
|
@@ -6378,8 +6395,11 @@ function createTransferCommand() {
|
|
|
6378
6395
|
return transferCmd;
|
|
6379
6396
|
}
|
|
6380
6397
|
function createMergeCommand() {
|
|
6381
|
-
const mergeCmd = new Command("merge").description("Merge UTXOs by self-transfer (consolidate small UTXOs)").argument("<amount>", "Amount to merge (e.g., 0.5)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (amount, options) => {
|
|
6398
|
+
const mergeCmd = new Command("merge").description("Merge UTXOs by self-transfer (consolidate small UTXOs)").argument("<asset>", "Asset to merge (ETH)").argument("<amount>", "Amount to merge (e.g., 0.5)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, options) => {
|
|
6382
6399
|
try {
|
|
6400
|
+
if (asset.toUpperCase() !== "ETH") {
|
|
6401
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, "Only ETH is supported");
|
|
6402
|
+
}
|
|
6383
6403
|
const veilKey = options.veilKey || process.env.VEIL_KEY;
|
|
6384
6404
|
if (!veilKey) {
|
|
6385
6405
|
throw new CLIError(ErrorCode.VEIL_KEY_MISSING, "VEIL_KEY required. Use --veil-key or set VEIL_KEY env");
|
|
@@ -6414,6 +6434,75 @@ function createMergeCommand() {
|
|
|
6414
6434
|
return mergeCmd;
|
|
6415
6435
|
}
|
|
6416
6436
|
|
|
6437
|
+
// src/cli/commands/status.ts
|
|
6438
|
+
function createStatusCommand() {
|
|
6439
|
+
const status = new Command("status").description("Check configuration and service status").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").action(async (options) => {
|
|
6440
|
+
const result = {
|
|
6441
|
+
walletKey: { found: false },
|
|
6442
|
+
veilKey: { found: false },
|
|
6443
|
+
depositKey: { found: false },
|
|
6444
|
+
rpcUrl: { found: false, url: "https://mainnet.base.org" },
|
|
6445
|
+
registration: { checked: false },
|
|
6446
|
+
relay: { checked: false }
|
|
6447
|
+
};
|
|
6448
|
+
const walletKey = process.env.WALLET_KEY;
|
|
6449
|
+
if (walletKey) {
|
|
6450
|
+
result.walletKey.found = true;
|
|
6451
|
+
try {
|
|
6452
|
+
result.walletKey.address = getAddress(walletKey);
|
|
6453
|
+
} catch {
|
|
6454
|
+
}
|
|
6455
|
+
}
|
|
6456
|
+
const veilKey = process.env.VEIL_KEY;
|
|
6457
|
+
if (veilKey) {
|
|
6458
|
+
result.veilKey.found = true;
|
|
6459
|
+
}
|
|
6460
|
+
const depositKey = process.env.DEPOSIT_KEY;
|
|
6461
|
+
if (depositKey) {
|
|
6462
|
+
result.depositKey.found = true;
|
|
6463
|
+
if (depositKey.length > 20) {
|
|
6464
|
+
result.depositKey.key = `${depositKey.slice(0, 10)}...${depositKey.slice(-8)}`;
|
|
6465
|
+
} else {
|
|
6466
|
+
result.depositKey.key = depositKey;
|
|
6467
|
+
}
|
|
6468
|
+
}
|
|
6469
|
+
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
6470
|
+
if (rpcUrl) {
|
|
6471
|
+
result.rpcUrl.found = true;
|
|
6472
|
+
result.rpcUrl.url = rpcUrl;
|
|
6473
|
+
}
|
|
6474
|
+
const effectiveRpcUrl = rpcUrl || "https://mainnet.base.org";
|
|
6475
|
+
if (result.walletKey.found && result.walletKey.address) {
|
|
6476
|
+
result.registration.checked = true;
|
|
6477
|
+
try {
|
|
6478
|
+
const regStatus = await isRegistered(
|
|
6479
|
+
result.walletKey.address,
|
|
6480
|
+
effectiveRpcUrl
|
|
6481
|
+
);
|
|
6482
|
+
result.registration.registered = regStatus.registered;
|
|
6483
|
+
result.registration.onChainKey = regStatus.depositKey;
|
|
6484
|
+
if (regStatus.registered && depositKey && regStatus.depositKey) {
|
|
6485
|
+
result.registration.matches = regStatus.depositKey.toLowerCase() === depositKey.toLowerCase();
|
|
6486
|
+
}
|
|
6487
|
+
} catch (error) {
|
|
6488
|
+
result.registration.error = error instanceof Error ? error.message : "Unknown error";
|
|
6489
|
+
}
|
|
6490
|
+
}
|
|
6491
|
+
result.relay.checked = true;
|
|
6492
|
+
try {
|
|
6493
|
+
const health = await checkRelayHealth();
|
|
6494
|
+
result.relay.healthy = health.status === "ok";
|
|
6495
|
+
result.relay.status = health.status;
|
|
6496
|
+
result.relay.network = health.network;
|
|
6497
|
+
} catch (error) {
|
|
6498
|
+
result.relay.healthy = false;
|
|
6499
|
+
result.relay.error = error instanceof Error ? error.message : "Unknown error";
|
|
6500
|
+
}
|
|
6501
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6502
|
+
});
|
|
6503
|
+
return status;
|
|
6504
|
+
}
|
|
6505
|
+
|
|
6417
6506
|
// src/cli/index.ts
|
|
6418
6507
|
loadEnv();
|
|
6419
6508
|
var program2 = new Command();
|
|
@@ -6428,4 +6517,5 @@ program2.addCommand(createPrivateBalanceCommand());
|
|
|
6428
6517
|
program2.addCommand(createWithdrawCommand());
|
|
6429
6518
|
program2.addCommand(createTransferCommand());
|
|
6430
6519
|
program2.addCommand(createMergeCommand());
|
|
6520
|
+
program2.addCommand(createStatusCommand());
|
|
6431
6521
|
program2.parse();
|
package/package.json
CHANGED
|
@@ -25,14 +25,20 @@ function progress(msg: string, quiet?: boolean) {
|
|
|
25
25
|
export function createDepositCommand(): Command {
|
|
26
26
|
const deposit = new Command('deposit')
|
|
27
27
|
.description('Deposit ETH into Veil')
|
|
28
|
+
.argument('<asset>', 'Asset to deposit (ETH)')
|
|
28
29
|
.argument('<amount>', 'Amount to deposit (e.g., 0.1)')
|
|
29
30
|
.option('--deposit-key <key>', 'Your Veil deposit key (or set DEPOSIT_KEY env)')
|
|
30
31
|
.option('--wallet-key <key>', 'Ethereum wallet key for signing (or set WALLET_KEY env)')
|
|
31
32
|
.option('--rpc-url <url>', 'RPC URL (or set RPC_URL env)')
|
|
32
33
|
.option('--unsigned', 'Output unsigned transaction payload (Bankr-compatible format)')
|
|
33
34
|
.option('--quiet', 'Suppress progress output')
|
|
34
|
-
.action(async (amount: string, options) => {
|
|
35
|
+
.action(async (asset: string, amount: string, options) => {
|
|
35
36
|
try {
|
|
37
|
+
// Validate asset is ETH
|
|
38
|
+
if (asset.toUpperCase() !== 'ETH') {
|
|
39
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, 'Only ETH is supported');
|
|
40
|
+
}
|
|
41
|
+
|
|
36
42
|
const amountNum = parseFloat(amount);
|
|
37
43
|
|
|
38
44
|
// Check minimum deposit
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status CLI command - Check configuration and service status
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { isRegistered, getAddress } from '../wallet.js';
|
|
7
|
+
import { checkRelayHealth } from '../../relay.js';
|
|
8
|
+
|
|
9
|
+
interface StatusResult {
|
|
10
|
+
walletKey: {
|
|
11
|
+
found: boolean;
|
|
12
|
+
address?: string;
|
|
13
|
+
};
|
|
14
|
+
veilKey: {
|
|
15
|
+
found: boolean;
|
|
16
|
+
};
|
|
17
|
+
depositKey: {
|
|
18
|
+
found: boolean;
|
|
19
|
+
key?: string;
|
|
20
|
+
};
|
|
21
|
+
rpcUrl: {
|
|
22
|
+
found: boolean;
|
|
23
|
+
url: string;
|
|
24
|
+
};
|
|
25
|
+
registration: {
|
|
26
|
+
checked: boolean;
|
|
27
|
+
registered?: boolean;
|
|
28
|
+
matches?: boolean;
|
|
29
|
+
onChainKey?: string | null;
|
|
30
|
+
error?: string;
|
|
31
|
+
};
|
|
32
|
+
relay: {
|
|
33
|
+
checked: boolean;
|
|
34
|
+
healthy?: boolean;
|
|
35
|
+
status?: string;
|
|
36
|
+
network?: string;
|
|
37
|
+
error?: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function createStatusCommand(): Command {
|
|
42
|
+
const status = new Command('status')
|
|
43
|
+
.description('Check configuration and service status')
|
|
44
|
+
.option('--rpc-url <url>', 'RPC URL (or set RPC_URL env)')
|
|
45
|
+
.action(async (options) => {
|
|
46
|
+
const result: StatusResult = {
|
|
47
|
+
walletKey: { found: false },
|
|
48
|
+
veilKey: { found: false },
|
|
49
|
+
depositKey: { found: false },
|
|
50
|
+
rpcUrl: { found: false, url: 'https://mainnet.base.org' },
|
|
51
|
+
registration: { checked: false },
|
|
52
|
+
relay: { checked: false },
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Check WALLET_KEY
|
|
56
|
+
const walletKey = process.env.WALLET_KEY;
|
|
57
|
+
if (walletKey) {
|
|
58
|
+
result.walletKey.found = true;
|
|
59
|
+
try {
|
|
60
|
+
result.walletKey.address = getAddress(walletKey as `0x${string}`);
|
|
61
|
+
} catch {
|
|
62
|
+
// Invalid key format, but it was found
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Check VEIL_KEY
|
|
67
|
+
const veilKey = process.env.VEIL_KEY;
|
|
68
|
+
if (veilKey) {
|
|
69
|
+
result.veilKey.found = true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check DEPOSIT_KEY
|
|
73
|
+
const depositKey = process.env.DEPOSIT_KEY;
|
|
74
|
+
if (depositKey) {
|
|
75
|
+
result.depositKey.found = true;
|
|
76
|
+
// Show truncated key
|
|
77
|
+
if (depositKey.length > 20) {
|
|
78
|
+
result.depositKey.key = `${depositKey.slice(0, 10)}...${depositKey.slice(-8)}`;
|
|
79
|
+
} else {
|
|
80
|
+
result.depositKey.key = depositKey;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check RPC_URL
|
|
85
|
+
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
86
|
+
if (rpcUrl) {
|
|
87
|
+
result.rpcUrl.found = true;
|
|
88
|
+
result.rpcUrl.url = rpcUrl;
|
|
89
|
+
}
|
|
90
|
+
const effectiveRpcUrl = rpcUrl || 'https://mainnet.base.org';
|
|
91
|
+
|
|
92
|
+
// Check registration status (requires wallet address)
|
|
93
|
+
if (result.walletKey.found && result.walletKey.address) {
|
|
94
|
+
result.registration.checked = true;
|
|
95
|
+
try {
|
|
96
|
+
const regStatus = await isRegistered(
|
|
97
|
+
result.walletKey.address as `0x${string}`,
|
|
98
|
+
effectiveRpcUrl
|
|
99
|
+
);
|
|
100
|
+
result.registration.registered = regStatus.registered;
|
|
101
|
+
result.registration.onChainKey = regStatus.depositKey;
|
|
102
|
+
|
|
103
|
+
// Check if on-chain key matches env DEPOSIT_KEY
|
|
104
|
+
if (regStatus.registered && depositKey && regStatus.depositKey) {
|
|
105
|
+
result.registration.matches =
|
|
106
|
+
regStatus.depositKey.toLowerCase() === depositKey.toLowerCase();
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
result.registration.error = error instanceof Error ? error.message : 'Unknown error';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check relay health
|
|
114
|
+
result.relay.checked = true;
|
|
115
|
+
try {
|
|
116
|
+
const health = await checkRelayHealth();
|
|
117
|
+
result.relay.healthy = health.status === 'ok';
|
|
118
|
+
result.relay.status = health.status;
|
|
119
|
+
result.relay.network = health.network;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
result.relay.healthy = false;
|
|
122
|
+
result.relay.error = error instanceof Error ? error.message : 'Unknown error';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log(JSON.stringify(result, null, 2));
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return status;
|
|
129
|
+
}
|
|
@@ -17,13 +17,19 @@ function progress(msg: string, quiet?: boolean) {
|
|
|
17
17
|
export function createTransferCommand(): Command {
|
|
18
18
|
const transferCmd = new Command('transfer')
|
|
19
19
|
.description('Transfer privately within the pool to another registered address')
|
|
20
|
+
.argument('<asset>', 'Asset to transfer (ETH)')
|
|
20
21
|
.argument('<amount>', 'Amount to transfer (e.g., 0.1)')
|
|
21
22
|
.argument('<recipient>', 'Recipient address (must be registered)')
|
|
22
23
|
.option('--veil-key <key>', 'Veil private key (or set VEIL_KEY env)')
|
|
23
24
|
.option('--rpc-url <url>', 'RPC URL (or set RPC_URL env)')
|
|
24
25
|
.option('--quiet', 'Suppress progress output')
|
|
25
|
-
.action(async (amount: string, recipient: string, options) => {
|
|
26
|
+
.action(async (asset: string, amount: string, recipient: string, options) => {
|
|
26
27
|
try {
|
|
28
|
+
// Validate asset is ETH
|
|
29
|
+
if (asset.toUpperCase() !== 'ETH') {
|
|
30
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, 'Only ETH is supported');
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
// Validate recipient
|
|
28
34
|
if (!/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
|
|
29
35
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, 'Invalid recipient address format');
|
|
@@ -82,12 +88,18 @@ export function createTransferCommand(): Command {
|
|
|
82
88
|
export function createMergeCommand(): Command {
|
|
83
89
|
const mergeCmd = new Command('merge')
|
|
84
90
|
.description('Merge UTXOs by self-transfer (consolidate small UTXOs)')
|
|
91
|
+
.argument('<asset>', 'Asset to merge (ETH)')
|
|
85
92
|
.argument('<amount>', 'Amount to merge (e.g., 0.5)')
|
|
86
93
|
.option('--veil-key <key>', 'Veil private key (or set VEIL_KEY env)')
|
|
87
94
|
.option('--rpc-url <url>', 'RPC URL (or set RPC_URL env)')
|
|
88
95
|
.option('--quiet', 'Suppress progress output')
|
|
89
|
-
.action(async (amount: string, options) => {
|
|
96
|
+
.action(async (asset: string, amount: string, options) => {
|
|
90
97
|
try {
|
|
98
|
+
// Validate asset is ETH
|
|
99
|
+
if (asset.toUpperCase() !== 'ETH') {
|
|
100
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, 'Only ETH is supported');
|
|
101
|
+
}
|
|
102
|
+
|
|
91
103
|
// Get keypair
|
|
92
104
|
const veilKey = options.veilKey || process.env.VEIL_KEY;
|
|
93
105
|
if (!veilKey) {
|
|
@@ -17,13 +17,19 @@ function progress(msg: string, quiet?: boolean) {
|
|
|
17
17
|
export function createWithdrawCommand(): Command {
|
|
18
18
|
const withdrawCmd = new Command('withdraw')
|
|
19
19
|
.description('Withdraw from private pool to a public address')
|
|
20
|
+
.argument('<asset>', 'Asset to withdraw (ETH)')
|
|
20
21
|
.argument('<amount>', 'Amount to withdraw (e.g., 0.1)')
|
|
21
22
|
.argument('<recipient>', 'Recipient address (e.g., 0x...)')
|
|
22
23
|
.option('--veil-key <key>', 'Veil private key (or set VEIL_KEY env)')
|
|
23
24
|
.option('--rpc-url <url>', 'RPC URL (or set RPC_URL env)')
|
|
24
25
|
.option('--quiet', 'Suppress progress output')
|
|
25
|
-
.action(async (amount: string, recipient: string, options) => {
|
|
26
|
+
.action(async (asset: string, amount: string, recipient: string, options) => {
|
|
26
27
|
try {
|
|
28
|
+
// Validate asset is ETH
|
|
29
|
+
if (asset.toUpperCase() !== 'ETH') {
|
|
30
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, 'Only ETH is supported');
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
// Validate recipient
|
|
28
34
|
if (!/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
|
|
29
35
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, 'Invalid recipient address format');
|
package/src/cli/index.ts
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
* Veil CLI - Command-line interface for Veil Cash
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
|
-
* veil init
|
|
6
|
-
* veil keypair
|
|
7
|
-
* veil
|
|
8
|
-
* veil
|
|
9
|
-
* veil
|
|
10
|
-
* veil
|
|
11
|
-
* veil
|
|
12
|
-
* veil
|
|
13
|
-
* veil
|
|
14
|
-
* veil
|
|
5
|
+
* veil init # Generate keypair
|
|
6
|
+
* veil keypair # Show keypair (JSON)
|
|
7
|
+
* veil status # Check config and service status
|
|
8
|
+
* veil register # Register on-chain
|
|
9
|
+
* veil deposit ETH 0.1 # Deposit ETH
|
|
10
|
+
* veil balance # Show all balances
|
|
11
|
+
* veil queue-balance # Show pending queue deposits
|
|
12
|
+
* veil private-balance # Show private balance
|
|
13
|
+
* veil withdraw ETH 0.1 0x... # Withdraw to public address
|
|
14
|
+
* veil transfer ETH 0.1 0x... # Transfer privately
|
|
15
|
+
* veil merge ETH 0.5 # Merge UTXOs (self-transfer)
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
18
|
import { Command } from 'commander';
|
|
@@ -25,6 +26,7 @@ import { createQueueBalanceCommand } from './commands/queue-balance.js';
|
|
|
25
26
|
import { createPrivateBalanceCommand } from './commands/private-balance.js';
|
|
26
27
|
import { createWithdrawCommand } from './commands/withdraw.js';
|
|
27
28
|
import { createTransferCommand, createMergeCommand } from './commands/transfer.js';
|
|
29
|
+
import { createStatusCommand } from './commands/status.js';
|
|
28
30
|
|
|
29
31
|
// Load environment variables
|
|
30
32
|
loadEnv();
|
|
@@ -47,6 +49,7 @@ program.addCommand(createPrivateBalanceCommand());
|
|
|
47
49
|
program.addCommand(createWithdrawCommand());
|
|
48
50
|
program.addCommand(createTransferCommand());
|
|
49
51
|
program.addCommand(createMergeCommand());
|
|
52
|
+
program.addCommand(createStatusCommand());
|
|
50
53
|
|
|
51
54
|
// Parse and execute
|
|
52
55
|
program.parse();
|