use near_sdk::{json_types::U64, near}; use crate::{ asset::{AssetClass, FungibleAssetAmount}, number::Decimal, }; #[derive(Clone, Debug, PartialEq, Eq)] #[near(serializers = [json, borsh])] pub enum Fee { Flat(FungibleAssetAmount), Proportional(Decimal), } impl Fee { pub fn zero() -> Self { Self::Flat(FungibleAssetAmount::zero()) } pub fn of(&self, amount: FungibleAssetAmount) -> Option> { match self { Fee::Flat(f) => Some(*f), Fee::Proportional(factor) => (factor * u128::from(amount)) .to_u128_ceil() .map(FungibleAssetAmount::new), } } } #[derive(Clone, Debug, PartialEq, Eq)] #[near(serializers = [json, borsh])] pub struct TimeBasedFee { pub fee: Fee, pub duration: U64, pub behavior: TimeBasedFeeFunction, } impl TimeBasedFee { pub fn zero() -> Self { Self { fee: Fee::Flat(0.into()), duration: 0.into(), behavior: TimeBasedFeeFunction::Fixed, } } } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[near(serializers = [json, borsh])] pub enum TimeBasedFeeFunction { Fixed, Linear, } impl TimeBasedFee { pub fn of( &self, amount: FungibleAssetAmount, duration: u64, ) -> Option> { let base_fee = self.fee.of(amount)?; if self.duration.0 == 0 { return Some(0.into()); } match self.behavior { TimeBasedFeeFunction::Fixed => { if duration >= self.duration.0 { Some(0.into()) } else { Some(base_fee) } } TimeBasedFeeFunction::Linear => { (Decimal::from(self.duration.0.saturating_sub(duration)) / Decimal::from(self.duration.0) * u128::from(base_fee)) .to_u128_ceil() .map(FungibleAssetAmount::new) } } } }