@veil-cash/sdk 0.6.0 → 0.6.1
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 +46 -37
- package/package.json +1 -1
- package/skills/veil/SKILL.md +74 -2
- package/skills/veil/reference.md +71 -2
- package/src/cli/commands/subaccount.ts +8 -7
- package/src/cli/index.ts +1 -1
- package/src/relay.ts +10 -1
- package/src/subaccount.ts +8 -3
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @veil-cash/sdk
|
|
2
2
|
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
3
|
+
[npm version](https://www.npmjs.com/package/@veil-cash/sdk)
|
|
4
|
+
[npm downloads](https://www.npmjs.com/package/@veil-cash/sdk)
|
|
5
|
+
[license](https://github.com/veildotcash/veildotcash-sdk/blob/main/LICENSE)
|
|
6
6
|
|
|
7
7
|
SDK and CLI for interacting with [Veil Cash](https://veil.cash) privacy pools on Base.
|
|
8
8
|
|
|
@@ -21,13 +21,14 @@ pnpm add @veil-cash/sdk
|
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
For global CLI access:
|
|
24
|
+
|
|
24
25
|
```bash
|
|
25
26
|
npm install -g @veil-cash/sdk
|
|
26
27
|
```
|
|
27
28
|
|
|
28
29
|
## Agent Skill
|
|
29
30
|
|
|
30
|
-
This repo includes a Veil agent skill at [
|
|
31
|
+
This repo includes a Veil agent skill at [skills/veil/SKILL.md](./skills/veil/SKILL.md).
|
|
31
32
|
|
|
32
33
|
Quick mapping:
|
|
33
34
|
|
|
@@ -35,16 +36,18 @@ Quick mapping:
|
|
|
35
36
|
- CLI binary: `veil`
|
|
36
37
|
- agent skill file: `skills/veil/SKILL.md`
|
|
37
38
|
|
|
38
|
-
If you are pointing an agent at this repo, send it to [
|
|
39
|
+
If you are pointing an agent at this repo, send it to [skills/veil/SKILL.md](./skills/veil/SKILL.md) for the canonical CLI workflow.
|
|
39
40
|
|
|
40
41
|
If you install the npm package, the published package also includes the `skills/` directory so the same skill can be discovered from the installed package contents.
|
|
41
42
|
|
|
42
43
|
## Supported Assets
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
|
47
|
-
|
|
|
45
|
+
|
|
46
|
+
| Asset | Decimals | Token Contract |
|
|
47
|
+
| ----- | -------- | -------------------------------------------- |
|
|
48
|
+
| ETH | 18 | Native ETH (via WETH) |
|
|
49
|
+
| USDC | 6 | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
|
|
50
|
+
|
|
48
51
|
|
|
49
52
|
## CLI Quick Start
|
|
50
53
|
|
|
@@ -220,21 +223,25 @@ veil subaccount status --slot 0 --json
|
|
|
220
223
|
|
|
221
224
|
The CLI uses two config files:
|
|
222
225
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
|
226
|
-
| `.env` |
|
|
226
|
+
|
|
227
|
+
| File | Purpose |
|
|
228
|
+
| ----------- | ---------------------------------------------------------------------------- |
|
|
229
|
+
| `.env.veil` | Veil keypair (VEIL_KEY, DEPOSIT_KEY) - created by `veil init` |
|
|
230
|
+
| `.env` | Wallet config (WALLET_KEY or SIGNER_ADDRESS, RPC_URL) - your existing config |
|
|
231
|
+
|
|
227
232
|
|
|
228
233
|
### Variables
|
|
229
234
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
|
233
|
-
| `
|
|
234
|
-
| `
|
|
235
|
-
| `
|
|
236
|
-
| `
|
|
237
|
-
| `
|
|
235
|
+
|
|
236
|
+
| Variable | Description |
|
|
237
|
+
| ---------------- | ---------------------------------------------------------------------------------------------- |
|
|
238
|
+
| `VEIL_KEY` | Your Veil private key (for ZK proofs, withdrawals, transfers) |
|
|
239
|
+
| `DEPOSIT_KEY` | Your Veil deposit key (public, for register/deposit) |
|
|
240
|
+
| `WALLET_KEY` | Ethereum wallet private key (for signing transactions) |
|
|
241
|
+
| `SIGNER_ADDRESS` | Ethereum address for unsigned/query flows when signing is handled externally |
|
|
242
|
+
| `RPC_URL` | Base RPC URL (optional, defaults to public RPC) |
|
|
243
|
+
| `RELAY_URL` | Override relay base URL for relayed CLI operations, subaccount deploy/sweep, and status checks |
|
|
244
|
+
|
|
238
245
|
|
|
239
246
|
`WALLET_KEY` and `SIGNER_ADDRESS` are mutually exclusive. Use `WALLET_KEY` for commands that sign transactions, and `SIGNER_ADDRESS` for address-only agent flows like `status`, `balance`, and `register --unsigned`.
|
|
240
247
|
|
|
@@ -252,22 +259,24 @@ Commands print human-readable success output by default. Errors are standardized
|
|
|
252
259
|
|
|
253
260
|
### Error Codes
|
|
254
261
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
|
258
|
-
| `
|
|
259
|
-
| `
|
|
260
|
-
| `
|
|
261
|
-
| `
|
|
262
|
-
| `
|
|
263
|
-
| `
|
|
264
|
-
| `
|
|
265
|
-
| `
|
|
266
|
-
| `
|
|
267
|
-
| `
|
|
268
|
-
| `
|
|
269
|
-
| `
|
|
270
|
-
| `
|
|
262
|
+
|
|
263
|
+
| Code | Description |
|
|
264
|
+
| ---------------------- | --------------------------------- |
|
|
265
|
+
| `VEIL_KEY_MISSING` | VEIL_KEY not provided |
|
|
266
|
+
| `WALLET_KEY_MISSING` | WALLET_KEY not provided |
|
|
267
|
+
| `DEPOSIT_KEY_MISSING` | DEPOSIT_KEY not provided |
|
|
268
|
+
| `CONFIG_CONFLICT` | Conflicting CLI env vars provided |
|
|
269
|
+
| `INVALID_ADDRESS` | Invalid Ethereum address format |
|
|
270
|
+
| `INVALID_SLOT` | Invalid subaccount slot format |
|
|
271
|
+
| `INVALID_AMOUNT` | Invalid or below minimum amount |
|
|
272
|
+
| `INSUFFICIENT_BALANCE` | Not enough ETH balance |
|
|
273
|
+
| `USER_NOT_REGISTERED` | Recipient not registered in Veil |
|
|
274
|
+
| `NO_UTXOS` | No unspent UTXOs available |
|
|
275
|
+
| `RELAY_ERROR` | Error from relayer service |
|
|
276
|
+
| `RPC_ERROR` | RPC/network error |
|
|
277
|
+
| `CONTRACT_ERROR` | Smart contract reverted |
|
|
278
|
+
| `UNKNOWN_ERROR` | Unexpected error |
|
|
279
|
+
|
|
271
280
|
|
|
272
281
|
## SDK Docs
|
|
273
282
|
|
package/package.json
CHANGED
package/skills/veil/SKILL.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: veil
|
|
3
|
-
version: 0.
|
|
3
|
+
version: 0.6.0
|
|
4
4
|
description: >
|
|
5
5
|
Veil CLI for private ETH and USDC transactions on Base. Use when the user wants
|
|
6
6
|
to deposit, withdraw, or transfer assets privately, check private balances,
|
|
7
|
-
manage Veil keypairs, register on-chain,
|
|
7
|
+
manage Veil keypairs, register on-chain, manage deterministic subaccounts
|
|
8
|
+
(forwarder deploy, sweep, recover), or build unsigned transaction payloads
|
|
8
9
|
for an external signer (e.g. Bankr). All operations target Base (chain ID 8453).
|
|
9
10
|
author: veildotcash
|
|
10
11
|
metadata:
|
|
@@ -27,11 +28,15 @@ triggers:
|
|
|
27
28
|
- pattern: veil withdraw
|
|
28
29
|
- pattern: veil transfer
|
|
29
30
|
- pattern: veil merge
|
|
31
|
+
- pattern: veil subaccount
|
|
30
32
|
- pattern: unsigned payload
|
|
31
33
|
- pattern: privacy pool
|
|
32
34
|
- pattern: deposit privately
|
|
33
35
|
- pattern: withdraw privately
|
|
34
36
|
- pattern: private transfer
|
|
37
|
+
- pattern: subaccount
|
|
38
|
+
- pattern: forwarder
|
|
39
|
+
- pattern: stealth deposit
|
|
35
40
|
---
|
|
36
41
|
|
|
37
42
|
# Veil CLI
|
|
@@ -164,6 +169,8 @@ What do you want to do?
|
|
|
164
169
|
|
|
|
165
170
|
+-- Withdraw / transfer / merge → Section 5
|
|
166
171
|
|
|
|
172
|
+
+-- Subaccounts (forwarders) → Section 5B
|
|
173
|
+
|
|
|
167
174
|
+-- Inspect or rotate keypair → veil keypair / veil init --force
|
|
168
175
|
```
|
|
169
176
|
|
|
@@ -188,6 +195,12 @@ What do you want to do?
|
|
|
188
195
|
| Withdraw | `veil withdraw ETH 0.05 0xRecipient` |
|
|
189
196
|
| Transfer privately | `veil transfer ETH 0.02 0xRecipient` |
|
|
190
197
|
| Merge UTXOs | `veil merge ETH 0.1` |
|
|
198
|
+
| Derive subaccount | `veil subaccount derive --slot 0` |
|
|
199
|
+
| Subaccount status | `veil subaccount status --slot 0` |
|
|
200
|
+
| Subaccount address | `veil subaccount address --slot 0` |
|
|
201
|
+
| Deploy forwarder | `veil subaccount deploy --slot 0` |
|
|
202
|
+
| Sweep forwarder | `veil subaccount sweep --slot 0 --asset eth` |
|
|
203
|
+
| Recover from forwarder | `veil subaccount recover --slot 0 --asset usdc --to 0xAddr --amount 25` |
|
|
191
204
|
|
|
192
205
|
---
|
|
193
206
|
|
|
@@ -315,6 +328,8 @@ Important:
|
|
|
315
328
|
|
|
316
329
|
Deposits treat the CLI amount as the **net** amount that lands in the pool.
|
|
317
330
|
The `0.3%` protocol fee is calculated on-chain and added automatically.
|
|
331
|
+
After submission, deposits go through screening / queue processing before they
|
|
332
|
+
are accepted into the private pool. This typically takes around `10-15 minutes`.
|
|
318
333
|
|
|
319
334
|
```bash
|
|
320
335
|
veil deposit ETH 0.1
|
|
@@ -369,6 +384,9 @@ Human-readable balance output includes:
|
|
|
369
384
|
- wallet public balances (`ETH`, `USDC`)
|
|
370
385
|
- queue and private balances
|
|
371
386
|
|
|
387
|
+
If a recent deposit still appears in queue balance, screening / queue processing
|
|
388
|
+
may still be in progress. Typical processing time is around `10-15 minutes`.
|
|
389
|
+
|
|
372
390
|
---
|
|
373
391
|
|
|
374
392
|
## 5. Private Actions
|
|
@@ -403,6 +421,59 @@ Note: withdraw proof generation is single-threaded for reliable CLI exit after s
|
|
|
403
421
|
|
|
404
422
|
---
|
|
405
423
|
|
|
424
|
+
## 5B. Subaccounts
|
|
425
|
+
|
|
426
|
+
Subaccounts are deterministic child slots derived from your main `VEIL_KEY`:
|
|
427
|
+
|
|
428
|
+
`root key → slot → child key → child deposit key → forwarder`
|
|
429
|
+
|
|
430
|
+
Base mainnet only. Slots are `0`–`2` (max 3 subaccounts). Deploy and sweep are
|
|
431
|
+
relay-backed (no `WALLET_KEY` needed). Recovery submits a direct on-chain
|
|
432
|
+
transaction and **requires `WALLET_KEY`** as a gas payer.
|
|
433
|
+
|
|
434
|
+
Status reports the forwarder wallet balances and queue state only, not private
|
|
435
|
+
pool attribution after queued funds are accepted.
|
|
436
|
+
|
|
437
|
+
### Derive and inspect
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
veil subaccount derive --slot 0 # Full slot metadata
|
|
441
|
+
veil subaccount derive --slot 0 --json
|
|
442
|
+
veil subaccount address --slot 0 # Just the forwarder address
|
|
443
|
+
veil subaccount status --slot 0 # Deployment, balances, queue state
|
|
444
|
+
veil subaccount status --slot 0 --json
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Deploy and sweep (relay-backed)
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
veil subaccount deploy --slot 0 # Deploy the forwarder contract
|
|
451
|
+
veil subaccount deploy --slot 0 --json
|
|
452
|
+
veil subaccount sweep --slot 0 --asset eth # Sweep ETH into the pool
|
|
453
|
+
veil subaccount sweep --slot 0 --asset usdc # Sweep USDC into the pool
|
|
454
|
+
veil subaccount sweep --slot 0 --asset eth --json
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Recover (direct on-chain — requires WALLET_KEY)
|
|
458
|
+
|
|
459
|
+
Recovery is for assets still sitting on the forwarder after refund or rejection.
|
|
460
|
+
It signs a forwarder withdraw with the child key and submits the transaction
|
|
461
|
+
using `WALLET_KEY` as the gas payer.
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
veil subaccount recover --slot 0 --asset usdc --to 0xRecipient --amount 25
|
|
465
|
+
veil subaccount recover --slot 0 --asset eth --to 0xRecipient --amount 0.05 --json
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Important:
|
|
469
|
+
|
|
470
|
+
- `--asset` is `eth` or `usdc` (case-insensitive in the CLI)
|
|
471
|
+
- `--slot` is `0`–`2`
|
|
472
|
+
- Deploy and sweep only need `VEIL_KEY`
|
|
473
|
+
- Recover needs both `VEIL_KEY` and `WALLET_KEY`
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
406
477
|
## 6. Unsigned Payloads
|
|
407
478
|
|
|
408
479
|
`--unsigned` is for external signer workflows. The CLI emits a signer-compatible
|
|
@@ -504,6 +575,7 @@ All CLI errors output JSON with a standardised `errorCode`:
|
|
|
504
575
|
| `DEPOSIT_KEY_MISSING` | `DEPOSIT_KEY` missing from `.env.veil` | Re-run `veil init` to regenerate |
|
|
505
576
|
| `USER_NOT_REGISTERED` | Transfer recipient has no deposit key registered on-chain | Recipient must run `veil register` first |
|
|
506
577
|
| `INVALID_AMOUNT` | Amount below minimum or invalid format | ETH min: `0.01`, USDC min: `10` |
|
|
578
|
+
| `INVALID_SLOT` | Invalid subaccount slot | Slot must be `0`–`2` (non-negative integer) |
|
|
507
579
|
| `INSUFFICIENT_BALANCE` | Not enough ETH for gas | Top up Base ETH balance |
|
|
508
580
|
| `RPC_ERROR` | Network or RPC failure | Check `RPC_URL` env var or retry |
|
|
509
581
|
| `RELAY_ERROR` | Relayer rejected the proof | Check relay health with `veil status`; retry |
|
package/skills/veil/reference.md
CHANGED
|
@@ -143,6 +143,63 @@ const priv = await getPrivateBalance({
|
|
|
143
143
|
});
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
+
### Subaccounts
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import {
|
|
150
|
+
deriveSubaccountSlot,
|
|
151
|
+
getSubaccountStatus,
|
|
152
|
+
deploySubaccountForwarder,
|
|
153
|
+
sweepSubaccountForwarder,
|
|
154
|
+
buildSubaccountRecoveryTx,
|
|
155
|
+
isSubaccountForwarderDeployed,
|
|
156
|
+
MAX_SUBACCOUNT_SLOTS,
|
|
157
|
+
} from '@veil-cash/sdk';
|
|
158
|
+
|
|
159
|
+
// Derive slot metadata (child key, salt, predicted forwarder address)
|
|
160
|
+
const slot = await deriveSubaccountSlot({
|
|
161
|
+
rootPrivateKey: '0xVEIL_KEY',
|
|
162
|
+
slot: 0, // 0–2
|
|
163
|
+
});
|
|
164
|
+
// slot.forwarderAddress, slot.childOwner, slot.childDepositKey, slot.salt
|
|
165
|
+
|
|
166
|
+
// Check deployment status
|
|
167
|
+
const deployed = await isSubaccountForwarderDeployed({
|
|
168
|
+
forwarderAddress: slot.forwarderAddress,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Full status (deployment, balances, queue state)
|
|
172
|
+
const status = await getSubaccountStatus({
|
|
173
|
+
rootPrivateKey: '0xVEIL_KEY',
|
|
174
|
+
slot: 0,
|
|
175
|
+
});
|
|
176
|
+
// status.deployed, status.balances.eth, status.balances.usdc, status.queues
|
|
177
|
+
|
|
178
|
+
// Deploy forwarder (relay-backed, no WALLET_KEY needed)
|
|
179
|
+
const deployResult = await deploySubaccountForwarder({
|
|
180
|
+
rootPrivateKey: '0xVEIL_KEY',
|
|
181
|
+
slot: 0,
|
|
182
|
+
});
|
|
183
|
+
// deployResult.transactionHash, deployResult.slot.forwarderAddress
|
|
184
|
+
|
|
185
|
+
// Sweep assets into pool (relay-backed)
|
|
186
|
+
const sweepResult = await sweepSubaccountForwarder({
|
|
187
|
+
forwarderAddress: slot.forwarderAddress,
|
|
188
|
+
asset: 'eth', // 'eth' | 'usdc'
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Build recovery transaction (for assets stuck on forwarder)
|
|
192
|
+
const recovery = await buildSubaccountRecoveryTx({
|
|
193
|
+
rootPrivateKey: '0xVEIL_KEY',
|
|
194
|
+
slot: 0,
|
|
195
|
+
asset: 'usdc',
|
|
196
|
+
to: '0xRecipient',
|
|
197
|
+
amount: '25',
|
|
198
|
+
});
|
|
199
|
+
// recovery.transaction — submit with your wallet client
|
|
200
|
+
// recovery.forwarderAddress, recovery.signature, recovery.nonce, recovery.deadline
|
|
201
|
+
```
|
|
202
|
+
|
|
146
203
|
---
|
|
147
204
|
|
|
148
205
|
## CLI quick reference
|
|
@@ -158,7 +215,7 @@ Install globally: `npm install -g @veil-cash/sdk`
|
|
|
158
215
|
| `WALLET_KEY` | Ethereum wallet private key (for signing) |
|
|
159
216
|
| `SIGNER_ADDRESS` | Ethereum address for unsigned/query flows when signing is external |
|
|
160
217
|
| `RPC_URL` | Base RPC URL (optional, defaults to public RPC) |
|
|
161
|
-
| `RELAY_URL` | Override relay base URL for relayed CLI operations |
|
|
218
|
+
| `RELAY_URL` | Override relay base URL for relayed CLI operations, subaccount deploy/sweep, and status checks |
|
|
162
219
|
|
|
163
220
|
`WALLET_KEY` and `SIGNER_ADDRESS` are mutually exclusive. Use `SIGNER_ADDRESS` only for address-only CLI flows.
|
|
164
221
|
|
|
@@ -195,6 +252,18 @@ veil balance queue --pool eth # Queue-only balance
|
|
|
195
252
|
veil balance queue --address 0x... --json # Queue balance for explicit address
|
|
196
253
|
veil balance private --pool eth # Private-only balance
|
|
197
254
|
veil balance private --json # Private balance as JSON
|
|
255
|
+
|
|
256
|
+
veil subaccount derive --slot 0 # Derive slot metadata
|
|
257
|
+
veil subaccount derive --slot 0 --json # Derive as JSON
|
|
258
|
+
veil subaccount address --slot 0 # Print forwarder address
|
|
259
|
+
veil subaccount status --slot 0 # Deployment, balances, queue state
|
|
260
|
+
veil subaccount status --slot 0 --json # Status as JSON
|
|
261
|
+
veil subaccount deploy --slot 0 # Deploy forwarder (relay-backed)
|
|
262
|
+
veil subaccount deploy --slot 0 --json # Deploy as JSON
|
|
263
|
+
veil subaccount sweep --slot 0 --asset eth # Sweep ETH into pool (relay-backed)
|
|
264
|
+
veil subaccount sweep --slot 0 --asset usdc --json # Sweep USDC as JSON
|
|
265
|
+
veil subaccount recover --slot 0 --asset usdc --to 0x... --amount 25 # Recover assets (needs WALLET_KEY)
|
|
266
|
+
veil subaccount recover --slot 0 --asset eth --to 0x... --amount 0.05 --json
|
|
198
267
|
```
|
|
199
268
|
|
|
200
269
|
### Error format
|
|
@@ -210,7 +279,7 @@ All CLI errors output JSON with a standardized `errorCode`:
|
|
|
210
279
|
```
|
|
211
280
|
|
|
212
281
|
Common codes: `VEIL_KEY_MISSING`, `WALLET_KEY_MISSING`, `DEPOSIT_KEY_MISSING`,
|
|
213
|
-
`CONFIG_CONFLICT`, `INVALID_AMOUNT`, `INSUFFICIENT_BALANCE`, `CONTRACT_ERROR`, `RPC_ERROR`.
|
|
282
|
+
`CONFIG_CONFLICT`, `INVALID_AMOUNT`, `INVALID_SLOT`, `INSUFFICIENT_BALANCE`, `CONTRACT_ERROR`, `RPC_ERROR`.
|
|
214
283
|
|
|
215
284
|
---
|
|
216
285
|
|
|
@@ -178,11 +178,6 @@ Examples:
|
|
|
178
178
|
.action(async (options) => {
|
|
179
179
|
try {
|
|
180
180
|
const rootPrivateKey = getRequiredVeilKey();
|
|
181
|
-
const slot = await deriveSubaccountSlot({
|
|
182
|
-
rootPrivateKey,
|
|
183
|
-
slot: options.slot,
|
|
184
|
-
rpcUrl: process.env.RPC_URL,
|
|
185
|
-
});
|
|
186
181
|
const result = await deploySubaccountForwarder({
|
|
187
182
|
rootPrivateKey,
|
|
188
183
|
slot: options.slot,
|
|
@@ -193,7 +188,7 @@ Examples:
|
|
|
193
188
|
const output = {
|
|
194
189
|
...result,
|
|
195
190
|
slot: options.slot,
|
|
196
|
-
forwarderAddress: slot.forwarderAddress,
|
|
191
|
+
forwarderAddress: result.slot.forwarderAddress,
|
|
197
192
|
};
|
|
198
193
|
|
|
199
194
|
if (options.json) {
|
|
@@ -204,7 +199,7 @@ Examples:
|
|
|
204
199
|
printHeader('Subaccount Deploy Submitted');
|
|
205
200
|
printFields([
|
|
206
201
|
{ label: 'Slot', value: options.slot },
|
|
207
|
-
{ label: 'Forwarder', value: slot.forwarderAddress },
|
|
202
|
+
{ label: 'Forwarder', value: result.slot.forwarderAddress },
|
|
208
203
|
{ label: 'Transaction', value: txUrl(result.transactionHash) },
|
|
209
204
|
{ label: 'Block', value: result.blockNumber },
|
|
210
205
|
]);
|
|
@@ -274,6 +269,12 @@ Examples:
|
|
|
274
269
|
if (!isAddress(options.to)) {
|
|
275
270
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, `Invalid recipient address: ${options.to}`);
|
|
276
271
|
}
|
|
272
|
+
if (!process.env.WALLET_KEY) {
|
|
273
|
+
throw new CLIError(
|
|
274
|
+
ErrorCode.WALLET_KEY_MISSING,
|
|
275
|
+
'WALLET_KEY required for recovery. Recovery submits a transaction on-chain and needs a gas payer.',
|
|
276
|
+
);
|
|
277
|
+
}
|
|
277
278
|
const config = getConfig({});
|
|
278
279
|
const recovery = await buildSubaccountRecoveryTx({
|
|
279
280
|
rootPrivateKey,
|
package/src/cli/index.ts
CHANGED
package/src/relay.ts
CHANGED
|
@@ -64,7 +64,16 @@ export async function postRelayJson<T>(
|
|
|
64
64
|
body: JSON.stringify(body),
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
const
|
|
67
|
+
const text = await response.text();
|
|
68
|
+
let data: unknown;
|
|
69
|
+
try {
|
|
70
|
+
data = JSON.parse(text);
|
|
71
|
+
} catch {
|
|
72
|
+
throw new RelayError(
|
|
73
|
+
`Relay returned non-JSON response (HTTP ${response.status})`,
|
|
74
|
+
response.status,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
68
77
|
|
|
69
78
|
if (!response.ok) {
|
|
70
79
|
const errorData = data as RelayErrorResponse;
|
package/src/subaccount.ts
CHANGED
|
@@ -134,11 +134,14 @@ export async function predictSubaccountForwarder(options: {
|
|
|
134
134
|
rpcUrl?: string;
|
|
135
135
|
}): Promise<`0x${string}`> {
|
|
136
136
|
const publicClient = createBaseClient(options.rpcUrl);
|
|
137
|
+
const depositKeyBytes = options.childDepositKey.startsWith('0x')
|
|
138
|
+
? options.childDepositKey
|
|
139
|
+
: `0x${options.childDepositKey}`;
|
|
137
140
|
return publicClient.readContract({
|
|
138
141
|
abi: FORWARDER_FACTORY_ABI,
|
|
139
142
|
address: getForwarderFactoryAddress(),
|
|
140
143
|
functionName: 'computeAddress',
|
|
141
|
-
args: [options.salt,
|
|
144
|
+
args: [options.salt, depositKeyBytes as `0x${string}`, options.childOwner],
|
|
142
145
|
}) as Promise<`0x${string}`>;
|
|
143
146
|
}
|
|
144
147
|
|
|
@@ -183,14 +186,14 @@ export async function isSubaccountForwarderDeployed(options: {
|
|
|
183
186
|
|
|
184
187
|
export async function deploySubaccountForwarder(
|
|
185
188
|
options: SubaccountDeployRequest,
|
|
186
|
-
): Promise<SubaccountRelayResult> {
|
|
189
|
+
): Promise<SubaccountRelayResult & { slot: SubaccountSlot }> {
|
|
187
190
|
const slot = await deriveSubaccountSlot({
|
|
188
191
|
rootPrivateKey: options.rootPrivateKey,
|
|
189
192
|
slot: options.slot,
|
|
190
193
|
rpcUrl: options.rpcUrl,
|
|
191
194
|
});
|
|
192
195
|
|
|
193
|
-
|
|
196
|
+
const result = await postRelayJson<SubaccountRelayResult>(
|
|
194
197
|
'/stealth/deploy',
|
|
195
198
|
{
|
|
196
199
|
salt: slot.salt,
|
|
@@ -200,6 +203,8 @@ export async function deploySubaccountForwarder(
|
|
|
200
203
|
},
|
|
201
204
|
options.relayUrl,
|
|
202
205
|
);
|
|
206
|
+
|
|
207
|
+
return { ...result, slot };
|
|
203
208
|
}
|
|
204
209
|
|
|
205
210
|
export async function sweepSubaccountForwarder(
|