naracli 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/src/swap.ts ADDED
@@ -0,0 +1,608 @@
1
+ import { PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
2
+ import BN from "bn.js";
3
+ import { NaraSDK } from "./client";
4
+ import {
5
+ deriveDammV2PoolAddress,
6
+ DAMM_V2_MIGRATION_FEE_ADDRESS,
7
+ } from "@meteora-ag/dynamic-bonding-curve-sdk";
8
+ import { NATIVE_MINT, TOKEN_PROGRAM_ID } from "@solana/spl-token";
9
+ import {
10
+ CpAmm,
11
+ SwapMode as CpAmmSwapMode,
12
+ getCurrentPoint,
13
+ ActivationType,
14
+ } from "@meteora-ag/cp-amm-sdk";
15
+
16
+ /**
17
+ * Swap mode enum
18
+ * - ExactIn: Exact input mode
19
+ * - PartialFill: Partial fill mode (recommended, can precisely fill the pool)
20
+ * - ExactOut: Exact output mode
21
+ */
22
+ export enum SwapMode {
23
+ ExactIn = 0,
24
+ PartialFill = 1,
25
+ ExactOut = 2,
26
+ }
27
+
28
+ export interface SwapQuoteResponse {
29
+ amountIn: string;
30
+ outputAmount: string;
31
+ minimumAmountOut: string;
32
+ nextSqrtPrice: string;
33
+ tradingFee: string;
34
+ protocolFee: string;
35
+ referralFee: string;
36
+ }
37
+
38
+ /**
39
+ * Check if pool has migrated to DAMM V2 and return relevant information
40
+ */
41
+ async function checkPoolMigration(
42
+ sdk: NaraSDK,
43
+ tokenAddress: string
44
+ ): Promise<{
45
+ isMigrated: boolean;
46
+ dammV2Pool?: PublicKey;
47
+ dammConfig?: PublicKey;
48
+ }> {
49
+ const client = sdk.getClient();
50
+ const tokenPubkey = new PublicKey(tokenAddress);
51
+
52
+ const poolAccount = await client.state.getPoolByBaseMint(tokenPubkey);
53
+ if (!poolAccount) {
54
+ throw new Error(`Pool not found for token: ${tokenAddress}`);
55
+ }
56
+
57
+ // Check if already migrated
58
+ if (poolAccount.account.isMigrated) {
59
+ // Get DAMM config
60
+ const virtualPool = poolAccount.account;
61
+ const poolConfig = await client.state.getPoolConfig(virtualPool.config);
62
+ const migrationFeeOption = (poolConfig as any).migrationFeeOption || 0;
63
+
64
+ // Get correct config address from array
65
+ const dammConfig = DAMM_V2_MIGRATION_FEE_ADDRESS[migrationFeeOption];
66
+
67
+ if (!dammConfig) {
68
+ throw new Error(
69
+ `Invalid migration fee option: ${migrationFeeOption}. Cannot determine DAMM V2 config address.`
70
+ );
71
+ }
72
+
73
+ // Derive DAMM V2 pool address
74
+ const dammV2Pool = deriveDammV2PoolAddress(
75
+ dammConfig,
76
+ NATIVE_MINT, // tokenA = SOL
77
+ tokenPubkey // tokenB = token
78
+ );
79
+
80
+ // Verify pool account actually exists
81
+ const connection = sdk.getConnection();
82
+ const poolAccountInfo = await connection.getAccountInfo(dammV2Pool);
83
+
84
+ if (!poolAccountInfo) {
85
+ // Pool marked as migrated but account doesn't exist, migration not yet complete
86
+ return { isMigrated: false };
87
+ }
88
+
89
+ return {
90
+ isMigrated: true,
91
+ dammV2Pool,
92
+ dammConfig,
93
+ };
94
+ }
95
+
96
+ return { isMigrated: false };
97
+ }
98
+
99
+ /**
100
+ * Get swap quote
101
+ * @param sdk NaraSDK SDK instance
102
+ * @param tokenAddress Token address (baseMint)
103
+ * @param amountIn Input amount
104
+ * @param swapBaseForQuote true=sell token for SOL, false=buy token with SOL
105
+ * @param slippageBps Slippage in basis points (default 100 = 1%)
106
+ * @returns Swap quote information
107
+ */
108
+ export async function getSwapQuote(
109
+ sdk: NaraSDK,
110
+ tokenAddress: string,
111
+ amountIn: BN,
112
+ swapBaseForQuote: boolean,
113
+ slippageBps: number = 100
114
+ ): Promise<SwapQuoteResponse> {
115
+ const client = sdk.getClient();
116
+ const tokenPubkey = new PublicKey(tokenAddress);
117
+
118
+ // Get pool by token (baseMint) address
119
+ const poolAccount = await client.state.getPoolByBaseMint(tokenPubkey);
120
+ if (!poolAccount) {
121
+ throw new Error(`Pool not found for token: ${tokenAddress}`);
122
+ }
123
+
124
+ const virtualPool = poolAccount.account;
125
+ const poolConfig = await client.state.getPoolConfig(virtualPool.config);
126
+
127
+ const quote = client.pool.swapQuote({
128
+ virtualPool,
129
+ config: poolConfig,
130
+ swapBaseForQuote,
131
+ amountIn,
132
+ slippageBps,
133
+ hasReferral: false,
134
+ eligibleForFirstSwapWithMinFee: false,
135
+ currentPoint: new BN(0),
136
+ });
137
+
138
+ // Cast to any to access IDL-derived properties that exist at runtime
139
+ const quoteResult = quote as any;
140
+
141
+ return {
142
+ amountIn: amountIn.toString(),
143
+ outputAmount: quoteResult.outputAmount.toString(),
144
+ minimumAmountOut: quote.minimumAmountOut.toString(),
145
+ nextSqrtPrice: quoteResult.nextSqrtPrice.toString(),
146
+ tradingFee: quoteResult.tradingFee.toString(),
147
+ protocolFee: quoteResult.protocolFee.toString(),
148
+ referralFee: quoteResult.referralFee.toString(),
149
+ };
150
+ }
151
+
152
+ export interface BuyTokenParams {
153
+ tokenAddress: string;
154
+ amountInSOL: number;
155
+ owner: PublicKey;
156
+ slippageBps?: number;
157
+ /** Swap mode, defaults to PartialFill (recommended) */
158
+ swapMode?: SwapMode;
159
+ }
160
+
161
+ export interface BuyTokenResult {
162
+ /** Unsigned transaction (returns VersionedTransaction if ALT is configured) */
163
+ transaction: Transaction | VersionedTransaction;
164
+ /** Input amount in lamports */
165
+ amountIn: string;
166
+ /** Expected output amount */
167
+ expectedAmountOut: string;
168
+ /** Minimum output amount */
169
+ minimumAmountOut: string;
170
+ }
171
+
172
+ /**
173
+ * Create buy token transaction (returns unsigned transaction)
174
+ * @param sdk NaraSDK SDK instance
175
+ * @param params Buy parameters
176
+ * @returns Unsigned transaction and related information
177
+ */
178
+ export async function buyToken(
179
+ sdk: NaraSDK,
180
+ params: BuyTokenParams
181
+ ): Promise<BuyTokenResult> {
182
+ const client = sdk.getClient();
183
+ const connection = sdk.getConnection();
184
+
185
+ const tokenPubkey = new PublicKey(params.tokenAddress);
186
+ const amountIn = new BN(params.amountInSOL * 1e9); // Convert SOL to lamports
187
+ const slippageBps = params.slippageBps ?? 100;
188
+ const swapMode = params.swapMode ?? SwapMode.PartialFill; // Default to PartialFill mode
189
+
190
+ // Check if pool has migrated to DAMM V2
191
+ const migrationInfo = await checkPoolMigration(sdk, params.tokenAddress);
192
+
193
+ if (migrationInfo.isMigrated && migrationInfo.dammV2Pool) {
194
+ console.log("🚀 Pool launched to DAMM V2, using CP-AMM for swap");
195
+
196
+ // Use CP-AMM SDK for swap
197
+ const cpAmm = new CpAmm(connection);
198
+
199
+ // Get pool state
200
+ const poolState = await cpAmm.fetchPoolState(migrationInfo.dammV2Pool);
201
+
202
+ // Get current point (based on pool's activation type)
203
+ const currentPoint = await getCurrentPoint(
204
+ connection,
205
+ poolState.activationType as ActivationType
206
+ );
207
+
208
+ // Determine input/output tokens (SOL = tokenA, Token = tokenB)
209
+ const isAToB = poolState.tokenAMint.equals(NATIVE_MINT);
210
+ const inputTokenMint = isAToB ? poolState.tokenAMint : poolState.tokenBMint;
211
+
212
+ // Convert SwapMode
213
+ const cpAmmSwapMode =
214
+ swapMode === SwapMode.PartialFill
215
+ ? CpAmmSwapMode.PartialFill
216
+ : swapMode === SwapMode.ExactOut
217
+ ? CpAmmSwapMode.ExactOut
218
+ : CpAmmSwapMode.ExactIn;
219
+
220
+ // Build quote parameters
221
+ const quoteBaseParams = {
222
+ inputTokenMint,
223
+ slippage: slippageBps / 10000,
224
+ currentPoint,
225
+ poolState,
226
+ tokenADecimal: 9, // SOL decimals
227
+ tokenBDecimal: 6, // Token decimals (assumed)
228
+ hasReferral: false,
229
+ };
230
+
231
+ // Calculate quote
232
+ let quote: any;
233
+ if (cpAmmSwapMode === CpAmmSwapMode.ExactOut) {
234
+ quote = cpAmm.getQuote2({
235
+ ...quoteBaseParams,
236
+ swapMode: cpAmmSwapMode,
237
+ amountOut: amountIn, // ExactOut: desired output amount
238
+ });
239
+ } else {
240
+ quote = cpAmm.getQuote2({
241
+ ...quoteBaseParams,
242
+ swapMode: cpAmmSwapMode,
243
+ amountIn,
244
+ });
245
+ }
246
+
247
+ // Build swap parameters
248
+ const swapBaseParams = {
249
+ payer: params.owner,
250
+ pool: migrationInfo.dammV2Pool,
251
+ inputTokenMint,
252
+ outputTokenMint: isAToB ? poolState.tokenBMint : poolState.tokenAMint,
253
+ tokenAMint: poolState.tokenAMint,
254
+ tokenBMint: poolState.tokenBMint,
255
+ tokenAVault: poolState.tokenAVault,
256
+ tokenBVault: poolState.tokenBVault,
257
+ tokenAProgram: TOKEN_PROGRAM_ID,
258
+ tokenBProgram: TOKEN_PROGRAM_ID,
259
+ referralTokenAccount: null,
260
+ poolState,
261
+ };
262
+
263
+ // Create transaction (TxBuilder returns Promise<Transaction>)
264
+ let transaction: Transaction;
265
+ if (cpAmmSwapMode === CpAmmSwapMode.ExactOut) {
266
+ transaction = await cpAmm.swap2({
267
+ ...swapBaseParams,
268
+ swapMode: cpAmmSwapMode,
269
+ amountOut: amountIn,
270
+ maximumAmountIn: quote.maxSwapInAmount || amountIn.muln(2), // 2x as max
271
+ });
272
+ } else {
273
+ transaction = await cpAmm.swap2({
274
+ ...swapBaseParams,
275
+ swapMode: cpAmmSwapMode,
276
+ amountIn,
277
+ minimumAmountOut: quote.minSwapOutAmount || new BN(0),
278
+ });
279
+ }
280
+
281
+ // Compile transaction with ALT if configured
282
+ const compiledTx = await sdk.compileTransactionWithALT(
283
+ transaction,
284
+ params.owner
285
+ );
286
+
287
+ return {
288
+ transaction: compiledTx,
289
+ amountIn: quote.swapInAmount?.toString() || amountIn.toString(),
290
+ expectedAmountOut: quote.swapOutAmount?.toString() || "0",
291
+ minimumAmountOut: quote.minSwapOutAmount?.toString() || "0",
292
+ };
293
+ }
294
+
295
+ // Not migrated, use DBC swap
296
+ const poolAccount = await client.state.getPoolByBaseMint(tokenPubkey);
297
+ if (!poolAccount) {
298
+ throw new Error(`Pool not found for token: ${params.tokenAddress}`);
299
+ }
300
+
301
+ // Get quote first for minimumAmountOut
302
+ // In PartialFill mode, continue even if insufficient liquidity
303
+ let quote: SwapQuoteResponse;
304
+ try {
305
+ quote = await getSwapQuote(
306
+ sdk,
307
+ params.tokenAddress,
308
+ amountIn,
309
+ false,
310
+ slippageBps
311
+ );
312
+ } catch (err: any) {
313
+ if (swapMode === SwapMode.PartialFill && err.message?.includes("Insufficient Liquidity")) {
314
+ // PartialFill mode: set minimumAmountOut to 0 when insufficient liquidity
315
+ console.warn("⚠️ Insufficient liquidity, using PartialFill mode to accept any available amount");
316
+ quote = {
317
+ amountIn: amountIn.toString(),
318
+ outputAmount: "0",
319
+ minimumAmountOut: "0",
320
+ nextSqrtPrice: "0",
321
+ tradingFee: "0",
322
+ protocolFee: "0",
323
+ referralFee: "0",
324
+ };
325
+ } else {
326
+ throw err;
327
+ }
328
+ }
329
+
330
+ // Use swap2 method to support different swap modes
331
+ let transaction: Transaction;
332
+
333
+ if (swapMode === SwapMode.PartialFill) {
334
+ transaction = await client.pool.swap2({
335
+ owner: params.owner,
336
+ pool: poolAccount.publicKey,
337
+ swapBaseForQuote: false,
338
+ referralTokenAccount: null,
339
+ swapMode: SwapMode.PartialFill,
340
+ amountIn,
341
+ minimumAmountOut: new BN(quote.minimumAmountOut),
342
+ });
343
+ } else if (swapMode === SwapMode.ExactOut) {
344
+ transaction = await client.pool.swap2({
345
+ owner: params.owner,
346
+ pool: poolAccount.publicKey,
347
+ swapBaseForQuote: false,
348
+ referralTokenAccount: null,
349
+ swapMode: SwapMode.ExactOut,
350
+ amountOut: new BN(quote.outputAmount),
351
+ maximumAmountIn: amountIn,
352
+ });
353
+ } else {
354
+ // SwapMode.ExactIn
355
+ transaction = await client.pool.swap2({
356
+ owner: params.owner,
357
+ pool: poolAccount.publicKey,
358
+ swapBaseForQuote: false,
359
+ referralTokenAccount: null,
360
+ swapMode: SwapMode.ExactIn,
361
+ amountIn,
362
+ minimumAmountOut: new BN(quote.minimumAmountOut),
363
+ });
364
+ }
365
+
366
+ // Compile transaction with ALT if configured
367
+ const compiledTx = await sdk.compileTransactionWithALT(
368
+ transaction,
369
+ params.owner
370
+ );
371
+
372
+ return {
373
+ transaction: compiledTx,
374
+ amountIn: amountIn.toString(),
375
+ expectedAmountOut: quote.outputAmount,
376
+ minimumAmountOut: quote.minimumAmountOut,
377
+ };
378
+ }
379
+
380
+ export interface SellTokenParams {
381
+ tokenAddress: string;
382
+ amountInToken: number;
383
+ owner: PublicKey;
384
+ tokenDecimals?: number;
385
+ slippageBps?: number;
386
+ /** Swap mode, defaults to PartialFill (recommended) */
387
+ swapMode?: SwapMode;
388
+ }
389
+
390
+ export interface SellTokenResult {
391
+ /** Unsigned transaction (returns VersionedTransaction if ALT is configured) */
392
+ transaction: Transaction | VersionedTransaction;
393
+ /** Input amount in token's smallest unit */
394
+ amountIn: string;
395
+ /** Expected output amount in lamports */
396
+ expectedAmountOut: string;
397
+ /** Minimum output amount in lamports */
398
+ minimumAmountOut: string;
399
+ }
400
+
401
+ /**
402
+ * Create sell token transaction (returns unsigned transaction)
403
+ * @param sdk NaraSDK SDK instance
404
+ * @param params Sell parameters
405
+ * @returns Unsigned transaction and related information
406
+ */
407
+ export async function sellToken(
408
+ sdk: NaraSDK,
409
+ params: SellTokenParams
410
+ ): Promise<SellTokenResult> {
411
+ const client = sdk.getClient();
412
+ const connection = sdk.getConnection();
413
+
414
+ const tokenPubkey = new PublicKey(params.tokenAddress);
415
+ const tokenDecimals = params.tokenDecimals ?? 6;
416
+ const amountIn = new BN(params.amountInToken * 10 ** tokenDecimals);
417
+ const slippageBps = params.slippageBps ?? 100;
418
+ const swapMode = params.swapMode ?? SwapMode.PartialFill; // Default to PartialFill mode
419
+
420
+ // Check if pool has migrated to DAMM V2
421
+ const migrationInfo = await checkPoolMigration(sdk, params.tokenAddress);
422
+
423
+ if (migrationInfo.isMigrated && migrationInfo.dammV2Pool) {
424
+ console.log("🚀 Pool launched to DAMM V2, using CP-AMM for swap");
425
+
426
+ // Use CP-AMM SDK for swap
427
+ const cpAmm = new CpAmm(connection);
428
+
429
+ // Get pool state
430
+ const poolState = await cpAmm.fetchPoolState(migrationInfo.dammV2Pool);
431
+
432
+ // Get current point (based on pool's activation type)
433
+ const currentPoint = await getCurrentPoint(
434
+ connection,
435
+ poolState.activationType as ActivationType
436
+ );
437
+
438
+ // Determine input/output tokens (Token = tokenB, SOL = tokenA)
439
+ const isAToB = poolState.tokenAMint.equals(tokenPubkey); // If token is A, then A->B (Token->SOL)
440
+ const inputTokenMint = isAToB ? poolState.tokenAMint : poolState.tokenBMint;
441
+
442
+ // Convert SwapMode
443
+ const cpAmmSwapMode =
444
+ swapMode === SwapMode.PartialFill
445
+ ? CpAmmSwapMode.PartialFill
446
+ : swapMode === SwapMode.ExactOut
447
+ ? CpAmmSwapMode.ExactOut
448
+ : CpAmmSwapMode.ExactIn;
449
+
450
+ // 构建报价参数
451
+ const quoteBaseParams = {
452
+ inputTokenMint,
453
+ slippage: slippageBps / 10000,
454
+ currentPoint,
455
+ poolState,
456
+ tokenADecimal: 9, // SOL decimals
457
+ tokenBDecimal: tokenDecimals,
458
+ hasReferral: false,
459
+ };
460
+
461
+ // Calculate quote
462
+ let quote: any;
463
+ if (cpAmmSwapMode === CpAmmSwapMode.ExactOut) {
464
+ quote = cpAmm.getQuote2({
465
+ ...quoteBaseParams,
466
+ swapMode: cpAmmSwapMode,
467
+ amountOut: amountIn, // ExactOut: desired output amount
468
+ });
469
+ } else {
470
+ quote = cpAmm.getQuote2({
471
+ ...quoteBaseParams,
472
+ swapMode: cpAmmSwapMode,
473
+ amountIn,
474
+ });
475
+ }
476
+
477
+ // Build swap parameters
478
+ const swapBaseParams = {
479
+ payer: params.owner,
480
+ pool: migrationInfo.dammV2Pool,
481
+ inputTokenMint,
482
+ outputTokenMint: isAToB ? poolState.tokenBMint : poolState.tokenAMint,
483
+ tokenAMint: poolState.tokenAMint,
484
+ tokenBMint: poolState.tokenBMint,
485
+ tokenAVault: poolState.tokenAVault,
486
+ tokenBVault: poolState.tokenBVault,
487
+ tokenAProgram: TOKEN_PROGRAM_ID,
488
+ tokenBProgram: TOKEN_PROGRAM_ID,
489
+ referralTokenAccount: null,
490
+ poolState,
491
+ };
492
+
493
+ // Create transaction
494
+ let transaction: Transaction;
495
+ if (cpAmmSwapMode === CpAmmSwapMode.ExactOut) {
496
+ transaction = await cpAmm.swap2({
497
+ ...swapBaseParams,
498
+ swapMode: cpAmmSwapMode,
499
+ amountOut: amountIn,
500
+ maximumAmountIn: quote.maxSwapInAmount || amountIn.muln(2),
501
+ });
502
+ } else {
503
+ transaction = await cpAmm.swap2({
504
+ ...swapBaseParams,
505
+ swapMode: cpAmmSwapMode,
506
+ amountIn,
507
+ minimumAmountOut: quote.minSwapOutAmount || new BN(0),
508
+ });
509
+ }
510
+
511
+ // Compile transaction with ALT if configured
512
+ const compiledTx = await sdk.compileTransactionWithALT(
513
+ transaction,
514
+ params.owner
515
+ );
516
+
517
+ return {
518
+ transaction: compiledTx,
519
+ amountIn: quote.swapInAmount?.toString() || amountIn.toString(),
520
+ expectedAmountOut: quote.swapOutAmount?.toString() || "0",
521
+ minimumAmountOut: quote.minSwapOutAmount?.toString() || "0",
522
+ };
523
+ }
524
+
525
+ // Not migrated, use DBC swap
526
+ const poolAccount = await client.state.getPoolByBaseMint(tokenPubkey);
527
+ if (!poolAccount) {
528
+ throw new Error(`Pool not found for token: ${params.tokenAddress}`);
529
+ }
530
+
531
+ // Get quote first for minimumAmountOut
532
+ // In PartialFill mode, continue even if insufficient liquidity
533
+ let quote: SwapQuoteResponse;
534
+ try {
535
+ quote = await getSwapQuote(
536
+ sdk,
537
+ params.tokenAddress,
538
+ amountIn,
539
+ true,
540
+ slippageBps
541
+ );
542
+ } catch (err: any) {
543
+ if (swapMode === SwapMode.PartialFill && err.message?.includes("Insufficient Liquidity")) {
544
+ // PartialFill mode: set minimumAmountOut to 0 when insufficient liquidity
545
+ console.warn("⚠️ Insufficient liquidity, using PartialFill mode to accept any available amount");
546
+ quote = {
547
+ amountIn: amountIn.toString(),
548
+ outputAmount: "0",
549
+ minimumAmountOut: "0",
550
+ nextSqrtPrice: "0",
551
+ tradingFee: "0",
552
+ protocolFee: "0",
553
+ referralFee: "0",
554
+ };
555
+ } else {
556
+ throw err;
557
+ }
558
+ }
559
+
560
+ // Use swap2 method to support different swap modes
561
+ let transaction: Transaction;
562
+
563
+ if (swapMode === SwapMode.PartialFill) {
564
+ transaction = await client.pool.swap2({
565
+ owner: params.owner,
566
+ pool: poolAccount.publicKey,
567
+ swapBaseForQuote: true, // Token -> SOL (sell)
568
+ referralTokenAccount: null,
569
+ swapMode: SwapMode.PartialFill,
570
+ amountIn,
571
+ minimumAmountOut: new BN(quote.minimumAmountOut),
572
+ });
573
+ } else if (swapMode === SwapMode.ExactOut) {
574
+ transaction = await client.pool.swap2({
575
+ owner: params.owner,
576
+ pool: poolAccount.publicKey,
577
+ swapBaseForQuote: true,
578
+ referralTokenAccount: null,
579
+ swapMode: SwapMode.ExactOut,
580
+ amountOut: new BN(quote.outputAmount),
581
+ maximumAmountIn: amountIn,
582
+ });
583
+ } else {
584
+ // SwapMode.ExactIn
585
+ transaction = await client.pool.swap2({
586
+ owner: params.owner,
587
+ pool: poolAccount.publicKey,
588
+ swapBaseForQuote: true,
589
+ referralTokenAccount: null,
590
+ swapMode: SwapMode.ExactIn,
591
+ amountIn,
592
+ minimumAmountOut: new BN(quote.minimumAmountOut),
593
+ });
594
+ }
595
+
596
+ // Compile transaction with ALT if configured
597
+ const compiledTx = await sdk.compileTransactionWithALT(
598
+ transaction,
599
+ params.owner
600
+ );
601
+
602
+ return {
603
+ transaction: compiledTx,
604
+ amountIn: amountIn.toString(),
605
+ expectedAmountOut: quote.outputAmount,
606
+ minimumAmountOut: quote.minimumAmountOut,
607
+ };
608
+ }
@@ -0,0 +1,9 @@
1
+ declare module "snarkjs" {
2
+ export const groth16: {
3
+ fullProve(
4
+ input: Record<string, string>,
5
+ wasmPath: string,
6
+ zkeyPath: string
7
+ ): Promise<{ proof: any; publicSignals: string[] }>;
8
+ };
9
+ }