@veil-cash/sdk 0.6.4 → 0.7.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 CHANGED
@@ -8,6 +8,8 @@ SDK and CLI for interacting with [Veil Cash](https://veil.cash) privacy pools on
8
8
 
9
9
  Generate keypairs, register, deposit, withdraw, transfer, and merge ETH and USDC privately.
10
10
 
11
+ `0.7.0` adds Coinbase-compatible x402 payments from private USDC balances via deterministic fresh payer EOAs.
12
+
11
13
  `0.6.2` adds `mergeSubaccount` — transfer a subaccount's private pool balance back to the main wallet via a ZK proof. Also adds `veil subaccount merge` CLI command.
12
14
 
13
15
  `0.6.0` adds SDK-first subaccount support for deterministic slot derivation, forwarder status, relay-backed deploy/sweep, and direct recovery.
@@ -91,7 +93,10 @@ veil subaccount sweep --slot 0 --asset eth
91
93
  veil subaccount merge --slot 0 --pool eth
92
94
  veil subaccount recover --slot 0 --asset usdc --to 0xRecipientAddress --amount 25
93
95
 
94
- # 9. Use JSON or unsigned modes when you need automation
96
+ # 9. Pay an x402 resource from private USDC in application code
97
+ # See SDK.md for payX402Resource().
98
+
99
+ # 10. Use JSON or unsigned modes when you need automation
95
100
  veil status --json
96
101
  veil deposit ETH 0.1 --unsigned --address 0x...
97
102
  veil subaccount status --slot 0 --json
@@ -142,11 +147,11 @@ SIGNER_ADDRESS=0x... veil register --unsigned
142
147
 
143
148
  In `--unsigned` mode, `--address` is optional when `SIGNER_ADDRESS` is set. `veil register --force` checks on-chain state first and emits a `changeDepositKey` payload only if the address is already registered; otherwise it emits a normal `register` payload.
144
149
 
145
- Deposit ETH or USDC into Veil. The amount you specify is the **net** amount that arrives in your Veil balance. A 0.3% protocol fee is normally added on top, but each address gets free daily deposits (fee waived). The CLI checks automatically:
150
+ Deposit ETH or USDC into Veil. The amount you specify is the **net** amount that arrives in your Veil balance. A 0.3% protocol fee is added on top:
146
151
 
147
152
  ```bash
148
- veil deposit ETH 0.1 # 0.1 ETH lands in pool (free or ~0.1003 ETH sent)
149
- veil deposit USDC 100 # 100 USDC lands in pool (free or ~100.30 USDC sent)
153
+ veil deposit ETH 0.1 # 0.1 ETH lands in pool (~0.1003 ETH sent)
154
+ veil deposit USDC 100 # 100 USDC lands in pool (~100.30 USDC sent)
150
155
  veil deposit ETH 0.1 --json
151
156
  veil deposit ETH 0.1 --unsigned --address 0x...
152
157
  SIGNER_ADDRESS=0x... veil deposit ETH 0.1 --unsigned
@@ -205,6 +210,43 @@ veil merge USDC 100
205
210
  veil merge ETH 0.1 --json
206
211
  ```
207
212
 
213
+ Pay a Coinbase-compatible x402 resource from private USDC:
214
+
215
+ ```typescript
216
+ import { payX402Resource } from '@veil-cash/sdk';
217
+
218
+ const result = await payX402Resource({
219
+ url: 'https://merchant.example/paid-resource',
220
+ rootPrivateKey: process.env.VEIL_KEY as `0x${string}`,
221
+ payerIndex: 0n,
222
+ maxPayment: '0.10', // reject if the resource demands more than 0.10 USDC
223
+ relayUrl: process.env.X402_RELAY_URL,
224
+ rpcUrl: process.env.RPC_URL,
225
+ });
226
+
227
+ console.log(result.response.status, result.payerAddress);
228
+ ```
229
+
230
+ The helper withdraws the exact x402 amount to a deterministic fresh payer EOA,
231
+ then signs a standard x402 v2 Base USDC `exact` payment from that EOA. Use a
232
+ new `payerIndex` per payment. Pass `maxPayment` (a decimal USDC string) to cap
233
+ exposure; the payment is rejected before any funds move if the requirement
234
+ exceeds the cap. The withdrawal and payment legs are public and can be correlated
235
+ by amount and timing, but the source private balance remains hidden.
236
+
237
+ Use `quoteX402Resource({ url, rpcUrl, maxPayment, init })` to probe a resource
238
+ for its price and payment requirement without funding a payer or paying. It
239
+ returns the parsed requirement for a supported `402` or the raw status/body
240
+ otherwise.
241
+
242
+ If a payment is funded but delivery fails, the USDC stays on the payer EOA. Retry
243
+ with `reuseExistingBalance: true` and the same `payerIndex` to pay from that
244
+ balance without a second withdrawal; it throws if the balance is insufficient.
245
+
246
+ To surface funds left on a payer after a failed payment, use
247
+ `getX402PayerBalances({ rootPrivateKey, startIndex, count, nonZeroOnly })`, which
248
+ returns the Base USDC balance of each derived payer EOA. It is read-only.
249
+
208
250
  ### Subaccounts
209
251
 
210
252
  Subaccounts are deterministic child slots derived from your main `VEIL_KEY`:
@@ -297,7 +339,7 @@ The CLI is the main entrypoint for most users. If you are integrating Veil progr
297
339
  2. **Derive Keypair**: Run `veil init` to derive and save your Veil keypair
298
340
  3. **Register**: Run `veil register` to link your deposit key on-chain (one-time)
299
341
  4. **Check Status**: Run `veil status` to verify your setup
300
- 5. **Deposit**: Run `veil deposit <asset> <amount>` — the amount is what lands in your balance (e.g., `veil deposit ETH 0.1` deposits 0.1 ETH; the fee is waived if you have daily free deposits remaining, otherwise 0.3% is added automatically)
342
+ 5. **Deposit**: Run `veil deposit <asset> <amount>` — the amount is what lands in your balance (e.g., `veil deposit ETH 0.1` deposits 0.1 ETH; a 0.3% protocol fee is added on top automatically)
301
343
  6. **Wait**: The Veil deposit engine processes your deposit
302
344
  7. **Done**: Your deposit is accepted into the privacy pool
303
345
 
package/SDK.md CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  Keypair, buildRegisterTx, buildDepositETHTx,
12
12
  buildDepositUSDCTx, buildApproveUSDCTx,
13
13
  withdraw, transfer, getSubaccountStatus, mergeSubaccount,
14
+ payX402Resource,
14
15
  } from '@veil-cash/sdk';
15
16
  import { createWalletClient, http } from 'viem';
16
17
  import { base } from 'viem/chains';
@@ -72,6 +73,14 @@ const subaccount = await getSubaccountStatus({
72
73
  });
73
74
  console.log(subaccount.slot.forwarderAddress);
74
75
 
76
+ // 8. Pay an x402 resource from private USDC
77
+ const paid = await payX402Resource({
78
+ url: 'https://merchant.example/paid-resource',
79
+ rootPrivateKey: keypair.privkey as `0x${string}`,
80
+ payerIndex: 0n,
81
+ relayUrl: process.env.X402_RELAY_URL,
82
+ });
83
+ console.log(paid.response.status, paid.payerAddress);
75
84
  ```
76
85
 
77
86
  ## SDK API Reference
@@ -109,10 +118,9 @@ keypair.privkey; // '0x...'
109
118
 
110
119
  ### Transaction Builders
111
120
 
112
- > **Daily free deposits**: Each address gets a configurable number of fee-free
113
- > deposits per UTC day. The CLI handles this automatically. If you use the
114
- > builders programmatically, call `getDailyFreeRemaining()` first — when the
115
- > user has free slots, pass the net amount directly (no fee markup needed).
121
+ The CLI treats deposit amounts as net amounts and adds the 0.3% protocol fee
122
+ automatically. The low-level transaction builders use the amount you pass as the
123
+ gross amount sent to the Entry contract.
116
124
 
117
125
  ```typescript
118
126
  import {
@@ -182,6 +190,70 @@ const mergeResult = await mergeUtxos({
182
190
  });
183
191
  ```
184
192
 
193
+ ### x402 Payments
194
+
195
+ `payX402Resource()` pays standard x402 v2 Base USDC `exact` resources from a
196
+ private Veil USDC balance while remaining compatible with Coinbase-facilitated
197
+ merchants.
198
+
199
+ ```typescript
200
+ import {
201
+ deriveX402PayerAddress,
202
+ payX402Resource,
203
+ usdcAtomicToDecimalString,
204
+ } from '@veil-cash/sdk';
205
+
206
+ const payerAddress = deriveX402PayerAddress(
207
+ process.env.VEIL_KEY as `0x${string}`,
208
+ 42n,
209
+ );
210
+
211
+ const amount = usdcAtomicToDecimalString('1000'); // "0.001"
212
+
213
+ const result = await payX402Resource({
214
+ url: 'https://merchant.example/paid-resource',
215
+ rootPrivateKey: process.env.VEIL_KEY as `0x${string}`,
216
+ payerIndex: 42n,
217
+ maxPayment: '0.10', // cap exposure; reject if the resource demands more
218
+ relayUrl: process.env.X402_RELAY_URL,
219
+ rpcUrl: process.env.RPC_URL,
220
+ onProgress: (stage, detail) => console.log(stage, detail),
221
+ });
222
+
223
+ console.log({
224
+ status: result.response.status,
225
+ payerAddress: result.payerAddress,
226
+ relayTx: result.relayTransactionHash,
227
+ paymentTx: result.paymentTransactionHash,
228
+ });
229
+ ```
230
+
231
+ The payer key uses the `veil-x402-payer` derivation domain, separate from
232
+ subaccounts. Use a fresh, persisted `payerIndex` for each payment. Set
233
+ `maxPayment` (a decimal USDC string) to cap exposure; the payment is rejected
234
+ before any funds move if the requirement exceeds the cap. The helper currently
235
+ supports x402 v2 `exact` requirements on Base mainnet USDC only; it rejects other
236
+ assets, networks, and schemes.
237
+
238
+ `quoteX402Resource({ url, rpcUrl, maxPayment, init })` probes a resource without
239
+ funding a payer or signing a payment. For a supported `402` it returns the price
240
+ and requirement (`amount`, `amountAtomic`, `payTo`, `network`, `asset`, and
241
+ `exceedsMax` when `maxPayment` is set); for any other status it returns the raw
242
+ `status` and parsed `body`. Use it to validate a request and confirm cost before
243
+ committing a withdrawal. A merchant that validates the request body only after
244
+ payment will still return `402` here, so a quote cannot catch post-payment errors.
245
+
246
+ To retry a payment whose funding succeeded but whose delivery failed (the USDC is
247
+ still on the payer EOA), pass `reuseExistingBalance: true` with the same
248
+ `payerIndex`. When the payer already holds at least the required amount,
249
+ `payX402Resource` skips the withdrawal and pays directly from that balance
250
+ (`relayTransactionHash` is empty); it throws if the balance is insufficient.
251
+
252
+ `getX402PayerBalances({ rootPrivateKey, startIndex, count, nonZeroOnly })`
253
+ inspects the Base USDC balance held by each derived payer EOA, which is useful
254
+ for surfacing funds left on a payer after a failed payment. It is read-only and
255
+ does not move funds.
256
+
185
257
  ### Browser Proof Generation
186
258
 
187
259
  `withdraw()`, `transfer()`, `mergeUtxos()`, `mergeSubaccount()`, `buildWithdrawProof()`,
@@ -232,7 +304,7 @@ such as `circomlib`, `eth-sig-util`, and `fixed-merkle-tree`.
232
304
  Balance functions accept an optional `pool` parameter (`'eth'` | `'usdc'`), defaulting to `'eth'`.
233
305
 
234
306
  ```typescript
235
- import { getQueueBalance, getPrivateBalance, getDailyFreeRemaining } from '@veil-cash/sdk';
307
+ import { getQueueBalance, getPrivateBalance } from '@veil-cash/sdk';
236
308
 
237
309
  // Check ETH queue balance (pending deposits)
238
310
  const queueBalance = await getQueueBalance({
@@ -246,12 +318,6 @@ const privateBalance = await getPrivateBalance({
246
318
  pool: 'usdc',
247
319
  });
248
320
 
249
- // Check how many fee-free deposits the user has left today
250
- const freeRemaining = await getDailyFreeRemaining({
251
- address: '0x...',
252
- pool: 'eth', // default
253
- });
254
- // freeRemaining: number — 0 when all free slots are used or the feature is disabled
255
321
  ```
256
322
 
257
323
  ### Subaccounts