Skip to main content

cronos_anchor_lang/
context.rs

1//! Data structures that are used to provide non-argument inputs to program endpoints
2
3use crate::{Accounts, ToAccountInfos, ToAccountMetas};
4use solana_program::account_info::AccountInfo;
5use solana_program::instruction::AccountMeta;
6use solana_program::pubkey::Pubkey;
7use std::collections::BTreeMap;
8use std::fmt;
9
10/// Provides non-argument inputs to the program.
11///
12/// # Example
13/// ```ignore
14/// pub fn set_data(ctx: Context<SetData>, age: u64, other_data: u32) -> Result<()> {
15///     // Set account data like this
16///     (*ctx.accounts.my_account).age = age;
17///     (*ctx.accounts.my_account).other_data = other_data;
18///     // or like this
19///     let my_account = &mut ctx.account.my_account;
20///     my_account.age = age;
21///     my_account.other_data = other_data;
22///     Ok(())
23/// }
24/// ```
25pub struct Context<'a, 'b, 'c, 'info, T> {
26    /// Currently executing program id.
27    pub program_id: &'a Pubkey,
28    /// Deserialized accounts.
29    pub accounts: &'b mut T,
30    /// Remaining accounts given but not deserialized or validated.
31    /// Be very careful when using this directly.
32    pub remaining_accounts: &'c [AccountInfo<'info>],
33    /// Bump seeds found during constraint validation. This is provided as a
34    /// convenience so that handlers don't have to recalculate bump seeds or
35    /// pass them in as arguments.
36    pub bumps: BTreeMap<String, u8>,
37}
38
39impl<'a, 'b, 'c, 'info, T: fmt::Debug> fmt::Debug for Context<'a, 'b, 'c, 'info, T> {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        f.debug_struct("Context")
42            .field("program_id", &self.program_id)
43            .field("accounts", &self.accounts)
44            .field("remaining_accounts", &self.remaining_accounts)
45            .field("bumps", &self.bumps)
46            .finish()
47    }
48}
49
50impl<'a, 'b, 'c, 'info, T: Accounts<'info>> Context<'a, 'b, 'c, 'info, T> {
51    pub fn new(
52        program_id: &'a Pubkey,
53        accounts: &'b mut T,
54        remaining_accounts: &'c [AccountInfo<'info>],
55        bumps: BTreeMap<String, u8>,
56    ) -> Self {
57        Self {
58            program_id,
59            accounts,
60            remaining_accounts,
61            bumps,
62        }
63    }
64}
65
66/// Context specifying non-argument inputs for cross-program-invocations.
67///
68/// # Example with and without PDA signature
69/// ```ignore
70/// // Callee Program
71///
72/// use anchor_lang::prelude::*;
73///
74/// declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
75///
76/// #[program]
77/// pub mod callee {
78///     use super::*;
79///     pub fn init(ctx: Context<Init>) -> Result<()> {
80///         (*ctx.accounts.data).authority = ctx.accounts.authority.key();
81///         Ok(())
82///     }
83///
84///     pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
85///         (*ctx.accounts.data_acc).data = data;
86///         Ok(())
87///     }
88/// }
89///
90/// #[account]
91/// #[derive(Default)]
92/// pub struct Data {
93///     data: u64,
94///     authority: Pubkey,
95/// }
96///
97/// #[derive(Accounts)]
98/// pub struct Init<'info> {
99///     #[account(init, payer = payer)]
100///     pub data: Account<'info, Data>,
101///     pub payer: Signer<'info>,
102///     pub authority: UncheckedAccount<'info>,
103///     pub system_program: Program<'info, System>
104/// }
105///
106/// #[derive(Accounts)]
107/// pub struct SetData<'info> {
108///     #[account(mut, has_one = authority)]
109///     pub data_acc: Account<'info, Data>,
110///     pub authority: Signer<'info>,
111/// }
112///
113/// // Caller Program
114///
115/// use anchor_lang::prelude::*;
116/// use callee::{self, program::Callee};
117///
118/// declare_id!("Sxg7dBh5VLT8S1o6BqncZCPq9nhHHukjfVd6ohQJeAk");
119///
120/// #[program]
121/// pub mod caller {
122///     use super::*;
123///     pub fn do_cpi(ctx: Context<DoCpi>, data: u64) -> Result<()> {
124///         let callee_id = ctx.accounts.callee.to_account_info();
125///         let callee_accounts = callee::cpi::accounts::SetData {
126///             data_acc: ctx.accounts.data_acc.to_account_info(),
127///             authority: ctx.accounts.callee_authority.to_account_info(),
128///         };
129///         let cpi_ctx = CpiContext::new(callee_id, callee_accounts);
130///         callee::cpi::set_data(cpi_ctx, data)
131///     }
132///
133///     pub fn do_cpi_with_pda_authority(ctx: Context<DoCpiWithPDAAuthority>, bump: u8, data: u64) -> Result<()> {
134///         let seeds = &[&[b"example_seed", bytemuck::bytes_of(&bump)][..]];
135///         let callee_id = ctx.accounts.callee.to_account_info();
136///         let callee_accounts = callee::cpi::accounts::SetData {
137///             data_acc: ctx.accounts.data_acc.to_account_info(),
138///             authority: ctx.accounts.callee_authority.to_account_info(),
139///         };
140///         let cpi_ctx = CpiContext::new_with_signer(callee_id, callee_accounts, seeds);
141///         callee::cpi::set_data(cpi_ctx, data)
142///     }
143/// }
144///
145/// // We can use "UncheckedAccount"s here because
146/// // the callee program does the checks.
147/// // We use "mut" so the autogenerated clients know
148/// // that this account should be mutable.
149/// #[derive(Accounts)]
150/// pub struct DoCpi<'info> {
151///     #[account(mut)]
152///     pub data_acc: UncheckedAccount<'info>,
153///     pub callee_authority: UncheckedAccount<'info>,
154///     pub callee: Program<'info, Callee>,
155/// }
156///
157/// #[derive(Accounts)]
158/// pub struct DoCpiWithPDAAuthority<'info> {
159///     #[account(mut)]
160///     pub data_acc: UncheckedAccount<'info>,
161///     pub callee_authority: UncheckedAccount<'info>,
162///     pub callee: Program<'info, Callee>,
163/// }
164/// ```
165pub struct CpiContext<'a, 'b, 'c, 'info, T>
166where
167    T: ToAccountMetas + ToAccountInfos<'info>,
168{
169    pub accounts: T,
170    pub remaining_accounts: Vec<AccountInfo<'info>>,
171    pub program: AccountInfo<'info>,
172    pub signer_seeds: &'a [&'b [&'c [u8]]],
173}
174
175impl<'a, 'b, 'c, 'info, T> CpiContext<'a, 'b, 'c, 'info, T>
176where
177    T: ToAccountMetas + ToAccountInfos<'info>,
178{
179    pub fn new(program: AccountInfo<'info>, accounts: T) -> Self {
180        Self {
181            accounts,
182            program,
183            remaining_accounts: Vec::new(),
184            signer_seeds: &[],
185        }
186    }
187
188    #[must_use]
189    pub fn new_with_signer(
190        program: AccountInfo<'info>,
191        accounts: T,
192        signer_seeds: &'a [&'b [&'c [u8]]],
193    ) -> Self {
194        Self {
195            accounts,
196            program,
197            signer_seeds,
198            remaining_accounts: Vec::new(),
199        }
200    }
201
202    #[must_use]
203    pub fn with_signer(mut self, signer_seeds: &'a [&'b [&'c [u8]]]) -> Self {
204        self.signer_seeds = signer_seeds;
205        self
206    }
207
208    #[must_use]
209    pub fn with_remaining_accounts(mut self, ra: Vec<AccountInfo<'info>>) -> Self {
210        self.remaining_accounts = ra;
211        self
212    }
213}
214
215impl<'info, T: ToAccountInfos<'info> + ToAccountMetas> ToAccountInfos<'info>
216    for CpiContext<'_, '_, '_, 'info, T>
217{
218    fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
219        let mut infos = self.accounts.to_account_infos();
220        infos.extend_from_slice(&self.remaining_accounts);
221        infos.push(self.program.clone());
222        infos
223    }
224}
225
226impl<'info, T: ToAccountInfos<'info> + ToAccountMetas> ToAccountMetas
227    for CpiContext<'_, '_, '_, 'info, T>
228{
229    fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
230        let mut metas = self.accounts.to_account_metas(is_signer);
231        metas.append(
232            &mut self
233                .remaining_accounts
234                .iter()
235                .map(|acc| match acc.is_writable {
236                    false => AccountMeta::new_readonly(*acc.key, acc.is_signer),
237                    true => AccountMeta::new(*acc.key, acc.is_signer),
238                })
239                .collect(),
240        );
241        metas
242    }
243}
244
245/// Context specifying non-argument inputs for cross-program-invocations
246/// targeted at program state instructions.
247#[doc(hidden)]
248#[deprecated]
249pub struct CpiStateContext<'a, 'b, 'c, 'info, T: Accounts<'info>> {
250    state: AccountInfo<'info>,
251    cpi_ctx: CpiContext<'a, 'b, 'c, 'info, T>,
252}
253
254#[allow(deprecated)]
255impl<'a, 'b, 'c, 'info, T: Accounts<'info>> CpiStateContext<'a, 'b, 'c, 'info, T> {
256    pub fn new(program: AccountInfo<'info>, state: AccountInfo<'info>, accounts: T) -> Self {
257        Self {
258            state,
259            cpi_ctx: CpiContext {
260                accounts,
261                program,
262                signer_seeds: &[],
263                remaining_accounts: Vec::new(),
264            },
265        }
266    }
267
268    pub fn new_with_signer(
269        program: AccountInfo<'info>,
270        state: AccountInfo<'info>,
271        accounts: T,
272        signer_seeds: &'a [&'b [&'c [u8]]],
273    ) -> Self {
274        Self {
275            state,
276            cpi_ctx: CpiContext {
277                accounts,
278                program,
279                signer_seeds,
280                remaining_accounts: Vec::new(),
281            },
282        }
283    }
284
285    #[must_use]
286    pub fn with_signer(mut self, signer_seeds: &'a [&'b [&'c [u8]]]) -> Self {
287        self.cpi_ctx = self.cpi_ctx.with_signer(signer_seeds);
288        self
289    }
290
291    pub fn program(&self) -> &AccountInfo<'info> {
292        &self.cpi_ctx.program
293    }
294
295    pub fn signer_seeds(&self) -> &[&[&[u8]]] {
296        self.cpi_ctx.signer_seeds
297    }
298}
299
300#[allow(deprecated)]
301impl<'a, 'b, 'c, 'info, T: Accounts<'info>> ToAccountMetas
302    for CpiStateContext<'a, 'b, 'c, 'info, T>
303{
304    fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
305        // State account is always first for state instructions.
306        let mut metas = vec![match self.state.is_writable {
307            false => AccountMeta::new_readonly(*self.state.key, false),
308            true => AccountMeta::new(*self.state.key, false),
309        }];
310        metas.append(&mut self.cpi_ctx.accounts.to_account_metas(is_signer));
311        metas
312    }
313}
314
315#[allow(deprecated)]
316impl<'a, 'b, 'c, 'info, T: Accounts<'info>> ToAccountInfos<'info>
317    for CpiStateContext<'a, 'b, 'c, 'info, T>
318{
319    fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
320        let mut infos = self.cpi_ctx.accounts.to_account_infos();
321        infos.push(self.state.clone());
322        infos.push(self.cpi_ctx.program.clone());
323        infos
324    }
325}