anchor_lang/accounts/
signer.rs

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