pallet_frequency_tx_payment/
payment.rs

1use common_primitives::msa::MsaValidator;
2use core::marker::PhantomData;
3use frame_support::traits::tokens::{fungible::Inspect as InspectFungible, Balance};
4
5use super::*;
6use crate::Config;
7
8/// A trait used for the withdrawal of Capacity.
9pub trait OnChargeCapacityTransaction<T: Config> {
10	/// Scalar type for representing balance of an account.
11	type Balance: Balance;
12
13	/// Handles withdrawal of Capacity from an Account.
14	fn withdraw_fee(
15		key: &T::AccountId,
16		fee: Self::Balance,
17	) -> Result<Self::Balance, TransactionValidityError>;
18
19	/// Checks if there is enough Capacity balance to cover the fee.
20	fn can_withdraw_fee(
21		key: &T::AccountId,
22		fee: Self::Balance,
23	) -> Result<(), TransactionValidityError>;
24}
25
26/// A type used to withdraw Capacity from an account.
27pub struct CapacityAdapter<Curr, Msa>(PhantomData<(Curr, Msa)>);
28
29impl<T, Curr, Msa> OnChargeCapacityTransaction<T> for CapacityAdapter<Curr, Msa>
30where
31	T: Config,
32	Curr: InspectFungible<<T as frame_system::Config>::AccountId>,
33	Msa: MsaValidator<AccountId = <T as frame_system::Config>::AccountId>,
34	BalanceOf<T>: Send + Sync + FixedPointOperand + IsType<CapacityBalanceOf<T>> + MaxEncodedLen,
35{
36	type Balance = BalanceOf<T>;
37
38	/// Handle withdrawal of Capacity using a key associated to an MSA.
39	/// It attempts to replenish an account of Capacity before withdrawing the fee.
40	fn withdraw_fee(
41		key: &T::AccountId,
42		fee: Self::Balance,
43	) -> Result<Self::Balance, TransactionValidityError> {
44		let msa_id = Msa::ensure_valid_msa_key(key)
45			.map_err(|_| ChargeFrqTransactionPaymentError::InvalidMsaKey.into())?;
46
47		if T::Capacity::can_replenish(msa_id) {
48			ensure!(
49				T::Capacity::replenish_all_for(msa_id).is_ok(),
50				TransactionValidityError::Invalid(InvalidTransaction::Payment)
51			);
52		}
53
54		ensure!(
55			T::Capacity::deduct(msa_id, fee.into()).is_ok(),
56			TransactionValidityError::Invalid(InvalidTransaction::Payment)
57		);
58
59		Ok(fee)
60	}
61
62	/// Check that there is enough capacity to cover the transaction.
63	/// Returns:  Msa ID for the AccountId, or TransactionValidityError.
64	fn can_withdraw_fee(
65		key: &T::AccountId,
66		fee: Self::Balance,
67	) -> Result<(), TransactionValidityError> {
68		let minimum_balance = Curr::minimum_balance();
69		ensure!(
70			Curr::total_balance(key) >= minimum_balance,
71			TransactionValidityError::Invalid(InvalidTransaction::Payment)
72		);
73
74		let msa_id = Msa::ensure_valid_msa_key(key)
75			.map_err(|_| ChargeFrqTransactionPaymentError::InvalidMsaKey.into())?;
76
77		let available_capacity: Self::Balance = if T::Capacity::can_replenish(msa_id) {
78			T::Capacity::replenishable_balance(msa_id).into()
79		} else {
80			T::Capacity::balance(msa_id).into()
81		};
82
83		ensure!(
84			fee <= available_capacity,
85			TransactionValidityError::Invalid(InvalidTransaction::Payment)
86		);
87		Ok(())
88	}
89}