diff --git a/Cargo.lock b/Cargo.lock
index e2b6bba2a56bdd125475db9f94084b56e52c89d6..8d2c3d8ceddaddf008d626ab7f5f3d342c853168 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -819,6 +819,8 @@ dependencies = [
  "pallet-babe",
  "pallet-balances",
  "pallet-certification",
+ "pallet-distance",
+ "pallet-distance-rpc-runtime-api",
  "pallet-duniter-account",
  "pallet-duniter-wot",
  "pallet-grandpa",
@@ -1472,6 +1474,8 @@ dependencies = [
  "maplit",
  "memmap2 0.5.0",
  "pallet-certification",
+ "pallet-distance-rpc",
+ "pallet-distance-rpc-runtime-api",
  "pallet-grandpa",
  "pallet-transaction-payment-rpc",
  "pallet-transaction-payment-rpc-runtime-api",
@@ -2419,6 +2423,8 @@ dependencies = [
  "pallet-balances",
  "pallet-certification",
  "pallet-collective",
+ "pallet-distance",
+ "pallet-distance-rpc-runtime-api",
  "pallet-duniter-account",
  "pallet-duniter-test-parameters",
  "pallet-duniter-wot",
@@ -2905,13 +2911,13 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "0.2.4"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
+checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
 dependencies = [
  "bytes",
  "fnv",
- "itoa 0.4.7",
+ "itoa 1.0.1",
 ]
 
 [[package]]
@@ -5028,6 +5034,55 @@ dependencies = [
  "sp-std",
 ]
 
+[[package]]
+name = "pallet-distance"
+version = "1.0.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-authority-members",
+ "pallet-certification",
+ "pallet-identity",
+ "pallet-membership",
+ "pallet-session",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-distance-rpc"
+version = "1.0.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "jsonrpsee 0.14.0",
+ "pallet-distance-rpc-runtime-api",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-api",
+ "sp-blockchain",
+ "sp-core",
+ "sp-rpc",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-distance-rpc-runtime-api"
+version = "1.0.0"
+dependencies = [
+ "frame-support",
+ "pallet-distance",
+ "parity-scale-codec",
+ "sp-api",
+ "sp-runtime",
+]
+
 [[package]]
 name = "pallet-duniter-account"
 version = "3.0.0"
@@ -9374,9 +9429,9 @@ version = "1.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "digest 0.10.3",
- "rand 0.7.3",
+ "rand 0.8.4",
  "static_assertions",
 ]
 
diff --git a/Cargo.toml b/Cargo.toml
index 16e11ef4537fe2323835a5ff30f6225e77070f4e..209751d76706e71b505a8f0b5b933fd41bdc04d8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -59,6 +59,8 @@ g1-runtime = { path = 'runtime/g1', optional = true }
 gdev-runtime = { path = 'runtime/gdev', optional = true }
 gtest-runtime = { path = 'runtime/gtest', optional = true }
 pallet-certification = { path = 'pallets/certification' }
+pallet-distance-rpc = { path = 'pallets/distance/rpc' }
+pallet-distance-rpc-runtime-api = { path = 'pallets/distance/rpc/runtime-api' }
 sp-membership = { path = 'primitives/membership' }
 
 # crates.io dependencies
@@ -128,6 +130,9 @@ members = [
     'end2end-tests',
     'live-tests',
     'pallets/certification',
+	'pallets/distance',
+	'pallets/distance/rpc',
+	'pallets/distance/rpc/runtime-api',
     'pallets/duniter-test-parameters',
     'pallets/duniter-test-parameters/macro',
     'pallets/duniter-wot',
diff --git a/node/src/rpc.rs b/node/src/rpc.rs
index 36dee008a8e037c36cd0b4430a120189b878fb2d..492f59fc048d893b2db2ec82768fce04ff136687 100644
--- a/node/src/rpc.rs
+++ b/node/src/rpc.rs
@@ -56,6 +56,7 @@ where
     C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
     C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
     C::Api: BlockBuilder<Block>,
+    //C::Api: pallet_distance_runtime_api::DistanceApi<Block>,
     P: TransactionPool + 'static,
 {
     use manual_seal::rpc::{ManualSeal, ManualSealApiServer};
@@ -83,6 +84,9 @@ where
     // `YourRpcStruct` should have a reference to a client, which is needed
     // to call into the runtime.
     // `module.merge(YourRpcTrait::into_rpc(YourRpcStruct::new(ReferenceToClient, ...)))?;`
+    /*module.merge(pallet_distance_rpc::DistanceApi::into_rpc(
+        pallet_distance_rpc::Distance::new(client),
+    ))?;*/
 
     Ok(module)
 }
diff --git a/pallets/authority-members/src/lib.rs b/pallets/authority-members/src/lib.rs
index 941a0af7d56e1f4be886df51bc7905436b93f900..2d052c75fadd1882893c14e2ea393b7a0ff6474f 100644
--- a/pallets/authority-members/src/lib.rs
+++ b/pallets/authority-members/src/lib.rs
@@ -29,13 +29,13 @@ mod tests;
 /*#[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;*/
 
+pub use self::traits::*;
 pub use pallet::*;
+pub use sp_staking::SessionIndex;
 pub use types::*;
 
-use self::traits::*;
 use frame_support::traits::Get;
 use sp_runtime::traits::Convert;
-use sp_staking::SessionIndex;
 use sp_std::prelude::*;
 
 #[frame_support::pallet]
diff --git a/pallets/distance/Cargo.toml b/pallets/distance/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..75ae1ef9a7210ca44ea7f12be96fe100d707168f
--- /dev/null
+++ b/pallets/distance/Cargo.toml
@@ -0,0 +1,78 @@
+[package]
+authors = ['tuxmain <tuxmain@zettascript.org>']
+description = 'FRAME pallet distance.'
+edition = '2021'
+homepage = 'https://duniter.org'
+license = 'AGPL-3.0'
+name = 'pallet-distance'
+readme = 'README.md'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '1.0.0'
+
+[features]
+default = ['std']
+std = [
+    'codec/std',
+    'frame-support/std',
+    'frame-system/std',
+    'pallet-session/std',
+    'sp-core/std',
+    'sp-runtime/std',
+    'sp-std/std',
+]
+
+[dependencies]
+
+pallet-authority-members = { path = "../authority-members", default-features = false }
+pallet-certification = { path = "../certification", default-features = false }
+pallet-identity = { path = "../identity", default-features = false }
+pallet-membership = { path = "../membership", default-features = false }
+
+# substrate
+scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+
+[dependencies.codec]
+default-features = false
+features = ['derive']
+package = 'parity-scale-codec'
+version = '3.1.5'
+
+[dependencies.frame-support]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.frame-system]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.pallet-session]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-core]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-inherents]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
diff --git a/pallets/distance/rpc/Cargo.toml b/pallets/distance/rpc/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..85baca4ba8c24d9480287dff80b015ffde7b2fa2
--- /dev/null
+++ b/pallets/distance/rpc/Cargo.toml
@@ -0,0 +1,71 @@
+[package]
+authors = ['tuxmain <tuxmain@zettascript.org>']
+description = 'FRAME pallet distance RPC.'
+edition = '2018'
+homepage = 'https://substrate.dev'
+license = 'AGPL-3.0'
+name = 'pallet-distance-rpc'
+readme = 'README.md'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '1.0.0'
+
+[dependencies]
+
+pallet-distance-rpc-runtime-api = { path = "./runtime-api" }
+
+serde = { version = "1.0", features = ["derive"] }
+
+# substrate
+jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+
+[dependencies.codec]
+default-features = false
+features = ['derive']
+package = 'parity-scale-codec'
+version = '3.1.5'
+
+[dependencies.frame-support]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.frame-system]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-api]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-blockchain]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-core]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-rpc]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
diff --git a/pallets/distance/rpc/runtime-api/Cargo.toml b/pallets/distance/rpc/runtime-api/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..d7f2c41ba2522e5f9cd33328d035391ef41f46ee
--- /dev/null
+++ b/pallets/distance/rpc/runtime-api/Cargo.toml
@@ -0,0 +1,32 @@
+[package]
+authors = ['tuxmain <tuxmain@zettascript.org>']
+description = 'FRAME pallet distance RPC runtime API.'
+edition = '2018'
+homepage = 'https://substrate.dev'
+license = 'AGPL-3.0'
+name = 'pallet-distance-rpc-runtime-api'
+readme = 'README.md'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '1.0.0'
+
+[dependencies]
+pallet-distance = { path = "../../", default-features = false }
+sp-api = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.26", default-features = false }
+sp-runtime = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.26", default-features = false }
+
+[dependencies.codec]
+default-features = false
+features = ['derive']
+package = 'parity-scale-codec'
+version = '3.1.5'
+
+[dependencies.frame-support]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.26'
+
+[features]
+default = ["std"]
+std = [
+	"sp-api/std",
+]
diff --git a/pallets/distance/rpc/runtime-api/src/lib.rs b/pallets/distance/rpc/runtime-api/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..94d1576df581e3fb201f5a287169e34ba9f2c71a
--- /dev/null
+++ b/pallets/distance/rpc/runtime-api/src/lib.rs
@@ -0,0 +1,15 @@
+#![cfg_attr(not(feature = "std"), no_std)]
+
+pub use pallet_distance::{ComputationMetadata, ComputationResult};
+
+use codec::{Decode, Encode};
+use frame_support::pallet_prelude::*;
+
+// Here we declare the runtime API. It is implemented it the `impl` block in
+// runtime amalgamator file (the `runtime/src/lib.rs`)
+sp_api::decl_runtime_apis! {
+    pub trait DistanceApi<IdtyIndex: Decode + Encode + PartialEq + TypeInfo> {
+        fn get_computation_metadata() -> Option<ComputationMetadata>;
+        fn publish_computation_result(computation_result: ComputationResult<IdtyIndex>);
+    }
+}
diff --git a/pallets/distance/rpc/src/lib.rs b/pallets/distance/rpc/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..56bc4651af5d24955c93feff872a3c350220c755
--- /dev/null
+++ b/pallets/distance/rpc/src/lib.rs
@@ -0,0 +1,158 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+use std::sync::Arc;
+
+use codec::{Decode, Encode};
+use frame_support::pallet_prelude::*;
+use jsonrpsee::{
+    core::{async_trait, RpcResult},
+    proc_macros::rpc,
+    types::error::{CallError, ErrorObject},
+};
+use serde::{Deserialize, Serialize};
+use sp_api::ProvideRuntimeApi;
+use sp_blockchain::HeaderBackend;
+use sp_core::Bytes;
+use sp_runtime::{generic::BlockId, traits::Block as BlockT};
+
+pub use pallet_distance_rpc_runtime_api::{ComputationResult, DistanceApi as DistanceRuntimeApi};
+
+#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct ComputationMetadata /*<Hash>*/ {
+    //pub block_hash: Hash,
+}
+
+impl From<pallet_distance_rpc_runtime_api::ComputationMetadata> for ComputationMetadata {
+    fn from(_val: pallet_distance_rpc_runtime_api::ComputationMetadata) -> Self {
+        Self {}
+    }
+}
+
+/*#[derive(Clone, Serialize, Deserialize)]
+pub struct ComputationResult {
+
+}
+
+impl Into<pallet_distance_rpc_runtime_api::ComputationResult> for ComputationResult {
+    fn into(self) -> pallet_distance_rpc_runtime_api::ComputationResult {
+        pallet_distance_rpc_runtime_api::ComputationResult{}
+    }
+}*/
+
+#[rpc(client, server)]
+pub trait DistanceApi<BlockHash, ResponseType> {
+    #[method(name = "distance_getComputationMetadata")]
+    fn get_computation_metadata(
+        &self,
+        at: Option<BlockHash>,
+    ) -> RpcResult<Option<ComputationMetadata>>;
+    #[method(name = "distance_publishComputationResult")]
+    fn publish_computation_result(
+        &self,
+        encoded_computation_result: Bytes,
+        at: Option<BlockHash>,
+    ) -> RpcResult<ResponseType>;
+}
+
+/// Provides RPC methods to query a dispatchable's class, weight and fee.
+pub struct Distance<C, P> {
+    /// Shared reference to the client.
+    client: Arc<C>,
+    _marker: std::marker::PhantomData<P>,
+}
+
+impl<C, P> Distance<C, P> {
+    /// Creates a new instance of the Distance Rpc helper.
+    pub fn new(client: Arc<C>) -> Self {
+        Self {
+            client,
+            _marker: Default::default(),
+        }
+    }
+}
+
+/// Error type of this RPC api.
+pub enum Error {
+    /// The transaction was not decodable.
+    DecodeError,
+    /// The call to runtime failed.
+    RuntimeError,
+}
+
+impl From<Error> for i32 {
+    fn from(e: Error) -> i32 {
+        match e {
+            Error::RuntimeError => 1,
+            Error::DecodeError => 2,
+        }
+    }
+}
+
+#[async_trait]
+impl<C, Block, IdtyIndex: 'static + Decode + Encode + PartialEq + Send + Sync + TypeInfo>
+    DistanceApiServer<<Block as BlockT>::Hash, ()> for Distance<C, (Block, IdtyIndex)>
+where
+    Block: BlockT,
+    C: ProvideRuntimeApi<Block> + HeaderBackend<Block> + Send + Sync + 'static,
+    C::Api: DistanceRuntimeApi<Block, IdtyIndex>,
+{
+    fn get_computation_metadata(
+        &self,
+        at: Option<Block::Hash>,
+    ) -> RpcResult<Option<ComputationMetadata>> {
+        let api = self.client.runtime_api();
+        let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));
+
+        api.get_computation_metadata(&at).map_or_else(
+            |e| {
+                Err(CallError::Custom(ErrorObject::owned(
+                    Error::RuntimeError.into(),
+                    "Unable to query dispatch info.",
+                    Some(e.to_string()),
+                ))
+                .into())
+            },
+            |v| Ok(v.map(Into::into)),
+        )
+    }
+    fn publish_computation_result(
+        &self,
+        encoded_computation_result: Bytes,
+        at: Option<Block::Hash>,
+    ) -> RpcResult<()> {
+        let api = self.client.runtime_api();
+        let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));
+
+        let computation_result: ComputationResult<IdtyIndex> =
+            Decode::decode(&mut &*encoded_computation_result).map_err(|e| {
+                CallError::Custom(ErrorObject::owned(
+                    Error::DecodeError.into(),
+                    "Unable to query dispatch info.",
+                    Some(format!("{:?}", e)),
+                ))
+            })?;
+        api.publish_computation_result(&at, computation_result)
+            .map_err(|e| {
+                CallError::Custom(ErrorObject::owned(
+                    Error::RuntimeError.into(),
+                    "Unable to query dispatch info.",
+                    Some(e.to_string()),
+                ))
+                .into()
+            })
+    }
+}
diff --git a/pallets/distance/src/lib.rs b/pallets/distance/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f131ceff7f1079b13ec928f560d49515c67986c6
--- /dev/null
+++ b/pallets/distance/src/lib.rs
@@ -0,0 +1,243 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+mod median;
+mod types;
+
+use median::*;
+pub use pallet::*;
+pub use types::*;
+
+use frame_support::traits::StorageVersion;
+use pallet_authority_members::SessionIndex;
+use sp_inherents::{InherentData, InherentIdentifier};
+use sp_std::convert::TryInto;
+
+pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"distanc0";
+
+type IdtyIndex = u32;
+
+#[frame_support::pallet]
+pub mod pallet {
+    use super::*;
+    use frame_support::pallet_prelude::*;
+    use frame_system::pallet_prelude::*;
+    use sp_runtime::Perbill;
+
+    /// The current storage version.
+    const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
+    #[pallet::pallet]
+    #[pallet::generate_store(pub(super) trait Store)]
+    #[pallet::storage_version(STORAGE_VERSION)]
+    #[pallet::without_storage_info]
+    pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
+    #[pallet::config]
+    pub trait Config<I: 'static = ()>:
+        frame_system::Config
+        + pallet_certification::Config<I, IdtyIndex = IdtyIndex>
+        + pallet_identity::Config<IdtyIndex = IdtyIndex>
+        + pallet_session::Config
+    {
+        /// Number of sessions before starting a new computation
+        type FinalityLag: Get<u32>;
+        /// Duration of a computation (in sessions)
+        type ComputationMaxDelay: Get<u32>;
+        /// Maximum number of identities in the evaluation queue
+        type QueueSize: Get<Option<u32>>;
+        /// Maximum number of identities to be evaluated in a session
+        type MaxEvaluationsPerSession: Get<u32>;
+        /// Minimum ratio of accessible referees
+        type MinAccessibleReferees: Get<Perbill>;
+    }
+
+    // STORAGE //
+
+    /// Identities to be evaluated in next sessions
+    #[pallet::storage]
+    pub type EvaluationQueue<T: Config<I>, I: 'static = ()> = CountedStorageMap<
+        _,
+        Twox64Concat,
+        <T as pallet_certification::Config<I>>::IdtyIndex,
+        (),
+        OptionQuery,
+        GetDefault,
+        <T as Config<I>>::QueueSize,
+    >;
+
+    /*#[pallet::storage]
+    pub type IdentitiesBeingEvaluated<T: Config<I>, I: 'static = ()> =
+        StorageValue<_, Vec<<T as pallet_certification::Config<I>>::IdtyIndex>, OptionQuery>;*/
+
+    /// Number of evaluators coming up with some value.
+    /// Indexed by identity index, then by value.
+    #[pallet::storage]
+    pub type EvaluatedIdentities<T: Config<I>, I: 'static = ()> = StorageMap<
+        _,
+        Twox64Concat,
+        <T as pallet_certification::Config<I>>::IdtyIndex,
+        MedianAcc<Perbill>,
+        OptionQuery,
+        GetDefault,
+    >;
+
+    /*/// Number of evaluators coming up with some referee count, indexed by referee count.
+    #[pallet::storage]
+    pub type Referees<T: Config<I>, I: 'static = ()> = StorageValue<_, MedianAcc<u32>, OptionQuery>;*/
+
+    #[pallet::error]
+    pub enum Error<T, I = ()> {
+        IdentityNotInEvaluation,
+        IdtyNotFound,
+        NonEligibleForEvaluation,
+        QueueFull,
+        UnauthorizedIdentity,
+    }
+
+    #[pallet::hooks]
+    impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {}
+
+    // CALLS //
+
+    #[pallet::call]
+    impl<T: Config<I>, I: 'static> Pallet<T, I> {
+        #[pallet::weight(1_000_000_000)]
+        pub fn evaluate_distance(
+            origin: OriginFor<T>,
+            idty_index: <T as pallet_certification::Config<I>>::IdtyIndex,
+        ) -> DispatchResultWithPostInfo {
+            let _who = ensure_signed(origin)?;
+            // TODO check whether origin is authorized to request evaluation
+            // TODO (maybe) check whether identity is already in queue
+            // TODO sort queue chronologically
+
+            if let Some(queue_size) = <T as Config<I>>::QueueSize::get() {
+                ensure!(
+                    EvaluationQueue::<T, I>::count() < queue_size,
+                    Error::<T, I>::QueueFull
+                );
+            }
+
+            ensure!(
+                pallet_identity::Identities::<T>::contains_key(idty_index),
+                Error::<T, I>::IdtyNotFound
+            );
+
+            EvaluationQueue::<T, I>::insert(idty_index, ());
+
+            Ok(().into())
+        }
+
+        #[pallet::weight(1_000_000_000)]
+        pub fn update_evaluation(
+            origin: OriginFor<T>,
+            computation_result: ComputationResult<<T as pallet_identity::Config>::IdtyIndex>,
+        ) -> DispatchResult {
+            ensure_none(origin)?;
+            //assert!(!DidUpdate::<T>::exists(), "At most one distance computation result can be submitted per block");
+
+            for (identity, result) in computation_result.identities {
+                EvaluatedIdentities::<T, I>::try_mutate::<_, _, Error<T, I>, _>(
+                    identity,
+                    |median_acc| {
+                        median_acc
+                            .as_mut()
+                            .ok_or(Error::<T, I>::IdentityNotInEvaluation)?
+                            .push(result);
+                        Ok(())
+                    },
+                )?;
+            }
+
+            Ok(())
+        }
+    }
+
+    // PUBLIC FUNCTIONS //
+
+    impl<T: Config<I>, I: 'static> Pallet<T, I> {
+        pub fn get_computation_metadata(
+        ) -> Option<ComputationMetadata /*<<T as frame_system::Config>::Hash>*/> {
+            None
+        }
+        pub fn publish_computation_result(
+            _computation_result: ComputationResult<<T as pallet_identity::Config>::IdtyIndex>,
+        ) {
+        }
+    }
+
+    // INTERNAL FUNCTIONS //
+
+    impl<T: Config<I>, I: 'static> Pallet<T, I> {}
+
+    impl<T: Config<I>, I: 'static> pallet_authority_members::OnNewSession for Pallet<T, I> {
+        fn on_new_session(index: SessionIndex) -> Weight {
+            match index % 3 {
+                0 => {
+                    EvaluationQueue::<T, I>::drain()
+                        .zip(0..<T as Config<I>>::MaxEvaluationsPerSession::get())
+                        .map(|((identity, _), _)| identity)
+                        .for_each(|identity| {
+                            EvaluatedIdentities::<T, I>::insert(identity, MedianAcc::new())
+                        });
+                }
+                1 => {}
+                2 => {
+                    for (_identity, median_acc) in EvaluatedIdentities::<T, I>::drain() {
+                        if let Some(median_result) = median_acc.get_median() {
+                            let median = match median_result {
+                                MedianResult::One(m) => m,
+                                MedianResult::Two(m1, m2) => m1 + (m2 - m1) / 2, // Avoid overflow (since max is 1)
+                            };
+                            if median >= T::MinAccessibleReferees::get() {
+                                todo!();
+                            } else {
+                                todo!();
+                            }
+                        }
+                    }
+                }
+                _ => unreachable!("index % 3 < 3"),
+            }
+            0
+        }
+    }
+
+    #[pallet::inherent]
+    impl<T: Config<I>, I: 'static> ProvideInherent for Pallet<T, I> {
+        type Call = Call<T, I>;
+        type Error = InherentError;
+
+        const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
+
+        fn create_inherent(data: &InherentData) -> Option<Self::Call> {
+            let inherent_data = data
+                .get_data::<ComputationResult<<T as pallet_identity::Config>::IdtyIndex>>(
+                    &INHERENT_IDENTIFIER,
+                )
+                .expect("Distance inherent data not correctly encoded")
+                .expect("Distance inherent data must be provided");
+            Some(Call::update_evaluation {
+                computation_result: inherent_data,
+            })
+        }
+        fn is_inherent(_call: &Self::Call) -> bool {
+            true
+        }
+    }
+}
diff --git a/pallets/distance/src/median.rs b/pallets/distance/src/median.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5d08c656ad88c637268b172f5d9912a9830440d1
--- /dev/null
+++ b/pallets/distance/src/median.rs
@@ -0,0 +1,143 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+use frame_support::pallet_prelude::*;
+use sp_std::{cmp::Ordering, vec::Vec};
+
+#[derive(Clone, Debug, Decode, Default, Encode, TypeInfo)]
+pub struct MedianAcc<T: Clone + Decode + Encode + Ord + TypeInfo> {
+    samples: Vec<(T, u32)>,
+    median_index: Option<u32>,
+    median_subindex: u32,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum MedianResult<T: Clone + Ord> {
+    One(T),
+    Two(T, T),
+}
+
+impl<T: Clone + Decode + Encode + Ord + TypeInfo> MedianAcc<T> {
+    pub fn new() -> Self {
+        Self {
+            samples: Vec::new(),
+            median_index: None,
+            median_subindex: 0,
+        }
+    }
+
+    pub fn push(&mut self, sample: T) {
+        if let Some(median_index) = &mut self.median_index {
+            match self
+                .samples
+                .binary_search_by_key(&sample, |(s, _n)| s.clone())
+            {
+                Ok(sample_index) => {
+                    self.samples.get_mut(sample_index).expect("unreachable").1 += 1;
+                    match (sample_index as u32).cmp(median_index) {
+                        Ordering::Greater => {
+                            if self.median_subindex
+                                == self
+                                    .samples
+                                    .get(*median_index as usize)
+                                    .expect("unreachable")
+                                    .1
+                                    * 2
+                                    - 1
+                            {
+                                self.median_subindex = 0;
+                                *median_index += 1;
+                            } else {
+                                self.median_subindex += 1;
+                            }
+                        }
+                        Ordering::Equal => {
+                            self.median_subindex += 1;
+                        }
+                        Ordering::Less => {
+                            if self.median_subindex == 0 {
+                                *median_index -= 1;
+                                self.median_subindex = self
+                                    .samples
+                                    .get(*median_index as usize)
+                                    .expect("unreachable")
+                                    .1
+                                    * 2
+                                    - 1;
+                            } else {
+                                self.median_subindex -= 1;
+                            }
+                        }
+                    }
+                }
+                Err(sample_index) => {
+                    self.samples.insert(sample_index, (sample, 1));
+                    if *median_index as usize >= sample_index {
+                        if self.median_subindex == 0 {
+                            self.median_subindex = self
+                                .samples
+                                .get(*median_index as usize)
+                                .expect("unreachable")
+                                .1
+                                * 2
+                                - 1;
+                        } else {
+                            self.median_subindex -= 1;
+                            *median_index += 1;
+                        }
+                    } else if self.median_subindex
+                        == self
+                            .samples
+                            .get(*median_index as usize)
+                            .expect("unreachable")
+                            .1
+                            * 2
+                            - 1
+                    {
+                        self.median_subindex = 0;
+                        *median_index += 1;
+                    } else {
+                        self.median_subindex += 1;
+                    }
+                }
+            }
+        } else {
+            self.samples.push((sample, 1));
+            self.median_index = Some(0);
+        }
+    }
+
+    pub fn get_median(&self) -> Option<MedianResult<T>> {
+        self.median_index.map(|median_index| {
+            let (median_sample, median_n) = self
+                .samples
+                .get(median_index as usize)
+                .expect("unreachable");
+            if self.median_subindex == median_n * 2 - 1 {
+                MedianResult::Two(
+                    median_sample.clone(),
+                    self.samples
+                        .get(median_index as usize + 1)
+                        .expect("unreachable")
+                        .0
+                        .clone(),
+                )
+            } else {
+                MedianResult::One(median_sample.clone())
+            }
+        })
+    }
+}
diff --git a/pallets/distance/src/types.rs b/pallets/distance/src/types.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9a39d09f80d5b20773ac9244d077a9802d001dbb
--- /dev/null
+++ b/pallets/distance/src/types.rs
@@ -0,0 +1,42 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+use codec::{Decode, Encode};
+use frame_support::pallet_prelude::*;
+use sp_inherents::IsFatalError;
+use sp_runtime::Perbill;
+use sp_std::vec::Vec;
+
+#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)]
+pub struct ComputationMetadata /*<Hash>*/ {
+    //pub block_hash: Hash,
+}
+
+#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)]
+pub struct ComputationResult<IdtyIndex: Decode + Encode + PartialEq + TypeInfo> {
+    pub identities: Vec<(IdtyIndex, Perbill)>,
+}
+
+#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+pub enum InherentError {
+    Foo,
+}
+
+impl IsFatalError for InherentError {
+    fn is_fatal_error(&self) -> bool {
+        false
+    }
+}
diff --git a/resources/metadata.scale b/resources/metadata.scale
index ff4c1c40a4d58bf8b3d8dc74373830583ef1ddbb..11bade8ba693169b83e825b6eb0d36a987a4a3dd 100644
Binary files a/resources/metadata.scale and b/resources/metadata.scale differ
diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml
index a4685b21bdeb8eefd696b83106d3ad4beb53afd9..7eb520c2e682083dcae1497121a26939b41d87d8 100644
--- a/runtime/common/Cargo.toml
+++ b/runtime/common/Cargo.toml
@@ -33,6 +33,8 @@ std = [
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
+    'pallet-distance/std',
+    'pallet-distance-rpc-runtime-api/std',
     'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
     'pallet-grandpa/std',
@@ -65,6 +67,8 @@ try-runtime = [
 duniter-primitives = { path = '../../primitives/duniter', default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-distance = { path = "../../pallets/distance", default-features = false }
+pallet-distance-rpc-runtime-api = { path = "../../pallets/distance/rpc/runtime-api", default-features = false }
 pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false }
 pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
diff --git a/runtime/common/src/apis.rs b/runtime/common/src/apis.rs
index dcd38e6e10ea4dccbea315532a2763c162757144..b02a4b61b3aeb47bff670de0de6b255c4f82f292 100644
--- a/runtime/common/src/apis.rs
+++ b/runtime/common/src/apis.rs
@@ -208,6 +208,15 @@ macro_rules! runtime_apis {
                     TransactionPayment::query_fee_details(uxt, len)
                 }
             }
+            impl pallet_distance_rpc_runtime_api::DistanceApi<Block, u32> for Runtime {
+                fn get_computation_metadata() -> Option<pallet_distance_rpc_runtime_api::ComputationMetadata/*<<T as frame_system::Config>::Hash>*/>
+         {
+                    Distance::get_computation_metadata()
+                }
+                fn publish_computation_result(computation_result: pallet_distance_rpc_runtime_api::ComputationResult<u32>) {
+                    Distance::publish_computation_result(computation_result)
+                }
+            }
 
             #[cfg(feature = "try-runtime")]
             impl frame_try_runtime::TryRuntime<Block> for Runtime {
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index e09b1d30fd008f604e4834e9f4b8a0c3531be31a..edf25c2943f4c2037572e45cd95c1334bc535f08 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -27,11 +27,11 @@ use sp_runtime::traits::IsMember;
 pub struct OnNewSessionHandler<Runtime>(core::marker::PhantomData<Runtime>);
 impl<Runtime> pallet_authority_members::traits::OnNewSession for OnNewSessionHandler<Runtime>
 where
-    Runtime: pallet_provide_randomness::Config,
+    Runtime: pallet_provide_randomness::Config + pallet_distance::Config<Instance1>,
 {
-    fn on_new_session(_index: sp_staking::SessionIndex) -> Weight {
+    fn on_new_session(index: sp_staking::SessionIndex) -> Weight {
         pallet_provide_randomness::Pallet::<Runtime>::on_new_epoch();
-        0
+        pallet_distance::Pallet::<Runtime, Instance1>::on_new_session(index)
     }
 }
 
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index cdcaa4944cda9a111335cbb204f901155570c1dc..ca02e9b612473c542da6ae72084caa6cfd01958c 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -468,6 +468,17 @@ macro_rules! pallets_config {
             type OnRemovedCert = Wot;
             type ValidityPeriod = ValidityPeriod;
         }
+        parameter_types! {
+            pub const MinAccessibleReferees: Perbill = Perbill::from_percent(80);
+        }
+        impl pallet_distance::Config<Instance1> for Runtime {
+            //type IdtyIndex: IdtyIndex;
+            type FinalityLag = frame_support::traits::ConstU32<1>;
+            type ComputationMaxDelay = frame_support::traits::ConstU32<1>;
+            type QueueSize = frame_support::traits::ConstU32<800>;
+            type MaxEvaluationsPerSession = frame_support::traits::ConstU32<100>;
+            type MinAccessibleReferees = MinAccessibleReferees;
+        }
 
         // SMITHS SUB-WOT //
 
diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml
index 65d3ec9afbf49d90c96ddf69b9189a25d293207c..8ec993dbacf4f2ba4f1fe1ab81007bec2509132d 100644
--- a/runtime/gdev/Cargo.toml
+++ b/runtime/gdev/Cargo.toml
@@ -63,6 +63,8 @@ std = [
     'pallet-balances/std',
     'pallet-certification/std',
     'pallet-collective/std',
+    'pallet-distance/std',
+    'pallet-distance-rpc-runtime-api/std',
     'pallet-duniter-test-parameters/std',
     'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
@@ -136,6 +138,8 @@ sp-keyring = { git = 'https://github.com/duniter/substrate', branch = 'duniter-s
 common-runtime = { path = "../common", default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-distance = { path = "../../pallets/distance", default-features = false }
+pallet-distance-rpc-runtime-api = { path = "../../pallets/distance/rpc/runtime-api", default-features = false }
 pallet-duniter-test-parameters = { path = '../../pallets/duniter-test-parameters', default-features = false }
 pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false }
 pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index eec2dc9c2bb696cc5e0b5f97f8e212fef237bd49..994f1b2b0044e01937876ec1a679b56b2ddceb54 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -313,6 +313,7 @@ construct_runtime!(
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 41,
         Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 42,
         Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 43,
+        Distance: pallet_distance::<Instance1>::{Call, Storage} = 44,
 
         // Smiths Sub-Wot
         SmithsSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50,