@0xbow/privacy-pools-core-sdk 1.1.0 → 1.2.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 (34) hide show
  1. package/README.md +102 -23
  2. package/dist/esm/{fetchArtifacts.esm-B6qveiM8.js → fetchArtifacts.esm-B0qaot8v.js} +2 -2
  3. package/dist/esm/{fetchArtifacts.esm-B6qveiM8.js.map → fetchArtifacts.esm-B0qaot8v.js.map} +1 -1
  4. package/dist/esm/{fetchArtifacts.node-BPQQPsnb.js → fetchArtifacts.node-PzijuwVc.js} +2 -2
  5. package/dist/esm/{fetchArtifacts.node-BPQQPsnb.js.map → fetchArtifacts.node-PzijuwVc.js.map} +1 -1
  6. package/dist/esm/{index-CRtEyHEf.js → index-BjOXETm6.js} +316 -316
  7. package/dist/esm/{index-CRtEyHEf.js.map → index-BjOXETm6.js.map} +1 -1
  8. package/dist/esm/index.mjs +1 -1
  9. package/dist/index.d.mts +81 -0
  10. package/dist/node/{fetchArtifacts.esm-z-KXbilc.js → fetchArtifacts.esm-B6uU6QdA.js} +2 -2
  11. package/dist/node/{fetchArtifacts.esm-z-KXbilc.js.map → fetchArtifacts.esm-B6uU6QdA.js.map} +1 -1
  12. package/dist/node/{fetchArtifacts.node-DvqhqpW9.js → fetchArtifacts.node-CZRy6KmV.js} +2 -2
  13. package/dist/node/{fetchArtifacts.node-DvqhqpW9.js.map → fetchArtifacts.node-CZRy6KmV.js.map} +1 -1
  14. package/dist/node/{index-BsmEKESv.js → index-b-U_m4Mi.js} +337 -337
  15. package/dist/node/{index-BsmEKESv.js.map → index-b-U_m4Mi.js.map} +1 -1
  16. package/dist/node/index.mjs +1 -1
  17. package/dist/types/circuits/artifactHashes.d.ts +19 -0
  18. package/dist/types/core/account.service.d.ts +79 -0
  19. package/dist/types/core/tmp.d.ts +1 -0
  20. package/dist/types/{fetchArtifacts.esm-DF01Zpo3.js → fetchArtifacts.esm-BKxGrC6w.js} +1 -1
  21. package/dist/types/{fetchArtifacts.node-BO6FBCAw.js → fetchArtifacts.node-kXMUDgNn.js} +1 -1
  22. package/dist/types/{index-CH7gk4sK.js → index-BwyNuaY0.js} +336 -336
  23. package/dist/types/index.js +1 -1
  24. package/dist/types/types/account.d.ts +2 -0
  25. package/package.json +1 -1
  26. package/src/circuits/artifactHashes.ts +74 -0
  27. package/src/circuits/circuits.impl.ts +8 -0
  28. package/src/core/account.service.ts +329 -35
  29. package/src/core/data.service.ts +3 -9
  30. package/src/core/tmp.ts +4 -0
  31. package/src/crypto.ts +5 -6
  32. package/src/types/account.ts +3 -1
  33. package/dist/types/keys.d.ts +0 -18
  34. package/src/keys.ts +0 -42
@@ -1,25 +1,25 @@
1
1
  import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
2
2
  import require$$0 from 'buffer';
3
3
  import require$$1 from 'http';
4
- import require$$1$1 from 'https';
5
- import require$$0$1 from 'zlib';
4
+ import require$$2 from 'https';
5
+ import require$$3$1 from 'zlib';
6
6
  import crypto$2 from 'crypto';
7
- import nc from 'node:crypto';
7
+ import require$$0$1 from 'node:crypto';
8
8
  import require$$0$3 from 'events';
9
- import require$$3$1 from 'net';
9
+ import require$$3$2 from 'net';
10
10
  import require$$4 from 'tls';
11
11
  import require$$0$2 from 'stream';
12
12
  import require$$7, { fileURLToPath } from 'url';
13
- import require$$2 from 'assert';
14
- import { keccak256, encodeAbiParameters, numberToHex, createPublicClient, http, createWalletClient, getAddress, bytesToNumber as bytesToNumber$1, parseAbiItem } from 'viem';
13
+ import require$$2$1 from 'assert';
14
+ import { bytesToBigInt, keccak256, encodeAbiParameters, numberToHex, createPublicClient, http, createWalletClient, getAddress, bytesToNumber, parseAbiItem } from 'viem';
15
15
  import { mainnet } from 'viem/chains';
16
16
  import os from 'os';
17
- import require$$1$2 from 'vm';
18
- import require$$2$1 from 'worker_threads';
17
+ import require$$1$1 from 'vm';
18
+ import require$$2$2 from 'worker_threads';
19
19
  import fs from 'fs';
20
20
  import { O_TRUNC, O_CREAT, O_RDWR, O_RDONLY } from 'constants';
21
21
  import 'readline';
22
- import require$$1$3 from 'path';
22
+ import require$$1$2 from 'path';
23
23
 
24
24
  /**
25
25
  * Default log fetch configuration
@@ -33,281 +33,6 @@ const DEFAULT_LOG_FETCH_CONFIG = {
33
33
  retryBaseDelayMs: 1000,
34
34
  };
35
35
 
36
- const version$1 = '2.22.14';
37
-
38
- let errorConfig = {
39
- getDocsUrl: ({ docsBaseUrl, docsPath = '', docsSlug, }) => docsPath
40
- ? `${docsBaseUrl ?? 'https://viem.sh'}${docsPath}${docsSlug ? `#${docsSlug}` : ''}`
41
- : undefined,
42
- version: `viem@${version$1}`,
43
- };
44
- class BaseError extends Error {
45
- constructor(shortMessage, args = {}) {
46
- const details = (() => {
47
- if (args.cause instanceof BaseError)
48
- return args.cause.details;
49
- if (args.cause?.message)
50
- return args.cause.message;
51
- return args.details;
52
- })();
53
- const docsPath = (() => {
54
- if (args.cause instanceof BaseError)
55
- return args.cause.docsPath || args.docsPath;
56
- return args.docsPath;
57
- })();
58
- const docsUrl = errorConfig.getDocsUrl?.({ ...args, docsPath });
59
- const message = [
60
- shortMessage || 'An error occurred.',
61
- '',
62
- ...(args.metaMessages ? [...args.metaMessages, ''] : []),
63
- ...(docsUrl ? [`Docs: ${docsUrl}`] : []),
64
- ...(details ? [`Details: ${details}`] : []),
65
- ...(errorConfig.version ? [`Version: ${errorConfig.version}`] : []),
66
- ].join('\n');
67
- super(message, args.cause ? { cause: args.cause } : undefined);
68
- Object.defineProperty(this, "details", {
69
- enumerable: true,
70
- configurable: true,
71
- writable: true,
72
- value: undefined
73
- });
74
- Object.defineProperty(this, "docsPath", {
75
- enumerable: true,
76
- configurable: true,
77
- writable: true,
78
- value: undefined
79
- });
80
- Object.defineProperty(this, "metaMessages", {
81
- enumerable: true,
82
- configurable: true,
83
- writable: true,
84
- value: undefined
85
- });
86
- Object.defineProperty(this, "shortMessage", {
87
- enumerable: true,
88
- configurable: true,
89
- writable: true,
90
- value: undefined
91
- });
92
- Object.defineProperty(this, "version", {
93
- enumerable: true,
94
- configurable: true,
95
- writable: true,
96
- value: undefined
97
- });
98
- Object.defineProperty(this, "name", {
99
- enumerable: true,
100
- configurable: true,
101
- writable: true,
102
- value: 'BaseError'
103
- });
104
- this.details = details;
105
- this.docsPath = docsPath;
106
- this.metaMessages = args.metaMessages;
107
- this.name = args.name ?? this.name;
108
- this.shortMessage = shortMessage;
109
- this.version = version$1;
110
- }
111
- walk(fn) {
112
- return walk(this, fn);
113
- }
114
- }
115
- function walk(err, fn) {
116
- if (fn?.(err))
117
- return err;
118
- if (err &&
119
- typeof err === 'object' &&
120
- 'cause' in err &&
121
- err.cause !== undefined)
122
- return walk(err.cause, fn);
123
- return fn ? null : err;
124
- }
125
-
126
- class SizeOverflowError extends BaseError {
127
- constructor({ givenSize, maxSize }) {
128
- super(`Size cannot exceed ${maxSize} bytes. Given size: ${givenSize} bytes.`, { name: 'SizeOverflowError' });
129
- }
130
- }
131
-
132
- class SizeExceedsPaddingSizeError extends BaseError {
133
- constructor({ size, targetSize, type, }) {
134
- super(`${type.charAt(0).toUpperCase()}${type
135
- .slice(1)
136
- .toLowerCase()} size (${size}) exceeds padding size (${targetSize}).`, { name: 'SizeExceedsPaddingSizeError' });
137
- }
138
- }
139
-
140
- function pad(hexOrBytes, { dir, size = 32 } = {}) {
141
- if (typeof hexOrBytes === 'string')
142
- return padHex(hexOrBytes, { dir, size });
143
- return padBytes(hexOrBytes, { dir, size });
144
- }
145
- function padHex(hex_, { dir, size = 32 } = {}) {
146
- if (size === null)
147
- return hex_;
148
- const hex = hex_.replace('0x', '');
149
- if (hex.length > size * 2)
150
- throw new SizeExceedsPaddingSizeError({
151
- size: Math.ceil(hex.length / 2),
152
- targetSize: size,
153
- type: 'hex',
154
- });
155
- return `0x${hex[dir === 'right' ? 'padEnd' : 'padStart'](size * 2, '0')}`;
156
- }
157
- function padBytes(bytes, { dir, size = 32 } = {}) {
158
- if (size === null)
159
- return bytes;
160
- if (bytes.length > size)
161
- throw new SizeExceedsPaddingSizeError({
162
- size: bytes.length,
163
- targetSize: size,
164
- type: 'bytes',
165
- });
166
- const paddedBytes = new Uint8Array(size);
167
- for (let i = 0; i < size; i++) {
168
- const padEnd = dir === 'right';
169
- paddedBytes[padEnd ? i : size - i - 1] =
170
- bytes[padEnd ? i : bytes.length - i - 1];
171
- }
172
- return paddedBytes;
173
- }
174
-
175
- function isHex(value, { strict = true } = {}) {
176
- if (!value)
177
- return false;
178
- if (typeof value !== 'string')
179
- return false;
180
- return strict ? /^0x[0-9a-fA-F]*$/.test(value) : value.startsWith('0x');
181
- }
182
-
183
- /**
184
- * @description Retrieves the size of the value (in bytes).
185
- *
186
- * @param value The value (hex or byte array) to retrieve the size of.
187
- * @returns The size of the value (in bytes).
188
- */
189
- function size(value) {
190
- if (isHex(value, { strict: false }))
191
- return Math.ceil((value.length - 2) / 2);
192
- return value.length;
193
- }
194
-
195
- function assertSize(hexOrBytes, { size: size$1 }) {
196
- if (size(hexOrBytes) > size$1)
197
- throw new SizeOverflowError({
198
- givenSize: size(hexOrBytes),
199
- maxSize: size$1,
200
- });
201
- }
202
- /**
203
- * Decodes a hex value into a bigint.
204
- *
205
- * - Docs: https://viem.sh/docs/utilities/fromHex#hextobigint
206
- *
207
- * @param hex Hex value to decode.
208
- * @param opts Options.
209
- * @returns BigInt value.
210
- *
211
- * @example
212
- * import { hexToBigInt } from 'viem'
213
- * const data = hexToBigInt('0x1a4', { signed: true })
214
- * // 420n
215
- *
216
- * @example
217
- * import { hexToBigInt } from 'viem'
218
- * const data = hexToBigInt('0x00000000000000000000000000000000000000000000000000000000000001a4', { size: 32 })
219
- * // 420n
220
- */
221
- function hexToBigInt(hex, opts = {}) {
222
- const { signed } = opts;
223
- if (opts.size)
224
- assertSize(hex, { size: opts.size });
225
- const value = BigInt(hex);
226
- if (!signed)
227
- return value;
228
- const size = (hex.length - 2) / 2;
229
- const max = (1n << (BigInt(size) * 8n - 1n)) - 1n;
230
- if (value <= max)
231
- return value;
232
- return value - BigInt(`0x${'f'.padStart(size * 2, 'f')}`) - 1n;
233
- }
234
- /**
235
- * Decodes a hex string into a number.
236
- *
237
- * - Docs: https://viem.sh/docs/utilities/fromHex#hextonumber
238
- *
239
- * @param hex Hex value to decode.
240
- * @param opts Options.
241
- * @returns Number value.
242
- *
243
- * @example
244
- * import { hexToNumber } from 'viem'
245
- * const data = hexToNumber('0x1a4')
246
- * // 420
247
- *
248
- * @example
249
- * import { hexToNumber } from 'viem'
250
- * const data = hexToBigInt('0x00000000000000000000000000000000000000000000000000000000000001a4', { size: 32 })
251
- * // 420
252
- */
253
- function hexToNumber(hex, opts = {}) {
254
- return Number(hexToBigInt(hex, opts));
255
- }
256
-
257
- const hexes = /*#__PURE__*/ Array.from({ length: 256 }, (_v, i) => i.toString(16).padStart(2, '0'));
258
- /**
259
- * Encodes a bytes array into a hex string
260
- *
261
- * - Docs: https://viem.sh/docs/utilities/toHex#bytestohex
262
- *
263
- * @param value Value to encode.
264
- * @param opts Options.
265
- * @returns Hex value.
266
- *
267
- * @example
268
- * import { bytesToHex } from 'viem'
269
- * const data = bytesToHex(Uint8Array.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
270
- * // '0x48656c6c6f20576f726c6421'
271
- *
272
- * @example
273
- * import { bytesToHex } from 'viem'
274
- * const data = bytesToHex(Uint8Array.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]), { size: 32 })
275
- * // '0x48656c6c6f20576f726c64210000000000000000000000000000000000000000'
276
- */
277
- function bytesToHex(value, opts = {}) {
278
- let string = '';
279
- for (let i = 0; i < value.length; i++) {
280
- string += hexes[value[i]];
281
- }
282
- const hex = `0x${string}`;
283
- if (typeof opts.size === 'number') {
284
- assertSize(hex, { size: opts.size });
285
- return pad(hex, { dir: 'right', size: opts.size });
286
- }
287
- return hex;
288
- }
289
-
290
- /**
291
- * Decodes a byte array into a number.
292
- *
293
- * - Docs: https://viem.sh/docs/utilities/fromBytes#bytestonumber
294
- *
295
- * @param bytes Byte array to decode.
296
- * @param opts Options.
297
- * @returns Number value.
298
- *
299
- * @example
300
- * import { bytesToNumber } from 'viem'
301
- * const data = bytesToNumber(new Uint8Array([1, 164]))
302
- * // 420
303
- */
304
- function bytesToNumber(bytes, opts = {}) {
305
- if (typeof opts.size !== 'undefined')
306
- assertSize(bytes, { size: opts.size });
307
- const hex = bytesToHex(bytes, opts);
308
- return hexToNumber(hex, opts);
309
- }
310
-
311
36
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
312
37
 
313
38
  function getDefaultExportFromCjs (x) {
@@ -16461,8 +16186,8 @@ function requireGeturl () {
16461
16186
  geturl.getUrl = geturl.createGetUrl = undefined;
16462
16187
  const tslib_1 = tslib_es6$1;
16463
16188
  const http_1 = tslib_1.__importDefault(require$$1);
16464
- const https_1 = tslib_1.__importDefault(require$$1$1);
16465
- const zlib_1 = require$$0$1;
16189
+ const https_1 = tslib_1.__importDefault(require$$2);
16190
+ const zlib_1 = require$$3$1;
16466
16191
  const errors_js_1 = /*@__PURE__*/ requireErrors();
16467
16192
  const data_js_1 = /*@__PURE__*/ requireData();
16468
16193
  /**
@@ -19099,8 +18824,8 @@ function requireCryptoNode () {
19099
18824
  // See utils.ts for details.
19100
18825
  // The file will throw on node.js 14 and earlier.
19101
18826
  // @ts-ignore
19102
- const nc$1 = nc;
19103
- cryptoNode.crypto = nc$1 && typeof nc$1 === 'object' && 'webcrypto' in nc$1 ? nc$1.webcrypto : undefined;
18827
+ const nc = require$$0$1;
18828
+ cryptoNode.crypto = nc && typeof nc === 'object' && 'webcrypto' in nc ? nc.webcrypto : undefined;
19104
18829
 
19105
18830
  return cryptoNode;
19106
18831
  }
@@ -39974,7 +39699,7 @@ function requirePermessageDeflate () {
39974
39699
  if (hasRequiredPermessageDeflate) return permessageDeflate;
39975
39700
  hasRequiredPermessageDeflate = 1;
39976
39701
 
39977
- const zlib = require$$0$1;
39702
+ const zlib = require$$3$1;
39978
39703
 
39979
39704
  const bufferUtil = requireBufferUtil();
39980
39705
  const Limiter = requireLimiter();
@@ -42364,9 +42089,9 @@ function requireWebsocket () {
42364
42089
  hasRequiredWebsocket = 1;
42365
42090
 
42366
42091
  const EventEmitter = require$$0$3;
42367
- const https = require$$1$1;
42092
+ const https = require$$2;
42368
42093
  const http = require$$1;
42369
- const net = require$$3$1;
42094
+ const net = require$$3$2;
42370
42095
  const tls = require$$4;
42371
42096
  const { randomBytes, createHash } = crypto$2;
42372
42097
  const { URL } = require$$7;
@@ -46456,7 +46181,7 @@ function requireProviderIpcsocket () {
46456
46181
  hasRequiredProviderIpcsocket = 1;
46457
46182
  Object.defineProperty(providerIpcsocket, "__esModule", { value: true });
46458
46183
  providerIpcsocket.IpcSocketProvider = undefined;
46459
- const net_1 = require$$3$1;
46184
+ const net_1 = require$$3$2;
46460
46185
  const provider_socket_js_1 = /*@__PURE__*/ requireProviderSocket();
46461
46186
  // @TODO: Is this sufficient? Is this robust? Will newlines occur between
46462
46187
  // all payloads and only between payloads?
@@ -50179,7 +49904,7 @@ function requireConstants () {
50179
49904
  exports.NOTHING_UP_MY_SLEEVE = exports.SNARK_FIELD_SIZE = undefined;
50180
49905
  const baby_jubjub_1 = requireDist$2();
50181
49906
  const ethers_1 = /*@__PURE__*/ requireLib_commonjs();
50182
- const assert_1 = __importDefault(require$$2);
49907
+ const assert_1 = __importDefault(require$$2$1);
50183
49908
  exports.SNARK_FIELD_SIZE = baby_jubjub_1.r;
50184
49909
  // A nothing-up-my-sleeve zero value
50185
49910
  // Should be equal to 8370432830353022751713833565135785980866757267633941821328460903436894336785
@@ -50203,7 +49928,7 @@ function requireHashing () {
50203
49928
  exports.hashOne = exports.hash12 = exports.hash5 = exports.hash4 = exports.hash3 = exports.hash2 = exports.hashN = exports.hashLeftRight = exports.poseidonT6 = exports.poseidonT5 = exports.poseidonT4 = exports.poseidonT3 = exports.poseidon = exports.sha256Hash = undefined;
50204
49929
  const poseidon_cipher_1 = requireDist$1();
50205
49930
  const ethers_1 = /*@__PURE__*/ requireLib_commonjs();
50206
- const assert_1 = __importDefault(require$$2);
49931
+ const assert_1 = __importDefault(require$$2$1);
50207
49932
  const constants_1 = requireConstants();
50208
49933
  /**
50209
49934
  * Hash an array of uint256 values the same way that the EVM does.
@@ -50862,10 +50587,10 @@ function generateMasterKeys(mnemonic) {
50862
50587
  if (!mnemonic) {
50863
50588
  throw new PrivacyPoolError(ErrorCode$1.INVALID_VALUE, "Invalid input: mnemonic phrase is required.");
50864
50589
  }
50865
- const key1 = bytesToNumber(mnemonicToAccount(mnemonic, { accountIndex: 0 }).getHdKey().privateKey);
50866
- const key2 = bytesToNumber(mnemonicToAccount(mnemonic, { accountIndex: 1 }).getHdKey().privateKey);
50867
- const masterNullifier = hashingExports.poseidon([BigInt(key1)]);
50868
- const masterSecret = hashingExports.poseidon([BigInt(key2)]);
50590
+ const key1 = bytesToBigInt(mnemonicToAccount(mnemonic, { accountIndex: 0 }).getHdKey().privateKey);
50591
+ const key2 = bytesToBigInt(mnemonicToAccount(mnemonic, { accountIndex: 1 }).getHdKey().privateKey);
50592
+ const masterNullifier = hashingExports.poseidon([key1]);
50593
+ const masterSecret = hashingExports.poseidon([key2]);
50869
50594
  return { masterNullifier, masterSecret };
50870
50595
  }
50871
50596
  /**
@@ -51082,10 +50807,62 @@ const circuitToAsset = {
51082
50807
 
51083
50808
  async function importFetchVersionedArtifact(isBrowser) {
51084
50809
  if (isBrowser) {
51085
- return import('./fetchArtifacts.esm-z-KXbilc.js');
50810
+ return import('./fetchArtifacts.esm-B6uU6QdA.js');
51086
50811
  }
51087
50812
  else {
51088
- return import('./fetchArtifacts.node-DvqhqpW9.js');
50813
+ return import('./fetchArtifacts.node-CZRy6KmV.js');
50814
+ }
50815
+ }
50816
+
50817
+ /**
50818
+ * Expected SHA-256 hex digests for every downloaded circuit artifact.
50819
+ *
50820
+ * vkey and zkey hashes are derived from the trusted-setup ceremony outputs
50821
+ * committed in packages/circuits/trusted-setup/final-keys/.
50822
+ *
50823
+ * wasm hashes are derived from the compiled circuit outputs
50824
+ * in packages/circuits/build/.
50825
+ *
50826
+ * Every artifact downloaded by the SDK MUST have a hash entry here.
50827
+ * verifyArtifactIntegrity throws if a hash is missing — refusing to
50828
+ * load unverified artifacts is the correct security posture.
50829
+ */
50830
+ const ARTIFACT_HASHES = {
50831
+ [CircuitName$1.Commitment]: {
50832
+ wasm: "254d2130607182fd6fd1aee67971526b13cfe178c88e360da96dce92663828d8",
50833
+ vkey: "7d48b4eb3dedc12fb774348287b587f0c18c3c7254cd60e9cf0f8b3636a570d8",
50834
+ zkey: "494ae92d64098fda2a5649690ddc5821fcd7449ca5fe8ef99ee7447544d7e1f3",
50835
+ },
50836
+ [CircuitName$1.Withdraw]: {
50837
+ wasm: "36cda22791def3d520a55c0fc808369cd5849532a75fab65686e666ed3d55c10",
50838
+ vkey: "666bd0983b20c1611543b04f7712e067fbe8cad69f07ada8a310837ff398d21e",
50839
+ zkey: "2a893b42174c813566e5c40c715a8b90cd49fc4ecf384e3a6024158c3d6de677",
50840
+ },
50841
+ [CircuitName$1.MerkleTree]: {},
50842
+ };
50843
+ // Freeze the manifest so runtime code cannot swap out trusted hashes.
50844
+ for (const circuitHashes of Object.values(ARTIFACT_HASHES)) {
50845
+ if (circuitHashes != null) {
50846
+ Object.freeze(circuitHashes);
50847
+ }
50848
+ }
50849
+ Object.freeze(ARTIFACT_HASHES);
50850
+ async function sha256Hex(data) {
50851
+ const hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
50852
+ return Array.from(new Uint8Array(hashBuffer))
50853
+ .map((b) => b.toString(16).padStart(2, "0"))
50854
+ .join("");
50855
+ }
50856
+ async function verifyArtifactIntegrity(circuitName, artifactType, data) {
50857
+ const expectedHash = ARTIFACT_HASHES[circuitName]?.[artifactType];
50858
+ if (expectedHash === undefined) {
50859
+ throw new Error(`No integrity hash registered for ${circuitName}.${artifactType}. ` +
50860
+ `Refusing to load unverified artifact.`);
50861
+ }
50862
+ const actualHash = await sha256Hex(data);
50863
+ if (actualHash !== expectedHash) {
50864
+ throw new Error(`Integrity check failed for ${circuitName}.${artifactType}: ` +
50865
+ `expected ${expectedHash}, got ${actualHash}`);
51089
50866
  }
51090
50867
  }
51091
50868
 
@@ -51202,6 +50979,11 @@ class Circuits {
51202
50979
  this._fetchVersionedArtifact(["artifacts", assetName.vkey].join("/")),
51203
50980
  this._fetchVersionedArtifact(["artifacts", assetName.zkey].join("/")),
51204
50981
  ]);
50982
+ await Promise.all([
50983
+ verifyArtifactIntegrity(circuitName, "wasm", wasm),
50984
+ verifyArtifactIntegrity(circuitName, "vkey", vkey),
50985
+ verifyArtifactIntegrity(circuitName, "zkey", zkey),
50986
+ ]);
51205
50987
  return { wasm, vkey, zkey };
51206
50988
  }
51207
50989
  /**
@@ -67061,9 +66843,9 @@ function requireNode () {
67061
66843
  hasRequiredNode = 1;
67062
66844
  const URL = require$$7;
67063
66845
 
67064
- const VM = require$$1$2;
66846
+ const VM = require$$1$1;
67065
66847
 
67066
- const threads = require$$2$1;
66848
+ const threads = require$$2$2;
67067
66849
 
67068
66850
  const WORKER = Symbol.for('worker');
67069
66851
  const EVENTS = Symbol.for('events');
@@ -74526,7 +74308,7 @@ function requireEjs () {
74526
74308
 
74527
74309
 
74528
74310
  var fs$1 = fs;
74529
- var path = require$$1$3;
74311
+ var path = require$$1$2;
74530
74312
  var utils = requireUtils();
74531
74313
 
74532
74314
  var scopeOptionWarned = false;
@@ -79119,6 +78901,38 @@ class AccountService {
79119
78901
  this.account = config.account;
79120
78902
  }
79121
78903
  }
78904
+ /**
78905
+ * Initializes a new account from a mnemonic phrase for the legacy account.
78906
+ *
78907
+ * @param mnemonic - The mnemonic phrase to derive keys from
78908
+ * @returns A new PrivacyPoolAccount with derived master keys
78909
+ *
78910
+ * @remarks
78911
+ * This method derives two master keys from the mnemonic:
78912
+ * 1. A master nullifier key from account index 0
78913
+ * 2. A master secret key from account index 1
78914
+ * These keys are used to deterministically generate nullifiers and secrets for deposits and withdrawals.
78915
+ *
78916
+ * @throws {AccountError} If account initialization fails
78917
+ * @private
78918
+ */
78919
+ static _initializeLegacyAccount(mnemonic) {
78920
+ try {
78921
+ const masterNullifierSeed = bytesToNumber(mnemonicToAccount(mnemonic, { accountIndex: 0 }).getHdKey().privateKey);
78922
+ const masterSecretSeed = bytesToNumber(mnemonicToAccount(mnemonic, { accountIndex: 1 }).getHdKey().privateKey);
78923
+ const masterNullifier = hashingExports.poseidon([BigInt(masterNullifierSeed)]);
78924
+ const masterSecret = hashingExports.poseidon([BigInt(masterSecretSeed)]);
78925
+ return {
78926
+ masterKeys: [masterNullifier, masterSecret],
78927
+ poolAccounts: new Map(),
78928
+ creationTimestamp: 0n,
78929
+ lastUpdateTimestamp: 0n,
78930
+ };
78931
+ }
78932
+ catch (error) {
78933
+ throw AccountError.accountInitializationFailed(error instanceof Error ? error.message : "Unknown error");
78934
+ }
78935
+ }
79122
78936
  /**
79123
78937
  * Initializes a new account from a mnemonic phrase.
79124
78938
  *
@@ -79137,10 +78951,7 @@ class AccountService {
79137
78951
  _initializeAccount(mnemonic) {
79138
78952
  try {
79139
78953
  this.logger.debug("Initializing account with mnemonic");
79140
- const masterNullifierSeed = bytesToNumber$1(mnemonicToAccount(mnemonic, { accountIndex: 0 }).getHdKey().privateKey);
79141
- const masterSecretSeed = bytesToNumber$1(mnemonicToAccount(mnemonic, { accountIndex: 1 }).getHdKey().privateKey);
79142
- const masterNullifier = hashingExports.poseidon([BigInt(masterNullifierSeed)]);
79143
- const masterSecret = hashingExports.poseidon([BigInt(masterSecretSeed)]);
78954
+ const { masterNullifier, masterSecret } = generateMasterKeys(mnemonic);
79144
78955
  return {
79145
78956
  masterKeys: [masterNullifier, masterSecret],
79146
78957
  poolAccounts: new Map(),
@@ -79239,7 +79050,7 @@ class AccountService {
79239
79050
  const nonZeroCommitments = [];
79240
79051
  for (const account of accounts) {
79241
79052
  // Skip accounts that have been ragequit
79242
- if (account.ragequit) {
79053
+ if (account.ragequit || account.isMigrated) {
79243
79054
  continue;
79244
79055
  }
79245
79056
  const lastCommitment = account.children.length > 0
@@ -79395,6 +79206,57 @@ class AccountService {
79395
79206
  this.logger.info(`Added new commitment with value ${value} to account with label ${parentCommitment.label}`);
79396
79207
  return newCommitment;
79397
79208
  }
79209
+ /**
79210
+ * Adds a new commitment to the account after migrate
79211
+ *
79212
+ * @param parentCommitment - The commitment that was spent
79213
+ * @param value - The remaining value after spending
79214
+ * @param nullifier - The nullifier used for migrate
79215
+ * @param secret - The secret used for migrate
79216
+ * @param blockNumber - The block number of the withdrawal
79217
+ * @param txHash - The transaction hash of the withdrawal
79218
+ * @returns The new commitment
79219
+ *
79220
+ * @remarks
79221
+ * This method finds the account containing the parent commitment, creates a new
79222
+ * commitment with the provided parameters, and adds it to the account's children.
79223
+ * The new commitment inherits the label from the parent commitment.
79224
+ *
79225
+ * @throws {AccountError} If no account is found for the commitment
79226
+ */
79227
+ addMigrationCommitment(parentCommitment, value, nullifier, secret, blockNumber, txHash) {
79228
+ let foundAccount;
79229
+ let foundScope;
79230
+ for (const [scope, accounts] of this.account.poolAccounts.entries()) {
79231
+ foundAccount = accounts.find((account) => {
79232
+ if (account.deposit.hash === parentCommitment.hash)
79233
+ return true;
79234
+ return account.children.some((child) => child.hash === parentCommitment.hash);
79235
+ });
79236
+ if (foundAccount) {
79237
+ foundScope = scope;
79238
+ break;
79239
+ }
79240
+ }
79241
+ if (!foundAccount || !foundScope) {
79242
+ throw AccountError.commitmentNotFound(parentCommitment.hash);
79243
+ }
79244
+ const precommitment = this._hashPrecommitment(nullifier, secret);
79245
+ const newCommitment = {
79246
+ hash: this._hashCommitment(value, parentCommitment.label, precommitment),
79247
+ value,
79248
+ label: parentCommitment.label,
79249
+ nullifier,
79250
+ secret,
79251
+ blockNumber,
79252
+ txHash,
79253
+ isMigration: true
79254
+ };
79255
+ foundAccount.children.push(newCommitment);
79256
+ foundAccount.isMigrated = true;
79257
+ this.logger.info(`Added new commitment with value ${value} to account with label ${parentCommitment.label}`);
79258
+ return newCommitment;
79259
+ }
79398
79260
  /**
79399
79261
  * Adds a ragequit event to an existing pool account
79400
79262
  *
@@ -79546,9 +79408,11 @@ class AccountService {
79546
79408
  });
79547
79409
  }
79548
79410
  else {
79549
- events.set(result.reason.details?.scope, {
79411
+ const errorWithDetails = result.reason;
79412
+ const scope = errorWithDetails.details?.scope;
79413
+ events.set(scope, {
79550
79414
  reason: result.reason.message,
79551
- scope: result.reason.details?.scope,
79415
+ scope: scope,
79552
79416
  });
79553
79417
  }
79554
79418
  }
@@ -79562,11 +79426,11 @@ class AccountService {
79562
79426
  * @param depositEvents - The map of deposit events
79563
79427
  *
79564
79428
  */
79565
- _processDepositEvents(scope, depositEvents) {
79429
+ _processDepositEvents(scope, depositEvents, startIndex = 0n) {
79566
79430
  const MAX_CONSECUTIVE_MISSES = 10; // Large enough to avoid tx failures
79567
79431
  const foundIndices = new Set();
79568
79432
  let consecutiveMisses = 0;
79569
- for (let index = BigInt(0);; index++) {
79433
+ for (let index = startIndex;; index++) {
79570
79434
  // Generate nullifier, secret, and precommitment for this index
79571
79435
  const { nullifier, secret, precommitment } = this.createDepositSecrets(scope, index);
79572
79436
  // Look for a deposit with this precommitment
@@ -79617,8 +79481,8 @@ class AccountService {
79617
79481
  // Process each account in parallel for better performance
79618
79482
  for (const account of accounts) {
79619
79483
  let currentCommitment = account.deposit;
79620
- let index = BigInt(0);
79621
- // Continue processing withdrawals until no more are found secuentially
79484
+ let index = BigInt(account.children.length);
79485
+ // Continue processing withdrawals until no more are found sequentially
79622
79486
  while (true) {
79623
79487
  // Generate nullifier for this withdrawal
79624
79488
  const nullifierHash = hashingExports.poseidon([currentCommitment.nullifier]);
@@ -79627,13 +79491,26 @@ class AccountService {
79627
79491
  if (!withdrawal) {
79628
79492
  break;
79629
79493
  }
79494
+ const remainingValue = currentCommitment.value - withdrawal.withdrawn;
79630
79495
  // Generate secret for this withdrawal
79631
79496
  const nullifier = this._genWithdrawalNullifier(account.label, index);
79632
79497
  const secret = this._genWithdrawalSecret(account.label, index);
79633
- // Add the withdrawal commitment to the account
79634
- const newCommitment = this.addWithdrawalCommitment(currentCommitment, currentCommitment.value - withdrawal.withdrawn, nullifier, secret, withdrawal.blockNumber, withdrawal.transactionHash);
79635
- // Update current commitment to the newly created one
79636
- currentCommitment = newCommitment;
79498
+ const precommitment = this._hashPrecommitment(nullifier, secret);
79499
+ const accountCommitment = this._hashCommitment(remainingValue, currentCommitment.label, precommitment);
79500
+ // If the locally-computed hash doesn't match the on-chain commitment,
79501
+ // the withdrawal was performed with different keys (e.g. migration from
79502
+ // legacy to safe keys). Mark the child as unspendable from this account.
79503
+ if (accountCommitment !== withdrawal.newCommitment) {
79504
+ this.logger.info(`Withdrawal commitment hash mismatch — marking as unspendable (migrated with different keys)`, { label: currentCommitment.label, expected: withdrawal.newCommitment, computed: accountCommitment });
79505
+ // Add the withdrawal commitment to the account
79506
+ const migrationCommitment = this.addMigrationCommitment(currentCommitment, remainingValue, nullifier, secret, withdrawal.blockNumber, withdrawal.transactionHash);
79507
+ currentCommitment = migrationCommitment;
79508
+ }
79509
+ else {
79510
+ // Add the withdrawal commitment to the account
79511
+ const withdrawalCommitment = this.addWithdrawalCommitment(currentCommitment, remainingValue, nullifier, secret, withdrawal.blockNumber, withdrawal.transactionHash);
79512
+ currentCommitment = withdrawalCommitment;
79513
+ }
79637
79514
  // Increment index for next potential withdrawal
79638
79515
  index++;
79639
79516
  }
@@ -79668,6 +79545,59 @@ class AccountService {
79668
79545
  }
79669
79546
  }
79670
79547
  }
79548
+ /**
79549
+ * Discovers commitments that were migrated from legacy accounts via 0-value withdrawal.
79550
+ *
79551
+ * @param scope - The scope of the pool
79552
+ * @param legacyAccounts - The legacy pool accounts for this scope
79553
+ * @param withdrawalEvents - The map of withdrawal events (keyed by spentNullifier)
79554
+ *
79555
+ * @remarks
79556
+ * When a legacy account performs a 0-value withdrawal to rotate keys (migration),
79557
+ * the resulting on-chain commitment is created with safe keys. This method finds
79558
+ * those commitments by:
79559
+ * 1. Identifying legacy accounts with the `isMigrated` flag (set by `addMigrationCommitment`)
79560
+ * 2. Computing the expected commitment hash using safe keys at withdrawal index 0
79561
+ * 3. Verifying the hash exists in on-chain withdrawal events
79562
+ * 4. Adding verified commitments as new safe pool accounts
79563
+ *
79564
+ * @private
79565
+ */
79566
+ _discoverMigratedCommitments(scope, legacyAccounts, withdrawalEvents) {
79567
+ // Build reverse lookup: newCommitment hash → WithdrawalEvent
79568
+ const newCommitmentMap = new Map();
79569
+ for (const event of withdrawalEvents.values()) {
79570
+ newCommitmentMap.set(event.newCommitment, event);
79571
+ }
79572
+ for (const legacyAccount of legacyAccounts) {
79573
+ // Skip if not flagged as migrated (set by addMigrationCommitment)
79574
+ if (!legacyAccount.isMigrated)
79575
+ continue;
79576
+ const migrationChild = legacyAccount.children.find(c => c.isMigration);
79577
+ if (!migrationChild)
79578
+ continue;
79579
+ const label = legacyAccount.label;
79580
+ // The migration child's value is the remaining value carried forward.
79581
+ // Zero-value migrations (full withdrawal + key rotation) are valid and
79582
+ // must still be registered so that poolAccounts.length reflects the
79583
+ // correct slot count for deposit index alignment in step C.
79584
+ const remainingValue = migrationChild.value;
79585
+ // Generate safe nullifier/secret at withdrawal index 0
79586
+ const nullifier = this._genWithdrawalNullifier(label, 0n);
79587
+ const secret = this._genWithdrawalSecret(label, 0n);
79588
+ // Compute expected commitment hash
79589
+ const precommitment = this._hashPrecommitment(nullifier, secret);
79590
+ const expectedHash = this._hashCommitment(remainingValue, label, precommitment);
79591
+ // Verify hash exists in withdrawal events' newCommitment
79592
+ const withdrawalEvent = newCommitmentMap.get(expectedHash);
79593
+ if (!withdrawalEvent)
79594
+ continue;
79595
+ // Verified — add as a new safe pool account
79596
+ const newAccount = this.addPoolAccount(scope, remainingValue, nullifier, secret, label, withdrawalEvent.blockNumber, withdrawalEvent.transactionHash);
79597
+ this.addWithdrawalCommitment(newAccount.deposit, remainingValue, nullifier, secret, withdrawalEvent.blockNumber, withdrawalEvent.transactionHash);
79598
+ this.logger.info(`Discovered migrated commitment for label ${label} with value ${remainingValue}`);
79599
+ }
79600
+ }
79671
79601
  /**
79672
79602
  * Initializes an AccountService instance with events for a given set of pools
79673
79603
  *
@@ -79701,25 +79631,99 @@ class AccountService {
79701
79631
  }
79702
79632
  uniqueScopes.add(pool.scope);
79703
79633
  }
79634
+ // Retry path (non-migration): reuse the existing service's account and
79635
+ // only process pools whose scopes haven't been fully processed yet.
79636
+ // Already-processed scopes are skipped to avoid duplicate deposits and
79637
+ // withdrawal misclassification.
79638
+ //
79639
+ // This path performs simple deposit/withdrawal/ragequit processing only
79640
+ // — no migration discovery. For migration-aware retries, the caller
79641
+ // should re-invoke with { mnemonic } scoped to only the failed pools;
79642
+ // the mnemonic path builds both safe and legacy accounts from scratch
79643
+ // with no shared references.
79644
+ if (!('mnemonic' in source)) {
79645
+ const account = new AccountService(dataService, { account: source.service.account });
79646
+ const processedScopes = source.service.account.poolAccounts;
79647
+ const newPools = pools.filter((p) => !processedScopes.has(p.scope));
79648
+ const errors = await account._processEvents(newPools);
79649
+ return { account, errors };
79650
+ }
79651
+ // Mnemonic path: phased processing with migration discovery
79652
+ const account = new AccountService(dataService, { mnemonic: source.mnemonic });
79653
+ const legacyPrivacyPoolAccount = AccountService._initializeLegacyAccount(source.mnemonic);
79654
+ const legacyAccount = new AccountService(dataService, { account: legacyPrivacyPoolAccount });
79655
+ const errors = await account._processEvents(pools, legacyAccount);
79656
+ return { account, legacyAccount, errors };
79657
+ }
79658
+ /**
79659
+ * Fetches and processes events for a set of pools.
79660
+ *
79661
+ * When a legacyAccount is provided, the full migration-aware pipeline runs
79662
+ * for each scope:
79663
+ * 1. Legacy account: process deposits and withdrawals (to detect migrations)
79664
+ * 2. Safe account: discover migrated commitments from the legacy accounts
79665
+ * 3. Safe account (this): process deposits (starting after migrated accounts)
79666
+ * 4. Safe account: process withdrawals (now includes migrated accounts)
79667
+ * 5. Both accounts: process ragequits
79668
+ *
79669
+ * Migration discovery (step 2) must run before safe deposit scanning (step 3)
79670
+ * so that the migrated account count can be used as the starting index.
79671
+ * Post-migration deposits use poolAccounts.length as their index, which
79672
+ * sits right after the migrated slots; scanning from 0 would hit
79673
+ * MAX_CONSECUTIVE_MISSES on the legacy-key indices and never reach them.
79674
+ *
79675
+ * Without a legacyAccount, only steps 3, 4, and 5 run (simple processing).
79676
+ *
79677
+ * Per-scope errors are caught and returned rather than thrown, and any
79678
+ * partial state left by a mid-scope failure is cleaned from both accounts
79679
+ * so that a subsequent retry starts fresh for that scope.
79680
+ */
79681
+ async _processEvents(pools, legacyAccount) {
79704
79682
  const errors = [];
79705
- const account = new AccountService(dataService, "mnemonic" in source
79706
- ? { mnemonic: source.mnemonic }
79707
- : { account: source.service.account });
79708
- const events = await account.getEvents(pools);
79683
+ const events = await this.getEvents(pools);
79709
79684
  for (const [scope, result] of events.entries()) {
79710
79685
  if ("reason" in result) {
79711
79686
  errors.push(result);
79712
79687
  }
79713
79688
  else {
79714
- // Process deposit events an create pool accounts
79715
- account._processDepositEvents(scope, result.depositEvents);
79716
- // Process withdrawal events and add commitments to pool accounts
79717
- account._processWithdrawalEvents(scope, result.withdrawalEvents);
79718
- // Process ragequit events and add ragequit to pool accounts
79719
- account._processRagequitEvents(scope, result.ragequitEvents);
79689
+ try {
79690
+ // a. Legacy: process deposits + withdrawals
79691
+ if (legacyAccount) {
79692
+ legacyAccount._processDepositEvents(scope, result.depositEvents);
79693
+ legacyAccount._processWithdrawalEvents(scope, result.withdrawalEvents);
79694
+ }
79695
+ // b. Safe: discover migrated commitments from legacy accounts.
79696
+ // Must run before safe deposit scanning so that the migrated
79697
+ // account count can serve as the starting index for step (c),
79698
+ // avoiding a gap of consecutive misses over legacy-key indices.
79699
+ if (legacyAccount) {
79700
+ const legacyAccounts = legacyAccount.account.poolAccounts.get(scope) ?? [];
79701
+ this._discoverMigratedCommitments(scope, legacyAccounts, result.withdrawalEvents);
79702
+ }
79703
+ // c. Safe: process deposits, starting after any migrated accounts.
79704
+ // New deposits created after migration use poolAccounts.length as
79705
+ // their index, so they sit right after the migrated slots.
79706
+ const depositStartIndex = BigInt(this.account.poolAccounts.get(scope)?.length ?? 0);
79707
+ this._processDepositEvents(scope, result.depositEvents, depositStartIndex);
79708
+ // d. Safe: process withdrawals (now includes migrated accounts)
79709
+ this._processWithdrawalEvents(scope, result.withdrawalEvents);
79710
+ // e. Both: process ragequits
79711
+ if (legacyAccount) {
79712
+ legacyAccount._processRagequitEvents(scope, result.ragequitEvents);
79713
+ }
79714
+ this._processRagequitEvents(scope, result.ragequitEvents);
79715
+ }
79716
+ catch (e) {
79717
+ this.account.poolAccounts.delete(scope);
79718
+ legacyAccount?.account.poolAccounts.delete(scope);
79719
+ errors.push({
79720
+ reason: e instanceof Error ? e.message : String(e),
79721
+ scope,
79722
+ });
79723
+ }
79720
79724
  }
79721
79725
  }
79722
- return { account, errors };
79726
+ return errors;
79723
79727
  }
79724
79728
  /**
79725
79729
  * @deprecated Use `initializeWithEvents` for instantiating an account with history reconstruction
@@ -79978,7 +79982,7 @@ class DataService {
79978
79982
  depositor: depositor.toLowerCase(),
79979
79983
  commitment: commitment,
79980
79984
  label: label,
79981
- value: value || BigInt(0),
79985
+ value: value ?? BigInt(0),
79982
79986
  precommitment: precommitment,
79983
79987
  blockNumber: BigInt(typedLog.blockNumber),
79984
79988
  transactionHash: typedLog.transactionHash,
@@ -80030,11 +80034,7 @@ class DataService {
80030
80034
  throw DataError.invalidLog("withdrawal", "missing args");
80031
80035
  }
80032
80036
  const { _value: value, _spentNullifier: spentNullifier, _newCommitment: newCommitment, } = typedLog.args;
80033
- if (!value ||
80034
- !spentNullifier ||
80035
- !newCommitment ||
80036
- !typedLog.blockNumber ||
80037
- !typedLog.transactionHash) {
80037
+ if (value == null || !spentNullifier || !newCommitment || !typedLog.blockNumber || !typedLog.transactionHash) {
80038
80038
  throw DataError.invalidLog("withdrawal", "missing required fields");
80039
80039
  }
80040
80040
  return {
@@ -80102,7 +80102,7 @@ class DataService {
80102
80102
  ragequitter: ragequitter.toLowerCase(),
80103
80103
  commitment: commitment,
80104
80104
  label: label,
80105
- value: value || BigInt(0),
80105
+ value: value ?? BigInt(0),
80106
80106
  blockNumber: BigInt(typedLog.blockNumber),
80107
80107
  transactionHash: typedLog.transactionHash,
80108
80108
  };
@@ -80205,4 +80205,4 @@ class DataService {
80205
80205
  }
80206
80206
 
80207
80207
  export { AccountService as A, BlockchainProvider as B, CommitmentService as C, DataService as D, ErrorCode as E, FetchArtifact as F, InvalidRpcUrl as I, PrivacyPoolSDK as P, SDKError as S, WithdrawalService as W, DEFAULT_LOG_FETCH_CONFIG as a, generateDepositSecrets as b, generateWithdrawalSecrets as c, getCommitment as d, generateMerkleProof as e, bigintToHash as f, generateMasterKeys as g, hashPrecommitment as h, bigintToHex as i, calculateContext as j, Circuits as k, ContractInteractionsService as l, ProofError as m, ContractError as n, AccountError as o, CircuitName as p };
80208
- //# sourceMappingURL=index-BsmEKESv.js.map
80208
+ //# sourceMappingURL=index-b-U_m4Mi.js.map