@veilo/sdk-core 0.1.17 → 0.4.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 (218) hide show
  1. package/README.md +1296 -272
  2. package/SHIELD_INTEGRATION.md +143 -0
  3. package/config.d.ts +2 -0
  4. package/config.js +4 -0
  5. package/dist/cjs/client.d.ts +407 -0
  6. package/dist/cjs/client.js +951 -0
  7. package/dist/cjs/compactNote.d.ts +107 -0
  8. package/dist/cjs/compactNote.js +167 -0
  9. package/dist/cjs/config.d.ts +82 -0
  10. package/dist/cjs/config.js +57 -0
  11. package/dist/cjs/events.d.ts +77 -0
  12. package/dist/cjs/events.js +167 -0
  13. package/dist/cjs/idl/privacy_pool.d.ts +5 -0
  14. package/dist/cjs/idl/privacy_pool.js +15218 -0
  15. package/dist/cjs/idl/privacy_pool.json +10313 -0
  16. package/dist/cjs/index.d.ts +16 -0
  17. package/dist/cjs/index.js +67 -0
  18. package/dist/cjs/merkle.d.ts +77 -0
  19. package/dist/cjs/merkle.js +156 -0
  20. package/dist/cjs/poseidon.d.ts +29 -0
  21. package/dist/cjs/poseidon.js +100 -0
  22. package/dist/cjs/program.d.ts +37 -0
  23. package/dist/cjs/program.js +61 -0
  24. package/dist/cjs/proof.d.ts +183 -0
  25. package/dist/cjs/proof.js +292 -0
  26. package/dist/cjs/prover.d.ts +54 -0
  27. package/dist/cjs/prover.js +112 -0
  28. package/dist/cjs/random.d.ts +16 -0
  29. package/dist/cjs/random.js +28 -0
  30. package/dist/cjs/relayer.d.ts +318 -0
  31. package/dist/cjs/relayer.js +257 -0
  32. package/dist/cjs/retry.d.ts +32 -0
  33. package/dist/cjs/retry.js +75 -0
  34. package/dist/cjs/shield/alt.d.ts +87 -0
  35. package/dist/cjs/shield/alt.js +194 -0
  36. package/dist/cjs/shield/computeBudget.d.ts +61 -0
  37. package/dist/cjs/shield/computeBudget.js +64 -0
  38. package/dist/cjs/shield/errors.d.ts +58 -0
  39. package/dist/cjs/shield/errors.js +121 -0
  40. package/dist/cjs/shield/finalize.d.ts +45 -0
  41. package/dist/cjs/shield/finalize.js +119 -0
  42. package/dist/cjs/shield/index.d.ts +35 -0
  43. package/dist/cjs/shield/index.js +68 -0
  44. package/dist/cjs/shield/ix.d.ts +54 -0
  45. package/dist/cjs/shield/ix.js +119 -0
  46. package/dist/cjs/shield/owner.d.ts +36 -0
  47. package/dist/cjs/shield/owner.js +126 -0
  48. package/dist/cjs/shield/ports.d.ts +43 -0
  49. package/dist/cjs/shield/ports.js +153 -0
  50. package/dist/cjs/shield/preflight.d.ts +30 -0
  51. package/dist/cjs/shield/preflight.js +154 -0
  52. package/dist/cjs/shield/shield.d.ts +68 -0
  53. package/dist/cjs/shield/shield.js +499 -0
  54. package/dist/cjs/shield/types.d.ts +202 -0
  55. package/dist/cjs/shield/types.js +2 -0
  56. package/dist/cjs/utxo.d.ts +235 -0
  57. package/dist/cjs/utxo.js +407 -0
  58. package/dist/esm/client.d.ts +407 -0
  59. package/dist/esm/client.js +891 -0
  60. package/dist/esm/compactNote.d.ts +107 -0
  61. package/dist/esm/compactNote.js +156 -0
  62. package/dist/esm/config.d.ts +82 -0
  63. package/dist/esm/config.js +51 -0
  64. package/dist/esm/events.d.ts +77 -0
  65. package/dist/esm/events.js +129 -0
  66. package/dist/esm/idl/privacy_pool.d.ts +5 -0
  67. package/dist/esm/idl/privacy_pool.js +15216 -0
  68. package/dist/esm/idl/privacy_pool.json +10313 -0
  69. package/dist/esm/index.d.ts +16 -0
  70. package/dist/esm/index.js +29 -0
  71. package/dist/esm/merkle.d.ts +77 -0
  72. package/dist/esm/merkle.js +151 -0
  73. package/dist/esm/package.json +1 -0
  74. package/dist/esm/poseidon.d.ts +29 -0
  75. package/dist/esm/poseidon.js +87 -0
  76. package/dist/esm/program.d.ts +37 -0
  77. package/dist/esm/program.js +53 -0
  78. package/dist/esm/proof.d.ts +183 -0
  79. package/dist/esm/proof.js +281 -0
  80. package/dist/esm/prover.d.ts +54 -0
  81. package/dist/esm/prover.js +75 -0
  82. package/dist/esm/random.d.ts +16 -0
  83. package/dist/esm/random.js +21 -0
  84. package/dist/esm/relayer.d.ts +318 -0
  85. package/dist/esm/relayer.js +249 -0
  86. package/dist/esm/retry.d.ts +32 -0
  87. package/dist/esm/retry.js +71 -0
  88. package/dist/esm/shield/alt.d.ts +87 -0
  89. package/dist/esm/shield/alt.js +186 -0
  90. package/dist/esm/shield/computeBudget.d.ts +61 -0
  91. package/dist/esm/shield/computeBudget.js +61 -0
  92. package/dist/esm/shield/errors.d.ts +58 -0
  93. package/dist/esm/shield/errors.js +115 -0
  94. package/dist/esm/shield/finalize.d.ts +45 -0
  95. package/dist/esm/shield/finalize.js +83 -0
  96. package/dist/esm/shield/index.d.ts +35 -0
  97. package/dist/esm/shield/index.js +32 -0
  98. package/dist/esm/shield/ix.d.ts +54 -0
  99. package/dist/esm/shield/ix.js +82 -0
  100. package/dist/esm/shield/owner.d.ts +36 -0
  101. package/dist/esm/shield/owner.js +122 -0
  102. package/dist/esm/shield/ports.d.ts +43 -0
  103. package/dist/esm/shield/ports.js +147 -0
  104. package/dist/esm/shield/preflight.d.ts +30 -0
  105. package/dist/esm/shield/preflight.js +151 -0
  106. package/dist/esm/shield/shield.d.ts +68 -0
  107. package/dist/esm/shield/shield.js +492 -0
  108. package/dist/esm/shield/types.d.ts +202 -0
  109. package/dist/esm/shield/types.js +1 -0
  110. package/dist/esm/utxo.d.ts +235 -0
  111. package/dist/esm/utxo.js +382 -0
  112. package/dist/src/client.d.ts +407 -0
  113. package/dist/src/client.js +951 -0
  114. package/dist/src/compactNote.d.ts +107 -0
  115. package/dist/src/compactNote.js +167 -0
  116. package/dist/src/config.d.ts +82 -0
  117. package/dist/src/config.js +57 -0
  118. package/dist/src/events.d.ts +77 -0
  119. package/dist/src/events.js +167 -0
  120. package/dist/src/idl/privacy_pool.d.ts +5 -0
  121. package/dist/src/idl/privacy_pool.js +15218 -0
  122. package/dist/src/index.d.ts +16 -0
  123. package/dist/src/index.js +67 -0
  124. package/dist/src/merkle.d.ts +77 -0
  125. package/dist/src/merkle.js +156 -0
  126. package/dist/src/poseidon.d.ts +29 -0
  127. package/dist/src/poseidon.js +100 -0
  128. package/dist/src/program.d.ts +37 -0
  129. package/dist/src/program.js +61 -0
  130. package/dist/src/proof.d.ts +183 -0
  131. package/dist/src/proof.js +292 -0
  132. package/dist/src/prover.d.ts +54 -0
  133. package/dist/src/prover.js +112 -0
  134. package/dist/src/random.d.ts +16 -0
  135. package/dist/src/random.js +28 -0
  136. package/dist/src/relayer.d.ts +318 -0
  137. package/dist/src/relayer.js +257 -0
  138. package/dist/src/retry.d.ts +32 -0
  139. package/dist/src/retry.js +75 -0
  140. package/dist/src/shield/alt.d.ts +87 -0
  141. package/dist/src/shield/alt.js +194 -0
  142. package/dist/src/shield/computeBudget.d.ts +61 -0
  143. package/dist/src/shield/computeBudget.js +64 -0
  144. package/dist/src/shield/errors.d.ts +58 -0
  145. package/dist/src/shield/errors.js +121 -0
  146. package/dist/src/shield/finalize.d.ts +45 -0
  147. package/dist/src/shield/finalize.js +119 -0
  148. package/dist/src/shield/index.d.ts +35 -0
  149. package/dist/src/shield/index.js +68 -0
  150. package/dist/src/shield/ix.d.ts +54 -0
  151. package/dist/src/shield/ix.js +119 -0
  152. package/dist/src/shield/owner.d.ts +36 -0
  153. package/dist/src/shield/owner.js +126 -0
  154. package/dist/src/shield/ports.d.ts +43 -0
  155. package/dist/src/shield/ports.js +153 -0
  156. package/dist/src/shield/preflight.d.ts +30 -0
  157. package/dist/src/shield/preflight.js +154 -0
  158. package/dist/src/shield/shield.d.ts +68 -0
  159. package/dist/src/shield/shield.js +499 -0
  160. package/dist/src/shield/types.d.ts +202 -0
  161. package/dist/src/shield/types.js +2 -0
  162. package/dist/src/utxo.d.ts +235 -0
  163. package/dist/src/utxo.js +407 -0
  164. package/dist/tests/compact-note.test.d.ts +1 -0
  165. package/dist/tests/compact-note.test.js +173 -0
  166. package/dist/tests/config.test.d.ts +1 -0
  167. package/dist/tests/config.test.js +102 -0
  168. package/dist/tests/edge-cases.test.d.ts +1 -0
  169. package/dist/tests/edge-cases.test.js +220 -0
  170. package/dist/tests/encryption.test.d.ts +1 -0
  171. package/dist/tests/encryption.test.js +215 -0
  172. package/dist/tests/events.test.d.ts +1 -0
  173. package/dist/tests/events.test.js +78 -0
  174. package/dist/tests/multi-tree.test.d.ts +1 -0
  175. package/dist/tests/multi-tree.test.js +405 -0
  176. package/dist/tests/pda.test.d.ts +1 -0
  177. package/dist/tests/pda.test.js +229 -0
  178. package/dist/tests/poseidon-builder-parity.test.d.ts +1 -0
  179. package/dist/tests/poseidon-builder-parity.test.js +72 -0
  180. package/dist/tests/poseidon.test.d.ts +1 -0
  181. package/dist/tests/poseidon.test.js +142 -0
  182. package/dist/tests/proof.test.d.ts +1 -0
  183. package/dist/tests/proof.test.js +296 -0
  184. package/dist/tests/relayer.test.d.ts +1 -0
  185. package/dist/tests/relayer.test.js +271 -0
  186. package/dist/tests/sdk.integration.test.d.ts +1 -0
  187. package/dist/tests/sdk.integration.test.js +330 -0
  188. package/dist/tests/shield-owner.test.d.ts +1 -0
  189. package/dist/tests/shield-owner.test.js +89 -0
  190. package/dist/tests/shield-preflight.test.d.ts +1 -0
  191. package/dist/tests/shield-preflight.test.js +87 -0
  192. package/dist/tests/shield-realproof.test.d.ts +1 -0
  193. package/dist/tests/shield-realproof.test.js +272 -0
  194. package/dist/tests/shield.test.d.ts +1 -0
  195. package/dist/tests/shield.test.js +403 -0
  196. package/dist/tests/utxo.test.d.ts +1 -0
  197. package/dist/tests/utxo.test.js +140 -0
  198. package/package.json +105 -11
  199. package/poseidon.d.ts +2 -0
  200. package/poseidon.js +4 -0
  201. package/proof.d.ts +2 -0
  202. package/proof.js +4 -0
  203. package/prover.d.ts +2 -0
  204. package/prover.js +4 -0
  205. package/shield.d.ts +2 -0
  206. package/shield.js +4 -0
  207. package/src/client.ts +0 -352
  208. package/src/config.ts +0 -13
  209. package/src/index.ts +0 -6
  210. package/src/merkle.ts +0 -178
  211. package/src/note.ts +0 -193
  212. package/src/poseidon.ts +0 -62
  213. package/src/proof.ts +0 -170
  214. package/test/script.js +0 -0
  215. package/test-tsconfig.json +0 -19
  216. package/tests/note.test.ts +0 -50
  217. package/tests/sdk.integration.test.ts +0 -210
  218. package/tsconfig.json +0 -18
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ require("mocha");
7
+ const assert_1 = require("assert");
8
+ const http_1 = __importDefault(require("http"));
9
+ const src_1 = require("../src");
10
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
11
+ /**
12
+ * Relayer client tests using a local HTTP mock server.
13
+ */
14
+ // Generate a real NaCl keypair for the "relayer"
15
+ const relayerKeyPair = tweetnacl_1.default.box.keyPair();
16
+ const relayerPublicKeyB64 = typeof Buffer !== "undefined"
17
+ ? Buffer.from(relayerKeyPair.publicKey).toString("base64")
18
+ : btoa(String.fromCharCode(...relayerKeyPair.publicKey));
19
+ let server;
20
+ let baseUrl;
21
+ let lastRequest;
22
+ function createMockServer(handler) {
23
+ return new Promise((resolve) => {
24
+ server = http_1.default.createServer((req, res) => {
25
+ let body = "";
26
+ req.on("data", (c) => (body += c));
27
+ req.on("end", () => {
28
+ lastRequest = {
29
+ method: req.method,
30
+ url: req.url,
31
+ body: body ? JSON.parse(body) : null,
32
+ headers: req.headers,
33
+ };
34
+ if (handler) {
35
+ handler(req, res);
36
+ }
37
+ else {
38
+ res.writeHead(200, { "Content-Type": "application/json" });
39
+ res.end(JSON.stringify({ success: true }));
40
+ }
41
+ });
42
+ });
43
+ server.listen(0, () => {
44
+ const addr = server.address();
45
+ resolve(`http://127.0.0.1:${addr.port}`);
46
+ });
47
+ });
48
+ }
49
+ function makeConfig(url) {
50
+ return {
51
+ relayerUrl: url,
52
+ apiKey: "test-api-key",
53
+ relayerPublicKey: relayerPublicKeyB64,
54
+ authToken: "test-token",
55
+ };
56
+ }
57
+ describe("VeiloRelayerClient", function () {
58
+ this.timeout(15000);
59
+ afterEach((done) => {
60
+ if (server)
61
+ server.close(done);
62
+ else
63
+ done();
64
+ });
65
+ // ---------------------------------------------------------------------------
66
+ // Basic request mechanics
67
+ // ---------------------------------------------------------------------------
68
+ it("sends x-api-key header on all requests", async () => {
69
+ baseUrl = await createMockServer((req, res) => {
70
+ res.writeHead(200, { "Content-Type": "application/json" });
71
+ res.end(JSON.stringify({ success: true, available: true }));
72
+ });
73
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl));
74
+ await client.checkUsername("alice");
75
+ assert_1.strict.equal(lastRequest.headers["x-api-key"], "test-api-key");
76
+ });
77
+ it("sends Authorization header for authenticated endpoints", async () => {
78
+ baseUrl = await createMockServer((req, res) => {
79
+ res.writeHead(200, { "Content-Type": "application/json" });
80
+ res.end(JSON.stringify({ success: true, notes: [], total: 0, limit: 50, offset: 0 }));
81
+ });
82
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl));
83
+ await client.queryEncryptedNotes();
84
+ assert_1.strict.equal(lastRequest.headers["authorization"], "Bearer test-token");
85
+ });
86
+ it("does not send Authorization when no authToken", async () => {
87
+ baseUrl = await createMockServer((req, res) => {
88
+ res.writeHead(200, { "Content-Type": "application/json" });
89
+ res.end(JSON.stringify({ success: true, notes: [], total: 0, limit: 50, offset: 0 }));
90
+ });
91
+ const cfg = makeConfig(baseUrl);
92
+ delete cfg.authToken;
93
+ const client = new src_1.VeiloRelayerClient(cfg);
94
+ await client.queryEncryptedNotes();
95
+ assert_1.strict.equal(lastRequest.headers["authorization"], undefined);
96
+ });
97
+ // ---------------------------------------------------------------------------
98
+ // Error handling
99
+ // ---------------------------------------------------------------------------
100
+ it("throws VeiloApiError on non-2xx responses", async () => {
101
+ baseUrl = await createMockServer((req, res) => {
102
+ res.writeHead(400, { "Content-Type": "application/json" });
103
+ res.end(JSON.stringify({ success: false, error: "BAD_REQUEST", message: "Invalid input" }));
104
+ });
105
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl));
106
+ try {
107
+ await client.checkUsername("");
108
+ assert_1.strict.fail("should have thrown");
109
+ }
110
+ catch (err) {
111
+ assert_1.strict.ok(err instanceof src_1.VeiloApiError);
112
+ assert_1.strict.equal(err.code, "BAD_REQUEST");
113
+ assert_1.strict.equal(err.status, 400);
114
+ assert_1.strict.equal(err.message, "Invalid input");
115
+ }
116
+ });
117
+ it("throws VeiloApiError when success=false on 200", async () => {
118
+ baseUrl = await createMockServer((req, res) => {
119
+ res.writeHead(200, { "Content-Type": "application/json" });
120
+ res.end(JSON.stringify({ success: false, error: "DUPLICATE_COMMITMENT" }));
121
+ });
122
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl));
123
+ try {
124
+ await client.saveEncryptedNote({
125
+ commitment: "abc",
126
+ ephemeralPublicKey: "def",
127
+ encryptedBlob: "ghi",
128
+ timestamp: Date.now(),
129
+ });
130
+ assert_1.strict.fail("should have thrown");
131
+ }
132
+ catch (err) {
133
+ assert_1.strict.ok(err instanceof src_1.VeiloApiError);
134
+ assert_1.strict.equal(err.code, "DUPLICATE_COMMITMENT");
135
+ }
136
+ });
137
+ // ---------------------------------------------------------------------------
138
+ // Retry behavior
139
+ // ---------------------------------------------------------------------------
140
+ it("retries on 503 and succeeds", async () => {
141
+ let callCount = 0;
142
+ baseUrl = await createMockServer((req, res) => {
143
+ callCount++;
144
+ if (callCount < 3) {
145
+ res.writeHead(503, { "Content-Type": "application/json" });
146
+ res.end(JSON.stringify({ success: false, error: "SERVICE_UNAVAILABLE" }));
147
+ }
148
+ else {
149
+ res.writeHead(200, { "Content-Type": "application/json" });
150
+ res.end(JSON.stringify({ success: true, available: true }));
151
+ }
152
+ });
153
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl), {
154
+ maxRetries: 3,
155
+ baseDelayMs: 50,
156
+ });
157
+ const result = await client.checkUsername("bob");
158
+ assert_1.strict.equal(result.success, true);
159
+ assert_1.strict.equal(callCount, 3);
160
+ });
161
+ it("does not retry on 400", async () => {
162
+ let callCount = 0;
163
+ baseUrl = await createMockServer((req, res) => {
164
+ callCount++;
165
+ res.writeHead(400, { "Content-Type": "application/json" });
166
+ res.end(JSON.stringify({ success: false, error: "INVALID" }));
167
+ });
168
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl), {
169
+ maxRetries: 3,
170
+ baseDelayMs: 50,
171
+ });
172
+ try {
173
+ await client.checkUsername("bad");
174
+ assert_1.strict.fail("should have thrown");
175
+ }
176
+ catch {
177
+ assert_1.strict.equal(callCount, 1, "should not retry on 400");
178
+ }
179
+ });
180
+ it("does not retry transact endpoints", async () => {
181
+ let callCount = 0;
182
+ baseUrl = await createMockServer((req, res) => {
183
+ callCount++;
184
+ res.writeHead(503, { "Content-Type": "application/json" });
185
+ res.end(JSON.stringify({ success: false, error: "SERVICE_UNAVAILABLE" }));
186
+ });
187
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl), {
188
+ maxRetries: 3,
189
+ baseDelayMs: 50,
190
+ });
191
+ try {
192
+ await client.submitWithdraw({
193
+ notes: [],
194
+ recipient: "11111111111111111111111111111111",
195
+ amount: "1000000",
196
+ userPublicKey: "11111111111111111111111111111111",
197
+ mintAddress: "11111111111111111111111111111111",
198
+ });
199
+ assert_1.strict.fail("should have thrown");
200
+ }
201
+ catch {
202
+ assert_1.strict.equal(callCount, 1, "transact endpoints should not retry");
203
+ }
204
+ });
205
+ // ---------------------------------------------------------------------------
206
+ // Encryption
207
+ // ---------------------------------------------------------------------------
208
+ it("encrypts withdraw payload (body contains encryptedPayload)", async () => {
209
+ baseUrl = await createMockServer((req, res) => {
210
+ res.writeHead(200, { "Content-Type": "application/json" });
211
+ res.end(JSON.stringify({ success: true, message: "ok" }));
212
+ });
213
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl));
214
+ await client.submitWithdraw({
215
+ notes: [],
216
+ recipient: "11111111111111111111111111111111",
217
+ amount: "1000000",
218
+ userPublicKey: "11111111111111111111111111111111",
219
+ mintAddress: "11111111111111111111111111111111",
220
+ });
221
+ assert_1.strict.ok(lastRequest.body.encryptedPayload, "body should contain encryptedPayload");
222
+ assert_1.strict.equal(typeof lastRequest.body.encryptedPayload, "string");
223
+ // Decrypt and verify the payload structure
224
+ const raw = Buffer.from(lastRequest.body.encryptedPayload, "base64");
225
+ const ephPub = raw.subarray(0, 32);
226
+ const nonce = raw.subarray(32, 56);
227
+ const ciphertext = raw.subarray(56);
228
+ const decrypted = tweetnacl_1.default.box.open(new Uint8Array(ciphertext), new Uint8Array(nonce), new Uint8Array(ephPub), relayerKeyPair.secretKey);
229
+ assert_1.strict.ok(decrypted, "relayer should be able to decrypt the payload");
230
+ const payload = JSON.parse(new TextDecoder().decode(decrypted));
231
+ assert_1.strict.equal(payload.recipient, "11111111111111111111111111111111");
232
+ assert_1.strict.equal(payload.amount, "1000000");
233
+ assert_1.strict.ok(payload.timestamp, "should include timestamp");
234
+ assert_1.strict.ok(payload.nonce, "should include nonce");
235
+ });
236
+ // ---------------------------------------------------------------------------
237
+ // Auth endpoints
238
+ // ---------------------------------------------------------------------------
239
+ it("setAuthToken updates subsequent requests", async () => {
240
+ baseUrl = await createMockServer((req, res) => {
241
+ res.writeHead(200, { "Content-Type": "application/json" });
242
+ res.end(JSON.stringify({ success: true, notes: [], total: 0, limit: 50, offset: 0 }));
243
+ });
244
+ const cfg = makeConfig(baseUrl);
245
+ cfg.authToken = undefined;
246
+ const client = new src_1.VeiloRelayerClient(cfg);
247
+ // First call — no auth
248
+ await client.queryEncryptedNotes();
249
+ assert_1.strict.equal(lastRequest.headers["authorization"], undefined);
250
+ // Set token and call again
251
+ client.setAuthToken("new-token");
252
+ await client.queryEncryptedNotes();
253
+ assert_1.strict.equal(lastRequest.headers["authorization"], "Bearer new-token");
254
+ });
255
+ // ---------------------------------------------------------------------------
256
+ // Merkle endpoints
257
+ // ---------------------------------------------------------------------------
258
+ it("getMerkleRoot passes query params", async () => {
259
+ baseUrl = await createMockServer((req, res) => {
260
+ res.writeHead(200, { "Content-Type": "application/json" });
261
+ res.end(JSON.stringify({
262
+ success: true,
263
+ data: { root: "abc", nextIndex: 5, treeId: 0, onChainTreeId: 0, mintAddress: "So11111111111111111111111111111111111111112" },
264
+ }));
265
+ });
266
+ const client = new src_1.VeiloRelayerClient(makeConfig(baseUrl));
267
+ await client.getMerkleRoot("So11111111111111111111111111111111111111112", 0);
268
+ assert_1.strict.ok(lastRequest.url.includes("mintAddress=So11111111111111111111111111111111111111112"));
269
+ assert_1.strict.ok(lastRequest.url.includes("treeId=0"));
270
+ });
271
+ });
@@ -0,0 +1 @@
1
+ import "mocha";
@@ -0,0 +1,330 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ require("mocha");
40
+ const assert_1 = require("assert");
41
+ const anchor = __importStar(require("@coral-xyz/anchor"));
42
+ const web3_js_1 = require("@solana/web3.js");
43
+ const fs_1 = __importDefault(require("fs"));
44
+ const os_1 = __importDefault(require("os"));
45
+ const path_1 = __importDefault(require("path"));
46
+ const src_1 = require("../src");
47
+ // ---- IDL + Provider helpers ----
48
+ function loadIdl() {
49
+ // NOTE: this path is relative to dist/tests at runtime
50
+ const idlPath = path_1.default.join(__dirname, "../../idl/idl/privacy_pool.json");
51
+ if (!fs_1.default.existsSync(idlPath))
52
+ return null;
53
+ const raw = fs_1.default.readFileSync(idlPath, "utf8");
54
+ return JSON.parse(raw);
55
+ }
56
+ function makeProvider() {
57
+ try {
58
+ const url = process.env.ANCHOR_PROVIDER_URL ?? "http://127.0.0.1:8899";
59
+ const connection = new anchor.web3.Connection(url, "confirmed");
60
+ const keypairPath = process.env.ANCHOR_WALLET ??
61
+ path_1.default.join(os_1.default.homedir(), ".config", "solana", "id.json");
62
+ if (!fs_1.default.existsSync(keypairPath))
63
+ return null;
64
+ const secret = JSON.parse(fs_1.default.readFileSync(keypairPath, "utf8"));
65
+ const kp = web3_js_1.Keypair.fromSecretKey(Uint8Array.from(secret));
66
+ const wallet = new anchor.Wallet(kp);
67
+ return new anchor.AnchorProvider(connection, wallet, {
68
+ commitment: "confirmed",
69
+ preflightCommitment: "confirmed",
70
+ });
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ }
76
+ describe("privacy-pool SDK integration (UTXO model)", function () {
77
+ this.timeout(60000);
78
+ const provider = makeProvider();
79
+ const idl = loadIdl();
80
+ // Skip on-chain tests when no provider or IDL is available, or program not deployed
81
+ before(async function () {
82
+ if (!provider || !idl) {
83
+ console.log("Skipping on-chain integration tests: no provider or IDL available");
84
+ this.skip();
85
+ return;
86
+ }
87
+ try {
88
+ const programId = new web3_js_1.PublicKey(idl.address);
89
+ const info = await provider.connection.getAccountInfo(programId);
90
+ if (!info) {
91
+ console.log(`Skipping on-chain integration tests: program ${programId.toBase58()} not deployed on this cluster`);
92
+ this.skip();
93
+ }
94
+ }
95
+ catch {
96
+ console.log("Skipping on-chain integration tests: could not reach cluster");
97
+ this.skip();
98
+ }
99
+ });
100
+ // These bindings are populated only when the suite runs
101
+ let program;
102
+ let wallet;
103
+ let connection;
104
+ before(async function () {
105
+ if (!provider || !idl)
106
+ return;
107
+ await (0, src_1.initPoseidon)();
108
+ anchor.setProvider(provider);
109
+ program = new anchor.Program(idl, provider);
110
+ wallet = provider.wallet;
111
+ connection = provider.connection;
112
+ });
113
+ const FEE_BPS = 50; // 0.5%
114
+ const MIN_DEPOSIT = (0, src_1.sol)(0.1);
115
+ const MAX_DEPOSIT = (0, src_1.sol)(100);
116
+ const MIN_WITHDRAW = (0, src_1.sol)(0.1);
117
+ const MAX_WITHDRAW = (0, src_1.sol)(100);
118
+ async function airdropAndConfirm(pubkey, lamports) {
119
+ const sig = await connection.requestAirdrop(pubkey, lamports);
120
+ await connection.confirmTransaction(sig, "confirmed");
121
+ }
122
+ it("initializes global config", async () => {
123
+ const globalConfig = (0, src_1.getGlobalConfigPda)(program.programId);
124
+ // Check if already initialized
125
+ const existingConfig = await connection.getAccountInfo(globalConfig);
126
+ if (!existingConfig) {
127
+ await airdropAndConfirm(wallet.publicKey, 2 * web3_js_1.LAMPORTS_PER_SOL);
128
+ await (0, src_1.initializeGlobalConfig)({
129
+ program,
130
+ admin: wallet,
131
+ payer: wallet.payer,
132
+ });
133
+ console.log("Global config initialized");
134
+ }
135
+ else {
136
+ console.log("Global config already exists, skipping initialization");
137
+ }
138
+ });
139
+ it("initializes pool with new parameters", async () => {
140
+ const { config } = (0, src_1.getPoolPdas)(program.programId, src_1.NATIVE_SOL_MINT);
141
+ // Check if already initialized
142
+ const existingConfig = await connection.getAccountInfo(config);
143
+ if (!existingConfig) {
144
+ await airdropAndConfirm(wallet.publicKey, 5 * web3_js_1.LAMPORTS_PER_SOL);
145
+ await (0, src_1.initializePool)({
146
+ program,
147
+ admin: wallet,
148
+ payer: wallet.payer,
149
+ feeBps: FEE_BPS,
150
+ mintAddress: src_1.NATIVE_SOL_MINT,
151
+ minDepositAmount: MIN_DEPOSIT,
152
+ maxDepositAmount: MAX_DEPOSIT,
153
+ minWithdrawAmount: MIN_WITHDRAW,
154
+ maxWithdrawAmount: MAX_WITHDRAW,
155
+ });
156
+ console.log("Pool initialized for native SOL");
157
+ }
158
+ else {
159
+ console.log("Pool already exists, skipping initialization");
160
+ }
161
+ // Verify the PDAs exist
162
+ const configAcc = await connection.getAccountInfo(config);
163
+ (0, assert_1.strict)(configAcc !== null, "Config account should exist");
164
+ });
165
+ it("adds a relayer to the pool", async () => {
166
+ const relayer = web3_js_1.Keypair.generate();
167
+ await airdropAndConfirm(relayer.publicKey, 1 * web3_js_1.LAMPORTS_PER_SOL);
168
+ await (0, src_1.addRelayer)({
169
+ program,
170
+ admin: wallet,
171
+ mintAddress: src_1.NATIVE_SOL_MINT,
172
+ newRelayer: relayer.publicKey,
173
+ });
174
+ console.log(`Relayer added: ${relayer.publicKey.toBase58()}`);
175
+ });
176
+ it("creates UTXOs with correct structure", () => {
177
+ const keypair = (0, src_1.generateKeypair)();
178
+ const amount = (0, src_1.sol)(1);
179
+ const utxo = (0, src_1.createUTXO)({
180
+ amount,
181
+ pubkey: keypair.publicKey,
182
+ mintAddress: src_1.NATIVE_SOL_MINT,
183
+ });
184
+ assert_1.strict.equal(utxo.amount, amount);
185
+ assert_1.strict.equal(utxo.pubkey, keypair.publicKey);
186
+ assert_1.strict.equal(utxo.commitment.length, 32);
187
+ assert_1.strict.ok(utxo.blinding > 0n);
188
+ });
189
+ it("derives nullifiers correctly", () => {
190
+ const privateKey = 12345n;
191
+ const utxo = (0, src_1.createOwnedUTXO)({
192
+ amount: (0, src_1.sol)(1),
193
+ privateKey,
194
+ mintAddress: src_1.NATIVE_SOL_MINT,
195
+ });
196
+ const pathIndex = 0;
197
+ const nullifier = (0, src_1.deriveNullifier)(utxo, pathIndex, privateKey);
198
+ assert_1.strict.equal(nullifier.length, 32);
199
+ // Verify determinism
200
+ const nullifier2 = (0, src_1.deriveNullifier)(utxo, pathIndex, privateKey);
201
+ assert_1.strict.equal(Buffer.compare(Buffer.from(nullifier), Buffer.from(nullifier2)), 0);
202
+ });
203
+ it("computes extDataHash correctly", () => {
204
+ const extData = {
205
+ recipient: web3_js_1.Keypair.generate().publicKey,
206
+ relayer: web3_js_1.Keypair.generate().publicKey,
207
+ fee: (0, src_1.sol)(0.01),
208
+ refund: 0n,
209
+ claimant: web3_js_1.PublicKey.default,
210
+ };
211
+ const hash = (0, src_1.computeExtDataHash)(extData);
212
+ assert_1.strict.equal(hash.length, 32);
213
+ // Verify determinism
214
+ const hash2 = (0, src_1.computeExtDataHash)(extData);
215
+ assert_1.strict.equal(Buffer.compare(Buffer.from(hash), Buffer.from(hash2)), 0);
216
+ });
217
+ it("builds Merkle tree with correct depth", () => {
218
+ const tree = new src_1.MerkleTree(16);
219
+ assert_1.strict.equal(tree.depth, 16);
220
+ assert_1.strict.equal(tree.capacity, 65536);
221
+ assert_1.strict.equal(tree.root.length, 32);
222
+ assert_1.strict.equal(tree.nextIndex, 0);
223
+ });
224
+ it("inserts commitments and generates paths", () => {
225
+ const tree = new src_1.MerkleTree(16);
226
+ const keypair = (0, src_1.generateKeypair)();
227
+ // Create and insert a UTXO
228
+ const utxo = (0, src_1.createUTXO)({
229
+ amount: (0, src_1.sol)(1),
230
+ pubkey: keypair.publicKey,
231
+ mintAddress: src_1.NATIVE_SOL_MINT,
232
+ });
233
+ const { index, root } = tree.insert(utxo.commitment);
234
+ assert_1.strict.equal(index, 0);
235
+ assert_1.strict.equal(root.length, 32);
236
+ // Get the path
237
+ const path = tree.getPath(index);
238
+ assert_1.strict.equal(path.leafIndex, 0);
239
+ assert_1.strict.equal(path.path.length, 16);
240
+ assert_1.strict.equal(path.indices.length, 16);
241
+ // All path elements should be 32 bytes
242
+ for (const element of path.path) {
243
+ assert_1.strict.equal(element.length, 32);
244
+ }
245
+ });
246
+ it("generates circuit-compatible paths", () => {
247
+ const tree = new src_1.MerkleTree(16);
248
+ const keypair = (0, src_1.generateKeypair)();
249
+ const utxo = (0, src_1.createUTXO)({
250
+ amount: (0, src_1.sol)(1),
251
+ pubkey: keypair.publicKey,
252
+ mintAddress: src_1.NATIVE_SOL_MINT,
253
+ });
254
+ const { index } = tree.insert(utxo.commitment);
255
+ const circuitPath = tree.getCircuitPath(index);
256
+ assert_1.strict.equal(circuitPath.pathIndex, 0);
257
+ assert_1.strict.equal(circuitPath.pathElements.length, 16);
258
+ // All elements should be bigints
259
+ for (const element of circuitPath.pathElements) {
260
+ assert_1.strict.equal(typeof element, "bigint");
261
+ }
262
+ });
263
+ // Note: The actual transact instruction test requires a valid ZK proof
264
+ // which would need the full circuit setup. This is a placeholder for
265
+ // when proof generation is available.
266
+ it.skip("executes a deposit transaction", async () => {
267
+ // This test would require:
268
+ // 1. A valid snarkjs proof
269
+ // 2. The circuit WASM and zkey files
270
+ // 3. A running local validator with the contract deployed
271
+ const relayer = web3_js_1.Keypair.generate();
272
+ const recipient = web3_js_1.Keypair.generate();
273
+ await airdropAndConfirm(relayer.publicKey, 2 * web3_js_1.LAMPORTS_PER_SOL);
274
+ const keypair = (0, src_1.generateKeypair)();
275
+ const tree = new src_1.MerkleTree(16);
276
+ // Create zero inputs for deposit
277
+ const zeroInput0 = (0, src_1.createOwnedZeroUTXO)(keypair.privateKey, src_1.NATIVE_SOL_MINT);
278
+ const zeroInput1 = (0, src_1.createOwnedZeroUTXO)(keypair.privateKey, src_1.NATIVE_SOL_MINT);
279
+ tree.insert(zeroInput0.commitment);
280
+ const { root } = tree.insert(zeroInput1.commitment);
281
+ // Create output UTXOs
282
+ const outputUTXO0 = (0, src_1.createUTXO)({
283
+ amount: (0, src_1.sol)(1),
284
+ pubkey: keypair.publicKey,
285
+ mintAddress: src_1.NATIVE_SOL_MINT,
286
+ });
287
+ const outputUTXO1 = (0, src_1.createUTXO)({
288
+ amount: 0n,
289
+ pubkey: keypair.publicKey,
290
+ mintAddress: src_1.NATIVE_SOL_MINT,
291
+ });
292
+ const extData = {
293
+ recipient: recipient.publicKey,
294
+ relayer: relayer.publicKey,
295
+ fee: 0n,
296
+ refund: 0n,
297
+ claimant: web3_js_1.PublicKey.default,
298
+ };
299
+ // Mock proof (would need real proof in production)
300
+ const mockProof = {
301
+ proofA: new Array(64).fill(0),
302
+ proofB: new Array(128).fill(0),
303
+ proofC: new Array(64).fill(0),
304
+ };
305
+ // This would fail without a valid proof, but tests the API
306
+ try {
307
+ await (0, src_1.transact)({
308
+ program,
309
+ relayer,
310
+ recipient: recipient.publicKey,
311
+ mintAddress: src_1.NATIVE_SOL_MINT,
312
+ root,
313
+ inputTreeId: 0,
314
+ outputTreeId: 0,
315
+ publicAmount: (0, src_1.sol)(1),
316
+ inputNullifiers: [
317
+ (0, src_1.deriveNullifier)(zeroInput0, 0, keypair.privateKey),
318
+ (0, src_1.deriveNullifier)(zeroInput1, 1, keypair.privateKey),
319
+ ],
320
+ outputCommitments: [outputUTXO0.commitment, outputUTXO1.commitment],
321
+ extData,
322
+ proof: mockProof,
323
+ });
324
+ }
325
+ catch (e) {
326
+ // Expected to fail with VerifyFailed since we're using a mock proof
327
+ console.log("Transaction failed as expected with mock proof:", e.message);
328
+ }
329
+ });
330
+ });
@@ -0,0 +1 @@
1
+ import "mocha";