@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.
- package/LICENSE +15 -0
- package/README.md +289 -1262
- package/dist/cjs/accounts/admin.d.ts +84 -0
- package/dist/cjs/accounts/admin.js +208 -0
- package/dist/cjs/accounts/errors.d.ts +6 -0
- package/dist/cjs/accounts/errors.js +98 -0
- package/dist/cjs/accounts/index.d.ts +4 -0
- package/dist/cjs/accounts/index.js +20 -0
- package/dist/cjs/accounts/pdas.d.ts +23 -0
- package/dist/cjs/accounts/pdas.js +44 -0
- package/dist/cjs/accounts/queries.d.ts +41 -0
- package/dist/cjs/accounts/queries.js +95 -0
- package/dist/cjs/client.d.ts +2 -407
- package/dist/cjs/client.js +17 -912
- package/dist/cjs/cloak/client.d.ts +28 -0
- package/dist/cjs/cloak/client.js +68 -0
- package/dist/cjs/cloak/errors.d.ts +13 -0
- package/dist/cjs/cloak/errors.js +25 -0
- package/dist/cjs/cloak/helpers.d.ts +6 -0
- package/dist/cjs/cloak/helpers.js +35 -0
- package/dist/cjs/cloak/index.d.ts +6 -0
- package/dist/cjs/cloak/index.js +24 -0
- package/dist/cjs/cloak/polling.d.ts +7 -0
- package/dist/cjs/cloak/polling.js +66 -0
- package/dist/cjs/cloak/transport.d.ts +15 -0
- package/dist/cjs/cloak/transport.js +119 -0
- package/dist/cjs/cloak/types.d.ts +188 -0
- package/dist/cjs/cloak/types.js +5 -0
- package/dist/cjs/cloak.d.ts +1 -0
- package/dist/cjs/cloak.js +18 -0
- package/dist/cjs/compactNote.d.ts +128 -0
- package/dist/cjs/compactNote.js +191 -0
- package/dist/cjs/events.d.ts +1 -1
- package/dist/cjs/events.js +2 -2
- package/dist/cjs/idl/privacy_pool.d.ts +5 -0
- package/dist/cjs/idl/privacy_pool.js +15218 -0
- package/dist/cjs/index.d.ts +17 -13
- package/dist/cjs/index.js +43 -30
- package/dist/cjs/merkle.d.ts +13 -0
- package/dist/cjs/merkle.js +31 -8
- package/dist/cjs/notes/encryption.d.ts +41 -0
- package/dist/cjs/notes/encryption.js +75 -0
- package/dist/cjs/notes/index.d.ts +5 -0
- package/dist/cjs/notes/index.js +21 -0
- package/dist/cjs/notes/mailbox.d.ts +70 -0
- package/dist/cjs/notes/mailbox.js +164 -0
- package/dist/cjs/notes/model.d.ts +91 -0
- package/dist/cjs/notes/model.js +109 -0
- package/dist/cjs/notes/nullifier.d.ts +27 -0
- package/dist/cjs/notes/nullifier.js +45 -0
- package/dist/cjs/notes/recovery.d.ts +10 -0
- package/dist/cjs/notes/recovery.js +31 -0
- package/dist/cjs/program.d.ts +11 -0
- package/dist/cjs/program.js +26 -3
- package/dist/cjs/proof.d.ts +1 -183
- package/dist/cjs/proof.js +16 -290
- package/dist/cjs/proofs/encoding.d.ts +17 -0
- package/dist/cjs/proofs/encoding.js +72 -0
- package/dist/cjs/proofs/formatting.d.ts +6 -0
- package/dist/cjs/proofs/formatting.js +34 -0
- package/dist/cjs/proofs/index.d.ts +5 -0
- package/dist/cjs/proofs/index.js +21 -0
- package/dist/cjs/proofs/swap.d.ts +87 -0
- package/dist/cjs/proofs/swap.js +144 -0
- package/dist/cjs/proofs/transaction.d.ts +28 -0
- package/dist/cjs/proofs/transaction.js +110 -0
- package/dist/cjs/proofs/types.d.ts +70 -0
- package/dist/cjs/proofs/types.js +2 -0
- package/dist/cjs/prover.d.ts +4 -1
- package/dist/cjs/prover.js +12 -2
- package/dist/cjs/random.d.ts +16 -0
- package/dist/cjs/random.js +28 -0
- package/dist/cjs/relayer/client.d.ts +61 -0
- package/dist/cjs/relayer/client.js +151 -0
- package/dist/cjs/relayer/crypto.d.ts +5 -0
- package/dist/cjs/relayer/crypto.js +26 -0
- package/dist/cjs/relayer/encoding.d.ts +2 -0
- package/dist/cjs/relayer/encoding.js +23 -0
- package/dist/cjs/relayer/errors.d.ts +7 -0
- package/dist/cjs/relayer/errors.js +17 -0
- package/dist/cjs/relayer/index.d.ts +3 -0
- package/dist/cjs/relayer/index.js +19 -0
- package/dist/cjs/relayer/transport.d.ts +17 -0
- package/dist/cjs/relayer/transport.js +63 -0
- package/dist/cjs/relayer/types.d.ts +276 -0
- package/dist/cjs/relayer/types.js +5 -0
- package/dist/cjs/relayer.d.ts +1 -295
- package/dist/cjs/relayer.js +15 -243
- package/dist/cjs/shield/alt.d.ts +87 -0
- package/dist/cjs/shield/alt.js +194 -0
- package/dist/cjs/shield/computeBudget.d.ts +61 -0
- package/dist/cjs/shield/computeBudget.js +64 -0
- package/dist/cjs/shield/errors.d.ts +58 -0
- package/dist/cjs/shield/errors.js +121 -0
- package/dist/cjs/shield/finalize.d.ts +45 -0
- package/dist/cjs/shield/finalize.js +119 -0
- package/dist/cjs/shield/index.d.ts +35 -0
- package/dist/cjs/shield/index.js +68 -0
- package/dist/cjs/shield/ix.d.ts +54 -0
- package/dist/cjs/shield/ix.js +119 -0
- package/dist/cjs/shield/owner.d.ts +36 -0
- package/dist/cjs/shield/owner.js +127 -0
- package/dist/cjs/shield/ports.d.ts +43 -0
- package/dist/cjs/shield/ports.js +153 -0
- package/dist/cjs/shield/preflight.d.ts +30 -0
- package/dist/cjs/shield/preflight.js +154 -0
- package/dist/cjs/shield/shield.d.ts +68 -0
- package/dist/cjs/shield/shield.js +500 -0
- package/dist/cjs/shield/types.d.ts +202 -0
- package/dist/cjs/shield/types.js +2 -0
- package/dist/cjs/transactions/deposit.d.ts +94 -0
- package/dist/cjs/transactions/deposit.js +234 -0
- package/dist/cjs/transactions/index.d.ts +7 -0
- package/dist/cjs/transactions/index.js +26 -0
- package/dist/cjs/transactions/swap.d.ts +71 -0
- package/dist/cjs/transactions/swap.js +184 -0
- package/dist/cjs/transactions/transact.d.ts +34 -0
- package/dist/cjs/transactions/transact.js +146 -0
- package/dist/cjs/transactions/transfer.d.ts +51 -0
- package/dist/cjs/transactions/transfer.js +106 -0
- package/dist/cjs/transactions/withdraw.d.ts +52 -0
- package/dist/cjs/transactions/withdraw.js +104 -0
- package/dist/cjs/utxo.d.ts +1 -215
- package/dist/cjs/utxo.js +15 -391
- package/dist/esm/accounts/admin.d.ts +84 -0
- package/dist/esm/accounts/admin.js +165 -0
- package/dist/esm/accounts/errors.d.ts +6 -0
- package/dist/esm/accounts/errors.js +95 -0
- package/dist/esm/accounts/index.d.ts +4 -0
- package/dist/esm/accounts/index.js +4 -0
- package/dist/esm/accounts/pdas.d.ts +23 -0
- package/dist/esm/accounts/pdas.js +38 -0
- package/dist/esm/accounts/queries.d.ts +41 -0
- package/dist/esm/accounts/queries.js +88 -0
- package/dist/esm/client.d.ts +2 -0
- package/dist/esm/client.js +3 -887
- package/dist/esm/cloak/client.d.ts +28 -0
- package/dist/esm/cloak/client.js +64 -0
- package/dist/esm/cloak/errors.d.ts +13 -0
- package/dist/esm/cloak/errors.js +21 -0
- package/dist/esm/cloak/helpers.d.ts +6 -0
- package/dist/esm/cloak/helpers.js +31 -0
- package/dist/esm/cloak/index.d.ts +6 -0
- package/dist/esm/cloak/index.js +6 -0
- package/dist/esm/cloak/polling.d.ts +7 -0
- package/dist/esm/cloak/polling.js +63 -0
- package/dist/esm/cloak/transport.d.ts +15 -0
- package/dist/esm/cloak/transport.js +115 -0
- package/dist/esm/cloak/types.d.ts +188 -0
- package/dist/esm/cloak/types.js +4 -0
- package/dist/esm/cloak.d.ts +1 -0
- package/dist/esm/cloak.js +2 -0
- package/dist/esm/compactNote.d.ts +128 -0
- package/dist/esm/compactNote.js +179 -0
- package/dist/esm/config.d.ts +82 -0
- package/dist/esm/events.d.ts +77 -0
- package/dist/esm/events.js +1 -1
- package/dist/esm/idl/privacy_pool.d.ts +5 -0
- package/dist/esm/idl/privacy_pool.js +15216 -0
- package/dist/esm/index.d.ts +17 -0
- package/dist/esm/index.js +20 -11
- package/dist/esm/merkle.d.ts +77 -0
- package/dist/esm/merkle.js +23 -1
- package/dist/esm/notes/encryption.d.ts +41 -0
- package/dist/esm/notes/encryption.js +67 -0
- package/dist/esm/notes/index.d.ts +5 -0
- package/dist/esm/notes/index.js +5 -0
- package/dist/esm/notes/mailbox.d.ts +70 -0
- package/dist/esm/notes/mailbox.js +154 -0
- package/dist/esm/notes/model.d.ts +91 -0
- package/dist/esm/notes/model.js +99 -0
- package/dist/esm/notes/nullifier.d.ts +27 -0
- package/dist/esm/notes/nullifier.js +40 -0
- package/dist/esm/notes/recovery.d.ts +10 -0
- package/dist/esm/notes/recovery.js +28 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/poseidon.d.ts +29 -0
- package/dist/esm/program.d.ts +37 -0
- package/dist/esm/program.js +23 -1
- package/dist/esm/proof.d.ts +1 -0
- package/dist/esm/proof.js +2 -281
- package/dist/esm/proofs/encoding.d.ts +17 -0
- package/dist/esm/proofs/encoding.js +68 -0
- package/dist/esm/proofs/formatting.d.ts +6 -0
- package/dist/esm/proofs/formatting.js +31 -0
- package/dist/esm/proofs/index.d.ts +5 -0
- package/dist/esm/proofs/index.js +5 -0
- package/dist/esm/proofs/swap.d.ts +87 -0
- package/dist/esm/proofs/swap.js +138 -0
- package/dist/esm/proofs/transaction.d.ts +28 -0
- package/dist/esm/proofs/transaction.js +105 -0
- package/dist/esm/proofs/types.d.ts +70 -0
- package/dist/esm/proofs/types.js +1 -0
- package/dist/esm/prover.d.ts +57 -0
- package/dist/esm/prover.js +10 -1
- package/dist/esm/random.d.ts +16 -0
- package/dist/esm/random.js +21 -0
- package/dist/esm/relayer/client.d.ts +61 -0
- package/dist/esm/relayer/client.js +144 -0
- package/dist/esm/relayer/crypto.d.ts +5 -0
- package/dist/esm/relayer/crypto.js +20 -0
- package/dist/esm/relayer/encoding.d.ts +2 -0
- package/dist/esm/relayer/encoding.js +19 -0
- package/dist/esm/relayer/errors.d.ts +7 -0
- package/dist/esm/relayer/errors.js +13 -0
- package/dist/esm/relayer/index.d.ts +3 -0
- package/dist/esm/relayer/index.js +3 -0
- package/dist/esm/relayer/transport.d.ts +17 -0
- package/dist/esm/relayer/transport.js +59 -0
- package/dist/esm/relayer/types.d.ts +276 -0
- package/dist/esm/relayer/types.js +4 -0
- package/dist/esm/relayer.d.ts +1 -0
- package/dist/esm/relayer.js +2 -238
- package/dist/esm/retry.d.ts +32 -0
- package/dist/esm/shield/alt.d.ts +87 -0
- package/dist/esm/shield/alt.js +186 -0
- package/dist/esm/shield/computeBudget.d.ts +61 -0
- package/dist/esm/shield/computeBudget.js +61 -0
- package/dist/esm/shield/errors.d.ts +58 -0
- package/dist/esm/shield/errors.js +115 -0
- package/dist/esm/shield/finalize.d.ts +45 -0
- package/dist/esm/shield/finalize.js +83 -0
- package/dist/esm/shield/index.d.ts +35 -0
- package/dist/esm/shield/index.js +32 -0
- package/dist/esm/shield/ix.d.ts +54 -0
- package/dist/esm/shield/ix.js +82 -0
- package/dist/esm/shield/owner.d.ts +36 -0
- package/dist/esm/shield/owner.js +123 -0
- package/dist/esm/shield/ports.d.ts +43 -0
- package/dist/esm/shield/ports.js +147 -0
- package/dist/esm/shield/preflight.d.ts +30 -0
- package/dist/esm/shield/preflight.js +151 -0
- package/dist/esm/shield/shield.d.ts +68 -0
- package/dist/esm/shield/shield.js +493 -0
- package/dist/esm/shield/types.d.ts +202 -0
- package/dist/esm/shield/types.js +1 -0
- package/dist/esm/transactions/deposit.d.ts +94 -0
- package/dist/esm/transactions/deposit.js +198 -0
- package/dist/esm/transactions/index.d.ts +7 -0
- package/dist/esm/transactions/index.js +7 -0
- package/dist/esm/transactions/swap.d.ts +71 -0
- package/dist/esm/transactions/swap.js +144 -0
- package/dist/esm/transactions/transact.d.ts +34 -0
- package/dist/esm/transactions/transact.js +110 -0
- package/dist/esm/transactions/transfer.d.ts +51 -0
- package/dist/esm/transactions/transfer.js +103 -0
- package/dist/esm/transactions/withdraw.d.ts +52 -0
- package/dist/esm/transactions/withdraw.js +101 -0
- package/dist/esm/utxo.d.ts +1 -0
- package/dist/esm/utxo.js +2 -372
- package/package.json +111 -15
package/README.md
CHANGED
|
@@ -1,1424 +1,451 @@
|
|
|
1
1
|
# @veilo/sdk-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build private payments and swaps on Solana with Veilo.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The SDK gives TypeScript applications a safe, typed way to:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
##
|
|
36
|
+
## Choose an integration
|
|
51
37
|
|
|
52
|
-
|
|
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
|
-
|
|
55
|
-
|
|
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
|
-
|
|
72
|
-
const { config, vault, nullifiers } = getPoolPdas(programId, mintAddress);
|
|
48
|
+
## Quick start: shield funds
|
|
73
49
|
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
235
|
-
const
|
|
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
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
306
|
-
|
|
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
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
|
|
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
|
-
|
|
106
|
+
To shield an SPL token, pass its mint:
|
|
381
107
|
|
|
382
108
|
```ts
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
-
|
|
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 {
|
|
126
|
+
import { rebuild } from "@veilo/sdk-core";
|
|
402
127
|
|
|
403
|
-
const
|
|
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
|
-
|
|
134
|
+
## Cloak Partner API
|
|
423
135
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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
|
-
|
|
434
|
-
|
|
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
|
-
|
|
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
|
-
|
|
493
|
-
|
|
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
|
-
//
|
|
504
|
-
const {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
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
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
|
|
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
|
-
|
|
530
|
-
|
|
531
|
-
|
|
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
|
-
|
|
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
|
-
|
|
588
|
-
const
|
|
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
|
-
|
|
597
|
-
|
|
598
|
-
|
|
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
|
-
|
|
607
|
-
|
|
608
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
222
|
+
## Full private wallet flows
|
|
671
223
|
|
|
672
|
-
-
|
|
673
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
234
|
+
### Use the relayer client
|
|
679
235
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
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
|
-
|
|
929
|
-
|
|
930
|
-
|
|
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
|
-
###
|
|
260
|
+
### Use the direct helpers
|
|
946
261
|
|
|
947
|
-
|
|
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
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
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
|
-
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1139
|
-
|
|
284
|
+
recipientPubkey: veiloOwnerPublicKey,
|
|
285
|
+
noteRecipientWallet: wallet.publicKey,
|
|
286
|
+
tree,
|
|
287
|
+
proofBuilder,
|
|
288
|
+
treeId: 0,
|
|
1140
289
|
});
|
|
1141
290
|
|
|
1142
|
-
await
|
|
1143
|
-
|
|
1144
|
-
|
|
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
|
-
//
|
|
1159
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1168
|
-
|
|
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
|
-
|
|
1171
|
-
|
|
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
|
-
###
|
|
318
|
+
### Amounts use base units
|
|
1193
319
|
|
|
1194
|
-
|
|
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
|
-
|
|
1208
|
-
const
|
|
1209
|
-
|
|
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
|
-
|
|
1225
|
-
const snarkjsInputs = formatInputsForSnarkjs(circuitInputs);
|
|
329
|
+
Avoid JavaScript floating-point values for token arithmetic.
|
|
1226
330
|
|
|
1227
|
-
|
|
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
|
-
|
|
1235
|
-
|
|
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
|
-
###
|
|
341
|
+
### Confirmation comes before local state updates
|
|
1241
342
|
|
|
1242
|
-
|
|
1243
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1269
|
-
|
|
1270
|
-
poseidon2,
|
|
1271
|
-
poseidon3,
|
|
1272
|
-
poseidon4,
|
|
1273
|
-
pubkeyToField,
|
|
360
|
+
CloakApiError,
|
|
361
|
+
mapShieldError,
|
|
1274
362
|
} from "@veilo/sdk-core";
|
|
1275
363
|
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
const
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
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
|
-
|
|
395
|
+
Available focused entry points:
|
|
1368
396
|
|
|
1369
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
421
|
+
These APIs are fully typed. Use their TypeScript definitions as the source of
|
|
422
|
+
truth for required inputs.
|
|
1396
423
|
|
|
1397
|
-
|
|
424
|
+
## Development
|
|
1398
425
|
|
|
1399
426
|
```bash
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
```
|
|
1403
|
-
|
|
1404
|
-
---
|
|
427
|
+
# Build CommonJS, ESM, and declaration outputs
|
|
428
|
+
npm run build
|
|
1405
429
|
|
|
1406
|
-
|
|
430
|
+
# Run deterministic unit and proof tests
|
|
431
|
+
npm test
|
|
1407
432
|
|
|
1408
|
-
|
|
1409
|
-
|
|
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
|
-
##
|
|
440
|
+
## Support
|
|
1415
441
|
|
|
1416
|
-
-
|
|
1417
|
-
-
|
|
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)
|