@@ -25,7 +25,11 @@ use sp_runtime::{
2525use sp_std:: marker:: PhantomData ;
2626
2727use frame_support:: {
28- traits:: { Currency , ExistenceRequirement , Imbalance , OnUnbalanced , WithdrawReasons } ,
28+ traits:: {
29+ fungible:: { Balanced , Credit , Debt , Inspect } ,
30+ tokens:: Precision ,
31+ Currency , ExistenceRequirement , Imbalance , OnUnbalanced , TryDrop , WithdrawReasons ,
32+ } ,
2933 unsigned:: TransactionValidityError ,
3034} ;
3135
@@ -66,18 +70,90 @@ pub trait OnChargeTransaction<T: Config> {
6670 ) -> Result < ( ) , TransactionValidityError > ;
6771}
6872
69- /// Implements the transaction payment for a pallet implementing the `Currency`
73+ /// Implements transaction payment for a pallet implementing the [`fungible`]
74+ /// trait (eg. pallet_balances) using an unbalance handler (implementing
75+ /// [`OnUnbalanced`]).
76+ ///
77+ /// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: `fee` and
78+ /// then `tip`.
79+ pub struct FungibleAdapter < F , OU > ( PhantomData < ( F , OU ) > ) ;
80+
81+ impl < T , F , OU > OnChargeTransaction < T > for FungibleAdapter < F , OU >
82+ where
83+ T : Config ,
84+ F : Balanced < T :: AccountId > ,
85+ OU : OnUnbalanced < Credit < T :: AccountId , F > > ,
86+ {
87+ type LiquidityInfo = Option < Credit < T :: AccountId , F > > ;
88+ type Balance = <F as Inspect < <T as frame_system:: Config >:: AccountId > >:: Balance ;
89+
90+ fn withdraw_fee (
91+ who : & <T >:: AccountId ,
92+ _call : & <T >:: RuntimeCall ,
93+ _dispatch_info : & DispatchInfoOf < <T >:: RuntimeCall > ,
94+ fee : Self :: Balance ,
95+ _tip : Self :: Balance ,
96+ ) -> Result < Self :: LiquidityInfo , TransactionValidityError > {
97+ if fee. is_zero ( ) {
98+ return Ok ( None )
99+ }
100+
101+ match F :: withdraw (
102+ who,
103+ fee,
104+ Precision :: Exact ,
105+ frame_support:: traits:: tokens:: Preservation :: Preserve ,
106+ frame_support:: traits:: tokens:: Fortitude :: Polite ,
107+ ) {
108+ Ok ( imbalance) => Ok ( Some ( imbalance) ) ,
109+ Err ( _) => Err ( InvalidTransaction :: Payment . into ( ) ) ,
110+ }
111+ }
112+
113+ fn correct_and_deposit_fee (
114+ who : & <T >:: AccountId ,
115+ _dispatch_info : & DispatchInfoOf < <T >:: RuntimeCall > ,
116+ _post_info : & PostDispatchInfoOf < <T >:: RuntimeCall > ,
117+ corrected_fee : Self :: Balance ,
118+ tip : Self :: Balance ,
119+ already_withdrawn : Self :: LiquidityInfo ,
120+ ) -> Result < ( ) , TransactionValidityError > {
121+ if let Some ( paid) = already_withdrawn {
122+ // Calculate how much refund we should return
123+ let refund_amount = paid. peek ( ) . saturating_sub ( corrected_fee) ;
124+ // refund to the the account that paid the fees. If this fails, the
125+ // account might have dropped below the existential balance. In
126+ // that case we don't refund anything.
127+ let refund_imbalance = F :: deposit ( who, refund_amount, Precision :: BestEffort )
128+ . unwrap_or_else ( |_| Debt :: < T :: AccountId , F > :: zero ( ) ) ;
129+ // merge the imbalance caused by paying the fees and refunding parts of it again.
130+ let adjusted_paid: Credit < T :: AccountId , F > = paid
131+ . offset ( refund_imbalance)
132+ . same ( )
133+ . map_err ( |_| TransactionValidityError :: Invalid ( InvalidTransaction :: Payment ) ) ?;
134+ // Call someone else to handle the imbalance (fee and tip separately)
135+ let ( tip, fee) = adjusted_paid. split ( tip) ;
136+ OU :: on_unbalanceds ( Some ( fee) . into_iter ( ) . chain ( Some ( tip) ) ) ;
137+ }
138+
139+ Ok ( ( ) )
140+ }
141+ }
142+
143+ /// Implements the transaction payment for a pallet implementing the [`Currency`]
70144/// trait (eg. the pallet_balances) using an unbalance handler (implementing
71- /// `OnUnbalanced`).
145+ /// [ `OnUnbalanced`] ).
72146///
73- /// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: fee and
74- /// then tip.
147+ /// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: `fee` and
148+ /// then `tip`.
149+ #[ deprecated( note = "Please use the fungible trait and FungibleAdapter instead where possible." ) ]
75150pub struct CurrencyAdapter < C , OU > ( PhantomData < ( C , OU ) > ) ;
76151
77152/// Default implementation for a Currency and an OnUnbalanced handler.
78153///
79- /// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: fee and
80- /// then tip.
154+ /// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: `fee` and
155+ /// then `tip`.
156+ #[ allow( deprecated) ]
81157impl < T , C , OU > OnChargeTransaction < T > for CurrencyAdapter < C , OU >
82158where
83159 T : Config ,
0 commit comments