templar_curator_primitives/policy/state/
mod.rs1use alloc::vec::Vec;
7
8use templar_vault_kernel::TargetId;
9
10use super::cap_group::{CapGroupId, CapGroupRecord};
11use super::market_lock::MarketLockSet;
12use super::supply_queue::SupplyQueue;
13
14#[templar_vault_macros::vault_derive(borsh, serde, postcard)]
15#[derive(Clone, PartialEq, Eq)]
16pub struct OrderedMap<K, V> {
17 entries: Vec<(K, V)>,
18}
19
20impl<K, V> Default for OrderedMap<K, V> {
21 fn default() -> Self {
22 Self {
23 entries: Vec::new(),
24 }
25 }
26}
27
28impl<K: PartialEq, V> OrderedMap<K, V> {
29 #[must_use]
30 pub fn new() -> Self {
31 Self::default()
32 }
33
34 #[must_use]
35 pub fn len(&self) -> usize {
36 self.entries.len()
37 }
38
39 #[must_use]
40 pub fn is_empty(&self) -> bool {
41 self.entries.is_empty()
42 }
43
44 pub fn clear(&mut self) {
45 self.entries.clear();
46 }
47
48 pub fn insert(&mut self, key: K, value: V) -> Option<V> {
49 if let Some((_, existing)) = self
50 .entries
51 .iter_mut()
52 .find(|(candidate, _)| candidate == &key)
53 {
54 return Some(core::mem::replace(existing, value));
55 }
56 self.entries.push((key, value));
57 None
58 }
59
60 #[must_use]
61 pub fn get(&self, key: &K) -> Option<&V> {
62 self.entries
63 .iter()
64 .find(|(candidate, _)| candidate == key)
65 .map(|(_, value)| value)
66 }
67
68 #[must_use]
69 pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
70 self.entries
71 .iter_mut()
72 .find(|(candidate, _)| candidate == key)
73 .map(|(_, value)| value)
74 }
75
76 #[must_use]
77 pub fn contains_key(&self, key: &K) -> bool {
78 self.entries.iter().any(|(candidate, _)| candidate == key)
79 }
80
81 pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
82 self.entries.iter().map(|(key, value)| (key, value))
83 }
84
85 pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
86 self.entries.iter_mut().map(|(key, value)| (&*key, value))
87 }
88
89 pub fn keys(&self) -> impl Iterator<Item = &K> {
90 self.entries.iter().map(|(key, _)| key)
91 }
92
93 pub fn values(&self) -> impl Iterator<Item = &V> {
94 self.entries.iter().map(|(_, value)| value)
95 }
96}
97
98impl<K: PartialEq, V> FromIterator<(K, V)> for OrderedMap<K, V> {
99 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
100 let mut map = Self::default();
101 for (key, value) in iter {
102 let _ = map.insert(key, value);
103 }
104 map
105 }
106}
107
108impl<K, V> IntoIterator for OrderedMap<K, V> {
109 type Item = (K, V);
110 type IntoIter = alloc::vec::IntoIter<(K, V)>;
111
112 fn into_iter(self) -> Self::IntoIter {
113 self.entries.into_iter()
114 }
115}
116
117#[templar_vault_macros::vault_derive(borsh, serde, postcard)]
118#[derive(Clone, PartialEq, Eq)]
119pub struct MarketConfig {
120 pub enabled: bool,
121 pub cap: u128,
122 pub cap_group_id: Option<CapGroupId>,
123}
124
125impl MarketConfig {
126 pub fn new(enabled: bool, cap_group_id: Option<CapGroupId>) -> Self {
127 Self {
128 enabled,
129 cap: 0,
130 cap_group_id,
131 }
132 }
133}
134
135impl Default for MarketConfig {
136 fn default() -> Self {
137 Self {
138 enabled: true,
139 cap: 0,
140 cap_group_id: None,
141 }
142 }
143}
144
145#[templar_vault_macros::vault_derive(borsh, serde, postcard)]
147#[derive(Clone, Default)]
148pub struct PolicyState {
149 pub markets: OrderedMap<TargetId, MarketConfig>,
150 pub principals: OrderedMap<TargetId, u128>,
151 pub cap_groups: OrderedMap<CapGroupId, CapGroupRecord>,
152 pub supply_queue: SupplyQueue,
153 pub locks: MarketLockSet,
154}
155
156impl PolicyState {
157 pub fn set_market_config(&mut self, target_id: TargetId, config: MarketConfig) {
158 self.markets.insert(target_id, config);
159 self.refresh_cap_group_principals();
161 }
162
163 pub fn set_principal(&mut self, target_id: TargetId, principal: u128) {
164 self.principals.insert(target_id, principal);
165 self.refresh_cap_group_principals();
167 }
168
169 pub fn principal_for(&self, target_id: TargetId) -> u128 {
171 self.principals.get(&target_id).copied().unwrap_or(0)
172 }
173
174 #[must_use]
176 pub fn external_assets(&self) -> u128 {
177 self.principals
178 .values()
179 .fold(0u128, |acc, p| acc.saturating_add(*p))
180 }
181
182 #[must_use]
186 pub fn compute_cap_group_totals(&self) -> Vec<(CapGroupId, u128)> {
187 let mut totals: Vec<(CapGroupId, u128)> = Vec::new();
188
189 for (target_id, config) in self.markets.iter() {
190 let group_id = match &config.cap_group_id {
191 Some(id) => id.clone(),
192 None => continue,
193 };
194 let principal = self.principal_for(*target_id);
195 if let Some((_, sum)) = totals
196 .iter_mut()
197 .find(|(existing_group_id, _)| *existing_group_id == group_id)
198 {
199 *sum = sum.saturating_add(principal);
200 } else {
201 totals.push((group_id, principal));
202 }
203 }
204
205 totals
206 }
207
208 pub fn refresh_cap_group_principals(&mut self) {
214 let totals = self.compute_cap_group_totals();
215
216 for (group_id, principal) in &totals {
218 if !self.cap_groups.contains_key(group_id) {
219 let record = CapGroupRecord {
221 principal: *principal,
222 ..Default::default()
223 };
224 self.cap_groups.insert(group_id.clone(), record);
225 }
226 }
227
228 for (group_id, record) in self.cap_groups.iter_mut() {
230 let total = totals
231 .iter()
232 .find(|(candidate, _)| candidate == group_id)
233 .map(|(_, sum)| *sum)
234 .unwrap_or(0);
235 record.principal = total;
236 }
237 }
238}