@@ -25,7 +25,11 @@ use sp_runtime::{
25
25
use sp_std:: marker:: PhantomData ;
26
26
27
27
use 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
+ } ,
29
33
unsigned:: TransactionValidityError ,
30
34
} ;
31
35
@@ -66,18 +70,90 @@ pub trait OnChargeTransaction<T: Config> {
66
70
) -> Result < ( ) , TransactionValidityError > ;
67
71
}
68
72
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`]
70
144
/// trait (eg. the pallet_balances) using an unbalance handler (implementing
71
- /// `OnUnbalanced`).
145
+ /// [ `OnUnbalanced`] ).
72
146
///
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." ) ]
75
150
pub struct CurrencyAdapter < C , OU > ( PhantomData < ( C , OU ) > ) ;
76
151
77
152
/// Default implementation for a Currency and an OnUnbalanced handler.
78
153
///
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) ]
81
157
impl < T , C , OU > OnChargeTransaction < T > for CurrencyAdapter < C , OU >
82
158
where
83
159
T : Config ,
0 commit comments