@veilo/sdk-core 0.4.0 → 0.5.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.
Files changed (296) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +286 -1298
  3. package/dist/cjs/accounts/admin.d.ts +84 -0
  4. package/dist/cjs/accounts/admin.js +208 -0
  5. package/dist/cjs/accounts/errors.d.ts +6 -0
  6. package/dist/cjs/accounts/errors.js +98 -0
  7. package/dist/cjs/accounts/index.d.ts +4 -0
  8. package/dist/cjs/accounts/index.js +20 -0
  9. package/dist/cjs/accounts/pdas.d.ts +23 -0
  10. package/dist/cjs/accounts/pdas.js +44 -0
  11. package/dist/cjs/accounts/queries.d.ts +41 -0
  12. package/dist/cjs/accounts/queries.js +95 -0
  13. package/dist/cjs/client.d.ts +2 -407
  14. package/dist/cjs/client.js +6 -938
  15. package/dist/cjs/cloak/client.d.ts +28 -0
  16. package/dist/cjs/cloak/client.js +68 -0
  17. package/dist/cjs/cloak/errors.d.ts +13 -0
  18. package/dist/cjs/cloak/errors.js +25 -0
  19. package/dist/cjs/cloak/helpers.d.ts +6 -0
  20. package/dist/cjs/cloak/helpers.js +35 -0
  21. package/dist/cjs/cloak/index.d.ts +6 -0
  22. package/dist/cjs/cloak/index.js +24 -0
  23. package/dist/cjs/cloak/polling.d.ts +7 -0
  24. package/dist/cjs/cloak/polling.js +66 -0
  25. package/dist/cjs/cloak/transport.d.ts +15 -0
  26. package/dist/cjs/cloak/transport.js +119 -0
  27. package/dist/cjs/cloak/types.d.ts +188 -0
  28. package/dist/cjs/cloak/types.js +5 -0
  29. package/dist/cjs/cloak.d.ts +1 -0
  30. package/dist/cjs/cloak.js +18 -0
  31. package/dist/cjs/compactNote.d.ts +21 -0
  32. package/dist/cjs/compactNote.js +31 -7
  33. package/dist/cjs/index.d.ts +2 -1
  34. package/dist/cjs/index.js +4 -1
  35. package/dist/cjs/notes/encryption.d.ts +41 -0
  36. package/dist/cjs/notes/encryption.js +75 -0
  37. package/dist/cjs/notes/index.d.ts +5 -0
  38. package/dist/cjs/notes/index.js +21 -0
  39. package/dist/cjs/notes/mailbox.d.ts +70 -0
  40. package/dist/cjs/notes/mailbox.js +164 -0
  41. package/dist/cjs/notes/model.d.ts +91 -0
  42. package/dist/cjs/notes/model.js +109 -0
  43. package/dist/cjs/notes/nullifier.d.ts +27 -0
  44. package/dist/cjs/notes/nullifier.js +45 -0
  45. package/dist/cjs/notes/recovery.d.ts +10 -0
  46. package/dist/cjs/notes/recovery.js +31 -0
  47. package/dist/cjs/proof.d.ts +1 -183
  48. package/dist/cjs/proof.js +16 -290
  49. package/dist/cjs/proofs/encoding.d.ts +17 -0
  50. package/dist/cjs/proofs/encoding.js +72 -0
  51. package/dist/cjs/proofs/formatting.d.ts +6 -0
  52. package/dist/cjs/proofs/formatting.js +34 -0
  53. package/dist/cjs/proofs/index.d.ts +5 -0
  54. package/dist/cjs/proofs/index.js +21 -0
  55. package/dist/cjs/proofs/swap.d.ts +87 -0
  56. package/dist/cjs/proofs/swap.js +144 -0
  57. package/dist/cjs/proofs/transaction.d.ts +28 -0
  58. package/dist/cjs/proofs/transaction.js +110 -0
  59. package/dist/cjs/proofs/types.d.ts +70 -0
  60. package/dist/cjs/prover.d.ts +4 -1
  61. package/dist/cjs/prover.js +12 -2
  62. package/dist/cjs/relayer/client.d.ts +61 -0
  63. package/dist/cjs/relayer/client.js +151 -0
  64. package/dist/cjs/relayer/crypto.d.ts +5 -0
  65. package/dist/cjs/relayer/crypto.js +26 -0
  66. package/dist/cjs/relayer/encoding.d.ts +2 -0
  67. package/dist/cjs/relayer/encoding.js +23 -0
  68. package/dist/cjs/relayer/errors.d.ts +7 -0
  69. package/dist/cjs/relayer/errors.js +17 -0
  70. package/dist/cjs/relayer/index.d.ts +3 -0
  71. package/dist/cjs/relayer/index.js +19 -0
  72. package/dist/cjs/relayer/transport.d.ts +17 -0
  73. package/dist/cjs/relayer/transport.js +63 -0
  74. package/dist/{src/relayer.d.ts → cjs/relayer/types.d.ts} +44 -86
  75. package/dist/cjs/relayer/types.js +5 -0
  76. package/dist/cjs/relayer.d.ts +1 -318
  77. package/dist/cjs/relayer.js +15 -254
  78. package/dist/cjs/shield/alt.js +8 -8
  79. package/dist/cjs/shield/errors.js +2 -2
  80. package/dist/cjs/shield/finalize.js +2 -2
  81. package/dist/cjs/shield/ix.d.ts +1 -1
  82. package/dist/cjs/shield/owner.js +9 -8
  83. package/dist/cjs/shield/ports.js +3 -3
  84. package/dist/cjs/shield/preflight.js +3 -3
  85. package/dist/cjs/shield/shield.js +20 -19
  86. package/dist/cjs/shield/types.d.ts +1 -1
  87. package/dist/cjs/transactions/deposit.d.ts +94 -0
  88. package/dist/cjs/transactions/deposit.js +234 -0
  89. package/dist/cjs/transactions/index.d.ts +7 -0
  90. package/dist/cjs/transactions/index.js +26 -0
  91. package/dist/cjs/transactions/swap.d.ts +71 -0
  92. package/dist/cjs/transactions/swap.js +184 -0
  93. package/dist/cjs/transactions/transact.d.ts +34 -0
  94. package/dist/cjs/transactions/transact.js +146 -0
  95. package/dist/cjs/transactions/transfer.d.ts +51 -0
  96. package/dist/cjs/transactions/transfer.js +106 -0
  97. package/dist/cjs/transactions/withdraw.d.ts +52 -0
  98. package/dist/cjs/transactions/withdraw.js +104 -0
  99. package/dist/cjs/utxo.d.ts +1 -235
  100. package/dist/cjs/utxo.js +15 -404
  101. package/dist/esm/accounts/admin.d.ts +84 -0
  102. package/dist/esm/accounts/admin.js +165 -0
  103. package/dist/esm/accounts/errors.d.ts +6 -0
  104. package/dist/esm/accounts/errors.js +95 -0
  105. package/dist/esm/accounts/index.d.ts +4 -0
  106. package/dist/esm/accounts/index.js +4 -0
  107. package/dist/esm/accounts/pdas.d.ts +23 -0
  108. package/dist/esm/accounts/pdas.js +38 -0
  109. package/dist/esm/accounts/queries.d.ts +41 -0
  110. package/dist/esm/accounts/queries.js +88 -0
  111. package/dist/esm/client.d.ts +2 -407
  112. package/dist/esm/client.js +3 -891
  113. package/dist/esm/cloak/client.d.ts +28 -0
  114. package/dist/esm/cloak/client.js +64 -0
  115. package/dist/esm/cloak/errors.d.ts +13 -0
  116. package/dist/esm/cloak/errors.js +21 -0
  117. package/dist/esm/cloak/helpers.d.ts +6 -0
  118. package/dist/esm/cloak/helpers.js +31 -0
  119. package/dist/esm/cloak/index.d.ts +6 -0
  120. package/dist/esm/cloak/index.js +6 -0
  121. package/dist/esm/cloak/polling.d.ts +7 -0
  122. package/dist/esm/cloak/polling.js +63 -0
  123. package/dist/esm/cloak/transport.d.ts +15 -0
  124. package/dist/esm/cloak/transport.js +115 -0
  125. package/dist/esm/cloak/types.d.ts +188 -0
  126. package/dist/esm/cloak/types.js +4 -0
  127. package/dist/esm/cloak.d.ts +1 -0
  128. package/dist/esm/cloak.js +2 -0
  129. package/dist/esm/compactNote.d.ts +21 -0
  130. package/dist/esm/compactNote.js +24 -1
  131. package/dist/esm/index.d.ts +2 -1
  132. package/dist/esm/index.js +3 -1
  133. package/dist/esm/notes/encryption.d.ts +41 -0
  134. package/dist/esm/notes/encryption.js +67 -0
  135. package/dist/esm/notes/index.d.ts +5 -0
  136. package/dist/esm/notes/index.js +5 -0
  137. package/dist/esm/notes/mailbox.d.ts +70 -0
  138. package/dist/esm/notes/mailbox.js +154 -0
  139. package/dist/esm/notes/model.d.ts +91 -0
  140. package/dist/esm/notes/model.js +99 -0
  141. package/dist/esm/notes/nullifier.d.ts +27 -0
  142. package/dist/esm/notes/nullifier.js +40 -0
  143. package/dist/esm/notes/recovery.d.ts +10 -0
  144. package/dist/esm/notes/recovery.js +28 -0
  145. package/dist/esm/proof.d.ts +1 -183
  146. package/dist/esm/proof.js +2 -281
  147. package/dist/esm/proofs/encoding.d.ts +17 -0
  148. package/dist/esm/proofs/encoding.js +68 -0
  149. package/dist/esm/proofs/formatting.d.ts +6 -0
  150. package/dist/esm/proofs/formatting.js +31 -0
  151. package/dist/esm/proofs/index.d.ts +5 -0
  152. package/dist/esm/proofs/index.js +5 -0
  153. package/dist/esm/proofs/swap.d.ts +87 -0
  154. package/dist/esm/proofs/swap.js +138 -0
  155. package/dist/esm/proofs/transaction.d.ts +28 -0
  156. package/dist/esm/proofs/transaction.js +105 -0
  157. package/dist/esm/proofs/types.d.ts +70 -0
  158. package/dist/esm/proofs/types.js +1 -0
  159. package/dist/esm/prover.d.ts +4 -1
  160. package/dist/esm/prover.js +10 -1
  161. package/dist/esm/relayer/client.d.ts +61 -0
  162. package/dist/esm/relayer/client.js +144 -0
  163. package/dist/esm/relayer/crypto.d.ts +5 -0
  164. package/dist/esm/relayer/crypto.js +20 -0
  165. package/dist/esm/relayer/encoding.d.ts +2 -0
  166. package/dist/esm/relayer/encoding.js +19 -0
  167. package/dist/esm/relayer/errors.d.ts +7 -0
  168. package/dist/esm/relayer/errors.js +13 -0
  169. package/dist/esm/relayer/index.d.ts +3 -0
  170. package/dist/esm/relayer/index.js +3 -0
  171. package/dist/esm/relayer/transport.d.ts +17 -0
  172. package/dist/esm/relayer/transport.js +59 -0
  173. package/dist/esm/relayer/types.d.ts +276 -0
  174. package/dist/esm/relayer/types.js +4 -0
  175. package/dist/esm/relayer.d.ts +1 -318
  176. package/dist/esm/relayer.js +2 -249
  177. package/dist/esm/shield/alt.js +1 -1
  178. package/dist/esm/shield/errors.js +1 -1
  179. package/dist/esm/shield/finalize.js +1 -1
  180. package/dist/esm/shield/ix.d.ts +1 -1
  181. package/dist/esm/shield/owner.js +2 -1
  182. package/dist/esm/shield/ports.js +1 -1
  183. package/dist/esm/shield/preflight.js +1 -1
  184. package/dist/esm/shield/shield.js +4 -3
  185. package/dist/esm/shield/types.d.ts +1 -1
  186. package/dist/esm/transactions/deposit.d.ts +94 -0
  187. package/dist/esm/transactions/deposit.js +198 -0
  188. package/dist/esm/transactions/index.d.ts +7 -0
  189. package/dist/esm/transactions/index.js +7 -0
  190. package/dist/esm/transactions/swap.d.ts +71 -0
  191. package/dist/esm/transactions/swap.js +144 -0
  192. package/dist/esm/transactions/transact.d.ts +34 -0
  193. package/dist/esm/transactions/transact.js +110 -0
  194. package/dist/esm/transactions/transfer.d.ts +51 -0
  195. package/dist/esm/transactions/transfer.js +103 -0
  196. package/dist/esm/transactions/withdraw.d.ts +52 -0
  197. package/dist/esm/transactions/withdraw.js +101 -0
  198. package/dist/esm/utxo.d.ts +1 -235
  199. package/dist/esm/utxo.js +2 -382
  200. package/package.json +54 -16
  201. package/SHIELD_INTEGRATION.md +0 -143
  202. package/config.d.ts +0 -2
  203. package/config.js +0 -4
  204. package/dist/src/client.d.ts +0 -407
  205. package/dist/src/client.js +0 -951
  206. package/dist/src/compactNote.d.ts +0 -107
  207. package/dist/src/compactNote.js +0 -167
  208. package/dist/src/config.d.ts +0 -82
  209. package/dist/src/config.js +0 -57
  210. package/dist/src/events.d.ts +0 -77
  211. package/dist/src/events.js +0 -167
  212. package/dist/src/idl/privacy_pool.d.ts +0 -5
  213. package/dist/src/idl/privacy_pool.js +0 -15218
  214. package/dist/src/index.d.ts +0 -16
  215. package/dist/src/index.js +0 -67
  216. package/dist/src/merkle.d.ts +0 -77
  217. package/dist/src/merkle.js +0 -156
  218. package/dist/src/poseidon.d.ts +0 -29
  219. package/dist/src/poseidon.js +0 -100
  220. package/dist/src/program.d.ts +0 -37
  221. package/dist/src/program.js +0 -61
  222. package/dist/src/proof.d.ts +0 -183
  223. package/dist/src/proof.js +0 -292
  224. package/dist/src/prover.d.ts +0 -54
  225. package/dist/src/prover.js +0 -112
  226. package/dist/src/random.d.ts +0 -16
  227. package/dist/src/random.js +0 -28
  228. package/dist/src/relayer.js +0 -257
  229. package/dist/src/retry.d.ts +0 -32
  230. package/dist/src/retry.js +0 -75
  231. package/dist/src/shield/alt.d.ts +0 -87
  232. package/dist/src/shield/alt.js +0 -194
  233. package/dist/src/shield/computeBudget.d.ts +0 -61
  234. package/dist/src/shield/computeBudget.js +0 -64
  235. package/dist/src/shield/errors.d.ts +0 -58
  236. package/dist/src/shield/errors.js +0 -121
  237. package/dist/src/shield/finalize.d.ts +0 -45
  238. package/dist/src/shield/finalize.js +0 -119
  239. package/dist/src/shield/index.d.ts +0 -35
  240. package/dist/src/shield/index.js +0 -68
  241. package/dist/src/shield/ix.d.ts +0 -54
  242. package/dist/src/shield/ix.js +0 -119
  243. package/dist/src/shield/owner.d.ts +0 -36
  244. package/dist/src/shield/owner.js +0 -126
  245. package/dist/src/shield/ports.d.ts +0 -43
  246. package/dist/src/shield/ports.js +0 -153
  247. package/dist/src/shield/preflight.d.ts +0 -30
  248. package/dist/src/shield/preflight.js +0 -154
  249. package/dist/src/shield/shield.d.ts +0 -68
  250. package/dist/src/shield/shield.js +0 -499
  251. package/dist/src/shield/types.d.ts +0 -202
  252. package/dist/src/utxo.d.ts +0 -235
  253. package/dist/src/utxo.js +0 -407
  254. package/dist/tests/compact-note.test.d.ts +0 -1
  255. package/dist/tests/compact-note.test.js +0 -173
  256. package/dist/tests/config.test.d.ts +0 -1
  257. package/dist/tests/config.test.js +0 -102
  258. package/dist/tests/edge-cases.test.d.ts +0 -1
  259. package/dist/tests/edge-cases.test.js +0 -220
  260. package/dist/tests/encryption.test.d.ts +0 -1
  261. package/dist/tests/encryption.test.js +0 -215
  262. package/dist/tests/events.test.d.ts +0 -1
  263. package/dist/tests/events.test.js +0 -78
  264. package/dist/tests/multi-tree.test.d.ts +0 -1
  265. package/dist/tests/multi-tree.test.js +0 -405
  266. package/dist/tests/pda.test.d.ts +0 -1
  267. package/dist/tests/pda.test.js +0 -229
  268. package/dist/tests/poseidon-builder-parity.test.d.ts +0 -1
  269. package/dist/tests/poseidon-builder-parity.test.js +0 -72
  270. package/dist/tests/poseidon.test.d.ts +0 -1
  271. package/dist/tests/poseidon.test.js +0 -142
  272. package/dist/tests/proof.test.d.ts +0 -1
  273. package/dist/tests/proof.test.js +0 -296
  274. package/dist/tests/relayer.test.d.ts +0 -1
  275. package/dist/tests/relayer.test.js +0 -271
  276. package/dist/tests/sdk.integration.test.d.ts +0 -1
  277. package/dist/tests/sdk.integration.test.js +0 -330
  278. package/dist/tests/shield-owner.test.d.ts +0 -1
  279. package/dist/tests/shield-owner.test.js +0 -89
  280. package/dist/tests/shield-preflight.test.d.ts +0 -1
  281. package/dist/tests/shield-preflight.test.js +0 -87
  282. package/dist/tests/shield-realproof.test.d.ts +0 -1
  283. package/dist/tests/shield-realproof.test.js +0 -272
  284. package/dist/tests/shield.test.d.ts +0 -1
  285. package/dist/tests/shield.test.js +0 -403
  286. package/dist/tests/utxo.test.d.ts +0 -1
  287. package/dist/tests/utxo.test.js +0 -140
  288. package/poseidon.d.ts +0 -2
  289. package/poseidon.js +0 -4
  290. package/proof.d.ts +0 -2
  291. package/proof.js +0 -4
  292. package/prover.d.ts +0 -2
  293. package/prover.js +0 -4
  294. package/shield.d.ts +0 -2
  295. package/shield.js +0 -4
  296. /package/dist/{src/shield → cjs/proofs}/types.js +0 -0
package/README.md CHANGED
@@ -1,1463 +1,451 @@
1
1
  # @veilo/sdk-core
2
2
 
3
- TypeScript SDK for the Veilo Privacy Pool Anchor program.
3
+ Build private payments and swaps on Solana with Veilo.
4
4
 
5
- This package provides a complete UTXO-based privacy protocol implementation on Solana with:
5
+ The SDK gives TypeScript applications a safe, typed way to:
6
6
 
7
- - **UTXO Model**: Full support for unspent transaction outputs with Poseidon commitments
8
- - **Multi-Tree Support**: Multiple concurrent Merkle trees for improved scalability
9
- - **ZK Proofs**: Integration with Circom circuits for private transactions
10
- - **Private Swaps**: Atomic cross-pool swaps via Jupiter (native SOL + SPL tokens)
11
- - **Note Encryption**: NaCl-based encrypted UTXO notes and blind mailbox delivery
12
- - **Event Scanning**: Reconstruct Merkle trees from on-chain events
13
- - **Poseidon Hashing**: BN254-curve compatible hashing using circomlibjs
14
- - **Relayer Support**: Built-in relayer infrastructure for private withdrawals and swaps
7
+ - shield SOL or SPL tokens into Veilo;
8
+ - withdraw, privately transfer, or privately swap shielded funds;
9
+ - work with Veilo's relayer without handling its encryption protocol yourself;
10
+ - add partner-powered private sends and swaps through the Cloak API.
15
11
 
16
- > **Status:** Active development. The SDK supports full transaction privacy with ZK-SNARK proofs.
17
- > Proofs are generated off-chain and verified on-chain using Groth16.
12
+ It works with both ESM and CommonJS and includes TypeScript declarations.
18
13
 
19
- ---
14
+ > **Project status:** Active development. Test integrations on Devnet before using
15
+ > them with real funds.
20
16
 
21
- ## 1. Installation
17
+ ## Install
22
18
 
23
19
  ```bash
24
20
  npm install @veilo/sdk-core
25
21
  ```
26
22
 
27
- ---
28
-
29
- ## 2. Prerequisites
30
-
31
- - A running Solana validator (localnet/devnet/mainnet)
32
- - The `privacy-pool` program deployed to the network
33
- - A funded keypair
34
-
35
- ```bash
36
- export ANCHOR_PROVIDER_URL=https://api.devnet.solana.com
37
- export ANCHOR_WALLET=$HOME/.config/solana/id.json
38
- ```
39
-
40
- ---
41
-
42
- ## 3. Build
23
+ Install `snarkjs` only if your application generates proofs locally:
43
24
 
44
25
  ```bash
45
- npm run build
26
+ npm install snarkjs
46
27
  ```
47
28
 
48
- ---
49
-
50
- ## 4. SDK API
51
-
52
- ### 4.1 PDA Helpers
53
-
54
- ```ts
55
- import {
56
- getPoolPdas,
57
- getNoteTreePda,
58
- getGlobalConfigPda,
59
- getNullifierMarkerPda,
60
- getSwapExecutorPda,
61
- } from "@veilo/sdk-core";
62
- import { PublicKey } from "@solana/web3.js";
63
-
64
- const programId = new PublicKey(
65
- "YourProgram1111111111111111111111111111111111",
66
- );
67
- const mintAddress = new PublicKey(
68
- "So11111111111111111111111111111111111111112",
69
- );
70
-
71
- // Pool PDAs (config, vault, nullifiers)
72
- const { config, vault, nullifiers } = getPoolPdas(programId, mintAddress);
29
+ You will also need:
73
30
 
74
- // Note tree PDA for tree ID 0
75
- const noteTree = getNoteTreePda(programId, mintAddress, 0);
31
+ - a Solana RPC connection;
32
+ - a connected wallet when a user must sign;
33
+ - the Veilo circuit `.wasm` and `.zkey` files for local proof generation;
34
+ - a Veilo-issued API key for partner or relayer endpoints that require one.
76
35
 
77
- // Global config PDA (one per program)
78
- const globalConfig = getGlobalConfigPda(programId);
79
-
80
- // Nullifier marker PDA (prevents double-spend)
81
- const nullifier = new Uint8Array(32);
82
- const marker = getNullifierMarkerPda(programId, mintAddress, nullifier);
83
-
84
- // Swap executor PDA (for cross-pool swaps)
85
- const relayerPubkey = new PublicKey("...");
86
- const executor = getSwapExecutorPda(
87
- programId,
88
- sourceMint,
89
- destMint,
90
- inputNullifier0, // Uint8Array[32]
91
- relayerPubkey,
92
- );
93
- ```
36
+ ## Choose an integration
94
37
 
95
- **PDA seeds (v3):**
38
+ | What you want to build | Start with | Who signs? |
39
+ | --- | --- | --- |
40
+ | Let any wallet shield funds into Veilo | `shield()` | The user's wallet |
41
+ | Add private transfers or swaps to a partner app | `VeiloCloakClient` | The user's wallet |
42
+ | Build a full Veilo wallet experience | `VeiloRelayerClient` | The relayer for private spends |
43
+ | Manage proofs, notes, trees, and transactions yourself | Transaction helpers | Your application or relayer |
96
44
 
97
- | Account | Seeds |
98
- | ---------------- | ------------------------------------------------------------------- |
99
- | Config | `["privacy_config_v3", mint]` |
100
- | Vault | `["privacy_vault_v3", mint]` |
101
- | Note Tree | `["privacy_note_tree_v3", mint, tree_id]` |
102
- | Nullifiers | `["privacy_nullifiers_v3", mint]` |
103
- | Nullifier Marker | `["nullifier_v3", mint, nullifier]` |
104
- | Global Config | `["global_config_v1"]` |
105
- | Swap Executor | `["swap_executor_v1", source_mint, dest_mint, nullifier0, relayer]` |
45
+ For most third-party deposit integrations, `shield()` is the best starting
46
+ point. For a managed private send or swap flow, use Cloak.
106
47
 
107
- ---
48
+ ## Quick start: shield funds
108
49
 
109
- ### 4.2 Pool Initialization
110
-
111
- ```ts
112
- import {
113
- initializeGlobalConfig,
114
- initializePool,
115
- updatePoolConfig,
116
- addMerkleTree,
117
- getPoolConfig,
118
- updateGlobalConfig,
119
- } from "@veilo/sdk-core";
120
- import { NATIVE_SOL_MINT, sol } from "@veilo/sdk-core/config";
121
-
122
- // Initialize global config (once per program)
123
- await initializeGlobalConfig({ program, admin: adminKeypair });
124
-
125
- // Update global config
126
- await updateGlobalConfig({
127
- program,
128
- admin: adminKeypair,
129
- newAdmin: newAdminPubkey, // optional
130
- paused: false, // optional
131
- });
132
-
133
- // Initialize a pool for native SOL
134
- await initializePool({
135
- program,
136
- payer: adminKeypair,
137
- admin: adminKeypair,
138
- mintAddress: NATIVE_SOL_MINT,
139
- minDepositAmount: sol(0.1),
140
- maxDepositAmount: sol(100),
141
- minWithdrawAmount: sol(0.1),
142
- maxWithdrawAmount: sol(100),
143
- feeBps: 50, // 0.5%
144
- feeErrorMarginBps: 10, // 0.1% margin
145
- minWithdrawalFee: 1_000_000n,
146
- });
147
-
148
- // Add Merkle tree (tree ID 0)
149
- await addMerkleTree({
150
- program,
151
- payer: adminKeypair,
152
- mintAddress: NATIVE_SOL_MINT,
153
- treeId: 0,
154
- });
155
-
156
- // Update pool fee
157
- await updatePoolConfig({
158
- program,
159
- admin: adminKeypair,
160
- mintAddress: NATIVE_SOL_MINT,
161
- feeBps: 30,
162
- });
163
-
164
- // Read pool configuration
165
- const poolConfig = await getPoolConfig(program, NATIVE_SOL_MINT);
166
- console.log("TVL:", poolConfig.totalTvl, " Fee:", poolConfig.feeBps, "bps");
167
- ```
168
-
169
- ---
170
-
171
- ### 4.3 On-Chain Account Queries
172
-
173
- ```ts
174
- import {
175
- fetchPoolConfig,
176
- checkNullifierSpent,
177
- getTreeInfo,
178
- getAllTreeInfo,
179
- getBestTreeForDeposit,
180
- } from "@veilo/sdk-core";
181
-
182
- // Fetch decoded PrivacyConfig account
183
- const config = await fetchPoolConfig(program, NATIVE_SOL_MINT);
184
-
185
- // Check if a nullifier has been spent
186
- const spent = await checkNullifierSpent(program, NATIVE_SOL_MINT, nullifier);
187
-
188
- // Info for a single tree
189
- const info = await getTreeInfo(program, NATIVE_SOL_MINT, 0);
190
- // info = { treeId, leafCount, root, isFull }
191
-
192
- // Info for all trees in a pool
193
- const allInfo = await getAllTreeInfo(program, NATIVE_SOL_MINT);
194
-
195
- // Pick the best tree for depositing (least full with capacity)
196
- const best = await getBestTreeForDeposit(program, NATIVE_SOL_MINT);
197
- // best = { treeId, leafCount, root }
198
- ```
199
-
200
- ---
201
-
202
- ### 4.4 UTXO Management
203
-
204
- ```ts
205
- import {
206
- generateKeypair,
207
- keypairFromPrivateKey,
208
- createUTXO,
209
- createOwnedUTXO,
210
- createOwnedZeroUTXO,
211
- deriveNullifier,
212
- type Keypair,
213
- type UTXO,
214
- type SerializedUTXO,
215
- type InputUTXO,
216
- } from "@veilo/sdk-core";
217
- import { NATIVE_SOL_MINT } from "@veilo/sdk-core/config";
218
- import { pubkeyToField } from "@veilo/sdk-core";
219
-
220
- // Generate a random UTXO keypair
221
- const keypair: Keypair = generateKeypair();
222
- // keypair = { privateKey: bigint, publicKey: bigint }
223
-
224
- // Restore from private key
225
- const restored = keypairFromPrivateKey(privateKeyBigInt);
226
-
227
- // Create an owned UTXO (includes private key)
228
- const ownedUtxo: SerializedUTXO = createOwnedUTXO({
229
- amount: 1_000_000_000n,
230
- privateKey: keypair.privateKey,
231
- mintAddress: NATIVE_SOL_MINT,
232
- });
233
-
234
- // Create a zero-value UTXO (for unused inputs/outputs)
235
- const zeroUtxo = createOwnedZeroUTXO(pubkeyToField(NATIVE_SOL_MINT), keypair);
236
-
237
- // Derive nullifier for spending
238
- const pathIndex = 0; // leaf index in Merkle tree
239
- const treeId = 0;
240
- const nullifier = deriveNullifier(
241
- ownedUtxo.privateKey,
242
- ownedUtxo.commitment,
243
- pathIndex,
244
- treeId,
245
- );
246
- ```
247
-
248
- **UTXO commitment:** `Poseidon(amount, pubkey, blinding, mintAddress)`
249
-
250
- **Nullifier:** `Poseidon(privateKey, commitment, pathIndex, treeId)`
251
-
252
- ---
253
-
254
- ### 4.5 UTXO Encryption
255
-
256
- The SDK provides NaCl-based encryption for UTXO notes (relayer storage) and blind mailbox delivery (wallet-to-wallet).
257
-
258
- ```ts
259
- import {
260
- deriveEncryptionKeypair,
261
- encryptUTXONote,
262
- decryptUTXONote,
263
- encryptBlindMailboxNote,
264
- decryptBlindMailboxNote,
265
- fetchAndDecryptNotes,
266
- computeSignature,
267
- inputUTXOToCircuitFormat,
268
- type EncryptedNote,
269
- type BlindMailboxNote,
270
- type BlindMailboxNoteData,
271
- type DecryptedNote,
272
- } from "@veilo/sdk-core";
273
- import { Keypair as SolanaKeypair } from "@solana/web3.js";
274
-
275
- // Derive a NaCl encryption keypair from a UTXO private key
276
- const encKeypair = deriveEncryptionKeypair(utxoKeypair.privateKey);
277
- // encKeypair = { publicKey: Uint8Array[32], secretKey: Uint8Array[32] }
278
-
279
- // Encrypt a UTXO note for relay storage
280
- const encryptedNote: EncryptedNote = encryptUTXONote(
281
- serializedUtxo, // SerializedUTXO
282
- encKeypair.publicKey, // NaCl public key (Uint8Array[32])
283
- );
284
-
285
- // Decrypt a UTXO note
286
- const decrypted: SerializedUTXO | null = decryptUTXONote(
287
- encryptedNote,
288
- encKeypair.secretKey, // NaCl secret key (Uint8Array[32])
289
- );
290
-
291
- // Blind mailbox: encrypt for a Solana wallet keypair
292
- const recipientKeypair = SolanaKeypair.generate();
293
-
294
- const mailboxNote: BlindMailboxNote = encryptBlindMailboxNote(
295
- serializedUtxo,
296
- recipientKeypair.publicKey.toBytes(), // ed25519 public key → X25519 DH
297
- );
298
-
299
- // Recipient decrypts using their Solana secret key (64-byte)
300
- const mailboxDecrypted: DecryptedNote | null = decryptBlindMailboxNote(
301
- mailboxNote,
302
- recipientKeypair.secretKey, // 64-byte Solana secret key
303
- );
304
-
305
- // Compute UTXO signature (used in circuit)
306
- const sig = computeSignature(utxoKeypair.privateKey, utxo.commitment);
307
-
308
- // Format an InputUTXO for snarkjs circuit
309
- const circuitFormat = inputUTXOToCircuitFormat(inputUtxo);
310
- ```
311
-
312
- ---
313
-
314
- ### 4.6 Merkle Tree Operations
315
-
316
- ```ts
317
- import { MerkleTree } from "@veilo/sdk-core";
318
-
319
- // Create a new Merkle tree (default depth: 22)
320
- const tree = new MerkleTree();
321
-
322
- // Insert commitments
323
- const index = tree.insert(ownedUtxo.commitment);
324
-
325
- // Current root
326
- const root = tree.root();
327
-
328
- // Merkle path for proof generation
329
- const path = tree.path(index);
330
- // path = { pathElements: Uint8Array[], pathIndices: number[] }
331
-
332
- // Total leaves inserted
333
- const count = tree.totalLeaves;
334
- ```
335
-
336
- ---
337
-
338
- ### 4.7 Transaction Operations
339
-
340
- All transaction functions return `Promise<string>` (the transaction signature).
341
-
342
- #### Deposits
343
-
344
- ```ts
345
- import { deposit, type DepositResult } from "@veilo/sdk-core";
346
-
347
- const result: DepositResult = await deposit({
348
- program,
349
- depositor: depositorKeypair,
350
- mintAddress: NATIVE_SOL_MINT,
351
- amount: 1_000_000_000n, // 1 SOL
352
- recipientPubkey: pubkeyToField(depositorKeypair.publicKey), // bigint
353
- tree,
354
- proofBuilder,
355
- treeId: 0,
356
- });
357
- // result = { outputUTXOs, leafIndices, root }
358
- ```
359
-
360
- #### Withdrawals
361
-
362
- ```ts
363
- import { withdraw, type WithdrawResult } from "@veilo/sdk-core";
364
-
365
- const result: WithdrawResult = await withdraw({
366
- program,
367
- relayer: relayerKeypair,
368
- mintAddress: NATIVE_SOL_MINT,
369
- amount: 900_000_000n, // 0.9 SOL
370
- fee: 100_000_000n, // 0.1 SOL to relayer
371
- inputs: [inputUtxo1, zeroInputUtxo],
372
- outputs: [changeUtxo, zeroOutputUtxo],
373
- recipient: recipientKeypair.publicKey,
374
- tree,
375
- proofBuilder,
376
- treeId: 0,
377
- });
378
- ```
379
-
380
- #### Private Transfers
381
-
382
- ```ts
383
- import { privateTransfer, type TransferResult } from "@veilo/sdk-core";
384
-
385
- const result: TransferResult = await privateTransfer({
386
- program,
387
- relayer: relayerKeypair,
388
- mintAddress: NATIVE_SOL_MINT,
389
- inputs: [inputUtxo1, zeroInputUtxo],
390
- outputs: [recipientUtxo, changeUtxo],
391
- recipient: relayerKeypair.publicKey,
392
- tree,
393
- proofBuilder,
394
- treeId: 0,
395
- });
396
- ```
397
-
398
- #### Low-Level `transact`
399
-
400
- ```ts
401
- import { transact } from "@veilo/sdk-core";
402
-
403
- const signature: string = await transact({
404
- program,
405
- relayer: relayerKeypair,
406
- mintAddress: NATIVE_SOL_MINT,
407
- inputTreeId: 0,
408
- outputTreeId: 0,
409
- root: tree.root(),
410
- publicAmount: 0n,
411
- inputNullifiers: [nullifier1, nullifier2],
412
- outputCommitments: [output1.commitment, output2.commitment],
413
- extData: { recipient, relayer: relayerPubkey, fee: 0n, refund: 0n, claimant },
414
- proof,
415
- });
416
- ```
417
-
418
- ---
419
-
420
- #### Wallet-agnostic shielding
421
-
422
- `shield()` builds an unsigned v0 deposit transaction for any Solana wallet to
423
- sign. The signer funds the deposit, while the resulting private note can belong
424
- to a different Veilo user. The SDK never receives a wallet secret key and never
425
- broadcasts on the caller's behalf.
50
+ `shield()` creates an unsigned transaction. Your application asks the user's
51
+ wallet to sign it, submits it, and then finalizes the new private note.
426
52
 
427
53
  ```ts
54
+ import { Connection } from "@solana/web3.js";
428
55
  import {
429
56
  createTransactionProver,
57
+ finalizeShield,
430
58
  resolveShieldOwner,
431
59
  shield,
432
60
  } from "@veilo/sdk-core";
433
61
 
62
+ const connection = new Connection(process.env.SOLANA_RPC_URL!, "confirmed");
63
+
64
+ // `wallet` is any connected Solana wallet with `publicKey` and
65
+ // `signTransaction` methods.
434
66
  const owner = await resolveShieldOwner({ username: "alice" });
67
+ const prover = createTransactionProver({
68
+ wasmPath: "/circuits/transaction.wasm",
69
+ zkeyPath: "/circuits/transaction_final.zkey",
70
+ });
71
+
435
72
  const result = await shield({
436
73
  connection,
437
- amount: 5_000_000n,
438
- mint: USDC_MINT,
74
+ amount: 1_000_000_000n, // 1 SOL in lamports
439
75
  owner,
440
76
  signer: { publicKey: wallet.publicKey },
441
- prover: createTransactionProver({ wasmPath, zkeyPath }),
77
+ prover,
442
78
  });
443
79
 
444
80
  const signed = await wallet.signTransaction(result.transaction);
445
81
  const signature = await connection.sendRawTransaction(signed.serialize());
446
- ```
447
-
448
- Use `rebuild()` if the blockhash or deadline expires, and call
449
- `finalizeShield()` after confirmation to obtain the authoritative Merkle leaf
450
- index. See [SHIELD_INTEGRATION.md](./SHIELD_INTEGRATION.md) for the complete
451
- build → sign → submit → finalize flow, retry rules, owner-key invariant, and
452
- fee/rent requirements.
453
-
454
- ---
455
82
 
456
- ### 4.8 Private Swaps
457
-
458
- Cross-pool private swaps via Jupiter/Raydium. For native SOL source pools the SDK automatically composes the required `fund_native_source` + `transact_swap` instructions into a single atomic transaction.
83
+ const confirmation = await connection.confirmTransaction(
84
+ {
85
+ signature,
86
+ blockhash: result.blockhash,
87
+ lastValidBlockHeight: result.lastValidBlockHeight,
88
+ },
89
+ "confirmed",
90
+ );
459
91
 
460
- ```ts
461
- import {
462
- transactSwap,
463
- getSwapExecutorPda,
464
- fundNativeSource,
465
- type SwapParams,
466
- type SwapProofStruct,
467
- } from "@veilo/sdk-core";
92
+ if (confirmation.value.err) {
93
+ throw new Error("Shield transaction failed");
94
+ }
468
95
 
469
- // Execute a private swap (returns transaction signature)
470
- const signature: string = await transactSwap({
471
- program,
472
- relayer: relayerKeypair,
473
- sourceMint, // NATIVE_SOL_MINT or SPL token mint
474
- destMint,
475
- sourceRoot: tree.root(),
476
- sourceTreeId: 0,
477
- destTreeId: 0,
478
- inputNullifiers: [nullifier0, nullifier1],
479
- outputCommitments: [changeCommitment, destCommitment],
480
- proof, // SwapProofStruct
481
- swapParams: {
482
- minAmountOut: 950_000_000n,
483
- deadline: BigInt(Math.floor(Date.now() / 1000) + 60),
484
- sourceMint,
485
- destMint,
486
- destAmount: 950_000_000n,
487
- swapDataHash: new Uint8Array(32), // SHA-256 of DEX ix bytes, or zeros
488
- },
489
- swapAmount: 1_000_000_000n,
490
- swapData: jupiterInstructionBytes, // Buffer
491
- extData: { recipient, relayer: relayerPubkey, fee, refund: 0n, claimant },
492
- sourceVaultTokenAccount,
493
- sourceMintAccount,
494
- destVaultTokenAccount,
495
- destMintAccount,
496
- relayerTokenAccount,
497
- swapProgram: JUPITER_PROGRAM_ID,
498
- jupiterEventAuthority,
96
+ const finalized = await finalizeShield({
97
+ connection,
98
+ signature,
99
+ note: result.note,
100
+ owner,
499
101
  });
500
102
 
501
- // Build the fund_native_source instruction standalone (advanced)
502
- const fundIx = await fundNativeSource({
503
- program,
504
- relayer: relayerKeypair,
505
- sourceMint: NATIVE_SOL_MINT,
506
- destMint,
507
- inputNullifier0: nullifier0,
508
- swapAmount: 1_000_000_000n,
509
- });
510
- // Returns TransactionInstruction — must be first ix in same tx as transact_swap
103
+ console.log("Private note created at leaf", finalized.leafIndex);
511
104
  ```
512
105
 
513
- > **Note:** `transactSwap` handles the atomicity requirement automatically. Only use `fundNativeSource` directly if you are building transactions manually.
514
-
515
- ---
516
-
517
- ### 4.9 Event Scanning & Tree Reconstruction
106
+ To shield an SPL token, pass its mint:
518
107
 
519
108
  ```ts
520
- import {
521
- scanCommitmentEvents,
522
- scanNullifierEvents,
523
- buildTreeFromEvents,
524
- type CommitmentEvent,
525
- type NullifierSpentEvent,
526
- } from "@veilo/sdk-core";
527
-
528
- // Scan all commitment events for a mint (paginated by signature)
529
- const { events, latestSignature } = await scanCommitmentEvents({
530
- program,
531
- mintAddress: NATIVE_SOL_MINT,
532
- treeId: 0,
533
- beforeSignature: undefined, // or last known signature for pagination
534
- limit: 1000,
535
- });
536
- // events: CommitmentEvent[]
537
- // CommitmentEvent = { commitment, leafIndex, newRoot, timestamp, mintAddress, treeId }
538
-
539
- // Scan spent nullifier events
540
- const { events: nullEvents } = await scanNullifierEvents({
541
- program,
542
- mintAddress: NATIVE_SOL_MINT,
543
- beforeSignature: undefined,
544
- limit: 1000,
545
- });
546
- // NullifierSpentEvent = { nullifier, mintAddress, treeId }
547
-
548
- // Reconstruct a Merkle tree from on-chain events
549
- const {
550
- tree,
551
- events: allEvents,
552
- latestSignature: sig,
553
- } = await buildTreeFromEvents({
554
- program,
555
- mintAddress: NATIVE_SOL_MINT,
556
- treeId: 0,
109
+ const result = await shield({
110
+ connection,
111
+ mint: usdcMint,
112
+ amount: 5_000_000n, // 5 USDC when the mint has 6 decimals
113
+ owner,
114
+ signer: { publicKey: wallet.publicKey },
115
+ prover,
557
116
  });
558
117
  ```
559
118
 
560
- ---
119
+ Keep `result.note` private. It contains the information needed to recover the
120
+ shielded funds. `finalizeShield()` gives you the authoritative leaf index after
121
+ the transaction lands.
561
122
 
562
- ### 4.10 Proof Generation
123
+ If the blockhash expires before submission, reuse the proof with `rebuild()`:
563
124
 
564
125
  ```ts
565
- import {
566
- prepareTransactionInputs,
567
- formatInputsForSnarkjs,
568
- computeExtDataHash,
569
- encodeSnarkjsProofToTransactionProof,
570
- packProofToBytes,
571
- computeSwapParamsHash,
572
- computeSwapDataHash,
573
- type ExtData,
574
- type TransactionCircuitInputs,
575
- } from "@veilo/sdk-core";
576
-
577
- // Prepare inputs for the transaction circuit
578
- const circuitInputs: TransactionCircuitInputs = prepareTransactionInputs({
579
- root: tree.root(),
580
- publicAmount: 1_000_000_000n,
581
- extData: { recipient, relayer: relayerPubkey, fee: 0n, refund: 0n, claimant },
582
- mintAddress: NATIVE_SOL_MINT,
583
- inputs: [input1, input2],
584
- outputs: [output1, output2],
585
- inputTreeId: 0,
586
- outputTreeId: 0,
587
- });
126
+ import { rebuild } from "@veilo/sdk-core";
588
127
 
589
- // Format for snarkjs (converts bigints / Uint8Arrays to strings)
590
- const snarkjsInputs = formatInputsForSnarkjs(circuitInputs);
591
-
592
- // After proof generation:
593
- // const { proof } = await snarkjs.groth16.fullProve(snarkjsInputs, wasmPath, zkeyPath);
594
- // const transactionProof = encodeSnarkjsProofToTransactionProof(proof);
595
-
596
- // Compute ext data hash (matches on-chain computation)
597
- const extDataHash = computeExtDataHash({
598
- recipient,
599
- relayer,
600
- fee: 0n,
601
- refund: 0n,
602
- claimant,
603
- });
604
-
605
- // Compute swap param/data hashes (for swap circuit inputs)
606
- const swapParamsHash = computeSwapParamsHash(swapParams);
607
- const swapDataHash = computeSwapDataHash(jupiterInstructionBytes);
128
+ const refreshed = await rebuild(result, { connection });
608
129
  ```
609
130
 
610
- ---
131
+ A stale Merkle root needs a new call to `shield()` because it requires a new
132
+ proof.
611
133
 
612
- ### 4.11 Fee Utilities
134
+ ## Cloak Partner API
613
135
 
614
- ```ts
615
- import {
616
- computeWithdrawalFee,
617
- computeSwapFee,
618
- DEFAULT_FEE_BPS,
619
- } from "@veilo/sdk-core/config";
136
+ Cloak is the simplest route for partner applications that want a private send
137
+ or cross-asset private swap. The SDK handles request types, API authentication,
138
+ transaction decoding, polling, and structured errors. It never signs for the
139
+ user.
620
140
 
621
- // Compute protocol fee for a withdrawal
622
- const fee = computeWithdrawalFee(amount, feeBps, minWithdrawalFee);
141
+ Keep your Cloak API key on a trusted server. Do not include it in a browser or
142
+ mobile bundle.
623
143
 
624
- // Compute protocol fee for a swap
625
- const swapFee = computeSwapFee(swapAmount, feeBps);
626
- ```
627
-
628
- ---
629
-
630
- ### 4.12 Relayer & Admin Management
144
+ ### Create an order on your server
631
145
 
632
146
  ```ts
633
- import { addRelayer, setPaused } from "@veilo/sdk-core";
147
+ import { VeiloCloakClient } from "@veilo/sdk-core/cloak";
634
148
 
635
- // Authorise a new relayer for a pool
636
- await addRelayer({
637
- program,
638
- admin: adminKeypair,
639
- mintAddress: NATIVE_SOL_MINT,
640
- newRelayer: relayerPubkey,
149
+ const cloak = new VeiloCloakClient({
150
+ apiKey: process.env.VEILO_CLOAK_KEY!,
641
151
  });
642
152
 
643
- // Pause or unpause a pool
644
- await setPaused({
645
- program,
646
- admin: adminKeypair,
647
- mintAddress: NATIVE_SOL_MINT,
648
- paused: true,
153
+ // The production API defaults to https://api.veilo.network/.
154
+ const { quote } = await cloak.getQuote({
155
+ amount: "100000000", // raw token units
156
+ sourceAssetId: "veilo-usdc",
157
+ destinationAssetId: "veilo-usdc",
158
+ senderAddress,
159
+ recipientAddress,
160
+ mode: "exact_in",
649
161
  });
650
- ```
651
-
652
- ---
653
-
654
- ### 4.13 Poseidon Utilities
655
-
656
- ```ts
657
- import {
658
- initPoseidon,
659
- poseidon1,
660
- poseidon2,
661
- poseidon3,
662
- poseidon4,
663
- pubkeyToField,
664
- bytesToBigIntBE,
665
- bigIntToBytesBE,
666
- BN254_FR_MODULUS,
667
- } from "@veilo/sdk-core";
668
162
 
669
- // Must be called once before using hash functions
670
- await initPoseidon();
671
-
672
- const h1 = poseidon1(12345n);
673
- const h2 = poseidon2(12345n, 67890n);
674
- const h3 = poseidon3(12345n, 67890n, 11111n);
675
- const h4 = poseidon4(12345n, 67890n, 11111n, 22222n);
676
-
677
- // Convert a Solana PublicKey to a BN254 field element
678
- const field = pubkeyToField(NATIVE_SOL_MINT);
679
-
680
- // Byte ↔ bigint helpers (big-endian)
681
- const n = bytesToBigIntBE(bytes32);
682
- const b = bigIntToBytesBE(someField, 32);
683
- ```
684
-
685
- ---
686
-
687
- ### 4.14 Error Utilities
688
-
689
- ```ts
690
- import { parseOnChainError } from "@veilo/sdk-core";
691
-
692
- try {
693
- await transactSwap({ ... });
694
- } catch (err) {
695
- // Returns a human-readable error string from Anchor/program errors
696
- const msg = parseOnChainError(err);
697
- console.error("Swap failed:", msg);
698
- }
163
+ const { order } = await cloak.createOrder(
164
+ {
165
+ quote, // return the complete quote without changing it
166
+ senderAddress,
167
+ recipientAddress,
168
+ },
169
+ { idempotencyKey: crypto.randomUUID() },
170
+ );
699
171
  ```
700
172
 
701
- ---
702
-
703
- ## 5. Architecture
173
+ For a cross-asset swap, use a different `destinationAssetId` and optionally add
174
+ `slippageBps` to the quote request. Use `listTokens()` to discover supported
175
+ asset IDs and their current limits.
704
176
 
705
- ### Transaction Model
706
-
707
- Veilo uses a UTXO privacy model inspired by Zcash and Tornado Cash Nova:
708
-
709
- - **Inputs**: 2 UTXOs (zero-value for deposits)
710
- - **Outputs**: 2 UTXOs (zero-value for withdrawals)
711
- - **Public Amount**: net pool change — positive = deposit, negative = withdrawal, zero = private transfer or swap
712
-
713
- Each transaction consumes 2 input UTXOs (Merkle proofs), creates 2 output UTXOs (commitments inserted to tree), and generates 2 nullifiers to prevent double-spend.
714
-
715
- ### Swap Architecture
716
-
717
- Private swaps require two instructions in a **single atomic transaction**:
718
-
719
- 1. `fund_native_source` — pre-funds the swap executor with SOL from the vault (native SOL pools only)
720
- 2. `transact_swap` — verifies the ZK proof, spends input UTXOs, creates output UTXOs, and executes the DEX swap
721
-
722
- `transactSwap()` handles this automatically. The on-chain program validates atomicity via the instructions sysvar.
723
-
724
- ### Privacy Guarantees
725
-
726
- - **Commitment hiding**: amount, owner, blinding are hidden via Poseidon
727
- - **Nullifier uniqueness**: each UTXO can only be spent once
728
- - **Unlinkability**: no public link between inputs and outputs
729
- - **ZK proofs**: Groth16 verified on-chain
730
-
731
- ### Constants
177
+ You can override the API address for another environment. Both the origin and
178
+ the full Cloak path are accepted:
732
179
 
733
180
  ```ts
734
- import {
735
- NATIVE_SOL_MINT, // PublicKey.default native SOL pools
736
- MERKLE_TREE_DEPTH, // 22
737
- ROOT_HISTORY_SIZE, // 256
738
- DEFAULT_FEE_BPS, // 50 (0.5%)
739
- sol, // sol(1) === 1_000_000_000n
740
- } from "@veilo/sdk-core/config";
741
- ```
742
-
743
- ### Type Exports
744
-
745
- ```ts
746
- import type {
747
- // UTXO
748
- Keypair,
749
- UTXO,
750
- SerializedUTXO,
751
- InputUTXO,
752
- // Encryption
753
- EncryptedNote,
754
- BlindMailboxNote,
755
- BlindMailboxNoteData,
756
- DecryptedNote,
757
- // Proof
758
- ExtData,
759
- TransactionCircuitInputs,
760
- TransactionProofStruct,
761
- RawProof,
762
- TransactionProofBuilder,
763
- // Swap
764
- SwapProofStruct,
765
- SwapParams,
766
- // Tree / events
767
- MerklePath,
768
- CircuitMerklePath,
769
- TreeInfo,
770
- CommitmentEvent,
771
- NullifierSpentEvent,
772
- // Results
773
- DepositResult,
774
- WithdrawResult,
775
- TransferResult,
776
- // Config
777
- PoolInitConfig,
778
- PrivacyConfigAccount,
779
- GlobalConfigAccount,
780
- } from "@veilo/sdk-core";
781
- ```
782
-
783
- ---
784
-
785
- ## 6. Development
786
-
787
- ```bash
788
- # Run tests (requires devnet or local validator)
789
- npm test
790
- ```
791
-
792
- ---
793
-
794
- ## 7. Resources
795
-
796
- - **Repository**: https://github.com/VeiloSolana/veilo-sdk
797
- - **Circomlibjs**: https://github.com/iden3/circomlibjs
798
- - **Poseidon Hash**: https://www.poseidon-hash.info/
799
-
800
- ---
801
-
802
- ## License
803
-
804
- ISC
805
-
806
- This package provides a complete UTXO-based privacy protocol implementation on Solana with:
807
-
808
- - **UTXO Model**: Full support for unspent transaction outputs with Poseidon commitments
809
- - **Multi-Tree Support**: Multiple concurrent Merkle trees for improved scalability
810
- - **ZK Proofs**: Integration with Circom circuits for private transactions
811
- - **Flexible Operations**: Deposits, withdrawals, and private transfers
812
- - **Poseidon Hashing**: BN254-curve compatible hashing using circomlibjs
813
- - **Merkle Trees**: Off-chain Merkle tree management with proof generation
814
- - **Relayer Support**: Built-in relayer infrastructure for private withdrawals
815
-
816
- > **Status:** Active development. The SDK supports full transaction privacy with ZK-SNARK proofs.
817
- > Proofs are generated off-chain and verified on-chain using Groth16.
818
-
819
- ---
820
-
821
- ## 1. Installation
822
-
823
- ```bash
824
- npm install @veilo/sdk-core
825
- ```
826
-
827
- Or from source:
828
-
829
- ```bash
830
- cd core-sdk
831
- npm install
832
- ```
833
-
834
- ---
835
-
836
- ## 2. Prerequisites
837
-
838
- You need:
839
-
840
- - A running Solana validator (localnet/devnet/mainnet):
841
-
842
- ```bash
843
- solana-test-validator
844
- ```
845
-
846
- - The `privacy-pool` program deployed to the network
847
- - The `privacy-pool` Anchor IDL available:
848
-
849
- ```text
850
- idl/idl/privacy_pool.json
851
- ```
852
-
853
- - A funded keypair:
854
-
855
- ```bash
856
- solana config set --url http://127.0.0.1:8899
857
- solana-keygen new --outfile ~/.config/solana/id.json
858
- solana airdrop 10
859
- ```
860
-
861
- Environment variables:
862
-
863
- ```bash
864
- export ANCHOR_PROVIDER_URL=http://127.0.0.1:8899
865
- export ANCHOR_WALLET=$HOME/.config/solana/id.json
866
- ```
867
-
868
- ---
869
-
870
- ## 3. Build
871
-
872
- ```bash
873
- npm run build
181
+ new VeiloCloakClient({
182
+ baseUrl: "https://api.veilo.network/", // `/cloak/v1` also works here
183
+ apiKey: process.env.VEILO_CLOAK_KEY!,
184
+ });
874
185
  ```
875
186
 
876
- ---
187
+ ### Sign in the user's application
877
188
 
878
- ## 4. SDK API
879
-
880
- ### 4.1 PDA Helpers
189
+ Send the returned `order` to the user's application, then deserialize and sign
190
+ its transaction:
881
191
 
882
192
  ```ts
883
- import {
884
- getPoolPdas,
885
- getNoteTreePda,
886
- getGlobalConfigPda,
887
- getNullifierMarkerPda,
888
- } from "@veilo/sdk-core";
889
- import { PublicKey } from "@solana/web3.js";
890
-
891
- const programId = new PublicKey(
892
- "YourProgram1111111111111111111111111111111111",
893
- );
894
- const mintAddress = new PublicKey(
895
- "So11111111111111111111111111111111111111112",
896
- ); // Native SOL
897
-
898
- // Get pool PDAs
899
- const { config, vault, nullifiers } = getPoolPdas(programId, mintAddress);
193
+ import { deserializeCloakTransaction } from "@veilo/sdk-core/cloak";
900
194
 
901
- // Get note tree PDA for tree ID 0
902
- const noteTree = getNoteTreePda(programId, mintAddress, 0);
903
-
904
- // Get global config
905
- const globalConfig = getGlobalConfigPda(programId);
906
-
907
- // Get nullifier marker PDA
908
- const nullifier = new Uint8Array(32);
909
- const marker = getNullifierMarkerPda(programId, mintAddress, 0, nullifier);
195
+ const transaction = deserializeCloakTransaction(order);
196
+ const signed = await wallet.signTransaction(transaction);
197
+ const signature = await connection.sendRawTransaction(signed.serialize());
198
+ await connection.confirmTransaction(signature, "confirmed");
910
199
  ```
911
200
 
912
- **PDA seeds (v3):**
913
-
914
- - Config: `["privacy_config_v3", mint_address]`
915
- - Vault: `["privacy_vault_v3", mint_address]`
916
- - Note Tree: `["privacy_note_tree_v3", mint_address, tree_id]`
917
- - Nullifiers: `["privacy_nullifiers_v3", mint_address]`
918
- - Nullifier Marker: `["privacy_nullifier_v3", mint_address, tree_id, nullifier]`
919
- - Global Config: `["global_config_v1"]`
920
-
921
- ---
922
-
923
- ### 4.2 Pool Initialization
201
+ Send the signature back to your server. The deposit notification is optional,
202
+ but it can reduce processing latency:
924
203
 
925
204
  ```ts
926
- import * as anchor from "@coral-xyz/anchor";
927
- import {
928
- initializeGlobalConfig,
929
- initializePool,
930
- updatePoolConfig,
931
- addMerkleTree,
932
- getPoolConfig,
933
- } from "@veilo/sdk-core";
934
- import { NATIVE_SOL_MINT, sol } from "@veilo/sdk-core/config";
935
-
936
- // Initialize global config (once per program)
937
- await initializeGlobalConfig({
938
- program,
939
- admin: adminKeypair,
205
+ await cloak.notifyDeposit({
206
+ trackingId: order.trackingId,
207
+ txSignature: signature,
940
208
  });
941
209
 
942
- // Initialize a pool for native SOL
943
- await initializePool({
944
- program,
945
- payer: adminKeypair,
946
- admin: adminKeypair,
947
- mintAddress: NATIVE_SOL_MINT,
948
- minDepositAmount: sol(0.1), // 0.1 SOL
949
- maxDepositAmount: sol(100), // 100 SOL
950
- minWithdrawAmount: sol(0.1),
951
- maxWithdrawAmount: sol(100),
952
- feeBps: 50, // 0.5%
953
- feeErrorMarginBps: 10, // 0.1% margin
954
- minWithdrawalFee: 1_000_000n, // 0.001 SOL minimum
210
+ const finalStatus = await cloak.waitForFinalStatus(order.trackingId, {
211
+ intervalMs: 3_000,
212
+ timeoutMs: 20 * 60_000,
955
213
  });
956
214
 
957
- // Add first Merkle tree (tree ID 0)
958
- await addMerkleTree({
959
- program,
960
- payer: adminKeypair,
961
- mintAddress: NATIVE_SOL_MINT,
962
- treeId: 0,
963
- });
964
-
965
- // Update pool configuration
966
- await updatePoolConfig({
967
- program,
968
- admin: adminKeypair,
969
- mintAddress: NATIVE_SOL_MINT,
970
- feeBps: 30, // Change to 0.3%
971
- });
972
-
973
- // Read pool configuration
974
- const poolConfig = await getPoolConfig(program, NATIVE_SOL_MINT);
975
- console.log("TVL:", poolConfig.totalTvl);
976
- console.log("Fee:", poolConfig.feeBps, "bps");
977
- console.log("Num Trees:", poolConfig.numTrees);
215
+ console.log(finalStatus.status);
978
216
  ```
979
217
 
980
- ---
218
+ If an unfunded order's transaction expires, call
219
+ `refreshTransaction(order.trackingId)` and ask the user to sign the refreshed
220
+ transaction.
981
221
 
982
- ### 4.3 UTXO Management
222
+ ## Full private wallet flows
983
223
 
984
- The SDK uses a UTXO (Unspent Transaction Output) model with Poseidon commitments:
224
+ The SDK supports all Veilo privacy-pool operations. Pick the highest-level API
225
+ that fits your application:
985
226
 
986
- ```ts
987
- import {
988
- generateKeypair,
989
- keypairFromPrivateKey,
990
- createUTXO,
991
- createOwnedUTXO,
992
- createOwnedZeroUTXO,
993
- deriveNullifier,
994
- type Keypair,
995
- type UTXO,
996
- type SerializedUTXO,
997
- type InputUTXO,
998
- } from "@veilo/sdk-core";
999
- import { NATIVE_SOL_MINT } from "@veilo/sdk-core/config";
1000
- import { pubkeyToField } from "@veilo/sdk-core";
227
+ | Operation | Managed relayer call | Direct SDK helper |
228
+ | --- | --- | --- |
229
+ | Deposit | Not required | `shield()` or `deposit()` |
230
+ | Withdraw | `submitWithdraw()` | `withdraw()` |
231
+ | Private transfer | `submitPrivateTransfer()` | `privateTransfer()` |
232
+ | Private swap | `submitPrivateSwap()` | `buildPrivateSwapInstructions()` or `transactSwap()` |
1001
233
 
1002
- // Generate a random keypair
1003
- const keypair: Keypair = generateKeypair();
1004
- // keypair = { privateKey: bigint, publicKey: bigint }
234
+ ### Use the relayer client
1005
235
 
1006
- // Restore keypair from private key
1007
- const restored = keypairFromPrivateKey(privateKeyBigInt);
1008
-
1009
- // Create an owned UTXO (includes private key)
1010
- const ownedUtxo: SerializedUTXO = createOwnedUTXO({
1011
- amount: 1_000_000_000n,
1012
- privateKey: keypair.privateKey,
1013
- mintAddress: NATIVE_SOL_MINT,
1014
- });
1015
-
1016
- // Create a zero UTXO (for unused inputs/outputs)
1017
- const zeroUtxo = createOwnedZeroUTXO(pubkeyToField(NATIVE_SOL_MINT), keypair);
1018
-
1019
- // Derive nullifier for spending
1020
- const nullifier = deriveNullifier(
1021
- ownedUtxo.privateKey,
1022
- ownedUtxo.commitment,
1023
- 0, // pathIndex in Merkle tree
1024
- 0, // treeId
1025
- );
1026
- ```
1027
-
1028
- **UTXO commitment formula:**
1029
-
1030
- ```
1031
- commitment = Poseidon(amount, pubkey, blinding, mintAddress)
1032
- ```
1033
-
1034
- **Nullifier formula:**
1035
-
1036
- ```
1037
- nullifier = Poseidon(privateKey, commitment, pathIndex, treeId)
1038
- ```
1039
-
1040
- ---
1041
-
1042
- ### 4.4 Merkle Tree Operations
1043
-
1044
- ```ts
1045
- import { MerkleTree } from "@veilo/sdk-core";
1046
-
1047
- // Create a new Merkle tree (default depth: 20)
1048
- const tree = new MerkleTree();
1049
-
1050
- // Insert commitments
1051
- const index1 = tree.insert(ownedUtxo1.commitment);
1052
- const index2 = tree.insert(ownedUtxo2.commitment);
1053
-
1054
- // Get current root
1055
- const root = tree.root();
1056
-
1057
- // Get Merkle path for proof generation
1058
- const path = tree.path(index1);
1059
- // path = { pathElements: Uint8Array[], pathIndices: number[] }
1060
-
1061
- // Get number of leaves
1062
- const numLeaves = tree.totalLeaves;
1063
-
1064
- // Custom tree depth
1065
- const deepTree = new MerkleTree(25); // 25 levels
1066
- ```
1067
-
1068
- The Merkle tree uses Poseidon hash for all internal nodes.
1069
-
1070
- ---
1071
-
1072
- ### 4.5 Transaction Operations
1073
-
1074
- The SDK supports three types of transactions:
1075
-
1076
- #### Deposits (publicAmount > 0)
236
+ `VeiloRelayerClient` encrypts private transaction requests before sending them
237
+ to the relayer. The request and response types are exported for TypeScript
238
+ autocomplete.
1077
239
 
1078
240
  ```ts
1079
- import { deposit } from "@veilo/sdk-core";
1080
-
1081
- // Create output UTXO
1082
- const outputUtxo = createOwnedUTXO({
1083
- amount: 1_000_000_000n, // 1 SOL
1084
- mintAddress: pubkeyToField(NATIVE_SOL_MINT),
1085
- keypair: utxoKeypair,
1086
- });
1087
-
1088
- // Zero inputs for deposit
1089
- const input1 = createOwnedZeroUTXO(pubkeyToField(NATIVE_SOL_MINT), utxoKeypair);
1090
- const input2 = createOwnedZeroUTXO(pubkeyToField(NATIVE_SOL_MINT), utxoKeypair);
1091
- const output2 = createOwnedZeroUTXO(
1092
- pubkeyToField(NATIVE_SOL_MINT),
1093
- utxoKeypair,
1094
- );
241
+ import {
242
+ VeiloRelayerClient,
243
+ type WithdrawRequest,
244
+ } from "@veilo/sdk-core/relayer";
1095
245
 
1096
- await deposit({
1097
- program,
1098
- depositor: depositorKeypair,
1099
- mintAddress: NATIVE_SOL_MINT,
1100
- inputTreeId: 0,
1101
- outputTreeId: 0,
1102
- root: tree.root(),
1103
- publicAmount: 1_000_000_000n, // Positive = deposit
1104
- inputs: [input1, input2],
1105
- outputs: [outputUtxo, output2],
1106
- recipient: depositorKeypair.publicKey,
1107
- fee: 0n,
1108
- refund: 0n,
1109
- proof: mockProof,
246
+ const relayer = new VeiloRelayerClient({
247
+ apiKey: process.env.VEILO_RELAYER_KEY!,
248
+ relayerPublicKey: process.env.VEILO_RELAYER_PUBLIC_KEY!,
249
+ authToken: process.env.VEILO_AUTH_TOKEN,
1110
250
  });
1111
251
 
1112
- // Insert outputs into tree
1113
- tree.insert(outputUtxo.commitment);
1114
- tree.insert(output2.commitment);
252
+ async function submitWithdrawal(request: WithdrawRequest) {
253
+ return relayer.submitWithdraw(request);
254
+ }
1115
255
  ```
1116
256
 
1117
- #### Withdrawals (publicAmount < 0)
257
+ The same client also provides account authentication, encrypted note storage,
258
+ Merkle tree reads, private transfers, and private swaps.
1118
259
 
1119
- ```ts
1120
- import { withdraw } from "@veilo/sdk-core";
1121
-
1122
- // Prepare input with Merkle path
1123
- const input1: InputUTXO = {
1124
- ...ownedUtxo1,
1125
- pathIndex: 0,
1126
- pathElements: tree.path(0).pathElements,
1127
- };
1128
-
1129
- const zeroInput2: InputUTXO = {
1130
- ...createOwnedZeroUTXO(pubkeyToField(NATIVE_SOL_MINT), utxoKeypair),
1131
- pathIndex: 0,
1132
- pathElements: tree.path(0).pathElements,
1133
- };
1134
-
1135
- // Zero outputs
1136
- const output1 = createOwnedZeroUTXO(
1137
- pubkeyToField(NATIVE_SOL_MINT),
1138
- utxoKeypair,
1139
- );
1140
- const output2 = createOwnedZeroUTXO(
1141
- pubkeyToField(NATIVE_SOL_MINT),
1142
- utxoKeypair,
1143
- );
260
+ ### Use the direct helpers
1144
261
 
1145
- await withdraw({
1146
- program,
1147
- relayer: relayerKeypair,
1148
- mintAddress: NATIVE_SOL_MINT,
1149
- inputTreeId: 0,
1150
- outputTreeId: 0,
1151
- root: tree.root(),
1152
- publicAmount: -900_000_000n, // Negative = withdrawal (0.9 SOL)
1153
- inputs: [input1, zeroInput2],
1154
- outputs: [output1, output2],
1155
- recipient: recipientKeypair.publicKey,
1156
- fee: 100_000_000n, // 0.1 SOL to relayer
1157
- refund: 0n,
1158
- proof,
1159
- });
1160
- ```
1161
-
1162
- #### Private Transfers (publicAmount = 0)
262
+ Direct helpers are intended for applications that already maintain Veilo note
263
+ and Merkle tree state and can generate proofs.
1163
264
 
1164
265
  ```ts
1165
266
  import {
1166
- privateTransfer,
1167
- generateKeypair,
1168
- createOwnedUTXO,
267
+ NATIVE_SOL_MINT,
268
+ createTransactionProver,
269
+ createVeiloProgram,
270
+ deposit,
1169
271
  } from "@veilo/sdk-core";
1170
272
 
1171
- // Create new outputs for recipient
1172
- const recipientKeypair = generateKeypair();
1173
- const output1 = createOwnedUTXO({
1174
- amount: 1_000_000_000n,
1175
- privateKey: recipientKeypair.privateKey,
1176
- mintAddress: NATIVE_SOL_MINT,
273
+ const program = createVeiloProgram(connection, anchorWallet);
274
+ const proofBuilder = createTransactionProver({
275
+ wasmPath: "/circuits/transaction.wasm",
276
+ zkeyPath: "/circuits/transaction_final.zkey",
1177
277
  });
1178
278
 
1179
- await privateTransfer({
279
+ const built = await deposit({
1180
280
  program,
1181
- relayer: relayerKeypair,
281
+ depositor: { publicKey: wallet.publicKey },
1182
282
  mintAddress: NATIVE_SOL_MINT,
1183
- inputTreeId: 0,
1184
- outputTreeId: 0,
1185
- root: tree.root(),
1186
- publicAmount: 0n, // Zero = private transfer
1187
- inputs: [input1, zeroInput2],
1188
- outputs: [output1, output2],
1189
- recipient: relayerKeypair.publicKey,
1190
- fee: 0n,
1191
- refund: 0n,
1192
- proof,
283
+ amount: 1_000_000_000n,
284
+ recipientPubkey: veiloOwnerPublicKey,
285
+ noteRecipientWallet: wallet.publicKey,
286
+ tree,
287
+ proofBuilder,
288
+ treeId: 0,
1193
289
  });
1194
290
 
1195
- // Insert new outputs
1196
- tree.insert(output1.commitment);
1197
- tree.insert(output2.commitment);
291
+ const signed = await wallet.signTransaction(built.transaction);
292
+ const signature = await connection.sendRawTransaction(signed.serialize());
293
+ await connection.confirmTransaction(signature, "confirmed");
294
+
295
+ // Update the local tree only after on-chain confirmation.
296
+ const receipt = built.commit();
1198
297
  ```
1199
298
 
1200
- #### Low-Level Transaction Function
299
+ `withdraw()` and `privateTransfer()` accept two spendable input notes, build the
300
+ proof, submit through the supplied relayer signer, and return the resulting
301
+ change or output notes. Important rules are enforced by the SDK:
1201
302
 
1202
- For advanced use cases, use the unified `transact` function directly:
303
+ - withdrawal amounts must be positive and fit within the selected notes;
304
+ - private-transfer outputs must equal the total input amount;
305
+ - direct private transfers use a zero public fee;
306
+ - note-recipient wallet keys should be supplied so new notes remain recoverable.
1203
307
 
1204
- ```ts
1205
- import { transact } from "@veilo/sdk-core";
308
+ Private swaps normally use Jupiter versioned transactions and address lookup
309
+ tables. Use `buildPrivateSwapInstructions()` to add Veilo's atomic instructions
310
+ to the exact Jupiter route. Preserve Jupiter's account order and duplicate
311
+ accounts. `transactSwap()` is available when a legacy transaction is sufficient.
1206
312
 
1207
- await transact({
1208
- program,
1209
- relayer: relayerKeypair,
1210
- mintAddress: NATIVE_SOL_MINT,
1211
- inputTreeId: 0,
1212
- outputTreeId: 0,
1213
- root: tree.root(),
1214
- publicAmount: 0n,
1215
- inputNullifiers: [nullifier1, nullifier2],
1216
- outputCommitments: [output1.commitment, output2.commitment],
1217
- extData: {
1218
- recipient: recipientPubkey,
1219
- relayer: relayerPubkey,
1220
- fee: 0n,
1221
- refund: 0n,
1222
- claimant: claimantPubkey,
1223
- },
1224
- proof,
1225
- });
1226
- ```
313
+ The low-level `transact()` and `buildRawTransactInstruction()` exports are for
314
+ custom transaction composition. Most applications should use the helpers above.
1227
315
 
1228
- ---
316
+ ## Important concepts
1229
317
 
1230
- ### 4.6 Proof Generation
318
+ ### Amounts use base units
1231
319
 
1232
- The SDK provides utilities for preparing circuit inputs:
320
+ Amounts are `bigint` values or decimal strings in the token's smallest unit:
1233
321
 
1234
322
  ```ts
1235
- import {
1236
- prepareTransactionInputs,
1237
- formatInputsForSnarkjs,
1238
- computeExtDataHash,
1239
- encodeSnarkjsProofToTransactionProof,
1240
- packProofToBytes,
1241
- type ExtData,
1242
- type TransactionCircuitInputs,
1243
- } from "@veilo/sdk-core";
323
+ import { sol } from "@veilo/sdk-core/config";
1244
324
 
1245
- // Prepare inputs for the circuit
1246
- const circuitInputs: TransactionCircuitInputs = prepareTransactionInputs({
1247
- root: tree.root(),
1248
- publicAmount: 1_000_000_000n,
1249
- extData: {
1250
- recipient: recipientPubkey,
1251
- relayer: relayerPubkey,
1252
- fee: 0n,
1253
- refund: 0n,
1254
- claimant: claimantPubkey,
1255
- },
1256
- mintAddress: NATIVE_SOL_MINT,
1257
- inputs: [input1, input2],
1258
- outputs: [output1, output2],
1259
- inputTreeId: 0,
1260
- outputTreeId: 0,
1261
- });
325
+ const oneSol = sol(1); // 1_000_000_000n lamports
326
+ const fiveUsdc = 5_000_000n; // 5 USDC for a 6-decimal mint
327
+ ```
1262
328
 
1263
- // Format for snarkjs (converts Uint8Array to string representations)
1264
- const snarkjsInputs = formatInputsForSnarkjs(circuitInputs);
329
+ Avoid JavaScript floating-point values for token arithmetic.
1265
330
 
1266
- // Use with snarkjs to generate proof
1267
- // const { proof, publicSignals } = await snarkjs.groth16.fullProve(
1268
- // snarkjsInputs,
1269
- // wasmPath,
1270
- // zkeyPath
1271
- // );
331
+ ### A private note is valuable secret data
1272
332
 
1273
- // Convert snarkjs proof to on-chain format
1274
- // const transactionProof = encodeSnarkjsProofToTransactionProof(proof);
1275
- ```
333
+ A note contains the information needed to locate and spend private funds. Store
334
+ it encrypted, never log it, and never send its unencrypted contents to an
335
+ analytics or application server.
1276
336
 
1277
- ---
337
+ For shielding, prefer `resolveShieldOwner()`. It obtains the spending and note
338
+ viewing keys as a matched pair. Supplying unrelated keys can create a note that
339
+ the recipient cannot discover.
1278
340
 
1279
- ### 4.7 Relayer Management
341
+ ### Confirmation comes before local state updates
1280
342
 
1281
- ```ts
1282
- import { addRelayer, setPaused } from "@veilo/sdk-core";
343
+ Do not mark notes as spent, insert commitments into a local tree, or persist a
344
+ predicted leaf index until the transaction is confirmed. Use `finalizeShield()`
345
+ for shields and call a deposit's `commit()` callback only after confirmation.
1283
346
 
1284
- // Add a relayer
1285
- await addRelayer({
1286
- program,
1287
- admin: adminKeypair,
1288
- mintAddress: NATIVE_SOL_MINT,
1289
- newRelayer: relayerPubkey,
1290
- });
347
+ ### Proof files are separate
1291
348
 
1292
- // Pause/unpause the pool
1293
- await setPaused({
1294
- program,
1295
- admin: adminKeypair,
1296
- mintAddress: NATIVE_SOL_MINT,
1297
- paused: true,
1298
- });
1299
- ```
349
+ Circuit `.wasm` and `.zkey` files are intentionally not bundled with the npm
350
+ package because they are large. Provide local paths, byte arrays, or hosted URLs
351
+ to `createTransactionProver()` and `createSwapProver()`.
1300
352
 
1301
- ---
353
+ ## Error handling
1302
354
 
1303
- ### 4.8 Poseidon Utilities
355
+ Shield and Cloak errors include stable fields that applications can use to show
356
+ useful recovery actions.
1304
357
 
1305
358
  ```ts
1306
359
  import {
1307
- initPoseidon,
1308
- poseidon1,
1309
- poseidon2,
1310
- poseidon3,
1311
- poseidon4,
1312
- pubkeyToField,
360
+ CloakApiError,
361
+ mapShieldError,
1313
362
  } from "@veilo/sdk-core";
1314
363
 
1315
- // Initialize Poseidon (required once before using hash functions)
1316
- await initPoseidon();
1317
-
1318
- // Hash functions
1319
- const hash1 = poseidon1(12345n);
1320
- const hash2 = poseidon2(12345n, 67890n);
1321
- const hash3 = poseidon3(12345n, 67890n, 11111n);
1322
- const hash4 = poseidon4(12345n, 67890n, 11111n, 22222n);
1323
-
1324
- // Convert Solana PublicKey to field element
1325
- const fieldElement = pubkeyToField(NATIVE_SOL_MINT);
364
+ try {
365
+ // Build or submit a Veilo operation.
366
+ } catch (error) {
367
+ if (error instanceof CloakApiError) {
368
+ console.error(error.code, error.status, error.message);
369
+ } else {
370
+ const shieldError = mapShieldError(error);
371
+ console.error(shieldError.code, shieldError.message);
372
+ // retryable is `rebuild`, `reshield`, or `none`.
373
+ console.log(shieldError.retryable);
374
+ }
375
+ }
1326
376
  ```
1327
377
 
1328
- ---
1329
-
1330
- ## 5. Architecture
1331
-
1332
- ### Transaction Model
378
+ When handling Cloak separately, `CloakApiError` also exposes actionable values
379
+ such as `min`, `max`, `field`, `maxBps`, and `retryAfter` when the API returns
380
+ them.
1333
381
 
1334
- Veilo uses a UTXO-based privacy model inspired by Zcash and Tornado Cash Nova:
382
+ ## Package entry points
1335
383
 
1336
- 1. **Inputs**: 2 UTXOs (can be zero for deposits)
1337
- 2. **Outputs**: 2 UTXOs (can be zero for withdrawals)
1338
- 3. **Public Amount**: Net change (positive = deposit, negative = withdrawal, zero = private transfer)
1339
-
1340
- Each transaction:
1341
-
1342
- - Consumes 2 input UTXOs (proven via Merkle paths)
1343
- - Creates 2 output UTXOs (commitments added to tree)
1344
- - Generates 2 nullifiers (prevents double-spending)
1345
- - Optionally transfers funds in/out of the pool
1346
-
1347
- ### Privacy Guarantees
1348
-
1349
- - **Commitment hiding**: Amount, owner, and blinding factor are hidden via Poseidon hash
1350
- - **Nullifier uniqueness**: Each UTXO can only be spent once
1351
- - **Unlinkability**: No public link between inputs and outputs
1352
- - **Zero-knowledge proofs**: Transactions proven valid without revealing private data
1353
-
1354
- ### Multi-Tree Support
1355
-
1356
- The protocol supports multiple concurrent Merkle trees per pool:
1357
-
1358
- - Improves scalability by reducing tree depth
1359
- - Allows parallel insertions
1360
- - Each tree has independent state
1361
-
1362
- ### Constants
384
+ Import from the package root for convenience or use a focused entry point:
1363
385
 
1364
386
  ```ts
1365
- import {
1366
- NATIVE_SOL_MINT, // PublicKey.default (all zeros) for native SOL
1367
- MERKLE_TREE_DEPTH, // 22 levels
1368
- ROOT_HISTORY_SIZE, // 256 historical roots
1369
- DEFAULT_FEE_BPS, // 50 (0.5%)
1370
- sol, // Helper: sol(1) = 1_000_000_000n lamports
1371
- } from "@veilo/sdk-core/config";
1372
-
1373
- import { BN254_FR_MODULUS } from "@veilo/sdk-core";
387
+ import { shield } from "@veilo/sdk-core";
388
+ import { getPoolPdas } from "@veilo/sdk-core/accounts";
389
+ import { createUTXO } from "@veilo/sdk-core/notes";
390
+ import { deposit, withdraw } from "@veilo/sdk-core/transactions";
391
+ import { VeiloRelayerClient } from "@veilo/sdk-core/relayer";
392
+ import { VeiloCloakClient } from "@veilo/sdk-core/cloak";
1374
393
  ```
1375
394
 
1376
- ### Type Exports
395
+ Available focused entry points:
1377
396
 
1378
- The SDK exports the following types for TypeScript users:
397
+ - `@veilo/sdk-core/accounts`
398
+ - `@veilo/sdk-core/cloak`
399
+ - `@veilo/sdk-core/config`
400
+ - `@veilo/sdk-core/notes`
401
+ - `@veilo/sdk-core/poseidon`
402
+ - `@veilo/sdk-core/proof`
403
+ - `@veilo/sdk-core/prover`
404
+ - `@veilo/sdk-core/relayer`
405
+ - `@veilo/sdk-core/shield`
406
+ - `@veilo/sdk-core/transactions`
1379
407
 
1380
- ```ts
1381
- import type {
1382
- // UTXO types
1383
- Keypair,
1384
- UTXO,
1385
- SerializedUTXO,
1386
- InputUTXO,
1387
-
1388
- // Proof types
1389
- ExtData,
1390
- TransactionCircuitInputs,
1391
- TransactionProofStruct,
1392
- RawProof,
1393
- TransactionProofBuilder,
1394
-
1395
- // Merkle types
1396
- MerklePath,
1397
- CircuitMerklePath,
1398
-
1399
- // Config types
1400
- PoolInitConfig,
1401
- PrivacyConfigAccount,
1402
- GlobalConfigAccount,
1403
- } from "@veilo/sdk-core";
1404
- ```
1405
-
1406
- ### SPL Token Support
408
+ ## Advanced building blocks
1407
409
 
1408
- The SDK supports both native SOL and SPL tokens:
410
+ The root package also exports tools for teams building their own Veilo wallet
411
+ or relayer:
1409
412
 
1410
- ```ts
1411
- import { PublicKey } from "@solana/web3.js";
413
+ - account and PDA queries;
414
+ - UTXO creation, ownership, encryption, and recovery;
415
+ - Merkle tree reconstruction from on-chain events;
416
+ - transaction and swap witness preparation;
417
+ - Poseidon hashing helpers;
418
+ - pool initialization and administration;
419
+ - raw IDL-correct transaction instruction builders.
1412
420
 
1413
- // For native SOL
1414
- const solMint = NATIVE_SOL_MINT; // PublicKey.default
421
+ These APIs are fully typed. Use their TypeScript definitions as the source of
422
+ truth for required inputs.
1415
423
 
1416
- // For SPL tokens
1417
- const usdcMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
1418
-
1419
- // Initialize pool for SPL token
1420
- await initializePool({
1421
- program,
1422
- payer: adminKeypair,
1423
- admin: adminKeypair,
1424
- mintAddress: usdcMint, // Use SPL token mint
1425
- minDepositAmount: 1_000_000n, // 1 USDC (6 decimals)
1426
- // ... other params
1427
- });
1428
- ```
1429
-
1430
- When using SPL tokens, the SDK automatically handles associated token accounts.
1431
-
1432
- ---
1433
-
1434
- ## 6. Development
1435
-
1436
- ### Environment Variables
424
+ ## Development
1437
425
 
1438
426
  ```bash
1439
- export ANCHOR_PROVIDER_URL=http://127.0.0.1:8899
1440
- export ANCHOR_WALLET=$HOME/.config/solana/id.json
1441
- ```
1442
-
1443
- ---
427
+ # Build CommonJS, ESM, and declaration outputs
428
+ npm run build
1444
429
 
1445
- ## 7. Limitations
430
+ # Run deterministic unit and proof tests
431
+ npm test
1446
432
 
1447
- - **Off-chain tree management**: Merkle trees must be maintained by relayers/clients
1448
- - **Proof generation not included**: You must integrate your own circuit/prover
1449
- - **Development status**: Active development, APIs may change
433
+ # Run opt-in live Devnet integration tests
434
+ npm run test:integration
1450
435
 
1451
- ---
436
+ # Check module boundaries for dependency cycles
437
+ npm run check:cycles
438
+ ```
1452
439
 
1453
- ## 8. Resources
440
+ ## Support
1454
441
 
1455
- - **Repository**: https://github.com/VeiloSolana/veilo-sdk
1456
- - **Circomlibjs**: https://github.com/iden3/circomlibjs
1457
- - **Poseidon Hash**: https://www.poseidon-hash.info/
442
+ - [Repository](https://github.com/VeiloSolana/veilo-sdk)
443
+ - [Issue tracker](https://github.com/VeiloSolana/veilo-sdk/issues)
1458
444
 
1459
- ---
445
+ When reporting a problem, include the SDK version, runtime, Solana cluster, and
446
+ the error's `code` and `status` or `programCode` where available. Never include
447
+ private notes, wallet secret keys, API keys, or authentication tokens.
1460
448
 
1461
449
  ## License
1462
450
 
1463
- ISC
451
+ [ISC](./LICENSE)