1use std::ops::{Deref, DerefMut};
2
3use anchor_lang::{context::Context, prelude::Pubkey, Bumps, Key, Result};
4
5use crate::{
6 compressed_account::LightAccounts,
7 constants::CPI_AUTHORITY_PDA_SEED,
8 merkle_context::{PackedAddressMerkleContext, PackedMerkleContext},
9 proof::CompressedProof,
10 traits::{
11 InvokeAccounts, InvokeCpiAccounts, InvokeCpiContextAccount, LightSystemAccount,
12 SignerAccounts,
13 },
14 verify::{verify, InstructionDataInvokeCpi},
15};
16
17pub struct LightContext<'a, 'b, 'c, 'info, T, U>
34where
35 T: Bumps,
36 U: LightAccounts,
37{
38 pub anchor_context: Context<'a, 'b, 'c, 'info, T>,
40 pub light_accounts: U,
41}
42
43impl<'a, 'b, 'c, 'info, T, U> Deref for LightContext<'a, 'b, 'c, 'info, T, U>
44where
45 T: Bumps,
46 U: LightAccounts,
47{
48 type Target = Context<'a, 'b, 'c, 'info, T>;
49
50 fn deref(&self) -> &Self::Target {
51 &self.anchor_context
52 }
53}
54
55impl<'a, 'b, 'c, 'info, T, U> DerefMut for LightContext<'a, 'b, 'c, 'info, T, U>
56where
57 T: Bumps,
58 U: LightAccounts,
59{
60 fn deref_mut(&mut self) -> &mut Self::Target {
61 &mut self.anchor_context
62 }
63}
64
65impl<'a, 'b, 'c, 'info, T, U> LightContext<'a, 'b, 'c, 'info, T, U>
66where
67 T: Bumps
68 + InvokeAccounts<'info>
69 + InvokeCpiAccounts<'info>
70 + InvokeCpiContextAccount<'info>
71 + LightSystemAccount<'info>
72 + SignerAccounts<'info>,
73 U: LightAccounts,
74{
75 pub fn new(
76 anchor_context: Context<'a, 'b, 'c, 'info, T>,
77 inputs: Vec<Vec<u8>>,
78 merkle_context: PackedMerkleContext,
79 merkle_tree_root_index: u16,
80 address_merkle_context: PackedAddressMerkleContext,
81 address_merkle_tree_root_index: u16,
82 ) -> Result<Self> {
83 let light_accounts = U::try_light_accounts(
84 inputs,
85 merkle_context,
86 merkle_tree_root_index,
87 address_merkle_context,
88 address_merkle_tree_root_index,
89 anchor_context.remaining_accounts,
90 )?;
91 Ok(Self {
92 anchor_context,
93 light_accounts,
94 })
95 }
96
97 pub fn verify(&mut self, proof: CompressedProof) -> Result<()> {
98 let bump = Pubkey::find_program_address(
99 &[CPI_AUTHORITY_PDA_SEED],
100 &self.anchor_context.accounts.get_invoking_program().key(),
101 )
102 .1;
103 let signer_seeds = [CPI_AUTHORITY_PDA_SEED, &[bump]];
104
105 let new_address_params = self.light_accounts.new_address_params();
106 let input_compressed_accounts_with_merkle_context = self
107 .light_accounts
108 .input_accounts(self.anchor_context.remaining_accounts)?;
109 let output_compressed_accounts = self
110 .light_accounts
111 .output_accounts(self.anchor_context.remaining_accounts)?;
112
113 let instruction = InstructionDataInvokeCpi {
114 proof: Some(proof),
115 new_address_params,
116 relay_fee: None,
117 input_compressed_accounts_with_merkle_context,
118 output_compressed_accounts,
119 compress_or_decompress_lamports: None,
120 is_compress: false,
121 cpi_context: None,
122 };
123
124 verify(
125 &self.anchor_context,
126 &instruction,
127 &[signer_seeds.as_slice()],
128 )?;
129
130 Ok(())
131 }
132}