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}