mpl_token_auth_rules/state/v2/constraint/
program_owned.rs1use solana_program::{
2 msg,
3 program_error::ProgramError,
4 pubkey::{Pubkey, PUBKEY_BYTES},
5};
6
7use crate::{
8 error::RuleSetError,
9 state::RuleResult,
10 state::{
11 try_from_bytes,
12 v2::{Constraint, ConstraintType, Str32, HEADER_SECTION},
13 Header,
14 },
15 utils::is_zeroed,
16};
17
18pub struct ProgramOwned<'a> {
26 pub program: &'a Pubkey,
28 pub field: &'a Str32,
30}
31
32impl<'a> ProgramOwned<'a> {
33 pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, RuleSetError> {
35 let program = try_from_bytes::<Pubkey>(0, PUBKEY_BYTES, bytes)?;
36 let field = try_from_bytes::<Str32>(PUBKEY_BYTES, Str32::SIZE, bytes)?;
37
38 Ok(Self { program, field })
39 }
40
41 pub fn serialize(field: String, program: Pubkey) -> Result<Vec<u8>, RuleSetError> {
43 let length = (PUBKEY_BYTES + Str32::SIZE) as u32;
44 let mut data = Vec::with_capacity(HEADER_SECTION + length as usize);
45
46 Header::serialize(ConstraintType::ProgramOwned, length, &mut data);
48
49 data.extend(program.as_ref());
52 let mut field_bytes = [0u8; Str32::SIZE];
54 field_bytes[..field.len()].copy_from_slice(field.as_bytes());
55 data.extend(field_bytes);
56
57 Ok(data)
58 }
59}
60
61impl<'a> Constraint<'a> for ProgramOwned<'a> {
62 fn constraint_type(&self) -> ConstraintType {
63 ConstraintType::ProgramOwned
64 }
65
66 fn validate(
67 &self,
68 accounts: &std::collections::HashMap<
69 solana_program::pubkey::Pubkey,
70 &solana_program::account_info::AccountInfo,
71 >,
72 payload: &crate::payload::Payload,
73 _update_rule_state: bool,
74 _rule_set_state_pda: &Option<&solana_program::account_info::AccountInfo>,
75 _rule_authority: &Option<&solana_program::account_info::AccountInfo>,
76 ) -> RuleResult {
77 msg!("Validating ProgramOwned");
78
79 let key = match payload.get_pubkey(&self.field.to_string()) {
80 Some(pubkey) => pubkey,
81 _ => return RuleResult::Error(RuleSetError::MissingPayloadValue.into()),
82 };
83
84 if let Some(account) = accounts.get(key) {
85 let data = match account.data.try_borrow() {
86 Ok(data) => data,
87 Err(_) => return RuleResult::Error(ProgramError::AccountBorrowFailed),
88 };
89
90 if is_zeroed(&data) {
91 if data.len() == 0 {
93 msg!("Account data is empty");
94 } else {
95 msg!("Account data is zeroed");
96 }
97
98 return RuleResult::Error(self.constraint_type().to_error());
100 } else if *account.owner == *self.program {
101 return RuleResult::Success(self.constraint_type().to_error());
102 }
103 } else {
104 return RuleResult::Error(RuleSetError::MissingAccount.into());
105 }
106
107 RuleResult::Failure(self.constraint_type().to_error())
108 }
109}