diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 8d57e6fbf8c27b286a9c76fa02e9c84c20fcec9a..ed10357e5983f3e0e04426d76ea7bddf35c5a11a 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -24,7 +24,7 @@ use sp_std::prelude::*;
 use frame_support::{
 	construct_runtime, parameter_types, debug,
 	weights::Weight,
-	traits::{SplitTwoWays, Currency, Randomness},
+	traits::{Currency, Randomness, OnUnbalanced, Imbalance},
 };
 use sp_core::u32_trait::{_1, _2, _3, _4};
 pub use node_primitives::{AccountId, Signature};
@@ -98,12 +98,21 @@ pub fn native_version() -> NativeVersion {
 
 type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
 
-pub type DealWithFees = SplitTwoWays<
-	Balance,
-	NegativeImbalance,
-	_4, Treasury,   // 4 parts (80%) goes to the treasury.
-	_1, Author,     // 1 part (20%) goes to the block author.
->;
+pub struct DealWithFees;
+impl OnUnbalanced<NegativeImbalance> for DealWithFees {
+	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item=NegativeImbalance>) {
+		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, 80% to treasury, 20% to author (though this can be anything)
+				tips.ration_merge_into(80, 20, &mut split);
+			}
+			Treasury::on_unbalanced(split.0);
+			Author::on_unbalanced(split.1);
+		}
+	}
+}
 
 parameter_types! {
 	pub const BlockHashCount: BlockNumber = 250;
diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs
index c1e9e7c317159b2b4eaeee51ade9762a7c311389..2e87629a9f02e86671c5fc7d726703e15401bf83 100644
--- a/substrate/frame/support/src/traits.rs
+++ b/substrate/frame/support/src/traits.rs
@@ -256,6 +256,13 @@ pub trait KeyOwnerProofSystem<Key> {
 /// - Someone got slashed.
 /// - Someone paid for a transaction to be included.
 pub trait OnUnbalanced<Imbalance: TryDrop> {
+	/// Handler for some imbalances. The different imbalances might have different origins or
+	/// meanings, dependent on the context. Will default to simply calling on_unbalanced for all
+	/// of them. Infallible.
+	fn on_unbalanceds<B>(amounts: impl Iterator<Item=Imbalance>) where Imbalance: crate::traits::Imbalance<B> {
+		Self::on_unbalanced(amounts.fold(Imbalance::zero(), |i, x| x.merge(i)))
+	}
+
 	/// Handler for some imbalance. Infallible.
 	fn on_unbalanced(amount: Imbalance) {
 		amount.try_drop().unwrap_or_else(Self::on_nonzero_unbalanced)
@@ -263,13 +270,11 @@ pub trait OnUnbalanced<Imbalance: TryDrop> {
 
 	/// Actually handle a non-zero imbalance. You probably want to implement this rather than
 	/// `on_unbalanced`.
-	fn on_nonzero_unbalanced(amount: Imbalance);
-}
-
-impl<Imbalance: TryDrop> OnUnbalanced<Imbalance> for () {
 	fn on_nonzero_unbalanced(amount: Imbalance) { drop(amount); }
 }
 
+impl<Imbalance: TryDrop> OnUnbalanced<Imbalance> for () {}
+
 /// Simple boolean for whether an account needs to be kept in existence.
 #[derive(Copy, Clone, Eq, PartialEq)]
 pub enum ExistenceRequirement {
@@ -331,10 +336,71 @@ pub trait Imbalance<Balance>: Sized + TryDrop {
 	/// is guaranteed to be at most `amount` and the second will be the remainder.
 	fn split(self, amount: Balance) -> (Self, Self);
 
+	/// Consume `self` and return two independent instances; the amounts returned will be in
+	/// approximately the same ratio as `first`:`second`.
+	///
+	/// NOTE: This requires up to `first + second` room for a multiply, and `first + second` should
+	/// fit into a `u32`. Overflow will safely saturate in both cases.
+	fn ration(self, first: u32, second: u32) -> (Self, Self)
+		where Balance: From<u32> + Saturating + Div<Output=Balance>
+	{
+		let total: u32 = first.saturating_add(second);
+		let amount1 = self.peek().saturating_mul(first.into()) / total.into();
+		self.split(amount1)
+	}
+
+	/// Consume self and add its two components, defined by the first component's balance,
+	/// element-wise to two pre-existing Imbalances.
+	///
+	/// A convenient replacement for `split` and `merge`.
+	fn split_merge(self, amount: Balance, others: (Self, Self)) -> (Self, Self) {
+		let (a, b) = self.split(amount);
+		(a.merge(others.0), b.merge(others.1))
+	}
+
+	/// Consume self and add its two components, defined by the ratio `first`:`second`,
+	/// element-wise to two pre-existing Imbalances.
+	///
+	/// A convenient replacement for `split` and `merge`.
+	fn ration_merge(self, first: u32, second: u32, others: (Self, Self)) -> (Self, Self)
+		where Balance: From<u32> + Saturating + Div<Output=Balance>
+	{
+		let (a, b) = self.ration(first, second);
+		(a.merge(others.0), b.merge(others.1))
+	}
+
+	/// Consume self and add its two components, defined by the first component's balance,
+	/// element-wise into two pre-existing Imbalance refs.
+	///
+	/// A convenient replacement for `split` and `subsume`.
+	fn split_merge_into(self, amount: Balance, others: &mut (Self, Self)) {
+		let (a, b) = self.split(amount);
+		others.0.subsume(a);
+		others.1.subsume(b);
+	}
+
+	/// Consume self and add its two components, defined by the ratio `first`:`second`,
+	/// element-wise to two pre-existing Imbalances.
+	///
+	/// A convenient replacement for `split` and `merge`.
+	fn ration_merge_into(self, first: u32, second: u32, others: &mut (Self, Self))
+		where Balance: From<u32> + Saturating + Div<Output=Balance>
+	{
+		let (a, b) = self.ration(first, second);
+		others.0.subsume(a);
+		others.1.subsume(b);
+	}
+
 	/// Consume `self` and an `other` to return a new instance that combines
 	/// both.
 	fn merge(self, other: Self) -> Self;
 
+	/// Consume self to mutate `other` so that it combines both. Just like `subsume`, only with
+	/// reversed arguments.
+	fn merge_into(self, other: &mut Self) {
+		other.subsume(self)
+	}
+
 	/// Consume `self` and maybe an `other` to return a new instance that combines
 	/// both.
 	fn maybe_merge(self, other: Option<Self>) -> Self {
diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs
index fe15bdf79465c8256f94e5f9e90a6731e2a9aff1..2367d5ee5abe30b1b1b8e661d446c1ae9202330a 100644
--- a/substrate/frame/transaction-payment/src/lib.rs
+++ b/substrate/frame/transaction-payment/src/lib.rs
@@ -35,7 +35,7 @@ use sp_std::prelude::*;
 use codec::{Encode, Decode};
 use frame_support::{
 	decl_storage, decl_module,
-	traits::{Currency, Get, OnUnbalanced, ExistenceRequirement, WithdrawReason},
+	traits::{Currency, Get, OnUnbalanced, ExistenceRequirement, WithdrawReason, Imbalance},
 	weights::{Weight, DispatchInfo, GetDispatchInfo},
 };
 use sp_runtime::{
@@ -58,7 +58,9 @@ pub trait Trait: frame_system::Trait {
 	/// The currency type in which fees will be paid.
 	type Currency: Currency<Self::AccountId> + Send + Sync;
 
-	/// Handler for the unbalanced reduction when taking transaction fees.
+	/// Handler for the unbalanced reduction when taking transaction fees. This is either one or
+	/// two separate imbalances, the first is the transaction fee paid, the second is the tip paid,
+	/// if any.
 	type OnTransactionPayment: OnUnbalanced<NegativeImbalanceOf<Self>>;
 
 	/// The fee to be paid for making a transaction; the base.
@@ -234,7 +236,9 @@ impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T>
 				Ok(imbalance) => imbalance,
 				Err(_) => return InvalidTransaction::Payment.into(),
 			};
-			T::OnTransactionPayment::on_unbalanced(imbalance);
+			let imbalances = imbalance.split(tip);
+			T::OnTransactionPayment::on_unbalanceds(Some(imbalances.0).into_iter()
+				.chain(Some(imbalances.1)));
 		}
 
 		let mut r = ValidTransaction::default();