11import { web3 , Program , AnchorProvider , setProvider } from "@coral-xyz/anchor" ;
2- import {
3- bn ,
4- createRpc ,
5- deriveAddressSeedV2 ,
6- deriveAddressV2 ,
7- batchAddressTree ,
8- PackedAccounts ,
9- Rpc ,
10- sleep ,
11- SystemAccountMetaConfig ,
12- defaultTestStateTreeAccounts ,
13- featureFlags ,
14- VERSION ,
15- confirmTx ,
16- } from "@lightprotocol/stateless.js" ;
2+ import { createRpc , Rpc , sleep , confirmTx } from "@lightprotocol/stateless.js" ;
173import * as assert from "assert" ;
184import * as path from "path" ;
195import * as fs from "fs" ;
206
21- // Force V2 mode
22- ( featureFlags as any ) . version = VERSION . V2 ;
23-
24- // Load IDL
257const IDL = JSON . parse (
268 fs . readFileSync ( path . join ( process . cwd ( ) , "target/idl/zk_nullifier.json" ) , "utf8" )
279) ;
2810
2911const PROGRAM_ID = new web3 . PublicKey ( IDL . address ) ;
30- const NULLIFIER_PREFIX = Buffer . from ( "nullifier" ) ;
12+
13+ async function createNullifierInstruction (
14+ rpc : Rpc ,
15+ program : Program ,
16+ signer : web3 . PublicKey ,
17+ nullifiers : Uint8Array [ ]
18+ ) : Promise < web3 . TransactionInstruction > {
19+ const {
20+ bn,
21+ deriveAddressSeedV2,
22+ deriveAddressV2,
23+ batchAddressTree,
24+ PackedAccounts,
25+ SystemAccountMetaConfig,
26+ defaultTestStateTreeAccounts,
27+ featureFlags,
28+ VERSION ,
29+ } = await import ( "@lightprotocol/stateless.js" ) ;
30+
31+ ( featureFlags as any ) . version = VERSION . V2 ;
32+
33+ const NULLIFIER_PREFIX = Buffer . from ( "nullifier" ) ;
34+ const addressTree = new web3 . PublicKey ( batchAddressTree ) ;
35+ const outputStateTree = defaultTestStateTreeAccounts ( ) . merkleTree ;
36+
37+ const addressesWithTree = nullifiers . map ( ( nullifier ) => {
38+ const seed = deriveAddressSeedV2 ( [ NULLIFIER_PREFIX , nullifier ] ) ;
39+ const address = deriveAddressV2 ( seed , addressTree , program . programId ) ;
40+ return { tree : addressTree , queue : addressTree , address : bn ( address . toBytes ( ) ) } ;
41+ } ) ;
42+
43+ const proofResult = await rpc . getValidityProofV0 ( [ ] , addressesWithTree ) ;
44+
45+ const remainingAccounts = new PackedAccounts ( ) ;
46+ remainingAccounts . addPreAccountsSigner ( signer ) ;
47+ remainingAccounts . addSystemAccountsV2 ( SystemAccountMetaConfig . new ( program . programId ) ) ;
48+
49+ const addressMerkleTreeIndex = remainingAccounts . insertOrGet ( addressTree ) ;
50+ const outputStateTreeIndex = remainingAccounts . insertOrGet ( outputStateTree ) ;
51+
52+ const { remainingAccounts : accountMetas , systemStart } = remainingAccounts . toAccountMetas ( ) ;
53+
54+ const data = {
55+ proof : { 0 : proofResult . compressedProof } ,
56+ addressTreeInfo : {
57+ addressMerkleTreePubkeyIndex : addressMerkleTreeIndex ,
58+ addressQueuePubkeyIndex : addressMerkleTreeIndex ,
59+ rootIndex : proofResult . rootIndices [ 0 ] ,
60+ } ,
61+ outputStateTreeIndex,
62+ systemAccountsOffset : systemStart ,
63+ } ;
64+
65+ return program . methods
66+ . createNullifier ( data , nullifiers . map ( ( n ) => Array . from ( n ) ) )
67+ . accounts ( { signer } )
68+ . remainingAccounts ( accountMetas )
69+ . instruction ( ) ;
70+ }
3171
3272describe ( "zk-nullifier" , ( ) => {
3373 let rpc : Rpc ;
@@ -46,7 +86,6 @@ describe("zk-nullifier", () => {
4686 await rpc . requestAirdrop ( signer . publicKey , web3 . LAMPORTS_PER_SOL ) ;
4787 await sleep ( 2000 ) ;
4888
49- // Setup Anchor provider and program
5089 const connection = new web3 . Connection ( "http://127.0.0.1:8899" , "confirmed" ) ;
5190 const wallet = {
5291 publicKey : signer . publicKey ,
@@ -64,71 +103,17 @@ describe("zk-nullifier", () => {
64103 program = new Program ( IDL , provider ) ;
65104 } ) ;
66105
67- /** Generate a random 32-byte value */
68106 function randomBytes32 ( ) : Uint8Array {
69107 return web3 . Keypair . generate ( ) . publicKey . toBytes ( ) ;
70108 }
71109
72- async function buildCreateNullifierInstruction (
73- nullifiers : Uint8Array [ ]
74- ) : Promise < web3 . TransactionInstruction > {
75- const addressTree = new web3 . PublicKey ( batchAddressTree ) ;
76- const outputStateTree = defaultTestStateTreeAccounts ( ) . merkleTree ;
77-
78- // Derive addresses for all nullifiers
79- const addressesWithTree = nullifiers . map ( ( nullifier ) => {
80- const seed = deriveAddressSeedV2 ( [ NULLIFIER_PREFIX , nullifier ] ) ;
81- const address = deriveAddressV2 ( seed , addressTree , PROGRAM_ID ) ;
82- return { tree : addressTree , queue : addressTree , address : bn ( address . toBytes ( ) ) } ;
83- } ) ;
84-
85- const proofResult = await rpc . getValidityProofV0 ( [ ] , addressesWithTree ) ;
86-
87- // Use V2 accounts layout
88- const remainingAccounts = new PackedAccounts ( ) ;
89- remainingAccounts . addPreAccountsSigner ( signer . publicKey ) ;
90- remainingAccounts . addSystemAccountsV2 ( SystemAccountMetaConfig . new ( PROGRAM_ID ) ) ;
91-
92- const addressMerkleTreeIndex = remainingAccounts . insertOrGet ( addressTree ) ;
93- const outputStateTreeIndex = remainingAccounts . insertOrGet ( outputStateTree ) ;
94-
95- const { remainingAccounts : accountMetas , systemStart } = remainingAccounts . toAccountMetas ( ) ;
96-
97- // ValidityProof struct
98- const proof = {
99- 0 : proofResult . compressedProof ,
100- } ;
101-
102- // NullifierInstructionData struct
103- const data = {
104- proof,
105- addressTreeInfo : {
106- addressMerkleTreePubkeyIndex : addressMerkleTreeIndex ,
107- addressQueuePubkeyIndex : addressMerkleTreeIndex ,
108- rootIndex : proofResult . rootIndices [ 0 ] ,
109- } ,
110- outputStateTreeIndex,
111- systemAccountsOffset : systemStart ,
112- } ;
113-
114- const ix = await program . methods
115- . createNullifier ( data , nullifiers . map ( ( n ) => Array . from ( n ) ) )
116- . accounts ( {
117- signer : signer . publicKey ,
118- } )
119- . remainingAccounts ( accountMetas )
120- . instruction ( ) ;
121-
122- return ix ;
123- }
124-
125110 describe ( "Single nullifier" , ( ) => {
126111 it ( "should create a nullifier" , async ( ) => {
127112 const nullifier = randomBytes32 ( ) ;
128113
129114 console . log ( "Nullifier:" , Buffer . from ( nullifier ) . toString ( "hex" ) . slice ( 0 , 16 ) + "..." ) ;
130115
131- const ix = await buildCreateNullifierInstruction ( [ nullifier ] ) ;
116+ const ix = await createNullifierInstruction ( rpc , program , signer . publicKey , [ nullifier ] ) ;
132117 const computeIx = web3 . ComputeBudgetProgram . setComputeUnitLimit ( { units : 200_000 } ) ;
133118
134119 const tx = new web3 . Transaction ( ) . add ( computeIx , ix ) ;
@@ -152,7 +137,7 @@ describe("zk-nullifier", () => {
152137 it ( "should reject duplicate nullifier" , async ( ) => {
153138 const nullifier = randomBytes32 ( ) ;
154139
155- const ix1 = await buildCreateNullifierInstruction ( [ nullifier ] ) ;
140+ const ix1 = await createNullifierInstruction ( rpc , program , signer . publicKey , [ nullifier ] ) ;
156141 const computeIx = web3 . ComputeBudgetProgram . setComputeUnitLimit ( { units : 200_000 } ) ;
157142
158143 const tx1 = new web3 . Transaction ( ) . add ( computeIx , ix1 ) ;
@@ -163,9 +148,8 @@ describe("zk-nullifier", () => {
163148 await rpc . sendTransaction ( tx1 , [ signer ] ) ;
164149 await sleep ( 2000 ) ;
165150
166- // Attempt to create duplicate - should fail when getting validity proof
167151 try {
168- await buildCreateNullifierInstruction ( [ nullifier ] ) ;
152+ await createNullifierInstruction ( rpc , program , signer . publicKey , [ nullifier ] ) ;
169153 assert . fail ( "Should have rejected duplicate nullifier" ) ;
170154 } catch ( err : any ) {
171155 assert . ok (
@@ -183,7 +167,7 @@ describe("zk-nullifier", () => {
183167
184168 console . log ( "Creating 3 nullifiers in one transaction..." ) ;
185169
186- const ix = await buildCreateNullifierInstruction ( nullifiers ) ;
170+ const ix = await createNullifierInstruction ( rpc , program , signer . publicKey , nullifiers ) ;
187171 const computeIx = web3 . ComputeBudgetProgram . setComputeUnitLimit ( { units : 300_000 } ) ;
188172
189173 const tx = new web3 . Transaction ( ) . add ( computeIx , ix ) ;
@@ -203,4 +187,4 @@ describe("zk-nullifier", () => {
203187 console . log ( "Total nullifier accounts:" , accounts . items . length ) ;
204188 } ) ;
205189 } ) ;
206- } ) ;
190+ } ) ;
0 commit comments