diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 3e37bcfd167e4ff47cd04719d26985cfcd483213..84872ce141da4f3ca649257666be90c392603ef7 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -5032,6 +5032,7 @@ dependencies = [
  "pallet-randomness-collective-flip",
  "pallet-recovery",
  "pallet-referenda",
+ "pallet-remark",
  "pallet-scheduler",
  "pallet-session",
  "pallet-session-benchmarking",
@@ -6306,6 +6307,22 @@ dependencies = [
  "sp-std",
 ]
 
+[[package]]
+name = "pallet-remark"
+version = "4.0.0-dev"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
 [[package]]
 name = "pallet-scheduler"
 version = "4.0.0-dev"
diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml
index c281913cd55edc34df6e59fe74d94c42dbc33ef8..5cc90ec6f183bd9667509983eaab947eb53d29c1 100644
--- a/substrate/Cargo.toml
+++ b/substrate/Cargo.toml
@@ -112,6 +112,7 @@ members = [
 	"frame/randomness-collective-flip",
 	"frame/recovery",
 	"frame/referenda",
+	"frame/remark",
 	"frame/scheduler",
 	"frame/scored-pool",
 	"frame/session",
diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml
index 41b2402d33a536793481ff5f363a20e00a9f8e3e..75f860eb240e857b340ed7d0864d7bdea148264c 100644
--- a/substrate/bin/node/runtime/Cargo.toml
+++ b/substrate/bin/node/runtime/Cargo.toml
@@ -83,6 +83,7 @@ pallet-proxy = { version = "4.0.0-dev", default-features = false, path = "../../
 pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" }
 pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/recovery" }
 pallet-referenda = { version = "4.0.0-dev", default-features = false, path = "../../../frame/referenda" }
+pallet-remark = { version = "4.0.0-dev", default-features = false, path = "../../../frame/remark" }
 pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../../frame/session", default-features = false }
 pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true }
 pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" }
@@ -173,6 +174,7 @@ std = [
 	"sp-version/std",
 	"pallet-society/std",
 	"pallet-referenda/std",
+	"pallet-remark/std",
 	"pallet-recovery/std",
 	"pallet-uniques/std",
 	"pallet-vesting/std",
@@ -213,6 +215,7 @@ runtime-benchmarks = [
 	"pallet-proxy/runtime-benchmarks",
 	"pallet-scheduler/runtime-benchmarks",
 	"pallet-referenda/runtime-benchmarks",
+	"pallet-remark/runtime-benchmarks",
 	"pallet-session-benchmarking",
 	"pallet-society/runtime-benchmarks",
 	"pallet-staking/runtime-benchmarks",
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index f37345014f3a15a2f2bbf0d232ca0c86ef1e87cf..dca386b3036109dadf5169149e16c7e6644b977f 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -778,6 +778,11 @@ impl pallet_referenda::Config for Runtime {
 	type Tracks = TracksInfo;
 }
 
+impl pallet_remark::Config for Runtime {
+	type WeightInfo = pallet_remark::weights::SubstrateWeight<Self>;
+	type Event = Event;
+}
+
 parameter_types! {
 	pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
 	pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
@@ -1457,6 +1462,7 @@ construct_runtime!(
 		StateTrieMigration: pallet_state_trie_migration,
 		ChildBounties: pallet_child_bounties,
 		Referenda: pallet_referenda,
+		Remark: pallet_remark,
 		ConvictionVoting: pallet_conviction_voting,
 		Whitelist: pallet_whitelist,
 	}
@@ -1547,6 +1553,7 @@ mod benches {
 		[pallet_preimage, Preimage]
 		[pallet_proxy, Proxy]
 		[pallet_referenda, Referenda]
+		[pallet_remark, Remark]
 		[pallet_scheduler, Scheduler]
 		[pallet_session, SessionBench::<Runtime>]
 		[pallet_staking, Staking]
diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..82c76d679cc10a2fee0f668afa011a6dca2ea3a0
--- /dev/null
+++ b/substrate/frame/remark/Cargo.toml
@@ -0,0 +1,42 @@
+[package]
+name = "pallet-remark"
+version = "4.0.0-dev"
+authors = ["Parity Technologies <admin@parity.io>"]
+edition = "2021"
+license = "Apache-2.0"
+homepage = "https://substrate.io"
+repository = "https://github.com/paritytech/substrate/"
+description = "Remark storage pallet"
+readme = "README.md"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dependencies]
+serde = { version = "1.0.136", optional = true }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
+frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
+frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
+sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
+sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
+sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" }
+sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" }
+frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true }
+
+[dev-dependencies]
+sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false }
+
+[features]
+default = ["std"]
+runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
+std = [
+	"serde",
+	"codec/std",
+	"scale-info/std",
+	"sp-runtime/std",
+	"frame-support/std",
+	"frame-system/std",
+	"sp-io/std",
+	"sp-std/std",
+]
diff --git a/substrate/frame/remark/README.md b/substrate/frame/remark/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f2341d6a0eaec45287957feab73a0199ddc17dff
--- /dev/null
+++ b/substrate/frame/remark/README.md
@@ -0,0 +1,6 @@
+# Remark Storage Pallet
+
+Allows storing arbitrary data off chain. 
+
+
+License: Apache-2.0
diff --git a/substrate/frame/remark/src/benchmarking.rs b/substrate/frame/remark/src/benchmarking.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d30a8aa5df07d5e5a4a8b700b20b298b375962f9
--- /dev/null
+++ b/substrate/frame/remark/src/benchmarking.rs
@@ -0,0 +1,47 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Benchmarks for remarks pallet
+
+#![cfg(feature = "runtime-benchmarks")]
+
+use super::*;
+use frame_benchmarking::{benchmarks, whitelisted_caller};
+use frame_system::{EventRecord, Pallet as System, RawOrigin};
+use sp_std::*;
+
+#[cfg(test)]
+use crate::Pallet as Remark;
+
+fn assert_last_event<T: Config>(generic_event: <T as Config>::Event) {
+	let events = System::<T>::events();
+	let system_event: <T as frame_system::Config>::Event = generic_event.into();
+	let EventRecord { event, .. } = &events[events.len() - 1];
+	assert_eq!(event, &system_event);
+}
+
+benchmarks! {
+	store {
+		let l in 1 .. 1024*1024;
+		let caller: T::AccountId = whitelisted_caller();
+	}: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize])
+	verify {
+		assert_last_event::<T>(Event::Stored { sender: caller, content_hash: sp_io::hashing::blake2_256(&vec![0u8; l as usize]).into() }.into());
+	}
+
+	impl_benchmark_test_suite!(Remark, crate::mock::new_test_ext(), crate::mock::Test);
+}
diff --git a/substrate/frame/remark/src/lib.rs b/substrate/frame/remark/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6803b2a60085fc8f664e7355f235eb90a4c83522
--- /dev/null
+++ b/substrate/frame/remark/src/lib.rs
@@ -0,0 +1,85 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Remark storage pallet. Indexes remarks and stores them off chain.
+
+// Ensure we're `no_std` when compiling for Wasm.
+#![cfg_attr(not(feature = "std"), no_std)]
+
+mod benchmarking;
+pub mod weights;
+
+#[cfg(test)]
+mod mock;
+#[cfg(test)]
+mod tests;
+
+use sp_std::prelude::*;
+
+// Re-export pallet items so that they can be accessed from the crate namespace.
+pub use pallet::*;
+pub use weights::WeightInfo;
+
+#[frame_support::pallet]
+pub mod pallet {
+	use super::*;
+	use frame_support::pallet_prelude::*;
+	use frame_system::pallet_prelude::*;
+
+	#[pallet::config]
+	pub trait Config: frame_system::Config {
+		/// The overarching event type.
+		type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
+		/// Weight information for extrinsics in this pallet.
+		type WeightInfo: WeightInfo;
+	}
+
+	#[pallet::error]
+	pub enum Error<T> {
+		/// Attempting to store empty data.
+		Empty,
+		/// Attempted to call `store` outside of block execution.
+		BadContext,
+	}
+
+	#[pallet::pallet]
+	#[pallet::without_storage_info]
+	pub struct Pallet<T>(_);
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {
+		/// Index and store data off chain.
+		#[pallet::weight(T::WeightInfo::store(remark.len() as u32))]
+		pub fn store(origin: OriginFor<T>, remark: Vec<u8>) -> DispatchResultWithPostInfo {
+			ensure!(!remark.is_empty(), Error::<T>::Empty);
+			let sender = ensure_signed(origin)?;
+			let content_hash = sp_io::hashing::blake2_256(&remark);
+			let extrinsic_index = <frame_system::Pallet<T>>::extrinsic_index()
+				.ok_or_else(|| Error::<T>::BadContext)?;
+			sp_io::transaction_index::index(extrinsic_index, remark.len() as u32, content_hash);
+			Self::deposit_event(Event::Stored { sender, content_hash: content_hash.into() });
+			Ok(().into())
+		}
+	}
+
+	#[pallet::event]
+	#[pallet::generate_deposit(pub(super) fn deposit_event)]
+	pub enum Event<T: Config> {
+		/// Stored data off chain.
+		Stored { sender: T::AccountId, content_hash: sp_core::H256 },
+	}
+}
diff --git a/substrate/frame/remark/src/mock.rs b/substrate/frame/remark/src/mock.rs
new file mode 100644
index 0000000000000000000000000000000000000000..67a0399e9c3864fa6b4731b23fa06a7273444229
--- /dev/null
+++ b/substrate/frame/remark/src/mock.rs
@@ -0,0 +1,79 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Test environment for remarks pallet.
+
+use crate as pallet_remark;
+use frame_support::traits::{ConstU16, ConstU32, ConstU64};
+use sp_core::H256;
+use sp_runtime::{
+	testing::Header,
+	traits::{BlakeTwo256, IdentityLookup},
+	BuildStorage,
+};
+
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
+pub type Block = frame_system::mocking::MockBlock<Test>;
+
+// Configure a mock runtime to test the pallet.
+frame_support::construct_runtime!(
+	pub enum Test where
+		Block = Block,
+		NodeBlock = Block,
+		UncheckedExtrinsic = UncheckedExtrinsic,
+	{
+		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
+		Remark: pallet_remark::{ Pallet, Call, Event<T> },
+	}
+);
+
+impl frame_system::Config for Test {
+	type BaseCallFilter = frame_support::traits::Everything;
+	type BlockWeights = ();
+	type BlockLength = ();
+	type Origin = Origin;
+	type Call = Call;
+	type Index = u64;
+	type BlockNumber = u64;
+	type Hash = H256;
+	type Hashing = BlakeTwo256;
+	type AccountId = u64;
+	type Lookup = IdentityLookup<Self::AccountId>;
+	type Header = Header;
+	type Event = Event;
+	type BlockHashCount = ConstU64<250>;
+	type DbWeight = ();
+	type Version = ();
+	type PalletInfo = PalletInfo;
+	type AccountData = ();
+	type OnNewAccount = ();
+	type OnKilledAccount = ();
+	type SystemWeightInfo = ();
+	type SS58Prefix = ConstU16<42>;
+	type OnSetCode = ();
+	type MaxConsumers = ConstU32<16>;
+}
+
+impl pallet_remark::Config for Test {
+	type Event = Event;
+	type WeightInfo = ();
+}
+
+pub fn new_test_ext() -> sp_io::TestExternalities {
+	let t = GenesisConfig { system: Default::default() }.build_storage().unwrap();
+	t.into()
+}
diff --git a/substrate/frame/remark/src/tests.rs b/substrate/frame/remark/src/tests.rs
new file mode 100644
index 0000000000000000000000000000000000000000..60a376c5afca57797add6ca829c3407762aabe79
--- /dev/null
+++ b/substrate/frame/remark/src/tests.rs
@@ -0,0 +1,55 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Tests for remarks pallet.
+
+use super::{Error, Event, Pallet as Remark};
+use crate::mock::*;
+use frame_support::{assert_noop, assert_ok};
+use frame_system::RawOrigin;
+
+#[test]
+fn generates_event() {
+	new_test_ext().execute_with(|| {
+		let caller = 1;
+		let data = vec![0u8; 100];
+		System::set_block_number(System::block_number() + 1); //otherwise event won't be registered.
+		assert_ok!(Remark::<Test>::store(RawOrigin::Signed(caller.clone()).into(), data.clone(),));
+		let events = System::events();
+		let system_event: <Test as frame_system::Config>::Event = Event::Stored {
+			content_hash: sp_io::hashing::blake2_256(&data).into(),
+			sender: caller,
+		}
+		.into();
+		let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
+		assert_eq!(event, &system_event);
+	});
+}
+
+#[test]
+fn does_not_store_empty() {
+	new_test_ext().execute_with(|| {
+		let caller = 1;
+		let data = vec![];
+		System::set_block_number(System::block_number() + 1); //otherwise event won't be registered.
+		assert_noop!(
+			Remark::<Test>::store(RawOrigin::Signed(caller.clone()).into(), data.clone(),),
+			Error::<Test>::Empty
+		);
+		assert!(System::events().is_empty());
+	});
+}
diff --git a/substrate/frame/remark/src/weights.rs b/substrate/frame/remark/src/weights.rs
new file mode 100644
index 0000000000000000000000000000000000000000..50b0fc3ebfc192e69fba1f6061de279ca938edf0
--- /dev/null
+++ b/substrate/frame/remark/src/weights.rs
@@ -0,0 +1,71 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Autogenerated weights for pallet_remark
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: 2022-03-11, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
+
+// Executed Command:
+// target/release/substrate
+// benchmark
+// --chain=dev
+// --steps=50
+// --repeat=20
+// --pallet=pallet_remark
+// --extrinsic=*
+// --execution=wasm
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --output=./frame/remark/src/weights.rs
+// --template=./.maintain/frame-weight-template.hbs
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use sp_std::marker::PhantomData;
+
+/// Weight functions needed for pallet_remark.
+pub trait WeightInfo {
+	fn store(l: u32, ) -> Weight;
+}
+
+/// Weights for pallet_remark using the Substrate node and recommended hardware.
+pub struct SubstrateWeight<T>(PhantomData<T>);
+impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
+	// Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0)
+	fn store(l: u32, ) -> Weight {
+		(18_328_000 as Weight)
+			// Standard Error: 0
+			.saturating_add((1_000 as Weight).saturating_mul(l as Weight))
+			.saturating_add(T::DbWeight::get().reads(1 as Weight))
+	}
+}
+
+// For backwards compatibility and tests
+impl WeightInfo for () {
+	// Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0)
+	fn store(l: u32, ) -> Weight {
+		(18_328_000 as Weight)
+			// Standard Error: 0
+			.saturating_add((1_000 as Weight).saturating_mul(l as Weight))
+			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
+	}
+}
diff --git a/substrate/frame/transaction-storage/src/lib.rs b/substrate/frame/transaction-storage/src/lib.rs
index d95a60b49512163852c38876ad14a5206a6933ab..e9aa786766dac0534cbf4e30094e99e062f172ec 100644
--- a/substrate/frame/transaction-storage/src/lib.rs
+++ b/substrate/frame/transaction-storage/src/lib.rs
@@ -170,7 +170,7 @@ pub mod pallet {
 
 	#[pallet::call]
 	impl<T: Config> Pallet<T> {
-		/// Index and store data on chain. Minimum data size is 1 bytes, maximum is
+		/// Index and store data off chain. Minimum data size is 1 bytes, maximum is
 		/// `MaxTransactionSize`. Data will be removed after `STORAGE_PERIOD` blocks, unless `renew`
 		/// is called. # <weight>
 		/// - n*log(n) of data size, as all data is pushed to an in-memory trie.