@0xbow/privacy-pools-core-sdk 0.0.0-c084059
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/README.md +73 -0
- package/dist/esm/ccip-nJye9Itm.js +166 -0
- package/dist/esm/ccip-nJye9Itm.js.map +1 -0
- package/dist/esm/index-DAWUECi8.js +84043 -0
- package/dist/esm/index-DAWUECi8.js.map +1 -0
- package/dist/esm/index.mjs +4 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/index.d.mts +666 -0
- package/dist/node/ccip-lPhPeJab.js +183 -0
- package/dist/node/ccip-lPhPeJab.js.map +1 -0
- package/dist/node/index-BiU5Ef8Z.js +90625 -0
- package/dist/node/index-BiU5Ef8Z.js.map +1 -0
- package/dist/node/index.mjs +21 -0
- package/dist/node/index.mjs.map +1 -0
- package/dist/types/abi/ERC20.d.ts +38 -0
- package/dist/types/abi/IEntrypoint.d.ts +794 -0
- package/dist/types/abi/IPrivacyPool.d.ts +51 -0
- package/dist/types/ccip-BZzz1Y5w.js +182 -0
- package/dist/types/circuits/circuits.impl.d.ts +108 -0
- package/dist/types/circuits/circuits.interface.d.ts +127 -0
- package/dist/types/circuits/index.d.ts +2 -0
- package/dist/types/constants.d.ts +2 -0
- package/dist/types/core/bruteForce.service.d.ts +61 -0
- package/dist/types/core/commitment.service.d.ts +30 -0
- package/dist/types/core/contracts.service.d.ts +106 -0
- package/dist/types/core/sdk.d.ts +44 -0
- package/dist/types/core/withdrawal.service.d.ts +32 -0
- package/dist/types/crypto.d.ts +45 -0
- package/dist/types/dirname.helper.d.ts +2 -0
- package/dist/types/errors/base.error.d.ts +52 -0
- package/dist/types/exceptions/circuitInitialization.exception.d.ts +3 -0
- package/dist/types/exceptions/fetchArtifacts.exception.d.ts +3 -0
- package/dist/types/exceptions/index.d.ts +4 -0
- package/dist/types/exceptions/invalidRpcUrl.exception.d.ts +3 -0
- package/dist/types/exceptions/privacyPool.exception.d.ts +13 -0
- package/dist/types/external.d.ts +7 -0
- package/dist/types/filename.helper.d.ts +2 -0
- package/dist/types/index-D-_1h8-n.js +90638 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.js +20 -0
- package/dist/types/interfaces/blockchainProvider.interface.d.ts +12 -0
- package/dist/types/interfaces/circuits.interface.d.ts +30 -0
- package/dist/types/interfaces/contracts.interface.d.ts +28 -0
- package/dist/types/interfaces/index.d.ts +1 -0
- package/dist/types/internal.d.ts +6 -0
- package/dist/types/providers/blockchainProvider.d.ts +8 -0
- package/dist/types/providers/index.d.ts +1 -0
- package/dist/types/types/commitment.d.ts +48 -0
- package/dist/types/types/index.d.ts +2 -0
- package/dist/types/types/withdrawal.d.ts +30 -0
- package/package.json +81 -0
- package/src/abi/ERC20.ts +222 -0
- package/src/abi/IEntrypoint.ts +1059 -0
- package/src/abi/IPrivacyPool.ts +576 -0
- package/src/circuits/circuits.impl.ts +232 -0
- package/src/circuits/circuits.interface.ts +166 -0
- package/src/circuits/fetchArtifacts.esm.ts +12 -0
- package/src/circuits/fetchArtifacts.node.ts +23 -0
- package/src/circuits/fetchArtifacts.ts +7 -0
- package/src/circuits/index.ts +2 -0
- package/src/constants.ts +3 -0
- package/src/core/account.service.ts +1077 -0
- package/src/core/bruteForce.service.ts +120 -0
- package/src/core/commitment.service.ts +84 -0
- package/src/core/contracts.service.ts +442 -0
- package/src/core/data.service.ts +272 -0
- package/src/core/sdk.ts +92 -0
- package/src/core/withdrawal.service.ts +126 -0
- package/src/crypto.ts +226 -0
- package/src/dirname.helper.ts +4 -0
- package/src/errors/account.error.ts +49 -0
- package/src/errors/base.error.ts +125 -0
- package/src/errors/data.error.ts +34 -0
- package/src/errors/events.error.ts +38 -0
- package/src/exceptions/circuitInitialization.exception.ts +6 -0
- package/src/exceptions/fetchArtifacts.exception.ts +7 -0
- package/src/exceptions/index.ts +4 -0
- package/src/exceptions/invalidRpcUrl.exception.ts +6 -0
- package/src/exceptions/privacyPool.exception.ts +19 -0
- package/src/external.ts +13 -0
- package/src/filename.helper.ts +4 -0
- package/src/index.ts +21 -0
- package/src/interfaces/blockchainProvider.interface.ts +13 -0
- package/src/interfaces/circuits.interface.ts +34 -0
- package/src/interfaces/contracts.interface.ts +66 -0
- package/src/interfaces/index.ts +1 -0
- package/src/internal.ts +6 -0
- package/src/keys.ts +42 -0
- package/src/providers/blockchainProvider.ts +26 -0
- package/src/providers/index.ts +1 -0
- package/src/types/account.ts +35 -0
- package/src/types/commitment.ts +50 -0
- package/src/types/events.ts +82 -0
- package/src/types/index.ts +3 -0
- package/src/types/keys.ts +6 -0
- package/src/types/withdrawal.ts +33 -0
- package/src/utils/logger.ts +56 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type PublicClient,
|
|
3
|
+
createPublicClient,
|
|
4
|
+
http,
|
|
5
|
+
parseAbiItem,
|
|
6
|
+
} from "viem";
|
|
7
|
+
import {
|
|
8
|
+
ChainConfig,
|
|
9
|
+
DepositEvent,
|
|
10
|
+
WithdrawalEvent,
|
|
11
|
+
RagequitEvent,
|
|
12
|
+
} from "../types/events.js";
|
|
13
|
+
import { PoolInfo } from "../types/account.js";
|
|
14
|
+
import { Hash } from "../types/commitment.js";
|
|
15
|
+
import { Logger } from "../utils/logger.js";
|
|
16
|
+
import { DataError } from "../errors/data.error.js";
|
|
17
|
+
import { ErrorCode } from "../errors/base.error.js";
|
|
18
|
+
|
|
19
|
+
// Event signatures from the contract
|
|
20
|
+
const DEPOSIT_EVENT = parseAbiItem('event Deposited(address indexed _depositor, uint256 _commitment, uint256 _label, uint256 _value, uint256 _merkleRoot)');
|
|
21
|
+
const WITHDRAWAL_EVENT = parseAbiItem('event Withdrawn(address indexed _processooor, uint256 _value, uint256 _spentNullifier, uint256 _newCommitment)');
|
|
22
|
+
const RAGEQUIT_EVENT = parseAbiItem('event Ragequit(address indexed _ragequitter, uint256 _commitment, uint256 _label, uint256 _value)');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Service responsible for fetching and managing privacy pool events across multiple chains.
|
|
26
|
+
* Handles event retrieval, parsing, and validation for deposits, withdrawals, and ragequits.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* This service uses viem's PublicClient to efficiently fetch and process blockchain events.
|
|
30
|
+
* It supports multiple chains and provides robust error handling and validation.
|
|
31
|
+
* All uint256 values from events are handled as bigints, with Hash type assertions for commitment-related fields.
|
|
32
|
+
*/
|
|
33
|
+
export class DataService {
|
|
34
|
+
private readonly clients: Map<number, PublicClient> = new Map();
|
|
35
|
+
private readonly logger: Logger;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Initialize the data service with chain configurations
|
|
39
|
+
*
|
|
40
|
+
* @param chainConfigs - Array of chain configurations containing chainId, RPC URL, and API key
|
|
41
|
+
* @throws {DataError} If client initialization fails for any chain
|
|
42
|
+
*/
|
|
43
|
+
constructor(private readonly chainConfigs: ChainConfig[]) {
|
|
44
|
+
this.logger = new Logger({ prefix: "Data" });
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
for (const config of chainConfigs) {
|
|
48
|
+
if (!config.rpcUrl) {
|
|
49
|
+
throw new Error(`Missing RPC URL for chain ${config.chainId}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const client = createPublicClient({
|
|
53
|
+
transport: http(config.rpcUrl),
|
|
54
|
+
});
|
|
55
|
+
this.clients.set(config.chainId, client);
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
throw new DataError(
|
|
59
|
+
"Failed to initialize PublicClient",
|
|
60
|
+
ErrorCode.NETWORK_ERROR,
|
|
61
|
+
{ error: error instanceof Error ? error.message : "Unknown error" },
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get deposit events for a specific chain
|
|
68
|
+
*
|
|
69
|
+
* @param chainId - Chain ID to fetch events from
|
|
70
|
+
* @param options - Event filter options including fromBlock, toBlock, and other filters
|
|
71
|
+
* @returns Array of deposit events with properly typed fields (bigint for numbers, Hash for commitments)
|
|
72
|
+
* @throws {DataError} If client is not configured, network error occurs, or event data is invalid
|
|
73
|
+
*/
|
|
74
|
+
async getDeposits(
|
|
75
|
+
pool: PoolInfo
|
|
76
|
+
): Promise<DepositEvent[]> {
|
|
77
|
+
try {
|
|
78
|
+
const client = this.getClientForChain(pool.chainId);
|
|
79
|
+
const config = this.getConfigForChain(pool.chainId);
|
|
80
|
+
|
|
81
|
+
const logs = await client.getLogs({
|
|
82
|
+
address: pool.address,
|
|
83
|
+
event: DEPOSIT_EVENT,
|
|
84
|
+
fromBlock: pool.deploymentBlock ?? config.startBlock
|
|
85
|
+
}).catch(error => {
|
|
86
|
+
throw new DataError(
|
|
87
|
+
"Failed to fetch deposit logs",
|
|
88
|
+
ErrorCode.NETWORK_ERROR,
|
|
89
|
+
{ error: error instanceof Error ? error.message : "Unknown error" },
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return logs.map((log) => {
|
|
94
|
+
try {
|
|
95
|
+
if (!log.args) {
|
|
96
|
+
throw DataError.invalidLog("deposit", "missing args");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const {
|
|
100
|
+
_depositor: depositor,
|
|
101
|
+
_commitment: commitment,
|
|
102
|
+
_label: label,
|
|
103
|
+
_value: value,
|
|
104
|
+
_merkleRoot: precommitment,
|
|
105
|
+
} = log.args;
|
|
106
|
+
|
|
107
|
+
if (!depositor || !commitment || !label || !precommitment || !log.blockNumber || !log.transactionHash) {
|
|
108
|
+
throw DataError.invalidLog("deposit", "missing required fields");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
depositor: depositor.toLowerCase(),
|
|
113
|
+
commitment: commitment as Hash,
|
|
114
|
+
label: label as Hash,
|
|
115
|
+
value: value || BigInt(0),
|
|
116
|
+
precommitment: precommitment as Hash,
|
|
117
|
+
blockNumber: BigInt(log.blockNumber),
|
|
118
|
+
transactionHash: log.transactionHash,
|
|
119
|
+
};
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (error instanceof DataError) throw error;
|
|
122
|
+
throw DataError.invalidLog("deposit", error instanceof Error ? error.message : "Unknown error");
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error instanceof DataError) throw error;
|
|
127
|
+
throw DataError.networkError(pool.chainId, error instanceof Error ? error : new Error(String(error)));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get withdrawal events for a specific chain
|
|
133
|
+
*
|
|
134
|
+
* @param chainId - Chain ID to fetch events from
|
|
135
|
+
* @param options - Event filter options including fromBlock, toBlock, and other filters
|
|
136
|
+
* @returns Array of withdrawal events with properly typed fields (bigint for numbers, Hash for commitments)
|
|
137
|
+
* @throws {DataError} If client is not configured, network error occurs, or event data is invalid
|
|
138
|
+
*/
|
|
139
|
+
async getWithdrawals(
|
|
140
|
+
pool: PoolInfo,
|
|
141
|
+
fromBlock: bigint = pool.deploymentBlock
|
|
142
|
+
): Promise<WithdrawalEvent[]> {
|
|
143
|
+
try {
|
|
144
|
+
const client = this.getClientForChain(pool.chainId);
|
|
145
|
+
const config = this.getConfigForChain(pool.chainId);
|
|
146
|
+
|
|
147
|
+
const logs = await client.getLogs({
|
|
148
|
+
address: pool.address,
|
|
149
|
+
event: WITHDRAWAL_EVENT,
|
|
150
|
+
fromBlock: fromBlock ?? config.startBlock,
|
|
151
|
+
}).catch(error => {
|
|
152
|
+
throw new DataError(
|
|
153
|
+
"Failed to fetch withdrawal logs",
|
|
154
|
+
ErrorCode.NETWORK_ERROR,
|
|
155
|
+
{ error: error instanceof Error ? error.message : "Unknown error" },
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return logs.map((log) => {
|
|
160
|
+
try {
|
|
161
|
+
if (!log.args) {
|
|
162
|
+
throw DataError.invalidLog("withdrawal", "missing args");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const {
|
|
166
|
+
_value: value,
|
|
167
|
+
_spentNullifier: spentNullifier,
|
|
168
|
+
_newCommitment: newCommitment,
|
|
169
|
+
} = log.args;
|
|
170
|
+
|
|
171
|
+
if (!value || !spentNullifier || !newCommitment || !log.blockNumber || !log.transactionHash) {
|
|
172
|
+
throw DataError.invalidLog("withdrawal", "missing required fields");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
withdrawn: value,
|
|
177
|
+
spentNullifier: spentNullifier as Hash,
|
|
178
|
+
newCommitment: newCommitment as Hash,
|
|
179
|
+
blockNumber: BigInt(log.blockNumber),
|
|
180
|
+
transactionHash: log.transactionHash,
|
|
181
|
+
};
|
|
182
|
+
} catch (error) {
|
|
183
|
+
if (error instanceof DataError) throw error;
|
|
184
|
+
throw DataError.invalidLog("withdrawal", error instanceof Error ? error.message : "Unknown error");
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (error instanceof DataError) throw error;
|
|
189
|
+
throw DataError.networkError(pool.chainId, error instanceof Error ? error : new Error(String(error)));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get ragequit events for a specific chain
|
|
195
|
+
*
|
|
196
|
+
* @param chainId - Chain ID to fetch events from
|
|
197
|
+
* @param options - Event filter options including fromBlock, toBlock, and other filters
|
|
198
|
+
* @returns Array of ragequit events with properly typed fields (bigint for numbers, Hash for commitments)
|
|
199
|
+
* @throws {DataError} If client is not configured, network error occurs, or event data is invalid
|
|
200
|
+
*/
|
|
201
|
+
async getRagequits(
|
|
202
|
+
pool: PoolInfo,
|
|
203
|
+
fromBlock: bigint = pool.deploymentBlock
|
|
204
|
+
): Promise<RagequitEvent[]> {
|
|
205
|
+
try {
|
|
206
|
+
const client = this.getClientForChain(pool.chainId);
|
|
207
|
+
const config = this.getConfigForChain(pool.chainId);
|
|
208
|
+
|
|
209
|
+
const logs = await client.getLogs({
|
|
210
|
+
address: pool.address,
|
|
211
|
+
event: RAGEQUIT_EVENT,
|
|
212
|
+
fromBlock: fromBlock ?? config.startBlock,
|
|
213
|
+
}).catch(error => {
|
|
214
|
+
throw new DataError(
|
|
215
|
+
"Failed to fetch ragequit logs",
|
|
216
|
+
ErrorCode.NETWORK_ERROR,
|
|
217
|
+
{ error: error instanceof Error ? error.message : "Unknown error" },
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return logs.map((log) => {
|
|
222
|
+
try {
|
|
223
|
+
if (!log.args) {
|
|
224
|
+
throw DataError.invalidLog("ragequit", "missing args");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const {
|
|
228
|
+
_ragequitter: ragequitter,
|
|
229
|
+
_commitment: commitment,
|
|
230
|
+
_label: label,
|
|
231
|
+
_value: value,
|
|
232
|
+
} = log.args;
|
|
233
|
+
|
|
234
|
+
if (!ragequitter || !commitment || !label || !log.blockNumber || !log.transactionHash) {
|
|
235
|
+
throw DataError.invalidLog("ragequit", "missing required fields");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
ragequitter: ragequitter.toLowerCase(),
|
|
240
|
+
commitment: commitment as Hash,
|
|
241
|
+
label: label as Hash,
|
|
242
|
+
value: value || BigInt(0),
|
|
243
|
+
blockNumber: BigInt(log.blockNumber),
|
|
244
|
+
transactionHash: log.transactionHash,
|
|
245
|
+
};
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (error instanceof DataError) throw error;
|
|
248
|
+
throw DataError.invalidLog("ragequit", error instanceof Error ? error.message : "Unknown error");
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
} catch (error) {
|
|
252
|
+
if (error instanceof DataError) throw error;
|
|
253
|
+
throw DataError.networkError(pool.chainId, error instanceof Error ? error : new Error(String(error)));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private getClientForChain(chainId: number): PublicClient {
|
|
258
|
+
const client = this.clients.get(chainId);
|
|
259
|
+
if (!client) {
|
|
260
|
+
throw DataError.chainNotConfigured(chainId);
|
|
261
|
+
}
|
|
262
|
+
return client;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private getConfigForChain(chainId: number): ChainConfig {
|
|
266
|
+
const config = this.chainConfigs.find(c => c.chainId === chainId);
|
|
267
|
+
if (!config) {
|
|
268
|
+
throw DataError.chainNotConfigured(chainId);
|
|
269
|
+
}
|
|
270
|
+
return config;
|
|
271
|
+
}
|
|
272
|
+
}
|
package/src/core/sdk.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
import { AccountCommitment } from "../types/account.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Main SDK class providing access to all privacy pool functionality.
|
|
12
|
+
* Uses Poseidon hash for all commitment operations.
|
|
13
|
+
*/
|
|
14
|
+
export class PrivacyPoolSDK {
|
|
15
|
+
private readonly commitmentService: CommitmentService;
|
|
16
|
+
private readonly withdrawalService: WithdrawalService;
|
|
17
|
+
|
|
18
|
+
constructor(circuits: CircuitsInterface) {
|
|
19
|
+
this.commitmentService = new CommitmentService(circuits);
|
|
20
|
+
this.withdrawalService = new WithdrawalService(circuits);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public createContractInstance(
|
|
24
|
+
rpcUrl: string,
|
|
25
|
+
chain: Chain,
|
|
26
|
+
entrypointAddress: Address,
|
|
27
|
+
privateKey: Hex,
|
|
28
|
+
): ContractInteractionsService {
|
|
29
|
+
return new ContractInteractionsService(
|
|
30
|
+
rpcUrl,
|
|
31
|
+
chain,
|
|
32
|
+
entrypointAddress,
|
|
33
|
+
privateKey,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Generates a commitment proof.
|
|
39
|
+
*
|
|
40
|
+
* @param value - Value to commit
|
|
41
|
+
* @param label - Label for the commitment
|
|
42
|
+
* @param nullifier - Nullifier for the commitment
|
|
43
|
+
* @param secret - Secret for the commitment
|
|
44
|
+
*/
|
|
45
|
+
public async proveCommitment(
|
|
46
|
+
value: bigint,
|
|
47
|
+
label: bigint,
|
|
48
|
+
nullifier: bigint,
|
|
49
|
+
secret: bigint,
|
|
50
|
+
): Promise<CommitmentProof> {
|
|
51
|
+
return this.commitmentService.proveCommitment(
|
|
52
|
+
value,
|
|
53
|
+
label,
|
|
54
|
+
nullifier,
|
|
55
|
+
secret,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Verifies a commitment proof.
|
|
61
|
+
*
|
|
62
|
+
* @param proof - The proof to verify
|
|
63
|
+
*/
|
|
64
|
+
public async verifyCommitment(proof: CommitmentProof): Promise<boolean> {
|
|
65
|
+
return this.commitmentService.verifyCommitment(proof);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Generates a withdrawal proof.
|
|
70
|
+
*
|
|
71
|
+
* @param commitment - Commitment to withdraw
|
|
72
|
+
* @param input - Input parameters for the withdrawal
|
|
73
|
+
* @param withdrawal - Withdrawal details
|
|
74
|
+
*/
|
|
75
|
+
public async proveWithdrawal(
|
|
76
|
+
commitment: Commitment | AccountCommitment ,
|
|
77
|
+
input: WithdrawalProofInput,
|
|
78
|
+
): Promise<WithdrawalProof> {
|
|
79
|
+
return await this.withdrawalService.proveWithdrawal(commitment, input);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Verifies a withdrawal proof.
|
|
84
|
+
*
|
|
85
|
+
* @param withdrawalProof - The withdrawal payload to verify
|
|
86
|
+
*/
|
|
87
|
+
public async verifyWithdrawal(
|
|
88
|
+
withdrawalProof: WithdrawalProof,
|
|
89
|
+
): Promise<boolean> {
|
|
90
|
+
return this.withdrawalService.verifyWithdrawal(withdrawalProof);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
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 { WithdrawalProof, WithdrawalProofInput } from "../types/withdrawal.js";
|
|
8
|
+
import { AccountCommitment, Commitment } from "../index.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 | AccountCommitment,
|
|
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 | AccountCommitment,
|
|
84
|
+
input: WithdrawalProofInput
|
|
85
|
+
): Record<string, bigint | bigint[] | string> {
|
|
86
|
+
let existingValue: bigint;
|
|
87
|
+
let existingNullifier: bigint;
|
|
88
|
+
let existingSecret: bigint;
|
|
89
|
+
let label: bigint;
|
|
90
|
+
if ("preimage" in commitment) {
|
|
91
|
+
existingValue = commitment.preimage.value;
|
|
92
|
+
existingNullifier = commitment.preimage.precommitment.nullifier;
|
|
93
|
+
existingSecret = commitment.preimage.precommitment.secret;
|
|
94
|
+
label = commitment.preimage.label;
|
|
95
|
+
} else {
|
|
96
|
+
existingValue = commitment.value;
|
|
97
|
+
existingNullifier = commitment.nullifier;
|
|
98
|
+
existingSecret = commitment.secret;
|
|
99
|
+
label = commitment.label;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
// Public signals
|
|
104
|
+
withdrawnValue: input.withdrawalAmount,
|
|
105
|
+
stateRoot: input.stateRoot,
|
|
106
|
+
stateTreeDepth: input.stateTreeDepth,
|
|
107
|
+
ASPRoot: input.aspRoot,
|
|
108
|
+
ASPTreeDepth: input.aspTreeDepth,
|
|
109
|
+
context: input.context,
|
|
110
|
+
|
|
111
|
+
// Private signals
|
|
112
|
+
label,
|
|
113
|
+
existingValue,
|
|
114
|
+
existingNullifier,
|
|
115
|
+
existingSecret,
|
|
116
|
+
newNullifier: input.newNullifier,
|
|
117
|
+
newSecret: input.newSecret,
|
|
118
|
+
|
|
119
|
+
// Merkle Proofs
|
|
120
|
+
stateSiblings: input.stateMerkleProof.siblings,
|
|
121
|
+
stateIndex: BigInt(input.stateMerkleProof.index),
|
|
122
|
+
ASPSiblings: input.aspMerkleProof.siblings,
|
|
123
|
+
ASPIndex: BigInt(input.aspMerkleProof.index),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|