light_sdk/
context.rs

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
17/// Provides non-argument inputs to the program, including light accounts and
18/// regular accounts.
19///
20/// # Example
21/// ```ignore
22/// pub fn set_data(ctx: Context<SetData>, age: u64, other_data: u32) -> Result<()> {
23///     // Set account data like this
24///     (*ctx.accounts.my_account).age = age;
25///     (*ctx.accounts.my_account).other_data = other_data;
26///     // or like this
27///     let my_account = &mut ctx.account.my_account;
28///     my_account.age = age;
29///     my_account.other_data = other_data;
30///     Ok(())
31/// }
32/// ```
33pub struct LightContext<'a, 'b, 'c, 'info, T, U>
34where
35    T: Bumps,
36    U: LightAccounts,
37{
38    /// Context provided by Anchor.
39    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}