diff --git a/Cargo.lock b/Cargo.lock
index 88442d3702e94881b25e10c0f6132e1ac5d7fe3e..0d62e43561a6930ee0416a54ddbd761d998c2039 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -12415,6 +12415,28 @@ dependencies = [
  "sp-weights 27.0.0",
 ]
 
+[[package]]
+name = "pallet-meta-tx"
+version = "0.1.0"
+dependencies = [
+ "docify",
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-transaction-payment",
+ "pallet-verify-signature",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-core 28.0.0",
+ "sp-io 30.0.0",
+ "sp-keyring",
+ "sp-keystore 0.34.0",
+ "sp-runtime 31.0.1",
+ "sp-std 14.0.0",
+]
+
 [[package]]
 name = "pallet-migrations"
 version = "1.0.0"
@@ -15892,6 +15914,7 @@ dependencies = [
  "pallet-lottery",
  "pallet-membership",
  "pallet-message-queue",
+ "pallet-meta-tx",
  "pallet-migrations",
  "pallet-mixnet",
  "pallet-mmr",
@@ -27489,6 +27512,7 @@ dependencies = [
  "pallet-indices",
  "pallet-membership",
  "pallet-message-queue",
+ "pallet-meta-tx",
  "pallet-migrations",
  "pallet-mmr",
  "pallet-multisig",
@@ -27516,6 +27540,7 @@ dependencies = [
  "pallet-transaction-payment-rpc-runtime-api",
  "pallet-treasury",
  "pallet-utility",
+ "pallet-verify-signature",
  "pallet-vesting",
  "pallet-whitelist",
  "pallet-xcm",
diff --git a/Cargo.toml b/Cargo.toml
index c355679143037ae2b420ba416fc57371dc6b5943..36bb51390b39fc0f13c62a76d7a891274358b7be 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -379,6 +379,7 @@ members = [
 	"substrate/frame/membership",
 	"substrate/frame/merkle-mountain-range",
 	"substrate/frame/message-queue",
+	"substrate/frame/meta-tx",
 	"substrate/frame/metadata-hash-extension",
 	"substrate/frame/migrations",
 	"substrate/frame/mixnet",
@@ -962,6 +963,7 @@ pallet-insecure-randomness-collective-flip = { path = "substrate/frame/insecure-
 pallet-lottery = { default-features = false, path = "substrate/frame/lottery" }
 pallet-membership = { path = "substrate/frame/membership", default-features = false }
 pallet-message-queue = { path = "substrate/frame/message-queue", default-features = false }
+pallet-meta-tx = { path = "substrate/frame/meta-tx", default-features = false }
 pallet-migrations = { path = "substrate/frame/migrations", default-features = false }
 pallet-minimal-template = { path = "templates/minimal/pallets/template", default-features = false }
 pallet-mixnet = { default-features = false, path = "substrate/frame/mixnet" }
diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml
index 3317484419a9a2472da1b28f6dcf9ce1d04e0d45..43794cbee854498853b2a39fdccadaed30af9953 100644
--- a/polkadot/runtime/westend/Cargo.toml
+++ b/polkadot/runtime/westend/Cargo.toml
@@ -70,6 +70,7 @@ pallet-identity = { workspace = true }
 pallet-indices = { workspace = true }
 pallet-membership = { workspace = true }
 pallet-message-queue = { workspace = true }
+pallet-meta-tx = { workspace = true }
 pallet-migrations = { workspace = true }
 pallet-mmr = { workspace = true }
 pallet-multisig = { workspace = true }
@@ -94,6 +95,7 @@ pallet-transaction-payment = { workspace = true }
 pallet-transaction-payment-rpc-runtime-api = { workspace = true }
 pallet-treasury = { workspace = true }
 pallet-utility = { workspace = true }
+pallet-verify-signature = { workspace = true }
 pallet-vesting = { workspace = true }
 pallet-whitelist = { workspace = true }
 pallet-xcm = { workspace = true }
@@ -168,6 +170,7 @@ std = [
 	"pallet-indices/std",
 	"pallet-membership/std",
 	"pallet-message-queue/std",
+	"pallet-meta-tx/std",
 	"pallet-migrations/std",
 	"pallet-mmr/std",
 	"pallet-multisig/std",
@@ -195,6 +198,7 @@ std = [
 	"pallet-transaction-payment/std",
 	"pallet-treasury/std",
 	"pallet-utility/std",
+	"pallet-verify-signature/std",
 	"pallet-vesting/std",
 	"pallet-whitelist/std",
 	"pallet-xcm-benchmarks?/std",
@@ -257,6 +261,7 @@ runtime-benchmarks = [
 	"pallet-indices/runtime-benchmarks",
 	"pallet-membership/runtime-benchmarks",
 	"pallet-message-queue/runtime-benchmarks",
+	"pallet-meta-tx/runtime-benchmarks",
 	"pallet-migrations/runtime-benchmarks",
 	"pallet-mmr/runtime-benchmarks",
 	"pallet-multisig/runtime-benchmarks",
@@ -279,6 +284,7 @@ runtime-benchmarks = [
 	"pallet-transaction-payment/runtime-benchmarks",
 	"pallet-treasury/runtime-benchmarks",
 	"pallet-utility/runtime-benchmarks",
+	"pallet-verify-signature/runtime-benchmarks",
 	"pallet-vesting/runtime-benchmarks",
 	"pallet-whitelist/runtime-benchmarks",
 	"pallet-xcm-benchmarks/runtime-benchmarks",
@@ -319,6 +325,7 @@ try-runtime = [
 	"pallet-indices/try-runtime",
 	"pallet-membership/try-runtime",
 	"pallet-message-queue/try-runtime",
+	"pallet-meta-tx/try-runtime",
 	"pallet-migrations/try-runtime",
 	"pallet-mmr/try-runtime",
 	"pallet-multisig/try-runtime",
@@ -340,6 +347,7 @@ try-runtime = [
 	"pallet-transaction-payment/try-runtime",
 	"pallet-treasury/try-runtime",
 	"pallet-utility/try-runtime",
+	"pallet-verify-signature/try-runtime",
 	"pallet-vesting/try-runtime",
 	"pallet-whitelist/try-runtime",
 	"pallet-xcm/try-runtime",
diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index b5dc9b8f55cd1b43567405e45a368ed14cc3c445..bb758afdf12fbb18acdcf9df81bfb5ab565ab29f 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -104,7 +104,7 @@ use sp_runtime::{
 		OpaqueKeys, SaturatedConversion, Verify,
 	},
 	transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, FixedU128, KeyTypeId, Percent, Permill,
+	ApplyExtrinsicResult, FixedU128, KeyTypeId, MultiSignature, MultiSigner, Percent, Permill,
 };
 use sp_staking::SessionIndex;
 #[cfg(any(feature = "std", test))]
@@ -1616,6 +1616,35 @@ impl OnSwap for SwapLeases {
 	}
 }
 
+pub type MetaTxExtension = (
+	pallet_verify_signature::VerifySignature<Runtime>,
+	pallet_meta_tx::MetaTxMarker<Runtime>,
+	frame_system::CheckNonZeroSender<Runtime>,
+	frame_system::CheckSpecVersion<Runtime>,
+	frame_system::CheckTxVersion<Runtime>,
+	frame_system::CheckGenesis<Runtime>,
+	frame_system::CheckMortality<Runtime>,
+	frame_system::CheckNonce<Runtime>,
+	frame_metadata_hash_extension::CheckMetadataHash<Runtime>,
+);
+
+impl pallet_meta_tx::Config for Runtime {
+	type WeightInfo = weights::pallet_meta_tx::WeightInfo<Runtime>;
+	type RuntimeEvent = RuntimeEvent;
+	#[cfg(not(feature = "runtime-benchmarks"))]
+	type Extension = MetaTxExtension;
+	#[cfg(feature = "runtime-benchmarks")]
+	type Extension = pallet_meta_tx::WeightlessExtension<Runtime>;
+}
+
+impl pallet_verify_signature::Config for Runtime {
+	type Signature = MultiSignature;
+	type AccountIdentifier = MultiSigner;
+	type WeightInfo = weights::pallet_verify_signature::WeightInfo<Runtime>;
+	#[cfg(feature = "runtime-benchmarks")]
+	type BenchmarkHelper = ();
+}
+
 #[frame_support::runtime(legacy_ordering)]
 mod runtime {
 	#[runtime::runtime]
@@ -1809,6 +1838,12 @@ mod runtime {
 	#[runtime::pallet_index(102)]
 	pub type RootTesting = pallet_root_testing;
 
+	#[runtime::pallet_index(103)]
+	pub type MetaTx = pallet_meta_tx::Pallet<Runtime>;
+
+	#[runtime::pallet_index(104)]
+	pub type VerifySignature = pallet_verify_signature::Pallet<Runtime>;
+
 	// BEEFY Bridges support.
 	#[runtime::pallet_index(200)]
 	pub type Beefy = pallet_beefy;
@@ -1959,6 +1994,8 @@ mod benches {
 		[pallet_vesting, Vesting]
 		[pallet_whitelist, Whitelist]
 		[pallet_asset_rate, AssetRate]
+		[pallet_meta_tx, MetaTx]
+		[pallet_verify_signature, VerifySignature]
 		// XCM
 		[pallet_xcm, PalletXcmExtrinsicsBenchmark::<Runtime>]
 		// NOTE: Make sure you point to the individual modules below.
diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs
index efd18b38545a26e2bb0c829cff659ea2b04c0f72..2cebb9bc0d0a21fea288e6a52e6ed2f09de67d0c 100644
--- a/polkadot/runtime/westend/src/weights/mod.rs
+++ b/polkadot/runtime/westend/src/weights/mod.rs
@@ -28,6 +28,7 @@ pub mod pallet_fast_unstake;
 pub mod pallet_identity;
 pub mod pallet_indices;
 pub mod pallet_message_queue;
+pub mod pallet_meta_tx;
 pub mod pallet_migrations;
 pub mod pallet_mmr;
 pub mod pallet_multisig;
@@ -44,6 +45,7 @@ pub mod pallet_timestamp;
 pub mod pallet_transaction_payment;
 pub mod pallet_treasury;
 pub mod pallet_utility;
+pub mod pallet_verify_signature;
 pub mod pallet_vesting;
 pub mod pallet_whitelist;
 pub mod pallet_xcm;
diff --git a/polkadot/runtime/westend/src/weights/pallet_meta_tx.rs b/polkadot/runtime/westend/src/weights/pallet_meta_tx.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cf182ced3ce37e4eb3faea1e6c784d1ce27cc58c
--- /dev/null
+++ b/polkadot/runtime/westend/src/weights/pallet_meta_tx.rs
@@ -0,0 +1,57 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Autogenerated weights for `pallet_meta_tx`
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! HOSTNAME: `cob`, CPU: `<UNKNOWN>`
+//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
+
+// Executed Command:
+// ./target/debug/polkadot
+// benchmark
+// pallet
+// --chain=westend-dev
+// --steps=50
+// --repeat=2
+// --pallet=pallet-meta-tx
+// --extrinsic=*
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --output=./polkadot/runtime/westend/src/weights/
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(missing_docs)]
+
+use frame_support::{traits::Get, weights::Weight};
+use core::marker::PhantomData;
+
+/// Weight functions for `pallet_meta_tx`.
+pub struct WeightInfo<T>(PhantomData<T>);
+impl<T: frame_system::Config> pallet_meta_tx::WeightInfo for WeightInfo<T> {
+	fn bare_dispatch() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 138_000_000 picoseconds.
+		Weight::from_parts(140_000_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
+}
diff --git a/polkadot/runtime/westend/src/weights/pallet_verify_signature.rs b/polkadot/runtime/westend/src/weights/pallet_verify_signature.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8796f0a613daee78151797c182e1221f2722fb13
--- /dev/null
+++ b/polkadot/runtime/westend/src/weights/pallet_verify_signature.rs
@@ -0,0 +1,59 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Autogenerated weights for `pallet_verify_signature`
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2025-01-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! HOSTNAME: `runner-ys-ssygq-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
+
+// Executed Command:
+// target/production/polkadot
+// benchmark
+// pallet
+// --steps=50
+// --repeat=20
+// --extrinsic=*
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
+// --pallet=pallet_verify_signature
+// --chain=westend-dev
+// --header=./polkadot/file_header.txt
+// --output=./polkadot/runtime/westend/src/weights/
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(missing_docs)]
+
+use frame_support::{traits::Get, weights::Weight};
+use core::marker::PhantomData;
+
+/// Weight functions for `pallet_verify_signature`.
+pub struct WeightInfo<T>(PhantomData<T>);
+impl<T: frame_system::Config> pallet_verify_signature::WeightInfo for WeightInfo<T> {
+	fn verify_signature() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 42_915_000 picoseconds.
+		Weight::from_parts(43_522_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
+}
diff --git a/prdoc/pr_6428.prdoc b/prdoc/pr_6428.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..43391f8082600c8700af403ac93df0661e18d22c
--- /dev/null
+++ b/prdoc/pr_6428.prdoc
@@ -0,0 +1,32 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: "FRAME: Meta Transaction"
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      Introduces the meta-tx pallet that implements Meta Transactions.
+
+      The meta transaction follows a layout similar to that of a regular transaction and can
+      leverage the same extensions that implement the `TransactionExtension` trait. Once signed and
+      shared by the signer, it can be relayed by a relayer. The relayer then submits a regular
+      transaction with the `meta-tx::dispatch` call, passing the signed meta transaction as an
+      argument.
+
+      To see an example, refer to the mock setup and the `sign_and_execute_meta_tx` test case within
+      the pallet.
+
+crates:
+- name: pallet-meta-tx
+  bump: major
+- name: westend-runtime
+  bump: major
+- name: kitchensink-runtime
+  bump: major
+- name: polkadot-sdk
+  bump: major
+- name: pallet-verify-signature
+  bump: patch
+- name: pallet-example-authorization-tx-extension
+  bump: major
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 94729a26b6d55f2a17a8991925635f91b866a596..659651fe837e76ca2d7d9c697918b675762d231a 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -2377,28 +2377,12 @@ impl pallet_transaction_storage::Config for Runtime {
 		ConstU32<{ pallet_transaction_storage::DEFAULT_MAX_TRANSACTION_SIZE }>;
 }
 
-#[cfg(feature = "runtime-benchmarks")]
-pub struct VerifySignatureBenchmarkHelper;
-#[cfg(feature = "runtime-benchmarks")]
-impl pallet_verify_signature::BenchmarkHelper<MultiSignature, AccountId>
-	for VerifySignatureBenchmarkHelper
-{
-	fn create_signature(_entropy: &[u8], msg: &[u8]) -> (MultiSignature, AccountId) {
-		use sp_io::crypto::{sr25519_generate, sr25519_sign};
-		use sp_runtime::traits::IdentifyAccount;
-		let public = sr25519_generate(0.into(), None);
-		let who_account: AccountId = MultiSigner::Sr25519(public).into_account().into();
-		let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &public, msg).unwrap());
-		(signature, who_account)
-	}
-}
-
 impl pallet_verify_signature::Config for Runtime {
 	type Signature = MultiSignature;
 	type AccountIdentifier = MultiSigner;
 	type WeightInfo = pallet_verify_signature::weights::SubstrateWeight<Runtime>;
 	#[cfg(feature = "runtime-benchmarks")]
-	type BenchmarkHelper = VerifySignatureBenchmarkHelper;
+	type BenchmarkHelper = ();
 }
 
 impl pallet_whitelist::Config for Runtime {
@@ -2726,6 +2710,27 @@ impl pallet_parameters::Config for Runtime {
 	type WeightInfo = ();
 }
 
+pub type MetaTxExtension = (
+	pallet_verify_signature::VerifySignature<Runtime>,
+	pallet_meta_tx::MetaTxMarker<Runtime>,
+	frame_system::CheckNonZeroSender<Runtime>,
+	frame_system::CheckSpecVersion<Runtime>,
+	frame_system::CheckTxVersion<Runtime>,
+	frame_system::CheckGenesis<Runtime>,
+	frame_system::CheckEra<Runtime>,
+	frame_system::CheckNonce<Runtime>,
+	frame_metadata_hash_extension::CheckMetadataHash<Runtime>,
+);
+
+impl pallet_meta_tx::Config for Runtime {
+	type WeightInfo = ();
+	type RuntimeEvent = RuntimeEvent;
+	#[cfg(not(feature = "runtime-benchmarks"))]
+	type Extension = MetaTxExtension;
+	#[cfg(feature = "runtime-benchmarks")]
+	type Extension = pallet_meta_tx::WeightlessExtension<Runtime>;
+}
+
 #[frame_support::runtime]
 mod runtime {
 	use super::*;
@@ -3010,6 +3015,9 @@ mod runtime {
 	pub type MultiBlockUnsigned = pallet_election_provider_multi_block::unsigned::Pallet<Runtime>;
 	#[runtime::pallet_index(88)]
 	pub type MultiBlockSigned = pallet_election_provider_multi_block::signed::Pallet<Runtime>;
+
+	#[runtime::pallet_index(89)]
+	pub type MetaTx = pallet_meta_tx::Pallet<Runtime>;
 }
 
 impl TryFrom<RuntimeCall> for pallet_revive::Call<Runtime> {
@@ -3277,6 +3285,7 @@ mod benches {
 		[pallet_example_mbm, PalletExampleMbms]
 		[pallet_asset_conversion_ops, AssetConversionMigration]
 		[pallet_verify_signature, VerifySignature]
+		[pallet_meta_tx, MetaTx]
 	);
 }
 
diff --git a/substrate/frame/examples/authorization-tx-extension/src/mock.rs b/substrate/frame/examples/authorization-tx-extension/src/mock.rs
index a4a76fe207aa068e9ccd93db05252a3cad3b079a..9772e52050bd19b194d60e7d6bca141250aa460c 100644
--- a/substrate/frame/examples/authorization-tx-extension/src/mock.rs
+++ b/substrate/frame/examples/authorization-tx-extension/src/mock.rs
@@ -84,26 +84,12 @@ mod example_runtime {
 		type Lookup = IdentityLookup<Self::AccountId>;
 	}
 
-	#[cfg(feature = "runtime-benchmarks")]
-	pub struct BenchmarkHelper;
-	#[cfg(feature = "runtime-benchmarks")]
-	impl pallet_verify_signature::BenchmarkHelper<MultiSignature, AccountId> for BenchmarkHelper {
-		fn create_signature(_entropy: &[u8], msg: &[u8]) -> (MultiSignature, AccountId) {
-			use sp_io::crypto::{sr25519_generate, sr25519_sign};
-			use sp_runtime::traits::IdentifyAccount;
-			let public = sr25519_generate(0.into(), None);
-			let who_account: AccountId = MultiSigner::Sr25519(public).into_account().into();
-			let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &public, msg).unwrap());
-			(signature, who_account)
-		}
-	}
-
 	impl pallet_verify_signature::Config for Runtime {
 		type Signature = MultiSignature;
 		type AccountIdentifier = MultiSigner;
 		type WeightInfo = ();
 		#[cfg(feature = "runtime-benchmarks")]
-		type BenchmarkHelper = BenchmarkHelper;
+		type BenchmarkHelper = ();
 	}
 
 	/// Type that enables any pallet to ask for a coowner origin.
diff --git a/substrate/frame/meta-tx/Cargo.toml b/substrate/frame/meta-tx/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..78c18384d2fd2e993b84a15ff5609df7d2466f2a
--- /dev/null
+++ b/substrate/frame/meta-tx/Cargo.toml
@@ -0,0 +1,65 @@
+[package]
+name = "pallet-meta-tx"
+description = "FRAME pallet enabling meta transactions."
+license = "Apache-2.0"
+version = "0.1.0"
+edition.workspace = true
+authors.workspace = true
+homepage.workspace = true
+repository.workspace = true
+
+[lints]
+workspace = true
+
+[dependencies]
+codec = { workspace = true, features = ["max-encoded-len"] }
+docify = { workspace = true }
+scale-info = { workspace = true, features = ["derive"] }
+serde = { features = ["derive"], optional = true, workspace = true }
+
+frame-benchmarking = { workspace = true, optional = true }
+frame-support = { workspace = true }
+frame-system = { workspace = true }
+sp-core = { workspace = true }
+sp-io = { workspace = true }
+sp-runtime = { workspace = true }
+sp-std = { workspace = true }
+
+[dev-dependencies]
+pallet-balances = { workspace = true, default-features = true }
+pallet-transaction-payment = { workspace = true, default-features = true }
+pallet-verify-signature = { workspace = true, default-features = true }
+sp-keyring = { workspace = true, default-features = true }
+sp-keystore = { workspace = true, default-features = true }
+
+[features]
+default = ["std"]
+std = [
+	"codec/std",
+	"frame-benchmarking?/std",
+	"frame-support/std",
+	"frame-system/std",
+	"scale-info/std",
+	"serde?/std",
+	"sp-core/std",
+	"sp-io/std",
+	"sp-runtime/std",
+	"sp-std/std",
+]
+runtime-benchmarks = [
+	"frame-benchmarking/runtime-benchmarks",
+	"frame-support/runtime-benchmarks",
+	"frame-system/runtime-benchmarks",
+	"pallet-balances/runtime-benchmarks",
+	"pallet-transaction-payment/runtime-benchmarks",
+	"pallet-verify-signature/runtime-benchmarks",
+	"sp-runtime/runtime-benchmarks",
+]
+try-runtime = [
+	"frame-support/try-runtime",
+	"frame-system/try-runtime",
+	"pallet-balances/try-runtime",
+	"pallet-transaction-payment/try-runtime",
+	"pallet-verify-signature/try-runtime",
+	"sp-runtime/try-runtime",
+]
diff --git a/substrate/frame/meta-tx/src/benchmarking.rs b/substrate/frame/meta-tx/src/benchmarking.rs
new file mode 100644
index 0000000000000000000000000000000000000000..49dd1388031f933ac980f03bb0e9acfc57f878f7
--- /dev/null
+++ b/substrate/frame/meta-tx/src/benchmarking.rs
@@ -0,0 +1,130 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+#![cfg(feature = "runtime-benchmarks")]
+
+use super::*;
+use frame_benchmarking::v2::*;
+use frame_support::traits::UnfilteredDispatchable;
+use sp_runtime::impl_tx_ext_default;
+
+pub mod types {
+	use super::*;
+	use frame_support::traits::OriginTrait;
+	use sp_runtime::traits::DispatchInfoOf;
+
+	type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
+
+	/// A weightless extension to facilitate the bare dispatch benchmark.
+	#[derive(TypeInfo, Eq, PartialEq, Clone, Encode, Decode, DecodeWithMemTracking)]
+	#[scale_info(skip_type_params(T))]
+	pub struct WeightlessExtension<T>(core::marker::PhantomData<T>);
+	impl<T: Config + Send + Sync> core::fmt::Debug for WeightlessExtension<T> {
+		fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+			write!(f, "WeightlessExtension")
+		}
+	}
+	impl<T: Config + Send + Sync> Default for WeightlessExtension<T> {
+		fn default() -> Self {
+			WeightlessExtension(Default::default())
+		}
+	}
+	impl<T: Config + Send + Sync> TransactionExtension<CallOf<T>> for WeightlessExtension<T> {
+		const IDENTIFIER: &'static str = "WeightlessExtension";
+		type Implicit = ();
+		type Pre = ();
+		type Val = ();
+		fn weight(&self, _call: &CallOf<T>) -> Weight {
+			Weight::from_all(0)
+		}
+		fn validate(
+			&self,
+			mut origin: <CallOf<T> as Dispatchable>::RuntimeOrigin,
+			_: &CallOf<T>,
+			_: &DispatchInfoOf<CallOf<T>>,
+			_: usize,
+			_: (),
+			_: &impl Encode,
+			_: TransactionSource,
+		) -> Result<
+			(ValidTransaction, Self::Val, <CallOf<T> as Dispatchable>::RuntimeOrigin),
+			TransactionValidityError,
+		> {
+			origin.set_caller_from_signed(whitelisted_caller());
+			Ok((ValidTransaction::default(), (), origin))
+		}
+
+		impl_tx_ext_default!(CallOf<T>; prepare);
+	}
+}
+
+fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
+	frame_system::Pallet::<T>::assert_last_event(generic_event.into());
+}
+
+#[benchmarks(
+	where
+		T: Config,
+		<T as Config>::Extension: Default,
+	)]
+mod benchmarks {
+	use super::*;
+
+	#[benchmark]
+	fn bare_dispatch() {
+		let meta_call = frame_system::Call::<T>::remark { remark: vec![] }.into();
+		let meta_ext = T::Extension::default();
+		let meta_ext_weight = meta_ext.weight(&meta_call);
+
+		#[cfg(not(test))]
+		assert!(
+			meta_ext_weight.is_zero(),
+			"meta tx extension weight for the benchmarks must be zero. \
+			use `pallet_meta_tx::WeightlessExtension` as `pallet_meta_tx::Config::Extension` \
+			with the `runtime-benchmarks` feature enabled.",
+		);
+
+		let meta_tx = MetaTxFor::<T>::new(meta_call.clone(), 0u8, meta_ext.clone());
+
+		let caller = whitelisted_caller();
+		let origin: <T as frame_system::Config>::RuntimeOrigin =
+			frame_system::RawOrigin::Signed(caller).into();
+		let call = Call::<T>::dispatch { meta_tx: Box::new(meta_tx) };
+
+		#[block]
+		{
+			let _ = call.dispatch_bypass_filter(origin);
+		}
+
+		let info = meta_call.get_dispatch_info();
+		assert_last_event::<T>(
+			Event::Dispatched {
+				result: Ok(PostDispatchInfo {
+					actual_weight: Some(info.call_weight + meta_ext_weight),
+					pays_fee: Pays::Yes,
+				}),
+			}
+			.into(),
+		);
+	}
+
+	impl_benchmark_test_suite! {
+		Pallet,
+		crate::mock::new_test_ext(),
+		crate::mock::Runtime,
+	}
+}
diff --git a/substrate/frame/meta-tx/src/extension.rs b/substrate/frame/meta-tx/src/extension.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7c0f6c54d4902c25e562f46d7fd3d77092715327
--- /dev/null
+++ b/substrate/frame/meta-tx/src/extension.rs
@@ -0,0 +1,49 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+use super::*;
+use sp_runtime::impl_tx_ext_default;
+
+/// This type serves as a marker extension to differentiate meta-transactions from regular
+/// transactions. It implements the `TransactionExtension` trait and carries constant implicit data
+/// ("_meta_tx").
+#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo, DebugNoBound, DecodeWithMemTracking)]
+#[scale_info(skip_type_params(T))]
+pub struct MetaTxMarker<T> {
+	_phantom: core::marker::PhantomData<T>,
+}
+
+impl<T> MetaTxMarker<T> {
+	/// Creates new `TransactionExtension` with implicit meta tx marked.
+	pub fn new() -> Self {
+		Self { _phantom: Default::default() }
+	}
+}
+
+impl<T: Config + Send + Sync> TransactionExtension<T::RuntimeCall> for MetaTxMarker<T> {
+	const IDENTIFIER: &'static str = "MetaTxMarker";
+	type Implicit = [u8; 8];
+	type Val = ();
+	type Pre = ();
+	fn implicit(&self) -> Result<Self::Implicit, TransactionValidityError> {
+		Ok(*b"_meta_tx")
+	}
+	fn weight(&self, _: &T::RuntimeCall) -> Weight {
+		Weight::zero()
+	}
+	impl_tx_ext_default!(T::RuntimeCall; validate prepare);
+}
diff --git a/substrate/frame/meta-tx/src/lib.rs b/substrate/frame/meta-tx/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..25a38a5bb4f092d1738286d9ec99c01cc00362e1
--- /dev/null
+++ b/substrate/frame/meta-tx/src/lib.rs
@@ -0,0 +1,242 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+//! # Meta Tx (Meta Transaction) Pallet
+//!
+//! This pallet enables the dispatch of transactions that are authorized by one party (the signer)
+//! and executed by an untrusted third party (the relayer), who covers the transaction fees.
+//!
+//! ## Pallet API
+//!
+//! See the [`pallet`] module for more information about the interfaces this pallet exposes,
+//! including its configuration trait, dispatchables, storage items, events and errors.
+//!
+//! ## Overview
+//!
+//! The pallet provides a client-level API, typically not meant for direct use by end users.
+//! A meta transaction, constructed with the help of a wallet, contains a target call, necessary
+//! extensions, and the signer's signature. This transaction is then broadcast, and any interested
+//! relayer can pick it up and execute it. The relayer submits a regular transaction via the
+//! [`dispatch`](`Pallet::dispatch`) function, passing the meta transaction as an argument to
+//! execute the target call on behalf of the signer while covering the fees.
+//!
+//! ### Example
+#![doc = docify::embed!("src/tests.rs", sign_and_execute_meta_tx)]
+//!
+//! ## Low-Level / Implementation Details
+//!
+//! The structure of a meta transaction is identical to the
+//! [`General`](sp_runtime::generic::Preamble::General) transaction.
+//! It contains the target call along with a configurable set of extensions and its associated
+//! version. Typically, these extensions include type like
+//! `pallet_verify_signature::VerifySignature`, which provides the signer address
+//! and the signature of the payload, encompassing the call and the meta-transaction’s
+//! configurations, such as its mortality.  The extensions follow the same [`TransactionExtension`]
+//! contract, and common types such as [`frame_system::CheckGenesis`],
+//! [`frame_system::CheckMortality`], [`frame_system::CheckNonce`], etc., are applicable in the
+//! context of meta transactions. Check the `mock` setup for the example.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+mod benchmarking;
+#[cfg(test)]
+mod mock;
+#[cfg(all(test, not(feature = "runtime-benchmarks")))]
+mod tests;
+pub mod weights;
+#[cfg(feature = "runtime-benchmarks")]
+pub use benchmarking::types::WeightlessExtension;
+pub use pallet::*;
+pub use weights::WeightInfo;
+mod extension;
+pub use extension::MetaTxMarker;
+
+use core::ops::Add;
+use frame_support::{
+	dispatch::{DispatchInfo, GetDispatchInfo, PostDispatchInfo},
+	pallet_prelude::*,
+};
+use frame_system::{pallet_prelude::*, RawOrigin as SystemOrigin};
+use sp_runtime::{
+	generic::ExtensionVersion,
+	traits::{
+		AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable, TransactionExtension,
+	},
+};
+use sp_std::prelude::*;
+
+/// Meta Transaction type.
+///
+/// The data that is provided and signed by the signer and shared with the relayer.
+#[derive(Encode, Decode, PartialEq, Eq, TypeInfo, Clone, RuntimeDebug, DecodeWithMemTracking)]
+pub struct MetaTx<Call, Extension> {
+	/// The target call to be executed on behalf of the signer.
+	call: Call,
+	/// The extension version.
+	extension_version: ExtensionVersion,
+	/// The extension/s for the meta transaction.
+	extension: Extension,
+}
+
+impl<Call, Extension> MetaTx<Call, Extension> {
+	/// Create a new meta transaction.
+	pub fn new(call: Call, extension_version: ExtensionVersion, extension: Extension) -> Self {
+		Self { call, extension_version, extension }
+	}
+}
+
+/// The [`MetaTx`] for the given config.
+pub type MetaTxFor<T> = MetaTx<<T as frame_system::Config>::RuntimeCall, <T as Config>::Extension>;
+
+#[frame_support::pallet]
+pub mod pallet {
+	use super::*;
+
+	#[pallet::config]
+	pub trait Config:
+		frame_system::Config<
+		RuntimeCall: Dispatchable<
+			Info = DispatchInfo,
+			PostInfo = PostDispatchInfo,
+			RuntimeOrigin = <Self as frame_system::Config>::RuntimeOrigin,
+		>,
+		RuntimeOrigin: AsTransactionAuthorizedOrigin + From<SystemOrigin<Self::AccountId>>,
+	>
+	{
+		/// Weight information for calls in this pallet.
+		type WeightInfo: WeightInfo;
+		/// The overarching event type.
+		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+		/// Transaction extension/s for meta transactions.
+		///
+		/// The extensions that must be present in every meta transaction. This generally includes
+		/// extensions like `pallet_verify_signature::VerifySignature`,
+		/// [frame_system::CheckSpecVersion], [frame_system::CheckTxVersion],
+		/// [frame_system::CheckGenesis], [frame_system::CheckMortality],
+		/// [frame_system::CheckNonce], etc. Check the `mock` setup for the example.
+		///
+		/// The types implementing the [`TransactionExtension`] trait can be composed into a tuple
+		/// type that will implement the same trait by piping invocations through each type.
+		///
+		/// In the `runtime-benchmarks` environment the type must implement [`Default`] trait.
+		/// The extension must provide an origin and the extension's weight must be zero. Use
+		/// `pallet_meta_tx::WeightlessExtension` type when the `runtime-benchmarks` feature
+		/// enabled.
+		type Extension: TransactionExtension<<Self as frame_system::Config>::RuntimeCall>;
+	}
+
+	#[pallet::error]
+	pub enum Error<T> {
+		/// Invalid proof (e.g. signature).
+		BadProof,
+		/// The meta transaction is not yet valid (e.g. nonce too high).
+		Future,
+		/// The meta transaction is outdated (e.g. nonce too low).
+		Stale,
+		/// The meta transactions's birth block is ancient.
+		AncientBirthBlock,
+		/// The transaction extension did not authorize any origin.
+		UnknownOrigin,
+		/// The meta transaction is invalid.
+		Invalid,
+	}
+
+	#[pallet::event]
+	#[pallet::generate_deposit(pub(crate) fn deposit_event)]
+	pub enum Event<T: Config> {
+		/// A meta transaction has been dispatched.
+		///
+		/// Contains the dispatch result of the meta transaction along with post-dispatch
+		/// information.
+		Dispatched { result: DispatchResultWithPostInfo },
+	}
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(_);
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {
+		/// Dispatch a given meta transaction.
+		///
+		/// - `_origin`: Can be any kind of origin.
+		/// - `meta_tx`: Meta Transaction with a target call to be dispatched.
+		#[pallet::call_index(0)]
+		#[pallet::weight({
+			let dispatch_info = meta_tx.call.get_dispatch_info();
+			let extension_weight = meta_tx.extension.weight(&meta_tx.call);
+			let bare_call_weight = T::WeightInfo::bare_dispatch();
+			(
+				dispatch_info.call_weight.add(extension_weight).add(bare_call_weight),
+				dispatch_info.class,
+			)
+		})]
+		pub fn dispatch(
+			_origin: OriginFor<T>,
+			meta_tx: Box<MetaTxFor<T>>,
+		) -> DispatchResultWithPostInfo {
+			let origin = SystemOrigin::None;
+			let meta_tx_size = meta_tx.encoded_size();
+			// `info` with worst-case call weight and extension weight.
+			let info = {
+				let mut info = meta_tx.call.get_dispatch_info();
+				info.extension_weight = meta_tx.extension.weight(&meta_tx.call);
+				info
+			};
+
+			// dispatch the meta transaction.
+			let meta_dispatch_res = meta_tx
+				.extension
+				.dispatch_transaction(
+					origin.into(),
+					meta_tx.call,
+					&info,
+					meta_tx_size,
+					meta_tx.extension_version,
+				)
+				.map_err(Error::<T>::from)?;
+
+			Self::deposit_event(Event::Dispatched { result: meta_dispatch_res });
+
+			// meta weight after possible refunds.
+			let meta_weight = meta_dispatch_res
+				.map_or_else(|err| err.post_info.actual_weight, |info| info.actual_weight)
+				.unwrap_or(info.total_weight());
+
+			Ok((Some(T::WeightInfo::bare_dispatch().saturating_add(meta_weight)), true.into())
+				.into())
+		}
+	}
+
+	/// Implements [`From<TransactionValidityError>`] for [`Error`] by mapping the relevant error
+	/// variants.
+	impl<T> From<TransactionValidityError> for Error<T> {
+		fn from(err: TransactionValidityError) -> Self {
+			use TransactionValidityError::*;
+			match err {
+				Unknown(_) => Error::<T>::Invalid,
+				Invalid(err) => match err {
+					InvalidTransaction::BadProof => Error::<T>::BadProof,
+					InvalidTransaction::Future => Error::<T>::Future,
+					InvalidTransaction::Stale => Error::<T>::Stale,
+					InvalidTransaction::AncientBirthBlock => Error::<T>::AncientBirthBlock,
+					InvalidTransaction::UnknownOrigin => Error::<T>::UnknownOrigin,
+					_ => Error::<T>::Invalid,
+				},
+			}
+		}
+	}
+}
diff --git a/substrate/frame/meta-tx/src/mock.rs b/substrate/frame/meta-tx/src/mock.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c361fcceca181ad82c1c26b66886a46a9aa02075
--- /dev/null
+++ b/substrate/frame/meta-tx/src/mock.rs
@@ -0,0 +1,147 @@
+// This file is part of Substrate.
+// Copyright (C) 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.
+
+//! Mock setup for tests.
+
+#![cfg(any(test, feature = "runtime-benchmarks"))]
+
+use crate as pallet_meta_tx;
+use crate::*;
+use frame_support::{
+	construct_runtime, derive_impl,
+	weights::{FixedFee, NoFee},
+};
+use sp_core::ConstU8;
+use sp_keystore::{testing::MemoryKeystore, KeystoreExt};
+use sp_runtime::{
+	traits::{IdentifyAccount, IdentityLookup, Verify},
+	MultiSignature,
+};
+
+pub type Balance = u64;
+
+pub type Signature = MultiSignature;
+pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
+
+#[cfg(feature = "runtime-benchmarks")]
+pub type MetaTxExtension = crate::benchmarking::types::WeightlessExtension<Runtime>;
+
+#[cfg(not(feature = "runtime-benchmarks"))]
+pub use tx_ext::*;
+
+#[cfg(not(feature = "runtime-benchmarks"))]
+mod tx_ext {
+	use super::*;
+
+	pub type UncheckedExtrinsic =
+		sp_runtime::generic::UncheckedExtrinsic<AccountId, RuntimeCall, Signature, TxExtension>;
+
+	/// Transaction extension.
+	pub type TxExtension = (pallet_verify_signature::VerifySignature<Runtime>, TxBareExtension);
+
+	/// Transaction extension without signature information.
+	///
+	/// Helper type used to decode the part of the extension which should be signed.
+	pub type TxBareExtension = (
+		frame_system::CheckNonZeroSender<Runtime>,
+		frame_system::CheckSpecVersion<Runtime>,
+		frame_system::CheckTxVersion<Runtime>,
+		frame_system::CheckGenesis<Runtime>,
+		frame_system::CheckMortality<Runtime>,
+		frame_system::CheckNonce<Runtime>,
+		frame_system::CheckWeight<Runtime>,
+		pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
+	);
+
+	pub const META_EXTENSION_VERSION: ExtensionVersion = 0;
+
+	/// Meta transaction extension.
+	pub type MetaTxExtension =
+		(pallet_verify_signature::VerifySignature<Runtime>, MetaTxBareExtension);
+
+	/// Meta transaction extension without signature information.
+	///
+	/// Helper type used to decode the part of the extension which should be signed.
+	pub type MetaTxBareExtension = (
+		MetaTxMarker<Runtime>,
+		frame_system::CheckNonZeroSender<Runtime>,
+		frame_system::CheckSpecVersion<Runtime>,
+		frame_system::CheckTxVersion<Runtime>,
+		frame_system::CheckGenesis<Runtime>,
+		frame_system::CheckMortality<Runtime>,
+		frame_system::CheckNonce<Runtime>,
+	);
+}
+
+impl Config for Runtime {
+	type WeightInfo = ();
+	type RuntimeEvent = RuntimeEvent;
+	type Extension = MetaTxExtension;
+}
+
+impl pallet_verify_signature::Config for Runtime {
+	type Signature = MultiSignature;
+	type AccountIdentifier = <Signature as Verify>::Signer;
+	type WeightInfo = ();
+	#[cfg(feature = "runtime-benchmarks")]
+	type BenchmarkHelper = ();
+}
+
+#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
+impl frame_system::Config for Runtime {
+	type AccountId = AccountId;
+	type Lookup = IdentityLookup<Self::AccountId>;
+	type Block = frame_system::mocking::MockBlock<Runtime>;
+	type AccountData = pallet_balances::AccountData<<Self as pallet_balances::Config>::Balance>;
+}
+
+#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
+impl pallet_balances::Config for Runtime {
+	type ReserveIdentifier = [u8; 8];
+	type AccountStore = System;
+}
+
+pub const TX_FEE: u32 = 10;
+
+impl pallet_transaction_payment::Config for Runtime {
+	type WeightInfo = ();
+	type RuntimeEvent = RuntimeEvent;
+	type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter<Balances, ()>;
+	type OperationalFeeMultiplier = ConstU8<1>;
+	type WeightToFee = FixedFee<TX_FEE, Balance>;
+	type LengthToFee = NoFee<Balance>;
+	type FeeMultiplierUpdate = ();
+}
+
+construct_runtime!(
+	pub enum Runtime {
+		System: frame_system,
+		Balances: pallet_balances,
+		MetaTx: pallet_meta_tx,
+		TxPayment: pallet_transaction_payment,
+		VerifySignature: pallet_verify_signature,
+	}
+);
+
+pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
+	let mut ext = sp_io::TestExternalities::new(Default::default());
+	ext.execute_with(|| {
+		frame_system::GenesisConfig::<Runtime>::default().build();
+		System::set_block_number(1);
+	});
+	ext.register_extension(KeystoreExt::new(MemoryKeystore::new()));
+	ext
+}
diff --git a/substrate/frame/meta-tx/src/tests.rs b/substrate/frame/meta-tx/src/tests.rs
new file mode 100644
index 0000000000000000000000000000000000000000..bde1de2f6091bcfb2f5674e1f5ea572b3107529a
--- /dev/null
+++ b/substrate/frame/meta-tx/src/tests.rs
@@ -0,0 +1,398 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+use crate::*;
+use frame_support::traits::tokens::fungible::Inspect;
+use mock::*;
+use sp_io::hashing::blake2_256;
+use sp_keyring::Sr25519Keyring;
+use sp_runtime::{
+	generic::Era,
+	traits::{Applyable, Checkable, Hash, IdentityLookup},
+	DispatchErrorWithPostInfo, MultiSignature,
+};
+
+type VerifySignatureExt = pallet_verify_signature::VerifySignature<Runtime>;
+
+fn create_tx_bare_ext(account: AccountId) -> TxBareExtension {
+	(
+		frame_system::CheckNonZeroSender::<Runtime>::new(),
+		frame_system::CheckSpecVersion::<Runtime>::new(),
+		frame_system::CheckTxVersion::<Runtime>::new(),
+		frame_system::CheckGenesis::<Runtime>::new(),
+		frame_system::CheckMortality::<Runtime>::from(Era::immortal()),
+		frame_system::CheckNonce::<Runtime>::from(
+			frame_system::Pallet::<Runtime>::account(&account).nonce,
+		),
+		frame_system::CheckWeight::<Runtime>::new(),
+		pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0),
+	)
+}
+
+pub fn create_meta_tx_bare_ext(account: AccountId) -> MetaTxBareExtension {
+	(
+		MetaTxMarker::new(),
+		frame_system::CheckNonZeroSender::<Runtime>::new(),
+		frame_system::CheckSpecVersion::<Runtime>::new(),
+		frame_system::CheckTxVersion::<Runtime>::new(),
+		frame_system::CheckGenesis::<Runtime>::new(),
+		frame_system::CheckMortality::<Runtime>::from(Era::immortal()),
+		frame_system::CheckNonce::<Runtime>::from(
+			frame_system::Pallet::<Runtime>::account(&account).nonce,
+		),
+	)
+}
+
+fn create_signature<Call: Encode, Ext: Encode + TransactionExtension<RuntimeCall>>(
+	call: Call,
+	ext: Ext,
+	signer: Sr25519Keyring,
+) -> MultiSignature {
+	MultiSignature::Sr25519(
+		(META_EXTENSION_VERSION, call, ext.clone(), ext.implicit().unwrap())
+			.using_encoded(|e| signer.sign(&blake2_256(e))),
+	)
+}
+
+fn force_set_balance(account: AccountId) -> Balance {
+	let balance = Balances::minimum_balance() * 100;
+	Balances::force_set_balance(RuntimeOrigin::root(), account.into(), balance).unwrap();
+	balance
+}
+
+fn apply_extrinsic(uxt: UncheckedExtrinsic) -> DispatchResultWithPostInfo {
+	let uxt_info = uxt.get_dispatch_info();
+	let uxt_len = uxt.using_encoded(|e| e.len());
+	let xt = <UncheckedExtrinsic as Checkable<IdentityLookup<AccountId>>>::check(
+		uxt,
+		&Default::default(),
+	)
+	.unwrap();
+	xt.apply::<Runtime>(&uxt_info, uxt_len).unwrap()
+}
+
+#[docify::export]
+#[test]
+fn sign_and_execute_meta_tx() {
+	new_test_ext().execute_with(|| {
+		// meta tx signer
+		let alice_keyring = Sr25519Keyring::Alice;
+		// meta tx relayer
+		let bob_keyring = Sr25519Keyring::Bob;
+
+		let alice_account: AccountId = alice_keyring.public().into();
+		let bob_account: AccountId = bob_keyring.public().into();
+
+		let tx_fee: Balance = (2 * TX_FEE).into(); // base tx fee + weight fee
+		let alice_balance = force_set_balance(alice_account.clone());
+		let bob_balance = force_set_balance(bob_account.clone());
+
+		// Alice builds a meta transaction.
+
+		let remark_call =
+			RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] });
+		let meta_tx_bare_ext = create_meta_tx_bare_ext(alice_account.clone());
+		let meta_tx_sig =
+			create_signature(remark_call.clone(), meta_tx_bare_ext.clone(), alice_keyring);
+		let meta_tx_ext = (
+			VerifySignatureExt::new_with_signature(meta_tx_sig, alice_account.clone()),
+			// append signed part.
+			meta_tx_bare_ext,
+		);
+
+		let meta_tx = MetaTxFor::<Runtime>::new(
+			remark_call.clone(),
+			META_EXTENSION_VERSION,
+			meta_tx_ext.clone(),
+		);
+
+		// Encode and share with the world.
+		let meta_tx_encoded = meta_tx.encode();
+
+		// Bob acts as meta transaction relayer.
+
+		let meta_tx = MetaTxFor::<Runtime>::decode(&mut &meta_tx_encoded[..]).unwrap();
+		let call = RuntimeCall::MetaTx(Call::dispatch { meta_tx: Box::new(meta_tx.clone()) });
+		let tx_bare_ext = create_tx_bare_ext(bob_account.clone());
+		let tx_sig = create_signature(call.clone(), tx_bare_ext.clone(), bob_keyring);
+		let tx_ext = (
+			VerifySignatureExt::new_with_signature(tx_sig, bob_account.clone()),
+			// append signed part
+			tx_bare_ext,
+		);
+
+		let uxt = UncheckedExtrinsic::new_transaction(call.clone(), tx_ext.clone());
+
+		// Check Extrinsic validity and apply it.
+		let result = apply_extrinsic(uxt);
+
+		// Asserting the results and make sure the weight is correct.
+
+		let tx_weight = tx_ext.weight(&call) + <Runtime as Config>::WeightInfo::bare_dispatch();
+		let meta_tx_weight = remark_call
+			.get_dispatch_info()
+			.call_weight
+			.add(meta_tx_ext.weight(&remark_call));
+
+		assert_eq!(
+			result,
+			Ok(PostDispatchInfo {
+				actual_weight: Some(meta_tx_weight + tx_weight),
+				pays_fee: Pays::Yes,
+			})
+		);
+
+		System::assert_has_event(RuntimeEvent::MetaTx(crate::Event::Dispatched {
+			result: Ok(PostDispatchInfo {
+				actual_weight: Some(meta_tx_weight),
+				pays_fee: Pays::Yes,
+			}),
+		}));
+
+		System::assert_has_event(RuntimeEvent::System(frame_system::Event::Remarked {
+			sender: alice_account.clone(),
+			hash: <Runtime as frame_system::Config>::Hashing::hash(&[1]),
+		}));
+
+		// Alice balance is unchanged, Bob paid the transaction fee.
+		assert_eq!(alice_balance, Balances::free_balance(alice_account));
+		assert_eq!(bob_balance - tx_fee, Balances::free_balance(bob_account));
+	});
+}
+
+#[test]
+fn invalid_signature() {
+	new_test_ext().execute_with(|| {
+		// meta tx signer
+		let alice_keyring = Sr25519Keyring::Alice;
+		// meta tx relayer
+		let bob_keyring = Sr25519Keyring::Bob;
+
+		let alice_account: AccountId = alice_keyring.public().into();
+		let bob_account: AccountId = bob_keyring.public().into();
+
+		let tx_fee: Balance = (2 * TX_FEE).into(); // base tx fee + weight fee
+		let alice_balance = force_set_balance(alice_account.clone());
+		let bob_balance = force_set_balance(bob_account.clone());
+
+		// Alice builds a meta transaction.
+
+		let remark_call =
+			RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] });
+		let meta_tx_bare_ext = create_meta_tx_bare_ext(alice_account.clone());
+		// signature is invalid since it's signed by charlie instead of alice.
+		let invalid_meta_tx_sig = create_signature(
+			remark_call.clone(),
+			meta_tx_bare_ext.clone(),
+			Sr25519Keyring::Charlie,
+		);
+		let meta_tx_ext = (
+			VerifySignatureExt::new_with_signature(invalid_meta_tx_sig, alice_account.clone()),
+			// append signed part.
+			meta_tx_bare_ext,
+		);
+
+		let meta_tx = MetaTxFor::<Runtime>::new(
+			remark_call.clone(),
+			META_EXTENSION_VERSION,
+			meta_tx_ext.clone(),
+		);
+
+		// Encode and share with the world.
+		let meta_tx_encoded = meta_tx.encode();
+
+		// Bob acts as meta transaction relayer.
+
+		let meta_tx = MetaTxFor::<Runtime>::decode(&mut &meta_tx_encoded[..]).unwrap();
+		let call = RuntimeCall::MetaTx(Call::dispatch { meta_tx: Box::new(meta_tx.clone()) });
+		let tx_bare_ext = create_tx_bare_ext(bob_account.clone());
+		let tx_sig = create_signature(call.clone(), tx_bare_ext.clone(), bob_keyring);
+		let tx_ext = (
+			VerifySignatureExt::new_with_signature(tx_sig, bob_account.clone()),
+			// append signed part
+			tx_bare_ext,
+		);
+
+		let uxt = UncheckedExtrinsic::new_transaction(call, tx_ext);
+
+		// Check Extrinsic validity and apply it.
+		let result = apply_extrinsic(uxt);
+
+		// Asserting the results.
+
+		assert_eq!(result.unwrap_err().error, Error::<Runtime>::BadProof.into());
+
+		// Alice balance is unchanged, Bob paid the transaction fee.
+		assert_eq!(alice_balance, Balances::free_balance(alice_account));
+		assert_eq!(bob_balance - tx_fee, Balances::free_balance(bob_account));
+	});
+}
+
+#[cfg(not(feature = "runtime-benchmarks"))]
+#[test]
+fn meta_tx_extension_work() {
+	new_test_ext().execute_with(|| {
+		// meta tx signer
+		let alice_keyring = Sr25519Keyring::Alice;
+		// meta tx relayer
+		let bob_keyring = Sr25519Keyring::Bob;
+
+		let alice_account: AccountId = alice_keyring.public().into();
+		let bob_account: AccountId = bob_keyring.public().into();
+
+		let tx_fee: Balance = (2 * TX_FEE).into(); // base tx fee + weight fee
+		let alice_balance = force_set_balance(alice_account.clone());
+		let bob_balance = force_set_balance(bob_account.clone());
+
+		// Alice builds a meta transaction.
+
+		let remark_call =
+			RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] });
+
+		let meta_tx_bare_ext = create_meta_tx_bare_ext(alice_account.clone());
+		let meta_tx_sig =
+			create_signature(remark_call.clone(), meta_tx_bare_ext.clone(), alice_keyring);
+		let meta_tx_ext = (
+			VerifySignatureExt::new_with_signature(meta_tx_sig, alice_account.clone()),
+			// append signed part.
+			meta_tx_bare_ext,
+		);
+
+		let meta_tx = MetaTxFor::<Runtime>::new(remark_call, META_EXTENSION_VERSION, meta_tx_ext);
+
+		// Encode and share with the world.
+		let meta_tx_encoded = meta_tx.encode();
+
+		// Bob acts as meta transaction relayer.
+
+		let meta_tx = MetaTxFor::<Runtime>::decode(&mut &meta_tx_encoded[..]).unwrap();
+		let call = RuntimeCall::MetaTx(Call::dispatch { meta_tx: Box::new(meta_tx.clone()) });
+		let tx_bare_ext = create_tx_bare_ext(bob_account.clone());
+		let tx_sig = create_signature(call.clone(), tx_bare_ext.clone(), bob_keyring);
+		let tx_ext = (
+			VerifySignatureExt::new_with_signature(tx_sig, bob_account.clone()),
+			// append signed part
+			tx_bare_ext,
+		);
+
+		let uxt = UncheckedExtrinsic::new_transaction(call, tx_ext);
+
+		// increment alice's nonce to invalidate the meta tx and verify that the
+		// meta tx extension works.
+		frame_system::Pallet::<Runtime>::inc_account_nonce(alice_account.clone());
+
+		// Check Extrinsic validity and apply it.
+		let result = apply_extrinsic(uxt);
+
+		// Asserting the results.
+		assert_eq!(result.unwrap_err().error, Error::<Runtime>::Stale.into());
+
+		// Alice balance is unchanged, Bob paid the transaction fee.
+		assert_eq!(alice_balance, Balances::free_balance(alice_account));
+		assert_eq!(bob_balance - tx_fee, Balances::free_balance(bob_account));
+	});
+}
+
+#[test]
+fn meta_tx_call_fails() {
+	new_test_ext().execute_with(|| {
+		// meta tx signer
+		let alice_keyring = Sr25519Keyring::Alice;
+		// meta tx relayer
+		let bob_keyring = Sr25519Keyring::Bob;
+
+		let alice_account: AccountId = alice_keyring.public().into();
+		let bob_account: AccountId = bob_keyring.public().into();
+
+		let tx_fee: Balance = (2 * TX_FEE).into(); // base tx fee + weight fee
+		let alice_balance = force_set_balance(alice_account.clone());
+		let bob_balance = force_set_balance(bob_account.clone());
+
+		// Alice builds a meta transaction.
+
+		// transfer more than alice has
+		let transfer_call = RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death {
+			dest: bob_account.clone(),
+			value: alice_balance * 2,
+		});
+
+		let meta_tx_bare_ext = create_meta_tx_bare_ext(alice_account.clone());
+		let meta_tx_sig =
+			create_signature(transfer_call.clone(), meta_tx_bare_ext.clone(), alice_keyring);
+		let meta_tx_ext = (
+			VerifySignatureExt::new_with_signature(meta_tx_sig, alice_account.clone()),
+			// append signed part.
+			meta_tx_bare_ext,
+		);
+
+		let meta_tx = MetaTxFor::<Runtime>::new(
+			transfer_call.clone(),
+			META_EXTENSION_VERSION,
+			meta_tx_ext.clone(),
+		);
+
+		// Encode and share with the world.
+		let meta_tx_encoded = meta_tx.encode();
+
+		// Bob acts as meta transaction relayer.
+
+		let meta_tx = MetaTxFor::<Runtime>::decode(&mut &meta_tx_encoded[..]).unwrap();
+		let call = RuntimeCall::MetaTx(Call::dispatch { meta_tx: Box::new(meta_tx.clone()) });
+		let tx_bare_ext = create_tx_bare_ext(bob_account.clone());
+		let tx_sig = create_signature(call.clone(), tx_bare_ext.clone(), bob_keyring);
+		let tx_ext = (
+			VerifySignatureExt::new_with_signature(tx_sig, bob_account.clone()),
+			// append signed part
+			tx_bare_ext,
+		);
+
+		let uxt = UncheckedExtrinsic::new_transaction(call.clone(), tx_ext.clone());
+
+		// Check Extrinsic validity and apply it.
+		let result = apply_extrinsic(uxt);
+
+		// Asserting the results and make sure the weight is correct.
+
+		let tx_weight = tx_ext.weight(&call) + <Runtime as Config>::WeightInfo::bare_dispatch();
+		let meta_tx_weight = transfer_call
+			.get_dispatch_info()
+			.call_weight
+			.add(meta_tx_ext.weight(&transfer_call));
+
+		assert_eq!(
+			result,
+			Ok(PostDispatchInfo {
+				actual_weight: Some(meta_tx_weight + tx_weight),
+				pays_fee: Pays::Yes,
+			})
+		);
+
+		System::assert_has_event(RuntimeEvent::MetaTx(crate::Event::Dispatched {
+			result: Err(DispatchErrorWithPostInfo {
+				post_info: PostDispatchInfo {
+					actual_weight: Some(meta_tx_weight),
+					pays_fee: Pays::Yes,
+				},
+				error: sp_runtime::DispatchError::Token(sp_runtime::TokenError::FundsUnavailable),
+			}),
+		}));
+
+		// Alice balance is unchanged, Bob paid the transaction fee.
+		assert_eq!(alice_balance, Balances::free_balance(alice_account));
+		assert_eq!(bob_balance - tx_fee, Balances::free_balance(bob_account));
+	});
+}
diff --git a/substrate/frame/meta-tx/src/weights.rs b/substrate/frame/meta-tx/src/weights.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fdc13d115941bcac4e2b1e8560891394d0be70b3
--- /dev/null
+++ b/substrate/frame/meta-tx/src/weights.rs
@@ -0,0 +1,86 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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_meta_tx`
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2025-01-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! HOSTNAME: `runner-ys-ssygq-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
+
+// Executed Command:
+// target/production/substrate-node
+// benchmark
+// pallet
+// --steps=50
+// --repeat=20
+// --extrinsic=*
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
+// --pallet=pallet_meta_tx
+// --chain=dev
+// --header=./substrate/HEADER-APACHE2
+// --output=./substrate/frame/meta-tx/src/weights.rs
+// --template=./substrate/.maintain/frame-weight-template.hbs
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(missing_docs)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use core::marker::PhantomData;
+
+/// Weight functions needed for `pallet_meta_tx`.
+pub trait WeightInfo {
+	fn bare_dispatch() -> Weight;
+}
+
+/// Weights for `pallet_meta_tx` using the Substrate node and recommended hardware.
+pub struct SubstrateWeight<T>(PhantomData<T>);
+impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
+	/// Storage: `SafeMode::EnteredUntil` (r:1 w:0)
+	/// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	/// Storage: `TxPause::PausedCalls` (r:1 w:0)
+	/// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`)
+	fn bare_dispatch() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `145`
+		//  Estimated: `3997`
+		// Minimum execution time: 13_110_000 picoseconds.
+		Weight::from_parts(13_605_000, 3997)
+			.saturating_add(T::DbWeight::get().reads(2_u64))
+	}
+}
+
+// For backwards compatibility and tests.
+impl WeightInfo for () {
+	/// Storage: `SafeMode::EnteredUntil` (r:1 w:0)
+	/// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	/// Storage: `TxPause::PausedCalls` (r:1 w:0)
+	/// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`)
+	fn bare_dispatch() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `145`
+		//  Estimated: `3997`
+		// Minimum execution time: 13_110_000 picoseconds.
+		Weight::from_parts(13_605_000, 3997)
+			.saturating_add(RocksDbWeight::get().reads(2_u64))
+	}
+}
diff --git a/substrate/frame/verify-signature/src/benchmarking.rs b/substrate/frame/verify-signature/src/benchmarking.rs
index 99e893e6f6aba228dd9564403d59b84acf0013d7..42c08c8888d47beb9d72d05ab53dfe0f22f2f0c6 100644
--- a/substrate/frame/verify-signature/src/benchmarking.rs
+++ b/substrate/frame/verify-signature/src/benchmarking.rs
@@ -32,16 +32,29 @@ use frame_support::{
 	pallet_prelude::TransactionSource,
 };
 use frame_system::{Call as SystemCall, RawOrigin};
-use sp_io::hashing::blake2_256;
+use sp_io::{
+	crypto::{sr25519_generate, sr25519_sign},
+	hashing::blake2_256,
+};
 use sp_runtime::{
 	generic::ExtensionVersion,
-	traits::{AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable},
+	traits::{AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable, IdentifyAccount},
+	AccountId32, MultiSignature, MultiSigner,
 };
 
 pub trait BenchmarkHelper<Signature, Signer> {
 	fn create_signature(entropy: &[u8], msg: &[u8]) -> (Signature, Signer);
 }
 
+impl BenchmarkHelper<MultiSignature, AccountId32> for () {
+	fn create_signature(_entropy: &[u8], msg: &[u8]) -> (MultiSignature, AccountId32) {
+		let public = sr25519_generate(0.into(), None);
+		let who_account: AccountId32 = MultiSigner::Sr25519(public).into_account().into();
+		let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &public, msg).unwrap());
+		(signature, who_account)
+	}
+}
+
 #[benchmarks(where
 	T: Config + Send + Sync,
 	T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml
index a1998e7bf2abd4eb8c743164dfd1f90e394003a1..98c30fd490dee01d3f6d168ba92693838dc97f2f 100644
--- a/umbrella/Cargo.toml
+++ b/umbrella/Cargo.toml
@@ -102,6 +102,7 @@ std = [
 	"pallet-lottery?/std",
 	"pallet-membership?/std",
 	"pallet-message-queue?/std",
+	"pallet-meta-tx?/std",
 	"pallet-migrations?/std",
 	"pallet-mixnet?/std",
 	"pallet-mmr?/std",
@@ -299,6 +300,7 @@ runtime-benchmarks = [
 	"pallet-lottery?/runtime-benchmarks",
 	"pallet-membership?/runtime-benchmarks",
 	"pallet-message-queue?/runtime-benchmarks",
+	"pallet-meta-tx?/runtime-benchmarks",
 	"pallet-migrations?/runtime-benchmarks",
 	"pallet-mmr?/runtime-benchmarks",
 	"pallet-multisig?/runtime-benchmarks",
@@ -439,6 +441,7 @@ try-runtime = [
 	"pallet-lottery?/try-runtime",
 	"pallet-membership?/try-runtime",
 	"pallet-message-queue?/try-runtime",
+	"pallet-meta-tx?/try-runtime",
 	"pallet-migrations?/try-runtime",
 	"pallet-mixnet?/try-runtime",
 	"pallet-mmr?/try-runtime",
@@ -511,6 +514,7 @@ serde = [
 	"pallet-conviction-voting?/serde",
 	"pallet-democracy?/serde",
 	"pallet-message-queue?/serde",
+	"pallet-meta-tx?/serde",
 	"pallet-offences?/serde",
 	"pallet-parameters?/serde",
 	"pallet-referenda?/serde",
@@ -654,6 +658,7 @@ runtime-full = [
 	"pallet-lottery",
 	"pallet-membership",
 	"pallet-message-queue",
+	"pallet-meta-tx",
 	"pallet-migrations",
 	"pallet-mixnet",
 	"pallet-mmr",
@@ -1500,6 +1505,11 @@ default-features = false
 optional = true
 path = "../substrate/frame/message-queue"
 
+[dependencies.pallet-meta-tx]
+default-features = false
+optional = true
+path = "../substrate/frame/meta-tx"
+
 [dependencies.pallet-migrations]
 default-features = false
 optional = true
diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs
index 19f80aac4a451d4d36cd0c58e7c91870fb80e625..26e8d8b5acc16c23e80d1a40d5d103b69701b05f 100644
--- a/umbrella/src/lib.rs
+++ b/umbrella/src/lib.rs
@@ -503,6 +503,10 @@ pub use pallet_membership;
 #[cfg(feature = "pallet-message-queue")]
 pub use pallet_message_queue;
 
+/// FRAME pallet enabling meta transactions.
+#[cfg(feature = "pallet-meta-tx")]
+pub use pallet_meta_tx;
+
 /// FRAME pallet to execute multi-block migrations.
 #[cfg(feature = "pallet-migrations")]
 pub use pallet_migrations;