anchor_lang/
context.rs

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