open_creator_protocol/
state.rs

1use crate::{action::ActionCtx, errors::OCPErrorCode, royalty::DynamicRoyalty};
2use anchor_lang::prelude::*;
3use anchor_lang::solana_program::pubkey::Pubkey;
4use json_rules_engine_fork::{Rule, Status};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[account]
9#[derive(Default, Serialize, Deserialize)]
10pub struct MintState {
11    pub version: u8,
12    pub bump: [u8; 1],
13    pub mint: Pubkey,
14    pub policy: Pubkey,
15    pub locked_by: Option<Pubkey>,
16    pub last_approved_at: i64,
17    pub last_transferred_at: i64,
18    pub transferred_count: u32,
19}
20
21impl MintState {
22    pub const LEN: usize = 200;
23    pub const SEED: &'static str = "mint_state";
24
25    pub fn record_transfer(&mut self) {
26        self.last_transferred_at = Clock::get().unwrap().unix_timestamp;
27        self.transferred_count = self.transferred_count.checked_add(1).unwrap_or(u32::MAX);
28    }
29    pub fn record_approve(&mut self) {
30        self.last_approved_at = Clock::get().unwrap().unix_timestamp;
31    }
32}
33
34#[account]
35#[derive(Default, Serialize, Deserialize)]
36pub struct Policy {
37    pub version: u8,
38    pub bump: [u8; 1],
39    pub uuid: Pubkey,
40    pub authority: Pubkey,
41    pub dynamic_royalty: Option<DynamicRoyalty>,
42    pub json_rule: Option<String>,
43}
44
45impl Policy {
46    pub const LEN: usize = Policy::JSON_RULE_MAX_LEN + 400 /* with padding */;
47    pub const SEED: &'static str = "policy";
48    pub const MANAGED_AUTHORITY: &'static str = "RULERZZDGsXqd9TeJu5ikLfbXzBFpoDPT8N3FHRhq1T";
49    pub const JSON_RULE_MAX_LEN: usize = 1000;
50
51    pub fn valid(&self) -> Result<()> {
52        match &self.json_rule {
53            Some(json_rule) => {
54                if json_rule.len() > Policy::JSON_RULE_MAX_LEN {
55                    return Err(OCPErrorCode::InvalidPolicyCreation.into());
56                }
57                serde_json::from_str::<Rule>(json_rule).expect("json_rule should be valid");
58            }
59            None => {}
60        }
61        match &self.dynamic_royalty {
62            Some(dynamic_royalty) => {
63                dynamic_royalty.valid()?;
64            }
65            None => {}
66        }
67        Ok(())
68    }
69
70    pub fn is_managed(&self) -> bool {
71        self.authority.to_string() == Policy::MANAGED_AUTHORITY
72    }
73
74    pub fn matches(&self, ctx: &ActionCtx) -> Result<()> {
75        match &self.json_rule {
76            Some(json_rule) => {
77                if json_rule.is_empty() {
78                    return Ok(());
79                }
80                let rule: Rule = serde_json::from_str::<Rule>(json_rule).expect("json_rule should be valid");
81                let fact: &Value = &serde_json::to_value::<&ActionCtx>(ctx).expect("action_ctx should be serializable");
82                let result = rule.check_value(fact);
83                if result.condition_result.status != Status::Met {
84                    msg!("Policy does not match: {}", result.condition_result.name);
85                    msg!("fact: {}", fact);
86                    return Err(OCPErrorCode::InvalidPolicyEvaluation.into());
87                }
88            }
89            None => {}
90        }
91
92        Ok(())
93    }
94
95    pub fn signer_seeds(&self) -> [&[u8]; 3] {
96        [Policy::SEED.as_bytes(), self.uuid.as_ref(), &self.bump]
97    }
98
99    pub fn get_freeze_authority(&self, upstream_authority: Pubkey) -> Pubkey {
100        let (freeze_authority, _) = Pubkey::find_program_address(&[upstream_authority.as_ref()], &community_managed_token::id());
101        freeze_authority
102    }
103}