From 672e62fe0f5a5dd0c3a821d719dd8354071869b0 Mon Sep 17 00:00:00 2001
From: Gavin Wood <gavin@parity.io>
Date: Sat, 24 Aug 2019 20:12:29 +0200
Subject: [PATCH] Allow root to force transfers (#3475)

* Allow root to force transfers

* Bump version

* Avoid changing pre-existing encodings
---
 substrate/node/runtime/src/lib.rs    |  2 +-
 substrate/srml/balances/src/lib.rs   | 17 ++++++++++++++++-
 substrate/srml/balances/src/tests.rs | 15 +++++++++++++++
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs
index d6014addaa5..d1b9abd4cf1 100644
--- a/substrate/node/runtime/src/lib.rs
+++ b/substrate/node/runtime/src/lib.rs
@@ -79,7 +79,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	// and set impl_version to equal spec_version. If only runtime
 	// implementation changes and behavior does not, then leave spec_version as
 	// is and increment impl_version.
-	spec_version: 150,
+	spec_version: 151,
 	impl_version: 151,
 	apis: RUNTIME_API_VERSIONS,
 };
diff --git a/substrate/srml/balances/src/lib.rs b/substrate/srml/balances/src/lib.rs
index e450ca64030..0c838970451 100644
--- a/substrate/srml/balances/src/lib.rs
+++ b/substrate/srml/balances/src/lib.rs
@@ -462,7 +462,7 @@ decl_module! {
 		/// - Independent of the arguments.
 		/// - Contains a limited number of reads and writes.
 		/// # </weight>
-		#[weight = SimpleDispatchInfo::FixedOperational(500_000)]
+		#[weight = SimpleDispatchInfo::FixedOperational(50_000)]
 		fn set_balance(
 			origin,
 			who: <T::Lookup as StaticLookup>::Source,
@@ -488,6 +488,21 @@ decl_module! {
 			}
 			Self::set_reserved_balance(&who, new_reserved);
 		}
+
+		/// Exactly as `transfer`, except the origin must be root and the source account may be
+		/// specified.
+		#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
+		pub fn force_transfer(
+			origin,
+			source: <T::Lookup as StaticLookup>::Source,
+			dest: <T::Lookup as StaticLookup>::Source,
+			#[compact] value: T::Balance
+		) {
+			ensure_root(origin)?;
+			let source = T::Lookup::lookup(source)?;
+			let dest = T::Lookup::lookup(dest)?;
+			<Self as Currency<_>>::transfer(&source, &dest, value)?;
+		}
 	}
 }
 
diff --git a/substrate/srml/balances/src/tests.rs b/substrate/srml/balances/src/tests.rs
index 338513d40d2..1af3ce6ba01 100644
--- a/substrate/srml/balances/src/tests.rs
+++ b/substrate/srml/balances/src/tests.rs
@@ -26,6 +26,7 @@ use srml_support::{
 	traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons,
 	Currency, ReservableCurrency}
 };
+use system::RawOrigin;
 
 const ID_1: LockIdentifier = *b"1       ";
 const ID_2: LockIdentifier = *b"2       ";
@@ -352,6 +353,20 @@ fn balance_transfer_works() {
 	});
 }
 
+#[test]
+fn force_transfer_works() {
+	with_externalities(&mut ExtBuilder::default().build(), || {
+		let _ = Balances::deposit_creating(&1, 111);
+		assert_noop!(
+			Balances::force_transfer(Some(2).into(), 1, 2, 69),
+			"bad origin: expected to be a root origin"
+		);
+		assert_ok!(Balances::force_transfer(RawOrigin::Root.into(), 1, 2, 69));
+		assert_eq!(Balances::total_balance(&1), 42);
+		assert_eq!(Balances::total_balance(&2), 69);
+	});
+}
+
 #[test]
 fn reserving_balance_should_work() {
 	with_externalities(&mut ExtBuilder::default().build(), || {
-- 
GitLab