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