Skip to main content

dpp/data_contract/change_control_rules/v0/
mod.rs

1use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers;
2use crate::data_contract::group::Group;
3use crate::data_contract::GroupContractPosition;
4use crate::group::action_taker::{ActionGoal, ActionTaker};
5#[cfg(feature = "json-conversion")]
6use crate::serialization::json_safe_fields;
7use bincode::{Decode, DecodeUntrusted, Encode};
8use platform_value::Identifier;
9use serde::{Deserialize, Serialize};
10use std::collections::BTreeMap;
11use std::fmt;
12
13#[cfg_attr(feature = "json-conversion", json_safe_fields)]
14#[derive(
15    Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, Default, DecodeUntrusted,
16)]
17#[serde(rename_all = "camelCase")]
18pub struct ChangeControlRulesV0 {
19    /// This is who is authorized to make such a change
20    pub authorized_to_make_change: AuthorizedActionTakers,
21    /// This is who is authorized to make such a change to the people authorized to make a change
22    pub admin_action_takers: AuthorizedActionTakers,
23    /// Are we allowed to change to None in the future
24    pub changing_authorized_action_takers_to_no_one_allowed: bool,
25    /// Are we allowed to change the admin action takers to no one in the future
26    pub changing_admin_action_takers_to_no_one_allowed: bool,
27    /// Can the admin action takers change themselves
28    pub self_changing_admin_action_takers_allowed: bool,
29}
30
31impl ChangeControlRulesV0 {
32    pub fn can_make_change(
33        &self,
34        contract_owner_id: &Identifier,
35        main_group: Option<GroupContractPosition>,
36        groups: &BTreeMap<GroupContractPosition, Group>,
37        action_taker: &ActionTaker,
38        goal: ActionGoal,
39    ) -> bool {
40        self.authorized_to_make_change.allowed_for_action_taker(
41            contract_owner_id,
42            main_group,
43            groups,
44            action_taker,
45            goal,
46        )
47    }
48    pub fn can_change_authorized_action_takers(
49        &self,
50        controlling_action_takers: &AuthorizedActionTakers,
51        contract_owner_id: &Identifier,
52        main_group: Option<GroupContractPosition>,
53        groups: &BTreeMap<GroupContractPosition, Group>,
54        action_taker: &ActionTaker,
55        goal: ActionGoal,
56    ) -> bool {
57        if !self.changing_authorized_action_takers_to_no_one_allowed
58            && controlling_action_takers == &AuthorizedActionTakers::NoOne
59        {
60            return false;
61        }
62        self.admin_action_takers.allowed_for_action_taker(
63            contract_owner_id,
64            main_group,
65            groups,
66            action_taker,
67            goal,
68        )
69    }
70
71    pub fn can_change_admin_action_takers(
72        &self,
73        admin_action_takers: &AuthorizedActionTakers,
74        contract_owner_id: &Identifier,
75        main_group: Option<GroupContractPosition>,
76        groups: &BTreeMap<GroupContractPosition, Group>,
77        action_taker: &ActionTaker,
78        goal: ActionGoal,
79    ) -> bool {
80        if !self.self_changing_admin_action_takers_allowed {
81            return false;
82        }
83        if !self.changing_admin_action_takers_to_no_one_allowed
84            && admin_action_takers == &AuthorizedActionTakers::NoOne
85        {
86            return false;
87        }
88        self.admin_action_takers.allowed_for_action_taker(
89            contract_owner_id,
90            main_group,
91            groups,
92            action_taker,
93            goal,
94        )
95    }
96
97    pub fn can_change_to(
98        &self,
99        other: &ChangeControlRulesV0,
100        contract_owner_id: &Identifier,
101        main_group: Option<GroupContractPosition>,
102        groups: &BTreeMap<GroupContractPosition, Group>,
103        action_taker: &ActionTaker,
104        goal: ActionGoal,
105    ) -> bool {
106        // First, check if the action taker is allowed to make any changes at all
107        if !self.authorized_to_make_change.allowed_for_action_taker(
108            contract_owner_id,
109            main_group,
110            groups,
111            action_taker,
112            goal,
113        ) {
114            return false;
115        }
116
117        // Check if authorized_to_make_change is being modified
118        if self.authorized_to_make_change != other.authorized_to_make_change {
119            // Changing the authorized action takers requires the action_taker to be allowed by
120            // authorized_to_change_authorized_action_takers in the current rules
121            if !self.admin_action_takers.allowed_for_action_taker(
122                contract_owner_id,
123                main_group,
124                groups,
125                action_taker,
126                goal,
127            ) {
128                return false;
129            }
130
131            // If we are changing to NoOne, ensure it's allowed
132            if let AuthorizedActionTakers::NoOne = other.authorized_to_make_change {
133                if !self.changing_authorized_action_takers_to_no_one_allowed {
134                    return false;
135                }
136            }
137        }
138
139        // Check if authorized_to_change_authorized_action_takers is being modified
140        if self.admin_action_takers != other.admin_action_takers {
141            if !self.self_changing_admin_action_takers_allowed {
142                return false;
143            }
144
145            // Must be allowed by the current authorized_to_change_authorized_action_takers
146            if !self.admin_action_takers.allowed_for_action_taker(
147                contract_owner_id,
148                main_group,
149                groups,
150                action_taker,
151                goal,
152            ) {
153                return false;
154            }
155
156            // If we are changing to NoOne, ensure it's allowed
157            if let AuthorizedActionTakers::NoOne = other.admin_action_takers {
158                if !self.changing_admin_action_takers_to_no_one_allowed {
159                    return false;
160                }
161            }
162        }
163
164        // If we reach here, the changes are allowed
165        true
166    }
167}
168
169impl fmt::Display for ChangeControlRulesV0 {
170    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171        write!(
172            f,
173            "ChangeControlRulesV0 {{\n  \
174            authorized_to_make_change: {},\n  \
175            admin_action_takers: {},\n  \
176            changing_authorized_action_takers_to_no_one_allowed: {},\n  \
177            changing_admin_action_takers_to_no_one_allowed: {},\n  \
178            self_changing_admin_action_takers_allowed: {}\n\
179            }}",
180            self.authorized_to_make_change,
181            self.admin_action_takers,
182            self.changing_authorized_action_takers_to_no_one_allowed,
183            self.changing_admin_action_takers_to_no_one_allowed,
184            self.self_changing_admin_action_takers_allowed
185        )
186    }
187}