mpl_token_auth_rules/state/v2/constraint/
pda_match.rs1use solana_program::{
2 msg,
3 pubkey::{Pubkey, PUBKEY_BYTES},
4};
5
6use crate::{
7 error::RuleSetError,
8 state::RuleResult,
9 state::{
10 try_from_bytes,
11 v2::{Constraint, ConstraintType, Str32, HEADER_SECTION},
12 Header,
13 },
14 utils::assert_derivation,
15};
16
17const DEFAULT_PUBKEY: Pubkey = Pubkey::new_from_array([0u8; 32]);
18
19pub struct PDAMatch<'a> {
26 pub program: &'a Pubkey,
29 pub pda_field: &'a Str32,
31 pub seeds_field: &'a Str32,
33}
34
35impl<'a> PDAMatch<'a> {
36 pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, RuleSetError> {
38 let program = try_from_bytes::<Pubkey>(0, PUBKEY_BYTES, bytes)?;
39 let mut cursor = PUBKEY_BYTES;
40
41 let pda_field = try_from_bytes::<Str32>(cursor, Str32::SIZE, bytes)?;
42 cursor += Str32::SIZE;
43
44 let seeds_field = try_from_bytes::<Str32>(cursor, Str32::SIZE, bytes)?;
45
46 Ok(Self {
47 program,
48 pda_field,
49 seeds_field,
50 })
51 }
52
53 pub fn serialize(
55 pda_field: String,
56 program: Option<Pubkey>,
57 seeds_field: String,
58 ) -> Result<Vec<u8>, RuleSetError> {
59 let length = (PUBKEY_BYTES + Str32::SIZE + Str32::SIZE) as u32;
60 let mut data = Vec::with_capacity(HEADER_SECTION + length as usize);
61
62 Header::serialize(ConstraintType::PDAMatch, length, &mut data);
64
65 let program = program.unwrap_or(DEFAULT_PUBKEY);
68 data.extend(program.as_ref());
69 let mut field_bytes = [0u8; Str32::SIZE];
71 field_bytes[..pda_field.len()].copy_from_slice(pda_field.as_bytes());
72 data.extend(field_bytes);
73 let mut field_bytes = [0u8; Str32::SIZE];
75 field_bytes[..seeds_field.len()].copy_from_slice(seeds_field.as_bytes());
76 data.extend(field_bytes);
77
78 Ok(data)
79 }
80}
81
82impl<'a> Constraint<'a> for PDAMatch<'a> {
83 fn constraint_type(&self) -> ConstraintType {
84 ConstraintType::PDAMatch
85 }
86
87 fn validate(
88 &self,
89 accounts: &std::collections::HashMap<
90 solana_program::pubkey::Pubkey,
91 &solana_program::account_info::AccountInfo,
92 >,
93 payload: &crate::payload::Payload,
94 _update_rule_state: bool,
95 _rule_set_state_pda: &Option<&solana_program::account_info::AccountInfo>,
96 _rule_authority: &Option<&solana_program::account_info::AccountInfo>,
97 ) -> RuleResult {
98 msg!("Validating PDAMatch");
99
100 let account = match payload.get_pubkey(&self.pda_field.to_string()) {
102 Some(pubkey) => pubkey,
103 _ => return RuleResult::Error(RuleSetError::MissingPayloadValue.into()),
104 };
105
106 let seeds = match payload.get_seeds(&self.seeds_field.to_string()) {
108 Some(seeds) => seeds,
109 _ => return RuleResult::Error(RuleSetError::MissingPayloadValue.into()),
110 };
111
112 let program = match self.program {
114 &DEFAULT_PUBKEY => {
115 match accounts.get(account) {
117 Some(account) => account.owner,
118 _ => return RuleResult::Error(RuleSetError::MissingAccount.into()),
119 }
120 }
121 _ => self.program,
123 };
124
125 let vec_of_slices = seeds
127 .seeds
128 .iter()
129 .map(Vec::as_slice)
130 .collect::<Vec<&[u8]>>();
131
132 if let Ok(_bump) = assert_derivation(program, account, &vec_of_slices) {
133 RuleResult::Success(self.constraint_type().to_error())
134 } else {
135 RuleResult::Failure(self.constraint_type().to_error())
136 }
137 }
138}