@0xbow/privacy-pools-core-sdk 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +73 -0
  2. package/dist/esm/ccip-nJye9Itm.js +166 -0
  3. package/dist/esm/ccip-nJye9Itm.js.map +1 -0
  4. package/dist/esm/index-DAWUECi8.js +84043 -0
  5. package/dist/esm/index-DAWUECi8.js.map +1 -0
  6. package/dist/esm/index.mjs +4 -0
  7. package/dist/esm/index.mjs.map +1 -0
  8. package/dist/index.d.mts +666 -0
  9. package/dist/node/artifacts/commitment.vkey +114 -0
  10. package/dist/node/artifacts/commitment.wasm +0 -0
  11. package/dist/node/artifacts/commitment.zkey +0 -0
  12. package/dist/node/artifacts/merkleTree.vkey +269 -0
  13. package/dist/node/artifacts/merkleTree.wasm +0 -0
  14. package/dist/node/artifacts/merkleTree.zkey +0 -0
  15. package/dist/node/artifacts/withdraw.vkey +129 -0
  16. package/dist/node/artifacts/withdraw.wasm +0 -0
  17. package/dist/node/artifacts/withdraw.zkey +0 -0
  18. package/dist/node/ccip-lPhPeJab.js +183 -0
  19. package/dist/node/ccip-lPhPeJab.js.map +1 -0
  20. package/dist/node/index-BiU5Ef8Z.js +90625 -0
  21. package/dist/node/index-BiU5Ef8Z.js.map +1 -0
  22. package/dist/node/index.mjs +21 -0
  23. package/dist/node/index.mjs.map +1 -0
  24. package/dist/types/abi/ERC20.d.ts +38 -0
  25. package/dist/types/abi/IEntrypoint.d.ts +794 -0
  26. package/dist/types/abi/IPrivacyPool.d.ts +51 -0
  27. package/dist/types/ccip-BZzz1Y5w.js +182 -0
  28. package/dist/types/circuits/circuits.impl.d.ts +108 -0
  29. package/dist/types/circuits/circuits.interface.d.ts +127 -0
  30. package/dist/types/circuits/index.d.ts +2 -0
  31. package/dist/types/constants.d.ts +2 -0
  32. package/dist/types/core/bruteForce.service.d.ts +61 -0
  33. package/dist/types/core/commitment.service.d.ts +30 -0
  34. package/dist/types/core/contracts.service.d.ts +106 -0
  35. package/dist/types/core/sdk.d.ts +44 -0
  36. package/dist/types/core/withdrawal.service.d.ts +32 -0
  37. package/dist/types/crypto.d.ts +45 -0
  38. package/dist/types/dirname.helper.d.ts +2 -0
  39. package/dist/types/errors/base.error.d.ts +52 -0
  40. package/dist/types/exceptions/circuitInitialization.exception.d.ts +3 -0
  41. package/dist/types/exceptions/fetchArtifacts.exception.d.ts +3 -0
  42. package/dist/types/exceptions/index.d.ts +4 -0
  43. package/dist/types/exceptions/invalidRpcUrl.exception.d.ts +3 -0
  44. package/dist/types/exceptions/privacyPool.exception.d.ts +13 -0
  45. package/dist/types/external.d.ts +7 -0
  46. package/dist/types/filename.helper.d.ts +2 -0
  47. package/dist/types/index-D-_1h8-n.js +90638 -0
  48. package/dist/types/index.d.ts +10 -0
  49. package/dist/types/index.js +20 -0
  50. package/dist/types/interfaces/blockchainProvider.interface.d.ts +12 -0
  51. package/dist/types/interfaces/circuits.interface.d.ts +30 -0
  52. package/dist/types/interfaces/contracts.interface.d.ts +28 -0
  53. package/dist/types/interfaces/index.d.ts +1 -0
  54. package/dist/types/internal.d.ts +6 -0
  55. package/dist/types/providers/blockchainProvider.d.ts +8 -0
  56. package/dist/types/providers/index.d.ts +1 -0
  57. package/dist/types/types/commitment.d.ts +48 -0
  58. package/dist/types/types/index.d.ts +2 -0
  59. package/dist/types/types/withdrawal.d.ts +30 -0
  60. package/package.json +81 -0
  61. package/src/abi/ERC20.ts +222 -0
  62. package/src/abi/IEntrypoint.ts +627 -0
  63. package/src/abi/IPrivacyPool.ts +386 -0
  64. package/src/circuits/circuits.impl.ts +213 -0
  65. package/src/circuits/circuits.interface.ts +162 -0
  66. package/src/circuits/index.ts +2 -0
  67. package/src/constants.ts +3 -0
  68. package/src/core/bruteForce.service.ts +120 -0
  69. package/src/core/commitment.service.ts +84 -0
  70. package/src/core/contracts.service.ts +407 -0
  71. package/src/core/sdk.ts +91 -0
  72. package/src/core/withdrawal.service.ts +110 -0
  73. package/src/crypto.ts +156 -0
  74. package/src/dirname.helper.ts +4 -0
  75. package/src/errors/base.error.ts +120 -0
  76. package/src/exceptions/circuitInitialization.exception.ts +6 -0
  77. package/src/exceptions/fetchArtifacts.exception.ts +7 -0
  78. package/src/exceptions/index.ts +4 -0
  79. package/src/exceptions/invalidRpcUrl.exception.ts +6 -0
  80. package/src/exceptions/privacyPool.exception.ts +19 -0
  81. package/src/external.ts +13 -0
  82. package/src/filename.helper.ts +4 -0
  83. package/src/index.ts +18 -0
  84. package/src/interfaces/blockchainProvider.interface.ts +13 -0
  85. package/src/interfaces/circuits.interface.ts +34 -0
  86. package/src/interfaces/contracts.interface.ts +58 -0
  87. package/src/interfaces/index.ts +1 -0
  88. package/src/internal.ts +6 -0
  89. package/src/providers/blockchainProvider.ts +26 -0
  90. package/src/providers/index.ts +1 -0
  91. package/src/types/commitment.ts +50 -0
  92. package/src/types/index.ts +2 -0
  93. package/src/types/withdrawal.ts +33 -0
@@ -0,0 +1,407 @@
1
+ import {
2
+ Abi,
3
+ Account,
4
+ Address,
5
+ Chain,
6
+ Hex,
7
+ PublicClient,
8
+ WalletClient,
9
+ createPublicClient,
10
+ createWalletClient,
11
+ getAddress,
12
+ http,
13
+ } from "viem";
14
+ import { Withdrawal, WithdrawalProof } from "../types/withdrawal.js";
15
+ import {
16
+ ContractInteractions,
17
+ TransactionResponse,
18
+ } from "../interfaces/contracts.interface.js";
19
+ import { IEntrypointABI } from "../abi/IEntrypoint.js";
20
+ import { IPrivacyPoolABI } from "../abi/IPrivacyPool.js";
21
+ import { ERC20ABI } from "../abi/ERC20.js";
22
+ import { privateKeyToAccount } from "viem/accounts";
23
+ import { CommitmentProof, Hash } from "../types/commitment.js";
24
+ import { bigintToHex } from "../crypto.js";
25
+ import { ContractError } from "../errors/base.error.js";
26
+
27
+ export class ContractInteractionsService implements ContractInteractions {
28
+ private publicClient: PublicClient;
29
+ private walletClient: WalletClient;
30
+ private entrypointAddress: Address;
31
+ private account: Account;
32
+
33
+ /**
34
+ * Initializes the contract interactions service.
35
+ *
36
+ * @param rpcUrl - The RPC endpoint URL for the blockchain network.
37
+ * @param chain - The blockchain network configuration.
38
+ * @param entrypointAddress - The address of the entrypoint contract.
39
+ * @param accountPrivateKey - The private key used for signing transactions.
40
+ */
41
+ constructor(
42
+ rpcUrl: string,
43
+ chain: Chain,
44
+ entrypointAddress: Address,
45
+ accountPrivateKey: Hex,
46
+ ) {
47
+ if (!entrypointAddress) {
48
+ throw new Error(
49
+ "Invalid entrypoint addresses provided to ContractInteractionsService",
50
+ );
51
+ }
52
+
53
+ this.account = privateKeyToAccount(accountPrivateKey);
54
+
55
+ this.walletClient = createWalletClient({
56
+ chain: chain,
57
+ transport: http(rpcUrl),
58
+ account: this.account,
59
+ });
60
+
61
+ this.publicClient = createPublicClient({
62
+ chain: chain,
63
+ transport: http(rpcUrl),
64
+ });
65
+
66
+ this.entrypointAddress = entrypointAddress;
67
+ }
68
+
69
+ /**
70
+ * Deposits ERC20 tokens into the privacy pool.
71
+ *
72
+ * @param asset - The address of the ERC20 token.
73
+ * @param amount - The amount of tokens to deposit.
74
+ * @param precommitment - The precommitment value.
75
+ * @returns Transaction response containing the transaction hash.
76
+ */
77
+ async depositERC20(
78
+ asset: Address,
79
+ amount: bigint,
80
+ precommitment: bigint,
81
+ ): Promise<TransactionResponse> {
82
+ try {
83
+ const { request } = await this.publicClient.simulateContract({
84
+ address: this.entrypointAddress,
85
+ abi: IEntrypointABI as Abi,
86
+ functionName: "deposit",
87
+ args: [asset, amount, precommitment],
88
+ value: 0n,
89
+ account: this.account,
90
+ });
91
+ return await this.executeTransaction(request);
92
+ } catch (error) {
93
+ console.error("Deposit ERC20 Error:", { error, asset, amount });
94
+ throw new Error(
95
+ `Failed to deposit ERC20: ${error instanceof Error ? error.message : "Unknown error"}`,
96
+ );
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Deposits ETH into the privacy pool.
102
+ *
103
+ * @param amount - The amount of ETH to deposit.
104
+ * @param precommitment - The precommitment value.
105
+ * @returns Transaction response containing the transaction hash.
106
+ */
107
+ async depositETH(
108
+ amount: bigint,
109
+ precommitment: bigint,
110
+ ): Promise<TransactionResponse> {
111
+ try {
112
+ const { request } = await this.publicClient.simulateContract({
113
+ address: this.entrypointAddress,
114
+ abi: IEntrypointABI as Abi,
115
+ functionName: "deposit",
116
+ args: [precommitment],
117
+ value: amount,
118
+ account: this.account,
119
+ });
120
+
121
+ return await this.executeTransaction(request);
122
+ } catch (error) {
123
+ console.error("Deposit ETH Error:", { error, amount });
124
+ throw new Error(
125
+ `Failed to deposit ETH: ${error instanceof Error ? error.message : "Unknown error"}`,
126
+ );
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Withdraws funds from the privacy pool.
132
+ *
133
+ * @param withdrawal - The withdrawal object containing recipient details and amount.
134
+ * @param withdrawalProof - The cryptographic proof verifying the withdrawal.
135
+ * @returns Transaction response containing the transaction hash.
136
+ */
137
+ async withdraw(
138
+ withdrawal: Withdrawal,
139
+ withdrawalProof: WithdrawalProof,
140
+ scope: Hash,
141
+ ): Promise<TransactionResponse> {
142
+ try {
143
+ const formattedProof = this.formatProof(withdrawalProof);
144
+
145
+ // get pool address from scope
146
+ const scopeData = await this.getScopeData(scope);
147
+
148
+ const { request } = await this.publicClient.simulateContract({
149
+ address: scopeData.poolAddress,
150
+ abi: IPrivacyPoolABI as Abi,
151
+ functionName: "withdraw",
152
+ account: this.account.address as Address,
153
+ args: [withdrawal, formattedProof],
154
+ });
155
+
156
+ return await this.executeTransaction(request);
157
+ } catch (error) {
158
+ console.error("Withdraw Error Details:", {
159
+ error,
160
+ accountAddress: this.account.address,
161
+ });
162
+ throw new Error(
163
+ `Failed to Withdraw: ${error instanceof Error ? error.message : "Unknown error"}`,
164
+ );
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Relays a withdrawal transaction to the entrypoint contract.
170
+ * This function is used to facilitate relayer transactions.
171
+ *
172
+ * @param withdrawal - The withdrawal data structure.
173
+ * @param withdrawalProof - The cryptographic proof required for withdrawal.
174
+ * @returns Transaction response containing hash and wait function.
175
+ */
176
+ async relay(
177
+ withdrawal: Withdrawal,
178
+ withdrawalProof: WithdrawalProof,
179
+ scope: Hash,
180
+ ): Promise<TransactionResponse> {
181
+ try {
182
+ const formattedProof = this.formatProof(withdrawalProof);
183
+
184
+ const { request } = await this.publicClient.simulateContract({
185
+ address: this.entrypointAddress,
186
+ abi: [...(IEntrypointABI as Abi), ...(IPrivacyPoolABI as Abi)],
187
+ functionName: "relay",
188
+ account: this.account,
189
+ args: [withdrawal, formattedProof, scope],
190
+ });
191
+
192
+ return await this.executeTransaction(request);
193
+ } catch (error) {
194
+ console.error("Withdraw Error Details:", {
195
+ error,
196
+ accountAddress: this.account.address,
197
+ });
198
+ throw error;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Executes a ragequit operation, allowing a user to exit the pool
204
+ * by nullifying their commitment and proving their withdrawal.
205
+ *
206
+ * @param commitmentProof - The cryptographic proof of the commitment.
207
+ * @param privacyPoolAddress - The address of the privacy pool contract.
208
+ * @returns Transaction response containing hash and wait function.
209
+ */
210
+ async ragequit(
211
+ commitmentProof: CommitmentProof,
212
+ privacyPoolAddress: Address,
213
+ ): Promise<TransactionResponse> {
214
+ try {
215
+ const formattedProof = this.formatProof(commitmentProof);
216
+
217
+ const { request } = await this.publicClient.simulateContract({
218
+ address: privacyPoolAddress,
219
+ abi: IPrivacyPoolABI as Abi,
220
+ functionName: "ragequit",
221
+ args: [formattedProof],
222
+ account: this.account,
223
+ });
224
+
225
+ return await this.executeTransaction(request);
226
+ } catch (error) {
227
+ console.error("Ragequit Error:", { error });
228
+ throw new Error(
229
+ `Failed to Ragequit: ${error instanceof Error ? error.message : "Unknown error"}`,
230
+ );
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Retrieves the scope identifier of a given privacy pool.
236
+ *
237
+ * @param privacyPoolAddress - The address of the privacy pool contract.
238
+ * @returns The scope identifier as a bigint.
239
+ */
240
+ async getScope(privacyPoolAddress: Address): Promise<bigint> {
241
+ const scope = await this.publicClient.readContract({
242
+ address: privacyPoolAddress,
243
+ abi: IPrivacyPoolABI as Abi,
244
+ functionName: "SCOPE",
245
+ account: this.account,
246
+ });
247
+
248
+ return BigInt(scope as string);
249
+ }
250
+
251
+ /**
252
+ * Retrieves the latest state root of the privacy pool from the entrypoint contract.
253
+ *
254
+ * @param privacyPoolAddress - The address of the privacy pool contract.
255
+ * @returns The latest state root as a bigint.
256
+ */
257
+ async getStateRoot(privacyPoolAddress: Address): Promise<bigint> {
258
+ const stateRoot = await this.publicClient.readContract({
259
+ address: privacyPoolAddress,
260
+ abi: IEntrypointABI as Abi,
261
+ account: this.account,
262
+ functionName: "latestRoot",
263
+ });
264
+
265
+ return BigInt(stateRoot as string);
266
+ }
267
+
268
+ /**
269
+ * Retrieves the current state size of the privacy pool.
270
+ *
271
+ * @param privacyPoolAddress - The address of the privacy pool contract.
272
+ * @returns The size of the state tree as a bigint.
273
+ */
274
+ async getStateSize(privacyPoolAddress: Address): Promise<bigint> {
275
+ const stateSize = await this.publicClient.readContract({
276
+ address: privacyPoolAddress,
277
+ abi: IPrivacyPoolABI as Abi,
278
+ account: this.account,
279
+ // this should be added in the next update of PrivacyPoolSimple.sol
280
+ functionName: "currentTreeSize",
281
+ });
282
+
283
+ return BigInt(stateSize as string);
284
+ }
285
+
286
+ /**
287
+ * Retrieves data about a specific scope, including the associated privacy pool
288
+ * and the asset used in that pool.
289
+ *
290
+ * @param scope - The scope identifier to look up.
291
+ * @returns An object containing the privacy pool address and asset address.
292
+ * @throws ContractError if the scope does not exist.
293
+ */
294
+ async getScopeData(
295
+ scope: bigint,
296
+ ): Promise<{ poolAddress: Address; assetAddress: Address }> {
297
+ try {
298
+ // get pool address fro entrypoint
299
+ const poolAddress = await this.publicClient.readContract({
300
+ address: this.entrypointAddress,
301
+ abi: IEntrypointABI as Abi,
302
+ account: this.account,
303
+ args: [scope],
304
+ functionName: "scopeToPool",
305
+ });
306
+
307
+ // if no pool throw error
308
+ if (
309
+ !poolAddress ||
310
+ poolAddress === "0x0000000000000000000000000000000000000000"
311
+ ) {
312
+ throw ContractError.scopeNotFound(scope);
313
+ }
314
+
315
+ // get asset adress from pool
316
+ const assetAddress = await this.publicClient.readContract({
317
+ address: getAddress(poolAddress as string),
318
+ abi: IPrivacyPoolABI as Abi,
319
+ account: this.account,
320
+ functionName: "ASSET",
321
+ });
322
+
323
+ return {
324
+ poolAddress: getAddress(poolAddress as string),
325
+ assetAddress: getAddress(assetAddress as string),
326
+ };
327
+ } catch (error) {
328
+ if (error instanceof ContractError) throw error;
329
+ console.error(`Error resolving scope ${scope.toString()}:`, error);
330
+ throw new Error(
331
+ `Failed to resolve scope ${scope.toString()}: ${error instanceof Error ? error.message : "Unknown error"}`,
332
+ );
333
+ }
334
+ }
335
+
336
+ /**
337
+ * Approves the entrypoint contract to spend a specified amount of ERC20 tokens.
338
+ *
339
+ * @param spenderAddress - The address of the entity that will be approved to spend tokens.
340
+ * @param tokenAddress - The address of the ERC20 token contract.
341
+ * @param amount - The amount of tokens to approve.
342
+ * @returns Transaction response containing hash and wait function.
343
+ */
344
+ async approveERC20(
345
+ spenderAddress: Address,
346
+ tokenAddress: Address,
347
+ amount: bigint,
348
+ ): Promise<TransactionResponse> {
349
+ try {
350
+ const { request } = await this.publicClient.simulateContract({
351
+ address: tokenAddress,
352
+ abi: ERC20ABI as Abi,
353
+ functionName: "approve",
354
+ args: [spenderAddress, amount],
355
+ account: this.account,
356
+ });
357
+
358
+ return await this.executeTransaction(request);
359
+ } catch (error) {
360
+ console.error("ERC20 Approval Error:", { error, tokenAddress, amount });
361
+ throw new Error(
362
+ `Failed to approve ERC20: ${error instanceof Error ? error.message : "Unknown error"}`,
363
+ );
364
+ }
365
+ }
366
+
367
+ private formatProof(proof: CommitmentProof | WithdrawalProof) {
368
+ return {
369
+ pA: [
370
+ bigintToHex(proof.proof.pi_a?.[0]),
371
+ bigintToHex(proof.proof.pi_a?.[1]),
372
+ ],
373
+ pB: [
374
+ [
375
+ bigintToHex(proof.proof.pi_b?.[0]?.[1]),
376
+ bigintToHex(proof.proof.pi_b?.[0]?.[0]),
377
+ ],
378
+ [
379
+ bigintToHex(proof.proof.pi_b?.[1]?.[1]),
380
+ bigintToHex(proof.proof.pi_b?.[1]?.[0]),
381
+ ],
382
+ ],
383
+ pC: [
384
+ bigintToHex(proof.proof.pi_c?.[0]),
385
+ bigintToHex(proof.proof.pi_c?.[1]),
386
+ ],
387
+ pubSignals: proof.publicSignals.map(bigintToHex),
388
+ };
389
+ }
390
+
391
+ private async executeTransaction(request: any): Promise<TransactionResponse> {
392
+ try {
393
+ const hash = await this.walletClient.writeContract(request);
394
+ return {
395
+ hash,
396
+ wait: async () => {
397
+ await this.publicClient.waitForTransactionReceipt({ hash });
398
+ },
399
+ };
400
+ } catch (error) {
401
+ console.error("Transaction Execution Error:", { error, request });
402
+ throw new Error(
403
+ `Transaction failed: ${error instanceof Error ? error.message : "Unknown error"}`,
404
+ );
405
+ }
406
+ }
407
+ }
@@ -0,0 +1,91 @@
1
+ import { CommitmentService } from "./commitment.service.js";
2
+ import { WithdrawalService } from "./withdrawal.service.js";
3
+ import { CircuitsInterface } from "../interfaces/circuits.interface.js";
4
+ import { Commitment, CommitmentProof } from "../types/commitment.js";
5
+ import { WithdrawalProof, WithdrawalProofInput } from "../types/withdrawal.js";
6
+ import { ContractInteractionsService } from "./contracts.service.js";
7
+ import { Hex, Address, Chain } from "viem";
8
+
9
+ /**
10
+ * Main SDK class providing access to all privacy pool functionality.
11
+ * Uses Poseidon hash for all commitment operations.
12
+ */
13
+ export class PrivacyPoolSDK {
14
+ private readonly commitmentService: CommitmentService;
15
+ private readonly withdrawalService: WithdrawalService;
16
+
17
+ constructor(circuits: CircuitsInterface) {
18
+ this.commitmentService = new CommitmentService(circuits);
19
+ this.withdrawalService = new WithdrawalService(circuits);
20
+ }
21
+
22
+ public createContractInstance(
23
+ rpcUrl: string,
24
+ chain: Chain,
25
+ entrypointAddress: Address,
26
+ privateKey: Hex,
27
+ ): ContractInteractionsService {
28
+ return new ContractInteractionsService(
29
+ rpcUrl,
30
+ chain,
31
+ entrypointAddress,
32
+ privateKey,
33
+ );
34
+ }
35
+
36
+ /**
37
+ * Generates a commitment proof.
38
+ *
39
+ * @param value - Value to commit
40
+ * @param label - Label for the commitment
41
+ * @param nullifier - Nullifier for the commitment
42
+ * @param secret - Secret for the commitment
43
+ */
44
+ public async proveCommitment(
45
+ value: bigint,
46
+ label: bigint,
47
+ nullifier: bigint,
48
+ secret: bigint,
49
+ ): Promise<CommitmentProof> {
50
+ return this.commitmentService.proveCommitment(
51
+ value,
52
+ label,
53
+ nullifier,
54
+ secret,
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Verifies a commitment proof.
60
+ *
61
+ * @param proof - The proof to verify
62
+ */
63
+ public async verifyCommitment(proof: CommitmentProof): Promise<boolean> {
64
+ return this.commitmentService.verifyCommitment(proof);
65
+ }
66
+
67
+ /**
68
+ * Generates a withdrawal proof.
69
+ *
70
+ * @param commitment - Commitment to withdraw
71
+ * @param input - Input parameters for the withdrawal
72
+ * @param withdrawal - Withdrawal details
73
+ */
74
+ public async proveWithdrawal(
75
+ commitment: Commitment,
76
+ input: WithdrawalProofInput,
77
+ ): Promise<WithdrawalProof> {
78
+ return await this.withdrawalService.proveWithdrawal(commitment, input);
79
+ }
80
+
81
+ /**
82
+ * Verifies a withdrawal proof.
83
+ *
84
+ * @param withdrawalProof - The withdrawal payload to verify
85
+ */
86
+ public async verifyWithdrawal(
87
+ withdrawalProof: WithdrawalProof,
88
+ ): Promise<boolean> {
89
+ return this.withdrawalService.verifyWithdrawal(withdrawalProof);
90
+ }
91
+ }
@@ -0,0 +1,110 @@
1
+ import * as snarkjs from "snarkjs";
2
+ import { ProofError } from "../errors/base.error.js";
3
+ import {
4
+ CircuitName,
5
+ CircuitsInterface,
6
+ } from "../interfaces/circuits.interface.js";
7
+ import { Commitment } from "../types/commitment.js";
8
+ import { WithdrawalProof, WithdrawalProofInput } from "../types/withdrawal.js";
9
+
10
+ /**
11
+ * Service responsible for handling withdrawal-related operations.
12
+ */
13
+ export class WithdrawalService {
14
+ constructor(private readonly circuits: CircuitsInterface) {}
15
+
16
+ /**
17
+ * Generates a withdrawal proof.
18
+ *
19
+ * @param commitment - Commitment to withdraw
20
+ * @param input - Input parameters for the withdrawal
21
+ * @param withdrawal - Withdrawal details
22
+ * @returns Promise resolving to withdrawal payload
23
+ * @throws {ProofError} If proof generation fails
24
+ */
25
+ public async proveWithdrawal(
26
+ commitment: Commitment,
27
+ input: WithdrawalProofInput,
28
+ ): Promise<WithdrawalProof> {
29
+ try {
30
+ const inputSignals = this.prepareInputSignals(commitment, input);
31
+
32
+ const wasm = await this.circuits.getWasm(CircuitName.Withdraw);
33
+ const zkey = await this.circuits.getProvingKey(CircuitName.Withdraw);
34
+
35
+ const { proof, publicSignals } = await snarkjs.groth16.fullProve(
36
+ inputSignals,
37
+ wasm,
38
+ zkey,
39
+ );
40
+
41
+ return {
42
+ proof,
43
+ publicSignals,
44
+ };
45
+ } catch (error) {
46
+ throw ProofError.generationFailed({
47
+ error: error instanceof Error ? error.message : "Unknown error",
48
+ });
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Verifies a withdrawal proof.
54
+ *
55
+ * @param withdrawalPayload - The withdrawal payload to verify
56
+ * @returns Promise resolving to boolean indicating proof validity
57
+ * @throws {ProofError} If verification fails
58
+ */
59
+ public async verifyWithdrawal(
60
+ withdrawalPayload: WithdrawalProof,
61
+ ): Promise<boolean> {
62
+ try {
63
+ const vkeyBin = await this.circuits.getVerificationKey(
64
+ CircuitName.Withdraw,
65
+ );
66
+ const vkey = JSON.parse(new TextDecoder("utf-8").decode(vkeyBin));
67
+ return await snarkjs.groth16.verify(
68
+ vkey,
69
+ withdrawalPayload.publicSignals,
70
+ withdrawalPayload.proof,
71
+ );
72
+ } catch (error) {
73
+ throw ProofError.verificationFailed({
74
+ error: error instanceof Error ? error.message : "Unknown error",
75
+ });
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Prepares input signals for the withdrawal circuit.
81
+ */
82
+ private prepareInputSignals(
83
+ commitment: Commitment,
84
+ input: WithdrawalProofInput,
85
+ ): Record<string, bigint | bigint[] | string> {
86
+ return {
87
+ // Public signals
88
+ withdrawnValue: input.withdrawalAmount,
89
+ stateRoot: input.stateRoot,
90
+ stateTreeDepth: input.stateTreeDepth,
91
+ ASPRoot: input.aspRoot,
92
+ ASPTreeDepth: input.aspTreeDepth,
93
+ context: input.context,
94
+
95
+ // Private signals
96
+ label: commitment.preimage.label,
97
+ existingValue: commitment.preimage.value,
98
+ existingNullifier: commitment.preimage.precommitment.nullifier,
99
+ existingSecret: commitment.preimage.precommitment.secret,
100
+ newNullifier: input.newNullifier,
101
+ newSecret: input.newSecret,
102
+
103
+ // Merkle Proofs
104
+ stateSiblings: input.stateMerkleProof.siblings,
105
+ stateIndex: BigInt(input.stateMerkleProof.index),
106
+ ASPSiblings: input.aspMerkleProof.siblings,
107
+ ASPIndex: BigInt(input.aspMerkleProof.index),
108
+ };
109
+ }
110
+ }