anchor_derive_accounts/lib.rs
1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::ToTokens;
5use syn::parse_macro_input;
6
7/// Implements an [`Accounts`](./trait.Accounts.html) deserializer on the given
8/// struct. Can provide further functionality through the use of attributes.
9///
10/// # Table of Contents
11/// - [Instruction Attribute](#instruction-attribute)
12/// - [Constraints](#constraints)
13///
14/// # Instruction Attribute
15///
16/// You can access the instruction's arguments with the
17/// `#[instruction(..)]` attribute. You have to list them
18/// in the same order as in the instruction but you can
19/// omit all arguments after the last one you need.
20///
21/// # Example
22///
23/// ```ignore
24/// ...
25/// pub fn initialize(ctx: Context<Create>, bump: u8, authority: Pubkey, data: u64) -> anchor_lang::Result<()> {
26/// ...
27/// Ok(())
28/// }
29/// ...
30/// #[derive(Accounts)]
31/// #[instruction(bump: u8)]
32/// pub struct Initialize<'info> {
33/// ...
34/// }
35/// ```
36///
37/// # Constraints
38///
39/// There are different types of constraints that can be applied with the `#[account(..)]` attribute.
40///
41/// Attributes may reference other data structures. When `<expr>` is used in the tables below, an arbitrary expression
42/// may be passed in as long as it evaluates to a value of the expected type, e.g. `owner = token_program.key()`. If `target_account`
43/// used, the `target_account` must exist in the struct and the `.key()` is implicit, e.g. `payer = authority`.
44///
45/// - [Normal Constraints](#normal-constraints)
46/// - [SPL Constraints](#spl-constraints)
47///
48/// # Normal Constraints
49/// <table>
50/// <thead>
51/// <tr>
52/// <th>Attribute</th>
53/// <th>Description</th>
54/// </tr>
55/// </thead>
56/// <tbody>
57/// <tr>
58/// <td>
59/// <code>#[account(signer)]</code> <br><br><code>#[account(signer @ <custom_error>)]</code>
60/// </td>
61/// <td>
62/// Checks the given account signed the transaction.<br>
63/// Custom errors are supported via <code>@</code>.<br>
64/// Consider using the <code>Signer</code> type if you would only have this constraint on the account.<br><br>
65/// Example:
66/// <pre><code>
67/// #[account(signer)]
68/// pub authority: AccountInfo<'info>,
69/// #[account(signer @ MyError::MyErrorCode)]
70/// pub payer: AccountInfo<'info>
71/// </code></pre>
72/// </td>
73/// </tr>
74/// <tr>
75/// <td>
76/// <code>#[account(mut)]</code> <br><br><code>#[account(mut @ <custom_error>)]</code>
77/// </td>
78/// <td>
79/// Checks the given account is mutable.<br>
80/// Makes anchor persist any state changes.<br>
81/// Custom errors are supported via <code>@</code>.<br><br>
82/// Example:
83/// <pre><code>
84/// #[account(mut)]
85/// pub data_account: Account<'info, MyData>,
86/// #[account(mut @ MyError::MyErrorCode)]
87/// pub data_account_two: Account<'info, MyData>
88/// </code></pre>
89/// </td>
90/// </tr>
91/// <tr>
92/// <td>
93/// <code>#[account(init, payer = <target_account>, space = <num_bytes>)]</code>
94/// </td>
95/// <td>
96/// Creates the account via a CPI to the system program and
97/// initializes it (sets its account discriminator). The annotated account is required to sign for this instruction
98/// unless `seeds` is provided. <br>
99/// Marks the account as mutable and is mutually exclusive with <code>mut</code>.<br>
100/// Makes the account rent exempt unless skipped with <code>rent_exempt = skip</code>.<br><br>
101/// Use <code>#[account(zero)]</code> for accounts larger than 10 Kibibyte.<br><br>
102/// <code>init</code> has to be used with additional constraints:
103/// <ul>
104/// <li>
105/// Requires the <code>payer</code> constraint to also be on the account.
106/// The <code>payer</code> account pays for the
107/// account creation.
108/// </li>
109/// <li>
110/// Requires the system program to exist on the struct
111/// and be called <code>system_program</code>.
112/// </li>
113/// <li>
114/// Requires that the <code>space</code> constraint is specified.
115/// When using the <code>space</code> constraint, one must remember to add 8 to it
116/// which is the size of the account discriminator. This only has to be done
117/// for accounts owned by anchor programs.<br>
118/// The given space number is the size of the account in bytes, so accounts that hold
119/// a variable number of items such as a <code>Vec</code> should allocate sufficient space for all items that may
120/// be added to the data structure because account size is fixed.
121/// Check out the <a href = "https://www.anchor-lang.com/docs/space" target = "_blank" rel = "noopener noreferrer">space reference</a>
122/// and the <a href = "https://borsh.io/" target = "_blank" rel = "noopener noreferrer">borsh library</a>
123/// (which anchor uses under the hood for serialization) specification to learn how much
124/// space different data structures require.
125/// </li>
126/// <br>
127/// Example:
128/// <pre>
129/// #[account]
130/// pub struct MyData {
131/// pub data: u64
132/// }
133/// #[derive(Accounts)]
134/// pub struct Initialize<'info> {
135/// #[account(init, payer = payer, space = 8 + 8)]
136/// pub data_account_two: Account<'info, MyData>,
137/// #[account(mut)]
138/// pub payer: Signer<'info>,
139/// pub system_program: Program<'info, System>,
140/// }
141/// </pre>
142/// </ul>
143/// <code>init</code> can be combined with other constraints (at the same time):
144/// <ul>
145/// <li>
146/// By default <code>init</code> sets the owner field of the created account to the
147/// currently executing program. Add the <code>owner</code> constraint to specify a
148/// different program owner.
149/// </li>
150/// <li>
151/// Use the <code>seeds</code> constraint together with <code>bump</code>to create PDAs.<br>
152/// <code>init</code> uses <code>find_program_address</code> to calculate the pda so the
153/// bump value can be left empty.<br>
154/// However, if you want to use the bump in your instruction,
155/// you can pass it in as instruction data and set the bump value like shown in the example,
156/// using the <code>instruction_data</code> attribute.
157/// Anchor will then check that the bump returned by <code>find_program_address</code> equals
158/// the bump in the instruction data.<br>
159/// <code>seeds::program</code> cannot be used together with init because the creation of an
160/// account requires its signature which for PDAs only the currently executing program can provide.
161/// </li>
162/// </ul>
163/// Example:
164/// <pre>
165/// #[derive(Accounts)]
166/// #[instruction(bump: u8)]
167/// pub struct Initialize<'info> {
168/// #[account(
169/// init, payer = payer, space = 8 + 8
170/// seeds = [b"example_seed"], bump = bump
171/// )]
172/// pub pda_data_account: Account<'info, MyData>,
173/// #[account(
174/// init, payer = payer,
175/// space = 8 + 8, owner = other_program.key()
176/// )]
177/// pub account_for_other_program: AccountInfo<'info>,
178/// #[account(
179/// init, payer = payer, space = 8 + 8,
180/// owner = other_program.key(),
181/// seeds = [b"other_seed"], bump
182/// )]
183/// pub pda_for_other_program: AccountInfo<'info>,
184/// #[account(mut)]
185/// pub payer: Signer<'info>,
186/// pub system_program: Program<'info, System>,
187/// pub other_program: Program<'info, OtherProgram>
188/// }
189/// </pre>
190/// </td>
191/// </tr>
192/// <tr>
193/// <td>
194/// <code>#[account(init_if_needed, payer = <target_account>)]</code><br><br>
195/// <code>#[account(init_if_needed, payer = <target_account>, space = <num_bytes>)]</code>
196/// </td>
197/// <td>
198/// Exact same functionality as the <code>init</code> constraint but only runs if the account does not exist yet.<br>
199/// If the account does exist, it still checks whether the given init constraints are correct,
200/// e.g. that the account has the expected amount of space and, if it's a PDA, the correct seeds etc.<br><br>
201/// This feature should be used with care and is therefore behind a feature flag.
202/// You can enable it by importing <code>anchor-lang</code> with the <code>init-if-needed</code> cargo feature.<br>
203/// When using <code>init_if_needed</code>, you need to make sure you properly protect yourself
204/// against re-initialization attacks. You need to include checks in your code that check
205/// that the initialized account cannot be reset to its initial settings after the first time it was
206/// initialized (unless that it what you want).<br>
207/// Because of the possibility of re-initialization attacks and the general guideline that instructions
208/// should avoid having multiple execution flows (which is important so they remain easy to understand),
209/// consider breaking up your instruction into two instructions - one for initializing and one for using
210/// the account - unless you have a good reason not to do so.
211/// <br><br>
212/// Example:
213/// <pre>
214/// #[account]
215/// #[derive(Default)]
216/// pub struct MyData {
217/// pub data: u64
218/// }
219/// #[account]
220/// pub struct OtherData {
221/// pub data: u64
222/// }
223/// #[derive(Accounts)]
224/// pub struct Initialize<'info> {
225/// #[account(init_if_needed, payer = payer)]
226/// pub data_account: Account<'info, MyData>,
227/// #[account(init_if_needed, payer = payer, space = 8 + 8)]
228/// pub data_account_two: Account<'info, OtherData>,
229/// #[account(mut)]
230/// pub payer: Signer<'info>,
231/// pub system_program: Program<'info, System>
232/// }
233/// </pre>
234/// </td>
235/// </tr>
236/// <tr>
237/// <td>
238/// <code>#[account(seeds = <seeds>, bump)]</code><br><br>
239/// <code>#[account(seeds = <seeds>, bump, seeds::program = <expr>)]<br><br>
240/// <code>#[account(seeds = <seeds>, bump = <expr>)]</code><br><br>
241/// <code>#[account(seeds = <seeds>, bump = <expr>, seeds::program = <expr>)]</code><br><br>
242/// </td>
243/// <td>
244/// Checks that given account is a PDA derived from the currently executing program,
245/// the seeds, and if provided, the bump. If not provided, anchor uses the canonical
246/// bump. <br>
247/// Add <code>seeds::program = <expr></code> to derive the PDA from a different
248/// program than the currently executing one.<br>
249/// This constraint behaves slightly differently when used with <code>init</code>.
250/// See its description.
251/// <br><br>
252/// Example:
253/// <pre><code>
254/// #[derive(Accounts)]
255/// #[instruction(first_bump: u8, second_bump: u8)]
256/// pub struct Example {
257/// #[account(seeds = [b"example_seed"], bump)]
258/// pub canonical_pda: AccountInfo<'info>,
259/// #[account(
260/// seeds = [b"example_seed"],
261/// bump,
262/// seeds::program = other_program.key()
263/// )]
264/// pub canonical_pda_two: AccountInfo<'info>,
265/// #[account(seeds = [b"other_seed"], bump = first_bump)]
266/// pub arbitrary_pda: AccountInfo<'info>
267/// #[account(
268/// seeds = [b"other_seed"],
269/// bump = second_bump,
270/// seeds::program = other_program.key()
271/// )]
272/// pub arbitrary_pda_two: AccountInfo<'info>,
273/// pub other_program: Program<'info, OtherProgram>
274/// }
275/// </code></pre>
276/// </td>
277/// </tr>
278/// <tr>
279/// <td>
280/// <code>#[account(has_one = <target_account>)]</code><br><br>
281/// <code>#[account(has_one = <target_account> @ <custom_error>)]</code>
282/// </td>
283/// <td>
284/// Checks the <code>target_account</code> field on the account matches the
285/// key of the <code>target_account</code> field in the Accounts struct.<br>
286/// Custom errors are supported via <code>@</code>.<br><br>
287/// Example:
288/// <pre><code>
289/// #[account(mut, has_one = authority)]
290/// pub data: Account<'info, MyData>,
291/// pub authority: Signer<'info>
292/// </code></pre>
293/// In this example <code>has_one</code> checks that <code>data.authority = authority.key()</code>
294/// </td>
295/// </tr>
296/// <tr>
297/// <td>
298/// <code>#[account(address = <expr>)]</code><br><br>
299/// <code>#[account(address = <expr> @ <custom_error>)]</code>
300/// </td>
301/// <td>
302/// Checks the account key matches the pubkey.<br>
303/// Custom errors are supported via <code>@</code>.<br><br>
304/// Example:
305/// <pre><code>
306/// #[account(address = crate::ID)]
307/// pub data: Account<'info, MyData>,
308/// #[account(address = crate::ID @ MyError::MyErrorCode)]
309/// pub data_two: Account<'info, MyData>
310/// </code></pre>
311/// </td>
312/// </tr>
313/// <tr>
314/// <td>
315/// <code>#[account(owner = <expr>)]</code><br><br>
316/// <code>#[account(owner = <expr> @ <custom_error>)]</code>
317/// </td>
318/// <td>
319/// Checks the account owner matches <code>expr</code>.<br>
320/// Custom errors are supported via <code>@</code>.<br><br>
321/// Example:
322/// <pre><code>
323/// #[account(owner = Token::ID @ MyError::MyErrorCode)]
324/// pub data: Account<'info, MyData>,
325/// #[account(owner = token_program.key())]
326/// pub data_two: Account<'info, MyData>,
327/// pub token_program: Program<'info, Token>
328/// </code></pre>
329/// </td>
330/// </tr>
331/// <tr>
332/// <td>
333/// <code>#[account(executable)]</code>
334/// </td>
335/// <td>
336/// Checks the account is executable (i.e. the account is a program).<br>
337/// You may want to use the <code>Program</code> type instead.<br><br>
338/// Example:
339/// <pre><code>
340/// #[account(executable)]
341/// pub my_program: AccountInfo<'info>
342/// </code></pre>
343/// </td>
344/// </tr>
345/// <tr>
346/// <td>
347/// <code>#[account(rent_exempt = skip)]</code><br><br>
348/// <code>#[account(rent_exempt = enforce)]</code>
349/// </td>
350/// <td>
351/// Enforces rent exemption with <code>= enforce</code>.<br>
352/// Skips rent exemption check that would normally be done
353/// through other constraints with <code>= skip</code>,
354/// e.g. when used with the <code>zero</code> constraint<br><br>
355/// Example:
356/// <pre><code>
357/// #[account(zero, rent_exempt = skip)]
358/// pub skipped_account: Account<'info, MyData>,
359/// #[account(rent_exempt = enforce)]
360/// pub enforced_account: AccountInfo<'info>
361/// </code></pre>
362/// </td>
363/// </tr>
364/// <tr>
365/// <td>
366/// <code>#[account(zero)]</code>
367/// </td>
368/// <td>
369/// Checks the account discriminator is zero.<br>
370/// Enforces rent exemption unless skipped with <code>rent_exempt = skip</code>.<br><br>
371/// Use this constraint if you want to create an account in a previous instruction
372/// and then initialize it in your instruction instead of using <code>init</code>.
373/// This is necessary for accounts that are larger than 10 Kibibyte because those
374/// accounts cannot be created via a CPI (which is what <code>init</code> would do).<br><br>
375/// Anchor adds internal data to the account when using <code>zero</code> just like it
376/// does with <code>init</code> which is why <code>zero</code> implies <code>mut</code>.
377/// <br><br>
378/// Example:
379/// <pre><code>
380/// #[account(zero)]
381/// pub my_account: Account<'info, MyData>
382/// </code></pre>
383/// </td>
384/// </tr>
385/// <tr>
386/// <td>
387/// <code>#[account(close = <target_account>)]</code>
388/// </td>
389/// <td>
390/// Closes the account by:<br>
391/// - Sending the lamports to the specified account<br>
392/// - Assigning the owner to the System Program<br>
393/// - Resetting the data of the account<br><br>
394/// Requires <code>mut</code> to exist on the account.
395/// <br><br>
396/// Example:
397/// <pre><code>
398/// #[account(mut, close = receiver)]
399/// pub data_account: Account<'info, MyData>,
400/// #[account(mut)]
401/// pub receiver: SystemAccount<'info>
402/// </code></pre>
403/// </td>
404/// </tr>
405/// <tr>
406/// <td>
407/// <code>#[account(constraint = <expr>)]</code><br><br><code>#[account(constraint = <expr> @ <custom_error>)]</code>
408/// </td>
409/// <td>
410/// Constraint that checks whether the given expression evaluates to true.<br>
411/// Use this when no other constraint fits your use case.
412/// <br><br>
413/// Example:
414/// <pre><code>
415/// #[account(constraint = one.keys[0].age == two.apple.age)]
416/// pub one: Account<'info, MyData>,
417/// pub two: Account<'info, OtherData>
418/// </code></pre>
419/// </td>
420/// </tr>
421/// <tr>
422/// <td>
423/// <code>#[account(realloc = <space>, realloc::payer = <target>, realloc::zero = <bool>)]</code>
424/// </td>
425/// <td>
426/// Used to <a href="https://docs.rs/solana-program/latest/solana_program/account_info/struct.AccountInfo.html#method.realloc" target = "_blank" rel = "noopener noreferrer">realloc</a>
427/// program account space at the beginning of an instruction.
428/// <br><br>
429/// The account must be marked as <code>mut</code> and applied to either <code>Account</code> or <code>AccountLoader</code> types.
430/// <br><br>
431/// If the change in account data length is additive, lamports will be transferred from the <code>realloc::payer</code> into the
432/// program account in order to maintain rent exemption. Likewise, if the change is subtractive, lamports will be transferred from
433/// the program account back into the <code>realloc::payer</code>.
434/// <br><br>
435/// The <code>realloc::zero</code> constraint is required in order to determine whether the new memory should be zero initialized after
436/// reallocation. Please read the documentation on the <code>AccountInfo::realloc</code> function linked above to understand the
437/// caveats regarding compute units when providing <code>true</code or <code>false</code> to this flag.
438/// <br><br>
439/// The manual use of `AccountInfo::realloc` is discouraged in favor of the `realloc` constraint group due to the lack of native runtime checks
440/// to prevent reallocation over the `MAX_PERMITTED_DATA_INCREASE` limit (which can unintentionally cause account data overwrite other accounts).
441/// The constraint group also ensure account reallocation idempotency but checking and restricting duplicate account reallocation within a single ix.
442/// <br><br>
443/// Example:
444/// <pre>
445/// #[derive(Accounts)]
446/// pub struct Example {
447/// #[account(mut)]
448/// pub payer: Signer<'info>,
449/// #[account(
450/// mut,
451/// seeds = [b"example"],
452/// bump,
453/// realloc = 8 + std::mem::size_of::<MyType>() + 100,
454/// realloc::payer = payer,
455/// realloc::zero = false,
456/// )]
457/// pub acc: Account<'info, MyType>,
458/// pub system_program: Program<'info, System>,
459/// }
460/// </pre>
461/// </td>
462/// </tr>
463/// </tbody>
464/// </table>
465///
466/// # SPL Constraints
467///
468/// Anchor provides constraints that make verifying SPL accounts easier.
469///
470/// <table>
471/// <thead>
472/// <tr>
473/// <th>Attribute</th>
474/// <th>Description</th>
475/// </tr>
476/// </thead>
477/// <tbody>
478/// <tr>
479/// <td>
480/// <code>#[account(token::mint = <target_account>, token::authority = <target_account>)]</code>
481/// <br><br>
482/// <code>#[account(token::mint = <target_account>, token::authority = <target_account>, token::token_program = <target_account>)]</code>
483/// </td>
484/// <td>
485/// Can be used as a check or with <code>init</code> to create a token
486/// account with the given mint address and authority.<br>
487/// When used as a check, it's possible to only specify a subset of the constraints.
488/// <br><br>
489/// Example:
490/// <pre>
491/// use anchor_spl::{mint, token::{TokenAccount, Mint, Token}};
492/// ...
493/// #[account(
494/// init,
495/// payer = payer,
496/// token::mint = mint,
497/// token::authority = payer,
498/// )]
499/// pub token: Account<'info, TokenAccount>,
500/// #[account(address = mint::USDC)]
501/// pub mint: Account<'info, Mint>,
502/// #[account(mut)]
503/// pub payer: Signer<'info>,
504/// pub token_program: Program<'info, Token>,
505/// pub system_program: Program<'info, System>
506/// </pre>
507/// </td>
508/// </tr>
509/// <tr>
510/// <td>
511/// <code>#[account(mint::authority = <target_account>, mint::decimals = <expr>)]</code>
512/// <br><br>
513/// <code>#[account(mint::authority = <target_account>, mint::decimals = <expr>, mint::freeze_authority = <target_account>)]</code>
514/// </td>
515/// <td>
516/// Can be used as a check or with <code>init</code> to create a mint
517/// account with the given mint decimals and mint authority.<br>
518/// The freeze authority is optional when used with <code>init</code>.<br>
519/// When used as a check, it's possible to only specify a subset of the constraints.
520/// <br><br>
521/// Example:
522/// <pre>
523/// use anchor_spl::token::{Mint, Token};
524/// ...
525/// #[account(
526/// init,
527/// payer = payer,
528/// mint::decimals = 9,
529/// mint::authority = payer,
530/// )]
531/// pub mint_one: Account<'info, Mint>,
532/// #[account(
533/// init,
534/// payer = payer,
535/// mint::decimals = 9,
536/// mint::authority = payer,
537/// mint::freeze_authority = payer
538/// )]
539/// pub mint_two: Account<'info, Mint>,
540/// #[account(mut)]
541/// pub payer: Signer<'info>,
542/// pub token_program: Program<'info, Token>,
543/// pub system_program: Program<'info, System>
544/// </pre>
545/// </td>
546/// </tr>
547/// <tr>
548/// <td>
549/// <code>#[account(associated_token::mint = <target_account>, associated_token::authority = <target_account>)]</code>
550/// <br><br>
551/// <code>#[account(associated_token::mint = <target_account>, associated_token::authority = <target_account>, associated_token::token_program = <target_account>)]</code>
552/// </td>
553/// <td>
554/// Can be used as a standalone as a check or with <code>init</code> to create an associated token
555/// account with the given mint address and authority.
556/// <br><br>
557/// Example:
558/// <pre>
559/// use anchor_spl::{
560/// associated_token::AssociatedToken,
561/// mint,
562/// token::{TokenAccount, Mint, Token}
563/// };
564/// ...
565/// #[account(
566/// init,
567/// payer = payer,
568/// associated_token::mint = mint,
569/// associated_token::authority = payer,
570/// )]
571/// pub token: Account<'info, TokenAccount>,
572/// #[account(
573/// associated_token::mint = mint,
574/// associated_token::authority = payer,
575/// )]
576/// pub second_token: Account<'info, TokenAccount>,
577/// #[account(address = mint::USDC)]
578/// pub mint: Account<'info, Mint>,
579/// #[account(mut)]
580/// pub payer: Signer<'info>,
581/// pub token_program: Program<'info, Token>,
582/// pub associated_token_program: Program<'info, AssociatedToken>,
583/// pub system_program: Program<'info, System>
584/// </pre>
585/// </td>
586/// </tr><tr>
587/// <td>
588/// <code>#[account(*::token_program = <target_account>)]</code>
589/// </td>
590/// <td>
591/// The <code>token_program</code> can optionally be overridden.
592/// <br><br>
593/// Example:
594/// <pre>
595/// use anchor_spl::token_interface::{TokenInterface, TokenAccount, Mint};
596/// ...
597/// #[account(
598/// mint::token_program = token_a_token_program,
599/// )]
600/// pub token_a_mint: InterfaceAccount<'info, Mint>,
601/// #[account(
602/// mint::token_program = token_b_token_program,
603/// )]
604/// pub token_b_mint: InterfaceAccount<'info, Mint>,
605/// #[account(
606/// init,
607/// payer = payer,
608/// token::mint = token_a_mint,
609/// token::authority = payer,
610/// token::token_program = token_a_token_program,
611/// )]
612/// pub token_a_account: InterfaceAccount<'info, TokenAccount>,
613/// #[account(
614/// init,
615/// payer = payer,
616/// token::mint = token_b_mint,
617/// token::authority = payer,
618/// token::token_program = token_b_token_program,
619/// )]
620/// pub token_b_account: InterfaceAccount<'info, TokenAccount>,
621/// pub token_a_token_program: Interface<'info, TokenInterface>,
622/// pub token_b_token_program: Interface<'info, TokenInterface>,
623/// #[account(mut)]
624/// pub payer: Signer<'info>,
625/// pub system_program: Program<'info, System>
626/// </pre>
627/// </td>
628/// </tr>
629/// <tbody>
630/// </table>
631#[proc_macro_derive(Accounts, attributes(account, instruction))]
632pub fn derive_accounts(item: TokenStream) -> TokenStream {
633 parse_macro_input!(item as anchor_syn::AccountsStruct)
634 .to_token_stream()
635 .into()
636}