abstract_os/objects/
fee.rs1use crate::{error::AbstractOsError, AbstractResult};
2use cosmwasm_std::{Addr, Api, CosmosMsg, Decimal, Uint128};
3use cw_asset::Asset;
4
5#[cosmwasm_schema::cw_serde]
8pub struct UsageFee {
9 fee: Fee,
10 recipient: Addr,
11}
12
13impl UsageFee {
14 pub fn new(
15 api: &dyn Api,
16 share: Decimal,
17 recipient: impl Into<String>,
18 ) -> AbstractResult<Self> {
19 let recipient = api.addr_validate(&recipient.into())?;
20 let fee = Fee::new(share)?;
21 Ok(UsageFee { fee, recipient })
22 }
23 pub fn set_share(&mut self, share: Decimal) -> AbstractResult<()> {
24 self.fee = Fee::new(share)?;
25 Ok(())
26 }
27 pub fn share(&self) -> Decimal {
28 self.fee.share()
29 }
30 pub fn compute(&self, amount: Uint128) -> Uint128 {
31 amount * self.share()
32 }
33 pub fn recipient(&self) -> Addr {
34 self.recipient.clone()
35 }
36 pub fn set_recipient(
37 &mut self,
38 api: &dyn Api,
39 recipient: impl Into<String>,
40 ) -> AbstractResult<()> {
41 self.recipient = api.addr_validate(&recipient.into())?;
42 Ok(())
43 }
44}
45
46#[cosmwasm_schema::cw_serde]
48pub struct Fee {
49 share: Decimal,
51}
52
53impl Fee {
54 pub fn new(share: Decimal) -> AbstractResult<Self> {
55 if share >= Decimal::percent(100) {
56 return Err(AbstractOsError::Fee(
57 "fee share must be lesser than 100%".to_string(),
58 ));
59 }
60 Ok(Fee { share })
61 }
62 pub fn compute(&self, amount: Uint128) -> Uint128 {
63 amount * self.share
64 }
65
66 pub fn msg(&self, asset: Asset, recipient: Addr) -> AbstractResult<CosmosMsg> {
67 asset.transfer_msg(recipient).map_err(Into::into)
68 }
69 pub fn share(&self) -> Decimal {
70 self.share
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 mod fee {
79 use super::*;
80
81 #[test]
82 fn test_fee_manual_construction() {
83 let fee = Fee {
84 share: Decimal::percent(20u64),
85 };
86 let deposit = Uint128::from(1000000u64);
87 let deposit_fee = fee.compute(deposit);
88 assert_eq!(deposit_fee, Uint128::from(200000u64));
89 }
90
91 #[test]
92 fn test_fee_new() {
93 let fee = Fee::new(Decimal::percent(20u64)).unwrap();
94 let deposit = Uint128::from(1000000u64);
95 let deposit_fee = fee.compute(deposit);
96 assert_eq!(deposit_fee, Uint128::from(200000u64));
97 }
98
99 #[test]
100 fn test_fee_new_gte_100() {
101 let fee = Fee::new(Decimal::percent(100u64));
102 assert!(fee.is_err());
103 let fee = Fee::new(Decimal::percent(101u64));
104 assert!(fee.is_err());
105 }
106
107 #[test]
108 fn test_fee_share() {
109 let expected_percent = 20u64;
110 let fee = Fee::new(Decimal::percent(expected_percent)).unwrap();
111 assert_eq!(fee.share(), Decimal::percent(expected_percent));
112 }
113
114 #[test]
115 fn test_fee_msg() {
116 let fee = Fee::new(Decimal::percent(20u64)).unwrap();
117 let asset = Asset::native("uusd", Uint128::from(1000000u64));
118
119 let recipient = Addr::unchecked("recipient");
120 let msg = fee.msg(asset.clone(), recipient.clone()).unwrap();
121 assert_eq!(msg, asset.transfer_msg(recipient).unwrap(),);
122 }
123 }
124 mod transfer_fee {
125 use cosmwasm_std::testing::MockApi;
126
127 use super::*;
128
129 #[test]
130 fn test_transfer_fee_new() {
131 let api = MockApi::default();
132 let fee = UsageFee::new(&api, Decimal::percent(20u64), "recipient").unwrap();
133 let deposit = Uint128::from(1000000u64);
134 let deposit_fee = fee.compute(deposit);
135 assert_eq!(deposit_fee, Uint128::from(200000u64));
136 }
137
138 #[test]
139 fn test_transfer_fee_share() {
140 let api = MockApi::default();
141 let expected_percent = 20u64;
142 let fee = UsageFee::new(&api, Decimal::percent(expected_percent), "recipient").unwrap();
143 assert_eq!(fee.share(), Decimal::percent(expected_percent));
144 }
145
146 #[test]
147 fn test_transfer_fee_msg() {
148 let api = MockApi::default();
149 let fee = UsageFee::new(&api, Decimal::percent(20u64), "recipient").unwrap();
150 let asset = Asset::native("uusd", Uint128::from(1000000u64));
151
152 let recipient = Addr::unchecked("recipient");
153 let msg = fee.fee.msg(asset.clone(), recipient.clone()).unwrap();
154 assert_eq!(msg, asset.transfer_msg(recipient).unwrap(),);
155 }
156
157 #[test]
158 fn test_transfer_fee_new_gte_100() {
159 let api = MockApi::default();
160 let fee = UsageFee::new(&api, Decimal::percent(100u64), "recipient");
161 assert!(fee.is_err());
162 let fee = UsageFee::new(&api, Decimal::percent(101u64), "recipient");
163 assert!(fee.is_err());
164 }
165
166 #[test]
167 fn test_transfer_fee_set_recipient() {
168 let api = MockApi::default();
169 let mut fee = UsageFee::new(&api, Decimal::percent(20u64), "recipient").unwrap();
170 let new_recipient = "new_recipient";
171 fee.set_recipient(&api, new_recipient).unwrap();
172 assert_eq!(fee.recipient(), Addr::unchecked(new_recipient));
173 }
174 #[test]
175 fn test_transfer_fee_set_share() {
176 let api = MockApi::default();
177 let mut fee = UsageFee::new(&api, Decimal::percent(20u64), "recipient").unwrap();
178 let new_share = Decimal::percent(10u64);
179 fee.set_share(new_share).unwrap();
180 assert_eq!(fee.share(), new_share);
181 }
182 }
183}