impls.rs 6.82 KB
Newer Older
Shawn Tabrizi's avatar
Shawn Tabrizi committed
1
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// This file is part of Polkadot.

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

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

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

Denis_P's avatar
Denis_P committed
17
//! Auxiliary `struct`/`enum`s for polkadot runtime.
18

19
use crate::NegativeImbalance;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
20
use frame_support::traits::{Currency, Imbalance, OnUnbalanced};
21
22

/// Logic for the author to get a portion of fees.
23
pub struct ToAuthor<R>(sp_std::marker::PhantomData<R>);
24
25
impl<R> OnUnbalanced<NegativeImbalance<R>> for ToAuthor<R>
where
26
27
28
	R: pallet_balances::Config + pallet_authorship::Config,
	<R as frame_system::Config>::AccountId: From<primitives::v1::AccountId>,
	<R as frame_system::Config>::AccountId: Into<primitives::v1::AccountId>,
29
	<R as frame_system::Config>::Event: From<pallet_balances::Event<R>>,
30
31
{
	fn on_nonzero_unbalanced(amount: NegativeImbalance<R>) {
32
		let numeric_amount = amount.peek();
33
		let author = <pallet_authorship::Pallet<R>>::author();
Shawn Tabrizi's avatar
Shawn Tabrizi committed
34
35
36
37
38
39
40
41
		<pallet_balances::Pallet<R>>::resolve_creating(
			&<pallet_authorship::Pallet<R>>::author(),
			amount,
		);
		<frame_system::Pallet<R>>::deposit_event(pallet_balances::Event::Deposit(
			author,
			numeric_amount,
		));
42
43
	}
}
44
45
46
47

pub struct DealWithFees<R>(sp_std::marker::PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for DealWithFees<R>
where
48
	R: pallet_balances::Config + pallet_treasury::Config + pallet_authorship::Config,
49
	pallet_treasury::Pallet<R>: OnUnbalanced<NegativeImbalance<R>>,
50
51
	<R as frame_system::Config>::AccountId: From<primitives::v1::AccountId>,
	<R as frame_system::Config>::AccountId: Into<primitives::v1::AccountId>,
52
	<R as frame_system::Config>::Event: From<pallet_balances::Event<R>>,
53
{
Shawn Tabrizi's avatar
Shawn Tabrizi committed
54
	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance<R>>) {
55
56
57
58
59
60
61
		if let Some(fees) = fees_then_tips.next() {
			// for fees, 80% to treasury, 20% to author
			let mut split = fees.ration(80, 20);
			if let Some(tips) = fees_then_tips.next() {
				// for tips, if any, 100% to author
				tips.merge_into(&mut split.1);
			}
62
			use pallet_treasury::Pallet as Treasury;
63
64
65
66
67
68
69
70
71
			<Treasury<R> as OnUnbalanced<_>>::on_unbalanced(split.0);
			<ToAuthor<R> as OnUnbalanced<_>>::on_unbalanced(split.1);
		}
	}
}

#[cfg(test)]
mod tests {
	use super::*;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
72
	use frame_support::{parameter_types, traits::FindAuthor, weights::DispatchClass, PalletId};
73
	use frame_system::limits;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
74
	use primitives::v1::AccountId;
75
76
	use sp_core::H256;
	use sp_runtime::{
Shawn Tabrizi's avatar
Shawn Tabrizi committed
77
		testing::Header,
78
79
80
81
		traits::{BlakeTwo256, IdentityLookup},
		Perbill,
	};

82
83
	type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
	type Block = frame_system::mocking::MockBlock<Test>;
84

85
86
87
88
89
90
	frame_support::construct_runtime!(
		pub enum Test where
			Block = Block,
			NodeBlock = Block,
			UncheckedExtrinsic = UncheckedExtrinsic,
		{
91
			System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
92
			Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent},
93
94
			Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
			Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>},
95
96
		}
	);
97
98
99

	parameter_types! {
		pub const BlockHashCount: u64 = 250;
100
		pub BlockWeights: limits::BlockWeights = limits::BlockWeights::builder()
thiolliere's avatar
thiolliere committed
101
			.base_block(10)
102
103
104
105
106
107
108
109
			.for_class(DispatchClass::all(), |weight| {
				weight.base_extrinsic = 100;
			})
			.for_class(DispatchClass::non_mandatory(), |weight| {
				weight.max_total = Some(1024);
			})
			.build_or_panic();
		pub BlockLength: limits::BlockLength = limits::BlockLength::max(2 * 1024);
110
111
112
		pub const AvailableBlockRatio: Perbill = Perbill::one();
	}

113
	impl frame_system::Config for Test {
114
		type BaseCallFilter = frame_support::traits::Everything;
115
116
117
		type Origin = Origin;
		type Index = u64;
		type BlockNumber = u64;
118
		type Call = Call;
119
120
121
122
123
		type Hash = H256;
		type Hashing = BlakeTwo256;
		type AccountId = AccountId;
		type Lookup = IdentityLookup<Self::AccountId>;
		type Header = Header;
124
		type Event = Event;
125
		type BlockHashCount = BlockHashCount;
126
127
		type BlockLength = BlockLength;
		type BlockWeights = BlockWeights;
128
129
		type DbWeight = ();
		type Version = ();
130
		type PalletInfo = PalletInfo;
131
132
133
134
		type AccountData = pallet_balances::AccountData<u64>;
		type OnNewAccount = ();
		type OnKilledAccount = ();
		type SystemWeightInfo = ();
135
		type SS58Prefix = ();
136
		type OnSetCode = ();
137
138
	}

139
	impl pallet_balances::Config for Test {
140
		type Balance = u64;
141
		type Event = Event;
142
143
144
145
		type DustRemoval = ();
		type ExistentialDeposit = ();
		type AccountStore = System;
		type MaxLocks = ();
Gavin Wood's avatar
Gavin Wood committed
146
147
		type MaxReserves = ();
		type ReserveIdentifier = [u8; 8];
148
149
150
151
		type WeightInfo = ();
	}

	parameter_types! {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
152
		pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
153
		pub const MaxApprovals: u32 = 100;
154
155
	}

156
	impl pallet_treasury::Config for Test {
157
		type Currency = pallet_balances::Pallet<Test>;
158
159
		type ApproveOrigin = frame_system::EnsureRoot<AccountId>;
		type RejectOrigin = frame_system::EnsureRoot<AccountId>;
160
		type Event = Event;
161
162
163
164
165
166
		type OnSlash = ();
		type ProposalBond = ();
		type ProposalBondMinimum = ();
		type SpendPeriod = ();
		type Burn = ();
		type BurnDestination = ();
Shawn Tabrizi's avatar
Shawn Tabrizi committed
167
		type PalletId = TreasuryPalletId;
168
		type SpendFunds = ();
169
		type MaxApprovals = MaxApprovals;
170
171
172
173
174
175
		type WeightInfo = ();
	}

	pub struct OneAuthor;
	impl FindAuthor<AccountId> for OneAuthor {
		fn find_author<'a, I>(_: I) -> Option<AccountId>
Shawn Tabrizi's avatar
Shawn Tabrizi committed
176
177
		where
			I: 'a,
178
179
180
181
		{
			Some(Default::default())
		}
	}
182
	impl pallet_authorship::Config for Test {
183
184
185
186
187
188
189
190
191
		type FindAuthor = OneAuthor;
		type UncleGenerations = ();
		type FilterUncle = ();
		type EventHandler = ();
	}

	pub fn new_test_ext() -> sp_io::TestExternalities {
		let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
		// We use default for brevity, but you can configure as desired if needed.
Shawn Tabrizi's avatar
Shawn Tabrizi committed
192
193
194
		pallet_balances::GenesisConfig::<Test>::default()
			.assimilate_storage(&mut t)
			.unwrap();
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
		t.into()
	}

	#[test]
	fn test_fees_and_tip_split() {
		new_test_ext().execute_with(|| {
			let fee = Balances::issue(10);
			let tip = Balances::issue(20);

			assert_eq!(Balances::free_balance(Treasury::account_id()), 0);
			assert_eq!(Balances::free_balance(AccountId::default()), 0);

			DealWithFees::on_unbalanceds(vec![fee, tip].into_iter());

			// Author gets 100% of tip and 20% of fee = 22
			assert_eq!(Balances::free_balance(AccountId::default()), 22);
			// Treasury gets 80% of fee
			assert_eq!(Balances::free_balance(Treasury::account_id()), 8);
		});
	}
}