Skip to main content

anchor_lang/
context.rs

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