mpl_token_auth_rules/state/v2/constraint/
is_wallet.rs

1use solana_program::{msg, system_program};
2
3use crate::{
4    error::RuleSetError,
5    state::{try_from_bytes, RuleResult},
6    state::{
7        v2::{Constraint, ConstraintType, Str32, HEADER_SECTION},
8        Header,
9    },
10};
11
12/// Constraint that represents a test on whether a pubkey can be signed from a client and therefore
13/// is a true wallet account or not.
14///
15/// The details of this constraint are as follows: a wallet is defined as being both owned by the
16/// System Program and the address is on-curve.  The `field` value in the rule is used to
17/// locate the `Pubkey` in the payload that must be on-curve and for which the owner must be
18/// the System Program.  Note this same `Pubkey` account must also be provided to `Validate`
19/// via the `additional_rule_accounts` argument.  This is so that the `Pubkey`'s owner can be
20/// found from its `AccountInfo` struct.
21pub struct IsWallet<'a> {
22    /// The field in the `Payload` to be checked.
23    pub field: &'a Str32,
24}
25
26impl<'a> IsWallet<'a> {
27    /// Deserialize a constraint from a byte array.
28    pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, RuleSetError> {
29        let field = try_from_bytes::<Str32>(0, Str32::SIZE, bytes)?;
30        Ok(Self { field })
31    }
32
33    /// Serialize a constraint into a byte array.
34    pub fn serialize(field: String) -> Result<Vec<u8>, RuleSetError> {
35        let mut data = Vec::with_capacity(HEADER_SECTION + Str32::SIZE);
36
37        // Header
38        Header::serialize(ConstraintType::IsWallet, Str32::SIZE as u32, &mut data);
39
40        // Constraint
41        // - field
42        let mut field_bytes = [0u8; Str32::SIZE];
43        field_bytes[..field.len()].copy_from_slice(field.as_bytes());
44        data.extend(field_bytes);
45
46        Ok(data)
47    }
48}
49
50impl<'a> Constraint<'a> for IsWallet<'a> {
51    fn constraint_type(&self) -> ConstraintType {
52        ConstraintType::IsWallet
53    }
54
55    fn validate(
56        &self,
57        accounts: &std::collections::HashMap<
58            solana_program::pubkey::Pubkey,
59            &solana_program::account_info::AccountInfo,
60        >,
61        payload: &crate::payload::Payload,
62        _update_rule_state: bool,
63        _rule_set_state_pda: &Option<&solana_program::account_info::AccountInfo>,
64        _rule_authority: &Option<&solana_program::account_info::AccountInfo>,
65    ) -> RuleResult {
66        msg!("Validating IsWallet");
67
68        // Get the `Pubkey` we are checking from the payload.
69        let key = match payload.get_pubkey(&self.field.to_string()) {
70            Some(pubkey) => pubkey,
71            _ => return RuleResult::Error(RuleSetError::MissingPayloadValue.into()),
72        };
73
74        // Get the `AccountInfo` struct for the `Pubkey` and verify that
75        // its owner is the System Program.
76        if let Some(account) = accounts.get(key) {
77            if *account.owner != system_program::ID {
78                // TODO: Change error return to commented line after on-curve syscall
79                // available.
80                return RuleResult::Error(RuleSetError::NotImplemented.into());
81                //return (false, self.to_error());
82            }
83        } else {
84            return RuleResult::Error(RuleSetError::MissingAccount.into());
85        }
86
87        // TODO: Uncomment call to `is_on_curve()` after on-curve sycall available.
88        RuleResult::Error(RuleSetError::NotImplemented.into())
89        //(is_on_curve(key), self.to_error())
90    }
91}