light_nullifier_program/
sdk.rs1use light_program_test::{AddressWithTree, Indexer, Rpc, RpcError};
7use light_sdk::{
8 address::v2::derive_address,
9 instruction::{PackedAccounts, PackedAddressTreeInfo, SystemAccountMetaConfig, ValidityProof},
10};
11use solana_sdk::{
12 instruction::{AccountMeta, Instruction},
13 pubkey::Pubkey,
14};
15
16pub const PROGRAM_ID: Pubkey = crate::ID;
18
19pub fn address_tree() -> Pubkey {
21 Pubkey::new_from_array(light_sdk::constants::ADDRESS_TREE_V2)
22}
23
24pub fn derive_nullifier_address(id: &[u8; 32]) -> [u8; 32] {
26 let (address, _) = derive_address(&[b"nullifier", id], &address_tree(), &PROGRAM_ID);
27 address
28}
29
30pub struct ProofResult {
32 pub proof: ValidityProof,
33 pub address_tree_info: PackedAddressTreeInfo,
34 pub output_state_tree_index: u8,
35 pub remaining_accounts: Vec<AccountMeta>,
36}
37
38pub async fn fetch_proof<R: Rpc + Indexer>(rpc: &mut R, id: &[u8; 32]) -> Result<ProofResult, RpcError> {
42 let address = derive_nullifier_address(id);
43 let tree = address_tree();
44
45 let config = SystemAccountMetaConfig::new(PROGRAM_ID);
46 let mut packed = PackedAccounts::default();
47 packed.add_system_accounts_v2(config)?;
48
49 let rpc_result = rpc
50 .get_validity_proof(vec![], vec![AddressWithTree { address, tree }], None)
51 .await?
52 .value;
53
54 let tree_infos = rpc_result.pack_tree_infos(&mut packed);
55
56 let output_state_tree_index = rpc
57 .get_random_state_tree_info()?
58 .pack_output_tree_index(&mut packed)?;
59
60 let (remaining_accounts, _, _) = packed.to_account_metas();
61
62 Ok(ProofResult {
63 proof: rpc_result.proof,
64 address_tree_info: tree_infos.address_trees[0],
65 output_state_tree_index,
66 remaining_accounts,
67 })
68}
69
70pub fn build_instruction(payer: Pubkey, id: [u8; 32], proof_result: ProofResult) -> Instruction {
74 use anchor_lang::InstructionData;
75
76 let data = crate::instruction::CreateNullifier {
77 proof: proof_result.proof,
78 address_tree_info: proof_result.address_tree_info,
79 output_state_tree_index: proof_result.output_state_tree_index,
80 id,
81 }
82 .data();
83
84 let mut accounts = vec![AccountMeta::new(payer, true)];
85 accounts.extend(proof_result.remaining_accounts);
86
87 Instruction {
88 program_id: PROGRAM_ID,
89 accounts,
90 data,
91 }
92}
93
94pub async fn create_nullifier_ix<R: Rpc + Indexer>(
99 rpc: &mut R,
100 payer: Pubkey,
101 id: [u8; 32],
102) -> Result<Instruction, RpcError> {
103 let proof_result = fetch_proof(rpc, &id).await?;
104 Ok(build_instruction(payer, id, proof_result))
105}