mpl_token_auth_rules/state/v2/constraint/
amount.rs1use solana_program::msg;
2
3use crate::{
4 error::RuleSetError,
5 state::{try_from_bytes, RuleResult},
6 state::{
7 v2::{Constraint, ConstraintType, Operator, Str32, HEADER_SECTION, U64_BYTES},
8 Header,
9 },
10};
11
12pub struct Amount<'a> {
18 pub amount: &'a u64,
20 pub operator: &'a u64,
22 pub field: &'a Str32,
24}
25
26impl<'a> Amount<'a> {
27 pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, RuleSetError> {
29 let amount = try_from_bytes::<u64>(0, U64_BYTES, bytes)?;
31 let mut cursor = U64_BYTES;
32
33 let operator = try_from_bytes::<u64>(cursor, U64_BYTES, bytes)?;
35 cursor += U64_BYTES;
36
37 let field = try_from_bytes::<Str32>(cursor, Str32::SIZE, bytes)?;
39
40 Ok(Self {
41 amount,
42 operator,
43 field,
44 })
45 }
46
47 pub fn serialize(
49 field: String,
50 operator: Operator,
51 amount: u64,
52 ) -> Result<Vec<u8>, RuleSetError> {
53 let length = (U64_BYTES + U64_BYTES + Str32::SIZE) as u32;
55 let mut data = Vec::with_capacity(HEADER_SECTION + length as usize);
56
57 Header::serialize(ConstraintType::Amount, length, &mut data);
59
60 data.extend(u64::to_le_bytes(amount));
63 data.extend(u64::to_le_bytes(operator as u64));
65 let mut field_bytes = [0u8; Str32::SIZE];
67 field_bytes[..field.len()].copy_from_slice(field.as_bytes());
68 data.extend(field_bytes);
69
70 Ok(data)
71 }
72}
73
74impl<'a> Constraint<'a> for Amount<'a> {
75 fn constraint_type(&self) -> ConstraintType {
76 ConstraintType::Amount
77 }
78
79 fn validate(
80 &self,
81 _accounts: &std::collections::HashMap<
82 solana_program::pubkey::Pubkey,
83 &solana_program::account_info::AccountInfo,
84 >,
85 payload: &crate::payload::Payload,
86 _update_rule_state: bool,
87 _rule_set_state_pda: &Option<&solana_program::account_info::AccountInfo>,
88 _rule_authority: &Option<&solana_program::account_info::AccountInfo>,
89 ) -> RuleResult {
90 msg!("Validating Amount");
91 let condition_type = self.constraint_type();
92
93 if let Some(payload_amount) = &payload.get_amount(&self.field.to_string()) {
94 let operator_fn = match Operator::try_from(*self.operator) {
95 Ok(Operator::Lt) => PartialOrd::lt,
96 Ok(Operator::LtEq) => PartialOrd::le,
97 Ok(Operator::Eq) => PartialEq::eq,
98 Ok(Operator::Gt) => PartialOrd::gt,
99 Ok(Operator::GtEq) => PartialOrd::ge,
100 Err(_) => return RuleResult::Failure(condition_type.to_error()),
102 };
103
104 if operator_fn(payload_amount, self.amount) {
105 RuleResult::Success(condition_type.to_error())
106 } else {
107 RuleResult::Failure(condition_type.to_error())
108 }
109 } else {
110 RuleResult::Error(RuleSetError::MissingPayloadValue.into())
111 }
112 }
113}