abstract_sdk/cw_helpers/
fees.rs

1//! # Fee helpers
2//! Helper trait that lets you easily charge fees on assets
3
4use cosmwasm_std::{CosmosMsg, Uint128};
5use cw_asset::Asset;
6
7use crate::{
8    std::objects::fee::{Fee, UsageFee},
9    AbstractSdkResult,
10};
11
12/// Indicates that the implementing type can be charged fees.
13pub trait Chargeable {
14    /// Charge a fee on the asset and returns the amount charged.
15    fn charge_fee(&mut self, fee: Fee) -> AbstractSdkResult<Uint128>;
16    /// Charge a fee on the asset and returns the fee transfer message.
17    fn charge_usage_fee(&mut self, fee: UsageFee) -> AbstractSdkResult<Option<CosmosMsg>>;
18}
19
20impl Chargeable for Asset {
21    fn charge_fee(&mut self, fee: Fee) -> AbstractSdkResult<Uint128> {
22        let fee_amount = fee.compute(self.amount);
23        self.amount -= fee_amount;
24        Ok(fee_amount)
25    }
26
27    /// returns a fee message if fee > 0
28    fn charge_usage_fee(&mut self, fee: UsageFee) -> AbstractSdkResult<Option<CosmosMsg>> {
29        let fee_amount = fee.compute(self.amount);
30        if fee_amount.is_zero() {
31            return Ok(None);
32        }
33        self.amount -= fee_amount;
34        Ok(Some(
35            Asset::new(self.info.clone(), fee_amount).transfer_msg(fee.recipient())?,
36        ))
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use cosmwasm_std::{Addr, Decimal};
43    use cw_asset::AssetInfo;
44
45    use super::*;
46
47    // test that we can charge fees on assets
48
49    #[coverage_helper::test]
50    fn test_charge_fee() {
51        let info = AssetInfo::native("uusd");
52        let mut asset = Asset::new(info, 1000u128);
53        let fee = Fee::new(Decimal::percent(10)).unwrap();
54        let charged = asset.charge_fee(fee).unwrap();
55        assert_eq!(asset.amount.u128(), 900);
56        assert_eq!(charged.u128(), 100);
57    }
58    // test transfer fee
59    #[coverage_helper::test]
60    fn test_charge_transfer_fee() {
61        let info = AssetInfo::native("uusd");
62        let mut asset: Asset = Asset::new(info.clone(), 1000u128);
63        let fee = UsageFee::new(Decimal::percent(10), Addr::unchecked("recipient")).unwrap();
64        let msg = asset.charge_usage_fee(fee).unwrap();
65        assert_eq!(asset.amount.u128(), 900);
66        assert_eq!(
67            msg,
68            Some(
69                Asset::new(info, 100u128)
70                    .transfer_msg(Addr::unchecked("recipient"))
71                    .unwrap()
72            )
73        );
74
75        // test zero fee
76        let fee = UsageFee::new(Decimal::zero(), Addr::unchecked("recipient")).unwrap();
77
78        let msg = asset.charge_usage_fee(fee).unwrap();
79        assert_eq!(asset.amount.u128(), 900);
80        assert_eq!(msg, None);
81    }
82}