mpl_token_auth_rules/state/v2/constraint/
pubkey_match.rs

1use solana_program::{
2    msg,
3    pubkey::{Pubkey, PUBKEY_BYTES},
4};
5
6use crate::{
7    error::RuleSetError,
8    state::{try_from_bytes, RuleResult},
9    state::{
10        v2::{Constraint, ConstraintType, Str32, HEADER_SECTION},
11        Header,
12    },
13};
14
15/// Constraint representing a direct comparison between `Pubkey`s.
16///
17/// This constraint requires a `PayloadType` value of `PayloadType::Pubkey`. The `field`
18/// value in the rule is used to locate the `Pubkey` in the payload to compare to the `Pubkey`
19/// in the rule.
20pub struct PubkeyMatch<'a> {
21    /// The public key to be compared against.
22    pub pubkey: &'a Pubkey,
23    /// The field in the `Payload` to be compared.
24    pub field: &'a Str32,
25}
26
27impl<'a> PubkeyMatch<'a> {
28    /// Deserialize a constraint from a byte array.
29    pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, RuleSetError> {
30        let pubkey = try_from_bytes::<Pubkey>(0, PUBKEY_BYTES, bytes)?;
31        let field = try_from_bytes::<Str32>(PUBKEY_BYTES, Str32::SIZE, bytes)?;
32
33        Ok(Self { pubkey, field })
34    }
35
36    /// Serialize a constraint into a byte array.
37    pub fn serialize(field: String, pubkey: Pubkey) -> Result<Vec<u8>, RuleSetError> {
38        let length = (PUBKEY_BYTES + Str32::SIZE) as u32;
39        let mut data = Vec::with_capacity(HEADER_SECTION + length as usize);
40
41        // Header
42        Header::serialize(ConstraintType::PubkeyMatch, length, &mut data);
43
44        // Constraint
45        // - pubkey
46        data.extend(pubkey.as_ref());
47        // - field
48        let mut field_bytes = [0u8; Str32::SIZE];
49        field_bytes[..field.len()].copy_from_slice(field.as_bytes());
50        data.extend(field_bytes);
51
52        Ok(data)
53    }
54}
55
56impl<'a> Constraint<'a> for PubkeyMatch<'a> {
57    fn constraint_type(&self) -> ConstraintType {
58        ConstraintType::PubkeyMatch
59    }
60
61    fn validate(
62        &self,
63        _accounts: &std::collections::HashMap<
64            solana_program::pubkey::Pubkey,
65            &solana_program::account_info::AccountInfo,
66        >,
67        payload: &crate::payload::Payload,
68        _update_rule_state: bool,
69        _rule_set_state_pda: &Option<&solana_program::account_info::AccountInfo>,
70        _rule_authority: &Option<&solana_program::account_info::AccountInfo>,
71    ) -> RuleResult {
72        msg!("Validating PubkeyMatch");
73
74        let key = match payload.get_pubkey(&self.field.to_string()) {
75            Some(pubkey) => pubkey,
76            _ => return RuleResult::Error(RuleSetError::MissingPayloadValue.into()),
77        };
78
79        if key == self.pubkey {
80            RuleResult::Success(self.constraint_type().to_error())
81        } else {
82            RuleResult::Failure(self.constraint_type().to_error())
83        }
84    }
85}