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