@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 CHANGED
@@ -1,8 +1,8 @@
1
1
  # @veil-cash/sdk
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@veil-cash/sdk.svg)](https://www.npmjs.com/package/@veil-cash/sdk)
4
- [![npm downloads](https://img.shields.io/npm/dm/@veil-cash/sdk.svg)](https://www.npmjs.com/package/@veil-cash/sdk)
5
- [![license](https://img.shields.io/npm/l/@veil-cash/sdk.svg)](https://github.com/veildotcash/veildotcash-sdk/blob/main/LICENSE)
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 [`skills/veil/SKILL.md`](./skills/veil/SKILL.md).
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 [`skills/veil/SKILL.md`](./skills/veil/SKILL.md) for the canonical CLI workflow.
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
- | Asset | Decimals | Token Contract |
45
- |-------|----------|---------------|
46
- | ETH | 18 | Native ETH (via WETH) |
47
- | USDC | 6 | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
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
- | File | Purpose |
224
- |------|---------|
225
- | `.env.veil` | Veil keypair (VEIL_KEY, DEPOSIT_KEY) - created by `veil init` |
226
- | `.env` | Wallet config (WALLET_KEY or SIGNER_ADDRESS, RPC_URL) - your existing config |
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
- | Variable | Description |
231
- |----------|-------------|
232
- | `VEIL_KEY` | Your Veil private key (for ZK proofs, withdrawals, transfers) |
233
- | `DEPOSIT_KEY` | Your Veil deposit key (public, for register/deposit) |
234
- | `WALLET_KEY` | Ethereum wallet private key (for signing transactions) |
235
- | `SIGNER_ADDRESS` | Ethereum address for unsigned/query flows when signing is handled externally |
236
- | `RPC_URL` | Base RPC URL (optional, defaults to public RPC) |
237
- | `RELAY_URL` | Override relay base URL for relayed CLI operations, subaccount deploy/sweep, and status checks |
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
- | Code | Description |
256
- |------|-------------|
257
- | `VEIL_KEY_MISSING` | VEIL_KEY not provided |
258
- | `WALLET_KEY_MISSING` | WALLET_KEY not provided |
259
- | `DEPOSIT_KEY_MISSING` | DEPOSIT_KEY not provided |
260
- | `CONFIG_CONFLICT` | Conflicting CLI env vars provided |
261
- | `INVALID_ADDRESS` | Invalid Ethereum address format |
262
- | `INVALID_SLOT` | Invalid subaccount slot format |
263
- | `INVALID_AMOUNT` | Invalid or below minimum amount |
264
- | `INSUFFICIENT_BALANCE` | Not enough ETH balance |
265
- | `USER_NOT_REGISTERED` | Recipient not registered in Veil |
266
- | `NO_UTXOS` | No unspent UTXOs available |
267
- | `RELAY_ERROR` | Error from relayer service |
268
- | `RPC_ERROR` | RPC/network error |
269
- | `CONTRACT_ERROR` | Smart contract reverted |
270
- | `UNKNOWN_ERROR` | Unexpected error |
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veil-cash/sdk",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "SDK and CLI for interacting with Veil Cash privacy pools - keypair generation, deposits, and status checking",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,10 +1,11 @@
1
1
  ---
2
2
  name: veil
3
- version: 0.5.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, or build unsigned transaction payloads
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 |
@@ -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
@@ -38,7 +38,7 @@ const program = new Command();
38
38
  program
39
39
  .name('veil')
40
40
  .description('CLI for Veil Cash privacy pools on Base')
41
- .version('0.6.0')
41
+ .version('0.6.1')
42
42
  .addHelpText('after', `
43
43
  Getting started:
44
44
  veil init
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 data = await response.json();
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, options.childDepositKey as `0x${string}`, options.childOwner],
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
- return postRelayJson<SubaccountRelayResult>(
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(