templar_vault_kernel/fee/
mod.rs1use alloc::string::String;
13
14use crate::math::wad::Wad;
15use crate::types::Address;
16
17#[templar_vault_macros::vault_derive(borsh, serde, postcard)]
24#[derive(Clone, PartialEq, Eq)]
25pub struct Fee<T> {
26 pub fee: T,
28 pub recipient: String,
30}
31
32impl<T> Fee<T> {
33 #[inline]
35 #[must_use]
36 pub fn new(fee: T, recipient: impl Into<String>) -> Self {
37 Self {
38 fee,
39 recipient: recipient.into(),
40 }
41 }
42}
43
44#[templar_vault_macros::vault_derive(borsh, serde, postcard)]
49#[derive(Clone, PartialEq, Eq)]
50pub struct Fees<T> {
51 pub performance: Fee<T>,
53 pub management: Fee<T>,
55 pub max_total_assets_growth_rate: Option<T>,
61}
62
63impl<T> Fees<T> {
64 #[inline]
66 #[must_use]
67 pub const fn new(
68 performance: Fee<T>,
69 management: Fee<T>,
70 max_total_assets_growth_rate: Option<T>,
71 ) -> Self {
72 Self {
73 performance,
74 management,
75 max_total_assets_growth_rate,
76 }
77 }
78}
79
80#[templar_vault_macros::vault_derive(borsh)]
91#[derive(Clone, Copy, PartialEq, Eq)]
92pub struct FeeSlot {
93 pub fee_wad: Wad,
95 pub recipient: Address,
97}
98
99impl FeeSlot {
100 #[inline]
102 #[must_use]
103 pub const fn new(fee_wad: Wad, recipient: Address) -> Self {
104 Self { fee_wad, recipient }
105 }
106
107 pub const ZERO: Self = Self {
108 fee_wad: Wad::ZERO,
109 recipient: Address([0u8; 32]),
110 };
111
112 #[inline]
114 #[must_use]
115 pub const fn zero() -> Self {
116 Self::ZERO
117 }
118
119 #[inline]
120 #[must_use]
121 pub fn has_rate(&self) -> bool {
122 !self.fee_wad.is_zero()
123 }
124
125 #[inline]
127 #[must_use]
128 pub fn is_zero_rate(&self) -> bool {
129 !self.has_rate()
130 }
131}
132
133impl Default for FeeSlot {
134 fn default() -> Self {
135 Self::zero()
136 }
137}
138
139#[templar_vault_macros::vault_derive(borsh)]
144#[derive(Clone, Copy, PartialEq, Eq)]
145pub struct FeesSpec {
146 pub performance: FeeSlot,
148 pub management: FeeSlot,
150 pub max_total_assets_growth_rate: Option<Wad>,
154}
155
156impl FeesSpec {
157 #[inline]
159 #[must_use]
160 pub const fn new(
161 performance: FeeSlot,
162 management: FeeSlot,
163 max_total_assets_growth_rate: Option<Wad>,
164 ) -> Self {
165 Self {
166 performance,
167 management,
168 max_total_assets_growth_rate,
169 }
170 }
171
172 #[inline]
173 #[must_use]
174 pub fn has_active_slot_fees(&self) -> bool {
175 self.performance.has_rate() || self.management.has_rate()
176 }
177
178 #[inline]
179 #[must_use]
180 pub fn has_growth_cap(&self) -> bool {
181 self.max_total_assets_growth_rate.is_some()
182 }
183
184 #[inline]
186 #[must_use]
187 pub fn is_zero(&self) -> bool {
188 !self.has_active_slot_fees() && !self.has_growth_cap()
189 }
190
191 pub const ZERO: Self = Self {
192 performance: FeeSlot::ZERO,
193 management: FeeSlot::ZERO,
194 max_total_assets_growth_rate: None,
195 };
196
197 #[inline]
199 #[must_use]
200 pub const fn zero() -> Self {
201 Self::ZERO
202 }
203}
204
205impl Default for FeesSpec {
206 fn default() -> Self {
207 Self::zero()
208 }
209}
210
211#[cfg(feature = "serde")]
212mod serde_impl {
213 use super::*;
214 use serde::{Deserialize, Deserializer, Serialize, Serializer};
215
216 #[cfg(any(not(feature = "postcard"), not(target_arch = "wasm32")))]
217 #[derive(Serialize, Deserialize)]
218 struct FeeSlotFields {
219 fee_wad: Wad,
220 recipient: Address,
221 }
222
223 #[cfg(any(not(feature = "postcard"), not(target_arch = "wasm32")))]
224 #[derive(Serialize, Deserialize)]
225 struct FeesSpecFields {
226 performance: FeeSlot,
227 management: FeeSlot,
228 max_total_assets_growth_rate: Option<Wad>,
229 }
230
231 impl Serialize for FeeSlot {
232 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
233 where
234 S: Serializer,
235 {
236 #[cfg(not(target_arch = "wasm32"))]
237 #[cfg(feature = "postcard")]
238 if serializer.is_human_readable() {
239 return FeeSlotFields {
240 fee_wad: self.fee_wad,
241 recipient: self.recipient,
242 }
243 .serialize(serializer);
244 }
245
246 #[cfg(not(feature = "postcard"))]
247 {
248 FeeSlotFields {
249 fee_wad: self.fee_wad,
250 recipient: self.recipient,
251 }
252 .serialize(serializer)
253 }
254
255 #[cfg(feature = "postcard")]
256 (&self.fee_wad, &self.recipient).serialize(serializer)
257 }
258 }
259
260 impl<'de> Deserialize<'de> for FeeSlot {
261 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
262 where
263 D: Deserializer<'de>,
264 {
265 #[cfg(not(target_arch = "wasm32"))]
266 #[cfg(feature = "postcard")]
267 if deserializer.is_human_readable() {
268 let value = FeeSlotFields::deserialize(deserializer)?;
269 return Ok(Self::new(value.fee_wad, value.recipient));
270 }
271
272 #[cfg(not(feature = "postcard"))]
273 {
274 let value = FeeSlotFields::deserialize(deserializer)?;
275 Ok(Self::new(value.fee_wad, value.recipient))
276 }
277
278 #[cfg(feature = "postcard")]
279 <(Wad, Address)>::deserialize(deserializer)
280 .map(|(fee_wad, recipient)| Self { fee_wad, recipient })
281 }
282 }
283
284 impl Serialize for FeesSpec {
285 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
286 where
287 S: Serializer,
288 {
289 #[cfg(not(target_arch = "wasm32"))]
290 #[cfg(feature = "postcard")]
291 if serializer.is_human_readable() {
292 return FeesSpecFields {
293 performance: self.performance,
294 management: self.management,
295 max_total_assets_growth_rate: self.max_total_assets_growth_rate,
296 }
297 .serialize(serializer);
298 }
299
300 #[cfg(not(feature = "postcard"))]
301 {
302 FeesSpecFields {
303 performance: self.performance,
304 management: self.management,
305 max_total_assets_growth_rate: self.max_total_assets_growth_rate,
306 }
307 .serialize(serializer)
308 }
309
310 #[cfg(feature = "postcard")]
311 (
312 &self.performance,
313 &self.management,
314 &self.max_total_assets_growth_rate,
315 )
316 .serialize(serializer)
317 }
318 }
319
320 impl<'de> Deserialize<'de> for FeesSpec {
321 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
322 where
323 D: Deserializer<'de>,
324 {
325 #[cfg(not(target_arch = "wasm32"))]
326 #[cfg(feature = "postcard")]
327 if deserializer.is_human_readable() {
328 let value = FeesSpecFields::deserialize(deserializer)?;
329 return Ok(Self::new(
330 value.performance,
331 value.management,
332 value.max_total_assets_growth_rate,
333 ));
334 }
335
336 #[cfg(not(feature = "postcard"))]
337 {
338 let value = FeesSpecFields::deserialize(deserializer)?;
339 Ok(Self::new(
340 value.performance,
341 value.management,
342 value.max_total_assets_growth_rate,
343 ))
344 }
345
346 #[cfg(feature = "postcard")]
347 <(FeeSlot, FeeSlot, Option<Wad>)>::deserialize(deserializer).map(
348 |(performance, management, max_total_assets_growth_rate)| Self {
349 performance,
350 management,
351 max_total_assets_growth_rate,
352 },
353 )
354 }
355 }
356}
357
358#[cfg(test)]
361mod tests;