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 output_queue() -> Pubkey {
26 solana_sdk::pubkey!("oq5oh5ZR3yGomuQgFduNDzjtGvVWfDRGLuDVjv9a96P")
27}
28
29pub fn derive_nullifier_address(id: &[u8; 32]) -> [u8; 32] {
31 let (address, _) = derive_address(&[b"nullifier", id], &address_tree(), &PROGRAM_ID);
32 address
33}
34
35pub struct ProofResult {
37 pub proof: ValidityProof,
38 pub address_tree_info: PackedAddressTreeInfo,
39 pub output_state_tree_index: u8,
40 pub remaining_accounts: Vec<AccountMeta>,
41}
42
43pub async fn fetch_proof<R: Rpc + Indexer>(rpc: &mut R, id: &[u8; 32]) -> Result<ProofResult, RpcError> {
47 let address = derive_nullifier_address(id);
48 let tree = address_tree();
49
50 let config = SystemAccountMetaConfig::new(PROGRAM_ID);
51 let mut packed = PackedAccounts::default();
52 packed.add_system_accounts_v2(config)?;
53
54 let rpc_result = rpc
55 .get_validity_proof(vec![], vec![AddressWithTree { address, tree }], None)
56 .await?
57 .value;
58
59 let tree_infos = rpc_result.pack_tree_infos(&mut packed);
60
61 let output_state_tree_index = packed.insert_or_get(output_queue());
63
64 let (remaining_accounts, _, _) = packed.to_account_metas();
65
66 Ok(ProofResult {
67 proof: rpc_result.proof,
68 address_tree_info: tree_infos.address_trees[0],
69 output_state_tree_index,
70 remaining_accounts,
71 })
72}
73
74pub fn build_instruction(payer: Pubkey, id: [u8; 32], proof_result: ProofResult) -> Instruction {
78 use anchor_lang::InstructionData;
79
80 let data = crate::instruction::CreateNullifier {
81 proof: proof_result.proof,
82 address_tree_info: proof_result.address_tree_info,
83 output_state_tree_index: proof_result.output_state_tree_index,
84 id,
85 }
86 .data();
87
88 let mut accounts = vec![AccountMeta::new(payer, true)];
89 accounts.extend(proof_result.remaining_accounts);
90
91 Instruction {
92 program_id: PROGRAM_ID,
93 accounts,
94 data,
95 }
96}
97
98pub async fn create_nullifier_ix<R: Rpc + Indexer>(
103 rpc: &mut R,
104 payer: Pubkey,
105 id: [u8; 32],
106) -> Result<Instruction, RpcError> {
107 let proof_result = fetch_proof(rpc, &id).await?;
108 Ok(build_instruction(payer, id, proof_result))
109}