Skip to main content

anchor_lang/accounts/
signer.rs

1//! Type validating that the account signed the transaction
2use {
3    crate::{
4        error::ErrorCode,
5        solana_program::{account_info::AccountInfo, instruction::AccountMeta, pubkey::Pubkey},
6        Accounts, AccountsExit, Key, Result, ToAccountInfos, ToAccountMetas,
7    },
8    std::{collections::BTreeSet, ops::Deref},
9};
10
11/// Type validating that the account signed the transaction. No other ownership
12/// or type checks are done. If this is used, one should not try to access the
13/// underlying account data.
14///
15/// Checks:
16///
17/// - `Signer.info.is_signer == true`
18///
19/// # Example
20/// ```ignore
21/// #[account]
22/// #[derive(Default)]
23/// pub struct MyData {
24///     pub data: u64
25/// }
26///
27/// #[derive(Accounts)]
28/// pub struct Example<'info> {
29///     #[account(init, payer = payer)]
30///     pub my_acc: Account<'info, MyData>,
31///     #[account(mut)]
32///     pub payer: Signer<'info>,
33///     pub system_program: Program<'info, System>
34/// }
35/// ```
36///
37/// When creating an account with `init`, the `payer` needs to sign the transaction.
38#[derive(Debug, Clone)]
39pub struct Signer<'info> {
40    info: &'info AccountInfo<'info>,
41}
42
43impl<'info> Signer<'info> {
44    fn new(info: &'info AccountInfo<'info>) -> Signer<'info> {
45        Self { info }
46    }
47
48    /// Deserializes the given `info` into a `Signer`.
49    #[inline(never)]
50    pub fn try_from(info: &'info AccountInfo<'info>) -> Result<Signer<'info>> {
51        if !info.is_signer {
52            return Err(ErrorCode::AccountNotSigner.into());
53        }
54        Ok(Signer::new(info))
55    }
56}
57
58impl<'info, B> Accounts<'info, B> for Signer<'info> {
59    #[inline(never)]
60    fn try_accounts(
61        _program_id: &Pubkey,
62        accounts: &mut &'info [AccountInfo<'info>],
63        _ix_data: &[u8],
64        _bumps: &mut B,
65        _reallocs: &mut BTreeSet<Pubkey>,
66    ) -> Result<Self> {
67        if accounts.is_empty() {
68            return Err(ErrorCode::AccountNotEnoughKeys.into());
69        }
70        let account = &accounts[0];
71        *accounts = &accounts[1..];
72        Signer::try_from(account)
73    }
74}
75
76impl<'info> AccountsExit<'info> for Signer<'info> {}
77
78impl ToAccountMetas for Signer<'_> {
79    fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
80        let is_signer = is_signer.unwrap_or(self.info.is_signer);
81        let meta = match self.info.is_writable {
82            false => AccountMeta::new_readonly(*self.info.key, is_signer),
83            true => AccountMeta::new(*self.info.key, is_signer),
84        };
85        vec![meta]
86    }
87}
88
89impl<'info> ToAccountInfos<'info> for Signer<'info> {
90    fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
91        vec![self.info.clone()]
92    }
93}
94
95impl<'info> AsRef<AccountInfo<'info>> for Signer<'info> {
96    fn as_ref(&self) -> &AccountInfo<'info> {
97        self.info
98    }
99}
100
101impl<'info> Deref for Signer<'info> {
102    type Target = AccountInfo<'info>;
103
104    fn deref(&self) -> &Self::Target {
105        self.info
106    }
107}
108
109impl Key for Signer<'_> {
110    fn key(&self) -> Pubkey {
111        *self.info.key
112    }
113}