@lightprotocol/stateless.js 0.1.0-alpha.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.
Files changed (44) hide show
  1. package/README.md +58 -0
  2. package/dist/cjs/index.cjs +4031 -0
  3. package/dist/es/index.js +3988 -0
  4. package/dist/types/actions/common.d.ts +3 -0
  5. package/dist/types/actions/compress-lamports.d.ts +16 -0
  6. package/dist/types/actions/decompress-lamports.d.ts +16 -0
  7. package/dist/types/actions/index.d.ts +4 -0
  8. package/dist/types/actions/init-sol-omnibus-account.d.ts +13 -0
  9. package/dist/types/constants.d.ts +34 -0
  10. package/dist/types/errors.d.ts +74 -0
  11. package/dist/types/idls/account_compression.d.ts +932 -0
  12. package/dist/types/idls/index.d.ts +5 -0
  13. package/dist/types/idls/light.d.ts +192 -0
  14. package/dist/types/idls/psp_compressed_pda.d.ts +607 -0
  15. package/dist/types/idls/user_registry.d.ts +69 -0
  16. package/dist/types/index.d.ts +12 -0
  17. package/dist/types/instruction/index.d.ts +1 -0
  18. package/dist/types/instruction/pack-compressed-accounts.d.ts +30 -0
  19. package/dist/types/programs/compressed-pda.d.ts +148 -0
  20. package/dist/types/programs/index.d.ts +1 -0
  21. package/dist/types/rpc-interface.d.ts +430 -0
  22. package/dist/types/rpc.d.ts +26 -0
  23. package/dist/types/state/BN254.d.ts +20 -0
  24. package/dist/types/state/compressed-account.d.ts +35 -0
  25. package/dist/types/state/index.d.ts +3 -0
  26. package/dist/types/state/types.d.ts +108 -0
  27. package/dist/types/test-utils/common.d.ts +32 -0
  28. package/dist/types/test-utils/index.d.ts +5 -0
  29. package/dist/types/test-utils/merkle-tree.d.ts +92 -0
  30. package/dist/types/test-utils/parse-event.d.ts +7 -0
  31. package/dist/types/test-utils/parse-validity-proof.d.ts +20 -0
  32. package/dist/types/test-utils/test-rpc.d.ts +51 -0
  33. package/dist/types/utils/airdrop.d.ts +7 -0
  34. package/dist/types/utils/conversion.d.ts +10 -0
  35. package/dist/types/utils/index.d.ts +6 -0
  36. package/dist/types/utils/pipe.d.ts +2 -0
  37. package/dist/types/utils/send-and-confirm.d.ts +18 -0
  38. package/dist/types/utils/sleep.d.ts +1 -0
  39. package/dist/types/utils/validation.d.ts +4 -0
  40. package/dist/types/wallet/index.d.ts +1 -0
  41. package/dist/types/wallet/interface.d.ts +25 -0
  42. package/dist/types/wallet/use-wallet.d.ts +9 -0
  43. package/dist/umd/index.js +4027 -0
  44. package/package.json +81 -0
@@ -0,0 +1,3988 @@
1
+ import { BN, AnchorProvider, setProvider, Program } from '@coral-xyz/anchor';
2
+ import { Connection, sendAndConfirmTransaction, PublicKey, Keypair, TransactionMessage, VersionedTransaction, SolanaJSONRPCError, ComputeBudgetProgram, SystemProgram } from '@solana/web3.js';
3
+ import { sign } from 'tweetnacl';
4
+ import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
5
+ import { Buffer as Buffer$1 } from 'buffer';
6
+ import { keccak_256 } from '@noble/hashes/sha3';
7
+ import { WasmFactory } from '@lightprotocol/hasher.rs';
8
+ import axios from 'axios';
9
+ import { coerce, instance, string, number, nullable, unknown, type, boolean, array, union, literal, any, create } from 'superstruct';
10
+
11
+ const IDL$3 = {
12
+ version: '0.3.0',
13
+ name: 'psp_compressed_pda',
14
+ constants: [
15
+ {
16
+ name: 'COMPRESSED_SOL_PDA_SEED',
17
+ type: 'bytes',
18
+ value: '[99, 111, 109, 112, 114, 101, 115, 115, 101, 100, 95, 115, 111, 108, 95, 112, 100, 97]',
19
+ },
20
+ ],
21
+ instructions: [
22
+ {
23
+ name: 'initCompressSolPda',
24
+ docs: [
25
+ 'Initializes the compressed sol pda.',
26
+ 'This pda is used to store compressed sol for the protocol.',
27
+ ],
28
+ accounts: [
29
+ {
30
+ name: 'feePayer',
31
+ isMut: true,
32
+ isSigner: true,
33
+ },
34
+ {
35
+ name: 'compressedSolPda',
36
+ isMut: true,
37
+ isSigner: false,
38
+ },
39
+ {
40
+ name: 'systemProgram',
41
+ isMut: false,
42
+ isSigner: false,
43
+ },
44
+ ],
45
+ args: [],
46
+ },
47
+ {
48
+ name: 'executeCompressedTransaction',
49
+ docs: [
50
+ 'This function can be used to transfer sol and execute any other compressed transaction.',
51
+ 'Instruction data is not optimized for space.',
52
+ 'This method can be called by cpi so that instruction data can be compressed with a custom algorithm.',
53
+ ],
54
+ accounts: [
55
+ {
56
+ name: 'signer',
57
+ isMut: false,
58
+ isSigner: true,
59
+ },
60
+ {
61
+ name: 'registeredProgramPda',
62
+ isMut: false,
63
+ isSigner: false,
64
+ },
65
+ {
66
+ name: 'noopProgram',
67
+ isMut: false,
68
+ isSigner: false,
69
+ },
70
+ {
71
+ name: 'pspAccountCompressionAuthority',
72
+ isMut: true,
73
+ isSigner: false,
74
+ },
75
+ {
76
+ name: 'accountCompressionProgram',
77
+ isMut: false,
78
+ isSigner: false,
79
+ },
80
+ {
81
+ name: 'cpiSignatureAccount',
82
+ isMut: false,
83
+ isSigner: false,
84
+ isOptional: true,
85
+ },
86
+ {
87
+ name: 'invokingProgram',
88
+ isMut: false,
89
+ isSigner: false,
90
+ isOptional: true,
91
+ },
92
+ {
93
+ name: 'compressedSolPda',
94
+ isMut: true,
95
+ isSigner: false,
96
+ isOptional: true,
97
+ },
98
+ {
99
+ name: 'compressionRecipient',
100
+ isMut: true,
101
+ isSigner: false,
102
+ isOptional: true,
103
+ },
104
+ {
105
+ name: 'systemProgram',
106
+ isMut: false,
107
+ isSigner: false,
108
+ isOptional: true,
109
+ },
110
+ ],
111
+ args: [
112
+ {
113
+ name: 'inputs',
114
+ type: 'bytes',
115
+ },
116
+ ],
117
+ returns: {
118
+ defined: 'crate::event::PublicTransactionEvent',
119
+ },
120
+ },
121
+ ],
122
+ accounts: [
123
+ {
124
+ name: 'cpiSignatureAccount',
125
+ docs: [
126
+ 'collects invocations without proofs',
127
+ 'invocations are collected and processed when an invocation with a proof is received',
128
+ ],
129
+ type: {
130
+ kind: 'struct',
131
+ fields: [
132
+ {
133
+ name: 'slot',
134
+ type: 'u64',
135
+ },
136
+ {
137
+ name: 'signatures',
138
+ type: {
139
+ vec: {
140
+ defined: 'InstructionDataTransfer',
141
+ },
142
+ },
143
+ },
144
+ ],
145
+ },
146
+ },
147
+ {
148
+ name: 'compressedSolPda',
149
+ type: {
150
+ kind: 'struct',
151
+ fields: [],
152
+ },
153
+ },
154
+ ],
155
+ types: [
156
+ {
157
+ name: 'CompressedAccountWithMerkleContext',
158
+ type: {
159
+ kind: 'struct',
160
+ fields: [
161
+ {
162
+ name: 'compressedAccount',
163
+ type: {
164
+ defined: 'CompressedAccount',
165
+ },
166
+ },
167
+ {
168
+ name: 'merkleTreePubkeyIndex',
169
+ type: 'u8',
170
+ },
171
+ {
172
+ name: 'nullifierQueuePubkeyIndex',
173
+ type: 'u8',
174
+ },
175
+ {
176
+ name: 'leafIndex',
177
+ type: 'u32',
178
+ },
179
+ ],
180
+ },
181
+ },
182
+ {
183
+ name: 'CompressedAccount',
184
+ type: {
185
+ kind: 'struct',
186
+ fields: [
187
+ {
188
+ name: 'owner',
189
+ type: 'publicKey',
190
+ },
191
+ {
192
+ name: 'lamports',
193
+ type: 'u64',
194
+ },
195
+ {
196
+ name: 'address',
197
+ type: {
198
+ option: {
199
+ array: ['u8', 32],
200
+ },
201
+ },
202
+ },
203
+ {
204
+ name: 'data',
205
+ type: {
206
+ option: {
207
+ defined: 'CompressedAccountData',
208
+ },
209
+ },
210
+ },
211
+ ],
212
+ },
213
+ },
214
+ {
215
+ name: 'CompressedAccountData',
216
+ type: {
217
+ kind: 'struct',
218
+ fields: [
219
+ {
220
+ name: 'discriminator',
221
+ type: {
222
+ array: ['u8', 8],
223
+ },
224
+ },
225
+ {
226
+ name: 'data',
227
+ type: 'bytes',
228
+ },
229
+ {
230
+ name: 'dataHash',
231
+ type: {
232
+ array: ['u8', 32],
233
+ },
234
+ },
235
+ ],
236
+ },
237
+ },
238
+ {
239
+ name: 'PublicTransactionEvent',
240
+ type: {
241
+ kind: 'struct',
242
+ fields: [
243
+ {
244
+ name: 'inputCompressedAccountHashes',
245
+ type: {
246
+ vec: {
247
+ array: ['u8', 32],
248
+ },
249
+ },
250
+ },
251
+ {
252
+ name: 'outputCompressedAccountHashes',
253
+ type: {
254
+ vec: {
255
+ array: ['u8', 32],
256
+ },
257
+ },
258
+ },
259
+ {
260
+ name: 'inputCompressedAccounts',
261
+ type: {
262
+ vec: {
263
+ defined: 'CompressedAccountWithMerkleContext',
264
+ },
265
+ },
266
+ },
267
+ {
268
+ name: 'outputCompressedAccounts',
269
+ type: {
270
+ vec: {
271
+ defined: 'CompressedAccount',
272
+ },
273
+ },
274
+ },
275
+ {
276
+ name: 'outputStateMerkleTreeAccountIndices',
277
+ type: 'bytes',
278
+ },
279
+ {
280
+ name: 'outputLeafIndices',
281
+ type: {
282
+ vec: 'u32',
283
+ },
284
+ },
285
+ {
286
+ name: 'relayFee',
287
+ type: {
288
+ option: 'u64',
289
+ },
290
+ },
291
+ {
292
+ name: 'isCompress',
293
+ type: 'bool',
294
+ },
295
+ {
296
+ name: 'compressionLamports',
297
+ type: {
298
+ option: 'u64',
299
+ },
300
+ },
301
+ {
302
+ name: 'pubkeyArray',
303
+ type: {
304
+ vec: 'publicKey',
305
+ },
306
+ },
307
+ {
308
+ name: 'message',
309
+ type: {
310
+ option: 'bytes',
311
+ },
312
+ },
313
+ ],
314
+ },
315
+ },
316
+ {
317
+ name: 'InstructionDataTransfer',
318
+ type: {
319
+ kind: 'struct',
320
+ fields: [
321
+ {
322
+ name: 'proof',
323
+ type: {
324
+ option: {
325
+ defined: 'CompressedProof',
326
+ },
327
+ },
328
+ },
329
+ {
330
+ name: 'newAddressParams',
331
+ type: {
332
+ vec: {
333
+ defined: 'NewAddressParamsPacked',
334
+ },
335
+ },
336
+ },
337
+ {
338
+ name: 'inputRootIndices',
339
+ type: {
340
+ vec: 'u16',
341
+ },
342
+ },
343
+ {
344
+ name: 'inputCompressedAccountsWithMerkleContext',
345
+ type: {
346
+ vec: {
347
+ defined: 'CompressedAccountWithMerkleContext',
348
+ },
349
+ },
350
+ },
351
+ {
352
+ name: 'outputCompressedAccounts',
353
+ type: {
354
+ vec: {
355
+ defined: 'CompressedAccount',
356
+ },
357
+ },
358
+ },
359
+ {
360
+ name: 'outputStateMerkleTreeAccountIndices',
361
+ docs: [
362
+ 'The indices of the accounts in the output state merkle tree.',
363
+ ],
364
+ type: 'bytes',
365
+ },
366
+ {
367
+ name: 'relayFee',
368
+ type: {
369
+ option: 'u64',
370
+ },
371
+ },
372
+ {
373
+ name: 'compressionLamports',
374
+ type: {
375
+ option: 'u64',
376
+ },
377
+ },
378
+ {
379
+ name: 'isCompress',
380
+ type: 'bool',
381
+ },
382
+ ],
383
+ },
384
+ },
385
+ {
386
+ name: 'NewAddressParamsPacked',
387
+ type: {
388
+ kind: 'struct',
389
+ fields: [
390
+ {
391
+ name: 'seed',
392
+ type: {
393
+ array: ['u8', 32],
394
+ },
395
+ },
396
+ {
397
+ name: 'addressQueueAccountIndex',
398
+ type: 'u8',
399
+ },
400
+ {
401
+ name: 'addressMerkleTreeAccountIndex',
402
+ type: 'u8',
403
+ },
404
+ {
405
+ name: 'addressMerkleTreeRootIndex',
406
+ type: 'u16',
407
+ },
408
+ ],
409
+ },
410
+ },
411
+ {
412
+ name: 'NewAddressParams',
413
+ type: {
414
+ kind: 'struct',
415
+ fields: [
416
+ {
417
+ name: 'seed',
418
+ type: {
419
+ array: ['u8', 32],
420
+ },
421
+ },
422
+ {
423
+ name: 'addressQueuePubkey',
424
+ type: 'publicKey',
425
+ },
426
+ {
427
+ name: 'addressMerkleTreePubkey',
428
+ type: 'publicKey',
429
+ },
430
+ {
431
+ name: 'addressMerkleTreeRootIndex',
432
+ type: 'u16',
433
+ },
434
+ ],
435
+ },
436
+ },
437
+ {
438
+ name: 'CompressedProof',
439
+ type: {
440
+ kind: 'struct',
441
+ fields: [
442
+ {
443
+ name: 'a',
444
+ type: {
445
+ array: ['u8', 32],
446
+ },
447
+ },
448
+ {
449
+ name: 'b',
450
+ type: {
451
+ array: ['u8', 64],
452
+ },
453
+ },
454
+ {
455
+ name: 'c',
456
+ type: {
457
+ array: ['u8', 32],
458
+ },
459
+ },
460
+ ],
461
+ },
462
+ },
463
+ ],
464
+ errors: [
465
+ {
466
+ code: 6000,
467
+ name: 'SumCheckFailed',
468
+ msg: 'Sum check failed',
469
+ },
470
+ {
471
+ code: 6001,
472
+ name: 'SignerCheckFailed',
473
+ msg: 'Signer check failed',
474
+ },
475
+ {
476
+ code: 6002,
477
+ name: 'CpiSignerCheckFailed',
478
+ msg: 'Cpi signer check failed',
479
+ },
480
+ {
481
+ code: 6003,
482
+ name: 'ComputeInputSumFailed',
483
+ msg: 'Computing input sum failed.',
484
+ },
485
+ {
486
+ code: 6004,
487
+ name: 'ComputeOutputSumFailed',
488
+ msg: 'Computing output sum failed.',
489
+ },
490
+ {
491
+ code: 6005,
492
+ name: 'ComputeRpcSumFailed',
493
+ msg: 'Computing rpc sum failed.',
494
+ },
495
+ {
496
+ code: 6006,
497
+ name: 'InUtxosAlreadyAdded',
498
+ msg: 'InUtxosAlreadyAdded',
499
+ },
500
+ {
501
+ code: 6007,
502
+ name: 'NumberOfLeavesMissmatch',
503
+ msg: 'NumberOfLeavesMissmatch',
504
+ },
505
+ {
506
+ code: 6008,
507
+ name: 'MerkleTreePubkeysMissmatch',
508
+ msg: 'MerkleTreePubkeysMissmatch',
509
+ },
510
+ {
511
+ code: 6009,
512
+ name: 'NullifierArrayPubkeysMissmatch',
513
+ msg: 'NullifierArrayPubkeysMissmatch',
514
+ },
515
+ {
516
+ code: 6010,
517
+ name: 'InvalidNoopPubkey',
518
+ msg: 'InvalidNoopPubkey',
519
+ },
520
+ {
521
+ code: 6011,
522
+ name: 'InvalidPublicInputsLength',
523
+ msg: 'InvalidPublicInputsLength',
524
+ },
525
+ {
526
+ code: 6012,
527
+ name: 'DecompressG1Failed',
528
+ msg: 'Decompress G1 Failed',
529
+ },
530
+ {
531
+ code: 6013,
532
+ name: 'DecompressG2Failed',
533
+ msg: 'Decompress G2 Failed',
534
+ },
535
+ {
536
+ code: 6014,
537
+ name: 'CreateGroth16VerifierFailed',
538
+ msg: 'CreateGroth16VerifierFailed',
539
+ },
540
+ {
541
+ code: 6015,
542
+ name: 'ProofVerificationFailed',
543
+ msg: 'ProofVerificationFailed',
544
+ },
545
+ {
546
+ code: 6016,
547
+ name: 'PublicInputsTryIntoFailed',
548
+ msg: 'PublicInputsTryIntoFailed',
549
+ },
550
+ {
551
+ code: 6017,
552
+ name: 'CompressedAccountHashError',
553
+ msg: 'CompressedAccountHashError',
554
+ },
555
+ {
556
+ code: 6018,
557
+ name: 'InvalidAddress',
558
+ msg: 'InvalidAddress',
559
+ },
560
+ {
561
+ code: 6019,
562
+ name: 'InvalidAddressQueue',
563
+ msg: 'InvalidAddressQueue',
564
+ },
565
+ {
566
+ code: 6020,
567
+ name: 'InvalidNullifierQueue',
568
+ msg: 'InvalidNullifierQueue',
569
+ },
570
+ {
571
+ code: 6021,
572
+ name: 'DeriveAddressError',
573
+ msg: 'DeriveAddressError',
574
+ },
575
+ {
576
+ code: 6022,
577
+ name: 'CompressSolTransferFailed',
578
+ msg: 'CompressSolTransferFailed',
579
+ },
580
+ {
581
+ code: 6023,
582
+ name: 'CompressedSolPdaUndefinedForCompressSol',
583
+ msg: 'CompressedSolPdaUndefinedForCompressSol',
584
+ },
585
+ {
586
+ code: 6024,
587
+ name: 'DeCompressLamportsUndefinedForCompressSol',
588
+ msg: 'DeCompressLamportsUndefinedForCompressSol',
589
+ },
590
+ {
591
+ code: 6025,
592
+ name: 'CompressedSolPdaUndefinedForDecompressSol',
593
+ msg: 'CompressedSolPdaUndefinedForDecompressSol',
594
+ },
595
+ {
596
+ code: 6026,
597
+ name: 'DeCompressLamportsUndefinedForDecompressSol',
598
+ msg: 'DeCompressLamportsUndefinedForDecompressSol',
599
+ },
600
+ {
601
+ code: 6027,
602
+ name: 'DecompressRecipientUndefinedForDecompressSol',
603
+ msg: 'DecompressRecipientUndefinedForDecompressSol',
604
+ },
605
+ {
606
+ code: 6028,
607
+ name: 'LengthMismatch',
608
+ msg: 'LengthMismatch',
609
+ },
610
+ {
611
+ code: 6029,
612
+ name: 'DelegateUndefined',
613
+ msg: 'DelegateUndefined while delegated amount is defined',
614
+ },
615
+ ],
616
+ };
617
+
618
+ /// TODO: extract wallet into its own npm package
619
+ /// Mock Solana web3 library
620
+ class Wallet {
621
+ _publicKey;
622
+ _keypair;
623
+ _connection;
624
+ _url;
625
+ _commitment;
626
+ constructor(keypair, url, commitment) {
627
+ this._publicKey = keypair.publicKey;
628
+ this._keypair = keypair;
629
+ this._connection = new Connection(url);
630
+ this._url = url;
631
+ this._commitment = commitment;
632
+ }
633
+ signTransaction = async (tx) => {
634
+ await tx.sign([this._keypair]);
635
+ return tx;
636
+ };
637
+ sendTransaction = async (transaction) => {
638
+ const signature = await this._connection.sendTransaction(transaction);
639
+ return signature;
640
+ };
641
+ signAllTransactions = async (transactions) => {
642
+ const signedTxs = await Promise.all(transactions.map(async (tx) => {
643
+ return await this.signTransaction(tx);
644
+ }));
645
+ return signedTxs;
646
+ };
647
+ signMessage = async (message) => {
648
+ return sign.detached(message, this._keypair.secretKey);
649
+ };
650
+ sendAndConfirmTransaction = async (transaction, signers = []) => {
651
+ const response = await sendAndConfirmTransaction(this._connection, transaction, [this._keypair, ...signers], {
652
+ commitment: this._commitment,
653
+ });
654
+ return response;
655
+ };
656
+ }
657
+
658
+ // // TODO consider adding isNodeWallet
659
+ const useWallet = (keypair, url = 'http://127.0.0.1:8899', commitment = 'confirmed') => {
660
+ url = url !== 'mock' ? url : 'http://127.0.0.1:8899';
661
+ const wallet = new Wallet(keypair, url, commitment);
662
+ return {
663
+ publicKey: wallet._publicKey,
664
+ sendAndConfirmTransaction: wallet.sendAndConfirmTransaction,
665
+ signMessage: wallet.signMessage,
666
+ signTransaction: wallet.signTransaction,
667
+ signAllTransactions: wallet.signAllTransactions,
668
+ sendTransaction: wallet.sendTransaction,
669
+ };
670
+ };
671
+
672
+ const FIELD_SIZE = new BN('21888242871839275222246405745257275088548364400416034343698204186575808495617');
673
+ // TODO: implement properly
674
+ const noopProgram = 'noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV';
675
+ const lightProgram = '5WzvRtu7LABotw1SUEpguJiKU27LRGsiCnF5FH6VV7yP';
676
+ const accountCompressionProgram = // also: merkletree program
677
+ '5QPEJ5zDsVou9FQS3KCauKswM3VwBEBu4dpL9xTqkWwN';
678
+ const getRegisteredProgramPda = () => new PublicKey('ytwwVWhQUMoTKdirKmvEW5xCRVr4B2dJZnToiHtE2L2'); // TODO: better labelling. gov authority pda
679
+ const getPspAccountCompressionAuthority = () => PublicKey.findProgramAddressSync([
680
+ Buffer$1.from('cpi_authority'),
681
+ new PublicKey(accountCompressionProgram).toBytes(),
682
+ ], new PublicKey(
683
+ // TODO: can add check to ensure its consistent with the idl
684
+ '6UqiSPd2mRCTTwkzhcs1M6DGYsqHWd5jiPueX3LwDMXQ'))[0];
685
+ const defaultStaticAccounts = () => [
686
+ new PublicKey(getRegisteredProgramPda()),
687
+ new PublicKey(noopProgram),
688
+ new PublicKey(accountCompressionProgram),
689
+ new PublicKey(getPspAccountCompressionAuthority()),
690
+ ];
691
+ const defaultStaticAccountsStruct = () => {
692
+ return {
693
+ registeredProgramPda: new PublicKey(getRegisteredProgramPda()),
694
+ noopProgram: new PublicKey(noopProgram),
695
+ accountCompressionProgram: new PublicKey(accountCompressionProgram),
696
+ pspAccountCompressionAuthority: new PublicKey(getPspAccountCompressionAuthority()),
697
+ cpiSignatureAccount: null,
698
+ };
699
+ };
700
+ const defaultTestStateTreeAccounts = () => {
701
+ return {
702
+ nullifierQueue: new PublicKey(nullifierQueuePubkey),
703
+ merkleTree: new PublicKey(merkletreePubkey),
704
+ merkleTreeHeight: DEFAULT_MERKLE_TREE_HEIGHT,
705
+ };
706
+ };
707
+ const nullifierQueuePubkey = '44J4oDXpjPAbzHCSc24q7NEiPekss4sAbLd8ka4gd9CZ'; // also called indexed_array
708
+ const merkletreePubkey = '5bdFnXU47QjzGpzHfXnxcEi5WXyxzEAZzd1vrE39bf1W';
709
+ const confirmConfig = {
710
+ commitment: 'confirmed',
711
+ preflightCommitment: 'confirmed',
712
+ };
713
+ const DEFAULT_MERKLE_TREE_HEIGHT = 26;
714
+ const DEFAULT_MERKLE_TREE_ROOTS = 2800;
715
+ /** Threshold (per asset) at which new in-UTXOs get merged, in order to reduce UTXO pool size */
716
+ const UTXO_MERGE_THRESHOLD = 20;
717
+ const UTXO_MERGE_MAXIMUM = 10;
718
+ /**
719
+ * Treshold after which the currently used transaction Merkle tree is switched
720
+ * to the next one
721
+ */
722
+ const TRANSACTION_MERKLE_TREE_ROLLOVER_THRESHOLD = new BN(Math.floor(2 ** DEFAULT_MERKLE_TREE_HEIGHT * 0.95));
723
+
724
+ // TODO: consider implementing BN254 as wrapper class around _BN mirroring
725
+ // PublicKey this would encapsulate our runtime checks and also enforce
726
+ // typesafety at compile time
727
+ const bn = (number, base, endian) => new BN(number, base, endian);
728
+ /** Create a bigint instance with <254-bit max size and base58 capabilities */
729
+ const createBN254 = (number, base) => {
730
+ if (base === 'base58') {
731
+ if (typeof number !== 'string')
732
+ throw new Error('Must be a base58 string');
733
+ return createBN254(bs58.decode(number));
734
+ }
735
+ const bigintNumber = new BN(number, base);
736
+ return enforceSize(bigintNumber);
737
+ };
738
+ /**
739
+ * Enforces a maximum size of <254 bits for bigint instances. This is necessary
740
+ * for compatibility with zk-SNARKs, where hashes must be less than the field
741
+ * modulus (~2^254).
742
+ */
743
+ function enforceSize(bigintNumber) {
744
+ if (bigintNumber.gte(FIELD_SIZE)) {
745
+ throw new Error('Value is too large. Max <254 bits');
746
+ }
747
+ return bigintNumber;
748
+ }
749
+ /** Convert <254-bit bigint to Base58 string. Fills up to 32 bytes. */
750
+ function encodeBN254toBase58(bigintNumber, pad = 32) {
751
+ let buffer = Buffer$1.from(bigintNumber.toString(16), 'hex');
752
+ // Ensure the buffer is 32 bytes. If not, pad it with leading zeros.
753
+ if (buffer.length < pad) {
754
+ const padding = Buffer$1.alloc(pad - buffer.length);
755
+ buffer = Buffer$1.concat([padding, buffer], pad);
756
+ }
757
+ return bs58.encode(buffer);
758
+ }
759
+ /** Convert Base58 string to <254-bit Solana Public key*/
760
+ function bigint254ToPublicKey(bigintNumber) {
761
+ const paddedBase58 = encodeBN254toBase58(bigintNumber);
762
+ return new PublicKey(paddedBase58);
763
+ }
764
+ // FIXME: assumes <254 bit pubkey. just use consistent type (pubkey254)
765
+ /** Convert Solana Public key to <254-bit bigint */
766
+ function PublicKeyToBN254(publicKey) {
767
+ const buffer = publicKey.toBuffer();
768
+ // Remove leading zeros from the buffer
769
+ const trimmedBuffer = buffer.subarray(buffer.findIndex(byte => byte !== 0));
770
+ return createBN254(trimmedBuffer);
771
+ }
772
+ //@ts-ignore
773
+ if (import.meta.vitest) {
774
+ //@ts-ignore
775
+ const { it, expect, describe } = import.meta.vitest;
776
+ describe('createBN254 function', () => {
777
+ it('should create a BN254 from a string', () => {
778
+ const bigint = createBN254('100');
779
+ expect(bigint.toNumber()).toBe(100);
780
+ });
781
+ it('should create a BN254 from a number', () => {
782
+ const bigint = createBN254(100);
783
+ expect(bigint.toNumber()).toBe(100);
784
+ });
785
+ it('should create a BN254 from a bigint', () => {
786
+ const bigint = createBN254(bn(100));
787
+ expect(bigint.toNumber()).toBe(100);
788
+ });
789
+ it('should create a BN254 from a Buffer', () => {
790
+ const bigint = createBN254(Buffer$1.from([100]));
791
+ expect(bigint.toNumber()).toBe(100);
792
+ });
793
+ it('should create a BN254 from a Uint8Array', () => {
794
+ const bigint = createBN254(new Uint8Array([100]));
795
+ expect(bigint.toNumber()).toBe(100);
796
+ });
797
+ it('should create a BN254 from a number[]', () => {
798
+ const bigint = createBN254([100]);
799
+ expect(bigint.toNumber()).toBe(100);
800
+ });
801
+ it('should create a BN254 from a base58 string', () => {
802
+ const bigint = createBN254('2j', 'base58');
803
+ expect(bigint.toNumber()).toBe(bn(100).toNumber());
804
+ });
805
+ });
806
+ describe('encodeBN254toBase58 function', () => {
807
+ it('should convert a BN254 to a base58 string, no pad', () => {
808
+ const bigint = createBN254('100');
809
+ const base58 = encodeBN254toBase58(bigint, 0);
810
+ expect(base58).toBe('2j');
811
+ });
812
+ it('should convert a BN254 to a base58 string, with pad', () => {
813
+ const bigint = createBN254('100');
814
+ const base58 = encodeBN254toBase58(bigint);
815
+ expect(base58).toBe('11111111111111111111111111111112j');
816
+ });
817
+ it('should throw an error for a value that is too large', () => {
818
+ expect(() => createBN254(FIELD_SIZE)).toThrow('Value is too large. Max <254 bits');
819
+ });
820
+ });
821
+ describe('bigint254ToPublicKey function', () => {
822
+ it('should convert a BN254 to a PublicKey', () => {
823
+ const bigint = createBN254('100');
824
+ const publicKey = bigint254ToPublicKey(bigint);
825
+ expect(publicKey).toBeInstanceOf(PublicKey);
826
+ });
827
+ });
828
+ describe('PublicKeyToBigint254 function', () => {
829
+ it('should convert a PublicKey to a BN254', () => {
830
+ const publicKey = PublicKey.unique();
831
+ const bigint = PublicKeyToBN254(publicKey);
832
+ expect(bigint).toBeInstanceOf(BN);
833
+ });
834
+ });
835
+ }
836
+
837
+ const createCompressedAccount = (owner, lamports, data, address) => ({
838
+ owner,
839
+ lamports: lamports ?? bn(0),
840
+ address: address ?? null,
841
+ data: data ?? null,
842
+ });
843
+ const createCompressedAccountWithMerkleContext = (merkleContext, owner, lamports, data, address) => ({
844
+ ...createCompressedAccount(owner, lamports, data, address),
845
+ ...merkleContext,
846
+ });
847
+ const createMerkleContext = (merkleTree, nullifierQueue, hash, // TODO: BN254,
848
+ leafIndex) => ({
849
+ merkleTree,
850
+ nullifierQueue,
851
+ hash,
852
+ leafIndex,
853
+ });
854
+ //@ts-ignore
855
+ if (import.meta.vitest) {
856
+ //@ts-ignore
857
+ const { it, expect, describe } = import.meta.vitest;
858
+ describe('createCompressedAccount function', () => {
859
+ it('should create a compressed account with default values', () => {
860
+ const owner = PublicKey.unique();
861
+ const account = createCompressedAccount(owner);
862
+ expect(account).toEqual({
863
+ owner,
864
+ lamports: bn(0),
865
+ address: null,
866
+ data: null,
867
+ });
868
+ });
869
+ it('should create a compressed account with provided values', () => {
870
+ const owner = PublicKey.unique();
871
+ const lamports = bn(100);
872
+ const data = {
873
+ discriminator: [0],
874
+ data: Buffer.from(new Uint8Array([1, 2, 3])),
875
+ dataHash: [0],
876
+ };
877
+ const address = PublicKey.unique();
878
+ const account = createCompressedAccount(owner, lamports, data, address);
879
+ expect(account).toEqual({
880
+ owner,
881
+ lamports,
882
+ address,
883
+ data,
884
+ });
885
+ });
886
+ });
887
+ describe('createCompressedAccountWithMerkleContext function', () => {
888
+ it('should create a compressed account with merkle context', () => {
889
+ const owner = PublicKey.unique();
890
+ const merkleTree = PublicKey.unique();
891
+ const nullifierQueue = PublicKey.unique();
892
+ const hash = new Array(32).fill(1);
893
+ const leafIndex = 0;
894
+ const merkleContext = createMerkleContext(merkleTree, nullifierQueue, hash, leafIndex);
895
+ const accountWithMerkleContext = createCompressedAccountWithMerkleContext(merkleContext, owner);
896
+ expect(accountWithMerkleContext).toEqual({
897
+ owner,
898
+ lamports: bn(0),
899
+ address: null,
900
+ data: null,
901
+ merkleTree,
902
+ nullifierQueue,
903
+ hash,
904
+ leafIndex,
905
+ });
906
+ });
907
+ });
908
+ describe('createMerkleContext function', () => {
909
+ it('should create a merkle context', () => {
910
+ const merkleTree = PublicKey.unique();
911
+ const nullifierQueue = PublicKey.unique();
912
+ const hash = new Array(32).fill(1);
913
+ const leafIndex = 0;
914
+ const merkleContext = createMerkleContext(merkleTree, nullifierQueue, hash, leafIndex);
915
+ expect(merkleContext).toEqual({
916
+ merkleTree,
917
+ nullifierQueue,
918
+ hash,
919
+ leafIndex,
920
+ });
921
+ });
922
+ });
923
+ }
924
+
925
+ function byteArrayToKeypair(byteArray) {
926
+ return Keypair.fromSecretKey(Uint8Array.from(byteArray));
927
+ }
928
+ const toArray = (value) => Array.isArray(value) ? value : [value];
929
+ const bufToDecStr = (buf) => {
930
+ return createBN254(buf).toString();
931
+ };
932
+ function isSmallerThanBn254FieldSizeLe(bytes) {
933
+ const bigint = bn(bytes, undefined, 'le');
934
+ return bigint.lt(FIELD_SIZE);
935
+ }
936
+ async function hashToBn254FieldSizeLe(bytes) {
937
+ let bumpSeed = 255;
938
+ while (bumpSeed >= 0) {
939
+ const inputWithBumpSeed = Buffer$1.concat([
940
+ bytes,
941
+ Buffer$1.from([bumpSeed]),
942
+ ]);
943
+ const hash = keccak_256(inputWithBumpSeed);
944
+ if (hash.length !== 32) {
945
+ throw new Error('Invalid hash length');
946
+ }
947
+ hash[0] = 0;
948
+ hash[1] = 0;
949
+ if (isSmallerThanBn254FieldSizeLe(Buffer$1.from(hash))) {
950
+ return [Buffer$1.from(hash), bumpSeed];
951
+ }
952
+ bumpSeed -= 1;
953
+ }
954
+ return null;
955
+ }
956
+ /** Mutates array in place */
957
+ function pushUniqueItems(items, map) {
958
+ items.forEach(item => {
959
+ if (!map.includes(item)) {
960
+ map.push(item);
961
+ }
962
+ });
963
+ }
964
+ function toCamelCase(obj) {
965
+ if (Array.isArray(obj)) {
966
+ return obj.map(v => toCamelCase(v));
967
+ }
968
+ else if (obj !== null && obj.constructor === Object) {
969
+ return Object.keys(obj).reduce((result, key) => {
970
+ const camelCaseKey = key.replace(/([-_][a-z])/gi, $1 => {
971
+ return $1.toUpperCase().replace('-', '').replace('_', '');
972
+ });
973
+ result[camelCaseKey] = toCamelCase(obj[key]);
974
+ return result;
975
+ }, {});
976
+ }
977
+ return obj;
978
+ }
979
+ // FIXME: check bundling and how to resolve the type error
980
+ //@ts-ignore
981
+ if (import.meta.vitest) {
982
+ //@ts-ignore
983
+ const { it, expect, describe } = import.meta.vitest;
984
+ describe('toArray function', () => {
985
+ it('should convert a single item to an array', () => {
986
+ expect(toArray(1)).toEqual([1]);
987
+ });
988
+ it('should leave an array unchanged', () => {
989
+ expect(toArray([1, 2, 3])).toEqual([1, 2, 3]);
990
+ });
991
+ });
992
+ describe('isSmallerThanBn254FieldSizeLe function', () => {
993
+ it('should return true for a small number', () => {
994
+ const buf = Buffer$1.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex');
995
+ expect(isSmallerThanBn254FieldSizeLe(buf)).toBe(true);
996
+ });
997
+ it('should return false for a large number', () => {
998
+ const buf = Buffer$1.from('6500000000000000000000000000000000000000000000000000000000000000', 'hex').reverse();
999
+ expect(isSmallerThanBn254FieldSizeLe(buf)).toBe(false);
1000
+ });
1001
+ });
1002
+ describe('hashToBn254FieldSizeLe function', () => {
1003
+ const bytes = [
1004
+ 131, 219, 249, 246, 221, 196, 33, 3, 114, 23, 121, 235, 18, 229, 71,
1005
+ 152, 39, 87, 169, 208, 143, 101, 43, 128, 245, 59, 22, 134, 182,
1006
+ 231, 116, 33,
1007
+ ];
1008
+ const refResult = [
1009
+ 0, 0, 138, 224, 71, 10, 16, 226, 30, 104, 100, 251, 232, 59, 50,
1010
+ 168, 21, 78, 218, 191, 159, 16, 119, 17, 30, 55, 194, 230, 138, 128,
1011
+ 18, 44,
1012
+ ];
1013
+ it('should return a valid value for initial buffer', async () => {
1014
+ const result = await hashToBn254FieldSizeLe(Buffer$1.from(bytes));
1015
+ expect(Array.from(result[0])).toEqual(refResult);
1016
+ });
1017
+ it('should return a valid value for initial buffer', async () => {
1018
+ const buf = Buffer$1.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex');
1019
+ const result = await hashToBn254FieldSizeLe(buf);
1020
+ expect(result).not.toBeNull();
1021
+ if (result) {
1022
+ expect(result[0]).toBeInstanceOf(Buffer$1);
1023
+ expect(result[1]).toBe(254);
1024
+ }
1025
+ });
1026
+ it('should return a valid value for a buffer that can be hashed to a smaller value', async () => {
1027
+ const buf = Buffer$1.from('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', 'hex');
1028
+ const result = await hashToBn254FieldSizeLe(buf);
1029
+ expect(result).not.toBeNull();
1030
+ if (result) {
1031
+ expect(result[1]).toBeLessThanOrEqual(255);
1032
+ expect(result[0]).toBeInstanceOf(Buffer$1);
1033
+ // Check if the hashed value is indeed smaller than the bn254 field size
1034
+ expect(isSmallerThanBn254FieldSizeLe(result[0])).toBe(true);
1035
+ }
1036
+ });
1037
+ it('should correctly hash the input buffer', async () => {
1038
+ const buf = Buffer$1.from('deadbeef', 'hex');
1039
+ const result = await hashToBn254FieldSizeLe(buf);
1040
+ expect(result).not.toBeNull();
1041
+ if (result) {
1042
+ // Since the actual hash value depends on the crypto implementation and input,
1043
+ // we cannot predict the exact output. However, we can check if the output is valid.
1044
+ expect(result[0].length).toBe(32); // SHA-256 hash length
1045
+ expect(result[1]).toBeLessThanOrEqual(255);
1046
+ expect(isSmallerThanBn254FieldSizeLe(result[0])).toBe(true);
1047
+ }
1048
+ });
1049
+ });
1050
+ describe('pushUniqueItems function', () => {
1051
+ it('should add unique items', () => {
1052
+ const map = [1, 2, 3];
1053
+ const itemsToAdd = [3, 4, 5];
1054
+ pushUniqueItems(itemsToAdd, map);
1055
+ expect(map).toEqual([1, 2, 3, 4, 5]);
1056
+ });
1057
+ it('should ignore duplicates', () => {
1058
+ const map = [1, 2, 3];
1059
+ const itemsToAdd = [1, 2, 3];
1060
+ pushUniqueItems(itemsToAdd, map);
1061
+ expect(map).toEqual([1, 2, 3]);
1062
+ });
1063
+ it('should handle empty arrays', () => {
1064
+ const map = [];
1065
+ const itemsToAdd = [];
1066
+ pushUniqueItems(itemsToAdd, map);
1067
+ expect(map).toEqual([]);
1068
+ });
1069
+ });
1070
+ describe('bufToDecStr', () => {
1071
+ it("should convert buffer [0] to '0'", () => {
1072
+ expect(bufToDecStr(Buffer$1.from([0]))).toEqual('0');
1073
+ });
1074
+ it("should convert buffer [1] to '1'", () => {
1075
+ expect(bufToDecStr(Buffer$1.from([1]))).toEqual('1');
1076
+ });
1077
+ it("should convert buffer [1, 0] to '256'", () => {
1078
+ expect(bufToDecStr(Buffer$1.from([1, 0]))).toEqual('256');
1079
+ });
1080
+ it("should convert buffer [1, 1] to '257'", () => {
1081
+ expect(bufToDecStr(Buffer$1.from([1, 1]))).toEqual('257');
1082
+ });
1083
+ it("should convert buffer [7, 91, 205, 21] to '123456789'", () => {
1084
+ expect(bufToDecStr(Buffer$1.from([7, 91, 205, 21]))).toEqual('123456789');
1085
+ });
1086
+ });
1087
+ describe('toCamelCase', () => {
1088
+ it('should convert object keys to camelCase', () => {
1089
+ const input = { test_key: 1, 'another-testKey': 2 };
1090
+ const expected = { testKey: 1, anotherTestKey: 2 };
1091
+ expect(toCamelCase(input)).toEqual(expected);
1092
+ });
1093
+ it('should handle arrays of objects', () => {
1094
+ const input = [{ array_key: 3 }, { 'another_array-key': 4 }];
1095
+ const expected = [{ arrayKey: 3 }, { anotherArrayKey: 4 }];
1096
+ expect(toCamelCase(input)).toEqual(expected);
1097
+ });
1098
+ it('should return the input if it is neither an object nor an array', () => {
1099
+ const input = 'testString';
1100
+ expect(toCamelCase(input)).toBe(input);
1101
+ });
1102
+ });
1103
+ }
1104
+
1105
+ /** pipe function */
1106
+ function pipe(initialFunction, ...functions) {
1107
+ return (initialValue) => functions.reduce((currentValue, currentFunction) => currentFunction(currentValue), initialFunction(initialValue));
1108
+ }
1109
+ //@ts-ignore
1110
+ if (import.meta.vitest) {
1111
+ //@ts-ignore
1112
+ const { it, expect, describe } = import.meta.vitest;
1113
+ describe('pipe', () => {
1114
+ it('should return the result of applying all fns to the initial value', () => {
1115
+ const addOne = (x) => x + 1;
1116
+ const multiplyByTwo = (x) => x * 2;
1117
+ const subtractThree = (x) => x - 3;
1118
+ const addOneMultiplyByTwoSubtractThree = pipe(addOne, multiplyByTwo, subtractThree);
1119
+ expect(addOneMultiplyByTwoSubtractThree(5)).toBe(9);
1120
+ });
1121
+ });
1122
+ }
1123
+
1124
+ /** Sends a versioned transaction and confirms it. */
1125
+ async function sendAndConfirmTx(rpc, tx, confirmOptions) {
1126
+ const txId = await rpc.sendTransaction(tx, confirmOptions);
1127
+ const { blockhash, lastValidBlockHeight } = await rpc.getLatestBlockhash(confirmOptions?.commitment);
1128
+ const transactionConfirmationStrategy0 = {
1129
+ signature: txId,
1130
+ blockhash,
1131
+ lastValidBlockHeight,
1132
+ };
1133
+ await rpc.confirmTransaction(transactionConfirmationStrategy0, confirmOptions?.commitment || rpc.commitment || 'confirmed');
1134
+ return txId;
1135
+ }
1136
+ /** @internal */
1137
+ async function confirmTx(rpc, txId, blockHashCtx) {
1138
+ if (!blockHashCtx)
1139
+ blockHashCtx = await rpc.getLatestBlockhash();
1140
+ const transactionConfirmationStrategy = {
1141
+ signature: txId,
1142
+ blockhash: blockHashCtx.blockhash,
1143
+ lastValidBlockHeight: blockHashCtx.lastValidBlockHeight,
1144
+ };
1145
+ const res = await rpc.confirmTransaction(transactionConfirmationStrategy, rpc.commitment || 'confirmed');
1146
+ return res;
1147
+ }
1148
+ /**
1149
+ * Builds a versioned Transaction from instructions and signs it.
1150
+ *
1151
+ * @param instructions instructions to include in the transaction
1152
+ * @param payer payer of the transaction
1153
+ * @param blockhash recent blockhash to use in the transaction
1154
+ * @param additionalSigners non-feepayer signers to include in the transaction
1155
+ */
1156
+ function buildAndSignTx(instructions, payer, blockhash, additionalSigners = []) {
1157
+ if (additionalSigners.includes(payer))
1158
+ throw new Error('payer must not be in additionalSigners');
1159
+ const allSigners = [payer, ...additionalSigners];
1160
+ const messageV0 = new TransactionMessage({
1161
+ payerKey: payer.publicKey,
1162
+ recentBlockhash: blockhash,
1163
+ instructions,
1164
+ }).compileToV0Message();
1165
+ const tx = new VersionedTransaction(messageV0);
1166
+ tx.sign(allSigners);
1167
+ return tx;
1168
+ }
1169
+
1170
+ // zzz
1171
+ function sleep(ms) {
1172
+ return new Promise(resolve => setTimeout(resolve, ms));
1173
+ }
1174
+
1175
+ async function airdropSol({ connection, lamports, recipientPublicKey, }) {
1176
+ const txHash = await connection.requestAirdrop(recipientPublicKey, lamports);
1177
+ await confirmTransaction(connection, txHash);
1178
+ return txHash;
1179
+ }
1180
+ async function confirmTransaction(connection, signature, confirmation = 'confirmed') {
1181
+ const latestBlockHash = await connection.getLatestBlockhash(confirmation);
1182
+ const strategy = {
1183
+ signature: signature.toString(),
1184
+ lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
1185
+ blockhash: latestBlockHash.blockhash,
1186
+ };
1187
+ return await connection.confirmTransaction(strategy, confirmation);
1188
+ }
1189
+
1190
+ const validateSufficientBalance = (balance) => {
1191
+ if (balance.lt(bn(0))) {
1192
+ throw new Error('Not enough balance for transfer');
1193
+ }
1194
+ };
1195
+ const validateSameOwner = (compressedAccounts) => {
1196
+ if (compressedAccounts.length === 0) {
1197
+ throw new Error('No accounts provided for validation');
1198
+ }
1199
+ const zerothOwner = compressedAccounts[0].owner;
1200
+ if (!compressedAccounts.every(account => account.owner.equals(zerothOwner))) {
1201
+ throw new Error('All input accounts must have the same owner');
1202
+ }
1203
+ };
1204
+
1205
+ /**
1206
+ * @internal Finds the index of a PublicKey in an array, or adds it if not
1207
+ * present
1208
+ * */
1209
+ function getIndexOrAdd(accountsArray, key) {
1210
+ const index = accountsArray.findIndex(existingKey => existingKey.equals(key));
1211
+ if (index === -1) {
1212
+ accountsArray.push(key);
1213
+ return accountsArray.length - 1;
1214
+ }
1215
+ return index;
1216
+ }
1217
+ /** @internal */
1218
+ function padOutputStateMerkleTrees(outputStateMerkleTrees, numberOfOutputCompressedAccounts, inputCompressedAccountsWithMerkleContext) {
1219
+ if (numberOfOutputCompressedAccounts <= 0) {
1220
+ return [];
1221
+ }
1222
+ /// Default: use the 0th state tree of input state for all output accounts
1223
+ if (outputStateMerkleTrees === undefined) {
1224
+ if (inputCompressedAccountsWithMerkleContext.length === 0) {
1225
+ throw new Error('inputCompressedAccountsWithMerkleContext cannot be empty when outputStateMerkleTrees is undefined');
1226
+ }
1227
+ return new Array(numberOfOutputCompressedAccounts).fill(inputCompressedAccountsWithMerkleContext[0].merkleTree);
1228
+ /// Align the number of output state trees with the number of output
1229
+ /// accounts, and fill up with 0th output state tree
1230
+ }
1231
+ else {
1232
+ /// Into array
1233
+ const treesArray = toArray(outputStateMerkleTrees);
1234
+ if (treesArray.length >= numberOfOutputCompressedAccounts) {
1235
+ return treesArray.slice(0, numberOfOutputCompressedAccounts);
1236
+ }
1237
+ else {
1238
+ return treesArray.concat(new Array(numberOfOutputCompressedAccounts - treesArray.length).fill(treesArray[0]));
1239
+ }
1240
+ }
1241
+ }
1242
+ // TODO: include owner and lamports in packing.
1243
+ /**
1244
+ * Packs Compressed Accounts.
1245
+ *
1246
+ * Replaces PublicKey with index pointer to remaining accounts.
1247
+ *
1248
+ * @param inputCompressedAccounts ix input state to be consumed
1249
+ * @param numberOfOutputCompressedAccounts ix ouput state to be created
1250
+ * @param outputStateMerkleTrees State trees that the output should
1251
+ * be inserted into. Defaults to the
1252
+ * 0th state tree of the input state.
1253
+ * Gets padded to the length of
1254
+ * outputCompressedAccounts.
1255
+ * @param remainingAccounts Optional existing array of accounts
1256
+ * to append to.
1257
+ **/
1258
+ function packCompressedAccounts(inputCompressedAccounts, numberOfOutputCompressedAccounts, outputStateMerkleTrees, remainingAccounts = []) {
1259
+ const _remainingAccounts = remainingAccounts.slice();
1260
+ const packedInputCompressedAccounts = [];
1261
+ /// input
1262
+ inputCompressedAccounts.forEach(account => {
1263
+ const merkleTreePubkeyIndex = getIndexOrAdd(_remainingAccounts, account.merkleTree);
1264
+ const nullifierQueuePubkeyIndex = getIndexOrAdd(_remainingAccounts, account.nullifierQueue);
1265
+ packedInputCompressedAccounts.push({
1266
+ compressedAccount: {
1267
+ owner: account.owner,
1268
+ lamports: account.lamports,
1269
+ address: account.address,
1270
+ data: account.data,
1271
+ },
1272
+ merkleTreePubkeyIndex,
1273
+ nullifierQueuePubkeyIndex,
1274
+ leafIndex: account.leafIndex,
1275
+ });
1276
+ });
1277
+ /// output
1278
+ const paddedOutputStateMerkleTrees = padOutputStateMerkleTrees(outputStateMerkleTrees, numberOfOutputCompressedAccounts, inputCompressedAccounts);
1279
+ const outputStateMerkleTreeIndices = [];
1280
+ paddedOutputStateMerkleTrees.forEach(account => {
1281
+ const indexMerkleTree = getIndexOrAdd(_remainingAccounts, account);
1282
+ outputStateMerkleTreeIndices.push(indexMerkleTree);
1283
+ });
1284
+ /// to meta
1285
+ const remainingAccountMetas = _remainingAccounts.map((account) => ({
1286
+ pubkey: account,
1287
+ isWritable: true,
1288
+ isSigner: false,
1289
+ }));
1290
+ return {
1291
+ packedInputCompressedAccounts,
1292
+ outputStateMerkleTreeIndices,
1293
+ remainingAccountMetas,
1294
+ };
1295
+ }
1296
+ //@ts-ignore
1297
+ if (import.meta.vitest) {
1298
+ //@ts-ignore
1299
+ const { describe, it, expect } = import.meta.vitest;
1300
+ // Inline unit tests for padOutputStateMerkleTrees function
1301
+ describe('padOutputStateMerkleTrees', () => {
1302
+ const treeA = PublicKey.unique();
1303
+ const treeB = PublicKey.unique();
1304
+ const treeC = PublicKey.unique();
1305
+ const accA = { merkleTree: treeA };
1306
+ const accB = { merkleTree: treeB };
1307
+ it('should use the 0th state tree of input state if no output state trees are provided', () => {
1308
+ const result = padOutputStateMerkleTrees(undefined, 3, [
1309
+ accA,
1310
+ accB,
1311
+ ]);
1312
+ expect(result).toEqual([treeA, treeA, treeA]);
1313
+ });
1314
+ it('should fill up with the first state tree if provided trees are less than required', () => {
1315
+ const result = padOutputStateMerkleTrees([treeA, treeB], 5, []);
1316
+ expect(result).toEqual([treeA, treeB, treeA, treeA, treeA]);
1317
+ });
1318
+ it('should remove extra trees if the number of output state trees is greater than the number of output accounts', () => {
1319
+ const result = padOutputStateMerkleTrees([treeA, treeB, treeC], 2, []);
1320
+ expect(result).toEqual([treeA, treeB]);
1321
+ });
1322
+ it('should return the same outputStateMerkleTrees if its length equals the number of output compressed accounts', () => {
1323
+ const result = padOutputStateMerkleTrees([treeA, treeB, treeC], 3, []);
1324
+ expect(result).toEqual([treeA, treeB, treeC]);
1325
+ });
1326
+ });
1327
+ }
1328
+
1329
+ const parseEvents = (indexerEventsTransactions, deserializeFn) => {
1330
+ const { noopProgram } = defaultStaticAccountsStruct();
1331
+ const transactions = [];
1332
+ indexerEventsTransactions.forEach(tx => {
1333
+ if (!tx ||
1334
+ !tx.meta ||
1335
+ tx.meta.err ||
1336
+ !tx.meta.innerInstructions ||
1337
+ tx.meta.innerInstructions.length <= 0) {
1338
+ return;
1339
+ }
1340
+ /// We only care about the very last inner instruction as it contains the
1341
+ /// PublicTransactionEvent
1342
+ tx.meta.innerInstructions.forEach(ix => {
1343
+ if (ix.instructions.length > 0) {
1344
+ const ixInner = ix.instructions[ix.instructions.length - 1];
1345
+ // Type guard for partially parsed web3js types.
1346
+ if ('data' in ixInner &&
1347
+ ixInner.data &&
1348
+ ixInner.programId.toBase58() === noopProgram.toBase58()) {
1349
+ const data = bs58.decode(ixInner.data);
1350
+ const decodedEvent = deserializeFn(data, tx);
1351
+ if (decodedEvent !== null && decodedEvent !== undefined) {
1352
+ transactions.push(decodedEvent);
1353
+ }
1354
+ }
1355
+ }
1356
+ });
1357
+ });
1358
+ return transactions;
1359
+ };
1360
+ // TODO: make it type safe. have to reimplement the types from the IDL.
1361
+ const parsePublicTransactionEventWithIdl = (data) => {
1362
+ const numericData = Buffer.from(data.map(byte => byte));
1363
+ try {
1364
+ return LightSystemProgram.program.coder.types.decode('PublicTransactionEvent', numericData);
1365
+ }
1366
+ catch (error) {
1367
+ console.error('Error deserializing event:', error);
1368
+ return null;
1369
+ }
1370
+ };
1371
+
1372
+ const DEFAULT_ZERO = '0';
1373
+ /**
1374
+ * @callback hashFunction
1375
+ * @param left Left leaf
1376
+ * @param right Right leaf
1377
+ */
1378
+ /**
1379
+ * Merkle tree
1380
+ */
1381
+ class MerkleTree {
1382
+ /**
1383
+ * Constructor
1384
+ * @param {number} levels Number of levels in the tree
1385
+ * @param {Array} [elements] Initial elements
1386
+ * @param {Object} options
1387
+ * @param {hashFunction} [options.hashFunction] Function used to hash 2 leaves
1388
+ * @param [options.zeroElement] Value for non-existent leaves
1389
+ */
1390
+ levels;
1391
+ capacity;
1392
+ zeroElement;
1393
+ _zeros;
1394
+ _layers;
1395
+ _lightWasm;
1396
+ constructor(levels, lightWasm, elements = [], { zeroElement = DEFAULT_ZERO } = {}) {
1397
+ this.levels = levels;
1398
+ this.capacity = 2 ** levels;
1399
+ this.zeroElement = zeroElement;
1400
+ this._lightWasm = lightWasm;
1401
+ if (elements.length > this.capacity) {
1402
+ throw new Error('Tree is full');
1403
+ }
1404
+ this._zeros = [];
1405
+ this._layers = [];
1406
+ this._layers[0] = elements;
1407
+ this._zeros[0] = this.zeroElement;
1408
+ for (let i = 1; i <= levels; i++) {
1409
+ this._zeros[i] = this._lightWasm.poseidonHashString([
1410
+ this._zeros[i - 1],
1411
+ this._zeros[i - 1],
1412
+ ]);
1413
+ }
1414
+ this._rebuild();
1415
+ }
1416
+ _rebuild() {
1417
+ for (let level = 1; level <= this.levels; level++) {
1418
+ this._layers[level] = [];
1419
+ for (let i = 0; i < Math.ceil(this._layers[level - 1].length / 2); i++) {
1420
+ this._layers[level][i] = this._lightWasm.poseidonHashString([
1421
+ this._layers[level - 1][i * 2],
1422
+ i * 2 + 1 < this._layers[level - 1].length
1423
+ ? this._layers[level - 1][i * 2 + 1]
1424
+ : this._zeros[level - 1],
1425
+ ]);
1426
+ }
1427
+ }
1428
+ }
1429
+ /**
1430
+ * Get tree root
1431
+ * @returns {*}
1432
+ */
1433
+ root() {
1434
+ return this._layers[this.levels].length > 0
1435
+ ? this._layers[this.levels][0]
1436
+ : this._zeros[this.levels];
1437
+ }
1438
+ /**
1439
+ * Insert new element into the tree
1440
+ * @param element Element to insert
1441
+ */
1442
+ insert(element) {
1443
+ if (this._layers[0].length >= this.capacity) {
1444
+ throw new Error('Tree is full');
1445
+ }
1446
+ this.update(this._layers[0].length, element);
1447
+ }
1448
+ /**
1449
+ * Insert multiple elements into the tree. Tree will be fully rebuilt during this operation.
1450
+ * @param {Array} elements Elements to insert
1451
+ */
1452
+ bulkInsert(elements) {
1453
+ if (this._layers[0].length + elements.length > this.capacity) {
1454
+ throw new Error('Tree is full');
1455
+ }
1456
+ this._layers[0].push(...elements);
1457
+ this._rebuild();
1458
+ }
1459
+ // TODO: update does not work debug
1460
+ /**
1461
+ * Change an element in the tree
1462
+ * @param {number} index Index of element to change
1463
+ * @param element Updated element value
1464
+ */
1465
+ update(index, element) {
1466
+ // index 0 and 1 and element is the commitment hash
1467
+ if (isNaN(Number(index)) ||
1468
+ index < 0 ||
1469
+ index > this._layers[0].length ||
1470
+ index >= this.capacity) {
1471
+ throw new Error('Insert index out of bounds: ' + index);
1472
+ }
1473
+ this._layers[0][index] = element;
1474
+ for (let level = 1; level <= this.levels; level++) {
1475
+ index >>= 1;
1476
+ this._layers[level][index] = this._lightWasm.poseidonHashString([
1477
+ this._layers[level - 1][index * 2],
1478
+ index * 2 + 1 < this._layers[level - 1].length
1479
+ ? this._layers[level - 1][index * 2 + 1]
1480
+ : this._zeros[level - 1],
1481
+ ]);
1482
+ }
1483
+ }
1484
+ /**
1485
+ * Get merkle path to a leaf
1486
+ * @param {number} index Leaf index to generate path for
1487
+ * @returns {{pathElements: number[], pathIndex: number[]}} An object containing adjacent elements and left-right index
1488
+ */
1489
+ path(index) {
1490
+ if (isNaN(Number(index)) ||
1491
+ index < 0 ||
1492
+ index >= this._layers[0].length) {
1493
+ throw new Error('Index out of bounds: ' + index);
1494
+ }
1495
+ const pathElements = [];
1496
+ const pathIndices = [];
1497
+ for (let level = 0; level < this.levels; level++) {
1498
+ pathIndices[level] = index % 2;
1499
+ pathElements[level] =
1500
+ (index ^ 1) < this._layers[level].length
1501
+ ? this._layers[level][index ^ 1]
1502
+ : this._zeros[level];
1503
+ index >>= 1;
1504
+ }
1505
+ return {
1506
+ pathElements,
1507
+ pathIndices,
1508
+ };
1509
+ }
1510
+ /**
1511
+ * Find an element in the tree
1512
+ * @param element An element to find
1513
+ * @param comparator A function that checks leaf value equality
1514
+ * @returns {number} Index if element is found, otherwise -1
1515
+ */
1516
+ indexOf(element, comparator = null) {
1517
+ if (comparator) {
1518
+ return this._layers[0].findIndex((el) => comparator(element, el));
1519
+ }
1520
+ else {
1521
+ return this._layers[0].indexOf(element);
1522
+ }
1523
+ }
1524
+ /**
1525
+ * Returns a copy of non-zero tree elements
1526
+ * @returns {Object[]}
1527
+ */
1528
+ elements() {
1529
+ return this._layers[0].slice();
1530
+ }
1531
+ /**
1532
+ * Serialize entire tree state including intermediate layers into a plain object
1533
+ * Deserializing it back will not require to recompute any hashes
1534
+ * Elements are not converted to a plain type, this is responsibility of the caller
1535
+ */
1536
+ serialize() {
1537
+ return {
1538
+ levels: this.levels,
1539
+ _zeros: this._zeros,
1540
+ _layers: this._layers,
1541
+ };
1542
+ }
1543
+ /**
1544
+ * Deserialize data into a MerkleTree instance
1545
+ * Make sure to provide the same hashFunction as was used in the source tree,
1546
+ * otherwise the tree state will be invalid
1547
+ *
1548
+ * @param data
1549
+ * @param hashFunction
1550
+ * @returns {MerkleTree}
1551
+ */
1552
+ static deserialize(data, hashFunction) {
1553
+ const instance = Object.assign(Object.create(this.prototype), data);
1554
+ instance._hash = hashFunction;
1555
+ instance.capacity = 2 ** instance.levels;
1556
+ instance.zeroElement = instance._zeros[0];
1557
+ return instance;
1558
+ }
1559
+ }
1560
+
1561
+ const placeholderValidityProof = () => ({
1562
+ a: Array.from({ length: 32 }, (_, i) => i + 1),
1563
+ b: Array.from({ length: 64 }, (_, i) => i + 1),
1564
+ c: Array.from({ length: 32 }, (_, i) => i + 1),
1565
+ });
1566
+ const checkValidityProofShape = (proof) => {
1567
+ if (proof.a.length !== 32 ||
1568
+ proof.b.length !== 64 ||
1569
+ proof.c.length !== 32) {
1570
+ throw new Error('ValidityProof has invalid shape');
1571
+ }
1572
+ };
1573
+ function proofFromJsonStruct(json) {
1574
+ const proofAX = deserializeHexStringToBeBytes(json.ar[0]);
1575
+ const proofAY = deserializeHexStringToBeBytes(json.ar[1]);
1576
+ const proofA = new Uint8Array([...proofAX, ...proofAY]);
1577
+ const proofBX0 = deserializeHexStringToBeBytes(json.bs[0][0]);
1578
+ const proofBX1 = deserializeHexStringToBeBytes(json.bs[0][1]);
1579
+ const proofBY0 = deserializeHexStringToBeBytes(json.bs[1][0]);
1580
+ const proofBY1 = deserializeHexStringToBeBytes(json.bs[1][1]);
1581
+ const proofB = new Uint8Array([
1582
+ ...proofBX0,
1583
+ ...proofBX1,
1584
+ ...proofBY0,
1585
+ ...proofBY1,
1586
+ ]);
1587
+ const proofCX = deserializeHexStringToBeBytes(json.krs[0]);
1588
+ const proofCY = deserializeHexStringToBeBytes(json.krs[1]);
1589
+ const proofC = new Uint8Array([...proofCX, ...proofCY]);
1590
+ const proofABC = { a: proofA, b: proofB, c: proofC };
1591
+ return proofABC;
1592
+ }
1593
+ // TODO: add unit test for negation
1594
+ // TODO: test if LE BE issue. unit test
1595
+ function negateAndCompressProof(proof) {
1596
+ const proofA = proof.a;
1597
+ const proofB = proof.b;
1598
+ const proofC = proof.c;
1599
+ const aXElement = proofA.slice(0, 32);
1600
+ const aYElement = new BN(proofA.slice(32, 64), 32, 'be');
1601
+ /// Negate
1602
+ const proofAIsPositive = yElementIsPositiveG1(aYElement) ? false : true;
1603
+ /// First byte of proofA is the bitmask
1604
+ aXElement[0] = addBitmaskToByte(aXElement[0], proofAIsPositive);
1605
+ const bXElement = proofB.slice(0, 64);
1606
+ const bYElement = proofB.slice(64, 128);
1607
+ const proofBIsPositive = yElementIsPositiveG2(new BN(bYElement.slice(0, 32), 32, 'be'), new BN(bYElement.slice(32, 64), 32, 'be'));
1608
+ bXElement[0] = addBitmaskToByte(bXElement[0], proofBIsPositive);
1609
+ const cXElement = proofC.slice(0, 32);
1610
+ const cYElement = proofC.slice(32, 64);
1611
+ const proofCIsPositive = yElementIsPositiveG1(new BN(cYElement, 32, 'be'));
1612
+ cXElement[0] = addBitmaskToByte(cXElement[0], proofCIsPositive);
1613
+ const compressedProof = {
1614
+ a: Array.from(aXElement),
1615
+ b: Array.from(bXElement),
1616
+ c: Array.from(cXElement),
1617
+ };
1618
+ return compressedProof;
1619
+ }
1620
+ function deserializeHexStringToBeBytes(hexStr) {
1621
+ // Using BN for simpler conversion from hex string to byte array
1622
+ const bn = new BN(hexStr.startsWith('0x') ? hexStr.substring(2) : hexStr, 'hex');
1623
+ return new Uint8Array(bn.toArray('be', 32));
1624
+ }
1625
+ function yElementIsPositiveG1(yElement) {
1626
+ return yElement.lte(FIELD_SIZE.sub(yElement));
1627
+ }
1628
+ function yElementIsPositiveG2(yElement1, yElement2) {
1629
+ const fieldMidpoint = FIELD_SIZE.div(new BN(2));
1630
+ // Compare the first component of the y coordinate
1631
+ if (yElement1.lt(fieldMidpoint)) {
1632
+ return true;
1633
+ }
1634
+ else if (yElement1.gt(fieldMidpoint)) {
1635
+ return false;
1636
+ }
1637
+ // If the first component is equal to the midpoint, compare the second component
1638
+ return yElement2.lt(fieldMidpoint);
1639
+ }
1640
+ // bitmask compatible with solana altbn128 compression syscall and arkworks' implementation
1641
+ // https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp/mod.rs#L580
1642
+ // https://github.com/arkworks-rs/algebra/blob/master/serialize/src/flags.rs#L18
1643
+ // fn u8_bitmask(value: u8, inf: bool, neg: bool) -> u8 {
1644
+ // let mut mask = 0;
1645
+ // match self {
1646
+ // inf => mask |= 1 << 6,
1647
+ // neg => mask |= 1 << 7,
1648
+ // _ => (),
1649
+ // }
1650
+ // mask
1651
+ // }
1652
+ function addBitmaskToByte(byte, yIsPositive) {
1653
+ if (!yIsPositive) {
1654
+ return (byte |= 1 << 7);
1655
+ }
1656
+ else {
1657
+ return byte;
1658
+ }
1659
+ }
1660
+ //@ts-ignore
1661
+ if (import.meta.vitest) {
1662
+ //@ts-ignore
1663
+ const { it, expect, describe } = import.meta.vitest;
1664
+ // Unit test for addBitmaskToByte function
1665
+ describe('addBitmaskToByte', () => {
1666
+ it('should add a bitmask to the byte if yIsPositive is false', () => {
1667
+ const byte = 0b00000000;
1668
+ const yIsPositive = false;
1669
+ const result = addBitmaskToByte(byte, yIsPositive);
1670
+ expect(result).toBe(0b10000000); // 128 in binary, which is 1 << 7
1671
+ });
1672
+ it('should not modify the byte if yIsPositive is true', () => {
1673
+ const byte = 0b00000000;
1674
+ const yIsPositive = true;
1675
+ const result = addBitmaskToByte(byte, yIsPositive);
1676
+ expect(result).toBe(0b00000000);
1677
+ });
1678
+ });
1679
+ describe('test prover server', () => {
1680
+ const TEST_JSON = {
1681
+ ar: [
1682
+ '0x22bdaa3187d8fe294925a66fa0165a11bc9e07678fa2fc72402ebfd33d521c69',
1683
+ '0x2d18ff780b69898b4cdd8d7b6ac72d077799399f0f45e52665426456f3903584',
1684
+ ],
1685
+ bs: [
1686
+ [
1687
+ '0x138cc0962e49f76a701d2871d2799892c9782940095eb0429e979f336d2e162d',
1688
+ '0x2fe1bfbb15cbfb83d7e00ace23e45f890604003783eaf34affa35e0d6f4822bc',
1689
+ ],
1690
+ [
1691
+ '0x1a89264f82cc6e8ef1c696bea0b5803c28c0ba6ab61366bcb71e73a4135cae8d',
1692
+ '0xf778d857b3df01a4100265c9d014ce02d47425f0114685356165fa5ee3f3a26',
1693
+ ],
1694
+ ],
1695
+ krs: [
1696
+ '0x176b6ae9001f66832951e2d43a98a972667447bb1781f534b70cb010270dcdd3',
1697
+ '0xb748d5fac1686db28d94c02250af7eb4f28dfdabc8983305c45bcbc6e163eeb',
1698
+ ],
1699
+ };
1700
+ const COMPRESSED_PROOF_A = [
1701
+ 34, 189, 170, 49, 135, 216, 254, 41, 73, 37, 166, 111, 160, 22, 90,
1702
+ 17, 188, 158, 7, 103, 143, 162, 252, 114, 64, 46, 191, 211, 61, 82,
1703
+ 28, 105,
1704
+ ];
1705
+ const COMPRESSED_PROOF_B = [
1706
+ 147, 140, 192, 150, 46, 73, 247, 106, 112, 29, 40, 113, 210, 121,
1707
+ 152, 146, 201, 120, 41, 64, 9, 94, 176, 66, 158, 151, 159, 51, 109,
1708
+ 46, 22, 45, 47, 225, 191, 187, 21, 203, 251, 131, 215, 224, 10, 206,
1709
+ 35, 228, 95, 137, 6, 4, 0, 55, 131, 234, 243, 74, 255, 163, 94, 13,
1710
+ 111, 72, 34, 188,
1711
+ ];
1712
+ const COMPRESSED_PROOF_C = [
1713
+ 23, 107, 106, 233, 0, 31, 102, 131, 41, 81, 226, 212, 58, 152, 169,
1714
+ 114, 102, 116, 71, 187, 23, 129, 245, 52, 183, 12, 176, 16, 39, 13,
1715
+ 205, 211,
1716
+ ];
1717
+ it('should execute a compressed token mint', async () => {
1718
+ const proof = proofFromJsonStruct(TEST_JSON);
1719
+ const compressedProof = negateAndCompressProof(proof);
1720
+ expect(compressedProof.a).toEqual(COMPRESSED_PROOF_A);
1721
+ expect(compressedProof.b).toEqual(COMPRESSED_PROOF_B);
1722
+ expect(compressedProof.c).toEqual(COMPRESSED_PROOF_C);
1723
+ });
1724
+ });
1725
+ describe('Validity Proof Functions', () => {
1726
+ describe('placeholderValidityProof', () => {
1727
+ it('should create a validity proof with correct shape', () => {
1728
+ const validityProof = placeholderValidityProof();
1729
+ expect(validityProof.a.length).toBe(32);
1730
+ expect(validityProof.b.length).toBe(64);
1731
+ expect(validityProof.c.length).toBe(32);
1732
+ });
1733
+ });
1734
+ describe('checkValidityProofShape', () => {
1735
+ it('should not throw an error for valid proof shape', () => {
1736
+ const validProof = {
1737
+ a: Array.from(new Uint8Array(32)),
1738
+ b: Array.from(new Uint8Array(64)),
1739
+ c: Array.from(new Uint8Array(32)),
1740
+ };
1741
+ expect(() => checkValidityProofShape(validProof)).not.toThrow();
1742
+ });
1743
+ it('should throw an error for an invalid proof', () => {
1744
+ const invalidProof = {
1745
+ a: Array.from(new Uint8Array(31)), // incorrect length
1746
+ b: Array.from(new Uint8Array(64)),
1747
+ c: Array.from(new Uint8Array(32)),
1748
+ };
1749
+ expect(() => checkValidityProofShape(invalidProof)).toThrow('ValidityProof has invalid shape');
1750
+ });
1751
+ });
1752
+ });
1753
+ }
1754
+
1755
+ /**
1756
+ * @internal
1757
+ */
1758
+ const PublicKeyFromString = coerce(instance(PublicKey), string(), value => new PublicKey(value));
1759
+ /**
1760
+ * @internal
1761
+ */
1762
+ // TODO: use a BN254 class here for the 1st parameter
1763
+ const BN254FromString = coerce(instance(BN), string(), value => {
1764
+ return createBN254(value, 'base58');
1765
+ });
1766
+ const BNFromInt = coerce(instance(BN), number(), value => bn(value));
1767
+ const BNFromBase10String = coerce(instance(BN), string(), value => bn(value));
1768
+ /**
1769
+ * @internal
1770
+ */
1771
+ const Base64EncodedCompressedAccountDataResult = coerce(nullable(string()), string(), value => (value === '' ? null : value));
1772
+ /**
1773
+ * @internal
1774
+ */
1775
+ function createRpcResult(result) {
1776
+ return union([
1777
+ type({
1778
+ jsonrpc: literal('2.0'),
1779
+ id: string(),
1780
+ result,
1781
+ }),
1782
+ type({
1783
+ jsonrpc: literal('2.0'),
1784
+ id: string(),
1785
+ error: type({
1786
+ code: unknown(),
1787
+ message: string(),
1788
+ data: nullable(any()),
1789
+ }),
1790
+ }),
1791
+ ]);
1792
+ }
1793
+ /**
1794
+ * @internal
1795
+ */
1796
+ const UnknownRpcResult = createRpcResult(unknown());
1797
+ /**
1798
+ * @internal
1799
+ */
1800
+ function jsonRpcResult(schema) {
1801
+ return coerce(createRpcResult(schema), UnknownRpcResult, value => {
1802
+ if ('error' in value) {
1803
+ return value;
1804
+ }
1805
+ else {
1806
+ return {
1807
+ ...value,
1808
+ result: create(value.result, schema),
1809
+ };
1810
+ }
1811
+ });
1812
+ }
1813
+ /**
1814
+ * @internal
1815
+ */
1816
+ function jsonRpcResultAndContext(value) {
1817
+ return jsonRpcResult(type({
1818
+ context: type({
1819
+ slot: number(),
1820
+ }),
1821
+ value,
1822
+ }));
1823
+ }
1824
+ /**
1825
+ * @internal
1826
+ */
1827
+ /// Compressed Account With Merkle Context
1828
+ const CompressedAccountResult = type({
1829
+ hash: BN254FromString,
1830
+ address: nullable(PublicKeyFromString),
1831
+ data: Base64EncodedCompressedAccountDataResult,
1832
+ dataHash: nullable(BN254FromString),
1833
+ discriminator: BNFromInt,
1834
+ owner: PublicKeyFromString,
1835
+ lamports: BNFromInt,
1836
+ tree: nullable(PublicKeyFromString), // TODO: should not be nullable
1837
+ seq: nullable(BNFromInt),
1838
+ slotUpdated: BNFromInt,
1839
+ leafIndex: number(),
1840
+ });
1841
+ /**
1842
+ * @internal
1843
+ */
1844
+ /// TODO: update: delegatedAmount, state, programOwner/tokenOwner, data includes the values?, no closeAuth!
1845
+ const CompressedTokenAccountResult = type({
1846
+ address: nullable(PublicKeyFromString), // TODO: why is this here
1847
+ amount: BNFromBase10String, // why string
1848
+ delegate: nullable(PublicKeyFromString),
1849
+ closeAuthority: nullable(PublicKeyFromString), // TODO: remove
1850
+ isNative: boolean(),
1851
+ frozen: boolean(),
1852
+ mint: PublicKeyFromString,
1853
+ owner: PublicKeyFromString, // owner or user?
1854
+ //
1855
+ hash: BN254FromString,
1856
+ data: Base64EncodedCompressedAccountDataResult,
1857
+ dataHash: nullable(BN254FromString),
1858
+ discriminator: BNFromInt,
1859
+ lamports: BNFromInt,
1860
+ tree: PublicKeyFromString,
1861
+ seq: BNFromInt,
1862
+ // slotUpdated: BNFromInt, TODO: add owner (?): TODO: check whether this
1863
+ // implicitly assumes tokenprogram as account owner
1864
+ leafIndex: number(),
1865
+ });
1866
+ /**
1867
+ * @internal
1868
+ */
1869
+ const MultipleCompressedAccountsResult = type({
1870
+ items: array(CompressedAccountResult),
1871
+ });
1872
+ /**
1873
+ * @internal
1874
+ */
1875
+ const CompressedAccountsByOwnerResult = type({
1876
+ items: array(CompressedAccountResult),
1877
+ // cursor: array(number()), // paginated
1878
+ });
1879
+ /**
1880
+ * @internal
1881
+ */
1882
+ const CompressedTokenAccountsByOwnerOrDelegateResult = type({
1883
+ items: array(CompressedTokenAccountResult),
1884
+ // cursor: array(number()), // paginated TODO: add cursor to photon / docs update
1885
+ });
1886
+ /**
1887
+ * @internal
1888
+ */
1889
+ const SlotResult = number();
1890
+ /**
1891
+ * @internal
1892
+ */
1893
+ const HealthResult = string();
1894
+ /**
1895
+ * @internal
1896
+ */
1897
+ const MerkeProofResult = type({
1898
+ hash: BN254FromString,
1899
+ merkleTree: PublicKeyFromString,
1900
+ leafIndex: number(),
1901
+ proof: array(BN254FromString),
1902
+ });
1903
+ /**
1904
+ * @internal
1905
+ */
1906
+ const MultipleMerkleProofsResult = array(MerkeProofResult);
1907
+ /**
1908
+ * @internal
1909
+ */
1910
+ const BalanceResult = BNFromInt;
1911
+ /// TODO: we need to add: tree, nullifierQueue, leafIndex, rootIndex
1912
+ const AccountProofResult = type({
1913
+ hash: array(number()),
1914
+ root: array(number()),
1915
+ proof: array(array(number())),
1916
+ });
1917
+
1918
+ function createRpc(endpointOrWeb3JsConnection = 'http://127.0.0.1:8899', compressionApiEndpoint = 'http://localhost:8784', config) {
1919
+ if (typeof endpointOrWeb3JsConnection === 'string') {
1920
+ return new Rpc(endpointOrWeb3JsConnection, compressionApiEndpoint, undefined, config);
1921
+ }
1922
+ return new Rpc(endpointOrWeb3JsConnection.rpcEndpoint, compressionApiEndpoint, undefined, config);
1923
+ }
1924
+ const rpcRequest = async (rpcEndpoint, method, params = [], // TODO: array?
1925
+ convertToCamelCase = true) => {
1926
+ const body = JSON.stringify({
1927
+ jsonrpc: '2.0',
1928
+ id: 'test-account',
1929
+ method: method,
1930
+ params: params,
1931
+ });
1932
+ const response = await fetch(rpcEndpoint, {
1933
+ method: 'POST',
1934
+ headers: { 'Content-Type': 'application/json' },
1935
+ body: body,
1936
+ });
1937
+ if (!response.ok) {
1938
+ throw new Error(`HTTP error! status: ${response.status}`);
1939
+ }
1940
+ if (convertToCamelCase) {
1941
+ const res = await response.json();
1942
+ return toCamelCase(res);
1943
+ }
1944
+ return await response.json();
1945
+ };
1946
+ const mockNullifierQueue = defaultTestStateTreeAccounts().nullifierQueue;
1947
+ class Rpc extends Connection {
1948
+ /// TODO: can photon expose the default methods as well?
1949
+ compressionApiEndpoint;
1950
+ constructor(endpoint, compressionApiEndpoint,
1951
+ // TODO: implement
1952
+ proverEndpoint, config) {
1953
+ super(endpoint, config || 'confirmed');
1954
+ this.compressionApiEndpoint = compressionApiEndpoint;
1955
+ }
1956
+ async getCompressedAccount(hash) {
1957
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getCompressedAccount', { hash: encodeBN254toBase58(hash) });
1958
+ const res = create(unsafeRes, jsonRpcResultAndContext(nullable(CompressedAccountResult)));
1959
+ if ('error' in res) {
1960
+ throw new SolanaJSONRPCError(res.error, `failed to get info for compressed account ${hash.toString()}`);
1961
+ }
1962
+ if (res.result.value === null) {
1963
+ return null;
1964
+ }
1965
+ const item = res.result.value;
1966
+ const account = createCompressedAccountWithMerkleContext(createMerkleContext(item.tree, mockNullifierQueue, item.hash.toArray(), item.leafIndex), item.owner, bn(item.lamports),
1967
+ // TODO: fix. add typesafety to the rest
1968
+ item.data
1969
+ ? {
1970
+ discriminator: item.discriminator.toArray('le'),
1971
+ data: Buffer.from(item.data, 'base64'),
1972
+ dataHash: item.dataHash.toArray('le'), //FIXME: need to calculate the hash or return from server
1973
+ }
1974
+ : undefined, item.address || undefined);
1975
+ return account;
1976
+ }
1977
+ async getCompressedBalance(hash) {
1978
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getCompressedBalance', { hash: encodeBN254toBase58(hash) });
1979
+ const res = create(unsafeRes, jsonRpcResultAndContext(BalanceResult));
1980
+ if ('error' in res) {
1981
+ throw new SolanaJSONRPCError(res.error, `failed to get balance for compressed account ${hash.toString()}`);
1982
+ }
1983
+ if (res.result.value === null) {
1984
+ return null;
1985
+ }
1986
+ return bn(res.result.value);
1987
+ }
1988
+ /** Retrieve the merkle proof for a compressed account */
1989
+ async getCompressedAccountProof(hash) {
1990
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getCompressedAccountProof', encodeBN254toBase58(hash));
1991
+ const res = create(unsafeRes, jsonRpcResultAndContext(MerkeProofResult));
1992
+ if ('error' in res) {
1993
+ throw new SolanaJSONRPCError(res.error, `failed to get proof for compressed account ${hash.toString()}`);
1994
+ }
1995
+ if (res.result.value === null) {
1996
+ throw new Error(`failed to get proof for compressed account ${hash.toString()}`);
1997
+ }
1998
+ const value = {
1999
+ hash: res.result.value.hash.toArray(),
2000
+ merkleTree: res.result.value.merkleTree,
2001
+ leafIndex: res.result.value.leafIndex,
2002
+ merkleProof: res.result.value.proof,
2003
+ nullifierQueue: mockNullifierQueue,
2004
+ rootIndex: 0, // TODO: add root index
2005
+ };
2006
+ return value;
2007
+ }
2008
+ async getMultipleCompressedAccounts(hashes) {
2009
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getMultipleCompressedAccounts', hashes.map(hash => encodeBN254toBase58(hash)));
2010
+ const res = create(unsafeRes, jsonRpcResultAndContext(MultipleCompressedAccountsResult));
2011
+ if ('error' in res) {
2012
+ throw new SolanaJSONRPCError(res.error, `failed to get info for compressed accounts ${hashes.map(hash => encodeBN254toBase58(hash)).join(', ')}`);
2013
+ }
2014
+ if (res.result.value === null) {
2015
+ return null;
2016
+ }
2017
+ const accounts = [];
2018
+ res.result.value.items.map((item) => {
2019
+ const account = createCompressedAccountWithMerkleContext(createMerkleContext(item.tree, mockNullifierQueue, item.hash.toArray(), item.leafIndex), item.owner, bn(item.lamports), item.data && {
2020
+ /// TODO: validate whether we need to convert to 'le' here
2021
+ discriminator: item.discriminator.toArray('le'),
2022
+ data: Buffer.from(item.data, 'base64'),
2023
+ dataHash: item.dataHash.toArray('le'), //FIXME: need to calculate the hash or return from server
2024
+ }, item.address);
2025
+ accounts.push(account);
2026
+ });
2027
+ return accounts;
2028
+ }
2029
+ /** Retrieve the merkle proof for a compressed account */
2030
+ async getMultipleCompressedAccountProofs(hashes) {
2031
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getMultipleCompressedAccountProofs', hashes.map(hash => encodeBN254toBase58(hash)));
2032
+ const res = create(unsafeRes, jsonRpcResultAndContext(array(MerkeProofResult)));
2033
+ if ('error' in res) {
2034
+ throw new SolanaJSONRPCError(res.error, `failed to get proofs for compressed accounts ${hashes.map(hash => encodeBN254toBase58(hash)).join(', ')}`);
2035
+ }
2036
+ if (res.result.value === null) {
2037
+ return null;
2038
+ }
2039
+ const merkleProofs = [];
2040
+ res.result.value.map((proof) => {
2041
+ const value = {
2042
+ hash: proof.hash.toArray(), // FIXME
2043
+ merkleTree: proof.merkleTree,
2044
+ leafIndex: proof.leafIndex,
2045
+ merkleProof: proof.proof.map((proof) => createBN254(proof)),
2046
+ nullifierQueue: mockNullifierQueue,
2047
+ rootIndex: 0, // TODO: add root index
2048
+ };
2049
+ merkleProofs.push(value);
2050
+ });
2051
+ return merkleProofs;
2052
+ }
2053
+ async getCompressedAccountsByOwner(owner) {
2054
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getCompressedAccountsByOwner', { owner: owner.toBase58() });
2055
+ const res = create(unsafeRes, jsonRpcResultAndContext(CompressedAccountsByOwnerResult));
2056
+ if ('error' in res) {
2057
+ throw new SolanaJSONRPCError(res.error, `failed to get info for compressed accounts owned by ${owner.toBase58()}`);
2058
+ }
2059
+ if (res.result.value === null) {
2060
+ return [];
2061
+ }
2062
+ const accounts = [];
2063
+ /// TODO: clean up. Make typesafe
2064
+ res.result.value.items.map((item) => {
2065
+ const account = createCompressedAccountWithMerkleContext(createMerkleContext(item.tree, mockNullifierQueue, item.hash.toArray(), item.leafIndex), item.owner, bn(item.lamports), item.data && {
2066
+ discriminator: item.discriminator.toArray('le'),
2067
+ data: Buffer.from(item.data, 'base64'),
2068
+ dataHash: item.dataHash.toArray('le'), //FIXME: need to calculate the hash or return from server
2069
+ }, item.address);
2070
+ accounts.push(account);
2071
+ });
2072
+ return accounts;
2073
+ }
2074
+ /// TODO: Implement self
2075
+ async getValidityProof(hashes) {
2076
+ const rpc = await getTestRpc();
2077
+ const proof = await rpc.getValidityProof(hashes);
2078
+ return proof;
2079
+ }
2080
+ async getHealth() {
2081
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getHealth');
2082
+ const res = create(unsafeRes, jsonRpcResult(HealthResult));
2083
+ if ('error' in res) {
2084
+ throw new SolanaJSONRPCError(res.error, 'failed to get health');
2085
+ }
2086
+ return res.result;
2087
+ }
2088
+ /** TODO: use from Connection */
2089
+ async getSlot() {
2090
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getSlot');
2091
+ const res = create(unsafeRes, jsonRpcResult(SlotResult));
2092
+ if ('error' in res) {
2093
+ throw new SolanaJSONRPCError(res.error, 'failed to get slot');
2094
+ }
2095
+ return res.result;
2096
+ }
2097
+ async getCompressedTokenAccountsByOwner(owner, options) {
2098
+ const unsafeRes = await rpcRequest(this.compressionApiEndpoint, 'getCompressedTokenAccountsByOwner', { owner: owner.toBase58(), mint: options?.mint?.toBase58() });
2099
+ const res = create(unsafeRes, jsonRpcResultAndContext(CompressedTokenAccountsByOwnerOrDelegateResult));
2100
+ if ('error' in res) {
2101
+ throw new SolanaJSONRPCError(res.error, `failed to get info for compressed accounts owned by ${owner.toBase58()}`);
2102
+ }
2103
+ if (res.result.value === null) {
2104
+ throw new Error('not implemented. NULL result');
2105
+ }
2106
+ const accounts = [];
2107
+ /// TODO: clean up. Make typesafe
2108
+ res.result.value.items.map((item) => {
2109
+ const account = createCompressedAccountWithMerkleContext(createMerkleContext(item.tree, mockNullifierQueue, item.hash.toArray(), item.leafIndex), new PublicKey('9sixVEthz2kMSKfeApZXHwuboT6DZuT6crAYJTciUCqE'), // TODO: photon should return programOwner
2110
+ bn(item.lamports), item.data && {
2111
+ discriminator: item.discriminator.toArray('le'),
2112
+ data: Buffer.from(item.data, 'base64'),
2113
+ dataHash: item.dataHash.toArray('le'), //FIXME: need to calculate the hash or return from server
2114
+ }, item.address);
2115
+ const tokenData = {
2116
+ mint: item.mint,
2117
+ owner: item.owner,
2118
+ amount: item.amount,
2119
+ delegate: item.delegate,
2120
+ state: 1, // TODO: dynamic
2121
+ isNative: null, // TODO: dynamic
2122
+ delegatedAmount: bn(0), // TODO: dynamic
2123
+ };
2124
+ accounts.push({
2125
+ compressedAccount: account,
2126
+ parsed: tokenData,
2127
+ });
2128
+ });
2129
+ /// TODO: consider custom sort. we're returning most recent first
2130
+ /// because thats how our tests expect it currently
2131
+ return accounts.sort((a, b) => b.compressedAccount.leafIndex - a.compressedAccount.leafIndex);
2132
+ }
2133
+ /// TODO: implement delegate
2134
+ async getCompressedTokenAccountsByDelegate(delegate, options) {
2135
+ throw new Error('Method not implemented.');
2136
+ }
2137
+ async getCompressedTokenAccountBalance(hash) {
2138
+ throw new Error('Method not implemented.');
2139
+ }
2140
+ }
2141
+
2142
+ function toHex(bnString) {
2143
+ return '0x' + new BN(bnString).toString(16);
2144
+ }
2145
+ /**
2146
+ * Simple mock rpc for unit tests that simulates the compression rpc interface.
2147
+ * Fetches, parses events and builds merkletree on-demand, i.e. it does not persist state.
2148
+ * Constraints:
2149
+ * - Can only index 1 merkletree
2150
+ * - Can only index up to 1000 transactions
2151
+ *
2152
+ * For advanced testing use photon: https://github.com/helius-labs/photon
2153
+ */
2154
+ class TestRpc extends Rpc {
2155
+ merkleTreeAddress;
2156
+ nullifierQueueAddress;
2157
+ lightWasm;
2158
+ depth;
2159
+ log = false;
2160
+ /**
2161
+ * Instantiate a mock RPC simulating the compression rpc interface.
2162
+ *
2163
+ * @param endpoint endpoint to the solana cluster (use for
2164
+ * localnet only)
2165
+ * @param hasher light wasm hasher instance
2166
+ * @param testRpcConfig Config for the mock rpc
2167
+ * @param proverEndpoint Optional endpoint to the prover server.
2168
+ * defaults to endpoint
2169
+ * @param connectionConfig Optional connection config
2170
+ */
2171
+ constructor(endpoint, hasher, proverEndpoint, testRpcConfig, connectionConfig) {
2172
+ super(endpoint, proverEndpoint, connectionConfig);
2173
+ const { merkleTreeAddress, nullifierQueueAddress, depth, log } = testRpcConfig ?? {};
2174
+ const { merkleTree, nullifierQueue, merkleTreeHeight } = defaultTestStateTreeAccounts();
2175
+ this.lightWasm = hasher;
2176
+ this.merkleTreeAddress = merkleTreeAddress ?? merkleTree;
2177
+ this.nullifierQueueAddress = nullifierQueueAddress ?? nullifierQueue;
2178
+ this.depth = depth ?? merkleTreeHeight;
2179
+ this.log = log ?? false;
2180
+ }
2181
+ /**
2182
+ * @internal
2183
+ * Returns newest first
2184
+ * */
2185
+ async getParsedEvents() {
2186
+ const { noopProgram, accountCompressionProgram } = defaultStaticAccountsStruct();
2187
+ /// Get raw transactions
2188
+ const signatures = (await this.getConfirmedSignaturesForAddress2(accountCompressionProgram, undefined, 'confirmed')).map(s => s.signature);
2189
+ const txs = await this.getParsedTransactions(signatures, {
2190
+ maxSupportedTransactionVersion: 0,
2191
+ commitment: 'confirmed',
2192
+ });
2193
+ /// Filter by NOOP program
2194
+ const transactionEvents = txs.filter((tx) => {
2195
+ if (!tx) {
2196
+ return false;
2197
+ }
2198
+ const accountKeys = tx.transaction.message.accountKeys;
2199
+ const hasSplNoopAddress = accountKeys.some((item) => {
2200
+ const itemStr = typeof item === 'string'
2201
+ ? item
2202
+ : item.pubkey.toBase58();
2203
+ return itemStr === noopProgram.toBase58();
2204
+ });
2205
+ return hasSplNoopAddress;
2206
+ });
2207
+ /// Parse events
2208
+ const parsedEvents = parseEvents(transactionEvents, parsePublicTransactionEventWithIdl);
2209
+ return parsedEvents;
2210
+ }
2211
+ /** Retrieve validity proof for compressed accounts */
2212
+ async getValidityProof(compressedAccountHashes) {
2213
+ /// rebuild tree
2214
+ const events = await this.getParsedEvents().then(events => events.reverse());
2215
+ const allLeaves = [];
2216
+ const allLeafIndices = [];
2217
+ for (const event of events) {
2218
+ for (let index = 0; index < event.outputCompressedAccounts.length; index++) {
2219
+ const hash = event.outputCompressedAccountHashes[index];
2220
+ allLeaves.push(hash);
2221
+ allLeafIndices.push(event.outputLeafIndices[index]);
2222
+ }
2223
+ }
2224
+ const tree = new MerkleTree(this.depth, this.lightWasm, allLeaves.map(leaf => bn(leaf).toString()));
2225
+ /// create merkle proofs
2226
+ const leafIndices = compressedAccountHashes.map(compressedAccountHash => tree.indexOf(compressedAccountHash.toString()));
2227
+ const hexPathElementsAll = leafIndices.map(leafIndex => {
2228
+ const pathElements = tree.path(leafIndex).pathElements;
2229
+ const hexPathElements = pathElements.map(value => toHex(value));
2230
+ return hexPathElements;
2231
+ });
2232
+ const roots = new Array(compressedAccountHashes.length).fill(toHex(tree.root()));
2233
+ const inputs = {
2234
+ roots,
2235
+ inPathIndices: leafIndices,
2236
+ inPathElements: hexPathElementsAll,
2237
+ leaves: compressedAccountHashes.map(compressedAccountHash => toHex(compressedAccountHash.toString())),
2238
+ };
2239
+ /// Validate
2240
+ compressedAccountHashes.forEach((compressedAccountHash, index) => {
2241
+ const leafIndex = leafIndices[index];
2242
+ const computedHash = tree.elements()[leafIndex].toString();
2243
+ if (computedHash !== compressedAccountHash.toString()) {
2244
+ throw new Error(`Mismatch at index ${index}: expected ${compressedAccountHash.toString()}, got ${computedHash}`);
2245
+ }
2246
+ });
2247
+ const inputsData = JSON.stringify(inputs);
2248
+ let logMsg = '';
2249
+ if (this.log) {
2250
+ logMsg = `Proof generation for depth:${this.depth} n:${compressedAccountHashes.length}`;
2251
+ console.time(logMsg);
2252
+ }
2253
+ // TODO: pass url into rpc constructor
2254
+ const SERVER_URL = 'http://localhost:3001';
2255
+ const INCLUSION_PROOF_URL = `${SERVER_URL}/inclusion`;
2256
+ const response = await axios.post(INCLUSION_PROOF_URL, inputsData);
2257
+ const parsed = proofFromJsonStruct(response.data);
2258
+ const compressedProof = negateAndCompressProof(parsed);
2259
+ if (this.log)
2260
+ console.timeEnd(logMsg);
2261
+ // TODO: in prover server, fix property names
2262
+ const value = {
2263
+ compressedProof,
2264
+ roots: roots,
2265
+ // TODO: temporary
2266
+ rootIndices: leafIndices.map(_ => allLeafIndices.length),
2267
+ leafIndices,
2268
+ leaves: compressedAccountHashes,
2269
+ merkleTree: this.merkleTreeAddress,
2270
+ nullifierQueue: this.nullifierQueueAddress,
2271
+ };
2272
+ return value;
2273
+ }
2274
+ }
2275
+
2276
+ let c = 1;
2277
+ const ALICE = getTestKeypair(255);
2278
+ const BOB = getTestKeypair(254);
2279
+ const CHARLIE = getTestKeypair(253);
2280
+ const DAVE = getTestKeypair(252);
2281
+ async function newAccountWithLamports(rpc, lamports = 1000000000, counter = undefined) {
2282
+ const account = getTestKeypair(counter);
2283
+ const sig = await rpc.requestAirdrop(account.publicKey, lamports);
2284
+ await confirmTx(rpc, sig);
2285
+ return account;
2286
+ }
2287
+ function getConnection() {
2288
+ const url = 'http://127.0.0.1:8899';
2289
+ const connection = new Connection(url, 'confirmed');
2290
+ return connection;
2291
+ }
2292
+ /**
2293
+ * Returns a mock RPC instance for use in unit tests.
2294
+ *
2295
+ * @param endpoint RPC endpoint URL. Defaults to
2296
+ * 'http://127.0.0.1:8899'.
2297
+ * @param proverEndpoint Prover server endpoint URL. Defaults to
2298
+ * 'http://localhost:3001'.
2299
+ * @param lightWasm Wasm hasher instance.
2300
+ * @param merkleTreeAddress Address of the merkle tree to index. Defaults
2301
+ * to the public default test state tree.
2302
+ * @param nullifierQueueAddress Optional address of the associated nullifier
2303
+ * queue.
2304
+ * @param depth Depth of the merkle tree.
2305
+ * @param log Log proof generation time.
2306
+ */
2307
+ async function getTestRpc(endpoint = 'http://127.0.0.1:8899', proverEndpoint = 'http://localhost:3001', lightWasm, merkleTreeAddress, nullifierQueueAddress, depth, log = false) {
2308
+ lightWasm = lightWasm || (await WasmFactory.getInstance());
2309
+ const defaultAccounts = defaultTestStateTreeAccounts();
2310
+ return new TestRpc(endpoint, lightWasm, proverEndpoint, {
2311
+ merkleTreeAddress: merkleTreeAddress || defaultAccounts.merkleTree,
2312
+ nullifierQueueAddress: nullifierQueueAddress || defaultAccounts.nullifierQueue,
2313
+ depth: depth || defaultAccounts.merkleTreeHeight,
2314
+ log,
2315
+ });
2316
+ }
2317
+ /**
2318
+ * For use in tests.
2319
+ * Generate a unique keypair by passing in a counter <255. If no counter
2320
+ * is supplied, it uses and increments a global counter.
2321
+ */
2322
+ function getTestKeypair(counter = undefined) {
2323
+ if (!counter) {
2324
+ counter = c;
2325
+ c++;
2326
+ }
2327
+ if (counter > 255) {
2328
+ throw new Error('Counter must be <= 255');
2329
+ }
2330
+ const seed = new Uint8Array(32);
2331
+ seed[0] = counter;
2332
+ return Keypair.fromSeed(seed);
2333
+ }
2334
+ //@ts-ignore
2335
+ if (import.meta.vitest) {
2336
+ //@ts-ignore
2337
+ const { describe, it, expect } = import.meta.vitest;
2338
+ describe('getTestKeypair', () => {
2339
+ it('should generate a keypair with a specific counter', () => {
2340
+ const keypair = getTestKeypair(10);
2341
+ expect(keypair).toBeInstanceOf(Keypair);
2342
+ expect(keypair.publicKey).toBeDefined();
2343
+ expect(keypair.secretKey).toBeDefined();
2344
+ });
2345
+ it('should throw an error if counter is greater than 255', () => {
2346
+ const testFn = () => getTestKeypair(256);
2347
+ expect(testFn).toThrow('Counter must be <= 255');
2348
+ });
2349
+ it('should increment the global counter if no counter is provided', () => {
2350
+ const initialKeypair = getTestKeypair();
2351
+ const nextKeypair = getTestKeypair();
2352
+ expect(initialKeypair).not.toEqual(nextKeypair);
2353
+ });
2354
+ });
2355
+ }
2356
+
2357
+ const sumUpLamports = (accounts) => {
2358
+ return accounts.reduce((acc, account) => acc.add(bn(account.lamports)), bn(0));
2359
+ };
2360
+ const COMPRESSED_SOL_PDA_SEED = Buffer.from('compressed_sol_pda');
2361
+ class LightSystemProgram {
2362
+ /**
2363
+ * @internal
2364
+ */
2365
+ constructor() { }
2366
+ /**
2367
+ * Public key that identifies the CompressedPda program
2368
+ */
2369
+ static programId = new PublicKey(
2370
+ // TODO: can add check to ensure its consistent with the idl
2371
+ '6UqiSPd2mRCTTwkzhcs1M6DGYsqHWd5jiPueX3LwDMXQ');
2372
+ static _program = null;
2373
+ static get program() {
2374
+ if (!this._program) {
2375
+ this.initializeProgram();
2376
+ }
2377
+ return this._program;
2378
+ }
2379
+ /**
2380
+ * @internal
2381
+ * Cwct1kQLwJm8Z3HetLu8m4SXkhD6FZ5fXbJQCxTxPnGY
2382
+ */
2383
+ static deriveCompressedSolPda() {
2384
+ const seeds = [COMPRESSED_SOL_PDA_SEED];
2385
+ const [address, _] = PublicKey.findProgramAddressSync(seeds, this.programId);
2386
+ return address;
2387
+ }
2388
+ /**
2389
+ * Initializes the program statically if not already initialized.
2390
+ */
2391
+ static initializeProgram() {
2392
+ if (!this._program) {
2393
+ const mockKeypair = Keypair.generate();
2394
+ const mockConnection = new Connection('http://127.0.0.1:8899', 'confirmed');
2395
+ const mockProvider = new AnchorProvider(mockConnection, useWallet(mockKeypair), {
2396
+ commitment: 'confirmed',
2397
+ preflightCommitment: 'confirmed',
2398
+ });
2399
+ setProvider(mockProvider);
2400
+ this._program = new Program(IDL$3, this.programId, mockProvider);
2401
+ }
2402
+ }
2403
+ static createTransferOutputState(inputCompressedAccounts, toAddress, lamports) {
2404
+ lamports = bn(lamports);
2405
+ const inputLamports = sumUpLamports(inputCompressedAccounts);
2406
+ const changeLamports = inputLamports.sub(lamports);
2407
+ validateSufficientBalance(changeLamports);
2408
+ if (changeLamports.eq(bn(0))) {
2409
+ return [createCompressedAccount(toAddress, lamports)];
2410
+ }
2411
+ validateSameOwner(inputCompressedAccounts);
2412
+ const outputCompressedAccounts = [
2413
+ createCompressedAccount(toAddress, lamports),
2414
+ createCompressedAccount(inputCompressedAccounts[0].owner, changeLamports),
2415
+ ];
2416
+ return outputCompressedAccounts;
2417
+ }
2418
+ static createDecompressOutputState(inputCompressedAccounts, lamports) {
2419
+ lamports = bn(lamports);
2420
+ const inputLamports = sumUpLamports(inputCompressedAccounts);
2421
+ const changeLamports = inputLamports.sub(lamports);
2422
+ validateSufficientBalance(changeLamports);
2423
+ /// lamports gets decompressed
2424
+ if (changeLamports.eq(bn(0))) {
2425
+ return [];
2426
+ }
2427
+ validateSameOwner(inputCompressedAccounts);
2428
+ const outputCompressedAccounts = [
2429
+ createCompressedAccount(inputCompressedAccounts[0].owner, changeLamports),
2430
+ ];
2431
+ return outputCompressedAccounts;
2432
+ }
2433
+ /**
2434
+ * Creates a transaction instruction that transfers compressed lamports from
2435
+ * one owner to another.
2436
+ */
2437
+ static async transfer(params) {
2438
+ const { payer, recentValidityProof, recentInputStateRootIndices, inputCompressedAccounts, lamports, outputStateTrees, } = params;
2439
+ /// Create output state
2440
+ const outputCompressedAccounts = this.createTransferOutputState(inputCompressedAccounts, params.toAddress, lamports);
2441
+ /// Pack accounts
2442
+ const { packedInputCompressedAccounts, outputStateMerkleTreeIndices, remainingAccountMetas, } = packCompressedAccounts(inputCompressedAccounts, outputCompressedAccounts.length, outputStateTrees);
2443
+ /// Encode instruction data
2444
+ const data = this.program.coder.types.encode('InstructionDataTransfer', {
2445
+ proof: recentValidityProof,
2446
+ inputRootIndices: recentInputStateRootIndices,
2447
+ /// TODO: here and on-chain: option<newAddressInputs> or similar.
2448
+ newAddressParams: [],
2449
+ inputCompressedAccountsWithMerkleContext: packedInputCompressedAccounts,
2450
+ outputCompressedAccounts,
2451
+ outputStateMerkleTreeAccountIndices: Buffer.from(outputStateMerkleTreeIndices),
2452
+ relayFee: null,
2453
+ compressionLamports: null,
2454
+ isCompress: false,
2455
+ });
2456
+ /// Build anchor instruction
2457
+ const instruction = await this.program.methods
2458
+ .executeCompressedTransaction(data)
2459
+ .accounts({
2460
+ ...defaultStaticAccountsStruct(),
2461
+ signer: payer,
2462
+ invokingProgram: this.programId,
2463
+ compressedSolPda: null,
2464
+ compressionRecipient: null,
2465
+ systemProgram: null,
2466
+ })
2467
+ .remainingAccounts(remainingAccountMetas)
2468
+ .instruction();
2469
+ const instructions = [
2470
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 1000000 }),
2471
+ instruction,
2472
+ ];
2473
+ return instructions;
2474
+ }
2475
+ /**
2476
+ * Initialize the compressed sol pda
2477
+ */
2478
+ static async initCompressedSolPda(feePayer) {
2479
+ const accounts = {
2480
+ feePayer,
2481
+ compressedSolPda: this.deriveCompressedSolPda(),
2482
+ systemProgram: SystemProgram.programId,
2483
+ };
2484
+ const instruction = await this.program.methods
2485
+ .initCompressSolPda()
2486
+ .accounts(accounts)
2487
+ .instruction();
2488
+ return instruction;
2489
+ }
2490
+ /**
2491
+ * Creates a transaction instruction that transfers compressed lamports from
2492
+ * one owner to another.
2493
+ */
2494
+ // TODO: add support for non-fee-payer owner
2495
+ static async compress(params) {
2496
+ const { payer, outputStateTree, toAddress } = params;
2497
+ /// Create output state
2498
+ const lamports = bn(params.lamports);
2499
+ const outputCompressedAccount = createCompressedAccount(toAddress, lamports);
2500
+ /// Pack accounts
2501
+ const { packedInputCompressedAccounts, outputStateMerkleTreeIndices, remainingAccountMetas, } = packCompressedAccounts([], 1, outputStateTree);
2502
+ /// Encode instruction data
2503
+ const data = this.program.coder.types.encode('InstructionDataTransfer', {
2504
+ proof: placeholderValidityProof(),
2505
+ inputRootIndices: [],
2506
+ /// TODO: here and on-chain: option<newAddressInputs> or similar.
2507
+ newAddressParams: [],
2508
+ inputCompressedAccountsWithMerkleContext: packedInputCompressedAccounts,
2509
+ outputCompressedAccounts: [outputCompressedAccount],
2510
+ outputStateMerkleTreeAccountIndices: Buffer.from(new Uint8Array(outputStateMerkleTreeIndices)),
2511
+ relayFee: null,
2512
+ compressionLamports: lamports,
2513
+ isCompress: true,
2514
+ });
2515
+ /// Build anchor instruction
2516
+ const instruction = await this.program.methods
2517
+ .executeCompressedTransaction(data)
2518
+ .accounts({
2519
+ ...defaultStaticAccountsStruct(),
2520
+ signer: payer,
2521
+ invokingProgram: this.programId,
2522
+ compressedSolPda: this.deriveCompressedSolPda(),
2523
+ compressionRecipient: null,
2524
+ systemProgram: SystemProgram.programId,
2525
+ })
2526
+ .remainingAccounts(remainingAccountMetas)
2527
+ .instruction();
2528
+ const instructions = [
2529
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 1000000 }),
2530
+ instruction,
2531
+ ];
2532
+ return instructions;
2533
+ }
2534
+ /**
2535
+ * Creates a transaction instruction that transfers compressed lamports from
2536
+ * one owner to another.
2537
+ */
2538
+ /// TODO: add check that outputStateTree is provided or supplemented if change exists
2539
+ static async decompress(params) {
2540
+ const { payer, outputStateTree, toAddress } = params;
2541
+ /// Create output state
2542
+ const lamports = bn(params.lamports);
2543
+ const outputCompressedAccounts = this.createDecompressOutputState(params.inputCompressedAccounts, lamports);
2544
+ /// Pack accounts
2545
+ const { packedInputCompressedAccounts, outputStateMerkleTreeIndices, remainingAccountMetas, } = packCompressedAccounts(params.inputCompressedAccounts, outputCompressedAccounts.length, outputStateTree);
2546
+ /// Encode instruction data
2547
+ const data = this.program.coder.types.encode('InstructionDataTransfer', {
2548
+ proof: params.recentValidityProof,
2549
+ inputRootIndices: params.recentInputStateRootIndices,
2550
+ /// TODO: here and on-chain: option<newAddressInputs> or similar.
2551
+ newAddressParams: [],
2552
+ inputCompressedAccountsWithMerkleContext: packedInputCompressedAccounts,
2553
+ outputCompressedAccounts: outputCompressedAccounts,
2554
+ outputStateMerkleTreeAccountIndices: Buffer.from(new Uint8Array(outputStateMerkleTreeIndices)),
2555
+ relayFee: null,
2556
+ compressionLamports: lamports,
2557
+ isCompress: false,
2558
+ });
2559
+ /// Build anchor instruction
2560
+ const instruction = await this.program.methods
2561
+ .executeCompressedTransaction(data)
2562
+ .accounts({
2563
+ ...defaultStaticAccountsStruct(),
2564
+ signer: payer,
2565
+ invokingProgram: this.programId,
2566
+ compressedSolPda: this.deriveCompressedSolPda(),
2567
+ compressionRecipient: toAddress,
2568
+ systemProgram: SystemProgram.programId,
2569
+ })
2570
+ .remainingAccounts(remainingAccountMetas)
2571
+ .instruction();
2572
+ const instructions = [
2573
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 1000000 }),
2574
+ instruction,
2575
+ ];
2576
+ return instructions;
2577
+ }
2578
+ }
2579
+ // /**
2580
+ // * @internal
2581
+ // *
2582
+ // * Selects the minimal number of compressed accounts for a transfer
2583
+ // * 1. Sorts the accounts by amount in descending order
2584
+ // * 2. Accumulates the lamports amount until it is greater than or equal to the transfer
2585
+ // * amount
2586
+ // */
2587
+ // function _selectMinCompressedAccountsForTransfer(
2588
+ // compressedAccounts: (UtxoWithMerkleContext | UtxoWithMerkleProof)[],
2589
+ // transferAmount: BN,
2590
+ // ): {
2591
+ // selectedAccounts: (UtxoWithMerkleContext | UtxoWithMerkleProof)[];
2592
+ // total: BN;
2593
+ // } {
2594
+ // let accumulatedAmount = bn(0);
2595
+ // const selectedAccounts: (UtxoWithMerkleContext | UtxoWithMerkleProof)[] =
2596
+ // [];
2597
+ // compressedAccounts.sort((a, b) =>
2598
+ // Number(bn(b.lamports).sub(bn(a.lamports))),
2599
+ // );
2600
+ // for (const utxo of compressedAccounts) {
2601
+ // if (accumulatedAmount.gte(bn(transferAmount))) break;
2602
+ // accumulatedAmount = accumulatedAmount.add(bn(utxo.lamports));
2603
+ // selectedAccounts.push(utxo);
2604
+ // }
2605
+ // if (accumulatedAmount.lt(bn(transferAmount))) {
2606
+ // throw new Error('Not enough balance for transfer');
2607
+ // }
2608
+ // return { selectedAccounts, total: accumulatedAmount };
2609
+ // }
2610
+
2611
+ /**
2612
+ * Init the SOL omnibus account for Light
2613
+ *
2614
+ * @param rpc RPC to use
2615
+ * @param payer Payer of the transaction and initialization fees
2616
+ * @param lamports Amount of lamports to compress
2617
+ * @param toAddress Address of the recipient compressed account
2618
+ * @param outputStateTree Optional output state tree. Defaults to a current shared state tree.
2619
+ * @param confirmOptions Options for confirming the transaction
2620
+ *
2621
+ * @return Transaction signature
2622
+ */
2623
+ /// TODO: add multisig support
2624
+ /// TODO: add support for payer != owner
2625
+ async function compressLamports(rpc, payer, lamports, toAddress, outputStateTree, confirmOptions) {
2626
+ const { blockhash } = await rpc.getLatestBlockhash();
2627
+ const ixs = await LightSystemProgram.compress({
2628
+ payer: payer.publicKey,
2629
+ toAddress,
2630
+ lamports,
2631
+ outputStateTree: outputStateTree
2632
+ ? outputStateTree
2633
+ : defaultTestStateTreeAccounts().merkleTree, // TODO: should fetch the current shared state tree
2634
+ });
2635
+ const tx = buildAndSignTx(ixs, payer, blockhash, []);
2636
+ const txId = await sendAndConfirmTx(rpc, tx, confirmOptions);
2637
+ return txId;
2638
+ }
2639
+
2640
+ /**
2641
+ * Init the SOL omnibus account for Light
2642
+ *
2643
+ * @param rpc RPC to use
2644
+ * @param payer Payer of the transaction and initialization fees
2645
+ * @param lamports Amount of lamports to compress
2646
+ * @param toAddress Address of the recipient compressed account
2647
+ * @param outputStateTree Optional output state tree. Defaults to a current shared state tree.
2648
+ * @param confirmOptions Options for confirming the transaction
2649
+ *
2650
+ * @return Transaction signature
2651
+ */
2652
+ /// TODO: add multisig support
2653
+ /// TODO: add support for payer != owner
2654
+ async function decompressLamports(rpc, payer, lamports, recipient, outputStateTree, confirmOptions) {
2655
+ /// TODO: use dynamic state tree and nullifier queue
2656
+ const userCompressedAccountsWithMerkleContext = await rpc.getCompressedAccountsByOwner(payer.publicKey);
2657
+ lamports = bn(lamports);
2658
+ const inputLamports = sumUpLamports(userCompressedAccountsWithMerkleContext);
2659
+ if (lamports.gt(inputLamports)) {
2660
+ throw new Error(`Not enough compressed lamports. Expected ${lamports}, got ${inputLamports}`);
2661
+ }
2662
+ const proof = await rpc.getValidityProof(userCompressedAccountsWithMerkleContext.map(x => bn(x.hash)));
2663
+ const { blockhash } = await rpc.getLatestBlockhash();
2664
+ const ixs = await LightSystemProgram.decompress({
2665
+ payer: payer.publicKey,
2666
+ toAddress: recipient,
2667
+ outputStateTree: outputStateTree,
2668
+ inputCompressedAccounts: userCompressedAccountsWithMerkleContext,
2669
+ recentValidityProof: proof.compressedProof,
2670
+ recentInputStateRootIndices: proof.rootIndices,
2671
+ lamports,
2672
+ });
2673
+ const tx = buildAndSignTx(ixs, payer, blockhash, []);
2674
+ const txId = await sendAndConfirmTx(rpc, tx, confirmOptions);
2675
+ return txId;
2676
+ }
2677
+
2678
+ /** @internal remove signer from signers if part of signers */
2679
+ function dedupeSigner(signer, signers) {
2680
+ if (signers.includes(signer)) {
2681
+ return signers.filter(s => s.publicKey.toString() !== signer.publicKey.toString());
2682
+ }
2683
+ return signers;
2684
+ }
2685
+
2686
+ /**
2687
+ * Init the SOL omnibus account for Light
2688
+ *
2689
+ * @param rpc RPC to use
2690
+ * @param payer Payer of the transaction and initialization fees
2691
+ * @param initAuthority Init authority.
2692
+ * @param confirmOptions Options for confirming the transaction
2693
+ *
2694
+ * @return Transaction signature
2695
+ */
2696
+ /// TODO: add multisig support
2697
+ async function initSolOmnibusAccount(rpc, payer, initAuthority, confirmOptions) {
2698
+ const { blockhash } = await rpc.getLatestBlockhash();
2699
+ const additionalSigners = dedupeSigner(payer, initAuthority ? [initAuthority] : []);
2700
+ const ix = await LightSystemProgram.initCompressedSolPda(initAuthority ? initAuthority.publicKey : payer.publicKey);
2701
+ const tx = buildAndSignTx([ix], payer, blockhash, additionalSigners);
2702
+ const txId = await sendAndConfirmTx(rpc, tx, confirmOptions);
2703
+ return txId;
2704
+ }
2705
+
2706
+ const IDL$2 = {
2707
+ version: '0.3.1',
2708
+ name: 'account_compression',
2709
+ constants: [
2710
+ {
2711
+ name: 'GROUP_AUTHORITY_SEED',
2712
+ type: 'bytes',
2713
+ value: '[103, 114, 111, 117, 112, 95, 97, 117, 116, 104, 111, 114, 105, 116, 121]',
2714
+ },
2715
+ {
2716
+ name: 'STATE_MERKLE_TREE_HEIGHT',
2717
+ type: 'u64',
2718
+ value: '26',
2719
+ },
2720
+ {
2721
+ name: 'STATE_MERKLE_TREE_CHANGELOG',
2722
+ type: 'u64',
2723
+ value: '1400',
2724
+ },
2725
+ {
2726
+ name: 'STATE_MERKLE_TREE_ROOTS',
2727
+ type: 'u64',
2728
+ value: '2400',
2729
+ },
2730
+ {
2731
+ name: 'STATE_MERKLE_TREE_CANOPY_DEPTH',
2732
+ type: 'u64',
2733
+ value: '10',
2734
+ },
2735
+ {
2736
+ name: 'STATE_INDEXED_ARRAY_INDICES',
2737
+ type: 'u16',
2738
+ value: '6857',
2739
+ },
2740
+ {
2741
+ name: 'STATE_INDEXED_ARRAY_VALUES',
2742
+ type: 'u16',
2743
+ value: '4800',
2744
+ },
2745
+ {
2746
+ name: 'STATE_INDEXED_ARRAY_SEQUENCE_THRESHOLD',
2747
+ type: 'u64',
2748
+ value: '2400',
2749
+ },
2750
+ {
2751
+ name: 'ADDRESS_MERKLE_TREE_HEIGHT',
2752
+ type: 'u64',
2753
+ value: '26',
2754
+ },
2755
+ {
2756
+ name: 'ADDRESS_MERKLE_TREE_CHANGELOG',
2757
+ type: 'u64',
2758
+ value: '1400',
2759
+ },
2760
+ {
2761
+ name: 'ADDRESS_MERKLE_TREE_ROOTS',
2762
+ type: 'u64',
2763
+ value: '2400',
2764
+ },
2765
+ {
2766
+ name: 'ADDRESS_MERKLE_TREE_CANOPY_DEPTH',
2767
+ type: 'u64',
2768
+ value: '10',
2769
+ },
2770
+ {
2771
+ name: 'ADDRESS_QUEUE_INDICES',
2772
+ type: 'u16',
2773
+ value: '6857',
2774
+ },
2775
+ {
2776
+ name: 'ADDRESS_QUEUE_VALUES',
2777
+ type: 'u16',
2778
+ value: '4800',
2779
+ },
2780
+ {
2781
+ name: 'ADDRESS_QUEUE_SEQUENCE_THRESHOLD',
2782
+ type: 'u64',
2783
+ value: '2400',
2784
+ },
2785
+ {
2786
+ name: 'PROGRAM_ID',
2787
+ type: 'string',
2788
+ value: '"5QPEJ5zDsVou9FQS3KCauKswM3VwBEBu4dpL9xTqkWwN"',
2789
+ },
2790
+ ],
2791
+ instructions: [
2792
+ {
2793
+ name: 'initializeAddressQueue',
2794
+ accounts: [
2795
+ {
2796
+ name: 'authority',
2797
+ isMut: true,
2798
+ isSigner: true,
2799
+ },
2800
+ {
2801
+ name: 'queue',
2802
+ isMut: true,
2803
+ isSigner: false,
2804
+ },
2805
+ ],
2806
+ args: [
2807
+ {
2808
+ name: 'index',
2809
+ type: 'u64',
2810
+ },
2811
+ {
2812
+ name: 'owner',
2813
+ type: 'publicKey',
2814
+ },
2815
+ {
2816
+ name: 'delegate',
2817
+ type: {
2818
+ option: 'publicKey',
2819
+ },
2820
+ },
2821
+ {
2822
+ name: 'associatedMerkleTree',
2823
+ type: {
2824
+ option: 'publicKey',
2825
+ },
2826
+ },
2827
+ {
2828
+ name: 'capacityIndices',
2829
+ type: 'u16',
2830
+ },
2831
+ {
2832
+ name: 'capacityValues',
2833
+ type: 'u16',
2834
+ },
2835
+ {
2836
+ name: 'sequenceThreshold',
2837
+ type: 'u64',
2838
+ },
2839
+ ],
2840
+ },
2841
+ {
2842
+ name: 'initializeAddressMerkleTree',
2843
+ accounts: [
2844
+ {
2845
+ name: 'authority',
2846
+ isMut: true,
2847
+ isSigner: true,
2848
+ },
2849
+ {
2850
+ name: 'merkleTree',
2851
+ isMut: true,
2852
+ isSigner: false,
2853
+ },
2854
+ ],
2855
+ args: [
2856
+ {
2857
+ name: 'index',
2858
+ type: 'u64',
2859
+ },
2860
+ {
2861
+ name: 'owner',
2862
+ type: 'publicKey',
2863
+ },
2864
+ {
2865
+ name: 'delegate',
2866
+ type: {
2867
+ option: 'publicKey',
2868
+ },
2869
+ },
2870
+ {
2871
+ name: 'height',
2872
+ type: 'u64',
2873
+ },
2874
+ {
2875
+ name: 'changelogSize',
2876
+ type: 'u64',
2877
+ },
2878
+ {
2879
+ name: 'rootsSize',
2880
+ type: 'u64',
2881
+ },
2882
+ {
2883
+ name: 'canopyDepth',
2884
+ type: 'u64',
2885
+ },
2886
+ ],
2887
+ },
2888
+ {
2889
+ name: 'insertAddresses',
2890
+ accounts: [
2891
+ {
2892
+ name: 'authority',
2893
+ isMut: true,
2894
+ isSigner: true,
2895
+ },
2896
+ {
2897
+ name: 'registeredProgramPda',
2898
+ isMut: false,
2899
+ isSigner: false,
2900
+ isOptional: true,
2901
+ },
2902
+ ],
2903
+ args: [
2904
+ {
2905
+ name: 'addresses',
2906
+ type: {
2907
+ vec: {
2908
+ array: ['u8', 32],
2909
+ },
2910
+ },
2911
+ },
2912
+ ],
2913
+ },
2914
+ {
2915
+ name: 'updateAddressMerkleTree',
2916
+ accounts: [
2917
+ {
2918
+ name: 'authority',
2919
+ isMut: true,
2920
+ isSigner: true,
2921
+ },
2922
+ {
2923
+ name: 'queue',
2924
+ isMut: true,
2925
+ isSigner: false,
2926
+ },
2927
+ {
2928
+ name: 'merkleTree',
2929
+ isMut: true,
2930
+ isSigner: false,
2931
+ },
2932
+ ],
2933
+ args: [
2934
+ {
2935
+ name: 'changelogIndex',
2936
+ type: 'u16',
2937
+ },
2938
+ {
2939
+ name: 'value',
2940
+ type: {
2941
+ array: ['u8', 32],
2942
+ },
2943
+ },
2944
+ {
2945
+ name: 'nextIndex',
2946
+ type: 'u64',
2947
+ },
2948
+ {
2949
+ name: 'nextValue',
2950
+ type: {
2951
+ array: ['u8', 32],
2952
+ },
2953
+ },
2954
+ {
2955
+ name: 'lowAddressIndex',
2956
+ type: 'u64',
2957
+ },
2958
+ {
2959
+ name: 'lowAddressValue',
2960
+ type: {
2961
+ array: ['u8', 32],
2962
+ },
2963
+ },
2964
+ {
2965
+ name: 'lowAddressNextIndex',
2966
+ type: 'u64',
2967
+ },
2968
+ {
2969
+ name: 'lowAddressNextValue',
2970
+ type: {
2971
+ array: ['u8', 32],
2972
+ },
2973
+ },
2974
+ {
2975
+ name: 'lowAddressProof',
2976
+ type: {
2977
+ array: [
2978
+ {
2979
+ array: ['u8', 32],
2980
+ },
2981
+ 16,
2982
+ ],
2983
+ },
2984
+ },
2985
+ {
2986
+ name: 'nextAddressProof',
2987
+ type: {
2988
+ array: ['u8', 128],
2989
+ },
2990
+ },
2991
+ ],
2992
+ },
2993
+ {
2994
+ name: 'initializeGroupAuthority',
2995
+ docs: [
2996
+ 'initialize group (a group can be used to give multiple programs acess to the same Merkle trees by registering the programs to the group)',
2997
+ ],
2998
+ accounts: [
2999
+ {
3000
+ name: 'authority',
3001
+ isMut: true,
3002
+ isSigner: true,
3003
+ },
3004
+ {
3005
+ name: 'groupAuthority',
3006
+ isMut: true,
3007
+ isSigner: false,
3008
+ },
3009
+ {
3010
+ name: 'systemProgram',
3011
+ isMut: false,
3012
+ isSigner: false,
3013
+ },
3014
+ ],
3015
+ args: [
3016
+ {
3017
+ name: 'seed',
3018
+ type: {
3019
+ array: ['u8', 32],
3020
+ },
3021
+ },
3022
+ {
3023
+ name: 'authority',
3024
+ type: 'publicKey',
3025
+ },
3026
+ ],
3027
+ },
3028
+ {
3029
+ name: 'updateGroupAuthority',
3030
+ accounts: [
3031
+ {
3032
+ name: 'authority',
3033
+ isMut: true,
3034
+ isSigner: true,
3035
+ },
3036
+ {
3037
+ name: 'groupAuthority',
3038
+ isMut: true,
3039
+ isSigner: false,
3040
+ },
3041
+ ],
3042
+ args: [
3043
+ {
3044
+ name: 'authority',
3045
+ type: 'publicKey',
3046
+ },
3047
+ ],
3048
+ },
3049
+ {
3050
+ name: 'registerProgramToGroup',
3051
+ accounts: [
3052
+ {
3053
+ name: 'authority',
3054
+ isMut: true,
3055
+ isSigner: true,
3056
+ },
3057
+ {
3058
+ name: 'registeredProgramPda',
3059
+ isMut: true,
3060
+ isSigner: false,
3061
+ },
3062
+ {
3063
+ name: 'groupAuthorityPda',
3064
+ isMut: true,
3065
+ isSigner: false,
3066
+ },
3067
+ {
3068
+ name: 'systemProgram',
3069
+ isMut: false,
3070
+ isSigner: false,
3071
+ },
3072
+ ],
3073
+ args: [
3074
+ {
3075
+ name: 'programId',
3076
+ type: 'publicKey',
3077
+ },
3078
+ ],
3079
+ },
3080
+ {
3081
+ name: 'initializeStateMerkleTree',
3082
+ docs: [
3083
+ 'Initializes a new Merkle tree from config bytes.',
3084
+ 'Index is an optional identifier and not checked by the program.',
3085
+ 'TODO: think the index over',
3086
+ ],
3087
+ accounts: [
3088
+ {
3089
+ name: 'authority',
3090
+ isMut: true,
3091
+ isSigner: true,
3092
+ },
3093
+ {
3094
+ name: 'merkleTree',
3095
+ isMut: true,
3096
+ isSigner: false,
3097
+ },
3098
+ {
3099
+ name: 'systemProgram',
3100
+ isMut: false,
3101
+ isSigner: false,
3102
+ },
3103
+ ],
3104
+ args: [
3105
+ {
3106
+ name: 'index',
3107
+ type: 'u64',
3108
+ },
3109
+ {
3110
+ name: 'owner',
3111
+ type: 'publicKey',
3112
+ },
3113
+ {
3114
+ name: 'delegate',
3115
+ type: {
3116
+ option: 'publicKey',
3117
+ },
3118
+ },
3119
+ {
3120
+ name: 'height',
3121
+ type: 'u64',
3122
+ },
3123
+ {
3124
+ name: 'changelogSize',
3125
+ type: 'u64',
3126
+ },
3127
+ {
3128
+ name: 'rootsSize',
3129
+ type: 'u64',
3130
+ },
3131
+ {
3132
+ name: 'canopyDepth',
3133
+ type: 'u64',
3134
+ },
3135
+ {
3136
+ name: 'associatedQueue',
3137
+ type: {
3138
+ option: 'publicKey',
3139
+ },
3140
+ },
3141
+ ],
3142
+ },
3143
+ {
3144
+ name: 'appendLeavesToMerkleTrees',
3145
+ accounts: [
3146
+ {
3147
+ name: 'authority',
3148
+ isMut: true,
3149
+ isSigner: true,
3150
+ },
3151
+ {
3152
+ name: 'registeredProgramPda',
3153
+ isMut: false,
3154
+ isSigner: false,
3155
+ isOptional: true,
3156
+ },
3157
+ {
3158
+ name: 'logWrapper',
3159
+ isMut: false,
3160
+ isSigner: false,
3161
+ },
3162
+ ],
3163
+ args: [
3164
+ {
3165
+ name: 'leaves',
3166
+ type: {
3167
+ vec: {
3168
+ array: ['u8', 32],
3169
+ },
3170
+ },
3171
+ },
3172
+ ],
3173
+ },
3174
+ {
3175
+ name: 'nullifyLeaves',
3176
+ accounts: [
3177
+ {
3178
+ name: 'authority',
3179
+ isMut: true,
3180
+ isSigner: true,
3181
+ },
3182
+ {
3183
+ name: 'registeredProgramPda',
3184
+ isMut: false,
3185
+ isSigner: false,
3186
+ isOptional: true,
3187
+ },
3188
+ {
3189
+ name: 'logWrapper',
3190
+ isMut: false,
3191
+ isSigner: false,
3192
+ },
3193
+ {
3194
+ name: 'merkleTree',
3195
+ isMut: true,
3196
+ isSigner: false,
3197
+ },
3198
+ {
3199
+ name: 'indexedArray',
3200
+ isMut: true,
3201
+ isSigner: false,
3202
+ },
3203
+ ],
3204
+ args: [
3205
+ {
3206
+ name: 'changeLogIndices',
3207
+ type: {
3208
+ vec: 'u64',
3209
+ },
3210
+ },
3211
+ {
3212
+ name: 'leavesQueueIndices',
3213
+ type: {
3214
+ vec: 'u16',
3215
+ },
3216
+ },
3217
+ {
3218
+ name: 'indices',
3219
+ type: {
3220
+ vec: 'u64',
3221
+ },
3222
+ },
3223
+ {
3224
+ name: 'proofs',
3225
+ type: {
3226
+ vec: {
3227
+ vec: {
3228
+ array: ['u8', 32],
3229
+ },
3230
+ },
3231
+ },
3232
+ },
3233
+ ],
3234
+ },
3235
+ {
3236
+ name: 'initializeIndexedArray',
3237
+ accounts: [
3238
+ {
3239
+ name: 'authority',
3240
+ isMut: false,
3241
+ isSigner: true,
3242
+ },
3243
+ {
3244
+ name: 'indexedArray',
3245
+ isMut: true,
3246
+ isSigner: false,
3247
+ },
3248
+ {
3249
+ name: 'systemProgram',
3250
+ isMut: false,
3251
+ isSigner: false,
3252
+ },
3253
+ ],
3254
+ args: [
3255
+ {
3256
+ name: 'index',
3257
+ type: 'u64',
3258
+ },
3259
+ {
3260
+ name: 'owner',
3261
+ type: 'publicKey',
3262
+ },
3263
+ {
3264
+ name: 'delegate',
3265
+ type: {
3266
+ option: 'publicKey',
3267
+ },
3268
+ },
3269
+ {
3270
+ name: 'associatedMerkleTree',
3271
+ type: {
3272
+ option: 'publicKey',
3273
+ },
3274
+ },
3275
+ {
3276
+ name: 'capacityIndices',
3277
+ type: 'u16',
3278
+ },
3279
+ {
3280
+ name: 'capacityValues',
3281
+ type: 'u16',
3282
+ },
3283
+ {
3284
+ name: 'sequenceThreshold',
3285
+ type: 'u64',
3286
+ },
3287
+ ],
3288
+ },
3289
+ {
3290
+ name: 'insertIntoIndexedArrays',
3291
+ accounts: [
3292
+ {
3293
+ name: 'authority',
3294
+ isMut: true,
3295
+ isSigner: true,
3296
+ },
3297
+ {
3298
+ name: 'registeredProgramPda',
3299
+ isMut: false,
3300
+ isSigner: false,
3301
+ isOptional: true,
3302
+ },
3303
+ ],
3304
+ args: [
3305
+ {
3306
+ name: 'elements',
3307
+ type: {
3308
+ vec: {
3309
+ array: ['u8', 32],
3310
+ },
3311
+ },
3312
+ },
3313
+ ],
3314
+ },
3315
+ ],
3316
+ accounts: [
3317
+ {
3318
+ name: 'groupAuthority',
3319
+ type: {
3320
+ kind: 'struct',
3321
+ fields: [
3322
+ {
3323
+ name: 'authority',
3324
+ type: 'publicKey',
3325
+ },
3326
+ {
3327
+ name: 'seed',
3328
+ type: {
3329
+ array: ['u8', 32],
3330
+ },
3331
+ },
3332
+ ],
3333
+ },
3334
+ },
3335
+ {
3336
+ name: 'indexedArrayAccount',
3337
+ type: {
3338
+ kind: 'struct',
3339
+ fields: [
3340
+ {
3341
+ name: 'index',
3342
+ type: 'u64',
3343
+ },
3344
+ {
3345
+ name: 'owner',
3346
+ type: 'publicKey',
3347
+ },
3348
+ {
3349
+ name: 'delegate',
3350
+ type: 'publicKey',
3351
+ },
3352
+ {
3353
+ name: 'associatedMerkleTree',
3354
+ type: 'publicKey',
3355
+ },
3356
+ ],
3357
+ },
3358
+ },
3359
+ {
3360
+ name: 'registeredProgram',
3361
+ type: {
3362
+ kind: 'struct',
3363
+ fields: [
3364
+ {
3365
+ name: 'pubkey',
3366
+ type: 'publicKey',
3367
+ },
3368
+ ],
3369
+ },
3370
+ },
3371
+ {
3372
+ name: 'addressQueueAccount',
3373
+ type: {
3374
+ kind: 'struct',
3375
+ fields: [
3376
+ {
3377
+ name: 'index',
3378
+ type: 'u64',
3379
+ },
3380
+ {
3381
+ name: 'owner',
3382
+ type: 'publicKey',
3383
+ },
3384
+ {
3385
+ name: 'delegate',
3386
+ type: 'publicKey',
3387
+ },
3388
+ {
3389
+ name: 'associatedMerkleTree',
3390
+ type: 'publicKey',
3391
+ },
3392
+ ],
3393
+ },
3394
+ },
3395
+ {
3396
+ name: 'addressMerkleTreeAccount',
3397
+ type: {
3398
+ kind: 'struct',
3399
+ fields: [
3400
+ {
3401
+ name: 'index',
3402
+ docs: ['Unique index.'],
3403
+ type: 'u64',
3404
+ },
3405
+ {
3406
+ name: 'nextMerkleTree',
3407
+ docs: ['Public key of the next Merkle tree.'],
3408
+ type: 'publicKey',
3409
+ },
3410
+ {
3411
+ name: 'owner',
3412
+ docs: ['Owner of the Merkle tree.'],
3413
+ type: 'publicKey',
3414
+ },
3415
+ {
3416
+ name: 'delegate',
3417
+ docs: [
3418
+ 'Delegate of the Merkle tree. This will be used for program owned Merkle trees.',
3419
+ ],
3420
+ type: 'publicKey',
3421
+ },
3422
+ {
3423
+ name: 'merkleTreeStruct',
3424
+ type: {
3425
+ array: ['u8', 256],
3426
+ },
3427
+ },
3428
+ {
3429
+ name: 'merkleTreeFilledSubtrees',
3430
+ type: {
3431
+ array: ['u8', 832],
3432
+ },
3433
+ },
3434
+ {
3435
+ name: 'merkleTreeChangelog',
3436
+ type: {
3437
+ array: ['u8', 1220800],
3438
+ },
3439
+ },
3440
+ {
3441
+ name: 'merkleTreeRoots',
3442
+ type: {
3443
+ array: ['u8', 76800],
3444
+ },
3445
+ },
3446
+ {
3447
+ name: 'merkleTreeCanopy',
3448
+ type: {
3449
+ array: ['u8', 65472],
3450
+ },
3451
+ },
3452
+ ],
3453
+ },
3454
+ },
3455
+ {
3456
+ name: 'stateMerkleTreeAccount',
3457
+ docs: [
3458
+ 'Concurrent state Merkle tree used for public compressed transactions.',
3459
+ ],
3460
+ type: {
3461
+ kind: 'struct',
3462
+ fields: [
3463
+ {
3464
+ name: 'index',
3465
+ docs: ['Unique index.'],
3466
+ type: 'u64',
3467
+ },
3468
+ {
3469
+ name: 'nextMerkleTree',
3470
+ docs: ['Public key of the next Merkle tree.'],
3471
+ type: 'publicKey',
3472
+ },
3473
+ {
3474
+ name: 'owner',
3475
+ docs: ['Owner of the Merkle tree.'],
3476
+ type: 'publicKey',
3477
+ },
3478
+ {
3479
+ name: 'delegate',
3480
+ docs: [
3481
+ 'Delegate of the Merkle tree. This will be used for program owned Merkle trees.',
3482
+ ],
3483
+ type: 'publicKey',
3484
+ },
3485
+ {
3486
+ name: 'associatedQueue',
3487
+ type: 'publicKey',
3488
+ },
3489
+ {
3490
+ name: 'stateMerkleTreeStruct',
3491
+ docs: ['Merkle tree for the transaction state.'],
3492
+ type: {
3493
+ array: ['u8', 256],
3494
+ },
3495
+ },
3496
+ {
3497
+ name: 'stateMerkleTreeFilledSubtrees',
3498
+ type: {
3499
+ array: ['u8', 832],
3500
+ },
3501
+ },
3502
+ {
3503
+ name: 'stateMerkleTreeChangelog',
3504
+ type: {
3505
+ array: ['u8', 1220800],
3506
+ },
3507
+ },
3508
+ {
3509
+ name: 'stateMerkleTreeRoots',
3510
+ type: {
3511
+ array: ['u8', 76800],
3512
+ },
3513
+ },
3514
+ {
3515
+ name: 'stateMerkleTreeCanopy',
3516
+ type: {
3517
+ array: ['u8', 65472],
3518
+ },
3519
+ },
3520
+ ],
3521
+ },
3522
+ },
3523
+ ],
3524
+ errors: [
3525
+ {
3526
+ code: 6000,
3527
+ name: 'AddressQueueInsert',
3528
+ msg: 'Failed to insert an element into indexing queue',
3529
+ },
3530
+ {
3531
+ code: 6001,
3532
+ name: 'AddressQueueDequeue',
3533
+ msg: 'Failed to dequeue an element from indexing queue',
3534
+ },
3535
+ {
3536
+ code: 6002,
3537
+ name: 'AddressMerkleTreeInitialize',
3538
+ msg: 'Failed to initialize address Merkle tree',
3539
+ },
3540
+ {
3541
+ code: 6003,
3542
+ name: 'AddressMerkleTreeUpdate',
3543
+ msg: 'Failed to update the address Merkle tree',
3544
+ },
3545
+ {
3546
+ code: 6004,
3547
+ name: 'InvalidIndex',
3548
+ msg: 'No element found under the given index in the queue',
3549
+ },
3550
+ {
3551
+ code: 6005,
3552
+ name: 'BytesToBigint',
3553
+ msg: 'Failed to convert bytes to big integer',
3554
+ },
3555
+ {
3556
+ code: 6006,
3557
+ name: 'IntegerOverflow',
3558
+ msg: 'Integer overflow',
3559
+ },
3560
+ {
3561
+ code: 6007,
3562
+ name: 'InvalidAuthority',
3563
+ msg: 'InvalidAuthority',
3564
+ },
3565
+ {
3566
+ code: 6008,
3567
+ name: 'InvalidVerifier',
3568
+ msg: 'InvalidVerifier',
3569
+ },
3570
+ {
3571
+ code: 6009,
3572
+ name: 'NumberOfLeavesMismatch',
3573
+ msg: 'Leaves <> remaining accounts missmatch. The number of remaining accounts must match the number of leaves.',
3574
+ },
3575
+ {
3576
+ code: 6010,
3577
+ name: 'InvalidNoopPubkey',
3578
+ msg: 'Provided noop program public key is invalid',
3579
+ },
3580
+ {
3581
+ code: 6011,
3582
+ name: 'EventNoChangelogEntry',
3583
+ msg: 'Emitting an event requires at least one changelog entry',
3584
+ },
3585
+ {
3586
+ code: 6012,
3587
+ name: 'NumberOfChangeLogIndicesMismatch',
3588
+ msg: 'Number of change log indices mismatch',
3589
+ },
3590
+ {
3591
+ code: 6013,
3592
+ name: 'NumberOfIndicesMismatch',
3593
+ msg: 'Number of indices mismatch',
3594
+ },
3595
+ {
3596
+ code: 6014,
3597
+ name: 'IndexOutOfBounds',
3598
+ msg: 'IndexOutOfBounds',
3599
+ },
3600
+ {
3601
+ code: 6015,
3602
+ name: 'ElementAlreadyExists',
3603
+ msg: 'ElementAlreadyExists',
3604
+ },
3605
+ {
3606
+ code: 6016,
3607
+ name: 'HashSetFull',
3608
+ msg: 'HashSetFull',
3609
+ },
3610
+ {
3611
+ code: 6017,
3612
+ name: 'NumberOfProofsMismatch',
3613
+ msg: 'NumberOfProofsMismatch',
3614
+ },
3615
+ {
3616
+ code: 6018,
3617
+ name: 'InvalidMerkleProof',
3618
+ msg: 'InvalidMerkleProof',
3619
+ },
3620
+ {
3621
+ code: 6019,
3622
+ name: 'InvalidIndexedArray',
3623
+ msg: 'InvalidIndexedArray',
3624
+ },
3625
+ {
3626
+ code: 6020,
3627
+ name: 'InvalidMerkleTree',
3628
+ msg: 'InvalidMerkleTree',
3629
+ },
3630
+ {
3631
+ code: 6021,
3632
+ name: 'LeafNotFound',
3633
+ msg: 'Could not find the leaf in the queue',
3634
+ },
3635
+ ],
3636
+ };
3637
+
3638
+ const IDL$1 = {
3639
+ version: '0.3.0',
3640
+ name: 'light',
3641
+ constants: [
3642
+ {
3643
+ name: 'AUTHORITY_PDA_SEED',
3644
+ type: 'bytes',
3645
+ value: '[97, 117, 116, 104, 111, 114, 105, 116, 121]',
3646
+ },
3647
+ {
3648
+ name: 'CPI_AUTHORITY_PDA_SEED',
3649
+ type: 'bytes',
3650
+ value: '[99, 112, 105, 95, 97, 117, 116, 104, 111, 114, 105, 116, 121]',
3651
+ },
3652
+ ],
3653
+ instructions: [
3654
+ {
3655
+ name: 'initializeGovernanceAuthority',
3656
+ accounts: [
3657
+ {
3658
+ name: 'authority',
3659
+ isMut: true,
3660
+ isSigner: true,
3661
+ },
3662
+ {
3663
+ name: 'authorityPda',
3664
+ isMut: true,
3665
+ isSigner: false,
3666
+ },
3667
+ {
3668
+ name: 'systemProgram',
3669
+ isMut: false,
3670
+ isSigner: false,
3671
+ },
3672
+ ],
3673
+ args: [
3674
+ {
3675
+ name: 'authority',
3676
+ type: 'publicKey',
3677
+ },
3678
+ {
3679
+ name: 'rewards',
3680
+ type: {
3681
+ vec: 'u64',
3682
+ },
3683
+ },
3684
+ {
3685
+ name: 'bump',
3686
+ type: 'u8',
3687
+ },
3688
+ ],
3689
+ },
3690
+ {
3691
+ name: 'updateGovernanceAuthorityReward',
3692
+ accounts: [
3693
+ {
3694
+ name: 'authority',
3695
+ isMut: true,
3696
+ isSigner: true,
3697
+ },
3698
+ {
3699
+ name: 'authorityPda',
3700
+ isMut: true,
3701
+ isSigner: false,
3702
+ },
3703
+ ],
3704
+ args: [
3705
+ {
3706
+ name: 'reward',
3707
+ type: 'u64',
3708
+ },
3709
+ {
3710
+ name: 'index',
3711
+ type: 'u64',
3712
+ },
3713
+ ],
3714
+ },
3715
+ {
3716
+ name: 'updateGovernanceAuthority',
3717
+ accounts: [
3718
+ {
3719
+ name: 'authority',
3720
+ isMut: true,
3721
+ isSigner: true,
3722
+ },
3723
+ {
3724
+ name: 'authorityPda',
3725
+ isMut: true,
3726
+ isSigner: false,
3727
+ },
3728
+ ],
3729
+ args: [
3730
+ {
3731
+ name: 'bump',
3732
+ type: 'u8',
3733
+ },
3734
+ {
3735
+ name: 'newAuthority',
3736
+ type: 'publicKey',
3737
+ },
3738
+ ],
3739
+ },
3740
+ {
3741
+ name: 'registerSystemProgram',
3742
+ accounts: [
3743
+ {
3744
+ name: 'authority',
3745
+ isMut: true,
3746
+ isSigner: true,
3747
+ },
3748
+ {
3749
+ name: 'authorityPda',
3750
+ isMut: true,
3751
+ isSigner: false,
3752
+ },
3753
+ {
3754
+ name: 'cpiAuthority',
3755
+ isMut: true,
3756
+ isSigner: false,
3757
+ },
3758
+ {
3759
+ name: 'groupPda',
3760
+ isMut: true,
3761
+ isSigner: false,
3762
+ },
3763
+ {
3764
+ name: 'accountCompressionProgram',
3765
+ isMut: false,
3766
+ isSigner: false,
3767
+ },
3768
+ {
3769
+ name: 'systemProgram',
3770
+ isMut: false,
3771
+ isSigner: false,
3772
+ },
3773
+ {
3774
+ name: 'registeredProgramPda',
3775
+ isMut: false,
3776
+ isSigner: false,
3777
+ },
3778
+ ],
3779
+ args: [
3780
+ {
3781
+ name: 'bump',
3782
+ type: 'u8',
3783
+ },
3784
+ {
3785
+ name: 'programId',
3786
+ type: 'publicKey',
3787
+ },
3788
+ ],
3789
+ },
3790
+ ],
3791
+ accounts: [
3792
+ {
3793
+ name: 'lightGovernanceAuthority',
3794
+ type: {
3795
+ kind: 'struct',
3796
+ fields: [
3797
+ {
3798
+ name: 'authority',
3799
+ type: 'publicKey',
3800
+ },
3801
+ {
3802
+ name: 'bump',
3803
+ type: 'u8',
3804
+ },
3805
+ {
3806
+ name: 'padding',
3807
+ type: {
3808
+ array: ['u8', 7],
3809
+ },
3810
+ },
3811
+ {
3812
+ name: 'rewards',
3813
+ type: {
3814
+ vec: 'u64',
3815
+ },
3816
+ },
3817
+ ],
3818
+ },
3819
+ },
3820
+ ],
3821
+ errors: [
3822
+ {
3823
+ code: 6000,
3824
+ name: 'SumCheckFailed',
3825
+ msg: 'Sum check failed',
3826
+ },
3827
+ ],
3828
+ };
3829
+
3830
+ const IDL = {
3831
+ version: '0.3.0',
3832
+ name: 'user_registry',
3833
+ instructions: [
3834
+ {
3835
+ name: 'initializeUserEntry',
3836
+ accounts: [
3837
+ {
3838
+ name: 'signer',
3839
+ isMut: true,
3840
+ isSigner: true,
3841
+ },
3842
+ {
3843
+ name: 'systemProgram',
3844
+ isMut: false,
3845
+ isSigner: false,
3846
+ },
3847
+ {
3848
+ name: 'userEntry',
3849
+ isMut: true,
3850
+ isSigner: false,
3851
+ },
3852
+ ],
3853
+ args: [
3854
+ {
3855
+ name: 'lightPubkey',
3856
+ type: {
3857
+ array: ['u8', 32],
3858
+ },
3859
+ },
3860
+ {
3861
+ name: 'lightEncryptionPubkey',
3862
+ type: {
3863
+ array: ['u8', 32],
3864
+ },
3865
+ },
3866
+ ],
3867
+ },
3868
+ ],
3869
+ accounts: [
3870
+ {
3871
+ name: 'userEntry',
3872
+ type: {
3873
+ kind: 'struct',
3874
+ fields: [
3875
+ {
3876
+ name: 'solanaPubkey',
3877
+ type: {
3878
+ array: ['u8', 32],
3879
+ },
3880
+ },
3881
+ {
3882
+ name: 'lightPubkey',
3883
+ type: {
3884
+ array: ['u8', 32],
3885
+ },
3886
+ },
3887
+ {
3888
+ name: 'lightEncryptionPubkey',
3889
+ type: {
3890
+ array: ['u8', 32],
3891
+ },
3892
+ },
3893
+ ],
3894
+ },
3895
+ },
3896
+ ],
3897
+ };
3898
+
3899
+ // TODO: Clean up
3900
+ var UtxoErrorCode;
3901
+ (function (UtxoErrorCode) {
3902
+ UtxoErrorCode["NEGATIVE_LAMPORTS"] = "NEGATIVE_LAMPORTS";
3903
+ UtxoErrorCode["NOT_U64"] = "NOT_U64";
3904
+ UtxoErrorCode["BLINDING_EXCEEDS_FIELD_SIZE"] = "BLINDING_EXCEEDS_FIELD_SIZE";
3905
+ })(UtxoErrorCode || (UtxoErrorCode = {}));
3906
+ var SelectInUtxosErrorCode;
3907
+ (function (SelectInUtxosErrorCode) {
3908
+ SelectInUtxosErrorCode["FAILED_TO_FIND_UTXO_COMBINATION"] = "FAILED_TO_FIND_UTXO_COMBINATION";
3909
+ SelectInUtxosErrorCode["INVALID_NUMBER_OF_IN_UTXOS"] = "INVALID_NUMBER_OF_IN_UTXOS";
3910
+ })(SelectInUtxosErrorCode || (SelectInUtxosErrorCode = {}));
3911
+ var CreateUtxoErrorCode;
3912
+ (function (CreateUtxoErrorCode) {
3913
+ CreateUtxoErrorCode["OWNER_UNDEFINED"] = "OWNER_UNDEFINED";
3914
+ CreateUtxoErrorCode["INVALID_OUTPUT_UTXO_LENGTH"] = "INVALID_OUTPUT_UTXO_LENGTH";
3915
+ CreateUtxoErrorCode["UTXO_DATA_UNDEFINED"] = "UTXO_DATA_UNDEFINED";
3916
+ })(CreateUtxoErrorCode || (CreateUtxoErrorCode = {}));
3917
+ var RpcErrorCode;
3918
+ (function (RpcErrorCode) {
3919
+ RpcErrorCode["CONNECTION_UNDEFINED"] = "CONNECTION_UNDEFINED";
3920
+ RpcErrorCode["RPC_PUBKEY_UNDEFINED"] = "RPC_PUBKEY_UNDEFINED";
3921
+ RpcErrorCode["RPC_METHOD_NOT_IMPLEMENTED"] = "RPC_METHOD_NOT_IMPLEMENTED";
3922
+ RpcErrorCode["RPC_INVALID"] = "RPC_INVALID";
3923
+ })(RpcErrorCode || (RpcErrorCode = {}));
3924
+ var LookupTableErrorCode;
3925
+ (function (LookupTableErrorCode) {
3926
+ LookupTableErrorCode["LOOK_UP_TABLE_UNDEFINED"] = "LOOK_UP_TABLE_UNDEFINED";
3927
+ LookupTableErrorCode["LOOK_UP_TABLE_NOT_INITIALIZED"] = "LOOK_UP_TABLE_NOT_INITIALIZED";
3928
+ })(LookupTableErrorCode || (LookupTableErrorCode = {}));
3929
+ var HashErrorCode;
3930
+ (function (HashErrorCode) {
3931
+ HashErrorCode["NO_POSEIDON_HASHER_PROVIDED"] = "NO_POSEIDON_HASHER_PROVIDED";
3932
+ })(HashErrorCode || (HashErrorCode = {}));
3933
+ var ProofErrorCode;
3934
+ (function (ProofErrorCode) {
3935
+ ProofErrorCode["INVALID_PROOF"] = "INVALID_PROOF";
3936
+ ProofErrorCode["PROOF_INPUT_UNDEFINED"] = "PROOF_INPUT_UNDEFINED";
3937
+ ProofErrorCode["PROOF_GENERATION_FAILED"] = "PROOF_GENERATION_FAILED";
3938
+ })(ProofErrorCode || (ProofErrorCode = {}));
3939
+ var MerkleTreeErrorCode;
3940
+ (function (MerkleTreeErrorCode) {
3941
+ MerkleTreeErrorCode["MERKLE_TREE_NOT_INITIALIZED"] = "MERKLE_TREE_NOT_INITIALIZED";
3942
+ MerkleTreeErrorCode["SOL_MERKLE_TREE_UNDEFINED"] = "SOL_MERKLE_TREE_UNDEFINED";
3943
+ MerkleTreeErrorCode["MERKLE_TREE_UNDEFINED"] = "MERKLE_TREE_UNDEFINED";
3944
+ MerkleTreeErrorCode["INPUT_UTXO_NOT_INSERTED_IN_MERKLE_TREE"] = "INPUT_UTXO_NOT_INSERTED_IN_MERKLE_TREE";
3945
+ MerkleTreeErrorCode["MERKLE_TREE_INDEX_UNDEFINED"] = "MERKLE_TREE_INDEX_UNDEFINED";
3946
+ MerkleTreeErrorCode["MERKLE_TREE_SET_SPACE_UNDEFINED"] = "MERKLE_TREE_SET_SPACE_UNDEFINED";
3947
+ })(MerkleTreeErrorCode || (MerkleTreeErrorCode = {}));
3948
+ var UtilsErrorCode;
3949
+ (function (UtilsErrorCode) {
3950
+ UtilsErrorCode["ACCOUNT_NAME_UNDEFINED_IN_IDL"] = "ACCOUNT_NAME_UNDEFINED_IN_IDL";
3951
+ UtilsErrorCode["PROPERTY_UNDEFINED"] = "PROPERTY_UNDEFINED";
3952
+ UtilsErrorCode["LOOK_UP_TABLE_CREATION_FAILED"] = "LOOK_UP_TABLE_CREATION_FAILED";
3953
+ UtilsErrorCode["UNSUPPORTED_ARCHITECTURE"] = "UNSUPPORTED_ARCHITECTURE";
3954
+ UtilsErrorCode["UNSUPPORTED_PLATFORM"] = "UNSUPPORTED_PLATFORM";
3955
+ UtilsErrorCode["ACCOUNTS_UNDEFINED"] = "ACCOUNTS_UNDEFINED";
3956
+ UtilsErrorCode["INVALID_NUMBER"] = "INVALID_NUMBER";
3957
+ })(UtilsErrorCode || (UtilsErrorCode = {}));
3958
+ class MetaError extends Error {
3959
+ code;
3960
+ functionName;
3961
+ codeMessage;
3962
+ constructor(code, functionName, codeMessage) {
3963
+ super(`${code}: ${codeMessage}`);
3964
+ this.code = code;
3965
+ this.functionName = functionName;
3966
+ this.codeMessage = codeMessage;
3967
+ }
3968
+ }
3969
+ class UtxoError extends MetaError {
3970
+ }
3971
+ class SelectInUtxosError extends MetaError {
3972
+ }
3973
+ class CreateUtxoError extends MetaError {
3974
+ }
3975
+ class RpcError extends MetaError {
3976
+ }
3977
+ class LookupTableError extends MetaError {
3978
+ }
3979
+ class HashError extends MetaError {
3980
+ }
3981
+ class ProofError extends MetaError {
3982
+ }
3983
+ class MerkleTreeError extends MetaError {
3984
+ }
3985
+ class UtilsError extends MetaError {
3986
+ }
3987
+
3988
+ export { ALICE, IDL$2 as AccountCompressionIDL, AccountProofResult, BOB, BalanceResult, CHARLIE, CompressedAccountResult, CompressedAccountsByOwnerResult, CompressedTokenAccountResult, CompressedTokenAccountsByOwnerOrDelegateResult, CreateUtxoError, CreateUtxoErrorCode, DAVE, DEFAULT_MERKLE_TREE_HEIGHT, DEFAULT_MERKLE_TREE_ROOTS, DEFAULT_ZERO, FIELD_SIZE, HashError, HashErrorCode, HealthResult, IDL$1 as LightIDL, LightSystemProgram, LookupTableError, LookupTableErrorCode, MerkeProofResult, MerkleTree, MerkleTreeError, MerkleTreeErrorCode, MultipleCompressedAccountsResult, MultipleMerkleProofsResult, ProofError, ProofErrorCode, IDL$3 as PspCompressedPdaIDL, PublicKeyToBN254, Rpc, RpcError, RpcErrorCode, SelectInUtxosError, SelectInUtxosErrorCode, SlotResult, TRANSACTION_MERKLE_TREE_ROLLOVER_THRESHOLD, TestRpc, UTXO_MERGE_MAXIMUM, UTXO_MERGE_THRESHOLD, IDL as UserRegistryIDL, UtilsError, UtilsErrorCode, UtxoError, UtxoErrorCode, accountCompressionProgram, airdropSol, bigint254ToPublicKey, bn, bufToDecStr, buildAndSignTx, byteArrayToKeypair, checkValidityProofShape, compressLamports, confirmConfig, confirmTransaction, confirmTx, createBN254, createCompressedAccount, createCompressedAccountWithMerkleContext, createMerkleContext, createRpc, createRpcResult, decompressLamports, dedupeSigner, defaultStaticAccounts, defaultStaticAccountsStruct, defaultTestStateTreeAccounts, encodeBN254toBase58, getConnection, getIndexOrAdd, getPspAccountCompressionAuthority, getRegisteredProgramPda, getTestKeypair, getTestRpc, hashToBn254FieldSizeLe, initSolOmnibusAccount, jsonRpcResult, jsonRpcResultAndContext, lightProgram, merkletreePubkey, negateAndCompressProof, newAccountWithLamports, noopProgram, nullifierQueuePubkey, packCompressedAccounts, padOutputStateMerkleTrees, parseEvents, parsePublicTransactionEventWithIdl, pipe, placeholderValidityProof, proofFromJsonStruct, pushUniqueItems, sendAndConfirmTx, sleep, sumUpLamports, toArray, toCamelCase, useWallet, validateSameOwner, validateSufficientBalance };