@veil-cash/sdk 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1840 @@
1
+ import { ethers } from 'ethers';
2
+ import * as crypto from 'crypto';
3
+ import { encodeFunctionData, parseEther, parseUnits, createPublicClient, http, formatEther, formatUnits } from 'viem';
4
+ import { base } from 'viem/chains';
5
+ import MerkleTree from 'fixed-merkle-tree-legacy';
6
+ import { groth16 } from 'snarkjs';
7
+ import * as path from 'path';
8
+ import * as fs from 'fs';
9
+ import { fileURLToPath } from 'url';
10
+
11
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
12
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
13
+ }) : x)(function(x) {
14
+ if (typeof require !== "undefined") return require.apply(this, arguments);
15
+ throw Error('Dynamic require of "' + x + '" is not supported');
16
+ });
17
+ var circomlib = __require("circomlib");
18
+ var poseidon = circomlib.poseidon;
19
+ var FIELD_SIZE = BigInt(
20
+ "21888242871839275222246405745257275088548364400416034343698204186575808495617"
21
+ );
22
+ var poseidonHash = (items) => BigInt(poseidon(items).toString());
23
+ var poseidonHash2 = (a, b) => poseidonHash([a, b]);
24
+ var randomBN = (nbytes = 31) => {
25
+ const bytes = crypto.randomBytes(nbytes);
26
+ let hex = "0x";
27
+ for (let i = 0; i < bytes.length; i++) {
28
+ hex += bytes[i].toString(16).padStart(2, "0");
29
+ }
30
+ return BigInt(hex);
31
+ };
32
+ function toFixedHex(number, length = 32) {
33
+ let hexValue;
34
+ if (number instanceof Buffer) {
35
+ hexValue = number.toString("hex");
36
+ } else {
37
+ let bigIntValue = BigInt(number);
38
+ if (bigIntValue < 0n) {
39
+ const maxValue = 1n << BigInt(length * 8);
40
+ bigIntValue = maxValue + bigIntValue;
41
+ }
42
+ hexValue = bigIntValue.toString(16);
43
+ }
44
+ return "0x" + hexValue.padStart(length * 2, "0");
45
+ }
46
+ var toBuffer = (value, length) => {
47
+ const bigIntValue = BigInt(value);
48
+ const hex = bigIntValue.toString(16).padStart(length * 2, "0");
49
+ return Buffer.from(hex, "hex");
50
+ };
51
+ function getExtDataHash(extData) {
52
+ const { ethers: ethers2 } = __require("ethers");
53
+ const abi = ethers2.AbiCoder.defaultAbiCoder();
54
+ const encodedData = abi.encode(
55
+ ["tuple(address,int256,address,uint256,bytes,bytes)"],
56
+ [[
57
+ extData.recipient,
58
+ extData.extAmount,
59
+ extData.relayer,
60
+ extData.fee,
61
+ extData.encryptedOutput1,
62
+ extData.encryptedOutput2
63
+ ]]
64
+ );
65
+ const hash = ethers2.keccak256(encodedData);
66
+ return BigInt(hash) % FIELD_SIZE;
67
+ }
68
+ function shuffle(array) {
69
+ let currentIndex = array.length;
70
+ let randomIndex;
71
+ while (currentIndex !== 0) {
72
+ randomIndex = Math.floor(Math.random() * currentIndex);
73
+ currentIndex--;
74
+ [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
75
+ }
76
+ return array;
77
+ }
78
+
79
+ // src/keypair.ts
80
+ var ethSigUtil = __require("eth-sig-util");
81
+ function packEncryptedMessage(encryptedMessage) {
82
+ const nonceBuf = Buffer.from(encryptedMessage.nonce, "base64");
83
+ const ephemPublicKeyBuf = Buffer.from(encryptedMessage.ephemPublicKey, "base64");
84
+ const ciphertextBuf = Buffer.from(encryptedMessage.ciphertext, "base64");
85
+ const messageBuff = Buffer.concat([
86
+ Buffer.alloc(24 - nonceBuf.length),
87
+ nonceBuf,
88
+ Buffer.alloc(32 - ephemPublicKeyBuf.length),
89
+ ephemPublicKeyBuf,
90
+ ciphertextBuf
91
+ ]);
92
+ return "0x" + messageBuff.toString("hex");
93
+ }
94
+ function unpackEncryptedMessage(encryptedMessage) {
95
+ if (encryptedMessage.slice(0, 2) === "0x") {
96
+ encryptedMessage = encryptedMessage.slice(2);
97
+ }
98
+ const messageBuff = Buffer.from(encryptedMessage, "hex");
99
+ const nonceBuf = messageBuff.slice(0, 24);
100
+ const ephemPublicKeyBuf = messageBuff.slice(24, 56);
101
+ const ciphertextBuf = messageBuff.slice(56);
102
+ return {
103
+ version: "x25519-xsalsa20-poly1305",
104
+ nonce: nonceBuf.toString("base64"),
105
+ ephemPublicKey: ephemPublicKeyBuf.toString("base64"),
106
+ ciphertext: ciphertextBuf.toString("base64")
107
+ };
108
+ }
109
+ var Keypair = class _Keypair {
110
+ /** Private key (null if created from public deposit key only) */
111
+ privkey;
112
+ /** Public key (Poseidon hash of private key) */
113
+ pubkey;
114
+ /** x25519 encryption public key */
115
+ encryptionKey;
116
+ /**
117
+ * Create a new Keypair
118
+ * @param privkey - Optional private key. If not provided, generates a random one.
119
+ */
120
+ constructor(privkey = ethers.Wallet.createRandom().privateKey) {
121
+ this.privkey = privkey;
122
+ this.pubkey = poseidonHash([this.privkey]);
123
+ this.encryptionKey = ethSigUtil.getEncryptionPublicKey(privkey.slice(2));
124
+ }
125
+ /**
126
+ * Get the deposit key for this keypair
127
+ * This is what you register on-chain
128
+ * @returns Deposit key as hex string (130 chars with 0x prefix)
129
+ */
130
+ toString() {
131
+ return toFixedHex(this.pubkey) + Buffer.from(this.encryptionKey, "base64").toString("hex");
132
+ }
133
+ /**
134
+ * Alias for toString() - returns the deposit key
135
+ * @returns Deposit key as hex string
136
+ */
137
+ depositKey() {
138
+ return this.toString();
139
+ }
140
+ /**
141
+ * Create a Keypair from a public deposit key (without private key)
142
+ * Useful for sending transfers to other users
143
+ * @param str - Deposit key (128 or 130 hex chars)
144
+ * @returns Keypair instance (privkey will be null)
145
+ */
146
+ static fromString(str) {
147
+ if (str.length === 130) {
148
+ str = str.slice(2);
149
+ }
150
+ if (str.length !== 128) {
151
+ throw new Error("Invalid deposit key length. Expected 128 hex chars (or 130 with 0x prefix)");
152
+ }
153
+ return Object.assign(new _Keypair(), {
154
+ privkey: null,
155
+ pubkey: BigInt("0x" + str.slice(0, 64)),
156
+ encryptionKey: Buffer.from(str.slice(64, 128), "hex").toString("base64")
157
+ });
158
+ }
159
+ /**
160
+ * Sign a message using the private key
161
+ * @param commitment - Commitment hash
162
+ * @param merklePath - Merkle path
163
+ * @returns Signature as bigint
164
+ */
165
+ sign(commitment, merklePath) {
166
+ if (!this.privkey) {
167
+ throw new Error("Cannot sign without private key");
168
+ }
169
+ return poseidonHash([this.privkey, commitment, merklePath]);
170
+ }
171
+ /**
172
+ * Encrypt data using the encryption key
173
+ * @param bytes - Data to encrypt
174
+ * @returns Encrypted data as hex string
175
+ */
176
+ encrypt(bytes) {
177
+ return packEncryptedMessage(
178
+ ethSigUtil.encrypt(
179
+ this.encryptionKey,
180
+ { data: bytes.toString("base64") },
181
+ "x25519-xsalsa20-poly1305"
182
+ )
183
+ );
184
+ }
185
+ /**
186
+ * Decrypt data using the private key
187
+ * @param data - Encrypted data as hex string
188
+ * @returns Decrypted data as Buffer
189
+ */
190
+ decrypt(data) {
191
+ if (!this.privkey) {
192
+ throw new Error("Cannot decrypt without private key");
193
+ }
194
+ return Buffer.from(
195
+ ethSigUtil.decrypt(unpackEncryptedMessage(data), this.privkey.slice(2)),
196
+ "base64"
197
+ );
198
+ }
199
+ };
200
+
201
+ // src/utxo.ts
202
+ var Utxo = class _Utxo {
203
+ amount;
204
+ blinding;
205
+ keypair;
206
+ index;
207
+ _commitment;
208
+ _nullifier;
209
+ /**
210
+ * Create a new UTXO
211
+ * @param params - UTXO parameters
212
+ */
213
+ constructor(params = {}) {
214
+ const { amount = 0, keypair = new Keypair(), blinding = randomBN(), index } = params;
215
+ this.amount = BigInt(amount);
216
+ this.blinding = BigInt(blinding);
217
+ this.keypair = keypair;
218
+ this.index = index;
219
+ }
220
+ /**
221
+ * Get the commitment for this UTXO
222
+ * commitment = poseidonHash([amount, pubkey, blinding])
223
+ * @returns Commitment as bigint
224
+ */
225
+ getCommitment() {
226
+ if (!this._commitment) {
227
+ this._commitment = poseidonHash([this.amount, this.keypair.pubkey, this.blinding]);
228
+ }
229
+ return this._commitment;
230
+ }
231
+ /**
232
+ * Get the nullifier for this UTXO
233
+ * Requires index and private key to be set
234
+ * nullifier = poseidonHash([commitment, index, signature])
235
+ * @returns Nullifier as bigint
236
+ */
237
+ getNullifier() {
238
+ if (!this._nullifier) {
239
+ if (this.amount > 0n && (this.index === void 0 || !this.keypair.privkey)) {
240
+ throw new Error("Cannot compute nullifier without UTXO index or private key");
241
+ }
242
+ const signature = this.keypair.privkey ? this.keypair.sign(this.getCommitment(), this.index || 0) : 0n;
243
+ this._nullifier = poseidonHash([this.getCommitment(), this.index || 0, signature]);
244
+ }
245
+ return this._nullifier;
246
+ }
247
+ /**
248
+ * Encrypt UTXO data using the keypair
249
+ * @returns Encrypted data as 0x-prefixed hex string
250
+ */
251
+ encrypt() {
252
+ const bytes = Buffer.concat([
253
+ toBuffer(this.amount, 31),
254
+ toBuffer(this.blinding, 31)
255
+ ]);
256
+ return this.keypair.encrypt(bytes);
257
+ }
258
+ /**
259
+ * Decrypt an encrypted output to create a UTXO
260
+ * Only succeeds if the keypair owns this UTXO
261
+ *
262
+ * @param data - Encrypted output as hex string
263
+ * @param keypair - Keypair to decrypt with
264
+ * @returns Decrypted UTXO
265
+ * @throws If decryption fails (wrong keypair)
266
+ */
267
+ static decrypt(data, keypair) {
268
+ const buf = keypair.decrypt(data);
269
+ return new _Utxo({
270
+ amount: BigInt("0x" + buf.slice(0, 31).toString("hex")),
271
+ blinding: BigInt("0x" + buf.slice(31, 62).toString("hex")),
272
+ keypair
273
+ });
274
+ }
275
+ };
276
+
277
+ // src/addresses.ts
278
+ var ADDRESSES = {
279
+ entry: "0xc2535c547B64b997A4BD9202E1663deaF11c78a5",
280
+ ethPool: "0x293dCda114533FF8f477271c5cA517209FFDEEe7",
281
+ ethQueue: "0xA4a926A2E7a22c38e8DFC6744A61a6aA8b06B230",
282
+ usdcPool: "0x5c50d58E49C59d112680c187De2Bf989d2a91242",
283
+ usdcQueue: "0x5530241b24504bF05C9a22e95A1F5458888e6a9B",
284
+ usdcToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
285
+ chainId: 8453,
286
+ relayUrl: "https://veil-relay.up.railway.app"
287
+ };
288
+ var POOL_CONFIG = {
289
+ eth: {
290
+ decimals: 18,
291
+ displayDecimals: 4,
292
+ symbol: "ETH",
293
+ name: "Ethereum"
294
+ },
295
+ usdc: {
296
+ decimals: 6,
297
+ displayDecimals: 2,
298
+ symbol: "USDC",
299
+ name: "USD Coin"
300
+ }
301
+ };
302
+ function getAddresses() {
303
+ return ADDRESSES;
304
+ }
305
+ function getRelayUrl() {
306
+ return ADDRESSES.relayUrl;
307
+ }
308
+
309
+ // src/abi.ts
310
+ var ENTRY_ABI = [
311
+ // ============ ERRORS ============
312
+ { inputs: [], name: "DepositsDisabled", type: "error" },
313
+ { inputs: [], name: "FeeTransferFailed", type: "error" },
314
+ { inputs: [], name: "InvalidDepositKey", type: "error" },
315
+ { inputs: [], name: "InvalidDepositKeyForUser", type: "error" },
316
+ { inputs: [], name: "InvalidInitialization", type: "error" },
317
+ { inputs: [], name: "MinimumDepositNotMet", type: "error" },
318
+ { inputs: [], name: "NotAllowedToDeposit", type: "error" },
319
+ { inputs: [], name: "NotInitializing", type: "error" },
320
+ { inputs: [], name: "OnlyOperatorAllowed", type: "error" },
321
+ { inputs: [], name: "OnlyOwnerCanRegister", type: "error" },
322
+ { inputs: [], name: "OnlyQueueContractAllowed", type: "error" },
323
+ { inputs: [{ name: "owner", type: "address" }], name: "OwnableInvalidOwner", type: "error" },
324
+ { inputs: [{ name: "account", type: "address" }], name: "OwnableUnauthorizedAccount", type: "error" },
325
+ { inputs: [], name: "ReentrancyGuardReentrantCall", type: "error" },
326
+ { inputs: [], name: "USDCTransferFailed", type: "error" },
327
+ { inputs: [], name: "UserAlreadyRegistered", type: "error" },
328
+ { inputs: [], name: "UserNotRegistered", type: "error" },
329
+ // ============ EVENTS ============
330
+ {
331
+ anonymous: false,
332
+ inputs: [
333
+ { indexed: true, name: "owner", type: "address" },
334
+ { indexed: false, name: "key", type: "bytes" }
335
+ ],
336
+ name: "DepositKey",
337
+ type: "event"
338
+ },
339
+ {
340
+ anonymous: false,
341
+ inputs: [
342
+ { indexed: true, name: "depositor", type: "address" },
343
+ { indexed: false, name: "amount", type: "uint256" }
344
+ ],
345
+ name: "DepositedETH",
346
+ type: "event"
347
+ },
348
+ // ============ FUNCTIONS ============
349
+ // Register deposit key
350
+ {
351
+ inputs: [
352
+ {
353
+ components: [
354
+ { name: "owner", type: "address" },
355
+ { name: "depositKey", type: "bytes" }
356
+ ],
357
+ name: "_account",
358
+ type: "tuple"
359
+ }
360
+ ],
361
+ name: "register",
362
+ outputs: [],
363
+ stateMutability: "nonpayable",
364
+ type: "function"
365
+ },
366
+ // Queue ETH deposit
367
+ {
368
+ inputs: [{ name: "_depositKey", type: "bytes" }],
369
+ name: "queueETH",
370
+ outputs: [],
371
+ stateMutability: "payable",
372
+ type: "function"
373
+ },
374
+ // Queue USDC deposit
375
+ {
376
+ inputs: [
377
+ { name: "_amount", type: "uint256" },
378
+ { name: "_depositKey", type: "bytes" }
379
+ ],
380
+ name: "queueUSDC",
381
+ outputs: [],
382
+ stateMutability: "nonpayable",
383
+ type: "function"
384
+ },
385
+ // Read deposit keys
386
+ {
387
+ inputs: [{ name: "", type: "address" }],
388
+ name: "depositKeys",
389
+ outputs: [{ name: "", type: "bytes" }],
390
+ stateMutability: "view",
391
+ type: "function"
392
+ },
393
+ // Check if deposits are enabled
394
+ {
395
+ inputs: [],
396
+ name: "depositETHEnabled",
397
+ outputs: [{ name: "", type: "bool" }],
398
+ stateMutability: "view",
399
+ type: "function"
400
+ },
401
+ // Get deposit fee
402
+ {
403
+ inputs: [],
404
+ name: "depositFee",
405
+ outputs: [{ name: "", type: "uint256" }],
406
+ stateMutability: "view",
407
+ type: "function"
408
+ },
409
+ // Get minimum deposit
410
+ {
411
+ inputs: [],
412
+ name: "minimumDeposit",
413
+ outputs: [{ name: "", type: "uint256" }],
414
+ stateMutability: "view",
415
+ type: "function"
416
+ },
417
+ // Calculate fee and net deposit
418
+ {
419
+ inputs: [{ name: "_totalAmount", type: "uint256" }],
420
+ name: "getFeeAndNetDeposit",
421
+ outputs: [
422
+ { name: "netDeposit", type: "uint256" },
423
+ { name: "fee", type: "uint256" }
424
+ ],
425
+ stateMutability: "view",
426
+ type: "function"
427
+ },
428
+ // Calculate deposit amount with fee
429
+ {
430
+ inputs: [{ name: "_netDepositAmount", type: "uint256" }],
431
+ name: "getDepositAmountWithFee",
432
+ outputs: [{ name: "", type: "uint256" }],
433
+ stateMutability: "view",
434
+ type: "function"
435
+ },
436
+ // Check if user is allowed depositor
437
+ {
438
+ inputs: [{ name: "_depositor", type: "address" }],
439
+ name: "isAllowedDepositor",
440
+ outputs: [{ name: "", type: "bool" }],
441
+ stateMutability: "view",
442
+ type: "function"
443
+ }
444
+ ];
445
+ var QUEUE_ABI = [
446
+ // Get all pending deposit nonces
447
+ {
448
+ inputs: [],
449
+ name: "getPendingDeposits",
450
+ outputs: [{ name: "nonces", type: "uint256[]" }],
451
+ stateMutability: "view",
452
+ type: "function"
453
+ },
454
+ // Get deposit details by nonce
455
+ {
456
+ inputs: [{ name: "_nonce", type: "uint256" }],
457
+ name: "getDeposit",
458
+ outputs: [
459
+ {
460
+ components: [
461
+ { name: "fallbackReceiver", type: "address" },
462
+ { name: "amountIn", type: "uint256" },
463
+ { name: "fee", type: "uint256" },
464
+ { name: "shieldAmount", type: "uint256" },
465
+ { name: "timestamp", type: "uint256" },
466
+ { name: "status", type: "uint8" },
467
+ { name: "depositKey", type: "bytes" }
468
+ ],
469
+ name: "deposit",
470
+ type: "tuple"
471
+ }
472
+ ],
473
+ stateMutability: "view",
474
+ type: "function"
475
+ },
476
+ // Get current nonce counter
477
+ {
478
+ inputs: [],
479
+ name: "depositQueueNonce",
480
+ outputs: [{ name: "", type: "uint256" }],
481
+ stateMutability: "view",
482
+ type: "function"
483
+ },
484
+ // Get pending count
485
+ {
486
+ inputs: [],
487
+ name: "getPendingCount",
488
+ outputs: [{ name: "count", type: "uint256" }],
489
+ stateMutability: "view",
490
+ type: "function"
491
+ }
492
+ ];
493
+ var POOL_ABI = [
494
+ // ============ ERRORS ============
495
+ { inputs: [], name: "CannotWithdrawToZeroAddress", type: "error" },
496
+ { inputs: [], name: "ETHTransferFailed", type: "error" },
497
+ { inputs: [], name: "IncorrectExternalDataHash", type: "error" },
498
+ { inputs: [], name: "InputAlreadySpent", type: "error" },
499
+ { inputs: [], name: "InvalidExtAmount", type: "error" },
500
+ { inputs: [], name: "InvalidFee", type: "error" },
501
+ { inputs: [], name: "InvalidMerkleRoot", type: "error" },
502
+ { inputs: [], name: "InvalidPublicAmount", type: "error" },
503
+ { inputs: [], name: "InvalidRange", type: "error" },
504
+ { inputs: [], name: "InvalidTransactionProof", type: "error" },
505
+ { inputs: [], name: "OnlyForDeposits", type: "error" },
506
+ { inputs: [], name: "OnlyForTransfers", type: "error" },
507
+ { inputs: [], name: "OnlyForWithdrawals", type: "error" },
508
+ { inputs: [], name: "OnlyValidatorContractAllowed", type: "error" },
509
+ { inputs: [], name: "OnlyWETHContractAllowed", type: "error" },
510
+ { inputs: [{ name: "owner", type: "address" }], name: "OwnableInvalidOwner", type: "error" },
511
+ { inputs: [{ name: "account", type: "address" }], name: "OwnableUnauthorizedAccount", type: "error" },
512
+ { inputs: [], name: "ProofAmountMismatch", type: "error" },
513
+ { inputs: [], name: "ReentrancyGuardReentrantCall", type: "error" },
514
+ { inputs: [], name: "UnsupportedInputCount", type: "error" },
515
+ { inputs: [], name: "WETHDepositFailed", type: "error" },
516
+ { inputs: [], name: "WETHUnwrapFailed", type: "error" },
517
+ // ============ EVENTS ============
518
+ {
519
+ anonymous: false,
520
+ inputs: [
521
+ { indexed: false, name: "commitment", type: "bytes32" },
522
+ { indexed: false, name: "index", type: "uint256" },
523
+ { indexed: false, name: "encryptedOutput", type: "bytes" }
524
+ ],
525
+ name: "NewCommitment",
526
+ type: "event"
527
+ },
528
+ {
529
+ anonymous: false,
530
+ inputs: [{ indexed: false, name: "nullifier", type: "bytes32" }],
531
+ name: "NewNullifier",
532
+ type: "event"
533
+ },
534
+ {
535
+ anonymous: false,
536
+ inputs: [
537
+ { indexed: true, name: "previousOwner", type: "address" },
538
+ { indexed: true, name: "newOwner", type: "address" }
539
+ ],
540
+ name: "OwnershipTransferred",
541
+ type: "event"
542
+ },
543
+ {
544
+ anonymous: false,
545
+ inputs: [{ indexed: true, name: "newValidatorContract", type: "address" }],
546
+ name: "ValidatorContractUpdated",
547
+ type: "event"
548
+ },
549
+ // ============ VIEW FUNCTIONS ============
550
+ {
551
+ inputs: [],
552
+ name: "FIELD_SIZE",
553
+ outputs: [{ name: "", type: "uint256" }],
554
+ stateMutability: "view",
555
+ type: "function"
556
+ },
557
+ {
558
+ inputs: [],
559
+ name: "ROOT_HISTORY_SIZE",
560
+ outputs: [{ name: "", type: "uint32" }],
561
+ stateMutability: "view",
562
+ type: "function"
563
+ },
564
+ {
565
+ inputs: [],
566
+ name: "ZERO_VALUE",
567
+ outputs: [{ name: "", type: "uint256" }],
568
+ stateMutability: "view",
569
+ type: "function"
570
+ },
571
+ {
572
+ inputs: [{ name: "", type: "uint256" }],
573
+ name: "commitments",
574
+ outputs: [{ name: "", type: "bytes32" }],
575
+ stateMutability: "view",
576
+ type: "function"
577
+ },
578
+ {
579
+ inputs: [],
580
+ name: "currentRootIndex",
581
+ outputs: [{ name: "", type: "uint32" }],
582
+ stateMutability: "view",
583
+ type: "function"
584
+ },
585
+ {
586
+ inputs: [{ name: "", type: "uint256" }],
587
+ name: "encryptedOutputs",
588
+ outputs: [{ name: "", type: "bytes" }],
589
+ stateMutability: "view",
590
+ type: "function"
591
+ },
592
+ {
593
+ inputs: [{ name: "", type: "uint256" }],
594
+ name: "filledSubtrees",
595
+ outputs: [{ name: "", type: "bytes32" }],
596
+ stateMutability: "view",
597
+ type: "function"
598
+ },
599
+ {
600
+ inputs: [
601
+ { name: "startIndex", type: "uint256" },
602
+ { name: "endIndex", type: "uint256" }
603
+ ],
604
+ name: "getCommitments",
605
+ outputs: [{ name: "", type: "bytes32[]" }],
606
+ stateMutability: "view",
607
+ type: "function"
608
+ },
609
+ {
610
+ inputs: [
611
+ { name: "startIndex", type: "uint256" },
612
+ { name: "endIndex", type: "uint256" }
613
+ ],
614
+ name: "getEncryptedOutputs",
615
+ outputs: [{ name: "", type: "bytes[]" }],
616
+ stateMutability: "view",
617
+ type: "function"
618
+ },
619
+ {
620
+ inputs: [],
621
+ name: "getLastRoot",
622
+ outputs: [{ name: "", type: "bytes32" }],
623
+ stateMutability: "view",
624
+ type: "function"
625
+ },
626
+ {
627
+ inputs: [
628
+ { name: "_left", type: "bytes32" },
629
+ { name: "_right", type: "bytes32" }
630
+ ],
631
+ name: "hashLeftRight",
632
+ outputs: [{ name: "", type: "bytes32" }],
633
+ stateMutability: "view",
634
+ type: "function"
635
+ },
636
+ {
637
+ inputs: [],
638
+ name: "hasher",
639
+ outputs: [{ name: "", type: "address" }],
640
+ stateMutability: "view",
641
+ type: "function"
642
+ },
643
+ {
644
+ inputs: [{ name: "_root", type: "bytes32" }],
645
+ name: "isKnownRoot",
646
+ outputs: [{ name: "", type: "bool" }],
647
+ stateMutability: "view",
648
+ type: "function"
649
+ },
650
+ {
651
+ inputs: [{ name: "_nullifierHash", type: "bytes32" }],
652
+ name: "isSpent",
653
+ outputs: [{ name: "", type: "bool" }],
654
+ stateMutability: "view",
655
+ type: "function"
656
+ },
657
+ {
658
+ inputs: [],
659
+ name: "levels",
660
+ outputs: [{ name: "", type: "uint32" }],
661
+ stateMutability: "view",
662
+ type: "function"
663
+ },
664
+ {
665
+ inputs: [],
666
+ name: "nextIndex",
667
+ outputs: [{ name: "", type: "uint32" }],
668
+ stateMutability: "view",
669
+ type: "function"
670
+ },
671
+ {
672
+ inputs: [{ name: "", type: "bytes32" }],
673
+ name: "nullifierHashes",
674
+ outputs: [{ name: "", type: "bool" }],
675
+ stateMutability: "view",
676
+ type: "function"
677
+ },
678
+ {
679
+ inputs: [],
680
+ name: "owner",
681
+ outputs: [{ name: "", type: "address" }],
682
+ stateMutability: "view",
683
+ type: "function"
684
+ },
685
+ {
686
+ inputs: [{ name: "", type: "uint256" }],
687
+ name: "roots",
688
+ outputs: [{ name: "", type: "bytes32" }],
689
+ stateMutability: "view",
690
+ type: "function"
691
+ },
692
+ {
693
+ inputs: [],
694
+ name: "validatorContract",
695
+ outputs: [{ name: "", type: "address" }],
696
+ stateMutability: "view",
697
+ type: "function"
698
+ },
699
+ {
700
+ inputs: [],
701
+ name: "verifier16",
702
+ outputs: [{ name: "", type: "address" }],
703
+ stateMutability: "view",
704
+ type: "function"
705
+ },
706
+ {
707
+ inputs: [],
708
+ name: "verifier2",
709
+ outputs: [{ name: "", type: "address" }],
710
+ stateMutability: "view",
711
+ type: "function"
712
+ },
713
+ {
714
+ inputs: [],
715
+ name: "weth",
716
+ outputs: [{ name: "", type: "address" }],
717
+ stateMutability: "view",
718
+ type: "function"
719
+ },
720
+ {
721
+ inputs: [{ name: "i", type: "uint256" }],
722
+ name: "zeros",
723
+ outputs: [{ name: "", type: "bytes32" }],
724
+ stateMutability: "pure",
725
+ type: "function"
726
+ },
727
+ // ============ PURE FUNCTIONS ============
728
+ {
729
+ inputs: [
730
+ { name: "_extAmount", type: "int256" },
731
+ { name: "_fee", type: "uint256" }
732
+ ],
733
+ name: "calculatePublicAmount",
734
+ outputs: [{ name: "", type: "uint256" }],
735
+ stateMutability: "pure",
736
+ type: "function"
737
+ },
738
+ // ============ WRITE FUNCTIONS ============
739
+ {
740
+ inputs: [
741
+ {
742
+ components: [
743
+ { name: "proof", type: "bytes" },
744
+ { name: "root", type: "bytes32" },
745
+ { name: "inputNullifiers", type: "bytes32[]" },
746
+ { name: "outputCommitments", type: "bytes32[2]" },
747
+ { name: "publicAmount", type: "uint256" },
748
+ { name: "extDataHash", type: "bytes32" }
749
+ ],
750
+ name: "_args",
751
+ type: "tuple"
752
+ },
753
+ {
754
+ components: [
755
+ { name: "recipient", type: "address" },
756
+ { name: "extAmount", type: "int256" },
757
+ { name: "relayer", type: "address" },
758
+ { name: "fee", type: "uint256" },
759
+ { name: "encryptedOutput1", type: "bytes" },
760
+ { name: "encryptedOutput2", type: "bytes" }
761
+ ],
762
+ name: "_extData",
763
+ type: "tuple"
764
+ }
765
+ ],
766
+ name: "depositETH",
767
+ outputs: [],
768
+ stateMutability: "payable",
769
+ type: "function"
770
+ },
771
+ {
772
+ inputs: [
773
+ {
774
+ components: [
775
+ { name: "proof", type: "bytes" },
776
+ { name: "root", type: "bytes32" },
777
+ { name: "inputNullifiers", type: "bytes32[]" },
778
+ { name: "outputCommitments", type: "bytes32[2]" },
779
+ { name: "publicAmount", type: "uint256" },
780
+ { name: "extDataHash", type: "bytes32" }
781
+ ],
782
+ name: "_args",
783
+ type: "tuple"
784
+ },
785
+ {
786
+ components: [
787
+ { name: "recipient", type: "address" },
788
+ { name: "extAmount", type: "int256" },
789
+ { name: "relayer", type: "address" },
790
+ { name: "fee", type: "uint256" },
791
+ { name: "encryptedOutput1", type: "bytes" },
792
+ { name: "encryptedOutput2", type: "bytes" }
793
+ ],
794
+ name: "_extData",
795
+ type: "tuple"
796
+ }
797
+ ],
798
+ name: "transactETH",
799
+ outputs: [],
800
+ stateMutability: "nonpayable",
801
+ type: "function"
802
+ },
803
+ {
804
+ inputs: [
805
+ {
806
+ components: [
807
+ { name: "proof", type: "bytes" },
808
+ { name: "root", type: "bytes32" },
809
+ { name: "inputNullifiers", type: "bytes32[]" },
810
+ { name: "outputCommitments", type: "bytes32[2]" },
811
+ { name: "publicAmount", type: "uint256" },
812
+ { name: "extDataHash", type: "bytes32" }
813
+ ],
814
+ name: "_args",
815
+ type: "tuple"
816
+ },
817
+ {
818
+ components: [
819
+ { name: "recipient", type: "address" },
820
+ { name: "extAmount", type: "int256" },
821
+ { name: "relayer", type: "address" },
822
+ { name: "fee", type: "uint256" },
823
+ { name: "encryptedOutput1", type: "bytes" },
824
+ { name: "encryptedOutput2", type: "bytes" }
825
+ ],
826
+ name: "_extData",
827
+ type: "tuple"
828
+ }
829
+ ],
830
+ name: "withdrawETH",
831
+ outputs: [],
832
+ stateMutability: "nonpayable",
833
+ type: "function"
834
+ },
835
+ {
836
+ inputs: [
837
+ {
838
+ components: [
839
+ { name: "proof", type: "bytes" },
840
+ { name: "root", type: "bytes32" },
841
+ { name: "inputNullifiers", type: "bytes32[]" },
842
+ { name: "outputCommitments", type: "bytes32[2]" },
843
+ { name: "publicAmount", type: "uint256" },
844
+ { name: "extDataHash", type: "bytes32" }
845
+ ],
846
+ name: "_args",
847
+ type: "tuple"
848
+ }
849
+ ],
850
+ name: "verifyProof",
851
+ outputs: [{ name: "", type: "bool" }],
852
+ stateMutability: "view",
853
+ type: "function"
854
+ },
855
+ {
856
+ inputs: [],
857
+ name: "renounceOwnership",
858
+ outputs: [],
859
+ stateMutability: "nonpayable",
860
+ type: "function"
861
+ },
862
+ {
863
+ inputs: [{ name: "newOwner", type: "address" }],
864
+ name: "transferOwnership",
865
+ outputs: [],
866
+ stateMutability: "nonpayable",
867
+ type: "function"
868
+ },
869
+ {
870
+ inputs: [{ name: "_newValidator", type: "address" }],
871
+ name: "updateValidatorContract",
872
+ outputs: [],
873
+ stateMutability: "nonpayable",
874
+ type: "function"
875
+ },
876
+ // ============ RECEIVE ============
877
+ { stateMutability: "payable", type: "receive" }
878
+ ];
879
+ var ERC20_ABI = [
880
+ {
881
+ inputs: [
882
+ { name: "spender", type: "address" },
883
+ { name: "amount", type: "uint256" }
884
+ ],
885
+ name: "approve",
886
+ outputs: [{ name: "", type: "bool" }],
887
+ stateMutability: "nonpayable",
888
+ type: "function"
889
+ },
890
+ {
891
+ inputs: [{ name: "account", type: "address" }],
892
+ name: "balanceOf",
893
+ outputs: [{ name: "", type: "uint256" }],
894
+ stateMutability: "view",
895
+ type: "function"
896
+ },
897
+ {
898
+ inputs: [
899
+ { name: "owner", type: "address" },
900
+ { name: "spender", type: "address" }
901
+ ],
902
+ name: "allowance",
903
+ outputs: [{ name: "", type: "uint256" }],
904
+ stateMutability: "view",
905
+ type: "function"
906
+ }
907
+ ];
908
+
909
+ // src/deposit.ts
910
+ function buildRegisterTx(depositKey, ownerAddress) {
911
+ const addresses = getAddresses();
912
+ const data = encodeFunctionData({
913
+ abi: ENTRY_ABI,
914
+ functionName: "register",
915
+ args: [{
916
+ owner: ownerAddress,
917
+ depositKey
918
+ }]
919
+ });
920
+ return {
921
+ to: addresses.entry,
922
+ data
923
+ };
924
+ }
925
+ function buildDepositETHTx(options) {
926
+ const { depositKey, amount } = options;
927
+ const addresses = getAddresses();
928
+ const value = parseEther(amount);
929
+ const data = encodeFunctionData({
930
+ abi: ENTRY_ABI,
931
+ functionName: "queueETH",
932
+ args: [depositKey]
933
+ });
934
+ return {
935
+ to: addresses.entry,
936
+ data,
937
+ value
938
+ };
939
+ }
940
+ function buildApproveUSDCTx(options) {
941
+ const { amount } = options;
942
+ const addresses = getAddresses();
943
+ const amountWei = parseUnits(amount, POOL_CONFIG.usdc.decimals);
944
+ const data = encodeFunctionData({
945
+ abi: ERC20_ABI,
946
+ functionName: "approve",
947
+ args: [addresses.entry, amountWei]
948
+ });
949
+ return {
950
+ to: addresses.usdcToken,
951
+ data
952
+ };
953
+ }
954
+ function buildDepositUSDCTx(options) {
955
+ const { depositKey, amount } = options;
956
+ const addresses = getAddresses();
957
+ const amountWei = parseUnits(amount, POOL_CONFIG.usdc.decimals);
958
+ const data = encodeFunctionData({
959
+ abi: ENTRY_ABI,
960
+ functionName: "queueUSDC",
961
+ args: [amountWei, depositKey]
962
+ });
963
+ return {
964
+ to: addresses.entry,
965
+ data
966
+ };
967
+ }
968
+ function buildDepositTx(options) {
969
+ const { token = "ETH", ...rest } = options;
970
+ if (token === "USDC") {
971
+ return buildDepositUSDCTx(rest);
972
+ }
973
+ return buildDepositETHTx(rest);
974
+ }
975
+ var DEPOSIT_STATUS_MAP = {
976
+ 0: "pending",
977
+ 1: "accepted",
978
+ 2: "rejected",
979
+ 3: "refunded"
980
+ };
981
+ async function getQueueBalance(options) {
982
+ const { address, rpcUrl, onProgress } = options;
983
+ const addresses = getAddresses();
984
+ const publicClient = createPublicClient({
985
+ chain: base,
986
+ transport: http(rpcUrl)
987
+ });
988
+ onProgress?.("Fetching pending deposits...");
989
+ const pendingNonces = await publicClient.readContract({
990
+ address: addresses.ethQueue,
991
+ abi: QUEUE_ABI,
992
+ functionName: "getPendingDeposits"
993
+ });
994
+ onProgress?.("Queue status", `${pendingNonces.length} pending deposits in queue`);
995
+ const pendingDeposits = [];
996
+ let totalQueueBalance = 0n;
997
+ for (let i = 0; i < pendingNonces.length; i++) {
998
+ const nonce = pendingNonces[i];
999
+ onProgress?.("Checking deposit", `${i + 1}/${pendingNonces.length}`);
1000
+ const deposit = await publicClient.readContract({
1001
+ address: addresses.ethQueue,
1002
+ abi: QUEUE_ABI,
1003
+ functionName: "getDeposit",
1004
+ args: [nonce]
1005
+ });
1006
+ if (deposit.fallbackReceiver.toLowerCase() === address.toLowerCase()) {
1007
+ totalQueueBalance += deposit.amountIn;
1008
+ pendingDeposits.push({
1009
+ nonce: nonce.toString(),
1010
+ status: DEPOSIT_STATUS_MAP[deposit.status] || "pending",
1011
+ amount: formatEther(deposit.amountIn),
1012
+ amountWei: deposit.amountIn.toString(),
1013
+ timestamp: new Date(Number(deposit.timestamp) * 1e3).toISOString()
1014
+ });
1015
+ }
1016
+ }
1017
+ if (pendingDeposits.length > 0) {
1018
+ onProgress?.("Found", `${pendingDeposits.length} deposits for your address`);
1019
+ }
1020
+ return {
1021
+ address,
1022
+ queueBalance: formatEther(totalQueueBalance),
1023
+ queueBalanceWei: totalQueueBalance.toString(),
1024
+ pendingDeposits,
1025
+ pendingCount: pendingDeposits.length
1026
+ };
1027
+ }
1028
+ async function getPrivateBalance(options) {
1029
+ const { keypair, rpcUrl, onProgress } = options;
1030
+ const addresses = getAddresses();
1031
+ if (!keypair.privkey) {
1032
+ throw new Error("Keypair must have a private key to calculate private balance");
1033
+ }
1034
+ const publicClient = createPublicClient({
1035
+ chain: base,
1036
+ transport: http(rpcUrl)
1037
+ });
1038
+ onProgress?.("Fetching pool index...");
1039
+ const nextIndex = await publicClient.readContract({
1040
+ address: addresses.ethPool,
1041
+ abi: POOL_ABI,
1042
+ functionName: "nextIndex"
1043
+ });
1044
+ onProgress?.("Pool index", `${nextIndex} commitments`);
1045
+ if (nextIndex === 0) {
1046
+ return {
1047
+ privateBalance: "0",
1048
+ privateBalanceWei: "0",
1049
+ utxoCount: 0,
1050
+ spentCount: 0,
1051
+ unspentCount: 0,
1052
+ utxos: []
1053
+ };
1054
+ }
1055
+ const BATCH_SIZE = 5e3;
1056
+ const allEncryptedOutputs = [];
1057
+ const totalBatches = Math.ceil(nextIndex / BATCH_SIZE);
1058
+ for (let start = 0; start < nextIndex; start += BATCH_SIZE) {
1059
+ const end = Math.min(start + BATCH_SIZE, nextIndex);
1060
+ const batchNum = Math.floor(start / BATCH_SIZE) + 1;
1061
+ onProgress?.("Fetching encrypted outputs", `batch ${batchNum}/${totalBatches} (${start}-${end})`);
1062
+ const batch = await publicClient.readContract({
1063
+ address: addresses.ethPool,
1064
+ abi: POOL_ABI,
1065
+ functionName: "getEncryptedOutputs",
1066
+ args: [BigInt(start), BigInt(end)]
1067
+ });
1068
+ allEncryptedOutputs.push(...batch);
1069
+ }
1070
+ onProgress?.("Decrypting outputs", `scanning ${allEncryptedOutputs.length} outputs...`);
1071
+ const decryptedUtxos = [];
1072
+ for (let i = 0; i < allEncryptedOutputs.length; i++) {
1073
+ try {
1074
+ const utxo = Utxo.decrypt(allEncryptedOutputs[i], keypair);
1075
+ utxo.index = i;
1076
+ if (utxo.amount > 0n) {
1077
+ decryptedUtxos.push({ utxo, index: i });
1078
+ }
1079
+ } catch {
1080
+ }
1081
+ }
1082
+ onProgress?.("Found UTXOs", `${decryptedUtxos.length} belonging to you`);
1083
+ const utxoInfos = [];
1084
+ let totalBalance = 0n;
1085
+ let spentCount = 0;
1086
+ let unspentCount = 0;
1087
+ for (let i = 0; i < decryptedUtxos.length; i++) {
1088
+ const { utxo, index } = decryptedUtxos[i];
1089
+ onProgress?.("Checking spent status", `UTXO ${i + 1}/${decryptedUtxos.length}`);
1090
+ const nullifier = utxo.getNullifier();
1091
+ const nullifierHex = toFixedHex(nullifier);
1092
+ const isSpent = await publicClient.readContract({
1093
+ address: addresses.ethPool,
1094
+ abi: POOL_ABI,
1095
+ functionName: "isSpent",
1096
+ args: [nullifierHex]
1097
+ });
1098
+ utxoInfos.push({
1099
+ index,
1100
+ amount: formatEther(utxo.amount),
1101
+ amountWei: utxo.amount.toString(),
1102
+ isSpent
1103
+ });
1104
+ if (isSpent) {
1105
+ spentCount++;
1106
+ } else {
1107
+ unspentCount++;
1108
+ totalBalance += utxo.amount;
1109
+ }
1110
+ }
1111
+ return {
1112
+ privateBalance: formatEther(totalBalance),
1113
+ privateBalanceWei: totalBalance.toString(),
1114
+ utxoCount: decryptedUtxos.length,
1115
+ spentCount,
1116
+ unspentCount,
1117
+ utxos: utxoInfos
1118
+ };
1119
+ }
1120
+ var MERKLE_TREE_HEIGHT = 23;
1121
+ async function buildMerkleTree(commitments) {
1122
+ const leaves = commitments.map((commitment) => toFixedHex(commitment));
1123
+ const hashFunction = (left, right) => {
1124
+ const result = poseidonHash2(left, right);
1125
+ return result.toString();
1126
+ };
1127
+ const tree = new MerkleTree(MERKLE_TREE_HEIGHT, leaves, { hashFunction });
1128
+ return tree;
1129
+ }
1130
+ function getMerklePath(tree, commitment) {
1131
+ const commitmentHex = toFixedHex(commitment);
1132
+ const index = tree.indexOf(commitmentHex);
1133
+ if (index < 0) {
1134
+ throw new Error(`Commitment ${commitmentHex} not found in merkle tree`);
1135
+ }
1136
+ const { pathElements } = tree.path(index);
1137
+ return {
1138
+ pathElements: pathElements.map((el) => BigInt(el)),
1139
+ pathIndices: index
1140
+ };
1141
+ }
1142
+ var utils = null;
1143
+ try {
1144
+ const ffjavascript = __require("ffjavascript");
1145
+ utils = ffjavascript.utils;
1146
+ } catch {
1147
+ console.warn("ffjavascript not found. Proof generation may not work.");
1148
+ }
1149
+ function findKeysDirectory() {
1150
+ const possiblePaths = [
1151
+ // When running from package (installed via npm)
1152
+ path.resolve(__dirname, "..", "keys"),
1153
+ path.resolve(__dirname, "..", "..", "keys"),
1154
+ // When running from source
1155
+ path.resolve(process.cwd(), "keys")
1156
+ // ESM module path
1157
+ ];
1158
+ try {
1159
+ const currentFilePath = fileURLToPath(import.meta.url);
1160
+ const currentDir = path.dirname(currentFilePath);
1161
+ possiblePaths.unshift(path.resolve(currentDir, "..", "keys"));
1162
+ } catch {
1163
+ }
1164
+ for (const p of possiblePaths) {
1165
+ if (fs.existsSync(p) && fs.existsSync(path.join(p, "transaction2.wasm"))) {
1166
+ return p;
1167
+ }
1168
+ }
1169
+ throw new Error(
1170
+ "Circuit keys not found. Expected to find keys/ directory with transaction2.wasm and transaction2.zkey files."
1171
+ );
1172
+ }
1173
+ async function prove(input, circuitName) {
1174
+ if (!utils) {
1175
+ throw new Error("ffjavascript is required for proof generation. Please install it: npm install ffjavascript");
1176
+ }
1177
+ const keysDir = findKeysDirectory();
1178
+ const wasmPath = path.join(keysDir, `${circuitName}.wasm`);
1179
+ const zkeyPath = path.join(keysDir, `${circuitName}.zkey`);
1180
+ if (!fs.existsSync(wasmPath)) {
1181
+ throw new Error(`Circuit WASM file not found: ${wasmPath}`);
1182
+ }
1183
+ if (!fs.existsSync(zkeyPath)) {
1184
+ throw new Error(`Circuit zkey file not found: ${zkeyPath}`);
1185
+ }
1186
+ const result = await groth16.fullProve(
1187
+ utils.stringifyBigInts(input),
1188
+ wasmPath,
1189
+ zkeyPath
1190
+ );
1191
+ const proof = result.proof;
1192
+ return "0x" + toFixedHex(proof.pi_a[0]).slice(2) + toFixedHex(proof.pi_a[1]).slice(2) + toFixedHex(proof.pi_b[0][1]).slice(2) + toFixedHex(proof.pi_b[0][0]).slice(2) + toFixedHex(proof.pi_b[1][1]).slice(2) + toFixedHex(proof.pi_b[1][0]).slice(2) + toFixedHex(proof.pi_c[0]).slice(2) + toFixedHex(proof.pi_c[1]).slice(2);
1193
+ }
1194
+ var CIRCUIT_CONFIG = {
1195
+ transaction2: { maxInputs: 2, maxOutputs: 2 },
1196
+ transaction16: { maxInputs: 16, maxOutputs: 2 }
1197
+ };
1198
+ function selectCircuit(inputCount) {
1199
+ if (inputCount <= 2) {
1200
+ return "transaction2";
1201
+ } else if (inputCount <= 16) {
1202
+ return "transaction16";
1203
+ } else {
1204
+ throw new Error(`Too many inputs: ${inputCount}. Maximum supported is 16.`);
1205
+ }
1206
+ }
1207
+
1208
+ // src/transaction.ts
1209
+ async function getProof({
1210
+ inputs,
1211
+ outputs,
1212
+ tree,
1213
+ extAmount,
1214
+ fee,
1215
+ recipient,
1216
+ relayer,
1217
+ onProgress
1218
+ }) {
1219
+ inputs = shuffle([...inputs]);
1220
+ outputs = shuffle([...outputs]);
1221
+ onProgress?.("Building merkle paths...");
1222
+ const inputMerklePathIndices = [];
1223
+ const inputMerklePathElements = [];
1224
+ for (const input of inputs) {
1225
+ if (input.amount > 0n) {
1226
+ const inputIndex = tree.indexOf(toFixedHex(input.getCommitment()));
1227
+ if (inputIndex < 0) {
1228
+ throw new Error(`Input commitment ${toFixedHex(input.getCommitment())} was not found in merkle tree`);
1229
+ }
1230
+ input.index = inputIndex;
1231
+ inputMerklePathIndices.push(inputIndex);
1232
+ inputMerklePathElements.push(
1233
+ tree.path(inputIndex).pathElements.map((el) => BigInt(el))
1234
+ );
1235
+ } else {
1236
+ inputMerklePathIndices.push(0);
1237
+ inputMerklePathElements.push(new Array(tree.levels).fill(0));
1238
+ }
1239
+ }
1240
+ onProgress?.("Encrypting outputs...");
1241
+ const extData = {
1242
+ recipient: toFixedHex(recipient, 20),
1243
+ extAmount: extAmount.toString(),
1244
+ relayer: toFixedHex(relayer, 20),
1245
+ fee: fee.toString(),
1246
+ encryptedOutput1: outputs[0].encrypt(),
1247
+ encryptedOutput2: outputs[1].encrypt()
1248
+ };
1249
+ const extDataHashInput = {
1250
+ recipient,
1251
+ extAmount,
1252
+ relayer,
1253
+ fee,
1254
+ encryptedOutput1: extData.encryptedOutput1,
1255
+ encryptedOutput2: extData.encryptedOutput2
1256
+ };
1257
+ const extDataHash = getExtDataHash(extDataHashInput);
1258
+ const proofInput = {
1259
+ root: BigInt(tree.root()),
1260
+ inputNullifier: inputs.map((x) => x.getNullifier()),
1261
+ outputCommitment: outputs.map((x) => x.getCommitment()),
1262
+ publicAmount: ((BigInt(extAmount) - BigInt(fee) + FIELD_SIZE) % FIELD_SIZE).toString(),
1263
+ extDataHash,
1264
+ // Input UTXO data
1265
+ inAmount: inputs.map((x) => x.amount),
1266
+ inPrivateKey: inputs.map((x) => x.keypair.privkey),
1267
+ inBlinding: inputs.map((x) => x.blinding),
1268
+ inPathIndices: inputMerklePathIndices,
1269
+ inPathElements: inputMerklePathElements,
1270
+ // Output UTXO data
1271
+ outAmount: outputs.map((x) => x.amount),
1272
+ outBlinding: outputs.map((x) => x.blinding),
1273
+ outPubkey: outputs.map((x) => x.keypair.pubkey)
1274
+ };
1275
+ onProgress?.("Generating ZK proof...", `${inputs.length} inputs`);
1276
+ const circuitName = selectCircuit(inputs.length);
1277
+ const proof = await prove(proofInput, circuitName);
1278
+ const args = {
1279
+ proof,
1280
+ root: toFixedHex(proofInput.root),
1281
+ inputNullifiers: inputs.map((x) => toFixedHex(x.getNullifier())),
1282
+ outputCommitments: outputs.map((x) => toFixedHex(x.getCommitment())),
1283
+ publicAmount: toFixedHex(proofInput.publicAmount),
1284
+ extDataHash: toFixedHex(extDataHash)
1285
+ };
1286
+ onProgress?.("Proof generated successfully");
1287
+ return {
1288
+ args,
1289
+ extData
1290
+ };
1291
+ }
1292
+ async function prepareTransaction({
1293
+ commitments,
1294
+ inputs = [],
1295
+ outputs = [],
1296
+ fee = 0,
1297
+ recipient = 0,
1298
+ relayer = 0,
1299
+ onProgress
1300
+ }) {
1301
+ if (inputs.length > 16 || outputs.length > 2) {
1302
+ throw new Error("Incorrect inputs/outputs count. Maximum: 16 inputs, 2 outputs.");
1303
+ }
1304
+ while (inputs.length !== 2 && inputs.length < 16) {
1305
+ inputs.push(new Utxo());
1306
+ }
1307
+ while (outputs.length < 2) {
1308
+ outputs.push(new Utxo());
1309
+ }
1310
+ const extAmount = BigInt(fee) + outputs.reduce((sum, x) => sum + x.amount, 0n) - inputs.reduce((sum, x) => sum + x.amount, 0n);
1311
+ onProgress?.("Building merkle tree...");
1312
+ const tree = await buildMerkleTree(commitments);
1313
+ const result = await getProof({
1314
+ inputs,
1315
+ outputs,
1316
+ tree,
1317
+ extAmount,
1318
+ fee: BigInt(fee),
1319
+ recipient: String(recipient),
1320
+ relayer: String(relayer),
1321
+ onProgress
1322
+ });
1323
+ return result;
1324
+ }
1325
+
1326
+ // src/relay.ts
1327
+ var RelayError = class extends Error {
1328
+ /** HTTP status code */
1329
+ statusCode;
1330
+ /** Seconds until rate limit resets (only for 429 errors) */
1331
+ retryAfter;
1332
+ /** Network the error occurred on */
1333
+ network;
1334
+ constructor(message, statusCode, retryAfter, network) {
1335
+ super(message);
1336
+ this.name = "RelayError";
1337
+ this.statusCode = statusCode;
1338
+ this.retryAfter = retryAfter;
1339
+ this.network = network;
1340
+ }
1341
+ };
1342
+ async function submitRelay(options) {
1343
+ const {
1344
+ type,
1345
+ pool = "eth",
1346
+ proofArgs,
1347
+ extData,
1348
+ metadata,
1349
+ relayUrl: customRelayUrl
1350
+ } = options;
1351
+ if (type !== "withdraw" && type !== "transfer") {
1352
+ throw new RelayError('Invalid type. Must be "withdraw" or "transfer"', 400);
1353
+ }
1354
+ if (pool !== "eth" && pool !== "usdc") {
1355
+ throw new RelayError('Invalid pool. Must be "eth" or "usdc"', 400);
1356
+ }
1357
+ if (!proofArgs || !extData) {
1358
+ throw new RelayError("Missing proofArgs or extData", 400);
1359
+ }
1360
+ const relayUrl = customRelayUrl || getRelayUrl();
1361
+ const endpoint = `${relayUrl}/relay/${pool}`;
1362
+ const response = await fetch(endpoint, {
1363
+ method: "POST",
1364
+ headers: {
1365
+ "Content-Type": "application/json"
1366
+ },
1367
+ body: JSON.stringify({
1368
+ type,
1369
+ proofArgs,
1370
+ extData,
1371
+ metadata
1372
+ })
1373
+ });
1374
+ const data = await response.json();
1375
+ if (!response.ok) {
1376
+ const errorData = data;
1377
+ throw new RelayError(
1378
+ errorData.error || errorData.message || "Relay request failed",
1379
+ response.status,
1380
+ errorData.retryAfter,
1381
+ errorData.network
1382
+ );
1383
+ }
1384
+ return data;
1385
+ }
1386
+ async function checkRelayHealth(relayUrl) {
1387
+ const url = relayUrl || getRelayUrl();
1388
+ const response = await fetch(`${url}/health`);
1389
+ if (!response.ok) {
1390
+ throw new RelayError("Relay service health check failed", response.status);
1391
+ }
1392
+ return response.json();
1393
+ }
1394
+ async function getRelayInfo(relayUrl) {
1395
+ const url = relayUrl || getRelayUrl();
1396
+ const response = await fetch(url);
1397
+ if (!response.ok) {
1398
+ throw new RelayError("Failed to get relay service info", response.status);
1399
+ }
1400
+ return response.json();
1401
+ }
1402
+
1403
+ // src/withdraw.ts
1404
+ function selectUtxosForWithdraw(utxos, amount, decimals = 18) {
1405
+ const withdrawWei = parseUnits(amount, decimals);
1406
+ const sortedUtxos = [...utxos].sort((a, b) => Number(b.amount - a.amount));
1407
+ let totalSelected = 0n;
1408
+ const selectedUtxos = [];
1409
+ for (const utxo of sortedUtxos) {
1410
+ selectedUtxos.push(utxo);
1411
+ totalSelected += utxo.amount;
1412
+ if (totalSelected >= withdrawWei) {
1413
+ break;
1414
+ }
1415
+ }
1416
+ if (totalSelected < withdrawWei) {
1417
+ throw new Error(
1418
+ `Insufficient balance. Need ${amount}, have ${formatUnits(totalSelected, decimals)}`
1419
+ );
1420
+ }
1421
+ const changeAmount = totalSelected - withdrawWei;
1422
+ return { selectedUtxos, totalSelected, changeAmount };
1423
+ }
1424
+ async function fetchCommitments(rpcUrl, poolAddress, onProgress) {
1425
+ const publicClient = createPublicClient({
1426
+ chain: base,
1427
+ transport: http(rpcUrl)
1428
+ });
1429
+ onProgress?.("Fetching commitment count...");
1430
+ const nextIndex = await publicClient.readContract({
1431
+ address: poolAddress,
1432
+ abi: POOL_ABI,
1433
+ functionName: "nextIndex"
1434
+ });
1435
+ if (nextIndex === 0) {
1436
+ return [];
1437
+ }
1438
+ const BATCH_SIZE = 5e3;
1439
+ const commitments = [];
1440
+ const totalBatches = Math.ceil(nextIndex / BATCH_SIZE);
1441
+ for (let start = 0; start < nextIndex; start += BATCH_SIZE) {
1442
+ const end = Math.min(start + BATCH_SIZE, nextIndex);
1443
+ const batchNum = Math.floor(start / BATCH_SIZE) + 1;
1444
+ onProgress?.("Fetching commitments", `batch ${batchNum}/${totalBatches}`);
1445
+ const batch = await publicClient.readContract({
1446
+ address: poolAddress,
1447
+ abi: POOL_ABI,
1448
+ functionName: "getCommitments",
1449
+ args: [BigInt(start), BigInt(end)]
1450
+ });
1451
+ commitments.push(...batch.map((c) => c.toString()));
1452
+ }
1453
+ return commitments;
1454
+ }
1455
+ async function buildWithdrawProof(options) {
1456
+ const {
1457
+ amount,
1458
+ recipient,
1459
+ keypair,
1460
+ rpcUrl,
1461
+ onProgress
1462
+ } = options;
1463
+ const addresses = getAddresses();
1464
+ const poolConfig = POOL_CONFIG.eth;
1465
+ const poolAddress = addresses.ethPool;
1466
+ onProgress?.("Fetching your UTXOs...");
1467
+ const balanceResult = await getPrivateBalance({
1468
+ keypair,
1469
+ rpcUrl,
1470
+ onProgress
1471
+ });
1472
+ const unspentUtxoInfos = balanceResult.utxos.filter((u) => !u.isSpent);
1473
+ if (unspentUtxoInfos.length === 0) {
1474
+ throw new Error("No unspent UTXOs available for withdrawal");
1475
+ }
1476
+ onProgress?.("Preparing UTXOs...");
1477
+ const publicClient = createPublicClient({
1478
+ chain: base,
1479
+ transport: http(rpcUrl)
1480
+ });
1481
+ const utxos = [];
1482
+ for (const utxoInfo of unspentUtxoInfos) {
1483
+ const encryptedOutputs = await publicClient.readContract({
1484
+ address: poolAddress,
1485
+ abi: POOL_ABI,
1486
+ functionName: "getEncryptedOutputs",
1487
+ args: [BigInt(utxoInfo.index), BigInt(utxoInfo.index + 1)]
1488
+ });
1489
+ if (encryptedOutputs.length > 0) {
1490
+ try {
1491
+ const utxo = Utxo.decrypt(encryptedOutputs[0], keypair);
1492
+ utxo.index = utxoInfo.index;
1493
+ utxos.push(utxo);
1494
+ } catch {
1495
+ }
1496
+ }
1497
+ }
1498
+ if (utxos.length === 0) {
1499
+ throw new Error("Failed to decrypt UTXOs");
1500
+ }
1501
+ onProgress?.("Selecting UTXOs...");
1502
+ const { selectedUtxos, changeAmount } = selectUtxosForWithdraw(
1503
+ utxos,
1504
+ amount,
1505
+ poolConfig.decimals
1506
+ );
1507
+ const outputs = [];
1508
+ if (changeAmount > 0n) {
1509
+ const changeUtxo = new Utxo({
1510
+ amount: changeAmount,
1511
+ keypair
1512
+ });
1513
+ outputs.push(changeUtxo);
1514
+ }
1515
+ const commitments = await fetchCommitments(rpcUrl, poolAddress, onProgress);
1516
+ onProgress?.("Building ZK proof...");
1517
+ const result = await prepareTransaction({
1518
+ commitments,
1519
+ inputs: selectedUtxos,
1520
+ outputs,
1521
+ fee: 0,
1522
+ recipient,
1523
+ relayer: "0x0000000000000000000000000000000000000000",
1524
+ onProgress
1525
+ });
1526
+ return {
1527
+ proofArgs: {
1528
+ proof: result.args.proof,
1529
+ root: result.args.root,
1530
+ inputNullifiers: result.args.inputNullifiers,
1531
+ outputCommitments: result.args.outputCommitments,
1532
+ publicAmount: result.args.publicAmount,
1533
+ extDataHash: result.args.extDataHash
1534
+ },
1535
+ extData: result.extData,
1536
+ inputCount: selectedUtxos.length,
1537
+ outputCount: outputs.length,
1538
+ amount
1539
+ };
1540
+ }
1541
+ async function withdraw(options) {
1542
+ const { amount, recipient, onProgress } = options;
1543
+ const proof = await buildWithdrawProof(options);
1544
+ onProgress?.("Submitting to relay...");
1545
+ const relayResult = await submitRelay({
1546
+ type: "withdraw",
1547
+ pool: "eth",
1548
+ proofArgs: proof.proofArgs,
1549
+ extData: proof.extData,
1550
+ metadata: {
1551
+ amount,
1552
+ recipient,
1553
+ inputUtxoCount: proof.inputCount,
1554
+ outputUtxoCount: proof.outputCount
1555
+ }
1556
+ });
1557
+ return {
1558
+ success: relayResult.success,
1559
+ transactionHash: relayResult.transactionHash,
1560
+ blockNumber: relayResult.blockNumber,
1561
+ amount,
1562
+ recipient
1563
+ };
1564
+ }
1565
+ async function checkRecipientRegistration(address, rpcUrl) {
1566
+ const addresses = getAddresses();
1567
+ const publicClient = createPublicClient({
1568
+ chain: base,
1569
+ transport: http(rpcUrl)
1570
+ });
1571
+ const depositKey = await publicClient.readContract({
1572
+ address: addresses.entry,
1573
+ abi: ENTRY_ABI,
1574
+ functionName: "depositKeys",
1575
+ args: [address]
1576
+ });
1577
+ const isRegistered = !!(depositKey && depositKey !== "0x" && depositKey.length > 2);
1578
+ return {
1579
+ isRegistered,
1580
+ depositKey: isRegistered ? depositKey : void 0
1581
+ };
1582
+ }
1583
+ async function fetchCommitments2(rpcUrl, poolAddress, onProgress) {
1584
+ const publicClient = createPublicClient({
1585
+ chain: base,
1586
+ transport: http(rpcUrl)
1587
+ });
1588
+ onProgress?.("Fetching commitment count...");
1589
+ const nextIndex = await publicClient.readContract({
1590
+ address: poolAddress,
1591
+ abi: POOL_ABI,
1592
+ functionName: "nextIndex"
1593
+ });
1594
+ if (nextIndex === 0) {
1595
+ return [];
1596
+ }
1597
+ const BATCH_SIZE = 5e3;
1598
+ const commitments = [];
1599
+ const totalBatches = Math.ceil(nextIndex / BATCH_SIZE);
1600
+ for (let start = 0; start < nextIndex; start += BATCH_SIZE) {
1601
+ const end = Math.min(start + BATCH_SIZE, nextIndex);
1602
+ const batchNum = Math.floor(start / BATCH_SIZE) + 1;
1603
+ onProgress?.("Fetching commitments", `batch ${batchNum}/${totalBatches}`);
1604
+ const batch = await publicClient.readContract({
1605
+ address: poolAddress,
1606
+ abi: POOL_ABI,
1607
+ functionName: "getCommitments",
1608
+ args: [BigInt(start), BigInt(end)]
1609
+ });
1610
+ commitments.push(...batch.map((c) => c.toString()));
1611
+ }
1612
+ return commitments;
1613
+ }
1614
+ async function buildTransferProof(options) {
1615
+ const {
1616
+ amount,
1617
+ recipientAddress,
1618
+ senderKeypair,
1619
+ rpcUrl,
1620
+ onProgress
1621
+ } = options;
1622
+ const addresses = getAddresses();
1623
+ const poolConfig = POOL_CONFIG.eth;
1624
+ const poolAddress = addresses.ethPool;
1625
+ onProgress?.("Checking recipient registration...");
1626
+ const { isRegistered, depositKey } = await checkRecipientRegistration(
1627
+ recipientAddress,
1628
+ rpcUrl
1629
+ );
1630
+ if (!isRegistered || !depositKey) {
1631
+ throw new Error(`Recipient ${recipientAddress} is not registered. They need to register first.`);
1632
+ }
1633
+ onProgress?.("Fetching your UTXOs...");
1634
+ const balanceResult = await getPrivateBalance({
1635
+ keypair: senderKeypair,
1636
+ rpcUrl,
1637
+ onProgress
1638
+ });
1639
+ const unspentUtxoInfos = balanceResult.utxos.filter((u) => !u.isSpent);
1640
+ if (unspentUtxoInfos.length === 0) {
1641
+ throw new Error("No unspent UTXOs available for transfer");
1642
+ }
1643
+ onProgress?.("Preparing UTXOs...");
1644
+ const publicClient = createPublicClient({
1645
+ chain: base,
1646
+ transport: http(rpcUrl)
1647
+ });
1648
+ const utxos = [];
1649
+ for (const utxoInfo of unspentUtxoInfos) {
1650
+ const encryptedOutputs = await publicClient.readContract({
1651
+ address: poolAddress,
1652
+ abi: POOL_ABI,
1653
+ functionName: "getEncryptedOutputs",
1654
+ args: [BigInt(utxoInfo.index), BigInt(utxoInfo.index + 1)]
1655
+ });
1656
+ if (encryptedOutputs.length > 0) {
1657
+ try {
1658
+ const utxo = Utxo.decrypt(encryptedOutputs[0], senderKeypair);
1659
+ utxo.index = utxoInfo.index;
1660
+ utxos.push(utxo);
1661
+ } catch {
1662
+ }
1663
+ }
1664
+ }
1665
+ if (utxos.length === 0) {
1666
+ throw new Error("Failed to decrypt UTXOs");
1667
+ }
1668
+ onProgress?.("Selecting UTXOs...");
1669
+ const { selectedUtxos, changeAmount } = selectUtxosForWithdraw(
1670
+ utxos,
1671
+ amount,
1672
+ poolConfig.decimals
1673
+ );
1674
+ const outputs = [];
1675
+ const transferWei = parseUnits(amount, poolConfig.decimals);
1676
+ const recipientKeypair = Keypair.fromString(depositKey);
1677
+ const recipientUtxo = new Utxo({
1678
+ amount: transferWei,
1679
+ keypair: recipientKeypair
1680
+ });
1681
+ outputs.push(recipientUtxo);
1682
+ if (changeAmount > 0n) {
1683
+ const changeUtxo = new Utxo({
1684
+ amount: changeAmount,
1685
+ keypair: senderKeypair
1686
+ });
1687
+ outputs.push(changeUtxo);
1688
+ }
1689
+ const commitments = await fetchCommitments2(rpcUrl, poolAddress, onProgress);
1690
+ onProgress?.("Building ZK proof...");
1691
+ const result = await prepareTransaction({
1692
+ commitments,
1693
+ inputs: selectedUtxos,
1694
+ outputs,
1695
+ fee: 0,
1696
+ recipient: "0x0000000000000000000000000000000000000000",
1697
+ relayer: "0x0000000000000000000000000000000000000000",
1698
+ onProgress
1699
+ });
1700
+ return {
1701
+ proofArgs: {
1702
+ proof: result.args.proof,
1703
+ root: result.args.root,
1704
+ inputNullifiers: result.args.inputNullifiers,
1705
+ outputCommitments: result.args.outputCommitments,
1706
+ publicAmount: result.args.publicAmount,
1707
+ extDataHash: result.args.extDataHash
1708
+ },
1709
+ extData: result.extData,
1710
+ inputCount: selectedUtxos.length,
1711
+ outputCount: outputs.length,
1712
+ amount
1713
+ };
1714
+ }
1715
+ async function transfer(options) {
1716
+ const { amount, recipientAddress, onProgress } = options;
1717
+ const proof = await buildTransferProof(options);
1718
+ onProgress?.("Submitting to relay...");
1719
+ const relayResult = await submitRelay({
1720
+ type: "transfer",
1721
+ pool: "eth",
1722
+ proofArgs: proof.proofArgs,
1723
+ extData: proof.extData,
1724
+ metadata: {
1725
+ amount,
1726
+ recipient: recipientAddress,
1727
+ inputUtxoCount: proof.inputCount,
1728
+ outputUtxoCount: proof.outputCount
1729
+ }
1730
+ });
1731
+ return {
1732
+ success: relayResult.success,
1733
+ transactionHash: relayResult.transactionHash,
1734
+ blockNumber: relayResult.blockNumber,
1735
+ amount,
1736
+ recipient: recipientAddress
1737
+ };
1738
+ }
1739
+ async function mergeUtxos(options) {
1740
+ const { amount, keypair, rpcUrl, onProgress } = options;
1741
+ const addresses = getAddresses();
1742
+ const poolConfig = POOL_CONFIG.eth;
1743
+ const poolAddress = addresses.ethPool;
1744
+ onProgress?.("Fetching your UTXOs...");
1745
+ const balanceResult = await getPrivateBalance({
1746
+ keypair,
1747
+ rpcUrl,
1748
+ onProgress
1749
+ });
1750
+ const unspentUtxoInfos = balanceResult.utxos.filter((u) => !u.isSpent);
1751
+ if (unspentUtxoInfos.length === 0) {
1752
+ throw new Error("No unspent UTXOs available for merge");
1753
+ }
1754
+ onProgress?.("Preparing UTXOs...");
1755
+ const publicClient = createPublicClient({
1756
+ chain: base,
1757
+ transport: http(rpcUrl)
1758
+ });
1759
+ const utxos = [];
1760
+ for (const utxoInfo of unspentUtxoInfos) {
1761
+ const encryptedOutputs = await publicClient.readContract({
1762
+ address: poolAddress,
1763
+ abi: POOL_ABI,
1764
+ functionName: "getEncryptedOutputs",
1765
+ args: [BigInt(utxoInfo.index), BigInt(utxoInfo.index + 1)]
1766
+ });
1767
+ if (encryptedOutputs.length > 0) {
1768
+ try {
1769
+ const utxo = Utxo.decrypt(encryptedOutputs[0], keypair);
1770
+ utxo.index = utxoInfo.index;
1771
+ utxos.push(utxo);
1772
+ } catch {
1773
+ }
1774
+ }
1775
+ }
1776
+ if (utxos.length === 0) {
1777
+ throw new Error("Failed to decrypt UTXOs");
1778
+ }
1779
+ onProgress?.("Selecting UTXOs...");
1780
+ const { selectedUtxos, changeAmount } = selectUtxosForWithdraw(
1781
+ utxos,
1782
+ amount,
1783
+ poolConfig.decimals
1784
+ );
1785
+ const outputs = [];
1786
+ const mergeWei = parseUnits(amount, poolConfig.decimals);
1787
+ const mergedUtxo = new Utxo({
1788
+ amount: mergeWei,
1789
+ keypair
1790
+ });
1791
+ outputs.push(mergedUtxo);
1792
+ if (changeAmount > 0n) {
1793
+ const changeUtxo = new Utxo({
1794
+ amount: changeAmount,
1795
+ keypair
1796
+ });
1797
+ outputs.push(changeUtxo);
1798
+ }
1799
+ const commitments = await fetchCommitments2(rpcUrl, poolAddress, onProgress);
1800
+ onProgress?.("Building ZK proof...");
1801
+ const result = await prepareTransaction({
1802
+ commitments,
1803
+ inputs: selectedUtxos,
1804
+ outputs,
1805
+ fee: 0,
1806
+ recipient: "0x0000000000000000000000000000000000000000",
1807
+ relayer: "0x0000000000000000000000000000000000000000",
1808
+ onProgress
1809
+ });
1810
+ onProgress?.("Submitting to relay...");
1811
+ const relayResult = await submitRelay({
1812
+ type: "transfer",
1813
+ pool: "eth",
1814
+ proofArgs: {
1815
+ proof: result.args.proof,
1816
+ root: result.args.root,
1817
+ inputNullifiers: result.args.inputNullifiers,
1818
+ outputCommitments: result.args.outputCommitments,
1819
+ publicAmount: result.args.publicAmount,
1820
+ extDataHash: result.args.extDataHash
1821
+ },
1822
+ extData: result.extData,
1823
+ metadata: {
1824
+ amount,
1825
+ inputUtxoCount: selectedUtxos.length,
1826
+ outputUtxoCount: outputs.length
1827
+ }
1828
+ });
1829
+ return {
1830
+ success: relayResult.success,
1831
+ transactionHash: relayResult.transactionHash,
1832
+ blockNumber: relayResult.blockNumber,
1833
+ amount,
1834
+ recipient: "self"
1835
+ };
1836
+ }
1837
+
1838
+ export { ADDRESSES, CIRCUIT_CONFIG, ENTRY_ABI, ERC20_ABI, FIELD_SIZE, Keypair, MERKLE_TREE_HEIGHT, POOL_ABI, POOL_CONFIG, QUEUE_ABI, RelayError, Utxo, buildApproveUSDCTx, buildDepositETHTx, buildDepositTx, buildDepositUSDCTx, buildMerkleTree, buildRegisterTx, buildTransferProof, buildWithdrawProof, checkRecipientRegistration, checkRelayHealth, getAddresses, getExtDataHash, getMerklePath, getPrivateBalance, getQueueBalance, getRelayInfo, getRelayUrl, mergeUtxos, packEncryptedMessage, poseidonHash, poseidonHash2, prepareTransaction, prove, randomBN, selectCircuit, selectUtxosForWithdraw, shuffle, submitRelay, toBuffer, toFixedHex, transfer, unpackEncryptedMessage, withdraw };
1839
+ //# sourceMappingURL=index.js.map
1840
+ //# sourceMappingURL=index.js.map