@veil-cash/sdk 0.4.0 → 0.6.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/SDK.md ADDED
@@ -0,0 +1,365 @@
1
+ # SDK Guide
2
+
3
+ This package ships both a CLI and a TypeScript SDK.
4
+
5
+ If you are looking for the CLI first-run flow, go back to the main [README](./README.md).
6
+
7
+ ## SDK Quick Start
8
+
9
+ ```typescript
10
+ import {
11
+ Keypair, buildRegisterTx, buildDepositETHTx,
12
+ buildDepositUSDCTx, buildApproveUSDCTx,
13
+ withdraw, transfer, getSubaccountStatus,
14
+ } from '@veil-cash/sdk';
15
+ import { createWalletClient, http } from 'viem';
16
+ import { base } from 'viem/chains';
17
+ import { privateKeyToAccount } from 'viem/accounts';
18
+
19
+ // 1. Generate a Veil keypair (do this once, save securely!)
20
+ const keypair = new Keypair();
21
+ console.log('Veil Private Key:', keypair.privkey); // SAVE THIS!
22
+ console.log('Deposit Key:', keypair.depositKey()); // Register this on-chain
23
+
24
+ // 2. Setup your Ethereum wallet
25
+ const account = privateKeyToAccount('0x...');
26
+ const client = createWalletClient({
27
+ account,
28
+ chain: base,
29
+ transport: http(),
30
+ });
31
+
32
+ // 3. Register your deposit key (one-time)
33
+ const registerTx = buildRegisterTx(keypair.depositKey(), account.address);
34
+ await client.sendTransaction(registerTx);
35
+
36
+ // 4. Deposit ETH
37
+ const depositTx = buildDepositETHTx({
38
+ depositKey: keypair.depositKey(),
39
+ amount: '0.1',
40
+ });
41
+ await client.sendTransaction({ ...depositTx, value: depositTx.value });
42
+
43
+ // 4b. Deposit USDC (approve first)
44
+ const approveTx = buildApproveUSDCTx({ amount: '100' });
45
+ await client.sendTransaction(approveTx);
46
+ const usdcTx = buildDepositUSDCTx({
47
+ depositKey: keypair.depositKey(),
48
+ amount: '100',
49
+ });
50
+ await client.sendTransaction(usdcTx);
51
+
52
+ // 5. Withdraw (sent via relayer, no wallet signing needed)
53
+ const withdrawResult = await withdraw({
54
+ amount: '0.05',
55
+ recipient: '0xRecipientAddress',
56
+ keypair,
57
+ pool: 'eth', // 'eth' | 'usdc' (default: 'eth')
58
+ });
59
+
60
+ // 6. Transfer privately
61
+ const transferResult = await transfer({
62
+ amount: '0.02',
63
+ recipientAddress: '0xRecipientAddress',
64
+ senderKeypair: keypair,
65
+ pool: 'eth', // 'eth' | 'usdc' (default: 'eth')
66
+ });
67
+
68
+ // 7. Inspect a deterministic subaccount slot
69
+ const subaccount = await getSubaccountStatus({
70
+ rootPrivateKey: keypair.privkey as `0x${string}`,
71
+ slot: 0,
72
+ });
73
+ console.log(subaccount.slot.forwarderAddress);
74
+
75
+ ```
76
+
77
+ ## SDK API Reference
78
+
79
+ ### Keypair
80
+
81
+ ```typescript
82
+ import { Keypair, VEIL_SIGNED_MESSAGE } from '@veil-cash/sdk';
83
+ import type { MessageSigner } from '@veil-cash/sdk';
84
+
85
+ // Generate random keypair
86
+ const keypair = new Keypair();
87
+
88
+ // Restore from saved Veil private key
89
+ const restored = new Keypair(savedVeilKey);
90
+
91
+ // Derive from wallet key (same keypair as frontend login)
92
+ const derived = await Keypair.fromWalletKey('0xYOUR_WALLET_KEY');
93
+
94
+ // Derive from a raw EIP-191 signature
95
+ const fromSig = Keypair.fromSignature('0xSIGNATURE...');
96
+
97
+ // Derive from any external signer (agent framework, MPC, custodial, etc.)
98
+ const fromSigner = await Keypair.fromSigner(async (message) => {
99
+ // Sign `message` using any personal_sign provider and return the signature
100
+ return await mySigningService.personalSign(message);
101
+ });
102
+
103
+ // Get deposit key (for registration)
104
+ keypair.depositKey(); // '0x...' (130 hex chars)
105
+
106
+ // Veil private key (store securely!)
107
+ keypair.privkey; // '0x...'
108
+ ```
109
+
110
+ ### Transaction Builders
111
+
112
+ ```typescript
113
+ import {
114
+ buildRegisterTx, buildChangeDepositKeyTx, buildDepositETHTx, buildDepositTx,
115
+ buildDepositUSDCTx, buildApproveUSDCTx,
116
+ } from '@veil-cash/sdk';
117
+
118
+ // Register deposit key (first time)
119
+ const registerTx = buildRegisterTx(depositKey, ownerAddress);
120
+ // -> { to: '0x...', data: '0x...' }
121
+
122
+ // Change deposit key (must already be registered)
123
+ const changeTx = buildChangeDepositKeyTx(newDepositKey, ownerAddress);
124
+ // -> { to: '0x...', data: '0x...' }
125
+
126
+ // Deposit ETH
127
+ const depositTx = buildDepositETHTx({
128
+ depositKey: keypair.depositKey(),
129
+ amount: '0.1',
130
+ });
131
+ // -> { to: '0x...', data: '0x...', value: 100000000000000000n }
132
+
133
+ // Deposit USDC (approve + deposit)
134
+ const approveUsdcTx = buildApproveUSDCTx({ amount: '100' });
135
+ const depositUsdcTx = buildDepositUSDCTx({
136
+ depositKey: keypair.depositKey(),
137
+ amount: '100',
138
+ });
139
+
140
+ // Generic builder (routes by token)
141
+ const tx = buildDepositTx({
142
+ depositKey: keypair.depositKey(),
143
+ amount: '0.1',
144
+ token: 'ETH', // 'ETH' | 'USDC'
145
+ });
146
+ ```
147
+
148
+ ### Withdraw & Transfer
149
+
150
+ All withdraw, transfer, and merge functions accept an optional `pool` parameter (`'eth'` | `'usdc'`), defaulting to `'eth'`.
151
+
152
+ ```typescript
153
+ import { withdraw, transfer, mergeUtxos } from '@veil-cash/sdk';
154
+
155
+ // Withdraw ETH to public address
156
+ const withdrawResult = await withdraw({
157
+ amount: '0.05',
158
+ recipient: '0xRecipientAddress',
159
+ keypair,
160
+ pool: 'eth', // default
161
+ onProgress: (stage, detail) => console.log(stage, detail),
162
+ });
163
+
164
+ // Withdraw USDC
165
+ const withdrawUsdc = await withdraw({
166
+ amount: '50',
167
+ recipient: '0xRecipientAddress',
168
+ keypair,
169
+ pool: 'usdc',
170
+ });
171
+
172
+ // Merge UTXOs (consolidate small balances)
173
+ const mergeResult = await mergeUtxos({
174
+ amount: '0.1',
175
+ keypair,
176
+ pool: 'eth',
177
+ });
178
+ ```
179
+
180
+ ### Balance Queries
181
+
182
+ Balance functions accept an optional `pool` parameter (`'eth'` | `'usdc'`), defaulting to `'eth'`.
183
+
184
+ ```typescript
185
+ import { getQueueBalance, getPrivateBalance } from '@veil-cash/sdk';
186
+
187
+ // Check ETH queue balance (pending deposits)
188
+ const queueBalance = await getQueueBalance({
189
+ address: '0x...',
190
+ pool: 'eth', // default
191
+ });
192
+
193
+ // Check USDC private balance (requires keypair)
194
+ const privateBalance = await getPrivateBalance({
195
+ keypair,
196
+ pool: 'usdc',
197
+ });
198
+ ```
199
+
200
+ ### Subaccounts
201
+
202
+ Subaccounts are deterministic child slots derived from your main Veil key:
203
+
204
+ `root key -> slot -> child key -> child deposit key -> forwarder`
205
+
206
+ Base mainnet only. Status shows the forwarder wallet and queue state only. Deploy and sweep are relay-backed. Recovery signs a forwarder withdraw request with the child key and returns a direct transaction for your gas payer to submit.
207
+
208
+ ```typescript
209
+ import {
210
+ deriveSubaccountSlot,
211
+ getSubaccountStatus,
212
+ deploySubaccountForwarder,
213
+ sweepSubaccountForwarder,
214
+ buildSubaccountRecoveryTx,
215
+ } from '@veil-cash/sdk';
216
+
217
+ const slot = await deriveSubaccountSlot({
218
+ rootPrivateKey: veilKey,
219
+ slot: 0,
220
+ });
221
+
222
+ const status = await getSubaccountStatus({
223
+ rootPrivateKey: veilKey,
224
+ slot: 0,
225
+ });
226
+
227
+ await deploySubaccountForwarder({
228
+ rootPrivateKey: veilKey,
229
+ slot: 0,
230
+ });
231
+
232
+ await sweepSubaccountForwarder({
233
+ forwarderAddress: slot.forwarderAddress,
234
+ asset: 'eth',
235
+ });
236
+
237
+ const recovery = await buildSubaccountRecoveryTx({
238
+ rootPrivateKey: veilKey,
239
+ slot: 0,
240
+ asset: 'usdc',
241
+ to: '0xRecipientAddress',
242
+ amount: '25',
243
+ });
244
+ // Send recovery.transaction with your wallet client
245
+ ```
246
+
247
+ ### Addresses
248
+
249
+ ```typescript
250
+ import { getAddresses, getPoolAddress, getQueueAddress } from '@veil-cash/sdk';
251
+
252
+ const addresses = getAddresses();
253
+ console.log(addresses.entry); // Entry contract
254
+ console.log(addresses.ethPool); // ETH pool
255
+ console.log(addresses.usdcPool); // USDC pool
256
+
257
+ // Helper functions to resolve by pool name
258
+ console.log(getPoolAddress('eth')); // ETH pool address
259
+ console.log(getPoolAddress('usdc')); // USDC pool address
260
+ ```
261
+
262
+ ## For AI Agents
263
+
264
+ This SDK is designed to work with AI agent frameworks and external signers.
265
+
266
+ ### Non-Interactive CLI
267
+
268
+ Human-readable output is the CLI default. Use `--json` for machine-readable responses and `--unsigned` for transaction payload generation:
269
+
270
+ ```bash
271
+ # Generate keypair as JSON (no prompts, no file save)
272
+ veil init --json
273
+
274
+ # Get unsigned transaction payloads for agent signing
275
+ SIGNER_ADDRESS=0x... veil register --unsigned
276
+ veil deposit ETH 0.1 --unsigned
277
+ veil deposit USDC 100 --unsigned # Outputs approve + deposit payloads
278
+
279
+ # Request machine-readable status or balances
280
+ veil balance --json
281
+ veil balance --pool usdc --json
282
+ veil withdraw ETH 0.05 0xRecipient --json
283
+ ```
284
+
285
+ `SIGNER_ADDRESS` can be used for address-only agent flows such as `veil status`, `veil balance`, and `veil register --unsigned` when the signer manages the wallet externally. `WALLET_KEY` and `SIGNER_ADDRESS` are mutually exclusive, and signed commands still require `WALLET_KEY`.
286
+
287
+ `veil status` shows a **Signing** row that reflects the active mode (`local (WALLET_KEY)`, `external (SIGNER_ADDRESS)`, or `not configured`), plus public ETH balance when it can be resolved.
288
+
289
+ ### Bankr Integration
290
+
291
+ #### Keypair Derivation via Bankr Sign API
292
+
293
+ Use `Keypair.fromSigner()` with Bankr's `POST /agent/sign` endpoint to derive the same keypair as the frontend:
294
+
295
+ ```typescript
296
+ import { Keypair } from '@veil-cash/sdk';
297
+
298
+ const keypair = await Keypair.fromSigner(async (message) => {
299
+ const res = await fetch('https://api.bankr.bot/agent/sign', {
300
+ method: 'POST',
301
+ headers: { 'X-API-Key': BANKR_API_KEY, 'Content-Type': 'application/json' },
302
+ body: JSON.stringify({ signatureType: 'personal_sign', message }),
303
+ });
304
+ return (await res.json()).signature;
305
+ });
306
+ ```
307
+
308
+ Or via CLI (two-step):
309
+
310
+ ```bash
311
+ # 1. Get signature from Bankr sign API
312
+ SIG=$(curl -s -X POST "https://api.bankr.bot/agent/sign" \
313
+ -H "X-API-Key: $BANKR_API_KEY" \
314
+ -H "Content-Type: application/json" \
315
+ -d "{\"signatureType\":\"personal_sign\",\"message\":\"$(node -e "const{VEIL_SIGNED_MESSAGE}=require('@veil-cash/sdk');console.log(VEIL_SIGNED_MESSAGE)")\"}" \
316
+ | jq -r '.signature')
317
+
318
+ # 2. Derive keypair from signature
319
+ veil init --signature $SIG
320
+ ```
321
+
322
+ #### Unsigned Transaction Payloads
323
+
324
+ Use `--unsigned` to get signer-compatible transaction payloads:
325
+
326
+ ```bash
327
+ SIGNER_ADDRESS=0x... veil register --unsigned
328
+ SIGNER_ADDRESS=0x... veil register --unsigned --force
329
+ veil deposit ETH 0.1 --unsigned
330
+ # {"to":"0x...","data":"0x...","value":"100000000000000000","chainId":8453}
331
+ ```
332
+
333
+ The `--unsigned` flag outputs a standard `{to, data, value, chainId}` payload compatible with any signer that accepts arbitrary transactions.
334
+ When `SIGNER_ADDRESS` is set, `veil register --unsigned` no longer requires the `--address` flag.
335
+ For `veil register --unsigned --force`, the CLI checks on-chain registration state first and emits `changeDepositKey` only when the address is already registered; otherwise it falls back to `register`.
336
+
337
+ ### Programmatic SDK Usage
338
+
339
+ ```typescript
340
+ import { Keypair, buildDepositETHTx, buildDepositTx, withdraw } from '@veil-cash/sdk';
341
+
342
+ // For deposits: build transaction, let agent sign via your signer
343
+ const keypair = new Keypair(veilKey);
344
+ const tx = buildDepositETHTx({
345
+ depositKey: keypair.depositKey(),
346
+ amount: '0.1',
347
+ });
348
+ // -> { to, data, value } - pass to your signer
349
+
350
+ // Generic builder works for any asset
351
+ const usdcTx = buildDepositTx({
352
+ depositKey: keypair.depositKey(),
353
+ amount: '100',
354
+ token: 'USDC',
355
+ });
356
+
357
+ // For withdrawals: SDK handles ZK proofs, submits to relayer
358
+ const result = await withdraw({
359
+ amount: '0.05',
360
+ recipient: '0xRecipient',
361
+ keypair,
362
+ pool: 'eth', // 'eth' | 'usdc'
363
+ });
364
+ // -> { success, transactionHash, blockNumber }
365
+ ```