diff --git a/substrate/bin/node/executor/tests/common.rs b/substrate/bin/node/executor/tests/common.rs
index 6b6ef272f8a35bac1140e77ed1411adc52f0e8cf..5a51e4312c5e80315c3b05fc5a82bc72a6842fb2 100644
--- a/substrate/bin/node/executor/tests/common.rs
+++ b/substrate/bin/node/executor/tests/common.rs
@@ -15,10 +15,21 @@
 // along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
 
 use codec::{Encode, Decode};
+use frame_system::offchain::AppCrypto;
 use frame_support::Hashable;
 use sp_state_machine::TestExternalities as CoreTestExternalities;
-use sp_core::{NeverNativeValue, NativeOrEncoded, traits::{CodeExecutor, RuntimeCode}};
-use sp_runtime::{ApplyExtrinsicResult, traits::{Header as HeaderT, BlakeTwo256}};
+use sp_core::{
+	NeverNativeValue, NativeOrEncoded,
+	crypto::KeyTypeId,
+	sr25519::Signature,
+	traits::{CodeExecutor, RuntimeCode},
+};
+use sp_runtime::{
+	ApplyExtrinsicResult,
+	MultiSigner,
+	MultiSignature,
+	traits::{Header as HeaderT, BlakeTwo256},
+};
 use sc_executor::{NativeExecutor, WasmExecutionMethod};
 use sc_executor::error::Result;
 
@@ -31,6 +42,25 @@ use node_primitives::{Hash, BlockNumber};
 use node_testing::keyring::*;
 use sp_externalities::Externalities;
 
+pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test");
+
+pub mod sr25519 {
+	mod app_sr25519 {
+		use sp_application_crypto::{app_crypto, sr25519};
+		use super::super::TEST_KEY_TYPE_ID;
+		app_crypto!(sr25519, TEST_KEY_TYPE_ID);
+	}
+
+	pub type AuthorityId = app_sr25519::Public;
+}
+
+pub struct TestAuthorityId;
+impl AppCrypto<MultiSigner, MultiSignature> for TestAuthorityId {
+	type RuntimeAppPublic = sr25519::AuthorityId;
+	type GenericSignature = Signature;
+	type GenericPublic = sp_core::sr25519::Public;
+}
+
 /// The wasm runtime code.
 ///
 /// `compact` since it is after post-processing with wasm-gc which performs tree-shaking thus
diff --git a/substrate/bin/node/executor/tests/submit_transaction.rs b/substrate/bin/node/executor/tests/submit_transaction.rs
index d92f3e3202f6e7cbcfa0743238b0774330244990..3a41c3483c280d7393c87e1f8f57e29f6cb2a4ff 100644
--- a/substrate/bin/node/executor/tests/submit_transaction.rs
+++ b/substrate/bin/node/executor/tests/submit_transaction.rs
@@ -15,24 +15,29 @@
 // along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
 
 use node_runtime::{
-	Call, Executive, Indices, Runtime, TransactionSubmitterOf, UncheckedExtrinsic,
+	Executive, Indices, Runtime, UncheckedExtrinsic,
 };
 use sp_application_crypto::AppKey;
 use sp_core::testing::KeyStore;
-use sp_core::traits::KeystoreExt;
-use sp_core::offchain::{
-	TransactionPoolExt,
-	testing::TestTransactionPoolExt,
+use sp_core::{
+	offchain::{
+		TransactionPoolExt,
+		testing::TestTransactionPoolExt,
+	},
+	traits::KeystoreExt,
+};
+use frame_system::{
+	offchain::{
+		Signer,
+		SubmitTransaction,
+		SendSignedTransaction,
+	}
 };
-use frame_system::offchain::{SubmitSignedTransaction, SubmitUnsignedTransaction};
-use pallet_im_online::sr25519::AuthorityPair as Key;
 use codec::Decode;
 
 pub mod common;
 use self::common::*;
 
-type SubmitTransaction = TransactionSubmitterOf<pallet_im_online::sr25519::AuthorityId>;
-
 #[test]
 fn should_submit_unsigned_transaction() {
 	let mut t = new_test_ext(COMPACT_CODE, false);
@@ -49,8 +54,7 @@ fn should_submit_unsigned_transaction() {
 		};
 
 		let call = pallet_im_online::Call::heartbeat(heartbeat_data, signature);
-		<SubmitTransaction as SubmitUnsignedTransaction<Runtime, Call>>
-			::submit_unsigned(call)
+		SubmitTransaction::<Runtime, pallet_im_online::Call<Runtime>>::submit_unsigned_transaction(call.into())
 			.unwrap();
 
 		assert_eq!(state.read().transactions.len(), 1)
@@ -66,23 +70,16 @@ fn should_submit_signed_transaction() {
 	t.register_extension(TransactionPoolExt::new(pool));
 
 	let keystore = KeyStore::new();
-	keystore.write().sr25519_generate_new(Key::ID, Some(&format!("{}/hunter1", PHRASE))).unwrap();
-	keystore.write().sr25519_generate_new(Key::ID, Some(&format!("{}/hunter2", PHRASE))).unwrap();
-	keystore.write().sr25519_generate_new(Key::ID, Some(&format!("{}/hunter3", PHRASE))).unwrap();
+	keystore.write().sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))).unwrap();
+	keystore.write().sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE))).unwrap();
+	keystore.write().sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter3", PHRASE))).unwrap();
 	t.register_extension(KeystoreExt(keystore));
 
 	t.execute_with(|| {
-		let keys = <SubmitTransaction as SubmitSignedTransaction<Runtime, Call>>
-			::find_all_local_keys();
-		assert_eq!(keys.len(), 3, "Missing keys: {:?}", keys);
-
-		let can_sign = <SubmitTransaction as SubmitSignedTransaction<Runtime, Call>>
-			::can_sign();
-		assert!(can_sign, "Since there are keys, `can_sign` should return true");
-
-		let call = pallet_balances::Call::transfer(Default::default(), Default::default());
-		let results =
-			<SubmitTransaction as SubmitSignedTransaction<Runtime, Call>>::submit_signed(call);
+		let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
+			.send_signed_transaction(|_| {
+				pallet_balances::Call::transfer(Default::default(), Default::default())
+			});
 
 		let len = results.len();
 		assert_eq!(len, 3);
@@ -98,27 +95,26 @@ fn should_submit_signed_twice_from_the_same_account() {
 	t.register_extension(TransactionPoolExt::new(pool));
 
 	let keystore = KeyStore::new();
-	keystore.write().sr25519_generate_new(Key::ID, Some(&format!("{}/hunter1", PHRASE))).unwrap();
+	keystore.write().sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))).unwrap();
+	keystore.write().sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE))).unwrap();
 	t.register_extension(KeystoreExt(keystore));
 
 	t.execute_with(|| {
-		let call = pallet_balances::Call::transfer(Default::default(), Default::default());
-		let results =
-			<SubmitTransaction as SubmitSignedTransaction<Runtime, Call>>::submit_signed(call);
+		let result = Signer::<Runtime, TestAuthorityId>::any_account()
+			.send_signed_transaction(|_| {
+				pallet_balances::Call::transfer(Default::default(), Default::default())
+			});
 
-		let len = results.len();
-		assert_eq!(len, 1);
-		assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len);
+		assert!(result.is_some());
 		assert_eq!(state.read().transactions.len(), 1);
 
 		// submit another one from the same account. The nonce should be incremented.
-		let call = pallet_balances::Call::transfer(Default::default(), Default::default());
-		let results =
-			<SubmitTransaction as SubmitSignedTransaction<Runtime, Call>>::submit_signed(call);
+		let result = Signer::<Runtime, TestAuthorityId>::any_account()
+			.send_signed_transaction(|_| {
+				pallet_balances::Call::transfer(Default::default(), Default::default())
+			});
 
-		let len = results.len();
-		assert_eq!(len, 1);
-		assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len);
+		assert!(result.is_some());
 		assert_eq!(state.read().transactions.len(), 2);
 
 		// now check that the transaction nonces are not equal
@@ -136,6 +132,60 @@ fn should_submit_signed_twice_from_the_same_account() {
 	});
 }
 
+#[test]
+fn should_submit_signed_twice_from_all_accounts() {
+	let mut t = new_test_ext(COMPACT_CODE, false);
+	let (pool, state) = TestTransactionPoolExt::new();
+	t.register_extension(TransactionPoolExt::new(pool));
+
+	let keystore = KeyStore::new();
+	keystore.write().sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))).unwrap();
+	keystore.write().sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE))).unwrap();
+	t.register_extension(KeystoreExt(keystore));
+
+	t.execute_with(|| {
+		let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
+			.send_signed_transaction(|_| {
+				pallet_balances::Call::transfer(Default::default(), Default::default())
+			});
+
+		let len = results.len();
+		assert_eq!(len, 2);
+		assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len);
+		assert_eq!(state.read().transactions.len(), 2);
+
+		// submit another one from the same account. The nonce should be incremented.
+		let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
+			.send_signed_transaction(|_| {
+				pallet_balances::Call::transfer(Default::default(), Default::default())
+			});
+
+		let len = results.len();
+		assert_eq!(len, 2);
+		assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len);
+		assert_eq!(state.read().transactions.len(), 4);
+
+		// now check that the transaction nonces are not equal
+		let s = state.read();
+		fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce<Runtime> {
+			let extra = tx.signature.unwrap().2;
+			extra.3
+		}
+		let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap());
+		let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());
+		let nonce3 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[2]).unwrap());
+		let nonce4 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[3]).unwrap());
+		assert!(
+			nonce1 != nonce3,
+			"Transactions should have different nonces. Got: 1st tx nonce: {:?}, 2nd nonce: {:?}", nonce1, nonce3
+		);
+		assert!(
+			nonce2 != nonce4,
+			"Transactions should have different nonces. Got: 1st tx nonce: {:?}, 2nd tx nonce: {:?}", nonce2, nonce4
+		);
+	});
+}
+
 #[test]
 fn submitted_transaction_should_be_valid() {
 	use codec::Encode;
@@ -148,13 +198,14 @@ fn submitted_transaction_should_be_valid() {
 	t.register_extension(TransactionPoolExt::new(pool));
 
 	let keystore = KeyStore::new();
-	keystore.write().sr25519_generate_new(Key::ID, Some(&format!("{}/hunter1", PHRASE))).unwrap();
+	keystore.write().sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))).unwrap();
 	t.register_extension(KeystoreExt(keystore));
 
 	t.execute_with(|| {
-		let call = pallet_balances::Call::transfer(Default::default(), Default::default());
-		let results =
-			<SubmitTransaction as SubmitSignedTransaction<Runtime, Call>>::submit_signed(call);
+		let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
+			.send_signed_transaction(|_| {
+				pallet_balances::Call::transfer(Default::default(), Default::default())
+			});
 		let len = results.len();
 		assert_eq!(len, 1);
 		assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len);
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 337242f884ddc0e01f7a9e90df74f84049f48310..b1797fffb33211570cf27c6273ccac5786e9285f 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -46,11 +46,10 @@ use sp_version::NativeVersion;
 use sp_core::OpaqueMetadata;
 use pallet_grandpa::AuthorityList as GrandpaAuthorityList;
 use pallet_grandpa::fg_primitives;
-use pallet_im_online::sr25519::{AuthorityId as ImOnlineId};
+use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
 use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
 use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo;
 use pallet_contracts_rpc_runtime_api::ContractExecResult;
-use frame_system::offchain::TransactionSubmitter;
 use sp_inherents::{InherentData, CheckInherentsResult};
 
 #[cfg(any(feature = "std", test))]
@@ -60,6 +59,7 @@ pub use pallet_balances::Call as BalancesCall;
 pub use pallet_contracts::Gas;
 pub use frame_support::StorageValue;
 pub use pallet_staking::StakerStatus;
+use codec::Encode;
 
 /// Implementations of some helper traits passed into runtime modules as associated types.
 pub mod impls;
@@ -73,50 +73,6 @@ use constants::{time::*, currency::*};
 #[cfg(feature = "std")]
 include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
 
-/// A transaction submitter with the given key type.
-pub type TransactionSubmitterOf<KeyType> = TransactionSubmitter<KeyType, Runtime, UncheckedExtrinsic>;
-
-/// Submits transaction with the node's public and signature type. Adheres to the signed extension
-/// format of the chain.
-impl frame_system::offchain::CreateTransaction<Runtime, UncheckedExtrinsic> for Runtime {
-	type Public = <Signature as traits::Verify>::Signer;
-	type Signature = Signature;
-
-	fn create_transaction<TSigner: frame_system::offchain::Signer<Self::Public, Self::Signature>>(
-		call: Call,
-		public: Self::Public,
-		account: AccountId,
-		index: Index,
-	) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
-		// take the biggest period possible.
-		let period = BlockHashCount::get()
-			.checked_next_power_of_two()
-			.map(|c| c / 2)
-			.unwrap_or(2) as u64;
-		let current_block = System::block_number()
-			.saturated_into::<u64>()
-			// The `System::block_number` is initialized with `n+1`,
-			// so the actual block number is `n`.
-			.saturating_sub(1);
-		let tip = 0;
-		let extra: SignedExtra = (
-			frame_system::CheckVersion::<Runtime>::new(),
-			frame_system::CheckGenesis::<Runtime>::new(),
-			frame_system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
-			frame_system::CheckNonce::<Runtime>::from(index),
-			frame_system::CheckWeight::<Runtime>::new(),
-			pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
-			Default::default(),
-		);
-		let raw_payload = SignedPayload::new(call, extra).map_err(|e| {
-			debug::warn!("Unable to create signed payload: {:?}", e);
-		}).ok()?;
-		let signature = TSigner::sign(public, &raw_payload)?;
-		let address = Indices::unlookup(account);
-		let (call, extra, _) = raw_payload.deconstruct();
-		Some((call, (address, signature, extra)))
-	}
-}
 
 /// Runtime version.
 pub const VERSION: RuntimeVersion = RuntimeVersion {
@@ -127,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	// and set impl_version to 0. If only runtime
 	// implementation changes and behavior does not, then leave spec_version as
 	// is and increment impl_version.
-	spec_version: 243,
+	spec_version: 244,
 	impl_version: 0,
 	apis: RUNTIME_API_VERSIONS,
 	transaction_version: 1,
@@ -362,7 +318,6 @@ impl pallet_staking::Trait for Runtime {
 	type NextNewSession = Session;
 	type ElectionLookahead = ElectionLookahead;
 	type Call = Call;
-	type SubmitTransaction = TransactionSubmitterOf<()>;
 	type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
 	type UnsignedPriority = StakingUnsignedPriority;
 }
@@ -549,11 +504,63 @@ parameter_types! {
 	pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2;
 }
 
+
+impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime where
+	Call: From<LocalCall>,
+{
+	fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
+		call: Call,
+		public: <Signature as traits::Verify>::Signer,
+		account: AccountId,
+		nonce: Index,
+	) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
+		// take the biggest period possible.
+		let period = BlockHashCount::get()
+			.checked_next_power_of_two()
+			.map(|c| c / 2)
+			.unwrap_or(2) as u64;
+		let current_block = System::block_number()
+			.saturated_into::<u64>()
+			// The `System::block_number` is initialized with `n+1`,
+			// so the actual block number is `n`.
+			.saturating_sub(1);
+		let tip = 0;
+		let extra: SignedExtra = (
+			frame_system::CheckVersion::<Runtime>::new(),
+			frame_system::CheckGenesis::<Runtime>::new(),
+			frame_system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
+			frame_system::CheckNonce::<Runtime>::from(nonce),
+			frame_system::CheckWeight::<Runtime>::new(),
+			pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
+			Default::default(),
+		);
+		let raw_payload = SignedPayload::new(call, extra).map_err(|e| {
+			debug::warn!("Unable to create signed payload: {:?}", e);
+		}).ok()?;
+		let signature = raw_payload.using_encoded(|payload| {
+			C::sign(payload, public)
+		})?;
+		let address = Indices::unlookup(account);
+		let (call, extra, _) = raw_payload.deconstruct();
+		Some((call, (address, signature.into(), extra)))
+	}
+}
+
+impl frame_system::offchain::SigningTypes for Runtime {
+	type Public = <Signature as traits::Verify>::Signer;
+	type Signature = Signature;
+}
+
+impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime where
+	Call: From<C>,
+{
+	type OverarchingCall = Call;
+	type Extrinsic = UncheckedExtrinsic;
+}
+
 impl pallet_im_online::Trait for Runtime {
 	type AuthorityId = ImOnlineId;
 	type Event = Event;
-	type Call = Call;
-	type SubmitTransaction = TransactionSubmitterOf<Self::AuthorityId>;
 	type SessionDuration = SessionDuration;
 	type ReportUnresponsiveness = Offences;
 	type UnsignedPriority = ImOnlineUnsignedPriority;
@@ -924,28 +931,14 @@ impl_runtime_apis! {
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use frame_system::offchain::{SignAndSubmitTransaction, SubmitSignedTransaction};
+	use frame_system::offchain::CreateSignedTransaction;
 
 	#[test]
 	fn validate_transaction_submitter_bounds() {
 		fn is_submit_signed_transaction<T>() where
-			T: SubmitSignedTransaction<
-				Runtime,
-				Call,
-			>,
-		{}
-
-		fn is_sign_and_submit_transaction<T>() where
-			T: SignAndSubmitTransaction<
-				Runtime,
-				Call,
-				Extrinsic=UncheckedExtrinsic,
-				CreateTransaction=Runtime,
-				Signer=ImOnlineId,
-			>,
+			T: CreateSignedTransaction<Call>,
 		{}
 
-		is_submit_signed_transaction::<TransactionSubmitterOf<ImOnlineId>>();
-		is_sign_and_submit_transaction::<TransactionSubmitterOf<ImOnlineId>>();
+		is_submit_signed_transaction::<Runtime>();
 	}
 }
diff --git a/substrate/frame/example-offchain-worker/src/lib.rs b/substrate/frame/example-offchain-worker/src/lib.rs
index 29a4859c78e212ad6d074c4aa6cdc6c461b3c99c..d2ebd1159e228ddb396e0011c859fc31a52399d7 100644
--- a/substrate/frame/example-offchain-worker/src/lib.rs
+++ b/substrate/frame/example-offchain-worker/src/lib.rs
@@ -22,12 +22,12 @@
 //! Run `cargo doc --package pallet-example-offchain-worker --open` to view this module's
 //! documentation.
 //!
-//! - \[`pallet_example_offchain_worker::Trait`](./trait.Trait.html)
-//! - \[`Call`](./enum.Call.html)
-//! - \[`Module`](./struct.Module.html)
+//! - [`pallet_example_offchain_worker::Trait`](./trait.Trait.html)
+//! - [`Call`](./enum.Call.html)
+//! - [`Module`](./struct.Module.html)
 //!
 //!
-//! \## Overview
+//! ## Overview
 //!
 //! In this example we are going to build a very simplistic, naive and definitely NOT
 //! production-ready oracle for BTC/USD price.
@@ -40,15 +40,24 @@
 //! one unsigned transaction floating in the network.
 #![cfg_attr(not(feature = "std"), no_std)]
 
+use frame_system::{
+	self as system,
+	ensure_signed,
+	ensure_none,
+	offchain::{
+		AppCrypto, CreateSignedTransaction, SendUnsignedTransaction,
+		SignedPayload, SigningTypes, Signer, SubmitTransaction,
+	}
+};
 use frame_support::{
 	debug,
 	dispatch::DispatchResult, decl_module, decl_storage, decl_event,
 	traits::Get,
 	weights::{SimpleDispatchInfo, MINIMUM_WEIGHT},
 };
-use frame_system::{self as system, ensure_signed, ensure_none, offchain};
 use sp_core::crypto::KeyTypeId;
 use sp_runtime::{
+	RuntimeDebug,
 	offchain::{http, Duration, storage::StorageValueRef},
 	traits::Zero,
 	transaction_validity::{
@@ -56,6 +65,7 @@ use sp_runtime::{
 		TransactionPriority,
 	},
 };
+use codec::{Encode, Decode};
 use sp_std::vec::Vec;
 use lite_json::json::JsonValue;
 
@@ -76,18 +86,25 @@ pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"btc!");
 /// the types with this pallet-specific identifier.
 pub mod crypto {
 	use super::KEY_TYPE;
-	use sp_runtime::app_crypto::{app_crypto, sr25519};
+	use sp_runtime::{
+		app_crypto::{app_crypto, sr25519},
+		traits::Verify,
+	};
+	use sp_core::sr25519::Signature as Sr25519Signature;
 	app_crypto!(sr25519, KEY_TYPE);
+
+	pub struct TestAuthId;
+	impl frame_system::offchain::AppCrypto<<Sr25519Signature as Verify>::Signer, Sr25519Signature> for TestAuthId {
+		type RuntimeAppPublic = Public;
+		type GenericSignature = sp_core::sr25519::Signature;
+		type GenericPublic = sp_core::sr25519::Public;
+	}
 }
 
 /// This pallet's configuration trait
-pub trait Trait: frame_system::Trait {
-	/// The type to sign and submit transactions.
-	type SubmitSignedTransaction:
-		offchain::SubmitSignedTransaction<Self, <Self as Trait>::Call>;
-	/// The type to submit unsigned transactions.
-	type SubmitUnsignedTransaction:
-		offchain::SubmitUnsignedTransaction<Self, <Self as Trait>::Call>;
+pub trait Trait: CreateSignedTransaction<Call<Self>> {
+	/// The identifier type for an offchain worker.
+	type AuthorityId: AppCrypto<Self::Public, Self::Signature>;
 
 	/// The overarching event type.
 	type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
@@ -115,6 +132,21 @@ pub trait Trait: frame_system::Trait {
 	type UnsignedPriority: Get<TransactionPriority>;
 }
 
+/// Payload used by this example crate to hold price
+/// data required to submit a transaction.
+#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
+pub struct PricePayload<Public, BlockNumber> {
+	block_number: BlockNumber,
+	price: u32,
+	public: Public,
+}
+
+impl<T: SigningTypes> SignedPayload<T> for PricePayload<T::Public, T::BlockNumber> {
+	fn public(&self) -> T::Public {
+		self.public.clone()
+	}
+}
+
 decl_storage! {
 	trait Store for Module<T: Trait> as ExampleOffchainWorker {
 		/// A vector of recently submitted prices.
@@ -196,6 +228,22 @@ decl_module! {
 			Ok(())
 		}
 
+		#[weight = SimpleDispatchInfo::FixedNormal(10_000)]
+		pub fn submit_price_unsigned_with_signed_payload(
+			origin,
+			price_payload: PricePayload<T::Public, T::BlockNumber>,
+			_signature: T::Signature,
+		) -> DispatchResult {
+			// This ensures that the function can only be called via unsigned transaction.
+			ensure_none(origin)?;
+			// Add the price to the on-chain list, but mark it as coming from an empty address.
+			Self::add_price(Default::default(), price_payload.price);
+			// now increment the block number at which we expect next unsigned transaction.
+			let current_block = <system::Module<T>>::block_number();
+			<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
+			Ok(())
+		}
+
 		/// Offchain Worker entry point.
 		///
 		/// By implementing `fn offchain_worker` within `decl_module!` you declare a new offchain
@@ -236,7 +284,9 @@ decl_module! {
 			let should_send = Self::choose_transaction_type(block_number);
 			let res = match should_send {
 				TransactionType::Signed => Self::fetch_price_and_send_signed(),
-				TransactionType::Unsigned => Self::fetch_price_and_send_unsigned(block_number),
+				TransactionType::UnsignedForAny => Self::fetch_price_and_send_unsigned_for_any_account(block_number),
+				TransactionType::UnsignedForAll => Self::fetch_price_and_send_unsigned_for_all_accounts(block_number),
+				TransactionType::Raw => Self::fetch_price_and_send_raw_unsigned(block_number),
 				TransactionType::None => Ok(()),
 			};
 			if let Err(e) = res {
@@ -248,7 +298,9 @@ decl_module! {
 
 enum TransactionType {
 	Signed,
-	Unsigned,
+	UnsignedForAny,
+	UnsignedForAll,
+	Raw,
 	None,
 }
 
@@ -311,12 +363,11 @@ impl<T: Trait> Module<T> {
 				// transactions in a row. If a strict order is desired, it's better to use
 				// the storage entry for that. (for instance store both block number and a flag
 				// indicating the type of next transaction to send).
-				let send_signed = block_number % 2.into() == Zero::zero();
-				if send_signed {
-					TransactionType::Signed
-				} else {
-					TransactionType::Unsigned
-				}
+				let transaction_type = block_number % 3.into();
+				if transaction_type == Zero::zero() { TransactionType::Signed }
+				else if transaction_type == T::BlockNumber::from(1) { TransactionType::UnsignedForAny }
+				else if transaction_type == T::BlockNumber::from(2) { TransactionType::UnsignedForAll }
+				else { TransactionType::Raw }
 			},
 			// We are in the grace period, we should not send a transaction this time.
 			Err(RECENTLY_SENT) => TransactionType::None,
@@ -331,44 +382,43 @@ impl<T: Trait> Module<T> {
 
 	/// A helper function to fetch the price and send signed transaction.
 	fn fetch_price_and_send_signed() -> Result<(), &'static str> {
-		use system::offchain::SubmitSignedTransaction;
-		// Firstly we check if there are any accounts in the local keystore that are capable of
-		// signing the transaction.
-		// If not it doesn't even make sense to make external HTTP requests, since we won't be able
-		// to put the results back on-chain.
-		if !T::SubmitSignedTransaction::can_sign() {
+		use frame_system::offchain::SendSignedTransaction;
+
+		let signer = Signer::<T, T::AuthorityId>::all_accounts();
+		if !signer.can_sign() {
 			return Err(
 				"No local accounts available. Consider adding one via `author_insertKey` RPC."
 			)?
 		}
-
 		// Make an external HTTP request to fetch the current price.
 		// Note this call will block until response is received.
 		let price = Self::fetch_price().map_err(|_| "Failed to fetch price")?;
 
-		// Received price is wrapped into a call to `submit_price` public function of this pallet.
-		// This means that the transaction, when executed, will simply call that function passing
-		// `price` as an argument.
-		let call = Call::submit_price(price);
-
-		// Using `SubmitSignedTransaction` associated type we create and submit a transaction
+		// Using `send_signed_transaction` associated type we create and submit a transaction
 		// representing the call, we've just created.
 		// Submit signed will return a vector of results for all accounts that were found in the
 		// local keystore with expected `KEY_TYPE`.
-		let results = T::SubmitSignedTransaction::submit_signed(call);
+		let results = signer.send_signed_transaction(
+			|_account| {
+				// Received price is wrapped into a call to `submit_price` public function of this pallet.
+				// This means that the transaction, when executed, will simply call that function passing
+				// `price` as an argument.
+				Call::submit_price(price)
+			}
+		);
+
 		for (acc, res) in &results {
 			match res {
-				Ok(()) => debug::info!("[{:?}] Submitted price of {} cents", acc, price),
-				Err(e) => debug::error!("[{:?}] Failed to submit transaction: {:?}", acc, e),
+				Ok(()) => debug::info!("[{:?}] Submitted price of {} cents", acc.id, price),
+				Err(e) => debug::error!("[{:?}] Failed to submit transaction: {:?}", acc.id, e),
 			}
 		}
 
 		Ok(())
 	}
 
-	/// A helper function to fetch the price and send unsigned transaction.
-	fn fetch_price_and_send_unsigned(block_number: T::BlockNumber) -> Result<(), &'static str> {
-		use system::offchain::SubmitUnsignedTransaction;
+	/// A helper function to fetch the price and send a raw unsigned transaction.
+	fn fetch_price_and_send_raw_unsigned(block_number: T::BlockNumber) -> Result<(), &'static str> {
 		// Make sure we don't fetch the price if unsigned transaction is going to be rejected
 		// anyway.
 		let next_unsigned_at = <NextUnsignedAt<T>>::get();
@@ -385,14 +435,101 @@ impl<T: Trait> Module<T> {
 		// passing `price` as an argument.
 		let call = Call::submit_price_unsigned(block_number, price);
 
-		// Now let's create an unsigned transaction out of this call and submit it to the pool.
+		// Now let's create a transaction out of this call and submit it to the pool.
+		// Here we showcase two ways to send an unsigned transaction / unsigned payload (raw)
+		//
 		// By default unsigned transactions are disallowed, so we need to whitelist this case
 		// by writing `UnsignedValidator`. Note that it's EXTREMELY important to carefuly
 		// implement unsigned validation logic, as any mistakes can lead to opening DoS or spam
 		// attack vectors. See validation logic docs for more details.
-		T::SubmitUnsignedTransaction::submit_unsigned(call)
-			.map_err(|()| "Unable to submit unsigned transaction.".into())
+		//
+		SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into())
+			.map_err(|()| "Unable to submit unsigned transaction.")?;
 
+		Ok(())
+	}
+
+	/// A helper function to fetch the price, sign payload and send an unsigned transaction
+	fn fetch_price_and_send_unsigned_for_any_account(block_number: T::BlockNumber) -> Result<(), &'static str> {
+		// Make sure we don't fetch the price if unsigned transaction is going to be rejected
+		// anyway.
+		let next_unsigned_at = <NextUnsignedAt<T>>::get();
+		if next_unsigned_at > block_number {
+			return Err("Too early to send unsigned transaction")
+		}
+
+		// Make an external HTTP request to fetch the current price.
+		// Note this call will block until response is received.
+		let price = Self::fetch_price().map_err(|_| "Failed to fetch price")?;
+
+		// Received price is wrapped into a call to `submit_price_unsigned` public function of this
+		// pallet. This means that the transaction, when executed, will simply call that function
+		// passing `price` as an argument.
+		let call = Call::submit_price_unsigned(block_number, price);
+
+		// Now let's create a transaction out of this call and submit it to the pool.
+		// Here we showcase two ways to send an unsigned transaction with a signed payload
+		SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into())
+			.map_err(|()| "Unable to submit unsigned transaction.")?;
+
+		// -- Sign using any account
+		let (_, result) = Signer::<T, T::AuthorityId>::any_account().send_unsigned_transaction(
+			|account| PricePayload {
+				price,
+				block_number,
+				public: account.public.clone()
+			},
+			|payload, signature| {
+				Call::submit_price_unsigned_with_signed_payload(payload, signature)
+			}
+		).ok_or("No local accounts accounts available.")?;
+		result.map_err(|()| "Unable to submit transaction")?;
+
+		Ok(())
+	}
+
+	/// A helper function to fetch the price, sign payload and send an unsigned transaction
+	fn fetch_price_and_send_unsigned_for_all_accounts(block_number: T::BlockNumber) -> Result<(), &'static str> {
+		// Make sure we don't fetch the price if unsigned transaction is going to be rejected
+		// anyway.
+		let next_unsigned_at = <NextUnsignedAt<T>>::get();
+		if next_unsigned_at > block_number {
+			return Err("Too early to send unsigned transaction")
+		}
+
+		// Make an external HTTP request to fetch the current price.
+		// Note this call will block until response is received.
+		let price = Self::fetch_price().map_err(|_| "Failed to fetch price")?;
+
+		// Received price is wrapped into a call to `submit_price_unsigned` public function of this
+		// pallet. This means that the transaction, when executed, will simply call that function
+		// passing `price` as an argument.
+		let call = Call::submit_price_unsigned(block_number, price);
+
+		// Now let's create a transaction out of this call and submit it to the pool.
+		// Here we showcase two ways to send an unsigned transaction with a signed payload
+		SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into())
+			.map_err(|()| "Unable to submit unsigned transaction.")?;
+
+		// -- Sign using all accounts
+		let transaction_results = Signer::<T, T::AuthorityId>::all_accounts()
+			.send_unsigned_transaction(
+				|account| PricePayload {
+					price,
+					block_number,
+					public: account.public.clone()
+				},
+				|payload, signature| {
+					Call::submit_price_unsigned_with_signed_payload(payload, signature)
+				}
+			);
+		for (_account_id, result) in transaction_results.into_iter() {
+			if result.is_err() {
+				return Err("Unable to submit transaction");
+			}
+		}
+
+		Ok(())
 	}
 
 	/// Fetch current price and return the result in cents.
@@ -507,6 +644,58 @@ impl<T: Trait> Module<T> {
 			Some(prices.iter().fold(0_u32, |a, b| a.saturating_add(*b)) / prices.len() as u32)
 		}
 	}
+
+	fn validate_transaction_parameters(
+		block_number: &T::BlockNumber,
+		new_price: &u32,
+	) -> TransactionValidity {
+		// Now let's check if the transaction has any chance to succeed.
+		let next_unsigned_at = <NextUnsignedAt<T>>::get();
+		if &next_unsigned_at > block_number {
+			return InvalidTransaction::Stale.into();
+		}
+		// Let's make sure to reject transactions from the future.
+		let current_block = <system::Module<T>>::block_number();
+		if &current_block < block_number {
+			return InvalidTransaction::Future.into();
+		}
+
+		// We prioritize transactions that are more far away from current average.
+		//
+		// Note this doesn't make much sense when building an actual oracle, but this example
+		// is here mostly to show off offchain workers capabilities, not about building an
+		// oracle.
+		let avg_price = Self::average_price()
+			.map(|price| if &price > new_price { price - new_price } else { new_price - price })
+			.unwrap_or(0);
+
+		ValidTransaction::with_tag_prefix("ExampleOffchainWorker")
+			// We set base priority to 2**20 and hope it's included before any other
+			// transactions in the pool. Next we tweak the priority depending on how much
+			// it differs from the current average. (the more it differs the more priority it
+			// has).
+			.priority(T::UnsignedPriority::get().saturating_add(avg_price as _))
+			// This transaction does not require anything else to go before into the pool.
+			// In theory we could require `previous_unsigned_at` transaction to go first,
+			// but it's not necessary in our case.
+			//.and_requires()
+			// We set the `provides` tag to be the same as `next_unsigned_at`. This makes
+			// sure only one transaction produced after `next_unsigned_at` will ever
+			// get to the transaction pool and will end up in the block.
+			// We can still have multiple transactions compete for the same "spot",
+			// and the one with higher priority will replace other one in the pool.
+			.and_provides(next_unsigned_at)
+			// The transaction is only valid for next 5 blocks. After that it's
+			// going to be revalidated by the pool.
+			.longevity(5)
+			// It's fine to propagate that transaction to other peers, which means it can be
+			// created even by nodes that don't produce blocks.
+			// Note that sometimes it's better to keep it for yourself (if you are the block
+			// producer), since for instance in some schemes others may copy your solution and
+			// claim a reward.
+			.propagate(true)
+			.build()
+	}
 }
 
 #[allow(deprecated)] // ValidateUnsigned
@@ -523,54 +712,16 @@ impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
 		call: &Self::Call,
 	) -> TransactionValidity {
 		// Firstly let's check that we call the right function.
-		if let Call::submit_price_unsigned(block_number, new_price) = call {
-			// Now let's check if the transaction has any chance to succeed.
-			let next_unsigned_at = <NextUnsignedAt<T>>::get();
-			if &next_unsigned_at > block_number {
-				return InvalidTransaction::Stale.into();
-			}
-			// Let's make sure to reject transactions from the future.
-			let current_block = <system::Module<T>>::block_number();
-			if &current_block < block_number {
-				return InvalidTransaction::Future.into();
+		if let Call::submit_price_unsigned_with_signed_payload(
+			ref payload, ref signature
+		) = call {
+			let signature_valid = SignedPayload::<T>::verify::<T::AuthorityId>(payload, signature.clone());
+			if !signature_valid {
+				return InvalidTransaction::BadProof.into();
 			}
-
-			// We prioritize transactions that are more far away from current average.
-			//
-			// Note this doesn't make much sense when building an actual oracle, but this example
-			// is here mostly to show off offchain workers capabilities, not about building an
-			// oracle.
-			let avg_price = Self::average_price()
-				.map(|price| if &price > new_price { price - new_price } else { new_price - price })
-				.unwrap_or(0);
-
-			ValidTransaction::with_tag_prefix("ExampleOffchainWorker")
-				// We set base priority to 2**20 to make sure it's included before any other
-				// transactions in the pool. Next we tweak the priority depending on how much
-				// it differs from the current average. (the more it differs the more priority it
-				// has).
-				.priority(T::UnsignedPriority::get().saturating_add(avg_price as _))
-				// This transaction does not require anything else to go before into the pool.
-				// In theory we could require `previous_unsigned_at` transaction to go first,
-				// but it's not necessary in our case.
-				//.and_requires()
-
-				// We set the `provides` tag to be the same as `next_unsigned_at`. This makes
-				// sure only one transaction produced after `next_unsigned_at` will ever
-				// get to the transaction pool and will end up in the block.
-				// We can still have multiple transactions compete for the same "spot",
-				// and the one with higher priority will replace other one in the pool.
-				.and_provides(next_unsigned_at)
-				// The transaction is only valid for next 5 blocks. After that it's
-				// going to be revalidated by the pool.
-				.longevity(5)
-				// It's fine to propagate that transaction to other peers, which means it can be
-				// created even by nodes that don't produce blocks.
-				// Note that sometimes it's better to keep it for yourself (if you are the block
-				// producer), since for instance in some schemes others may copy your solution and
-				// claim a reward.
-				.propagate(true)
-				.build()
+			Self::validate_transaction_parameters(&payload.block_number, &payload.price)
+		} else if let Call::submit_price_unsigned(block_number, new_price) = call {
+			Self::validate_transaction_parameters(block_number, new_price)
 		} else {
 			InvalidTransaction::Call.into()
 		}
diff --git a/substrate/frame/example-offchain-worker/src/tests.rs b/substrate/frame/example-offchain-worker/src/tests.rs
index 279de7ef4a3820c6ca3e5425430306ccce5bf62c..aebcbde451b151b2f8e94ac5df7766a7a6238905 100644
--- a/substrate/frame/example-offchain-worker/src/tests.rs
+++ b/substrate/frame/example-offchain-worker/src/tests.rs
@@ -16,7 +16,7 @@
 
 use crate::*;
 
-use codec::Decode;
+use codec::{Encode, Decode};
 use frame_support::{
 	assert_ok, impl_outer_origin, parameter_types,
 	weights::Weight,
@@ -24,13 +24,17 @@ use frame_support::{
 use sp_core::{
 	H256,
 	offchain::{OffchainExt, TransactionPoolExt, testing},
+	sr25519::Signature,
 	testing::KeyStore,
 	traits::KeystoreExt,
 };
 use sp_runtime::{
 	Perbill, RuntimeAppPublic,
 	testing::{Header, TestXt},
-	traits::{BlakeTwo256, IdentityLookup, Extrinsic as ExtrinsicsT},
+	traits::{
+		BlakeTwo256, IdentityLookup, Extrinsic as ExtrinsicT,
+		IdentifyAccount, Verify,
+	},
 };
 
 impl_outer_origin! {
@@ -40,7 +44,7 @@ impl_outer_origin! {
 // For testing the module, we construct most of a mock runtime. This means
 // first constructing a configuration type (`Test`) which `impl`s each of the
 // configuration traits of modules we want to use.
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Clone, Eq, PartialEq, Encode, Decode)]
 pub struct Test;
 parameter_types! {
 	pub const BlockHashCount: u64 = 250;
@@ -72,22 +76,29 @@ impl frame_system::Trait for Test {
 }
 
 type Extrinsic = TestXt<Call<Test>, ()>;
-type SubmitTransaction = frame_system::offchain::TransactionSubmitter<
-	crypto::Public,
-	Test,
-	Extrinsic
->;
-
-impl frame_system::offchain::CreateTransaction<Test, Extrinsic> for Test {
-	type Public = sp_core::sr25519::Public;
-	type Signature = sp_core::sr25519::Signature;
-
-	fn create_transaction<F: frame_system::offchain::Signer<Self::Public, Self::Signature>>(
-		call: <Extrinsic as ExtrinsicsT>::Call,
-		_public: Self::Public,
-		_account: <Test as frame_system::Trait>::AccountId,
-		nonce: <Test as frame_system::Trait>::Index,
-	) -> Option<(<Extrinsic as ExtrinsicsT>::Call, <Extrinsic as ExtrinsicsT>::SignaturePayload)> {
+type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
+
+impl frame_system::offchain::SigningTypes for Test {
+	type Public = <Signature as Verify>::Signer;
+	type Signature = Signature;
+}
+
+impl<LocalCall> frame_system::offchain::SendTransactionTypes<LocalCall> for Test where
+	Call<Test>: From<LocalCall>,
+{
+	type OverarchingCall = Call<Test>;
+	type Extrinsic = Extrinsic;
+}
+
+impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Test where
+	Call<Test>: From<LocalCall>,
+{
+	fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
+		call: Call<Test>,
+		_public: <Signature as Verify>::Signer,
+		_account: AccountId,
+		nonce: u64,
+	) -> Option<(Call<Test>, <Extrinsic as ExtrinsicT>::SignaturePayload)> {
 		Some((call, (nonce, ())))
 	}
 }
@@ -100,9 +111,8 @@ parameter_types! {
 
 impl Trait for Test {
 	type Event = ();
+	type AuthorityId = crypto::TestAuthId;
 	type Call = Call<Test>;
-	type SubmitSignedTransaction = SubmitTransaction;
-	type SubmitUnsignedTransaction = SubmitTransaction;
 	type GracePeriod = GracePeriod;
 	type UnsignedInterval = UnsignedInterval;
 	type UnsignedPriority = UnsignedPriority;
@@ -172,18 +182,128 @@ fn should_submit_signed_transaction_on_chain() {
 }
 
 #[test]
-fn should_submit_unsigned_transaction_on_chain() {
+fn should_submit_unsigned_transaction_on_chain_for_any_account() {
+	const PHRASE: &str = "news slush supreme milk chapter athlete soap sausage put clutch what kitten";
 	let (offchain, offchain_state) = testing::TestOffchainExt::new();
 	let (pool, pool_state) = testing::TestTransactionPoolExt::new();
+
+	let keystore = KeyStore::new();
+
+	keystore.write().sr25519_generate_new(
+		crate::crypto::Public::ID,
+		Some(&format!("{}/hunter1", PHRASE))
+	).unwrap();
+
 	let mut t = sp_io::TestExternalities::default();
 	t.register_extension(OffchainExt::new(offchain));
 	t.register_extension(TransactionPoolExt::new(pool));
+	t.register_extension(KeystoreExt(keystore.clone()));
+
+	price_oracle_response(&mut offchain_state.write());
+
+	let public_key = keystore.read()
+		.sr25519_public_keys(crate::crypto::Public::ID)
+		.get(0)
+		.unwrap()
+		.clone();
+
+	let price_payload = PricePayload {
+		block_number: 1,
+		price: 15523,
+		public: <Test as SigningTypes>::Public::from(public_key),
+	};
+
+	// let signature = price_payload.sign::<crypto::TestAuthId>().unwrap();
+	t.execute_with(|| {
+		// when
+		Example::fetch_price_and_send_unsigned_for_any_account(1).unwrap();
+		// then
+		let tx = pool_state.write().transactions.pop().unwrap();
+		let tx = Extrinsic::decode(&mut &*tx).unwrap();
+		assert_eq!(tx.signature, None);
+		if let Call::submit_price_unsigned_with_signed_payload(body, signature) = tx.call {
+			assert_eq!(body, price_payload);
+
+			let signature_valid = <PricePayload<
+				<Test as SigningTypes>::Public,
+				<Test as frame_system::Trait>::BlockNumber
+					> as SignedPayload<Test>>::verify::<crypto::TestAuthId>(&price_payload, signature);
+
+			assert!(signature_valid);
+		}
+	});
+}
+
+#[test]
+fn should_submit_unsigned_transaction_on_chain_for_all_accounts() {
+	const PHRASE: &str = "news slush supreme milk chapter athlete soap sausage put clutch what kitten";
+	let (offchain, offchain_state) = testing::TestOffchainExt::new();
+	let (pool, pool_state) = testing::TestTransactionPoolExt::new();
+
+	let keystore = KeyStore::new();
+
+	keystore.write().sr25519_generate_new(
+		crate::crypto::Public::ID,
+		Some(&format!("{}/hunter1", PHRASE))
+	).unwrap();
+
+	let mut t = sp_io::TestExternalities::default();
+	t.register_extension(OffchainExt::new(offchain));
+	t.register_extension(TransactionPoolExt::new(pool));
+	t.register_extension(KeystoreExt(keystore.clone()));
+
+	price_oracle_response(&mut offchain_state.write());
+
+	let public_key = keystore.read()
+		.sr25519_public_keys(crate::crypto::Public::ID)
+		.get(0)
+		.unwrap()
+		.clone();
+
+	let price_payload = PricePayload {
+		block_number: 1,
+		price: 15523,
+		public: <Test as SigningTypes>::Public::from(public_key),
+	};
+
+	// let signature = price_payload.sign::<crypto::TestAuthId>().unwrap();
+	t.execute_with(|| {
+		// when
+		Example::fetch_price_and_send_unsigned_for_all_accounts(1).unwrap();
+		// then
+		let tx = pool_state.write().transactions.pop().unwrap();
+		let tx = Extrinsic::decode(&mut &*tx).unwrap();
+		assert_eq!(tx.signature, None);
+		if let Call::submit_price_unsigned_with_signed_payload(body, signature) = tx.call {
+			assert_eq!(body, price_payload);
+
+			let signature_valid = <PricePayload<
+				<Test as SigningTypes>::Public,
+				<Test as frame_system::Trait>::BlockNumber
+					> as SignedPayload<Test>>::verify::<crypto::TestAuthId>(&price_payload, signature);
+
+			assert!(signature_valid);
+		}
+	});
+}
+
+#[test]
+fn should_submit_raw_unsigned_transaction_on_chain() {
+	let (offchain, offchain_state) = testing::TestOffchainExt::new();
+	let (pool, pool_state) = testing::TestTransactionPoolExt::new();
+
+	let keystore = KeyStore::new();
+
+	let mut t = sp_io::TestExternalities::default();
+	t.register_extension(OffchainExt::new(offchain));
+	t.register_extension(TransactionPoolExt::new(pool));
+	t.register_extension(KeystoreExt(keystore));
 
 	price_oracle_response(&mut offchain_state.write());
 
 	t.execute_with(|| {
 		// when
-		Example::fetch_price_and_send_unsigned(1).unwrap();
+		Example::fetch_price_and_send_raw_unsigned(1).unwrap();
 		// then
 		let tx = pool_state.write().transactions.pop().unwrap();
 		assert!(pool_state.read().transactions.is_empty());
diff --git a/substrate/frame/im-online/src/lib.rs b/substrate/frame/im-online/src/lib.rs
index 1137fc2699fe3f13e60cb7e220092cf43913c184..813b11bbc9360c5a07a95aa67857dca5f9cb5b11 100644
--- a/substrate/frame/im-online/src/lib.rs
+++ b/substrate/frame/im-online/src/lib.rs
@@ -98,7 +98,10 @@ use frame_support::{
 	weights::{SimpleDispatchInfo, MINIMUM_WEIGHT},
 };
 use frame_system::{self as system, ensure_none};
-use frame_system::offchain::SubmitUnsignedTransaction;
+use frame_system::offchain::{
+	SendTransactionTypes,
+	SubmitTransaction,
+};
 
 pub mod sr25519 {
 	mod app_sr25519 {
@@ -221,19 +224,13 @@ pub struct Heartbeat<BlockNumber>
 	pub authority_index: AuthIndex,
 }
 
-pub trait Trait: frame_system::Trait + pallet_session::historical::Trait {
+pub trait Trait: SendTransactionTypes<Call<Self>> + pallet_session::historical::Trait {
 	/// The identifier type for an authority.
 	type AuthorityId: Member + Parameter + RuntimeAppPublic + Default + Ord;
 
 	/// The overarching event type.
 	type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
 
-	/// A dispatchable call type.
-	type Call: From<Call<Self>>;
-
-	/// A transaction submitter.
-	type SubmitTransaction: SubmitUnsignedTransaction<Self, <Self as Trait>::Call>;
-
 	/// An expected duration of the session.
 	///
 	/// This parameter is used to determine the longevity of `heartbeat` transaction
@@ -444,6 +441,7 @@ impl<T: Trait> Module<T> {
 		}
 
 		let session_index = <pallet_session::Module<T>>::current_index();
+
 		Ok(Self::local_authority_keys()
 			.map(move |(authority_index, key)|
 				Self::send_single_heartbeat(authority_index, key, session_index, block_number)
@@ -467,7 +465,9 @@ impl<T: Trait> Module<T> {
 				session_index,
 				authority_index,
 			};
+
 			let signature = key.sign(&heartbeat_data.encode()).ok_or(OffchainErr::FailedSigning)?;
+
 			Ok(Call::heartbeat(heartbeat_data, signature))
 		};
 
@@ -492,7 +492,7 @@ impl<T: Trait> Module<T> {
 					call,
 				);
 
-				T::SubmitTransaction::submit_unsigned(call)
+				SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into())
 					.map_err(|_| OffchainErr::SubmitTransaction)?;
 
 				Ok(())
@@ -501,9 +501,18 @@ impl<T: Trait> Module<T> {
 	}
 
 	fn local_authority_keys() -> impl Iterator<Item=(u32, T::AuthorityId)> {
-		// we run only when a local authority key is configured
+		// on-chain storage
+		//
+		// At index `idx`:
+		// 1. A (ImOnline) public key to be used by a validator at index `idx` to send im-online
+		//          heartbeats.
 		let authorities = Keys::<T>::get();
+
+		// local keystore
+		//
+		// All `ImOnline` public (+private) keys currently in the local keystore.
 		let mut local_keys = T::AuthorityId::all();
+
 		local_keys.sort();
 
 		authorities.into_iter()
@@ -565,6 +574,11 @@ impl<T: Trait> Module<T> {
 			Keys::<T>::put(keys);
 		}
 	}
+
+	#[cfg(test)]
+	fn set_keys(keys: Vec<T::AuthorityId>) {
+		Keys::<T>::put(&keys)
+	}
 }
 
 impl<T: Trait> sp_runtime::BoundToRuntimeAppPublic for Module<T> {
diff --git a/substrate/frame/im-online/src/mock.rs b/substrate/frame/im-online/src/mock.rs
index d620bb51b7436be9005d8d48ac1d65962456b3c1..e9b5ef95ef4a02be212ce3758b21d44471c94cfb 100644
--- a/substrate/frame/im-online/src/mock.rs
+++ b/substrate/frame/im-online/src/mock.rs
@@ -27,7 +27,6 @@ use sp_runtime::testing::{Header, UintAuthorityId, TestXt};
 use sp_runtime::traits::{IdentityLookup, BlakeTwo256, ConvertInto};
 use sp_core::H256;
 use frame_support::{impl_outer_origin, impl_outer_dispatch, parameter_types, weights::Weight};
-
 use frame_system as system;
 impl_outer_origin!{
 	pub enum Origin for Runtime {}
@@ -40,7 +39,11 @@ impl_outer_dispatch! {
 }
 
 thread_local! {
-	pub static VALIDATORS: RefCell<Option<Vec<u64>>> = RefCell::new(Some(vec![1, 2, 3]));
+	pub static VALIDATORS: RefCell<Option<Vec<u64>>> = RefCell::new(Some(vec![
+		1,
+		2,
+		3,
+	]));
 }
 
 pub struct TestSessionManager;
@@ -68,7 +71,6 @@ impl pallet_session::historical::SessionManager<u64, u64> for TestSessionManager
 
 /// An extrinsic type used for tests.
 pub type Extrinsic = TestXt<Call, ()>;
-type SubmitTransaction = frame_system::offchain::TransactionSubmitter<(), Call, Extrinsic>;
 type IdentificationTuple = (u64, u64);
 type Offence = crate::UnresponsivenessOffence<IdentificationTuple>;
 
@@ -90,7 +92,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
 	t.into()
 }
 
-
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct Runtime;
 
@@ -168,13 +169,18 @@ parameter_types! {
 impl Trait for Runtime {
 	type AuthorityId = UintAuthorityId;
 	type Event = ();
-	type Call = Call;
-	type SubmitTransaction = SubmitTransaction;
 	type ReportUnresponsiveness = OffenceHandler;
 	type SessionDuration = Period;
 	type UnsignedPriority = UnsignedPriority;
 }
 
+impl<LocalCall> frame_system::offchain::SendTransactionTypes<LocalCall> for Runtime where
+	Call: From<LocalCall>,
+{
+	type OverarchingCall = Call;
+	type Extrinsic = Extrinsic;
+}
+
 /// Im Online module.
 pub type ImOnline = Module<Runtime>;
 pub type System = frame_system::Module<Runtime>;
@@ -184,5 +190,7 @@ pub fn advance_session() {
 	let now = System::block_number().max(1);
 	System::set_block_number(now + 1);
 	Session::rotate_session();
+	let keys = Session::validators().into_iter().map(UintAuthorityId).collect();
+	ImOnline::set_keys(keys);
 	assert_eq!(Session::current_index(), (now / Period::get()) as u32);
 }
diff --git a/substrate/frame/im-online/src/tests.rs b/substrate/frame/im-online/src/tests.rs
index c7bf2afcca629f74765c1519abdd063e63dae1f1..e49f28f4896e068d58adbfcaa3062a9482996497 100644
--- a/substrate/frame/im-online/src/tests.rs
+++ b/substrate/frame/im-online/src/tests.rs
@@ -61,15 +61,15 @@ fn should_report_offline_validators() {
 		let block = 1;
 		System::set_block_number(block);
 		// buffer new validators
-		Session::rotate_session();
+		advance_session();
 		// enact the change and buffer another one
 		let validators = vec![1, 2, 3, 4, 5, 6];
 		VALIDATORS.with(|l| *l.borrow_mut() = Some(validators.clone()));
-		Session::rotate_session();
+		advance_session();
 
 		// when
 		// we end current session and start the next one
-		Session::rotate_session();
+		advance_session();
 
 		// then
 		let offences = OFFENCES.with(|l| l.replace(vec![]));
@@ -89,7 +89,7 @@ fn should_report_offline_validators() {
 		for (idx, v) in validators.into_iter().take(4).enumerate() {
 			let _ = heartbeat(block, 3, idx as u32, v.into()).unwrap();
 		}
-		Session::rotate_session();
+		advance_session();
 
 		// then
 		let offences = OFFENCES.with(|l| l.replace(vec![]));
@@ -174,7 +174,7 @@ fn late_heartbeat_should_fail() {
 	new_test_ext().execute_with(|| {
 		advance_session();
 		// given
-		VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 4, 4, 5, 6]));
+		VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6]));
 		assert_eq!(Session::validators(), Vec::<u64>::new());
 		// enact the change and buffer another one
 		advance_session();
@@ -315,7 +315,7 @@ fn should_not_send_a_report_if_already_online() {
 		ImOnline::note_uncle(3, 0);
 
 		// when
-		UintAuthorityId::set_all_keys(vec![0]); // all authorities use pallet_session key 0
+		UintAuthorityId::set_all_keys(vec![1, 2, 3]);
 		// we expect error, since the authority is already online.
 		let mut res = ImOnline::send_heartbeats(4).unwrap();
 		assert_eq!(res.next().unwrap().unwrap(), ());
diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs
index 4c022eb8b89b6cb3ee710cd27e3c498635d297ec..c3863e16bbbad244a4541a4147dd32f9f11dd29b 100644
--- a/substrate/frame/session/benchmarking/src/mock.rs
+++ b/substrate/frame/session/benchmarking/src/mock.rs
@@ -151,11 +151,13 @@ parameter_types! {
 }
 
 pub type Extrinsic = sp_runtime::testing::TestXt<Call, ()>;
-type SubmitTransaction = frame_system::offchain::TransactionSubmitter<
-	sp_runtime::testing::UintAuthorityId,
-	Test,
-	Extrinsic,
->;
+
+impl<C> frame_system::offchain::SendTransactionTypes<C> for Test where
+	Call: From<C>,
+{
+	type OverarchingCall = Call;
+	type Extrinsic = Extrinsic;
+}
 
 impl pallet_staking::Trait for Test {
 	type Currency = Balances;
@@ -174,7 +176,6 @@ impl pallet_staking::Trait for Test {
 	type NextNewSession = Session;
 	type ElectionLookahead = ();
 	type Call = Call;
-	type SubmitTransaction = SubmitTransaction;
 	type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
 	type UnsignedPriority = UnsignedPriority;
 }
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 40fce5b0d4439934c3e8d48b7c62f0f499d79e08..25d9a10709d2128b204316c3b6d6623fbef6076e 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -320,7 +320,7 @@ use sp_staking::{
 use sp_runtime::{Serialize, Deserialize};
 use frame_system::{
 	self as system, ensure_signed, ensure_root, ensure_none,
-	offchain::SubmitUnsignedTransaction,
+	offchain::SendTransactionTypes,
 };
 use sp_phragmen::{
 	ExtendedBalance, Assignment, PhragmenScore, PhragmenResult, build_support_map, evaluate_support,
@@ -743,7 +743,7 @@ impl<T: Trait> SessionInterface<<T as frame_system::Trait>::AccountId> for T whe
 	}
 }
 
-pub trait Trait: frame_system::Trait {
+pub trait Trait: frame_system::Trait + SendTransactionTypes<Call<Self>> {
 	/// The staking balance.
 	type Currency: LockableCurrency<Self::AccountId, Moment=Self::BlockNumber>;
 
@@ -804,10 +804,7 @@ pub trait Trait: frame_system::Trait {
 	/// The overarching call type.
 	type Call: Dispatchable + From<Call<Self>> + IsSubType<Module<Self>, Self> + Clone;
 
-	/// A transaction submitter.
-	type SubmitTransaction: SubmitUnsignedTransaction<Self, <Self as Trait>::Call>;
-
-	/// The maximum number of nominators rewarded for each validator.
+	/// The maximum number of nominator rewarded for each validator.
 	///
 	/// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can claim
 	/// their reward. This used to limit the i/o cost for the nominator payout.
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index 20ec6f46a6b8b270665c2a6351512942c2f8c07f..cd943abfa3974d54b8079f0429196464f8145a91 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -29,7 +29,6 @@ use frame_support::{
 	traits::{Currency, Get, FindAuthor, OnFinalize, OnInitialize},
 	weights::Weight,
 };
-use frame_system::offchain::TransactionSubmitter;
 use sp_io;
 use sp_phragmen::{
 	build_support_map, evaluate_support, reduce, ExtendedBalance, StakedAssignment, PhragmenScore,
@@ -309,13 +308,18 @@ impl Trait for Test {
 	type NextNewSession = Session;
 	type ElectionLookahead = ElectionLookahead;
 	type Call = Call;
-	type SubmitTransaction = SubmitTransaction;
 	type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
 	type UnsignedPriority = UnsignedPriority;
 }
 
+impl<LocalCall> frame_system::offchain::SendTransactionTypes<LocalCall> for Test where
+	Call: From<LocalCall>,
+{
+	type OverarchingCall = Call;
+	type Extrinsic = Extrinsic;
+}
+
 pub type Extrinsic = TestXt<Call, ()>;
-type SubmitTransaction = TransactionSubmitter<(), Test, Extrinsic>;
 
 pub struct ExtBuilder {
 	session_length: BlockNumber,
diff --git a/substrate/frame/staking/src/offchain_election.rs b/substrate/frame/staking/src/offchain_election.rs
index 4d8ccc6f25cca09f5fca272a2e898621f91cf602..c2383d1eebb69b2ab2a5427f1441b29d74c64211 100644
--- a/substrate/frame/staking/src/offchain_election.rs
+++ b/substrate/frame/staking/src/offchain_election.rs
@@ -19,7 +19,7 @@
 use crate::{
 	Call, CompactAssignments, Module, NominatorIndex, OffchainAccuracy, Trait, ValidatorIndex,
 };
-use frame_system::offchain::SubmitUnsignedTransaction;
+use frame_system::offchain::SubmitTransaction;
 use sp_phragmen::{
 	build_support_map, evaluate_support, reduce, Assignment, ExtendedBalance, PhragmenResult,
 	PhragmenScore,
@@ -117,14 +117,14 @@ pub(crate) fn compute_offchain_election<T: Trait>() -> Result<(), OffchainElecti
 	let current_era = <Module<T>>::current_era().unwrap_or_default();
 
 	// send it.
-	let call: <T as Trait>::Call = Call::submit_election_solution_unsigned(
+	let call = Call::submit_election_solution_unsigned(
 		winners,
 		compact,
 		score,
 		current_era,
 	).into();
 
-	T::SubmitTransaction::submit_unsigned(call)
+	SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call)
 		.map_err(|_| OffchainElectionError::PoolSubmissionFailed)
 }
 
diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs
index d1bc3c1a51eab13935447f0a1e1e0a3227f57554..49c404c02209971751a6b0a1e8938c8ef766133a 100644
--- a/substrate/frame/system/src/lib.rs
+++ b/substrate/frame/system/src/lib.rs
@@ -1591,7 +1591,7 @@ impl<T: Trait> Lookup for ChainContext<T> {
 }
 
 #[cfg(test)]
-mod tests {
+pub(crate) mod tests {
 	use super::*;
 	use sp_std::cell::RefCell;
 	use sp_core::H256;
@@ -1602,7 +1602,7 @@ mod tests {
 		pub enum Origin for Test where system = super {}
 	}
 
-	#[derive(Clone, Eq, PartialEq)]
+	#[derive(Clone, Eq, PartialEq, Debug)]
 	pub struct Test;
 
 	parameter_types! {
@@ -1630,8 +1630,9 @@ mod tests {
 		fn on_killed_account(who: &u64) { KILLED.with(|r| r.borrow_mut().push(*who)) }
 	}
 
-	#[derive(Debug)]
-	pub struct Call {}
+	#[derive(Debug, codec::Encode, codec::Decode)]
+	pub struct Call;
+
 	impl Dispatchable for Call {
 		type Origin = ();
 		type Trait = ();
@@ -1679,7 +1680,7 @@ mod tests {
 
 	type System = Module<Test>;
 
-	const CALL: &<Test as Trait>::Call = &Call {};
+	const CALL: &<Test as Trait>::Call = &Call;
 
 	fn new_test_ext() -> sp_io::TestExternalities {
 		GenesisConfig::default().build_storage::<Test>().unwrap().into()
diff --git a/substrate/frame/system/src/offchain.rs b/substrate/frame/system/src/offchain.rs
index a3fe3e00ca4be879ed6074cc6b13f75e0fbae83f..04cd3001e43a3899cdbdafaa7fb3a1eeb9bed9db 100644
--- a/substrate/frame/system/src/offchain.rs
+++ b/substrate/frame/system/src/offchain.rs
@@ -15,353 +15,832 @@
 // along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
 
 //! Module helpers for off-chain calls.
+//!
+//! ## Overview
+//!
+//! This module provides transaction related helpers to:
+//! - Submit a raw unsigned transaction
+//! - Submit an unsigned transaction with a signed payload
+//! - Submit a signed transction.
+//!
+//! ## Usage
+//!
+//! Please refer to [`example-offchain-worker`](../../pallet_example_offchain_worker/index.html) for
+//! a concrete example usage of this crate.
+//!
+//! ### Submit a raw unsigned transaction
+//!
+//! To submit a raw unsigned transaction, [`SubmitTransaction`](./struct.SubmitTransaction.html)
+//! can be used.
+//!
+//! ### Signing transactions
+//!
+//! To be able to use signing, the following trait should be implemented:
+//!
+//! - [`AppCrypto`](./trait.AppCrypto.html): where an application-specific key
+//!   is defined and can be used by this module's helpers for signing.
+//! - [`CreateSignedTransaction`](./trait.CreateSignedTransaction.html): where
+//!   the manner in which the transaction is constructed is defined.
+//!
+//! #### Submit an unsigned transaction with a signed payload
+//!
+//! Initially, a payload instance that implements the `SignedPayload` trait should be defined.
+//! See [`PricePayload`](../../pallet_example_offchain_worker/struct.PricePayload.html)
+//!
+//! The payload type that is defined defined can then be signed and submitted onchain.
+//!
+//! #### Submit a signed transaction
+//!
+//! [`Signer`](./struct.Signer.html) can be used to sign/verify payloads
+//!
+
+#![warn(missing_docs)]
 
 use codec::Encode;
-use sp_std::convert::TryInto;
-use sp_std::prelude::Vec;
-use sp_runtime::app_crypto::{RuntimeAppPublic, AppPublic, AppSignature};
+use sp_std::collections::btree_set::BTreeSet;
+use sp_std::convert::{TryInto, TryFrom};
+use sp_std::prelude::{Box, Vec};
+use sp_runtime::app_crypto::RuntimeAppPublic;
 use sp_runtime::traits::{Extrinsic as ExtrinsicT, IdentifyAccount, One};
-use frame_support::{debug, storage::StorageMap};
+use frame_support::{debug, storage::StorageMap, RuntimeDebug};
 
-/// Creates runtime-specific signed transaction.
+/// Marker struct used to flag using all supported keys to sign a payload.
+pub struct ForAll {}
+/// Marker struct used to flag using any of the supported keys to sign a payload.
+pub struct ForAny {}
+
+/// Provides the ability to directly submit signed and unsigned
+/// transaction onchain.
 ///
-/// This trait should be implemented by your `Runtime` to be able
-/// to submit `SignedTransaction`s` to the pool from off-chain code.
-pub trait CreateTransaction<T: crate::Trait, Extrinsic: ExtrinsicT> {
-	/// A `Public` key representing a particular `AccountId`.
-	type Public: IdentifyAccount<AccountId=T::AccountId> + Clone;
-	/// A `Signature` generated by the `Signer`.
-	type Signature;
+/// For submitting unsigned transactions, `submit_unsigned_transaction`
+/// utility function can be used. However, this struct is used by `Signer`
+/// to submit a signed transactions providing the signature along with the call.
+pub struct SubmitTransaction<T: SendTransactionTypes<OverarchingCall>, OverarchingCall> {
+	_phantom: sp_std::marker::PhantomData<(T, OverarchingCall)>
+}
 
-	/// Attempt to create signed extrinsic data that encodes call from given account.
-	///
-	/// Runtime implementation is free to construct the payload to sign and the signature
-	/// in any way it wants.
-	/// Returns `None` if signed extrinsic could not be created (either because signing failed
-	/// or because of any other runtime-specific reason).
-	fn create_transaction<F: Signer<Self::Public, Self::Signature>>(
-		call: Extrinsic::Call,
-		public: Self::Public,
-		account: T::AccountId,
-		nonce: T::Index,
-	) -> Option<(Extrinsic::Call, Extrinsic::SignaturePayload)>;
+impl<T, LocalCall> SubmitTransaction<T, LocalCall>
+where
+	T: SendTransactionTypes<LocalCall>,
+{
+	/// Submit transaction onchain by providing the call and an optional signature
+	pub fn submit_transaction(
+		call: <T as SendTransactionTypes<LocalCall>>::OverarchingCall,
+		signature: Option<<T::Extrinsic as ExtrinsicT>::SignaturePayload>,
+	) -> Result<(), ()> {
+		let xt = T::Extrinsic::new(call.into(), signature).ok_or(())?;
+		sp_io::offchain::submit_transaction(xt.encode())
+	}
+
+	/// A convenience method to submit an unsigned transaction onchain.
+	pub fn submit_unsigned_transaction(
+		call: <T as SendTransactionTypes<LocalCall>>::OverarchingCall,
+	) -> Result<(), ()> {
+		SubmitTransaction::<T, LocalCall>::submit_transaction(call, None)
+	}
 }
 
-/// A trait responsible for signing a payload using given account.
+/// Provides an implementation for signing transaction payloads.
 ///
-/// This trait is usually going to represent a local public key
-/// that has ability to sign arbitrary `Payloads`.
+/// Keys used for signing are defined when instantiating the signer object.
+/// Signing can be done using:
 ///
-/// NOTE: Most likely you don't need to implement this trait manually.
-/// It has a blanket implementation for all `RuntimeAppPublic` types,
-/// so it's enough to pass an application-specific crypto type.
+/// - All supported keys in the keystore
+/// - Any of the supported keys in the keystore
+/// - An intersection of in-keystore keys and the list of provided keys
 ///
-/// To easily create `SignedTransaction`s have a look at the
-/// [`TransactionSubmitter`] type.
-pub trait Signer<Public, Signature> {
-	/// Sign any encodable payload with given account and produce a signature.
+/// The signer is then able to:
+/// - Submit a unsigned transaction with a signed payload
+/// - Submit a signed transaction
+#[derive(RuntimeDebug)]
+pub struct Signer<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>, X = ForAny> {
+	accounts: Option<Vec<T::Public>>,
+	_phantom: sp_std::marker::PhantomData<(X, C)>,
+}
+
+impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>, X> Default for Signer<T, C, X> {
+	fn default() -> Self {
+		Self {
+			accounts: Default::default(),
+			_phantom: Default::default(),
+		}
+	}
+}
+
+impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>, X> Signer<T, C, X> {
+	/// Use all available keys for signing.
+	pub fn all_accounts() -> Signer<T, C, ForAll> {
+		Default::default()
+	}
+
+	/// Use any of the available keys for signing.
+	pub fn any_account() -> Signer<T, C, ForAny> {
+		Default::default()
+	}
+
+	/// Use provided `accounts` for signing.
 	///
-	/// Returns `Some` if signing succeeded and `None` in case the `account` couldn't
-	/// be used (for instance we couldn't convert it to required application specific crypto).
-	fn sign<Payload: Encode>(public: Public, payload: &Payload) -> Option<Signature>;
+	/// Note that not all keys will be necessarily used. The provided
+	/// vector of accounts will be intersected with the supported keys
+	/// in the keystore and the resulting list will be used for signing.
+	pub fn with_filter(mut self, accounts: Vec<T::Public>) -> Self {
+		self.accounts = Some(accounts);
+		self
+	}
+
+	/// Check if there are any keys that could be used for signing.
+	pub fn can_sign(&self) -> bool {
+		self.accounts_from_keys().count() > 0
+	}
+
+	/// Return a vector of the intersection between
+	/// all available accounts and the provided accounts
+	/// in `with_filter`. If no accounts are provided,
+	/// use all accounts by default.
+	fn accounts_from_keys<'a>(&'a self) -> Box<dyn Iterator<Item = Account<T>> + 'a> {
+		let keystore_accounts = self.keystore_accounts();
+		match self.accounts {
+			None => Box::new(keystore_accounts),
+			Some(ref keys) =>  {
+				let keystore_lookup: BTreeSet<<T as SigningTypes>::Public> = keystore_accounts
+					.map(|account| account.public).collect();
+
+				Box::new(keys.into_iter()
+					.enumerate()
+					.map(|(index, key)| {
+						let account_id = key.clone().into_account();
+						Account::new(index, account_id, key.clone())
+					})
+					.filter(move |account| keystore_lookup.contains(&account.public)))
+			}
+		}
+	}
+
+	fn keystore_accounts(&self) -> impl Iterator<Item = Account<T>> {
+		C::RuntimeAppPublic::all()
+			.into_iter()
+			.enumerate()
+			.map(|(index, key)| {
+				let generic_public = C::GenericPublic::from(key);
+				let public = generic_public.into();
+				let account_id = public.clone().into_account();
+				Account::new(index, account_id, public.clone())
+			})
+	}
 }
 
-/// A `Signer` implementation for any `AppPublic` type.
-///
-/// This implementation additionally supports conversion to/from multi-signature/multi-signer
-/// wrappers.
-/// If the wrapped crypto doesn't match `AppPublic`s crypto `None` is returned.
-impl<Public, Signature, TAnyAppPublic> Signer<Public, Signature> for TAnyAppPublic where
-	TAnyAppPublic: RuntimeAppPublic
-		+ AppPublic
-		+ From<<TAnyAppPublic as AppPublic>::Generic>,
-	<TAnyAppPublic as RuntimeAppPublic>::Signature: AppSignature,
-	Signature: From<
-		<<TAnyAppPublic as RuntimeAppPublic>::Signature as AppSignature>::Generic
-	>,
-	Public: TryInto<<TAnyAppPublic as AppPublic>::Generic>
-{
-	fn sign<Payload: Encode>(public: Public, raw_payload: &Payload) -> Option<Signature> {
-		raw_payload.using_encoded(|payload| {
-			let public = public.try_into().ok()?;
-			TAnyAppPublic::from(public).sign(&payload)
-				.map(
-					<<TAnyAppPublic as RuntimeAppPublic>::Signature as AppSignature>
-					 ::Generic::from
-				)
-				.map(Signature::from)
+
+impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>> Signer<T, C, ForAll> {
+	fn for_all<F, R>(&self, f: F) -> Vec<(Account<T>, R)> where
+		F: Fn(&Account<T>) -> Option<R>,
+	{
+		let accounts = self.accounts_from_keys();
+		accounts
+			.into_iter()
+			.filter_map(|account| {
+				f(&account).map(|res| (account, res))
+			})
+			.collect()
+	}
+}
+
+impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>> Signer<T, C, ForAny> {
+	fn for_any<F, R>(&self, f: F) -> Option<(Account<T>, R)> where
+		F: Fn(&Account<T>) -> Option<R>,
+	{
+		let accounts = self.accounts_from_keys();
+		for account in accounts.into_iter() {
+			let res = f(&account);
+			if let Some(res) = res {
+				return Some((account, res));
+			}
+		}
+		None
+	}
+}
+
+impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>> SignMessage<T> for Signer<T, C, ForAll> {
+	type SignatureData = Vec<(Account<T>, T::Signature)>;
+
+	fn sign_message(&self, message: &[u8]) -> Self::SignatureData {
+		self.for_all(|account| C::sign(message, account.public.clone()))
+	}
+
+	fn sign<TPayload, F>(&self, f: F) -> Self::SignatureData where
+		F: Fn(&Account<T>) -> TPayload,
+		TPayload: SignedPayload<T>,
+	{
+		self.for_all(|account| f(account).sign::<C>())
+	}
+}
+
+impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>> SignMessage<T> for Signer<T, C, ForAny> {
+	type SignatureData = Option<(Account<T>, T::Signature)>;
+
+	fn sign_message(&self, message: &[u8]) -> Self::SignatureData {
+		self.for_any(|account| C::sign(message, account.public.clone()))
+	}
+
+	fn sign<TPayload, F>(&self, f: F) -> Self::SignatureData where
+		F: Fn(&Account<T>) -> TPayload,
+		TPayload: SignedPayload<T>,
+	{
+		self.for_any(|account| f(account).sign::<C>())
+	}
+}
+
+impl<
+	T: CreateSignedTransaction<LocalCall> + SigningTypes,
+	C: AppCrypto<T::Public, T::Signature>,
+	LocalCall,
+> SendSignedTransaction<T, C, LocalCall> for Signer<T, C, ForAny> {
+	type Result = Option<(Account<T>, Result<(), ()>)>;
+
+	fn send_signed_transaction(
+		&self,
+		f: impl Fn(&Account<T>) -> LocalCall,
+	) -> Self::Result {
+		self.for_any(|account| {
+			let call = f(account);
+			self.send_single_signed_transaction(account, call)
 		})
 	}
 }
 
-/// Retrieves a public key type for given `SignAndSubmitTransaction`.
-pub type PublicOf<T, Call, X> =
-<
-	<X as SignAndSubmitTransaction<T, Call>>::CreateTransaction
-	as
-	CreateTransaction<T, <X as SignAndSubmitTransaction<T, Call>>::Extrinsic>
->::Public;
+impl<
+	T: SigningTypes + CreateSignedTransaction<LocalCall>,
+	C: AppCrypto<T::Public, T::Signature>,
+	LocalCall,
+> SendSignedTransaction<T, C, LocalCall> for Signer<T, C, ForAll> {
+	type Result = Vec<(Account<T>, Result<(), ()>)>;
+
+	fn send_signed_transaction(
+		&self,
+		f: impl Fn(&Account<T>) -> LocalCall,
+	) -> Self::Result {
+		self.for_all(|account| {
+			let call = f(account);
+			self.send_single_signed_transaction(account, call)
+		})
+	}
+}
+
+impl<
+	T: SigningTypes + SendTransactionTypes<LocalCall>,
+	C: AppCrypto<T::Public, T::Signature>,
+	LocalCall,
+> SendUnsignedTransaction<T, LocalCall> for Signer<T, C, ForAny> {
+	type Result = Option<(Account<T>, Result<(), ()>)>;
+
+	fn send_unsigned_transaction<TPayload, F>(
+		&self,
+		f: F,
+		f2: impl Fn(TPayload, T::Signature) -> LocalCall,
+	) -> Self::Result
+	where
+		F: Fn(&Account<T>) -> TPayload,
+		TPayload: SignedPayload<T>,
+	{
+		self.for_any(|account| {
+			let payload = f(account);
+			let signature= payload.sign::<C>()?;
+			let call = f2(payload, signature);
+			self.submit_unsigned_transaction(call)
+		})
+	}
+}
+
+impl<
+	T: SigningTypes + SendTransactionTypes<LocalCall>,
+	C: AppCrypto<T::Public, T::Signature>,
+	LocalCall,
+> SendUnsignedTransaction<T, LocalCall> for Signer<T, C, ForAll> {
+	type Result = Vec<(Account<T>, Result<(), ()>)>;
+
+	fn send_unsigned_transaction<TPayload, F>(
+		&self,
+		f: F,
+		f2: impl Fn(TPayload, T::Signature) -> LocalCall,
+	) -> Self::Result
+	where
+		F: Fn(&Account<T>) -> TPayload,
+		TPayload: SignedPayload<T> {
+		self.for_all(|account| {
+			let payload = f(account);
+			let signature = payload.sign::<C>()?;
+			let call = f2(payload, signature);
+			self.submit_unsigned_transaction(call)
+		})
+	}
+}
+
+/// Details of an account for which a private key is contained in the keystore.
+#[derive(RuntimeDebug, PartialEq)]
+pub struct Account<T: SigningTypes> {
+	/// Index on the provided list of accounts or list of all accounts.
+	pub index: usize,
+	/// Runtime-specific `AccountId`.
+	pub id: T::AccountId,
+	/// A runtime-specific `Public` key for that key pair.
+	pub public: T::Public,
+}
+
+impl<T: SigningTypes> Account<T> {
+	/// Create a new Account instance
+	pub fn new(index: usize, id: T::AccountId, public: T::Public) -> Self {
+		Self { index, id, public }
+	}
+}
+
+impl<T: SigningTypes> Clone for Account<T> where
+	T::AccountId: Clone,
+	T::Public: Clone,
+{
+	fn clone(&self) -> Self {
+		Self {
+			index: self.index,
+			id: self.id.clone(),
+			public: self.public.clone(),
+		}
+	}
+}
 
-/// A trait to sign and submit transactions in off-chain calls.
+/// A type binding runtime-level `Public/Signature` pair with crypto wrapped by `RuntimeAppPublic`.
 ///
-/// NOTE: Most likely you should not implement this trait yourself.
-/// There is an implementation for
-/// [`TransactionSubmitter`] type, which
-/// you should use.
-pub trait SignAndSubmitTransaction<T: crate::Trait, Call> {
-	/// Unchecked extrinsic type.
-	type Extrinsic: ExtrinsicT<Call=Call> + Encode;
-
-	/// A runtime-specific type to produce signed data for the extrinsic.
-	type CreateTransaction: CreateTransaction<T, Self::Extrinsic>;
-
-	/// A type used to sign transactions created using `CreateTransaction`.
-	type Signer: Signer<
-		PublicOf<T, Call, Self>,
-		<Self::CreateTransaction as CreateTransaction<T, Self::Extrinsic>>::Signature,
-	>;
-
-	/// Sign given call and submit it to the transaction pool.
-	///
-	/// Returns `Ok` if the transaction was submitted correctly
-	/// and `Err` if the key for given `id` was not found or the
-	/// transaction was rejected from the pool.
-	fn sign_and_submit(call: impl Into<Call>, public: PublicOf<T, Call, Self>) -> Result<(), ()> {
-		let call = call.into();
-		let id = public.clone().into_account();
-		let mut account = super::Account::<T>::get(&id);
-		debug::native::debug!(
-			target: "offchain",
-			"Creating signed transaction from account: {:?} (nonce: {:?})",
-			id,
-			account.nonce,
-		);
-		let (call, signature_data) = Self::CreateTransaction
-			::create_transaction::<Self::Signer>(call, public, id.clone(), account.nonce)
-			.ok_or(())?;
-		// increment the nonce. This is fine, since the code should always
-		// be running in off-chain context, so we NEVER persists data.
-		account.nonce += One::one();
-		super::Account::<T>::insert(&id, account);
-
-		let xt = Self::Extrinsic::new(call, Some(signature_data)).ok_or(())?;
-		sp_io::offchain::submit_transaction(xt.encode())
+/// Implementations of this trait should specify the app-specific public/signature types.
+/// This is merely a wrapper around an existing `RuntimeAppPublic` type, but with
+/// extra non-application-specific crypto type that is being wrapped (e.g. `sr25519`, `ed25519`).
+/// This is needed to later on convert into runtime-specific `Public` key, which might support
+/// multiple different crypto.
+/// The point of this trait is to be able to easily convert between `RuntimeAppPublic`, the wrapped
+/// (generic = non application-specific) crypto types and the `Public` type required by the runtime.
+///
+/// TODO [#5662] Potentially use `IsWrappedBy` types, or find some other way to make it easy to
+/// obtain unwrapped crypto (and wrap it back).
+///
+///	Example (pseudo-)implementation:
+/// ```ignore
+///	// im-online specific crypto
+/// type RuntimeAppPublic = ImOnline(sr25519::Public);
+/// // wrapped "raw" crypto
+/// type GenericPublic = sr25519::Public;
+/// type GenericSignature = sr25519::Signature;
+///
+/// // runtime-specific public key
+/// type Public = MultiSigner: From<sr25519::Public>;
+/// type Signature = MulitSignature: From<sr25519::Signature>;
+/// ```
+pub trait AppCrypto<Public, Signature> {
+	/// A application-specific crypto.
+	type RuntimeAppPublic: RuntimeAppPublic;
+
+	/// A raw crypto public key wrapped by `RuntimeAppPublic`.
+	type GenericPublic:
+		From<Self::RuntimeAppPublic>
+		+ Into<Self::RuntimeAppPublic>
+		+ TryFrom<Public>
+		+ Into<Public>;
+
+	/// A matching raw crypto `Signature` type.
+	type GenericSignature:
+		From<<Self::RuntimeAppPublic as RuntimeAppPublic>::Signature>
+		+ Into<<Self::RuntimeAppPublic as RuntimeAppPublic>::Signature>
+		+ TryFrom<Signature>
+		+ Into<Signature>;
+
+	/// Sign payload with the private key to maps to the provided public key.
+	fn sign(payload: &[u8], public: Public) -> Option<Signature> {
+		let p: Self::GenericPublic = public.try_into().ok()?;
+		let x = Into::<Self::RuntimeAppPublic>::into(p);
+		x.sign(&payload)
+			.map(|x| {
+				let sig: Self::GenericSignature = x.into();
+				sig
+			})
+			.map(Into::into)
+	}
+
+	/// Verify signature against the provided public key.
+	fn verify(payload: &[u8], public: Public, signature: Signature) -> bool {
+		let p: Self::GenericPublic = match public.try_into() {
+			Ok(a) => a,
+			_ => return false
+		};
+		let x = Into::<Self::RuntimeAppPublic>::into(p);
+		let signature: Self::GenericSignature = match signature.try_into() {
+			Ok(a) => a,
+			_ => return false
+		};
+		let signature = Into::<<
+			Self::RuntimeAppPublic as RuntimeAppPublic
+		>::Signature>::into(signature);
+
+		x.verify(&payload, &signature)
 	}
 }
 
-/// A trait to submit unsigned transactions in off-chain calls.
+/// A wrapper around the types which are used for signing.
+///
+/// This trait adds extra bounds to `Public` and `Signature` types of the runtime
+/// that are necessary to use these types for signing.
 ///
-/// NOTE: Most likely you should not implement this trait yourself.
-/// There is an implementation for
-/// [`TransactionSubmitter`] type, which
-/// you should use.
-pub trait SubmitUnsignedTransaction<T: crate::Trait, Call> {
-	/// Unchecked extrinsic type.
-	type Extrinsic: ExtrinsicT<Call=Call> + Encode;
-
-	/// Submit given call to the transaction pool as unsigned transaction.
+///	TODO [#5663] Could this be just `T::Signature as traits::Verify>::Signer`?
+/// Seems that this may cause issues with bounds resolution.
+pub trait SigningTypes: crate::Trait {
+	/// A public key that is capable of identifing `AccountId`s.
 	///
-	/// Returns `Ok` if the transaction was submitted correctly
-	/// and `Err` if transaction was rejected from the pool.
-	fn submit_unsigned(call: impl Into<Call>) -> Result<(), ()> {
-		let xt = Self::Extrinsic::new(call.into(), None).ok_or(())?;
-		let encoded_xt = xt.encode();
-		sp_io::offchain::submit_transaction(encoded_xt)
-	}
+	/// Usually that's either a raw crypto public key (e.g. `sr25519::Public`) or
+	/// an aggregate type for multiple crypto public keys, like `MulitSigner`.
+	type Public: Clone
+		+ PartialEq
+		+ IdentifyAccount<AccountId = Self::AccountId>
+		+ core::fmt::Debug
+		+ codec::Codec
+		+ Ord;
+
+	/// A matching `Signature` type.
+	type Signature: Clone
+		+ PartialEq
+		+ core::fmt::Debug
+		+ codec::Codec;
 }
 
-/// A utility trait to easily create signed transactions
-/// from accounts in node's local keystore.
+/// A definition of types required to submit transactions from within the runtime.
+pub trait SendTransactionTypes<LocalCall> {
+	/// The extrinsic type expected by the runtime.
+	type Extrinsic: ExtrinsicT<Call=Self::OverarchingCall> + codec::Encode;
+	/// The runtime's call type.
+	///
+	/// This has additional bound to be able to be created from pallet-local `Call` types.
+	type OverarchingCall: From<LocalCall>;
+}
+
+/// Create signed transaction.
 ///
-/// NOTE: Most likely you should not implement this trait yourself.
-/// There is an implementation for
-/// [`TransactionSubmitter`] type, which
-/// you should use.
-pub trait SubmitSignedTransaction<T: crate::Trait, Call> {
-	/// A `SignAndSubmitTransaction` implementation.
-	type SignAndSubmit: SignAndSubmitTransaction<T, Call>;
-
-	/// Find local keys that match given list of accounts.
+/// This trait is meant to be implemented by the runtime and is responsible for constructing
+/// a payload to be signed and contained within the extrinsic.
+/// This will most likely include creation of `SignedExtra` (a set of `SignedExtensions`).
+/// Note that the result can be altered by inspecting the `Call` (for instance adjusting
+/// fees, or mortality depending on the `pallet` being called).
+pub trait CreateSignedTransaction<LocalCall>: SendTransactionTypes<LocalCall> + SigningTypes {
+	/// Attempt to create signed extrinsic data that encodes call from given account.
 	///
-	/// Technically it finds an intersection between given list of `AccountId`s
-	/// and accounts that are represented by public keys in local keystore.
-	/// If `None` is passed it returns all accounts in the keystore.
+	/// Runtime implementation is free to construct the payload to sign and the signature
+	/// in any way it wants.
+	/// Returns `None` if signed extrinsic could not be created (either because signing failed
+	/// or because of any other runtime-specific reason).
+	fn create_transaction<C: AppCrypto<Self::Public, Self::Signature>>(
+		call: Self::OverarchingCall,
+		public: Self::Public,
+		account: Self::AccountId,
+		nonce: Self::Index,
+	) -> Option<(Self::OverarchingCall, <Self::Extrinsic as ExtrinsicT>::SignaturePayload)>;
+}
+
+/// A message signer.
+pub trait SignMessage<T: SigningTypes> {
+	/// A signature data.
 	///
-	/// Returns both public keys and `AccountId`s of accounts that are available.
-	/// Such accounts can later be used to sign a payload or send signed transactions.
-	fn find_local_keys(accounts: Option<impl IntoIterator<Item = T::AccountId>>) -> Vec<(
-		T::AccountId,
-		PublicOf<T, Call, Self::SignAndSubmit>,
-	)>;
-
-	/// Find all available local keys.
+	/// May contain account used for signing and the `Signature` itself.
+	type SignatureData;
+
+	/// Sign a message.
 	///
-	/// This is equivalent of calling `find_local_keys(None)`.
-	fn find_all_local_keys() -> Vec<(T::AccountId, PublicOf<T, Call, Self::SignAndSubmit>)> {
-		Self::find_local_keys(None as Option<Vec<_>>)
-	}
+	/// Implementation of this method should return
+	/// a result containing the signature.
+	fn sign_message(&self, message: &[u8]) -> Self::SignatureData;
 
-	/// Check if there are keys for any of given accounts that could be used to send a transaction.
+	/// Construct and sign given payload.
 	///
-	/// This check can be used as an early-exit condition to avoid doing too
-	/// much work, before we actually realise that there are no accounts that you
-	/// we could use for signing.
-	fn can_sign_with(accounts: Option<impl IntoIterator<Item = T::AccountId>>) -> bool {
-		!Self::find_local_keys(accounts).is_empty()
-	}
+	/// This method expects `f` to return a `SignedPayload`
+	/// object which is then used for signing.
+	fn sign<TPayload, F>(&self, f: F) -> Self::SignatureData where
+		F: Fn(&Account<T>) -> TPayload,
+		TPayload: SignedPayload<T>,
+		;
+}
 
-	/// Check if there are any keys that could be used for signing.
+/// Submit a signed transaction to the transaction pool.
+pub trait SendSignedTransaction<
+	T: SigningTypes + CreateSignedTransaction<LocalCall>,
+	C: AppCrypto<T::Public, T::Signature>,
+	LocalCall
+> {
+	/// A submission result.
 	///
-	/// This is equivalent of calling `can_sign_with(None)`.
-	fn can_sign() -> bool {
-		Self::can_sign_with(None as Option<Vec<_>>)
+	/// This should contain an indication of success and the account that was used for signing.
+	type Result;
+
+	/// Submit a signed transaction to the local pool.
+	///
+	/// Given `f` closure will be called for every requested account and expects a `Call` object
+	/// to be returned.
+	/// The call is then wrapped into a transaction (see `#CreateSignedTransaction`), signed and
+	/// submitted to the pool.
+	fn send_signed_transaction(
+		&self,
+		f: impl Fn(&Account<T>) -> LocalCall,
+	) -> Self::Result;
+
+	/// Wraps the call into transaction, signs using given account and submits to the pool.
+	fn send_single_signed_transaction(
+		&self,
+		account: &Account<T>,
+		call: LocalCall,
+	) -> Option<Result<(), ()>> {
+		let mut account_data = crate::Account::<T>::get(&account.id);
+		debug::native::debug!(
+			target: "offchain",
+			"Creating signed transaction from account: {:?} (nonce: {:?})",
+			account.id,
+			account_data.nonce,
+		);
+		let (call, signature) = T::create_transaction::<C>(
+			call.into(),
+			account.public.clone(),
+			account.id.clone(),
+			account_data.nonce
+		)?;
+		let res = SubmitTransaction::<T, LocalCall>
+			::submit_transaction(call, Some(signature));
+
+		if res.is_ok() {
+			// increment the nonce. This is fine, since the code should always
+			// be running in off-chain context, so we NEVER persists data.
+			account_data.nonce += One::one();
+			crate::Account::<T>::insert(&account.id, account_data);
+		}
+
+		Some(res)
 	}
+}
 
-	/// Create and submit signed transactions from supported accounts.
+/// Submit an unsigned transaction onchain with a signed payload
+pub trait SendUnsignedTransaction<
+	T: SigningTypes + SendTransactionTypes<LocalCall>,
+	LocalCall,
+> {
+	/// A submission result.
 	///
-	/// This method should intersect given list of accounts with the ones
-	/// supported locally and submit signed transaction containing given `Call`
-	/// with every of them.
+	/// Should contain the submission result and the account(s) that signed the payload.
+	type Result;
+
+	/// Send an unsigned transaction with a signed payload.
 	///
-	/// Returns a vector of results and account ids that were supported.
-	#[must_use]
-	fn submit_signed_from(
-		call: impl Into<Call> + Clone,
-		accounts: impl IntoIterator<Item = T::AccountId>,
-	) -> Vec<(T::AccountId, Result<(), ()>)> {
-		let keys = Self::find_local_keys(Some(accounts));
-		keys.into_iter().map(|(account, pub_key)| {
-			let call = call.clone().into();
-			(
-				account,
-				Self::SignAndSubmit::sign_and_submit(call, pub_key)
-			)
-		}).collect()
-	}
-
-	/// Create and submit signed transactions from all local accounts.
+	/// This method takes `f` and `f2` where:
+	/// - `f` is called for every account and is expected to return a `SignedPayload` object.
+	/// - `f2` is then called with the `SignedPayload` returned by `f` and the signature and is
+	/// expected to return a `Call` object to be embedded into transaction.
+	fn send_unsigned_transaction<TPayload, F>(
+		&self,
+		f: F,
+		f2: impl Fn(TPayload, T::Signature) -> LocalCall,
+	) -> Self::Result
+	where
+		F: Fn(&Account<T>) -> TPayload,
+		TPayload: SignedPayload<T>;
+
+	/// Submits an unsigned call to the transaction pool.
+	fn submit_unsigned_transaction(
+		&self,
+		call: LocalCall
+	) -> Option<Result<(), ()>> {
+		Some(SubmitTransaction::<T, LocalCall>
+			::submit_unsigned_transaction(call.into()))
+	}
+}
+
+/// Utility trait to be implemented on payloads that can be signed.
+pub trait SignedPayload<T: SigningTypes>: Encode {
+	/// Return a public key that is expected to have a matching key in the keystore,
+	/// which should be used to sign the payload.
+	fn public(&self) -> T::Public;
+
+	/// Sign the payload using the implementor's provided public key.
 	///
-	/// This method submits a signed transaction from all local accounts
-	/// for given application crypto.
+	/// Returns `Some(signature)` if public key is supported.
+	fn sign<C: AppCrypto<T::Public, T::Signature>>(&self) -> Option<T::Signature> {
+		self.using_encoded(|payload| C::sign(payload, self.public()))
+	}
+
+	/// Verify signature against payload.
 	///
-	/// Returns a vector of results and account ids that were supported.
-	#[must_use]
-	fn submit_signed(
-		call: impl Into<Call> + Clone,
-	) -> Vec<(T::AccountId, Result<(), ()>)> {
-		let keys = Self::find_all_local_keys();
-		keys.into_iter().map(|(account, pub_key)| {
-			let call = call.clone().into();
-			(
-				account,
-				Self::SignAndSubmit::sign_and_submit(call, pub_key)
-			)
-		}).collect()
+	/// Returns a bool indicating whether the signature is valid or not.
+	fn verify<C: AppCrypto<T::Public, T::Signature>>(&self, signature: T::Signature) -> bool {
+		self.using_encoded(|payload| C::verify(payload, self.public(), signature))
 	}
 }
 
-/// A default type used to submit transactions to the pool.
-///
-/// This is passed into each runtime as an opaque associated type that can have either of:
-/// - [`SignAndSubmitTransaction`]
-/// - [`SubmitUnsignedTransaction`]
-/// - [`SubmitSignedTransaction`]
-/// and used accordingly.
-///
-/// This struct should be constructed by providing the following generic parameters:
-/// * `Signer` - Usually the application specific key type (see `app_crypto`).
-/// * `CreateTransaction` - A type that is able to produce signed transactions,
-///		usually it's going to be the entire `Runtime` object.
-/// * `Extrinsic` - A runtime-specific type for in-block extrinsics.
-///
-/// If you only need the ability to submit unsigned transactions,
-/// you may substitute both `Signer` and `CreateTransaction` with any type.
-pub struct TransactionSubmitter<Signer, CreateTransaction, Extrinsic> {
-	_signer: sp_std::marker::PhantomData<(Signer, CreateTransaction, Extrinsic)>,
-}
 
-impl<S, C, E> Default for TransactionSubmitter<S, C, E> {
-	fn default() -> Self {
-		Self {
-			_signer: Default::default(),
-		}
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use codec::Decode;
+	use crate::tests::{Test as TestRuntime, Call};
+	use sp_core::offchain::{testing, TransactionPoolExt};
+	use sp_runtime::testing::{UintAuthorityId, TestSignature, TestXt};
+
+	impl SigningTypes for TestRuntime {
+		type Public = UintAuthorityId;
+		type Signature = TestSignature;
 	}
-}
 
-/// A blanket implementation to simplify creation of transaction signer & submitter in the runtime.
-impl<T, E, S, C, Call> SignAndSubmitTransaction<T, Call> for TransactionSubmitter<S, C, E> where
-	T: crate::Trait,
-	C: CreateTransaction<T, E>,
-	S: Signer<<C as CreateTransaction<T, E>>::Public, <C as CreateTransaction<T, E>>::Signature>,
-	E: ExtrinsicT<Call=Call> + Encode,
-{
-	type Extrinsic = E;
-	type CreateTransaction = C;
-	type Signer = S;
-}
+	type Extrinsic = TestXt<Call, ()>;
 
-/// A blanket implementation to use the same submitter for unsigned transactions as well.
-impl<T, E, S, C, Call> SubmitUnsignedTransaction<T, Call> for TransactionSubmitter<S, C, E> where
-	T: crate::Trait,
-	E: ExtrinsicT<Call=Call> + Encode,
-{
-	type Extrinsic = E;
-}
+	impl SendTransactionTypes<Call> for TestRuntime {
+		type Extrinsic = Extrinsic;
+		type OverarchingCall = Call;
+	}
 
-/// A blanket implementation to support local keystore of application-crypto types.
-impl<T, C, E, S, Call> SubmitSignedTransaction<T, Call> for TransactionSubmitter<S, C, E> where
-	T: crate::Trait,
-	C: CreateTransaction<T, E>,
-	E: ExtrinsicT<Call=Call> + Encode,
-	S: Signer<<C as CreateTransaction<T, E>>::Public, <C as CreateTransaction<T, E>>::Signature>,
-	// Make sure we can unwrap the app crypto key.
-	S: RuntimeAppPublic + AppPublic + Into<<S as AppPublic>::Generic>,
-	// Make sure we can convert from wrapped crypto to public key (e.g. `MultiSigner`)
-	S::Generic: Into<PublicOf<T, Call, Self>>,
-	// For simplicity we require the same trait to implement `SignAndSubmitTransaction` too.
-	Self: SignAndSubmitTransaction<T, Call, Signer = S, Extrinsic = E, CreateTransaction = C>,
-{
-	type SignAndSubmit = Self;
-
-	fn find_local_keys(accounts: Option<impl IntoIterator<Item = T::AccountId>>) -> Vec<(
-		T::AccountId,
-		PublicOf<T, Call, Self::SignAndSubmit>,
-	)> {
-		// Convert app-specific keys into generic ones.
-		let local_accounts_and_keys = S::all()
-			.into_iter()
-			.map(|app_key| {
-				// unwrap app-crypto
-				let generic_pub_key: <S as AppPublic>::Generic = app_key.into();
-				// convert to expected public key type (might be MultiSigner)
-				let signer_pub_key: PublicOf<T, Call, Self::SignAndSubmit> = generic_pub_key.into();
-				// lookup accountid for that pubkey
-				let account = signer_pub_key.clone().into_account();
-				(account, signer_pub_key)
-			}).collect::<Vec<_>>();
-
-		if let Some(accounts) = accounts {
-			let mut local_accounts_and_keys = local_accounts_and_keys;
-			// sort by accountId to allow bin-search.
-			local_accounts_and_keys.sort_by(|a, b| a.0.cmp(&b.0));
-
-			// get all the matching accounts
-			accounts.into_iter().filter_map(|acc| {
-				let idx = local_accounts_and_keys.binary_search_by(|a| a.0.cmp(&acc)).ok()?;
-				local_accounts_and_keys.get(idx).cloned()
-			}).collect()
-		} else {
-			// just return all account ids and keys
-			local_accounts_and_keys
-		}
+	#[derive(codec::Encode, codec::Decode)]
+	struct SimplePayload {
+		pub public: UintAuthorityId,
+		pub data: Vec<u8>,
 	}
 
-	fn can_sign_with(accounts: Option<impl IntoIterator<Item = T::AccountId>>) -> bool {
-		// early exit if we care about any account.
-		if accounts.is_none() {
-			!S::all().is_empty()
-		} else {
-			!Self::find_local_keys(accounts).is_empty()
+	impl SignedPayload<TestRuntime> for SimplePayload {
+		fn public(&self) -> UintAuthorityId {
+			self.public.clone()
 		}
 	}
+
+	struct DummyAppCrypto;
+	// Bind together the `SigningTypes` with app-crypto and the wrapper types.
+	// here the implementation is pretty dummy, because we use the same type for
+	// both application-specific crypto and the runtime crypto, but in real-life
+	// runtimes it's going to use different types everywhere.
+	impl AppCrypto<UintAuthorityId, TestSignature> for DummyAppCrypto {
+		type RuntimeAppPublic = UintAuthorityId;
+		type GenericPublic = UintAuthorityId;
+		type GenericSignature = TestSignature;
+	}
+
+	fn assert_account(
+		next: Option<(Account<TestRuntime>, Result<(), ()>)>,
+		index: usize,
+		id: u64,
+	) {
+		assert_eq!(next, Some((Account {
+			index,
+			id,
+			public: id.into(),
+		}, Ok(()))));
+	}
+
+	#[test]
+	fn should_send_unsigned_with_signed_payload_with_all_accounts() {
+		let (pool, pool_state) = testing::TestTransactionPoolExt::new();
+
+		let mut t = sp_io::TestExternalities::default();
+		t.register_extension(TransactionPoolExt::new(pool));
+
+		// given
+		UintAuthorityId::set_all_keys(vec![0xf0, 0xf1, 0xf2]);
+
+		t.execute_with(|| {
+			// when
+			let result = Signer::<TestRuntime, DummyAppCrypto>
+				::all_accounts()
+				.send_unsigned_transaction(
+					|account| SimplePayload {
+						data: vec![1, 2, 3],
+						public: account.public.clone()
+					},
+					|_payload, _signature| {
+						Call
+					}
+				);
+
+			// then
+			let mut res = result.into_iter();
+			assert_account(res.next(), 0, 0xf0);
+			assert_account(res.next(), 1, 0xf1);
+			assert_account(res.next(), 2, 0xf2);
+			assert_eq!(res.next(), None);
+
+			// check the transaction pool content:
+			let tx1 = pool_state.write().transactions.pop().unwrap();
+			let _tx2 = pool_state.write().transactions.pop().unwrap();
+			let _tx3 = pool_state.write().transactions.pop().unwrap();
+			assert!(pool_state.read().transactions.is_empty());
+			let tx1 = Extrinsic::decode(&mut &*tx1).unwrap();
+			assert_eq!(tx1.signature, None);
+		});
+	}
+
+	#[test]
+	fn should_send_unsigned_with_signed_payload_with_any_account() {
+		let (pool, pool_state) = testing::TestTransactionPoolExt::new();
+
+		let mut t = sp_io::TestExternalities::default();
+		t.register_extension(TransactionPoolExt::new(pool));
+
+		// given
+		UintAuthorityId::set_all_keys(vec![0xf0, 0xf1, 0xf2]);
+
+		t.execute_with(|| {
+			// when
+			let result = Signer::<TestRuntime, DummyAppCrypto>
+				::any_account()
+				.send_unsigned_transaction(
+					|account| SimplePayload {
+						data: vec![1, 2, 3],
+						public: account.public.clone()
+					},
+					|_payload, _signature| {
+						Call
+					}
+				);
+
+			// then
+			let mut res = result.into_iter();
+			assert_account(res.next(), 0, 0xf0);
+			assert_eq!(res.next(), None);
+
+			// check the transaction pool content:
+			let tx1 = pool_state.write().transactions.pop().unwrap();
+			assert!(pool_state.read().transactions.is_empty());
+			let tx1 = Extrinsic::decode(&mut &*tx1).unwrap();
+			assert_eq!(tx1.signature, None);
+		});
+	}
+
+	#[test]
+	fn should_send_unsigned_with_signed_payload_with_all_account_and_filter() {
+		let (pool, pool_state) = testing::TestTransactionPoolExt::new();
+
+		let mut t = sp_io::TestExternalities::default();
+		t.register_extension(TransactionPoolExt::new(pool));
+
+		// given
+		UintAuthorityId::set_all_keys(vec![0xf0, 0xf1, 0xf2]);
+
+		t.execute_with(|| {
+			// when
+			let result = Signer::<TestRuntime, DummyAppCrypto>
+				::all_accounts()
+				.with_filter(vec![0xf2.into(), 0xf1.into()])
+				.send_unsigned_transaction(
+					|account| SimplePayload {
+						data: vec![1, 2, 3],
+						public: account.public.clone()
+					},
+					|_payload, _signature| {
+						Call
+					}
+				);
+
+			// then
+			let mut res = result.into_iter();
+			assert_account(res.next(), 0, 0xf2);
+			assert_account(res.next(), 1, 0xf1);
+			assert_eq!(res.next(), None);
+
+			// check the transaction pool content:
+			let tx1 = pool_state.write().transactions.pop().unwrap();
+			let _tx2 = pool_state.write().transactions.pop().unwrap();
+			assert!(pool_state.read().transactions.is_empty());
+			let tx1 = Extrinsic::decode(&mut &*tx1).unwrap();
+			assert_eq!(tx1.signature, None);
+		});
+	}
+
+	#[test]
+	fn should_send_unsigned_with_signed_payload_with_any_account_and_filter() {
+		let (pool, pool_state) = testing::TestTransactionPoolExt::new();
+
+		let mut t = sp_io::TestExternalities::default();
+		t.register_extension(TransactionPoolExt::new(pool));
+
+		// given
+		UintAuthorityId::set_all_keys(vec![0xf0, 0xf1, 0xf2]);
+
+		t.execute_with(|| {
+			// when
+			let result = Signer::<TestRuntime, DummyAppCrypto>
+				::any_account()
+				.with_filter(vec![0xf2.into(), 0xf1.into()])
+				.send_unsigned_transaction(
+					|account| SimplePayload {
+						data: vec![1, 2, 3],
+						public: account.public.clone()
+					},
+					|_payload, _signature| {
+						Call
+					}
+				);
+
+			// then
+			let mut res = result.into_iter();
+			assert_account(res.next(), 0, 0xf2);
+			assert_eq!(res.next(), None);
+
+			// check the transaction pool content:
+			let tx1 = pool_state.write().transactions.pop().unwrap();
+			assert!(pool_state.read().transactions.is_empty());
+			let tx1 = Extrinsic::decode(&mut &*tx1).unwrap();
+			assert_eq!(tx1.signature, None);
+		});
+	}
+
 }
diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs
index 79572eb49d1e60d38a06b13356481c25a23803cf..8bad474ede81e1281648953b035be1dbd1cc63ee 100644
--- a/substrate/primitives/application-crypto/src/lib.rs
+++ b/substrate/primitives/application-crypto/src/lib.rs
@@ -25,7 +25,7 @@ pub use sp_core::{self, crypto::{CryptoType, CryptoTypePublicPair, Public, Deriv
 #[doc(hidden)]
 #[cfg(feature = "full_crypto")]
 pub use sp_core::crypto::{SecretStringError, DeriveJunction, Ss58Codec, Pair};
-pub use sp_core::crypto::{CryptoTypeId, KeyTypeId, key_types};
+pub use sp_core::crypto::{KeyTypeId, key_types};
 
 #[doc(hidden)]
 pub use codec;
diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs
index 4aae575b2c15a7ff7281cb35659d60b60490d65b..4eb96ff960bcc72d65fd12d0567bd7206945d131 100644
--- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs
+++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs
@@ -320,29 +320,10 @@ mod tests {
 	use super::*;
 	use sp_io::hashing::blake2_256;
 	use crate::codec::{Encode, Decode};
-	use crate::traits::{SignedExtension, IdentifyAccount, IdentityLookup};
-	use serde::{Serialize, Deserialize};
+	use crate::traits::{SignedExtension, IdentityLookup};
+	use crate::testing::TestSignature as TestSig;
 
 	type TestContext = IdentityLookup<u64>;
-
-	#[derive(Eq, PartialEq, Clone, Copy, Debug, Serialize, Deserialize, Encode, Decode)]
-	pub struct TestSigner(pub u64);
-	impl From<u64> for TestSigner { fn from(x: u64) -> Self { Self(x) } }
-	impl From<TestSigner> for u64 { fn from(x: TestSigner) -> Self { x.0 } }
-	impl IdentifyAccount for TestSigner {
-		type AccountId = u64;
-		fn into_account(self) -> u64 { self.into() }
-	}
-
-	#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Encode, Decode)]
-	struct TestSig(u64, Vec<u8>);
-	impl traits::Verify for TestSig {
-		type Signer = TestSigner;
-		fn verify<L: traits::Lazy<[u8]>>(&self, mut msg: L, signer: &u64) -> bool {
-			signer == &self.0 && msg.get() == &self.1[..]
-		}
-	}
-
 	type TestAccountId = u64;
 	type TestCall = Vec<u8>;
 
diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs
index 0f609b005001858a4efbe594b7da97b16728e257..a5b3e71edcde3d9f1d258730f58ba3749daf2f46 100644
--- a/substrate/primitives/runtime/src/lib.rs
+++ b/substrate/primitives/runtime/src/lib.rs
@@ -182,18 +182,39 @@ impl From<ed25519::Signature> for MultiSignature {
 	}
 }
 
+impl TryFrom<MultiSignature> for ed25519::Signature {
+	type Error = ();
+	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
+		if let MultiSignature::Ed25519(x) = m { Ok(x) } else { Err(()) }
+	}
+}
+
 impl From<sr25519::Signature> for MultiSignature {
 	fn from(x: sr25519::Signature) -> Self {
 		MultiSignature::Sr25519(x)
 	}
 }
 
+impl TryFrom<MultiSignature> for sr25519::Signature {
+	type Error = ();
+	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
+		if let MultiSignature::Sr25519(x) = m { Ok(x) } else { Err(()) }
+	}
+}
+
 impl From<ecdsa::Signature> for MultiSignature {
 	fn from(x: ecdsa::Signature) -> Self {
 		MultiSignature::Ecdsa(x)
 	}
 }
 
+impl TryFrom<MultiSignature> for ecdsa::Signature {
+	type Error = ();
+	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
+		if let MultiSignature::Ecdsa(x) = m { Ok(x) } else { Err(()) }
+	}
+}
+
 impl Default for MultiSignature {
 	fn default() -> Self {
 		MultiSignature::Ed25519(Default::default())
diff --git a/substrate/primitives/runtime/src/testing.rs b/substrate/primitives/runtime/src/testing.rs
index 1414a5f4f0a753d02abc6ed2c25c574bfbe531f7..40b4e23e3fa0a6b94bb340a1d640f6461c543ca5 100644
--- a/substrate/primitives/runtime/src/testing.rs
+++ b/substrate/primitives/runtime/src/testing.rs
@@ -17,7 +17,7 @@
 //! Testing utilities.
 
 use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializer};
-use std::{fmt::Debug, ops::Deref, fmt, cell::RefCell};
+use std::{fmt::{self, Debug}, ops::Deref, cell::RefCell};
 use crate::codec::{Codec, Encode, Decode};
 use crate::traits::{
 	self, Checkable, Applyable, BlakeTwo256, OpaqueKeys,
@@ -29,7 +29,12 @@ pub use sp_core::{H256, sr25519};
 use sp_core::{crypto::{CryptoType, Dummy, key_types, Public}, U256};
 use crate::transaction_validity::{TransactionValidity, TransactionValidityError, TransactionSource};
 
-/// Authority Id
+/// A dummy type which can be used instead of regular cryptographic primitives.
+///
+/// 1. Wraps a `u64` `AccountId` and is able to `IdentifyAccount`.
+/// 2. Can be converted to any `Public` key.
+/// 3. Implements `RuntimeAppPublic` so it can be used instead of regular application-specific
+///    crypto.
 #[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug, Hash, Serialize, Deserialize, PartialOrd, Ord)]
 pub struct UintAuthorityId(pub u64);
 
@@ -82,7 +87,7 @@ impl UintAuthorityId {
 impl sp_application_crypto::RuntimeAppPublic for UintAuthorityId {
 	const ID: KeyTypeId = key_types::DUMMY;
 
-	type Signature = u64;
+	type Signature = TestSignature;
 
 	fn all() -> Vec<Self> {
 		ALL_KEYS.with(|l| l.borrow().clone())
@@ -94,25 +99,11 @@ impl sp_application_crypto::RuntimeAppPublic for UintAuthorityId {
 	}
 
 	fn sign<M: AsRef<[u8]>>(&self, msg: &M) -> Option<Self::Signature> {
-		let mut signature = [0u8; 8];
-		msg.as_ref().iter()
-			.chain(std::iter::repeat(&42u8))
-			.take(8)
-			.enumerate()
-			.for_each(|(i, v)| { signature[i] = *v; });
-
-		Some(u64::from_le_bytes(signature))
+		Some(TestSignature(self.0, msg.as_ref().to_vec()))
 	}
 
 	fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool {
-		let mut msg_signature = [0u8; 8];
-		msg.as_ref().iter()
-			.chain(std::iter::repeat(&42))
-			.take(8)
-			.enumerate()
-			.for_each(|(i, v)| { msg_signature[i] = *v; });
-
-		u64::from_le_bytes(msg_signature) == *signature
+		traits::Verify::verify(signature, msg.as_ref(), &self.0)
 	}
 
 	fn to_raw_vec(&self) -> Vec<u8> {
@@ -140,6 +131,26 @@ impl crate::BoundToRuntimeAppPublic for UintAuthorityId {
 	type Public = Self;
 }
 
+impl traits::IdentifyAccount for UintAuthorityId {
+	type AccountId = u64;
+
+	fn into_account(self) -> Self::AccountId {
+		self.0
+	}
+}
+
+/// A dummy signature type, to match `UintAuthorityId`.
+#[derive(Eq, PartialEq, Clone, Debug, Hash, Serialize, Deserialize, Encode, Decode)]
+pub struct TestSignature(pub u64, pub Vec<u8>);
+
+impl traits::Verify for TestSignature {
+	type Signer = UintAuthorityId;
+
+	fn verify<L: traits::Lazy<[u8]>>(&self, mut msg: L, signer: &u64) -> bool {
+		signer == &self.0 && msg.get() == &self.1[..]
+	}
+}
+
 /// Digest item
 pub type DigestItem = generic::DigestItem<H256>;
 
@@ -332,6 +343,7 @@ impl<Call: Codec + Sync + Send, Context, Extra> Checkable<Context> for TestXt<Ca
 	type Checked = Self;
 	fn check(self, _: &Context) -> Result<Self::Checked, TransactionValidityError> { Ok(self) }
 }
+
 impl<Call: Codec + Sync + Send, Extra> traits::Extrinsic for TestXt<Call, Extra> {
 	type Call = Call;
 	type SignaturePayload = (u64, Extra);