1
// Copyright 2024 Moonbeam foundation
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Moonbeam is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use frame_support::__private::Get;
18
use frame_support::pallet_prelude::TypedGet;
19
use frame_support::traits::fungible::Credit;
20
use frame_support::traits::tokens::imbalance::ResolveTo;
21
use frame_support::traits::Imbalance;
22
use frame_support::traits::OnUnbalanced;
23
use pallet_treasury::TreasuryAccountId;
24
use sp_runtime::Perbill;
25

            
26
/// Deal with substrate based fees and tip. This should be used with pallet_transaction_payment.
27
pub struct DealWithSubstrateFeesAndTip<R, FeesTreasuryProportion>(
28
	sp_std::marker::PhantomData<(R, FeesTreasuryProportion)>,
29
);
30
impl<R, FeesTreasuryProportion> DealWithSubstrateFeesAndTip<R, FeesTreasuryProportion>
31
where
32
	R: pallet_balances::Config + pallet_treasury::Config + pallet_author_inherent::Config,
33
	pallet_author_inherent::Pallet<R>: Get<R::AccountId>,
34
	FeesTreasuryProportion: Get<Perbill>,
35
{
36
3
	fn deal_with_fees(amount: Credit<R::AccountId, pallet_balances::Pallet<R>>) {
37
3
		// Balances pallet automatically burns dropped Credits by decreasing
38
3
		// total_supply accordingly
39
3
		let treasury_proportion = FeesTreasuryProportion::get();
40
3
		let treasury_part = treasury_proportion.deconstruct();
41
3
		let burn_part = Perbill::one().deconstruct() - treasury_part;
42
3
		let (_, to_treasury) = amount.ration(burn_part, treasury_part);
43
3
		ResolveTo::<TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(to_treasury);
44
3
	}
45

            
46
3
	fn deal_with_tip(amount: Credit<R::AccountId, pallet_balances::Pallet<R>>) {
47
3
		ResolveTo::<BlockAuthorAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(amount);
48
3
	}
49
}
50

            
51
impl<R, FeesTreasuryProportion> OnUnbalanced<Credit<R::AccountId, pallet_balances::Pallet<R>>>
52
	for DealWithSubstrateFeesAndTip<R, FeesTreasuryProportion>
53
where
54
	R: pallet_balances::Config + pallet_treasury::Config + pallet_author_inherent::Config,
55
	pallet_author_inherent::Pallet<R>: Get<R::AccountId>,
56
	FeesTreasuryProportion: Get<Perbill>,
57
{
58
3
	fn on_unbalanceds(
59
3
		mut fees_then_tips: impl Iterator<Item = Credit<R::AccountId, pallet_balances::Pallet<R>>>,
60
3
	) {
61
3
		if let Some(fees) = fees_then_tips.next() {
62
3
			Self::deal_with_fees(fees);
63
3
			if let Some(tip) = fees_then_tips.next() {
64
3
				Self::deal_with_tip(tip);
65
3
			}
66
		}
67
3
	}
68
}
69

            
70
/// Deal with ethereum based fees. To handle tips/priority fees, use DealWithEthereumPriorityFees.
71
pub struct DealWithEthereumBaseFees<R, FeesTreasuryProportion>(
72
	sp_std::marker::PhantomData<(R, FeesTreasuryProportion)>,
73
);
74
impl<R, FeesTreasuryProportion> OnUnbalanced<Credit<R::AccountId, pallet_balances::Pallet<R>>>
75
	for DealWithEthereumBaseFees<R, FeesTreasuryProportion>
76
where
77
	R: pallet_balances::Config + pallet_treasury::Config,
78
	FeesTreasuryProportion: Get<Perbill>,
79
{
80
240
	fn on_nonzero_unbalanced(amount: Credit<R::AccountId, pallet_balances::Pallet<R>>) {
81
240
		// Balances pallet automatically burns dropped Credits by decreasing
82
240
		// total_supply accordingly
83
240
		let treasury_proportion = FeesTreasuryProportion::get();
84
240
		let treasury_part = treasury_proportion.deconstruct();
85
240
		let burn_part = Perbill::one().deconstruct() - treasury_part;
86
240
		let (_, to_treasury) = amount.ration(burn_part, treasury_part);
87
240
		ResolveTo::<TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(to_treasury);
88
240
	}
89
}
90

            
91
pub struct BlockAuthorAccountId<R>(sp_std::marker::PhantomData<R>);
92
impl<R> TypedGet for BlockAuthorAccountId<R>
93
where
94
	R: frame_system::Config + pallet_author_inherent::Config,
95
	pallet_author_inherent::Pallet<R>: Get<R::AccountId>,
96
{
97
	type Type = R::AccountId;
98
103
	fn get() -> Self::Type {
99
103
		<pallet_author_inherent::Pallet<R> as Get<R::AccountId>>::get()
100
103
	}
101
}
102

            
103
/// Deal with ethereum based priority fees/tips. See DealWithEthereumBaseFees for base fees.
104
pub struct DealWithEthereumPriorityFees<R>(sp_std::marker::PhantomData<R>);
105
impl<R> OnUnbalanced<Credit<R::AccountId, pallet_balances::Pallet<R>>>
106
	for DealWithEthereumPriorityFees<R>
107
where
108
	R: pallet_balances::Config + pallet_author_inherent::Config,
109
	pallet_author_inherent::Pallet<R>: Get<R::AccountId>,
110
{
111
100
	fn on_nonzero_unbalanced(amount: Credit<R::AccountId, pallet_balances::Pallet<R>>) {
112
100
		ResolveTo::<BlockAuthorAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(amount);
113
100
	}
114
}