diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 4e1b6d4e8bec03f365b93c0723ff67122747c844..87ec467dca934bee0923e123c9f04266e471ebfb 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -1265,6 +1265,7 @@ impl pallet_contracts::Config for Runtime {
 	type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
 	#[cfg(feature = "unsafe-debug")]
 	type Debug = ();
+	type Environment = ();
 }
 
 impl pallet_sudo::Config for Runtime {
diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs
index a511ac81a73b731e0f72602efebd228419211f10..c6a43779ada2354853bf3c273742bfc35a6652c7 100644
--- a/substrate/frame/contracts/src/lib.rs
+++ b/substrate/frame/contracts/src/lib.rs
@@ -103,7 +103,7 @@ pub mod weights;
 #[cfg(test)]
 mod tests;
 use crate::{
-	exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Key, Stack as ExecStack},
+	exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Key, MomentOf, Stack as ExecStack},
 	gas::GasMeter,
 	storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager},
 	wasm::{CodeInfo, WasmBlob},
@@ -122,9 +122,13 @@ use frame_support::{
 		ConstU32, Contains, Get, Randomness, Time,
 	},
 	weights::Weight,
-	BoundedVec, RuntimeDebug, RuntimeDebugNoBound,
+	BoundedVec, DefaultNoBound, RuntimeDebug, RuntimeDebugNoBound,
+};
+use frame_system::{
+	ensure_signed,
+	pallet_prelude::{BlockNumberFor, OriginFor},
+	EventRecord, Pallet as System,
 };
-use frame_system::{ensure_signed, pallet_prelude::OriginFor, EventRecord, Pallet as System};
 use pallet_contracts_primitives::{
 	Code, CodeUploadResult, CodeUploadReturnValue, ContractAccessError, ContractExecResult,
 	ContractInstantiateResult, ContractResult, ExecReturnValue, GetStorageResult,
@@ -179,6 +183,36 @@ const SENTINEL: u32 = u32::MAX;
 /// Example: `RUST_LOG=runtime::contracts=debug my_code --dev`
 const LOG_TARGET: &str = "runtime::contracts";
 
+/// Wrapper around `PhantomData` to prevent it being filtered by `scale-info`.
+///
+/// `scale-info` filters out `PhantomData` fields because usually we are only interested
+/// in sized types. However, when trying to communicate **types** as opposed to **values**
+/// we want to have those zero sized types be included.
+#[derive(Encode, Decode, DefaultNoBound, TypeInfo)]
+#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
+pub struct EnvironmentType<T>(PhantomData<T>);
+
+/// List of all runtime configurable types that are used in the communication between
+/// `pallet-contracts` and any given contract.
+///
+/// Since those types are configurable they can vary between
+/// chains all using `pallet-contracts`. Hence we need a mechanism to communicate those types
+/// in a way that can be consumed by offchain tooling.
+///
+/// This type only exists in order to appear in the metadata where it can be read by
+/// offchain tooling.
+#[derive(Encode, Decode, DefaultNoBound, TypeInfo)]
+#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
+#[scale_info(skip_type_params(T))]
+pub struct Environment<T: Config> {
+	account_id: EnvironmentType<AccountIdOf<T>>,
+	balance: EnvironmentType<BalanceOf<T>>,
+	hash: EnvironmentType<<T as frame_system::Config>::Hash>,
+	hasher: EnvironmentType<<T as frame_system::Config>::Hashing>,
+	timestamp: EnvironmentType<MomentOf<T>>,
+	block_number: EnvironmentType<BlockNumberFor<T>>,
+}
+
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
@@ -360,6 +394,13 @@ pub mod pallet {
 		/// Do **not** use it in a production environment or for benchmarking purposes.
 		#[cfg(feature = "unsafe-debug")]
 		type Debug: unsafe_debug::UnsafeDebug<Self>;
+
+		/// Type that bundles together all the runtime configurable interface types.
+		///
+		/// This is not a real config. We just mention the type here as constant so that
+		/// its type appears in the metadata. Only valid value is `()`.
+		#[pallet::constant]
+		type Environment: Get<Environment<Self>>;
 	}
 
 	#[pallet::hooks]
diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs
index 5c8fca43ab746b1eb02f0c3fe48e3a067251a329..b421bbf3e30937fca8947a9f29ef31a49edbff08 100644
--- a/substrate/frame/contracts/src/tests.rs
+++ b/substrate/frame/contracts/src/tests.rs
@@ -481,6 +481,7 @@ impl Config for Test {
 	type MaxDelegateDependencies = MaxDelegateDependencies;
 	#[cfg(feature = "unsafe-debug")]
 	type Debug = unsafe_debug::TestDebugger;
+	type Environment = ();
 }
 
 pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]);