templar_common/vault/
wad.rs1use core::ops::Div;
2use std::collections::BTreeMap;
3use std::ops::{Add, Sub};
4
5use near_sdk::borsh::schema::{add_definition, Declaration, Definition};
6use near_sdk::borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
7use near_sdk::serde::{Deserialize, Serialize};
8use primitive_types::{U256, U512};
9use schemars::JsonSchema;
10
11use crate::schemars::r#gen::SchemaGenerator;
12use crate::schemars::schema::Schema;
13
14pub type WIDE = U512;
15
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
17pub struct Number(pub U256);
18
19impl Serialize for Number {
20 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21 where
22 S: near_sdk::serde::Serializer,
23 {
24 serializer.serialize_str(&self.0.to_string())
25 }
26}
27
28impl<'de> Deserialize<'de> for Number {
29 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
30 where
31 D: near_sdk::serde::Deserializer<'de>,
32 {
33 let s = <String as near_sdk::serde::Deserialize>::deserialize(deserializer)?;
34 U256::from_dec_str(&s)
35 .map(Number)
36 .map_err(|_| near_sdk::serde::de::Error::custom("invalid decimal string for U256"))
37 }
38}
39
40impl Number {
41 pub const ZERO: Self = Number(U256([0, 0, 0, 0]));
42
43 #[inline]
44 #[must_use]
45 pub fn zero() -> Self {
46 Self::ZERO
47 }
48
49 #[inline]
50 #[must_use]
51 pub fn one() -> Self {
52 Number(U256::one())
53 }
54
55 #[inline]
56 #[must_use]
57 pub fn is_zero(&self) -> bool {
58 self.0.is_zero()
59 }
60
61 #[inline]
62 #[must_use]
63 pub fn as_u128_trunc(self) -> u128 {
64 let mut b32 = [0u8; 32];
65 self.0.write_as_little_endian(&mut b32);
66 let mut b16 = [0u8; 16];
67 b16.copy_from_slice(&b32[..16]);
68 u128::from_le_bytes(b16)
69 }
70
71 #[inline]
72 #[must_use]
73 pub fn saturating_add(self, other: Number) -> Number {
74 Number(self.0.saturating_add(other.0))
75 }
76
77 #[inline]
78 #[must_use]
79 pub fn saturating_sub(self, other: Number) -> Number {
80 Number(self.0.saturating_sub(other.0))
81 }
82
83 #[inline]
84 fn as_u256_trunc(q: U512) -> U256 {
85 let mut b64 = [0u8; 64];
86 q.write_as_little_endian(&mut b64);
87 U256::from_little_endian(&b64[..32])
88 }
89
90 #[inline]
91 #[must_use]
92 pub fn mul_div_floor(multiplicand: Number, multiplier: Number, denominator: Number) -> Number {
93 if denominator.is_zero() {
94 return Number::zero();
95 }
96 let product = multiplicand.0.full_mul(multiplier.0);
97 let quotient = product / U512::from(denominator.0);
98 Number(Self::as_u256_trunc(quotient))
99 }
100
101 #[inline]
102 #[must_use]
103 pub fn mul_div_ceil(multiplicand: Number, multiplier: Number, denominator: Number) -> Number {
104 if denominator.is_zero() {
105 return Number::zero();
106 }
107 let product = multiplicand.0.full_mul(multiplier.0);
108 let wide_denominator = U512::from(denominator.0);
109 let quotient = product / wide_denominator;
110 let remainder = product % wide_denominator;
111 let base = Number(Self::as_u256_trunc(quotient));
112 if remainder.is_zero() {
113 base
114 } else {
115 base.saturating_add(Number::one())
116 }
117 }
118}
119
120impl From<u128> for Number {
121 fn from(v: u128) -> Self {
122 Number(U256::from(v))
123 }
124}
125
126impl From<Number> for u128 {
127 fn from(n: Number) -> u128 {
128 n.as_u128_trunc()
129 }
130}
131
132impl From<U256> for Number {
133 fn from(v: U256) -> Self {
134 Number(v)
135 }
136}
137
138impl From<Number> for U256 {
139 fn from(n: Number) -> U256 {
140 n.0
141 }
142}
143
144impl Div<u128> for Number {
145 type Output = Number;
146
147 fn div(self, rhs: u128) -> Number {
148 Number(self.0 / U256::from(rhs))
149 }
150}
151
152impl Div<Number> for Number {
153 type Output = Number;
154
155 fn div(self, rhs: Number) -> Number {
156 Number(self.0 / rhs.0)
157 }
158}
159
160impl Add<Number> for Number {
161 type Output = Number;
162
163 fn add(self, rhs: Number) -> Number {
164 Number(self.0 + rhs.0)
165 }
166}
167
168impl Sub<Number> for Number {
169 type Output = Number;
170
171 fn sub(self, rhs: Number) -> Number {
172 Number(self.0 - rhs.0)
173 }
174}
175
176impl BorshSerialize for Number {
177 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
178 let mut b32 = [0u8; 32];
179 self.0.write_as_little_endian(&mut b32);
180 writer.write_all(&b32)
181 }
182}
183
184impl BorshDeserialize for Number {
185 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
186 let mut b32 = [0u8; 32];
187 reader.read_exact(&mut b32)?;
188 Ok(Number(U256::from_little_endian(&b32)))
189 }
190}
191
192impl BorshSchema for Number {
193 fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
194 add_definition(Self::declaration(), Definition::Primitive(32), definitions);
195 }
196
197 fn declaration() -> Declaration {
198 "Number".into()
199 }
200}
201
202impl JsonSchema for Number {
203 fn schema_name() -> String {
204 "Number".to_string()
205 }
206
207 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
208 let mut g = generator.subschema_for::<String>().into_object();
209 g.metadata().description = Some("256-bit Unsigned Integer".to_string());
210 g.string().pattern = Some("^(0|[1-9][0-9]{0,77})$".to_string());
211 g.into()
212 }
213}
214
215pub const MAX_MANAGEMENT_FEE_WAD: u128 = Wad::SCALE / 100 * 5;
216pub const MAX_PERFORMANCE_FEE_WAD: u128 = Wad::SCALE / 100 * 50;
217pub const MAX_FEE_WAD: u128 = MAX_PERFORMANCE_FEE_WAD;
218pub const YEAR_NS: u64 = 365 * 24 * 60 * 60 * 1_000_000_000;
219
220#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
221pub struct Wad(pub Number);
222
223impl Serialize for Wad {
224 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
225 where
226 S: near_sdk::serde::Serializer,
227 {
228 Serialize::serialize(&self.0, serializer)
229 }
230}
231
232impl<'de> Deserialize<'de> for Wad {
233 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
234 where
235 D: near_sdk::serde::Deserializer<'de>,
236 {
237 <Number as Deserialize>::deserialize(deserializer).map(Wad)
238 }
239}
240
241impl Wad {
242 const SCALE_LOW_LIMB: u64 = 1_000_000_000_000_000_000u64;
243 pub const SCALE: u128 = 1_000_000_000_000_000_000u128;
244 pub const ZERO: Self = Wad(Number::ZERO);
245 pub const ONE: Self = Wad(Number(U256([Self::SCALE_LOW_LIMB, 0, 0, 0])));
246
247 #[inline]
248 #[must_use]
249 pub fn zero() -> Self {
250 Self::ZERO
251 }
252
253 #[inline]
254 #[must_use]
255 pub fn one() -> Self {
256 Self::ONE
257 }
258
259 #[inline]
260 #[must_use]
261 pub fn is_zero(&self) -> bool {
262 self.0.is_zero()
263 }
264
265 #[inline]
266 #[must_use]
267 pub fn is_one(&self) -> bool {
268 self.0 .0 == U256::from(Self::SCALE)
269 }
270
271 #[inline]
272 #[must_use]
273 pub fn as_u128_trunc(self) -> u128 {
274 self.0.as_u128_trunc()
275 }
276
277 #[inline]
278 #[must_use]
279 pub fn apply_floored(self, amount: Number) -> Number {
280 mul_wad_floor(amount, self)
281 }
282}
283
284impl From<u128> for Wad {
285 fn from(v: u128) -> Self {
286 Wad(Number::from(v))
287 }
288}
289
290impl From<Wad> for u128 {
291 fn from(v: Wad) -> Self {
292 v.0.as_u128_trunc()
293 }
294}
295
296impl Div<u128> for Wad {
297 type Output = Wad;
298
299 fn div(self, rhs: u128) -> Wad {
300 Wad(self.0 / rhs)
301 }
302}
303
304impl Div<Number> for Wad {
305 type Output = Wad;
306
307 fn div(self, rhs: Number) -> Wad {
308 Wad(self.0 / rhs)
309 }
310}
311
312impl BorshSerialize for Wad {
313 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
314 BorshSerialize::serialize(&self.0, writer)
315 }
316}
317
318impl BorshDeserialize for Wad {
319 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
320 Number::deserialize_reader(reader).map(Wad)
321 }
322}
323
324impl BorshSchema for Wad {
325 fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
326 add_definition(Self::declaration(), Definition::Primitive(32), definitions);
327 }
328
329 fn declaration() -> Declaration {
330 "Wad".into()
331 }
332}
333
334impl JsonSchema for Wad {
335 fn schema_name() -> String {
336 "Wad".to_string()
337 }
338
339 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
340 let mut g = generator.subschema_for::<String>().into_object();
341 g.metadata().description = Some("WAD-scaled U256 (1e18 = 100%)".to_string());
342 g.string().pattern = Some("^(0|[1-9][0-9]{0,77})$".to_string());
343 g.into()
344 }
345}
346
347#[inline]
348#[must_use]
349pub fn mul_wad_floor(x: Number, y: Wad) -> Number {
350 Number::mul_div_floor(x, y.0, Number::from(Wad::SCALE))
351}
352
353#[inline]
354#[must_use]
355pub fn mul_div_floor(x: Number, y: Number, denom: Number) -> Number {
356 Number::mul_div_floor(x, y, denom)
357}
358
359#[inline]
360#[must_use]
361pub fn mul_div_ceil(x: Number, y: Number, denom: Number) -> Number {
362 Number::mul_div_ceil(x, y, denom)
363}
364
365#[must_use]
366pub fn compute_fee_shares(
367 cur_total_assets: Number,
368 last_total_assets: Number,
369 fee_wad: Wad,
370 total_supply: Number,
371) -> Number {
372 if cur_total_assets <= last_total_assets || fee_wad.is_zero() || total_supply.is_zero() {
373 return Number::zero();
374 }
375
376 let profit = cur_total_assets.saturating_sub(last_total_assets);
377 let fee_assets = fee_wad.apply_floored(profit);
378 compute_fee_shares_from_assets(fee_assets, cur_total_assets, total_supply)
379}
380
381#[must_use]
382pub fn compute_fee_shares_from_assets(
383 fee_assets: Number,
384 cur_total_assets: Number,
385 total_supply: Number,
386) -> Number {
387 if fee_assets.is_zero() || cur_total_assets.is_zero() || total_supply.is_zero() {
388 return Number::zero();
389 }
390
391 let denom = Number(cur_total_assets.0 - fee_assets.0);
392 Number::mul_div_floor(fee_assets, total_supply, denom)
393}