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}