diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3070b8018c7c4e188342e3ca960c949140efd8c5..f6e785cae54a157c5013b596877b512387c97924 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -14,5 +14,6 @@
     "port_p2p": 19931,
     "port_rpc": 19932,
     "port_ws": 19933
-  }
+  },
+  "rust-analyzer.showUnlinkedFileNotification": false
 }
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index ca42803f51c2bfcf7572cb79fe08e322b48a14d8..9f89e471d401ecf9e0d9a07d87b9b0789b695a72 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -27,7 +27,7 @@ version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
 dependencies = [
- "gimli 0.27.0",
+ "gimli 0.27.1",
 ]
 
 [[package]]
@@ -313,13 +313,13 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
 
 [[package]]
 name = "async-trait"
-version = "0.1.60"
+version = "0.1.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3"
+checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -337,9 +337,9 @@ dependencies = [
 
 [[package]]
 name = "atomic-waker"
-version = "1.0.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
+checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599"
 
 [[package]]
 name = "atty"
@@ -369,7 +369,7 @@ dependencies = [
  "cfg-if 1.0.0",
  "libc",
  "miniz_oxide",
- "object 0.30.0",
+ "object 0.30.3",
  "rustc-demangle",
 ]
 
@@ -397,6 +397,12 @@ version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 
+[[package]]
+name = "base64"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
+
 [[package]]
 name = "base64ct"
 version = "1.5.3"
@@ -554,11 +560,12 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
 
 [[package]]
 name = "bstr"
-version = "0.2.17"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+checksum = "b7f0778972c64420fdedc63f09919c8a88bda7b25135357fd25a5d9f3257e832"
 dependencies = [
  "memchr",
+ "serde",
 ]
 
 [[package]]
@@ -572,9 +579,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.11.1"
+version = "3.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
 
 [[package]]
 name = "byte-slice-cast"
@@ -602,15 +609,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "bytes"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
 
 [[package]]
 name = "camino"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e"
+checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055"
 dependencies = [
  "serde",
 ]
@@ -639,9 +646,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.78"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
 dependencies = [
  "jobserver",
 ]
@@ -708,7 +715,7 @@ dependencies = [
  "js-sys",
  "num-integer",
  "num-traits",
- "time",
+ "time 0.1.45",
  "wasm-bindgen",
  "winapi 0.3.9",
 ]
@@ -763,13 +770,13 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.0.30"
+version = "4.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2"
+checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
 dependencies = [
  "bitflags",
- "clap_derive 4.0.21",
- "clap_lex 0.3.0",
+ "clap_derive 4.1.0",
+ "clap_lex 0.3.1",
  "is-terminal",
  "once_cell",
  "strsim",
@@ -778,11 +785,11 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.0.6"
+version = "4.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da"
+checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75"
 dependencies = [
- "clap 4.0.30",
+ "clap 4.1.4",
 ]
 
 [[package]]
@@ -791,24 +798,24 @@ version = "3.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
 dependencies = [
- "heck 0.4.0",
+ "heck 0.4.1",
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.0.21"
+version = "4.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
+checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
 dependencies = [
- "heck 0.4.0",
+ "heck 0.4.1",
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -822,13 +829,22 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
+checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
 dependencies = [
  "os_str_bytes",
 ]
 
+[[package]]
+name = "cmake"
+version = "0.1.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "codespan-reporting"
 version = "0.11.1"
@@ -839,6 +855,17 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "colored"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6"
+dependencies = [
+ "is-terminal",
+ "lazy_static",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "combine"
 version = "3.8.1"
@@ -854,9 +881,9 @@ dependencies = [
 
 [[package]]
 name = "comfy-table"
-version = "6.1.3"
+version = "6.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e621e7e86c46fd8a14c32c6ae3cb95656621b4743a27d0cffedb831d46e7ad21"
+checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d"
 dependencies = [
  "strum",
  "strum_macros",
@@ -878,6 +905,7 @@ dependencies = [
  "pallet-balances",
  "pallet-certification",
  "pallet-collective",
+ "pallet-distance",
  "pallet-duniter-account",
  "pallet-duniter-wot",
  "pallet-grandpa",
@@ -905,6 +933,7 @@ dependencies = [
  "sp-arithmetic",
  "sp-consensus-babe",
  "sp-core",
+ "sp-distance",
  "sp-membership",
  "sp-runtime",
  "sp-staking",
@@ -914,25 +943,24 @@ dependencies = [
 
 [[package]]
 name = "concurrent-queue"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b"
+checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e"
 dependencies = [
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "console"
-version = "0.15.2"
+version = "0.15.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
+checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60"
 dependencies = [
  "encode_unicode",
  "lazy_static",
  "libc",
- "terminal_size",
  "unicode-width",
- "winapi 0.3.9",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -1201,7 +1229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
 dependencies = [
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1219,7 +1247,7 @@ version = "3.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1631ca6e3c59112501a9d87fd86f21591ff77acd31331e8a73f8d80a65bbdd71"
 dependencies = [
- "nix 0.26.1",
+ "nix 0.26.2",
  "windows-sys 0.42.0",
 ]
 
@@ -1237,7 +1265,7 @@ dependencies = [
  "cucumber-expressions",
  "derive_more",
  "either",
- "futures 0.3.25",
+ "futures 0.3.26",
  "gherkin",
  "globwalk",
  "inventory",
@@ -1260,7 +1288,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "regex",
- "syn",
+ "syn 1.0.107",
  "synthez",
 ]
 
@@ -1305,9 +1333,9 @@ dependencies = [
 
 [[package]]
 name = "curve25519-dalek"
-version = "4.0.0-pre.5"
+version = "4.0.0-rc.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f"
+checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac"
 dependencies = [
  "cfg-if 1.0.0",
  "fiat-crypto",
@@ -1319,9 +1347,9 @@ dependencies = [
 
 [[package]]
 name = "cxx"
-version = "1.0.85"
+version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
+checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9"
 dependencies = [
  "cc",
  "cxxbridge-flags",
@@ -1331,9 +1359,9 @@ dependencies = [
 
 [[package]]
 name = "cxx-build"
-version = "1.0.85"
+version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
+checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d"
 dependencies = [
  "cc",
  "codespan-reporting",
@@ -1341,24 +1369,24 @@ dependencies = [
  "proc-macro2",
  "quote",
  "scratch",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
 name = "cxxbridge-flags"
-version = "1.0.85"
+version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59"
+checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a"
 
 [[package]]
 name = "cxxbridge-macro"
-version = "1.0.85"
+version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
+checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1382,7 +1410,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1393,7 +1421,7 @@ checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"
 dependencies = [
  "darling_core",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1419,7 +1447,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db"
 dependencies = [
  "data-encoding",
- "syn",
+ "syn 1.0.107",
+]
+
+[[package]]
+name = "dc-distance"
+version = "1.0.0"
+dependencies = [
+ "frame-support",
+ "log",
+ "pallet-distance",
+ "parity-scale-codec",
+ "sc-client-api",
+ "scale-info",
+ "sp-core",
+ "sp-distance",
+ "sp-keystore",
+ "sp-runtime",
+ "thiserror",
 ]
 
 [[package]]
@@ -1439,7 +1484,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1450,7 +1495,7 @@ checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1529,6 +1574,29 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "distance-oracle"
+version = "0.1.0"
+dependencies = [
+ "bincode",
+ "clap 4.1.4",
+ "dubp-wot",
+ "flate2",
+ "fnv",
+ "log",
+ "num-traits",
+ "parity-scale-codec",
+ "rayon",
+ "simple_logger",
+ "sp-core",
+ "sp-distance",
+ "sp-runtime",
+ "subxt",
+ "time 0.1.45",
+ "time-macros",
+ "tokio",
+]
+
 [[package]]
 name = "dns-parser"
 version = "0.8.0"
@@ -1557,18 +1625,33 @@ version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c00704156a7de8df8da0911424e30c2049957b0a714542a44e05fe693dd85313"
 
+[[package]]
+name = "dubp-wot"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59f62bdc1abf2da65794c9fd7fe46f7328834a97a2346048d46b0b6676302de0"
+dependencies = [
+ "log",
+ "once_cell",
+ "parking_lot 0.11.2",
+ "rayon",
+ "serde",
+]
+
 [[package]]
 name = "duniter"
 version = "0.3.0"
 dependencies = [
  "async-io",
- "clap 4.0.30",
+ "clap 4.1.4",
  "clap_complete",
  "common-runtime",
+ "dc-distance",
+ "distance-oracle",
  "frame-benchmarking",
  "frame-benchmarking-cli",
  "frame-system",
- "futures 0.3.25",
+ "futures 0.3.26",
  "g1-runtime",
  "gdev-runtime",
  "gtest-runtime",
@@ -1613,6 +1696,7 @@ dependencies = [
  "sp-consensus",
  "sp-consensus-babe",
  "sp-core",
+ "sp-distance",
  "sp-finality-grandpa",
  "sp-inherents",
  "sp-io",
@@ -1641,7 +1725,8 @@ dependencies = [
  "clap 3.2.23",
  "ctrlc",
  "cucumber",
- "env_logger",
+ "distance-oracle",
+ "env_logger 0.9.3",
  "hex",
  "notify",
  "parity-scale-codec",
@@ -1693,7 +1778,7 @@ checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1716,9 +1801,9 @@ dependencies = [
 
 [[package]]
 name = "ed25519"
-version = "1.5.2"
+version = "1.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369"
+checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
 dependencies = [
  "signature",
 ]
@@ -1753,9 +1838,9 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.8.0"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
 
 [[package]]
 name = "elliptic-curve"
@@ -1783,9 +1868,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
 
 [[package]]
 name = "encoding_rs"
-version = "0.8.31"
+version = "0.8.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
+checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
 dependencies = [
  "cfg-if 1.0.0",
 ]
@@ -1796,10 +1881,10 @@ version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116"
 dependencies = [
- "heck 0.4.0",
+ "heck 0.4.1",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1815,6 +1900,19 @@ dependencies = [
  "termcolor",
 ]
 
+[[package]]
+name = "env_logger"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
+dependencies = [
+ "humantime",
+ "is-terminal",
+ "log",
+ "regex",
+ "termcolor",
+]
+
 [[package]]
 name = "environmental"
 version = "1.1.4"
@@ -1864,7 +1962,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
 ]
 
 [[package]]
@@ -1885,7 +1983,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "synstructure",
 ]
 
@@ -1937,11 +2035,11 @@ checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90"
 
 [[package]]
 name = "file-per-thread-logger"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21e16290574b39ee41c71aeb90ae960c504ebaf1e2a1c87bd52aa56ed6e1a02f"
+checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866"
 dependencies = [
- "env_logger",
+ "env_logger 0.10.0",
  "log",
 ]
 
@@ -1953,18 +2051,18 @@ checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
 dependencies = [
  "cfg-if 1.0.0",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "windows-sys 0.42.0",
 ]
 
 [[package]]
 name = "finality-grandpa"
-version = "0.16.0"
+version = "0.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b22349c6a11563a202d95772a68e0fcf56119e74ea8a2a19cf2301460fcd0df5"
+checksum = "e24e6c429951433ccb7c87fd528c60084834dcd14763182c1f83291bcde24c34"
 dependencies = [
  "either",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "log",
  "num-traits",
@@ -2086,7 +2184,7 @@ dependencies = [
  "Inflector",
  "array-bytes",
  "chrono",
- "clap 4.0.30",
+ "clap 4.1.4",
  "comfy-table",
  "frame-benchmarking",
  "frame-support",
@@ -2201,7 +2299,7 @@ dependencies = [
  "itertools",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -2213,7 +2311,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -2223,7 +2321,7 @@ source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -2349,9 +2447,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
 
 [[package]]
 name = "futures"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
+checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -2364,9 +2462,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
+checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -2374,15 +2472,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
+checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
+checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -2392,9 +2490,9 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
+checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
 
 [[package]]
 name = "futures-lite"
@@ -2413,13 +2511,13 @@ dependencies = [
 
 [[package]]
 name = "futures-macro"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
+checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -2435,15 +2533,15 @@ dependencies = [
 
 [[package]]
 name = "futures-sink"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
+checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364"
 
 [[package]]
 name = "futures-task"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
+checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
 
 [[package]]
 name = "futures-timer"
@@ -2453,9 +2551,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
 
 [[package]]
 name = "futures-util"
-version = "0.3.25"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
+checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
 dependencies = [
  "futures 0.1.31",
  "futures-channel",
@@ -2501,6 +2599,7 @@ dependencies = [
  "pallet-balances",
  "pallet-certification",
  "pallet-collective",
+ "pallet-distance",
  "pallet-duniter-account",
  "pallet-duniter-test-parameters",
  "pallet-duniter-wot",
@@ -2570,6 +2669,7 @@ dependencies = [
  "pallet-balances",
  "pallet-certification",
  "pallet-collective",
+ "pallet-distance",
  "pallet-duniter-account",
  "pallet-duniter-test-parameters",
  "pallet-duniter-wot",
@@ -2606,6 +2706,7 @@ dependencies = [
  "sp-consensus-slots",
  "sp-consensus-vrf",
  "sp-core",
+ "sp-distance",
  "sp-finality-grandpa",
  "sp-inherents",
  "sp-io",
@@ -2705,7 +2806,7 @@ dependencies = [
  "quote",
  "serde",
  "serde_json",
- "syn",
+ "syn 1.0.107",
  "textwrap 0.12.1",
  "thiserror",
  "typed-builder",
@@ -2719,7 +2820,7 @@ checksum = "41973d4c45f7a35af8753ba3457cc99d406d863941fd7f52663cff54a5ab99b3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -2735,15 +2836,15 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.27.0"
+version = "0.27.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793"
+checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec"
 
 [[package]]
 name = "globset"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
+checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
 dependencies = [
  "aho-corasick",
  "bstr",
@@ -2765,9 +2866,9 @@ dependencies = [
 
 [[package]]
 name = "gloo-timers"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98c4a8d6391675c6b2ee1a6c8d06e8e2d03605c44cec1270675985a4c2a5500b"
+checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -2819,7 +2920,7 @@ dependencies = [
  "quote",
  "serde",
  "serde_json",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -2830,7 +2931,7 @@ checksum = "e56b093bfda71de1da99758b036f4cc811fd2511c8a76f75680e9ffbd2bb4251"
 dependencies = [
  "graphql_client_codegen",
  "proc-macro2",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -2866,6 +2967,7 @@ dependencies = [
  "pallet-balances",
  "pallet-certification",
  "pallet-collective",
+ "pallet-distance",
  "pallet-duniter-account",
  "pallet-duniter-wot",
  "pallet-grandpa",
@@ -2982,9 +3084,9 @@ dependencies = [
 
 [[package]]
 name = "heck"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
 [[package]]
 name = "hermit-abi"
@@ -3100,9 +3202,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "hyper"
-version = "0.14.23"
+version = "0.14.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c"
+checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -3221,7 +3323,7 @@ dependencies = [
  "async-io",
  "core-foundation",
  "fnv",
- "futures 0.3.25",
+ "futures 0.3.26",
  "if-addrs",
  "ipnet",
  "log",
@@ -3232,11 +3334,10 @@ dependencies = [
 
 [[package]]
 name = "ignore"
-version = "0.4.18"
+version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
+checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
 dependencies = [
- "crossbeam-utils",
  "globset",
  "lazy_static",
  "log",
@@ -3274,7 +3375,7 @@ checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -3350,12 +3451,12 @@ checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074"
 
 [[package]]
 name = "io-lifetimes"
-version = "1.0.3"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
+checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
 dependencies = [
  "libc",
- "windows-sys 0.42.0",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -3387,9 +3488,9 @@ dependencies = [
 
 [[package]]
 name = "ipnet"
-version = "2.7.0"
+version = "2.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
+checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
 
 [[package]]
 name = "is-terminal"
@@ -3398,8 +3499,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
 dependencies = [
  "hermit-abi 0.2.6",
- "io-lifetimes 1.0.3",
- "rustix 0.36.5",
+ "io-lifetimes 1.0.5",
+ "rustix 0.36.7",
  "windows-sys 0.42.0",
 ]
 
@@ -3429,9 +3530,9 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.60"
+version = "0.3.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -3606,7 +3707,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -3744,9 +3845,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.138"
+version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
 
 [[package]]
 name = "libm"
@@ -3767,7 +3868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec878fda12ebec479186b3914ebc48ff180fa4c51847e11a1a68bf65249e02c1"
 dependencies = [
  "bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "getrandom 0.2.8",
  "instant",
@@ -3805,7 +3906,7 @@ dependencies = [
  "ed25519-dalek",
  "either",
  "fnv",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "instant",
  "lazy_static",
@@ -3834,7 +3935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2322c9fb40d99101def6a01612ee30500c89abbbecb6297b3cd252903a4c1720"
 dependencies = [
  "async-std-resolver",
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p-core",
  "log",
  "parking_lot 0.12.1",
@@ -3849,7 +3950,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dcf9a121f699e8719bda2e6e9e9b6ddafc6cff4602471d6481c1067930ccb29b"
 dependencies = [
  "asynchronous-codec",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "libp2p-core",
  "libp2p-swarm",
@@ -3874,7 +3975,7 @@ dependencies = [
  "bytes",
  "either",
  "fnv",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "instant",
  "libp2p-core",
@@ -3900,7 +4001,7 @@ dependencies = [
  "async-io",
  "data-encoding",
  "dns-parser",
- "futures 0.3.25",
+ "futures 0.3.26",
  "if-watch",
  "libp2p-core",
  "libp2p-swarm",
@@ -3933,7 +4034,7 @@ checksum = "692664acfd98652de739a8acbb0a0d670f1d67190a49be6b4395e22c37337d89"
 dependencies = [
  "asynchronous-codec",
  "bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p-core",
  "log",
  "nohash-hasher",
@@ -3951,7 +4052,7 @@ checksum = "048155686bd81fe6cb5efdef0c6290f25ad32a0a42e8f4f72625cf6a505a206f"
 dependencies = [
  "bytes",
  "curve25519-dalek 3.2.0",
- "futures 0.3.25",
+ "futures 0.3.26",
  "lazy_static",
  "libp2p-core",
  "log",
@@ -3971,7 +4072,7 @@ version = "0.40.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7228b9318d34689521349a86eb39a3c3a802c9efc99a0568062ffb80913e3f91"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "instant",
  "libp2p-core",
@@ -3989,7 +4090,7 @@ checksum = "8827af16a017b65311a410bb626205a9ad92ec0473967618425039fa5231adc1"
 dependencies = [
  "async-trait",
  "bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "instant",
  "libp2p-core",
  "libp2p-swarm",
@@ -4007,7 +4108,7 @@ checksum = "46d13df7c37807965d82930c0e4b04a659efcb6cca237373b206043db5398ecf"
 dependencies = [
  "either",
  "fnv",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "instant",
  "libp2p-core",
@@ -4025,9 +4126,9 @@ version = "0.30.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a0eddc4497a8b5a506013c40e8189864f9c3a00db2b25671f428ae9007f3ba32"
 dependencies = [
- "heck 0.4.0",
+ "heck 0.4.1",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -4037,7 +4138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9839d96761491c6d3e238e70554b856956fca0ab60feb9de2cd08eed4473fa92"
 dependencies = [
  "async-io",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "if-watch",
  "libc",
@@ -4052,7 +4153,7 @@ version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a17b5b8e7a73e379e47b1b77f8a82c4721e97eca01abcd18e9cd91a23ca6ce97"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "js-sys",
  "libp2p-core",
  "parity-send-wrapper",
@@ -4067,7 +4168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3758ae6f89b2531a24b6d9f5776bda6a626b60a57600d7185d43dfa75ca5ecc4"
 dependencies = [
  "either",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-rustls",
  "libp2p-core",
  "log",
@@ -4085,7 +4186,7 @@ version = "0.41.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d6874d66543c4f7e26e3b8ca9a6bead351563a13ab4fafd43c7927f7c0d6c12"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p-core",
  "log",
  "parking_lot 0.12.1",
@@ -4100,7 +4201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1"
 dependencies = [
  "arrayref",
- "base64",
+ "base64 0.13.1",
  "digest 0.9.0",
  "hmac-drbg",
  "libsecp256k1-core",
@@ -4148,6 +4249,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
 dependencies = [
  "cc",
+ "cmake",
+ "libc",
  "pkg-config",
  "vcpkg",
 ]
@@ -4200,9 +4303,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
 
 [[package]]
 name = "lock_api"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
+checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -4297,9 +4400,9 @@ dependencies = [
 
 [[package]]
 name = "matches"
-version = "0.1.9"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
+checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
 
 [[package]]
 name = "matrixmultiply"
@@ -4322,7 +4425,7 @@ version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb"
 dependencies = [
- "rustix 0.36.5",
+ "rustix 0.36.7",
 ]
 
 [[package]]
@@ -4481,7 +4584,7 @@ dependencies = [
  "cfg-if 1.0.0",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -4532,15 +4635,15 @@ dependencies = [
 
 [[package]]
 name = "multihash-derive"
-version = "0.8.0"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd"
+checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db"
 dependencies = [
  "proc-macro-crate",
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "synstructure",
 ]
 
@@ -4557,7 +4660,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8552ab875c1313b97b8d20cb857b9fd63e2d1d6a0a1b53ce9821e575405f27a"
 dependencies = [
  "bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "log",
  "pin-project",
  "smallvec",
@@ -4590,7 +4693,7 @@ checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -4659,9 +4762,9 @@ dependencies = [
 
 [[package]]
 name = "netlink-packet-utils"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e"
+checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34"
 dependencies = [
  "anyhow",
  "byteorder",
@@ -4676,7 +4779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6"
 dependencies = [
  "bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "log",
  "netlink-packet-core",
  "netlink-sys",
@@ -4686,13 +4789,13 @@ dependencies = [
 
 [[package]]
 name = "netlink-sys"
-version = "0.8.3"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027"
+checksum = "260e21fbb6f3d253a14df90eb0000a6066780a15dd901a7519ce02d77a94985b"
 dependencies = [
  "async-io",
  "bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "libc",
  "log",
 ]
@@ -4716,9 +4819,9 @@ dependencies = [
 
 [[package]]
 name = "nix"
-version = "0.26.1"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
+checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
 dependencies = [
  "bitflags",
  "cfg-if 1.0.0",
@@ -4740,9 +4843,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
 
 [[package]]
 name = "nom"
-version = "7.1.1"
+version = "7.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
 dependencies = [
  "memchr",
  "minimal-lexical",
@@ -4750,9 +4853,9 @@ dependencies = [
 
 [[package]]
 name = "nom_locate"
-version = "4.0.0"
+version = "4.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37794436ca3029a3089e0b95d42da1f0b565ad271e4d3bb4bad0c7bb70b10605"
+checksum = "b1e299bf5ea7b212e811e71174c5d1a5d065c4c0ad0c8691ecb1f97e3e66025e"
 dependencies = [
  "bytecount",
  "memchr",
@@ -4807,9 +4910,9 @@ dependencies = [
 
 [[package]]
 name = "num-complex"
-version = "0.4.2"
+version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
+checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
 dependencies = [
  "num-traits",
 ]
@@ -4880,22 +4983,31 @@ dependencies = [
 
 [[package]]
 name = "num_enum"
-version = "0.5.7"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
+checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b"
 dependencies = [
  "num_enum_derive",
 ]
 
 [[package]]
 name = "num_enum_derive"
-version = "0.5.7"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
+checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
+]
+
+[[package]]
+name = "num_threads"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+dependencies = [
+ "libc",
 ]
 
 [[package]]
@@ -4912,20 +5024,20 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.30.0"
+version = "0.30.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
+checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.16.0"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 dependencies = [
- "parking_lot_core 0.9.5",
+ "parking_lot_core 0.9.8",
 ]
 
 [[package]]
@@ -4963,7 +5075,7 @@ checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -5142,6 +5254,26 @@ dependencies = [
  "sp-std",
 ]
 
+[[package]]
+name = "pallet-distance"
+version = "1.0.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-authority-members",
+ "pallet-authorship",
+ "pallet-identity",
+ "pallet-membership",
+ "pallet-session",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-distance",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+]
+
 [[package]]
 name = "pallet-duniter-account"
 version = "3.0.0"
@@ -5186,7 +5318,7 @@ dependencies = [
  "num_enum",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -5197,6 +5329,7 @@ dependencies = [
  "frame-support",
  "frame-system",
  "pallet-certification",
+ "pallet-distance",
  "pallet-identity",
  "pallet-membership",
  "parity-scale-codec",
@@ -5608,9 +5741,9 @@ dependencies = [
 
 [[package]]
 name = "parity-scale-codec"
-version = "3.2.1"
+version = "3.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a"
+checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed"
 dependencies = [
  "arrayvec 0.7.2",
  "bitvec",
@@ -5623,14 +5756,14 @@ dependencies = [
 
 [[package]]
 name = "parity-scale-codec-derive"
-version = "3.1.3"
+version = "3.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd"
+checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -5661,7 +5794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2"
 dependencies = [
  "proc-macro2",
- "syn",
+ "syn 1.0.107",
  "synstructure",
 ]
 
@@ -5704,7 +5837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 dependencies = [
  "lock_api",
- "parking_lot_core 0.9.5",
+ "parking_lot_core 0.9.8",
 ]
 
 [[package]]
@@ -5716,22 +5849,22 @@ dependencies = [
  "cfg-if 1.0.0",
  "instant",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "smallvec",
  "winapi 0.3.9",
 ]
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.5"
+version = "0.9.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
+checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
 dependencies = [
  "cfg-if 1.0.0",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.3.5",
  "smallvec",
- "windows-sys 0.42.0",
+ "windows-targets 0.48.1",
 ]
 
 [[package]]
@@ -5793,9 +5926,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
 
 [[package]]
 name = "pest"
-version = "2.5.1"
+version = "2.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0"
+checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f"
 dependencies = [
  "thiserror",
  "ucd-trie",
@@ -5803,9 +5936,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.5.1"
+version = "2.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344"
+checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea"
 dependencies = [
  "pest",
  "pest_generator",
@@ -5813,26 +5946,26 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.5.1"
+version = "2.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c"
+checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f"
 dependencies = [
  "pest",
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
 name = "pest_meta"
-version = "2.5.1"
+version = "2.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20"
+checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d"
 dependencies = [
  "once_cell",
  "pest",
- "sha1",
+ "sha2 0.10.6",
 ]
 
 [[package]]
@@ -5862,7 +5995,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -5976,9 +6109,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "predicates"
-version = "2.1.4"
+version = "2.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f54fc5dc63ed3bbf19494623db4f3af16842c0d975818e469022d09e53f0aa05"
+checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
 dependencies = [
  "difflib",
  "float-cmp",
@@ -6006,12 +6139,12 @@ dependencies = [
 
 [[package]]
 name = "prettyplease"
-version = "0.1.22"
+version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773"
+checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78"
 dependencies = [
  "proc-macro2",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -6029,11 +6162,10 @@ dependencies = [
 
 [[package]]
 name = "proc-macro-crate"
-version = "1.2.1"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
+checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
 dependencies = [
- "once_cell",
  "thiserror",
  "toml",
 ]
@@ -6047,7 +6179,7 @@ dependencies = [
  "proc-macro-error-attr",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "version_check",
 ]
 
@@ -6064,9 +6196,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.49"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
+checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
 dependencies = [
  "unicode-ident",
 ]
@@ -6105,14 +6237,14 @@ checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
 name = "prost"
-version = "0.11.5"
+version = "0.11.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592"
+checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698"
 dependencies = [
  "bytes",
  "prost-derive",
@@ -6120,12 +6252,12 @@ dependencies = [
 
 [[package]]
 name = "prost-build"
-version = "0.11.5"
+version = "0.11.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6"
+checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e"
 dependencies = [
  "bytes",
- "heck 0.4.0",
+ "heck 0.4.1",
  "itertools",
  "lazy_static",
  "log",
@@ -6135,7 +6267,7 @@ dependencies = [
  "prost",
  "prost-types",
  "regex",
- "syn",
+ "syn 1.0.107",
  "tempfile",
  "which",
 ]
@@ -6155,22 +6287,22 @@ dependencies = [
 
 [[package]]
 name = "prost-derive"
-version = "0.11.5"
+version = "0.11.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720"
+checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d"
 dependencies = [
  "anyhow",
  "itertools",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
 name = "prost-types"
-version = "0.11.5"
+version = "0.11.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091"
+checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788"
 dependencies = [
  "bytes",
  "prost",
@@ -6204,9 +6336,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.23"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
@@ -6325,9 +6457,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
 
 [[package]]
 name = "rayon"
-version = "1.6.1"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
+checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
 dependencies = [
  "either",
  "rayon-core",
@@ -6335,9 +6467,9 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.10.1"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
+checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
@@ -6354,6 +6486,15 @@ dependencies = [
  "bitflags",
 ]
 
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags",
+]
+
 [[package]]
 name = "redox_users"
 version = "0.4.3"
@@ -6361,7 +6502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
 dependencies = [
  "getrandom 0.2.8",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "thiserror",
 ]
 
@@ -6382,7 +6523,7 @@ checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -6399,9 +6540,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.7.0"
+version = "1.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
+checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -6428,7 +6569,7 @@ name = "remote-externalities"
 version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "env_logger",
+ "env_logger 0.9.3",
  "log",
  "parity-scale-codec",
  "serde",
@@ -6451,11 +6592,11 @@ dependencies = [
 
 [[package]]
 name = "reqwest"
-version = "0.11.13"
+version = "0.11.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
+checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9"
 dependencies = [
- "base64",
+ "base64 0.21.0",
  "bytes",
  "encoding_rs",
  "futures-core",
@@ -6540,7 +6681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0"
 dependencies = [
  "async-global-executor",
- "futures 0.3.25",
+ "futures 0.3.26",
  "log",
  "netlink-packet-route",
  "netlink-proto",
@@ -6610,13 +6751,13 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.36.5"
+version = "0.36.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
+checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
 dependencies = [
  "bitflags",
  "errno",
- "io-lifetimes 1.0.3",
+ "io-lifetimes 1.0.5",
  "libc",
  "linux-raw-sys 0.1.4",
  "windows-sys 0.42.0",
@@ -6624,9 +6765,9 @@ dependencies = [
 
 [[package]]
 name = "rustls"
-version = "0.20.7"
+version = "0.20.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c"
+checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
 dependencies = [
  "log",
  "ring",
@@ -6648,11 +6789,11 @@ dependencies = [
 
 [[package]]
 name = "rustls-pemfile"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55"
+checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
 dependencies = [
- "base64",
+ "base64 0.21.0",
 ]
 
 [[package]]
@@ -6679,7 +6820,7 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "26338f5e09bb721b85b135ea05af7767c90b52f6de4f087d4f4a3a9d64e7dc04"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "pin-project",
  "static_assertions",
 ]
@@ -6715,7 +6856,7 @@ name = "sc-basic-authorship"
 version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "log",
  "parity-scale-codec",
@@ -6774,7 +6915,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -6784,9 +6925,9 @@ source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9
 dependencies = [
  "array-bytes",
  "chrono",
- "clap 4.0.30",
+ "clap 4.1.4",
  "fdlimit",
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p",
  "log",
  "names",
@@ -6823,7 +6964,7 @@ version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "fnv",
- "futures 0.3.25",
+ "futures 0.3.26",
  "hash-db",
  "log",
  "parity-scale-codec",
@@ -6875,7 +7016,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "async-trait",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "libp2p",
  "log",
@@ -6899,7 +7040,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "async-trait",
- "futures 0.3.25",
+ "futures 0.3.26",
  "log",
  "parity-scale-codec",
  "sc-block-builder",
@@ -6929,7 +7070,7 @@ source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9
 dependencies = [
  "async-trait",
  "fork-tree",
- "futures 0.3.25",
+ "futures 0.3.26",
  "log",
  "merlin",
  "num-bigint 0.2.6",
@@ -6984,7 +7125,7 @@ source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9
 dependencies = [
  "assert_matches",
  "async-trait",
- "futures 0.3.25",
+ "futures 0.3.26",
  "jsonrpsee 0.15.1",
  "log",
  "parity-scale-codec",
@@ -7017,7 +7158,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "async-trait",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "log",
  "parity-scale-codec",
@@ -7135,7 +7276,7 @@ dependencies = [
  "dyn-clone",
  "finality-grandpa",
  "fork-tree",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "log",
  "parity-scale-codec",
@@ -7171,7 +7312,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "ansi_term",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "log",
  "parity-util-mem",
@@ -7211,7 +7352,7 @@ dependencies = [
  "either",
  "fnv",
  "fork-tree",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "ip_network",
  "libp2p",
@@ -7250,7 +7391,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "cid",
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p",
  "log",
  "prost",
@@ -7272,7 +7413,7 @@ dependencies = [
  "async-trait",
  "bitflags",
  "bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "libp2p",
  "linked_hash_set",
@@ -7296,7 +7437,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "ahash",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "libp2p",
  "log",
@@ -7314,7 +7455,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "array-bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p",
  "log",
  "parity-scale-codec",
@@ -7336,7 +7477,7 @@ source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9
 dependencies = [
  "array-bytes",
  "fork-tree",
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p",
  "log",
  "lru 0.7.8",
@@ -7365,7 +7506,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "array-bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "hex",
  "libp2p",
  "log",
@@ -7386,7 +7527,7 @@ dependencies = [
  "array-bytes",
  "bytes",
  "fnv",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "hyper",
  "hyper-rustls",
@@ -7413,7 +7554,7 @@ name = "sc-peerset"
 version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p",
  "log",
  "sc-utils",
@@ -7435,7 +7576,7 @@ name = "sc-rpc"
 version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "hash-db",
  "jsonrpsee 0.15.1",
  "log",
@@ -7465,7 +7606,7 @@ name = "sc-rpc-api"
 version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "jsonrpsee 0.15.1",
  "log",
  "parity-scale-codec",
@@ -7488,7 +7629,7 @@ name = "sc-rpc-server"
 version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "jsonrpsee 0.15.1",
  "log",
  "serde_json",
@@ -7501,7 +7642,7 @@ name = "sc-rpc-spec-v2"
 version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "hex",
  "jsonrpsee 0.15.1",
  "parity-scale-codec",
@@ -7523,7 +7664,7 @@ dependencies = [
  "async-trait",
  "directories",
  "exit-future",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "hash-db",
  "jsonrpsee 0.15.1",
@@ -7605,7 +7746,7 @@ name = "sc-sysinfo"
 version = "6.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "libc",
  "log",
  "rand 0.7.3",
@@ -7625,7 +7766,7 @@ version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "chrono",
- "futures 0.3.25",
+ "futures 0.3.26",
  "libp2p",
  "log",
  "parking_lot 0.12.1",
@@ -7676,7 +7817,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -7685,7 +7826,7 @@ version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "async-trait",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "linked-hash-map",
  "log",
@@ -7712,7 +7853,7 @@ version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "async-trait",
- "futures 0.3.25",
+ "futures 0.3.26",
  "log",
  "serde",
  "sp-blockchain",
@@ -7725,7 +7866,7 @@ name = "sc-utils"
 version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "lazy_static",
  "log",
@@ -7779,7 +7920,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -7801,12 +7942,11 @@ dependencies = [
 
 [[package]]
 name = "schannel"
-version = "0.1.20"
+version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
+checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
 dependencies = [
- "lazy_static",
- "windows-sys 0.36.1",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -7858,7 +7998,7 @@ dependencies = [
  "heck 0.3.3",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -7870,7 +8010,7 @@ dependencies = [
  "heck 0.3.3",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -7888,9 +8028,9 @@ dependencies = [
 
 [[package]]
 name = "secp256k1"
-version = "0.24.2"
+version = "0.24.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3"
+checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62"
 dependencies = [
  "secp256k1-sys",
 ]
@@ -7915,9 +8055,9 @@ dependencies = [
 
 [[package]]
 name = "security-framework"
-version = "2.7.0"
+version = "2.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c"
+checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
 dependencies = [
  "bitflags",
  "core-foundation",
@@ -7928,9 +8068,9 @@ dependencies = [
 
 [[package]]
 name = "security-framework-sys"
-version = "2.6.1"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
+checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -7962,22 +8102,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 
 [[package]]
 name = "serde"
-version = "1.0.151"
+version = "1.0.188"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
+checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.151"
+version = "1.0.188"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
+checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -8025,17 +8165,6 @@ dependencies = [
  "opaque-debug 0.3.0",
 ]
 
-[[package]]
-name = "sha1"
-version = "0.10.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
-dependencies = [
- "cfg-if 1.0.0",
- "cpufeatures",
- "digest 0.10.6",
-]
-
 [[package]]
 name = "sha2"
 version = "0.8.2"
@@ -8132,6 +8261,18 @@ dependencies = [
  "paste",
 ]
 
+[[package]]
+name = "simple_logger"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2230cd5c29b815c9b699fb610b49a5ed65588f3509d9f0108be3a885da629333"
+dependencies = [
+ "colored",
+ "log",
+ "time 0.3.23",
+ "windows-sys 0.42.0",
+]
+
 [[package]]
 name = "slab"
 version = "0.4.7"
@@ -8161,14 +8302,14 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831"
 
 [[package]]
 name = "snow"
-version = "0.9.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d"
+checksum = "12ba5f4d4ff12bdb6a169ed51b7c48c0e0ac4b0b4b31012b2571e97d78d3201d"
 dependencies = [
  "aes-gcm",
  "blake2",
  "chacha20poly1305",
- "curve25519-dalek 4.0.0-pre.5",
+ "curve25519-dalek 4.0.0-rc.0",
  "rand_core 0.6.4",
  "ring",
  "rustc_version",
@@ -8192,10 +8333,10 @@ version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2"
 dependencies = [
- "base64",
+ "base64 0.13.1",
  "bytes",
  "flate2",
- "futures 0.3.25",
+ "futures 0.3.26",
  "httparse",
  "log",
  "rand 0.8.5",
@@ -8229,7 +8370,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -8302,7 +8443,7 @@ name = "sp-blockchain"
 version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "log",
  "lru 0.7.8",
  "parity-scale-codec",
@@ -8321,7 +8462,7 @@ version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "async-trait",
- "futures 0.3.25",
+ "futures 0.3.26",
  "futures-timer",
  "log",
  "parity-scale-codec",
@@ -8414,7 +8555,7 @@ dependencies = [
  "byteorder",
  "dyn-clonable",
  "ed25519-zebra",
- "futures 0.3.25",
+ "futures 0.3.26",
  "hash-db",
  "hash256-std-hasher",
  "impl-serde",
@@ -8470,7 +8611,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "sp-core-hashing",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -8489,7 +8630,22 @@ source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
+]
+
+[[package]]
+name = "sp-distance"
+version = "3.0.0"
+dependencies = [
+ "async-trait",
+ "frame-support",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+ "thiserror",
 ]
 
 [[package]]
@@ -8541,7 +8697,7 @@ version = "6.0.0"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "bytes",
- "futures 0.3.25",
+ "futures 0.3.26",
  "hash-db",
  "libsecp256k1",
  "log",
@@ -8578,7 +8734,7 @@ version = "0.12.0"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "async-trait",
- "futures 0.3.25",
+ "futures 0.3.26",
  "merlin",
  "parity-scale-codec",
  "parking_lot 0.12.1",
@@ -8690,7 +8846,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -8886,7 +9042,7 @@ dependencies = [
  "parity-scale-codec",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -8936,9 +9092,9 @@ dependencies = [
 
 [[package]]
 name = "ss58-registry"
-version = "1.36.0"
+version = "1.38.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284"
+checksum = "e40c020d72bc0a9c5660bb71e4a6fdef081493583062c474740a7d59f55f0e7b"
 dependencies = [
  "Inflector",
  "num-format",
@@ -8986,7 +9142,7 @@ dependencies = [
  "memchr",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -9023,11 +9179,11 @@ version = "0.24.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
 dependencies = [
- "heck 0.4.0",
+ "heck 0.4.1",
  "proc-macro2",
  "quote",
  "rustversion",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -9057,7 +9213,7 @@ version = "4.0.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
  "frame-system-rpc-runtime-api",
- "futures 0.3.25",
+ "futures 0.3.26",
  "jsonrpsee 0.15.1",
  "log",
  "parity-scale-codec",
@@ -9129,7 +9285,7 @@ dependencies = [
  "bitvec",
  "derivative",
  "frame-metadata",
- "futures 0.3.25",
+ "futures 0.3.26",
  "getrandom 0.2.8",
  "hex",
  "jsonrpsee 0.16.2",
@@ -9155,7 +9311,7 @@ source = "git+https://github.com/duniter/subxt.git?branch=duniter-substrate-v0.9
 dependencies = [
  "darling",
  "frame-metadata",
- "heck 0.4.0",
+ "heck 0.4.1",
  "hex",
  "jsonrpsee 0.16.2",
  "parity-scale-codec",
@@ -9164,7 +9320,7 @@ dependencies = [
  "quote",
  "scale-info",
  "subxt-metadata",
- "syn",
+ "syn 1.0.107",
  "tokio",
 ]
 
@@ -9176,7 +9332,7 @@ dependencies = [
  "darling",
  "proc-macro-error",
  "subxt-codegen",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -9201,6 +9357,17 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "syn"
+version = "2.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
 [[package]]
 name = "synstructure"
 version = "0.12.6"
@@ -9209,7 +9376,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "unicode-xid",
 ]
 
@@ -9219,7 +9386,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "033178d0acccffc5490021657006e6a8dd586ee9dc6f7c24e7608b125e568cb1"
 dependencies = [
- "syn",
+ "syn 1.0.107",
  "synthez-codegen",
  "synthez-core",
 ]
@@ -9230,7 +9397,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "69263462a40e46960f070618e20094ce69e783a41f86e54bc75545136afd597a"
 dependencies = [
- "syn",
+ "syn 1.0.107",
  "synthez-core",
 ]
 
@@ -9243,7 +9410,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "sealed 0.3.0",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -9288,16 +9455,16 @@ dependencies = [
  "cfg-if 1.0.0",
  "fastrand",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "remove_dir_all",
  "winapi 0.3.9",
 ]
 
 [[package]]
 name = "tera"
-version = "1.17.0"
+version = "1.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d4685e72cb35f0eb74319c8fe2d3b61e93da5609841cde2cb87fcc3bea56d20"
+checksum = "3df578c295f9ec044ff1c829daf31bb7581d5b3c2a7a3d87419afe1f2531438c"
 dependencies = [
  "globwalk",
  "lazy_static",
@@ -9311,23 +9478,13 @@ dependencies = [
 
 [[package]]
 name = "termcolor"
-version = "1.1.3"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
 dependencies = [
  "winapi-util",
 ]
 
-[[package]]
-name = "terminal_size"
-version = "0.1.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
-dependencies = [
- "libc",
- "winapi 0.3.9",
-]
-
 [[package]]
 name = "termtree"
 version = "0.4.0"
@@ -9366,7 +9523,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -9404,6 +9561,35 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "time"
+version = "0.3.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446"
+dependencies = [
+ "itoa",
+ "libc",
+ "num_threads",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
+
+[[package]]
+name = "time-macros"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4"
+dependencies = [
+ "time-core",
+]
+
 [[package]]
 name = "tiny-bip39"
 version = "0.8.2"
@@ -9434,15 +9620,15 @@ dependencies = [
 
 [[package]]
 name = "tinyvec_macros"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.23.0"
+version = "1.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
+checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64"
 dependencies = [
  "autocfg",
  "bytes",
@@ -9455,7 +9641,7 @@ dependencies = [
  "signal-hook-registry",
  "socket2",
  "tokio-macros",
- "windows-sys 0.42.0",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -9466,7 +9652,7 @@ checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -9518,9 +9704,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.5.10"
+version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
 dependencies = [
  "serde",
 ]
@@ -9551,7 +9737,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -9685,16 +9871,16 @@ dependencies = [
 
 [[package]]
 name = "try-lock"
-version = "0.2.3"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
 
 [[package]]
 name = "try-runtime-cli"
 version = "0.10.0-dev"
 source = "git+https://github.com/duniter/substrate?branch=duniter-substrate-v0.9.32#7f8b8db65b441ce1d1b2ffb26ebde314b54e117c"
 dependencies = [
- "clap 4.0.30",
+ "clap 4.1.4",
  "frame-try-runtime",
  "log",
  "parity-scale-codec",
@@ -9742,7 +9928,7 @@ checksum = "f85f4270f4f449a3f2c0cf2aecc8415e388a597aeacc7d55fc749c5c968c8533"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -9830,9 +10016,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.8"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
+checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
 
 [[package]]
 name = "unicode-ident"
@@ -9851,9 +10037,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.10.0"
+version = "1.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
+checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
 
 [[package]]
 name = "unicode-width"
@@ -10012,9 +10198,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
 dependencies = [
  "cfg-if 1.0.0",
  "wasm-bindgen-macro",
@@ -10022,24 +10208,24 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.33"
+version = "0.4.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
+checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
 dependencies = [
  "cfg-if 1.0.0",
  "js-sys",
@@ -10049,9 +10235,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -10059,22 +10245,22 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
 
 [[package]]
 name = "wasm-gc-api"
@@ -10102,7 +10288,7 @@ version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "js-sys",
  "parking_lot 0.11.2",
  "pin-utils",
@@ -10197,7 +10383,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bcd849399d17d2270141cfe47fa0d91ee52d5f8ea9b98cf7ddde0d53e5f79882"
 dependencies = [
  "anyhow",
- "base64",
+ "base64 0.13.1",
  "bincode",
  "directories-next",
  "file-per-thread-logger",
@@ -10325,9 +10511,9 @@ dependencies = [
 
 [[package]]
 name = "web-sys"
-version = "0.3.60"
+version = "0.3.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
+checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -10363,9 +10549,9 @@ dependencies = [
 
 [[package]]
 name = "which"
-version = "4.3.0"
+version = "4.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
+checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
 dependencies = [
  "either",
  "libc",
@@ -10453,20 +10639,74 @@ version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc 0.42.0",
- "windows_i686_gnu 0.42.0",
- "windows_i686_msvc 0.42.0",
- "windows_x86_64_gnu 0.42.0",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc 0.42.0",
+ "windows_aarch64_gnullvm 0.42.1",
+ "windows_aarch64_msvc 0.42.1",
+ "windows_i686_gnu 0.42.1",
+ "windows_i686_msvc 0.42.1",
+ "windows_x86_64_gnu 0.42.1",
+ "windows_x86_64_gnullvm 0.42.1",
+ "windows_x86_64_msvc 0.42.1",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.1",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.1",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.1",
+ "windows_aarch64_msvc 0.42.1",
+ "windows_i686_gnu 0.42.1",
+ "windows_i686_msvc 0.42.1",
+ "windows_x86_64_gnu 0.42.1",
+ "windows_x86_64_gnullvm 0.42.1",
+ "windows_x86_64_msvc 0.42.1",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.0",
+ "windows_aarch64_msvc 0.48.0",
+ "windows_i686_gnu 0.48.0",
+ "windows_i686_msvc 0.48.0",
+ "windows_x86_64_gnu 0.48.0",
+ "windows_x86_64_gnullvm 0.48.0",
+ "windows_x86_64_msvc 0.48.0",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -10482,9 +10722,15 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -10500,9 +10746,15 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -10518,9 +10770,15 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -10536,15 +10794,27 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -10560,9 +10830,15 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
 
 [[package]]
 name = "winreg"
@@ -10608,7 +10884,7 @@ name = "xtask"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "clap 4.0.30",
+ "clap 4.1.4",
  "frame-metadata",
  "graphql_client",
  "hex",
@@ -10632,7 +10908,7 @@ version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5d9ba232399af1783a58d8eb26f6b5006fbefe2dc9ef36bd283324792d03ea5"
 dependencies = [
- "futures 0.3.25",
+ "futures 0.3.26",
  "log",
  "nohash-hasher",
  "parking_lot 0.12.1",
@@ -10663,7 +10939,7 @@ checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "synstructure",
 ]
 
@@ -10688,10 +10964,11 @@ dependencies = [
 
 [[package]]
 name = "zstd-sys"
-version = "2.0.4+zstd.1.5.2"
+version = "2.0.6+zstd.1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0"
+checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b"
 dependencies = [
  "cc",
  "libc",
+ "pkg-config",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 0896f98b8037d2e72ff49d5552a27b58b2df43f0..16f852337fafcea846c74c388539c1bb2c77e619 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,10 +32,10 @@ runtime-benchmarks = [
     'sc-client-db/runtime-benchmarks',
 ]
 try-runtime = [
-	#"g1-runtime/try-runtime",
-	"gdev-runtime/try-runtime",
-	#"gtest-runtime/try-runtime",
-	"try-runtime-cli"
+    #"g1-runtime/try-runtime",
+    "gdev-runtime/try-runtime",
+    #"gtest-runtime/try-runtime",
+    "try-runtime-cli",
 ]
 
 [build-dependencies]
@@ -48,19 +48,28 @@ rusty-hook = "^0.11.2"
 
 # Dependencies for specific targets
 [target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies]
-sc-cli = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.32", default-features = false, features = ["wasmtime"] }
-sc-service = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.32", default-features = false, features = ["wasmtime"] }
-sp-trie = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.32", features = ["memory-tracker"] }
+sc-cli = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.32", default-features = false, features = [
+    "wasmtime",
+] }
+sc-service = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.32", default-features = false, features = [
+    "wasmtime",
+] }
+sp-trie = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.32", features = [
+    "memory-tracker",
+] }
 
 
 [dependencies]
 # local dependencies
 common-runtime = { path = 'runtime/common' }
+dc-distance = { path = 'client/distance' }
+distance-oracle = { path = 'distance-oracle', optional = true }
 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-oneshot-account = { path = 'pallets/oneshot-account' }
+sp-distance = { path = 'primitives/distance' }
 sp-membership = { path = 'primitives/membership' }
 
 # crates.io dependencies
@@ -131,9 +140,12 @@ try-runtime-cli = { git = "https://github.com/duniter/substrate", branch = "duni
 resolver = "2"
 
 members = [
+    'client/distance',
+    'distance-oracle',
     'end2end-tests',
     'live-tests',
     'pallets/certification',
+    'pallets/distance',
     'pallets/duniter-test-parameters',
     'pallets/duniter-test-parameters/macro',
     'pallets/duniter-wot',
@@ -144,6 +156,7 @@ members = [
     'pallets/universal-dividend',
     'pallets/upgrade-origin',
     'primitives/membership',
+    'primitives/distance',
     'runtime/common',
     'runtime/gdev',
     'xtask',
diff --git a/client/distance/Cargo.toml b/client/distance/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..27f16c31e957d63ad3a64cb87490d2a2094f7a54
--- /dev/null
+++ b/client/distance/Cargo.toml
@@ -0,0 +1,51 @@
+[package]
+authors = ['tuxmain <tuxmain@zettascript.org>']
+description = 'Duniter client distance'
+edition = '2021'
+homepage = 'https://duniter.org'
+license = 'AGPL-3.0'
+name = 'dc-distance'
+readme = 'README.md'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '1.0.0'
+
+[dependencies]
+
+pallet-distance = { path = "../../pallets/distance" }
+sp-distance = { path = "../../primitives/distance" }
+
+log = "0.4"
+thiserror = "1.0.30"
+
+# substrate
+scale-info = { version = "2.1.1", features = ["derive"] }
+
+[dependencies.codec]
+features = ['derive']
+package = 'parity-scale-codec'
+version = '3.1.5'
+
+[dependencies.frame-support]
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sc-client-api]
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-core]
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-keystore]
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-runtime]
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
diff --git a/client/distance/src/lib.rs b/client/distance/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ea345101015990ac80c3ce4ee269367ce4c7a450
--- /dev/null
+++ b/client/distance/src/lib.rs
@@ -0,0 +1,107 @@
+// Copyright 2022 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 codec::{Decode, Encode};
+use frame_support::pallet_prelude::*;
+use sc_client_api::{ProvideUncles, StorageKey, StorageProvider};
+use scale_info::TypeInfo;
+use sp_runtime::{generic::BlockId, traits::Block as BlockT, AccountId32};
+use std::path::PathBuf;
+
+type IdtyIndex = u32;
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error<B: BlockT> {
+    #[error("Could not retrieve the block hash for block id: {0:?}")]
+    NoHashForBlockId(BlockId<B>),
+}
+
+/// Create a new [`sp_distance::InherentDataProvider`] at the given block.
+pub fn create_distance_inherent_data_provider<B, C, Backend>(
+    client: &C,
+    parent: B::Hash,
+    distance_dir: PathBuf,
+    owner_keys: &[sp_core::sr25519::Public],
+) -> Result<sp_distance::InherentDataProvider<IdtyIndex>, sc_client_api::blockchain::Error>
+where
+    B: BlockT,
+    C: ProvideUncles<B> + StorageProvider<B, Backend>,
+    Backend: sc_client_api::Backend<B>,
+    IdtyIndex: Decode + Encode + PartialEq + TypeInfo,
+{
+    let &[owner_key] = owner_keys else {
+        return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(
+            None
+        ))
+    };
+    let owner_key = sp_runtime::AccountId32::new(owner_key.0);
+
+    let session_index = client
+        .storage(
+            &parent,
+            &StorageKey(
+                frame_support::storage::storage_prefix(b"Session", b"CurrentIndex").to_vec(),
+            ),
+        )
+        .expect("CurrentIndex is Err")
+        .map_or(0, |raw| {
+            u32::decode(&mut &raw.0[..]).expect("cannot decode CurrentIndex")
+        });
+
+    let published_results = client
+        .storage(
+            &parent,
+            &StorageKey(
+                frame_support::storage::storage_prefix(
+                    b"Distance",
+                    match session_index % 3 {
+                        0 => b"StoragePublishedResults1",
+                        1 => b"StoragePublishedResults2",
+                        2 => b"StoragePublishedResults0",
+                        _ => unreachable!("n%3<3"),
+                    },
+                )
+                .to_vec(),
+            ),
+        )?
+        .map_or_else(Default::default, |raw| {
+            pallet_distance::EvaluationPool::<AccountId32, IdtyIndex>::decode(&mut &raw.0[..])
+                .expect("cannot decode EvaluationPool")
+        });
+
+    // Have we already published a result for this session?
+    if published_results.evaluators.contains(&owner_key) {
+        return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(None));
+    }
+
+    // Read evaluation result from file, if it exists
+    let evaluation_result = match std::fs::read(distance_dir.join(session_index.to_string())) {
+        Ok(data) => data,
+        Err(e) => {
+            match e.kind() {
+                std::io::ErrorKind::NotFound => {}
+                _ => {
+                    log::error!("Cannot read distance evaluation result file: {e:?}");
+                }
+            }
+            return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(None));
+        }
+    };
+
+    Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(Some(
+        sp_distance::ComputationResult::decode(&mut evaluation_result.as_slice()).unwrap(),
+    )))
+}
diff --git a/distance-oracle/Cargo.toml b/distance-oracle/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..60240d9f20bb33b4802b57cb25b972a6b2a346fb
--- /dev/null
+++ b/distance-oracle/Cargo.toml
@@ -0,0 +1,44 @@
+[package]
+name = "distance-oracle"
+version = "0.1.0"
+authors = ["tuxmain <tuxmain@zettascript.org>"]
+repository = "https://git.duniter.org/nodes/rust/duniter-v2s"
+license = "AGPL-3.0-only"
+edition = "2021"
+
+[dependencies]
+sp-distance = { path = "../primitives/distance" }
+
+codec = { package = "parity-scale-codec", version = "3.1.5" }
+fnv = "1.0.7"
+log = "0.4.17"
+num-traits = "0.2.15"
+rayon = "1.7.0"
+simple_logger = "4.2.0"
+sp-core = { git = "https://github.com/duniter/substrate.git", branch = "duniter-substrate-v0.9.32" }
+sp-runtime = { git = "https://github.com/duniter/substrate.git", branch = "duniter-substrate-v0.9.32" }
+subxt = { git = 'https://github.com/duniter/subxt.git', branch = "duniter-substrate-v0.9.32" }
+time = "<=0.3.23"# required for MSRV
+time-macros = "=0.2.10"
+
+# standalone only
+clap = { version = "4.0", features = ["derive"], optional = true }
+tokio = { version = "1.15.0", features = [
+	"rt-multi-thread",
+	"macros",
+], optional = true }
+
+[dev-dependencies]
+bincode = "1.3.3"
+dubp-wot = "0.11.1"
+flate2 = { version = "1.0", features = [
+	"zlib-ng-compat",
+], default-features = false }
+
+[features]
+default = ["standalone"]
+standalone = ["clap", "tokio"]
+
+[[bin]]
+name = "distance-oracle"
+required-features = ["standalone"]
diff --git a/distance-oracle/README.md b/distance-oracle/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5a4233827626c53a79da4b6750ec3bb93f6918c3
--- /dev/null
+++ b/distance-oracle/README.md
@@ -0,0 +1,20 @@
+# Distance oracle
+
+> for explanation about the Duniter web of trust, see https://duniter.org/wiki/web-of-trust/deep-dive-wot/
+
+Distance computation on the Duniter web of trust is an expensive operation that should not be included in the runtime for multiple reasons:
+
+- it could exceed the time available for a block computation
+- it takes a lot of resource from the host machine
+- the result is not critical to the operation of Äž1
+
+It is then separated into an other program that the user (a duniter smith) can choose to run or not. This program publishes its result in a inherent and the network selects the median of the results given by the smith who published some.
+
+## Structure
+
+This feature is organized in multiple parts:
+
+- **/distance-oracle/** (here): binary executing the distance algorithm
+- **/primitives/distance/**: primitive types used both by client and runtime
+- **/client/distance/**: exposes the `create_distance_inherent_data_provider` which provides data to the runtime
+- **/pallets/distance/**: distance pallet exposing type, traits, storage/calls/hooks executing in the runtime
\ No newline at end of file
diff --git a/distance-oracle/src/api.rs b/distance-oracle/src/api.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ee5ce2587325f15a61cc08c09e723b732a68929c
--- /dev/null
+++ b/distance-oracle/src/api.rs
@@ -0,0 +1,155 @@
+// Copyright 2023 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 crate::runtime;
+
+use sp_core::H256;
+use subxt::storage::StorageKey;
+
+pub type Client = subxt::OnlineClient<crate::RuntimeConfig>;
+pub type AccountId = subxt::ext::sp_runtime::AccountId32;
+pub type IdtyIndex = u32;
+
+pub async fn client(rpc_url: String) -> Client {
+    Client::from_url(rpc_url)
+        .await
+        .expect("Cannot create RPC client")
+}
+
+pub async fn parent_hash(client: &Client) -> H256 {
+    client
+        .storage()
+        .fetch(&runtime::storage().system().parent_hash(), None)
+        .await
+        .expect("Cannot fetch parent hash")
+        .expect("Parent hash is None")
+}
+
+pub async fn current_session(client: &Client, parent_hash: H256) -> u32 {
+    client
+        .storage()
+        .fetch(
+            &runtime::storage().session().current_index(),
+            Some(parent_hash),
+        )
+        .await
+        .expect("Cannot fetch current session")
+        .unwrap_or_default()
+}
+
+pub async fn current_pool(
+    client: &Client,
+    parent_hash: H256,
+    current_session: u32,
+) -> Option<runtime::runtime_types::pallet_distance::types::EvaluationPool<AccountId, IdtyIndex>> {
+    client
+        .storage()
+        .fetch(
+            &match current_session % 3 {
+                0 => runtime::storage().distance().evaluation_pool1(),
+                1 => runtime::storage().distance().evaluation_pool2(),
+                2 => runtime::storage().distance().evaluation_pool0(),
+                _ => unreachable!("n%3<3"),
+            },
+            Some(parent_hash),
+        )
+        .await
+        .expect("Cannot fetch current pool")
+}
+
+pub async fn evaluation_block(client: &Client, parent_hash: H256) -> H256 {
+    client
+        .storage()
+        .fetch(
+            &runtime::storage().distance().evaluation_block(),
+            Some(parent_hash),
+        )
+        .await
+        .expect("Cannot fetch evaluation block")
+        .expect("No evaluation block")
+}
+
+pub async fn member_iter(client: &Client, evaluation_block: H256) -> MemberIter {
+    MemberIter(
+        client
+            .storage()
+            .iter(
+                runtime::storage().membership().membership(0),
+                100,
+                Some(evaluation_block),
+            )
+            .await
+            .expect("Cannot fetch memberships"),
+    )
+}
+
+pub struct MemberIter(
+    subxt::storage::KeyIter<
+        crate::RuntimeConfig,
+        Client,
+        subxt::metadata::DecodeStaticType<
+            runtime::runtime_types::sp_membership::MembershipData<u32>,
+        >,
+    >,
+);
+
+impl MemberIter {
+    pub async fn next(&mut self) -> Result<Option<IdtyIndex>, subxt::error::Error> {
+        Ok(self
+            .0
+            .next()
+            .await?
+            .map(|(storage_key, _membership_data)| idty_id_from_storage_key(&storage_key)))
+    }
+}
+
+pub async fn cert_iter(client: &Client, evaluation_block: H256) -> CertIter {
+    CertIter(
+        client
+            .storage()
+            .iter(
+                runtime::storage().cert().certs_by_receiver(0),
+                100,
+                Some(evaluation_block),
+            )
+            .await
+            .expect("Cannot fetch certifications"),
+    )
+}
+
+pub struct CertIter(
+    subxt::storage::KeyIter<
+        crate::RuntimeConfig,
+        Client,
+        subxt::metadata::DecodeStaticType<Vec<(IdtyIndex, u32)>>,
+    >,
+);
+
+impl CertIter {
+    pub async fn next(
+        &mut self,
+    ) -> Result<Option<(IdtyIndex, Vec<(IdtyIndex, u32)>)>, subxt::error::Error> {
+        Ok(self
+            .0
+            .next()
+            .await?
+            .map(|(storage_key, issuers)| (idty_id_from_storage_key(&storage_key), issuers)))
+    }
+}
+
+fn idty_id_from_storage_key(storage_key: &StorageKey) -> IdtyIndex {
+    u32::from_le_bytes(storage_key.as_ref()[40..44].try_into().unwrap())
+}
diff --git a/distance-oracle/src/lib.rs b/distance-oracle/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..be8b8432eb500d46ac8b30502371c6564e8eba33
--- /dev/null
+++ b/distance-oracle/src/lib.rs
@@ -0,0 +1,313 @@
+// Copyright 2023 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(not(test))]
+pub mod api;
+#[cfg(test)]
+pub mod mock;
+#[cfg(test)]
+mod tests;
+
+#[cfg(test)]
+pub use mock as api;
+
+use api::{AccountId, IdtyIndex};
+
+use codec::Encode;
+use fnv::{FnvHashMap, FnvHashSet};
+use log::{debug, error, warn};
+use rayon::iter::IntoParallelRefIterator;
+use rayon::iter::ParallelIterator;
+use std::io::Write;
+use std::path::PathBuf;
+
+// TODO select metadata file using features
+#[subxt::subxt(runtime_metadata_path = "../resources/metadata.scale")]
+pub mod runtime {}
+
+pub enum RuntimeConfig {}
+impl subxt::config::Config for RuntimeConfig {
+    type Index = u32;
+    type BlockNumber = u32;
+    type Hash = sp_core::H256;
+    type Hashing = subxt::ext::sp_runtime::traits::BlakeTwo256;
+    type AccountId = AccountId;
+    type Address = subxt::ext::sp_runtime::MultiAddress<Self::AccountId, u32>;
+    type Header = subxt::ext::sp_runtime::generic::Header<
+        Self::BlockNumber,
+        subxt::ext::sp_runtime::traits::BlakeTwo256,
+    >;
+    type Signature = subxt::ext::sp_runtime::MultiSignature;
+    type ExtrinsicParams = subxt::tx::BaseExtrinsicParams<Self, Tip>;
+}
+
+#[derive(Copy, Clone, Debug, Default, Encode)]
+pub struct Tip {
+    #[codec(compact)]
+    tip: u64,
+}
+
+impl Tip {
+    pub fn new(amount: u64) -> Self {
+        Tip { tip: amount }
+    }
+}
+
+impl From<u64> for Tip {
+    fn from(n: u64) -> Self {
+        Self::new(n)
+    }
+}
+
+pub struct Settings {
+    pub evaluation_result_dir: PathBuf,
+    pub max_depth: u32,
+    pub rpc_url: String,
+}
+
+impl Default for Settings {
+    fn default() -> Self {
+        Self {
+            evaluation_result_dir: PathBuf::from("/tmp/duniter/chains/gdev/distance"),
+            max_depth: 5,
+            rpc_url: String::from("ws://127.0.0.1:9944"),
+        }
+    }
+}
+
+pub async fn run_and_save(client: &api::Client, settings: Settings) {
+    let Some((evaluation, current_session, evaluation_result_path)) = run(client, &settings, true).await else {return};
+
+    let mut evaluation_result_file = std::fs::OpenOptions::new()
+        .write(true)
+        .create_new(true)
+        .open(&evaluation_result_path)
+        .unwrap_or_else(|e| {
+            panic!(
+                "Cannot open distance evaluation result file `{evaluation_result_path:?}`: {e:?}"
+            )
+        });
+    evaluation_result_file
+        .write_all(
+            &sp_distance::ComputationResult {
+                distances: evaluation,
+            }
+            .encode(),
+        )
+        .unwrap_or_else(|e| {
+            panic!(
+                "Cannot write distance evaluation result to file `{evaluation_result_path:?}`: {e:?}"
+            )
+        });
+
+    // Remove old results
+    let mut files_to_remove = Vec::new();
+    for entry in settings
+        .evaluation_result_dir
+        .read_dir()
+        .unwrap_or_else(|e| {
+            panic!(
+                "Cannot read distance evaluation result directory `{0:?}`: {e:?}",
+                settings.evaluation_result_dir
+            )
+        })
+        .flatten()
+    {
+        if let Ok(entry_name) = entry.file_name().into_string() {
+            if let Ok(entry_session) = entry_name.parse::<isize>() {
+                if current_session as isize - entry_session > 3 {
+                    files_to_remove.push(entry.path());
+                }
+            }
+        }
+    }
+    files_to_remove.into_iter().for_each(|f| {
+        std::fs::remove_file(&f)
+            .unwrap_or_else(move |e| warn!("Cannot remove old result file `{f:?}`: {e:?}"));
+    });
+}
+
+/// Returns `Option<(evaluation, current_session, evaluation_result_path)>`
+pub async fn run(
+    client: &api::Client,
+    settings: &Settings,
+    handle_fs: bool,
+) -> Option<(Vec<sp_runtime::Perbill>, u32, PathBuf)> {
+    let parent_hash = api::parent_hash(client).await;
+
+    let current_session = api::current_session(client, parent_hash).await;
+
+    // Fetch the pending identities
+    let Some(evaluation_pool) = api::current_pool(client, parent_hash, current_session).await
+         else {
+            debug!("Nothing to do: Pool does not exist");
+            return None
+        };
+
+    // Stop if nothing to evaluate
+    if evaluation_pool.evaluations.0.is_empty() {
+        debug!("Nothing to do: Pool is empty");
+        return None;
+    }
+
+    let evaluation_result_path = settings
+        .evaluation_result_dir
+        .join((current_session + 1).to_string());
+
+    if handle_fs {
+        // Stop if already evaluated
+        if evaluation_result_path.try_exists().unwrap() {
+            debug!("Nothing to do: File already exists");
+            return None;
+        }
+
+        std::fs::create_dir_all(&settings.evaluation_result_dir).unwrap_or_else(|e| {
+            error!(
+                "Cannot create distance evaluation result directory `{0:?}`: {e:?}",
+                settings.evaluation_result_dir
+            );
+        });
+    }
+
+    let evaluation_block = api::evaluation_block(client, parent_hash).await;
+
+    // member idty -> issued certs
+    let mut members = FnvHashMap::<IdtyIndex, u32>::default();
+
+    let mut members_iter = api::member_iter(client, evaluation_block).await;
+    while let Some(member_idty) = members_iter.next().await.unwrap() {
+        members.insert(member_idty, 0);
+    }
+
+    let min_certs_for_referee = (members.len() as f32)
+        .powf(1. / (settings.max_depth as f32))
+        .ceil() as u32;
+
+    // idty -> received certs
+    let mut received_certs = FnvHashMap::<IdtyIndex, Vec<IdtyIndex>>::default();
+
+    let mut certs_iter = api::cert_iter(client, evaluation_block).await;
+    while let Some((receiver, issuers)) = certs_iter
+        .next()
+        .await
+        .expect("Cannot fetch next certification")
+    {
+        if (issuers.len() as u32) < min_certs_for_referee {
+            // This member is not referee
+            members.remove(&receiver);
+        }
+        for (issuer, _removable_on) in issuers.iter() {
+            if let Some(issued_certs) = members.get_mut(issuer) {
+                *issued_certs += 1;
+            }
+        }
+        received_certs.insert(
+            receiver,
+            issuers
+                .into_iter()
+                .map(|(issuer, _removable_on)| issuer)
+                .collect(),
+        );
+    }
+
+    // Only retain referees
+    members.retain(|_idty, issued_certs| *issued_certs >= min_certs_for_referee);
+    let referees = members;
+
+    let evaluation = evaluation_pool
+        .evaluations
+        .0
+        .as_slice()
+        .par_iter()
+        .map(|(idty, _)| distance_rule(&received_certs, &referees, settings.max_depth, *idty))
+        .collect();
+
+    Some((evaluation, current_session, evaluation_result_path))
+}
+
+fn distance_rule_recursive(
+    received_certs: &FnvHashMap<IdtyIndex, Vec<IdtyIndex>>,
+    referees: &FnvHashMap<IdtyIndex, u32>,
+    idty: IdtyIndex,
+    accessible_referees: &mut FnvHashSet<IdtyIndex>,
+    known_idties: &mut FnvHashMap<IdtyIndex, u32>,
+    depth: u32,
+) {
+    // Do not re-explore identities that have already been explored at least as deeply
+    match known_idties.entry(idty) {
+        std::collections::hash_map::Entry::Occupied(mut entry) => {
+            if *entry.get() >= depth {
+                return;
+            } else {
+                *entry.get_mut() = depth;
+            }
+        }
+        std::collections::hash_map::Entry::Vacant(entry) => {
+            entry.insert(depth);
+        }
+    }
+
+    // If referee, add it to the list
+    if referees.contains_key(&idty) {
+        accessible_referees.insert(idty);
+    }
+
+    // If reached the maximum distance, stop exploring
+    if depth == 0 {
+        return;
+    }
+
+    // Explore certifiers
+    for &certifier in received_certs.get(&idty).unwrap_or(&vec![]).iter() {
+        distance_rule_recursive(
+            received_certs,
+            referees,
+            certifier,
+            accessible_referees,
+            known_idties,
+            depth - 1,
+        );
+    }
+}
+
+/// Returns the fraction `nb_accessible_referees / nb_referees`
+fn distance_rule(
+    received_certs: &FnvHashMap<IdtyIndex, Vec<IdtyIndex>>,
+    referees: &FnvHashMap<IdtyIndex, u32>,
+    depth: u32,
+    idty: IdtyIndex,
+) -> sp_runtime::Perbill {
+    let mut accessible_referees =
+        FnvHashSet::<IdtyIndex>::with_capacity_and_hasher(referees.len(), Default::default());
+    let mut known_idties =
+        FnvHashMap::<IdtyIndex, u32>::with_capacity_and_hasher(referees.len(), Default::default());
+    distance_rule_recursive(
+        received_certs,
+        referees,
+        idty,
+        &mut accessible_referees,
+        &mut known_idties,
+        depth,
+    );
+    if referees.contains_key(&idty) {
+        sp_runtime::Perbill::from_rational(
+            accessible_referees.len() as u32 - 1,
+            referees.len() as u32 - 1,
+        )
+    } else {
+        sp_runtime::Perbill::from_rational(accessible_referees.len() as u32, referees.len() as u32)
+    }
+}
diff --git a/distance-oracle/src/main.rs b/distance-oracle/src/main.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d60668e87fa145b1da53fcf60d5f38a007eaf8cd
--- /dev/null
+++ b/distance-oracle/src/main.rs
@@ -0,0 +1,51 @@
+// Copyright 2023 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 clap::Parser;
+
+#[derive(Debug, clap::Parser)]
+struct Cli {
+    #[clap(short = 'd', long, default_value = "/tmp/duniter/chains/gdev/distance")]
+    evaluation_result_dir: String,
+    /// Maximum depth to explore the WoT graph for referees
+    #[clap(short = 'D', long, default_value = "5")]
+    max_depth: u32,
+    #[clap(short = 'u', long, default_value = "ws://127.0.0.1:9944")]
+    rpc_url: String,
+    /// Log level (off, error, warn, info, debug, trace)
+    #[clap(short = 'l', long, default_value = "info")]
+    log: log::LevelFilter,
+}
+
+#[tokio::main]
+async fn main() {
+    let cli = Cli::parse();
+
+    simple_logger::SimpleLogger::new()
+        .with_level(cli.log)
+        .init()
+        .unwrap();
+
+    distance_oracle::run_and_save(
+        &distance_oracle::api::client(cli.rpc_url.clone()).await,
+        distance_oracle::Settings {
+            evaluation_result_dir: cli.evaluation_result_dir.into(),
+            max_depth: cli.max_depth,
+            rpc_url: cli.rpc_url,
+        },
+    )
+    .await;
+}
diff --git a/distance-oracle/src/mock.rs b/distance-oracle/src/mock.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1ecc7a74c2d91fc36d3b0887c5e47081ffe2e881
--- /dev/null
+++ b/distance-oracle/src/mock.rs
@@ -0,0 +1,121 @@
+// Copyright 2023 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 crate::runtime::runtime_types::{
+    pallet_distance::median::MedianAcc, sp_arithmetic::per_things::Perbill,
+};
+
+use dubp_wot::{data::rusty::RustyWebOfTrust, WebOfTrust, WotId};
+use sp_core::H256;
+use std::collections::BTreeSet;
+
+pub struct Client {
+    wot: RustyWebOfTrust,
+    pub pool_len: usize,
+}
+pub type AccountId = subxt::ext::sp_runtime::AccountId32;
+pub type IdtyIndex = u32;
+
+pub struct EvaluationPool<AccountId: Ord, IdtyIndex> {
+    pub evaluations: (Vec<(IdtyIndex, MedianAcc<Perbill>)>,),
+    pub evaluators: BTreeSet<AccountId>,
+}
+
+pub async fn client(_rpc_url: String) -> Client {
+    unimplemented!()
+}
+
+pub fn client_from_wot(wot: RustyWebOfTrust) -> Client {
+    Client { wot, pool_len: 1 }
+}
+
+pub async fn parent_hash(_client: &Client) -> H256 {
+    Default::default()
+}
+
+pub async fn current_session(_client: &Client, _parent_hash: H256) -> u32 {
+    0
+}
+
+pub async fn current_pool(
+    client: &Client,
+    _parent_hash: H256,
+    _current_session: u32,
+) -> Option<EvaluationPool<AccountId, IdtyIndex>> {
+    Some(EvaluationPool {
+        evaluations: (client
+            .wot
+            .get_enabled()
+            .into_iter()
+            .chain(client.wot.get_disabled().into_iter())
+            .zip(0..client.pool_len)
+            .map(|(wot_id, _)| {
+                (wot_id.0 as IdtyIndex, unsafe {
+                    std::mem::transmute((Vec::<()>::new(), Option::<u32>::None, 0))
+                })
+            })
+            .collect(),),
+        evaluators: BTreeSet::new(),
+    })
+}
+
+pub async fn evaluation_block(_client: &Client, _parent_hash: H256) -> H256 {
+    Default::default()
+}
+
+pub async fn member_iter(client: &Client, _evaluation_block: H256) -> MemberIter {
+    MemberIter(client.wot.get_enabled().into_iter())
+}
+
+pub struct MemberIter(std::vec::IntoIter<WotId>);
+
+impl MemberIter {
+    pub async fn next(&mut self) -> Result<Option<IdtyIndex>, subxt::error::Error> {
+        Ok(self.0.next().map(|wot_id| wot_id.0 as u32))
+    }
+}
+
+pub async fn cert_iter(client: &Client, _evaluation_block: H256) -> CertIter {
+    CertIter(
+        client
+            .wot
+            .get_enabled()
+            .iter()
+            .chain(client.wot.get_disabled().iter())
+            .map(|wot_id| {
+                (
+                    wot_id.0 as IdtyIndex,
+                    client
+                        .wot
+                        .get_links_source(*wot_id)
+                        .unwrap_or_default()
+                        .into_iter()
+                        .map(|wot_id| (wot_id.0 as IdtyIndex, 0))
+                        .collect::<Vec<(IdtyIndex, u32)>>(),
+                )
+            })
+            .collect::<Vec<_>>()
+            .into_iter(),
+    )
+}
+
+pub struct CertIter(std::vec::IntoIter<(IdtyIndex, Vec<(IdtyIndex, u32)>)>);
+
+impl CertIter {
+    pub async fn next(&mut self) -> Result<Option<(u32, Vec<(u32, u32)>)>, subxt::error::Error> {
+        Ok(self.0.next())
+    }
+}
diff --git a/distance-oracle/src/tests.rs b/distance-oracle/src/tests.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f2f6d77ed3ac38172f6f41efa3a4fc9042c3f580
--- /dev/null
+++ b/distance-oracle/src/tests.rs
@@ -0,0 +1,109 @@
+// Copyright 2023 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 dubp_wot::{
+    data::rusty::RustyWebOfTrust, operations::distance::DistanceCalculator, WebOfTrust,
+};
+use flate2::read::ZlibDecoder;
+use sp_runtime::Perbill;
+use std::{fs::File, io::Read};
+
+#[tokio::test]
+#[ignore = "long to execute"]
+async fn test_distance_against_v1() {
+    let wot = wot_from_v1_file();
+    let n = wot.size();
+    let max_depth = 5;
+    let min_certs_for_referee = (wot.get_enabled().len() as f32).powf(1. / 5.).ceil() as u32;
+
+    // Reference implementation
+    let ref_calculator = dubp_wot::operations::distance::RustyDistanceCalculator;
+    let t_a = std::time::Instant::now();
+    let ref_results: Vec<Perbill> = wot
+        .get_enabled()
+        .into_iter()
+        .chain(wot.get_disabled().into_iter())
+        .zip(0..n)
+        .map(|(i, _)| {
+            let result = ref_calculator
+                .compute_distance(
+                    &wot,
+                    dubp_wot::operations::distance::WotDistanceParameters {
+                        node: i,
+                        sentry_requirement: min_certs_for_referee,
+                        step_max: max_depth,
+                        x_percent: 0.8,
+                    },
+                )
+                .unwrap();
+            Perbill::from_rational(result.success, result.sentries)
+        })
+        .collect();
+    println!("ref time: {}", t_a.elapsed().as_millis());
+
+    // Our implementation
+    let mut client = crate::api::client_from_wot(wot);
+    client.pool_len = n;
+
+    let t_a = std::time::Instant::now();
+    let results = crate::run(
+        &client,
+        &crate::Settings {
+            max_depth,
+            ..Default::default()
+        },
+        false,
+    )
+    .await
+    .unwrap();
+    println!("new time: {}", t_a.elapsed().as_millis());
+    assert_eq!(results.0.len(), n);
+
+    let mut errors: Vec<_> = results
+        .0
+        .iter()
+        .zip(ref_results.iter())
+        .map(|(r, r_ref)| r.deconstruct() as i64 - r_ref.deconstruct() as i64)
+        .collect();
+    errors.sort_unstable();
+    println!(
+        "Error: {:?} / {:?} / {:?} / {:?} / {:?}  (min / 1Q / med / 3Q / max)",
+        errors[0],
+        errors[errors.len() / 4],
+        errors[errors.len() / 2],
+        errors[errors.len() * 3 / 4],
+        errors[errors.len() - 1]
+    );
+
+    let correct_results = results
+        .0
+        .iter()
+        .zip(ref_results.iter())
+        .map(|(r, r_ref)| (r == r_ref) as usize)
+        .sum::<usize>();
+    println!("Correct results: {correct_results} / {n}");
+    assert_eq!(correct_results, n);
+}
+
+fn wot_from_v1_file() -> RustyWebOfTrust {
+    let file = File::open("wot.deflate").expect("Cannot open wot.deflate");
+    let mut decompressor = ZlibDecoder::new(file);
+    let mut decompressed_bytes = Vec::new();
+    decompressor
+        .read_to_end(&mut decompressed_bytes)
+        .expect("Cannot decompress wot.deflate");
+    bincode::deserialize::<RustyWebOfTrust>(&decompressed_bytes).expect("Cannot decode wot.deflate")
+}
diff --git a/distance-oracle/wot.deflate b/distance-oracle/wot.deflate
new file mode 100644
index 0000000000000000000000000000000000000000..087c09cfc125ee954a63b79d04e4013630b4c4f5
Binary files /dev/null and b/distance-oracle/wot.deflate differ
diff --git a/docs/api/manual.md b/docs/api/manual.md
index 6ef23fce558d559381dcde268301bea5f63316bf..0b9a91eb7f77a347a0379ee6e4515435460db990 100644
--- a/docs/api/manual.md
+++ b/docs/api/manual.md
@@ -20,6 +20,9 @@ Only use `identity` pallet. The `membership` calls are disabled.
 1. The account that wants to gain membership needs to exists.
 1. Any account that already has membership and respects the identity creation period can create an identity for another account, using `identity.createIdentity`.
 1. The account has to confirm its identity with a name, using `identity.confirmIdentity`. The name must be ASCII alphanumeric, punctuation or space characters: ``/^[-!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~a-zA-Z0-9 ]{3,64}$/`` (additionally, trailing spaces and double spaces are forbidden, as a phishing countermeasure). If the name is already used, the call will fail.
+1. 4 different member accounts must certify the account using `cert.addCert`.
+1. The distance evaluation must be requested for the pending identity using `distance.evaluateDistance`.
+1. 3 sessions later, if the distance rule is respected, `identity.validateIdentity` can be called.
 
 ## Change key
 
diff --git a/docs/user/distance.md b/docs/user/distance.md
new file mode 100644
index 0000000000000000000000000000000000000000..3dea9edf231cca1e0c0722fe6a7176ecadcd9d85
--- /dev/null
+++ b/docs/user/distance.md
@@ -0,0 +1,31 @@
+# Distance rule evaluation
+
+The [distance rule](https://duniter.org/blog/duniter-deep-dive-wot/) is computationally too heavy to be handled by the runtime. Therefore it is computed offchain using the distance oracle.
+
+Distance evaluation is operated on a voluntary basis by individual smiths. Since evaluators can lie or make errors, the result considered for applying the distance rule is the median of results published by the different evaluators.
+
+## Running distance evaluation
+
+Any smith member authoring blocks can run a distance evaluation oracle. It is better to have a machine more powerful than the reference machine.
+
+The simplest way is to run the oracle on the same machine as Duniter.
+
+Build the oracle:
+
+    cargo build --release -p distance-oracle
+
+It will be available at `./target/release/distance-oracle`. Move it to somewhere appropriate.
+
+Add this line to your cron with the command `crontab -e`: (add option `-u <user>` to edit another user's cron)
+
+    4,24,44 * * * * nice -n 2 /absolute/path/to/distance-oracle
+
+The precise hours don't matter so you can pick random values, but it should run at least one time per hour, and running it more often decreases the risk of problem in case of missing blocks or temporary network failure.
+
+If the evaluation ran successfully in a session, the next runs in the same session won't re-evaluate the same data.
+
+The `nice -n 2` lowers the oracle's priority, so that Duniter has the priority even when the oracle wants to use all the cores.
+
+### Additional Duniter configuration
+
+Duniter should keep states at least one session old, that it 600 blocks (while 256 is the default). Use the option `--state-pruning 600` if your node is not already an archive (`--state-pruning archive`).
diff --git a/end2end-tests/Cargo.toml b/end2end-tests/Cargo.toml
index 07df18c1aa1878428fd2c5c9b1b655df405ea810..95e15c04acbbcdfd5179b8b5e1a7ecab6e6cc9a4 100644
--- a/end2end-tests/Cargo.toml
+++ b/end2end-tests/Cargo.toml
@@ -14,6 +14,7 @@ async-trait = "0.1"
 clap = { version = "3.2.23", features = ["derive"] }
 ctrlc = "3.2.2"
 cucumber = "0.11"
+distance-oracle = { path = "../distance-oracle", default_features = false }
 env_logger = "0.9.0"
 hex = "0.4"
 notify = "4.0"
@@ -26,4 +27,4 @@ tokio = { version = "1.15.0", features = ["macros"] }
 
 [[test]]
 name = "cucumber_tests"
-harness = false  # allows Cucumber to print output instead of libtest
+harness = false         # allows Cucumber to print output instead of libtest
diff --git a/end2end-tests/README.md b/end2end-tests/README.md
index b5f21c0c2013e983c6566a804a558899a1735984..79da56e7fded4010bf8fd29abdc05109db261538 100644
--- a/end2end-tests/README.md
+++ b/end2end-tests/README.md
@@ -163,7 +163,7 @@ To work, the integration tests need to have the runtime metadata up to date, her
 them:
 
 ```bash
-subxt metadata -f bytes > resources/metadata.scale
+subxt metadata -f bytes --version 14 > resources/metadata.scale
 ```
 
 If you don't have subxt, install it: `cargo install subxt-cli`
diff --git a/end2end-tests/cucumber-features/identity_creation.feature b/end2end-tests/cucumber-features/identity_creation.feature
index 81113d8b1549154e6f3ca5e91691ff137691a18b..56a7404dffbd9390f1560fb547259c540fcfaa1a 100644
--- a/end2end-tests/cucumber-features/identity_creation.feature
+++ b/end2end-tests/cucumber-features/identity_creation.feature
@@ -5,8 +5,9 @@ Feature: Identity creation
     # - account creation fees (3 ÄžD) 
     # - existential deposit (2 ÄžD)
     # - transaction fees (below 1 ÄžD)
-    When alice sends 6 ÄžD to dave
-    When bob sends 6 ÄžD to eve
+    When alice sends 7 ÄžD to dave
+    When bob sends 750 cÄžD to dave
+    When charlie sends 6 ÄžD to eve
     # alice last certification is counted from block zero
     # then next cert can be done after cert_period, which is 15
     When 15 block later
@@ -20,6 +21,12 @@ Feature: Identity creation
     When charlie certifies dave
     Then dave should be certified by bob
     Then dave should be certified by charlie
-    When 3 block later
+    When dave requests distance evaluation
+    Then dave should have distance result in 2 sessions
+    When 30 blocks later
+    Then dave should have distance result in 1 session
+    When alice runs distance oracle
+    When 30 blocks later
+    Then dave should have distance ok
     When eve validates dave identity
     Then dave identity should be validated
diff --git a/end2end-tests/tests/common/distance.rs b/end2end-tests/tests/common/distance.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e1a8f1ecaa6e002400aa0f456eac9284b99e0d8a
--- /dev/null
+++ b/end2end-tests/tests/common/distance.rs
@@ -0,0 +1,87 @@
+// Copyright 2023 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 super::gdev;
+use super::gdev::runtime_types::pallet_identity;
+use super::*;
+use crate::DuniterWorld;
+use sp_keyring::AccountKeyring;
+use subxt::ext::sp_runtime::AccountId32;
+use subxt::tx::{PairSigner, Signer};
+
+pub async fn request_evaluation(client: &Client, origin: AccountKeyring) -> Result<()> {
+    let origin = PairSigner::new(origin.pair());
+
+    let _events = create_block_with_extrinsic(
+        client,
+        client
+            .tx()
+            .create_signed(
+                &gdev::tx().distance().request_distance_evaluation(),
+                &origin,
+                BaseExtrinsicParamsBuilder::new(),
+            )
+            .await?,
+    )
+    .await?;
+
+    Ok(())
+}
+
+pub async fn run_oracle(client: &Client, origin: AccountKeyring, rpc_url: String) -> Result<()> {
+    let origin = PairSigner::new(origin.pair());
+    let account_id: &AccountId32 = origin.account_id();
+
+    if let Some((distances, _current_session, _evaluation_result_path)) = distance_oracle::run(
+        &distance_oracle::api::client(rpc_url.clone()).await,
+        &distance_oracle::Settings {
+            evaluation_result_dir: PathBuf::default(),
+            max_depth: 5,
+            rpc_url,
+        },
+        false,
+    )
+    .await
+    {
+        for _ in 0..30 {
+            super::create_empty_block(client).await?;
+        }
+
+        let _events = create_block_with_extrinsic(
+            client,
+            client
+                .tx()
+                .create_signed(
+                    &gdev::tx().sudo().sudo(gdev::runtime_types::gdev_runtime::RuntimeCall::Distance(
+                            gdev::runtime_types::pallet_distance::pallet::Call::force_update_evaluation {
+                                evaluator: account_id.clone(),
+                                computation_result:
+                                    gdev::runtime_types::sp_distance::ComputationResult {
+                                        distances: distances.into_iter().map(|res| unsafe{std::mem::transmute(res)}).collect(),
+                                    },
+                            },
+                        )
+                    ),
+                    &origin,
+                    BaseExtrinsicParamsBuilder::new(),
+                )
+                .await?,
+        )
+        .await?;
+    }
+
+    Ok(())
+}
diff --git a/end2end-tests/tests/common/identity.rs b/end2end-tests/tests/common/identity.rs
index 58e881264a4daed837fdc4bc0a039e3f2428f27c..735e655fd66fa8d55bb74e709a7d0fc5946e245a 100644
--- a/end2end-tests/tests/common/identity.rs
+++ b/end2end-tests/tests/common/identity.rs
@@ -84,9 +84,11 @@ pub async fn validate_identity(client: &Client, from: AccountKeyring, to: u32) -
                 &from,
                 BaseExtrinsicParamsBuilder::new(),
             )
-            .await?,
+            .await
+            .unwrap(),
     )
-    .await?;
+    .await
+    .unwrap();
 
     Ok(())
 }
diff --git a/end2end-tests/tests/common/mod.rs b/end2end-tests/tests/common/mod.rs
index 24a2658321cf9eea4c6bd42aff42be6e80e90114..956a2f546b94d77a6b77f09c0eb5069226c77d77 100644
--- a/end2end-tests/tests/common/mod.rs
+++ b/end2end-tests/tests/common/mod.rs
@@ -18,6 +18,7 @@
 
 pub mod balances;
 pub mod cert;
+pub mod distance;
 pub mod identity;
 pub mod oneshot;
 
@@ -86,6 +87,7 @@ impl Process {
     }
 }
 
+pub const DISTANCE_ORACLE_LOCAL_PATH: &str = "../target/debug/distance-oracle";
 const DUNITER_DOCKER_PATH: &str = "/usr/local/bin/duniter";
 const DUNITER_LOCAL_PATH: &str = "../target/debug/duniter";
 
@@ -95,7 +97,7 @@ struct FullNode {
     ws_port: u16,
 }
 
-pub async fn spawn_node(maybe_genesis_conf_file: Option<PathBuf>) -> (Client, Process) {
+pub async fn spawn_node(maybe_genesis_conf_file: Option<PathBuf>) -> (Client, Process, u16) {
     println!("maybe_genesis_conf_file={:?}", maybe_genesis_conf_file);
     let duniter_binary_path = std::env::var("DUNITER_BINARY_PATH").unwrap_or_else(|_| {
         if std::path::Path::new(DUNITER_DOCKER_PATH).exists() {
@@ -118,7 +120,7 @@ pub async fn spawn_node(maybe_genesis_conf_file: Option<PathBuf>) -> (Client, Pr
         .await
         .expect("fail to connect to node");
 
-    (client, process)
+    (client, process, ws_port)
 }
 
 pub async fn create_empty_block(client: &Client) -> Result<()> {
@@ -174,6 +176,9 @@ fn spawn_full_node(
     let log_file_path = format!("duniter-v2s-{}.log", ws_port);
     let log_file = std::fs::File::create(&log_file_path).expect("fail to create log file");
 
+    // Clean previous data
+    std::fs::remove_dir_all("/tmp/duniter-cucumber").ok();
+
     // Command
     let process = Process(
         Command::new(duniter_binary_path)
@@ -181,13 +186,14 @@ fn spawn_full_node(
                 [
                     "--no-telemetry",
                     "--no-prometheus",
-                    "--tmp",
                     "--port",
                     &p2p_port.to_string(),
                     "--rpc-port",
                     &rpc_port.to_string(),
                     "--ws-port",
                     &ws_port.to_string(),
+                    "--base-path",
+                    "/tmp/duniter-cucumber",
                 ]
                 .iter()
                 .chain(args),
@@ -280,3 +286,20 @@ fn has_log_line(log_file_path: &str, expected_log_line: &str) -> bool {
     }
     false
 }
+
+pub fn spawn_distance_oracle(distance_oracle_binary_path: &str, duniter_rpc_port: u16) {
+    Command::new(distance_oracle_binary_path)
+        .args(
+            [
+                "-u",
+                &format!("ws://127.0.0.1:{duniter_rpc_port}"),
+                "-d",
+                "/tmp/duniter-cucumber/chains/gdev/distance",
+            ]
+            .iter(),
+        )
+        .spawn()
+        .expect("failed to spawn distance oracle")
+        .wait()
+        .unwrap();
+}
diff --git a/end2end-tests/tests/cucumber_tests.rs b/end2end-tests/tests/cucumber_tests.rs
index e0b1b2da7388a61d3ee300df0e2bd604a527b18a..49177f72cd32eb2bb5454eed3fe7eccf42ba3cca 100644
--- a/end2end-tests/tests/cucumber_tests.rs
+++ b/end2end-tests/tests/cucumber_tests.rs
@@ -120,12 +120,17 @@ impl World for DuniterWorld {
 struct DuniterWorldInner {
     client: Client,
     process: Process,
+    ws_port: u16,
 }
 
 impl DuniterWorldInner {
     async fn new(maybe_genesis_conf_file: Option<PathBuf>) -> Self {
-        let (client, process) = spawn_node(maybe_genesis_conf_file).await;
-        DuniterWorldInner { client, process }
+        let (client, process, ws_port) = spawn_node(maybe_genesis_conf_file).await;
+        DuniterWorldInner {
+            client,
+            process,
+            ws_port,
+        }
     }
     fn kill(&mut self) {
         self.process.kill();
@@ -317,11 +322,32 @@ async fn confirm_identity(world: &mut DuniterWorld, from: String, pseudo: String
 async fn validate_identity(world: &mut DuniterWorld, from: String, to: String) -> Result<()> {
     // input names to keyrings
     let from = AccountKeyring::from_str(&from).expect("unknown from");
-    let to: u32 = common::identity::get_identity_index(world, to).await?;
+    let to: u32 = common::identity::get_identity_index(world, to)
+        .await
+        .unwrap();
 
     common::identity::validate_identity(world.client(), from, to).await
 }
 
+#[when(regex = r#"([a-zA-Z]+) requests distance evaluation"#)]
+async fn request_distance_evaluation(world: &mut DuniterWorld, who: String) -> Result<()> {
+    let who = AccountKeyring::from_str(&who).expect("unknown origin");
+
+    common::distance::request_evaluation(world.client(), who).await
+}
+
+#[when(regex = r#"([a-zA-Z]+) runs distance oracle"#)]
+async fn run_distance_oracle(world: &mut DuniterWorld, who: String) -> Result<()> {
+    let who = AccountKeyring::from_str(&who).expect("unknown origin");
+
+    common::distance::run_oracle(
+        world.client(),
+        who,
+        format!("ws://127.0.0.1:{}", world.inner.as_ref().unwrap().ws_port),
+    )
+    .await
+}
+
 // ===== then ====
 
 #[then(regex = r"([a-zA-Z]+) should have (\d+) (ÄžD|cÄžD)")]
@@ -437,6 +463,67 @@ async fn should_be_certified_by(
     }
 }
 
+#[then(regex = r"([a-zA-Z]+) should have distance result in (\d+) sessions?")]
+async fn should_have_distance_result_in_sessions(
+    world: &mut DuniterWorld,
+    who: String,
+    sessions: u32,
+) -> Result<()> {
+    assert!(sessions < 3, "Session number must be < 3");
+
+    let who = AccountKeyring::from_str(&who).unwrap().to_account_id();
+
+    let idty_id = world
+        .read(&gdev::storage().identity().identity_index_of(&who))
+        .await?
+        .unwrap();
+
+    let current_session = world
+        .read(&gdev::storage().session().current_index())
+        .await?
+        .unwrap_or_default();
+
+    let pool = world
+        .read(&match (current_session + sessions) % 3 {
+            0 => gdev::storage().distance().evaluation_pool0(),
+            1 => gdev::storage().distance().evaluation_pool1(),
+            2 => gdev::storage().distance().evaluation_pool2(),
+            _ => unreachable!("n%3<3"),
+        })
+        .await
+        .unwrap()
+        .ok_or_else(|| anyhow::anyhow!("given pool is empty"))?;
+
+    for (sample_idty, _) in pool.evaluations.0 {
+        if sample_idty == idty_id {
+            return Ok(());
+        }
+    }
+
+    Err(anyhow::anyhow!("no evaluation in given pool").into())
+}
+
+#[then(regex = r"([a-zA-Z]+) should have distance ok")]
+async fn should_have_distance_ok(world: &mut DuniterWorld, who: String) -> Result<()> {
+    let who = AccountKeyring::from_str(&who).unwrap().to_account_id();
+
+    let idty_id = world
+        .read(&gdev::storage().identity().identity_index_of(&who))
+        .await?
+        .unwrap();
+
+    match world
+        .read(&gdev::storage().distance().identity_distance_status(idty_id))
+        .await?
+    {
+        Some((_, gdev::runtime_types::pallet_distance::types::DistanceStatus::Valid)) => Ok(()),
+        Some((_, gdev::runtime_types::pallet_distance::types::DistanceStatus::Pending)) => {
+            Err(anyhow::anyhow!("pending distance status").into())
+        }
+        None => Err(anyhow::anyhow!("no distance status").into()),
+    }
+}
+
 use gdev::runtime_types::pallet_identity::types::IdtyStatus;
 
 // status from string
diff --git a/node/src/service.rs b/node/src/service.rs
index 6562b6584d5066396d394da7344140c82f19b519..78b432c7be726af93ef884fc47d37f5e7b52c24f 100644
--- a/node/src/service.rs
+++ b/node/src/service.rs
@@ -31,7 +31,7 @@ use sc_service::{error::Error as ServiceError, Configuration, PartialComponents,
 use sc_telemetry::{Telemetry, TelemetryWorker};
 use sp_core::H256;
 use sp_runtime::traits::BlakeTwo256;
-use std::{sync::Arc, time::Duration};
+use std::{path::PathBuf, sync::Arc, time::Duration};
 
 type FullClient<RuntimeApi, Executor> =
     sc_service::TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>;
@@ -309,7 +309,7 @@ where
             Some(Box::new(justification_import)),
             client.clone(),
             select_chain.clone(),
-            move |_, ()| async move {
+            move |_parent, ()| async move {
                 let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
 
                 let slot =
@@ -431,6 +431,20 @@ where
 
     let mut command_sink_opt = None;
     if role.is_authority() {
+        let distance_dir = config.base_path.as_ref().map_or_else(
+            || {
+                PathBuf::from(format!(
+                    "/tmp/duniter/chains/{}/distance",
+                    config.chain_spec.id()
+                ))
+            },
+            |base_path| {
+                base_path
+                    .config_dir(config.chain_spec.id())
+                    .join("distance")
+            },
+        );
+
         let proposer_factory = sc_basic_authorship::ProposerFactory::new(
             task_manager.spawn_handle(),
             client.clone(),
@@ -439,6 +453,9 @@ where
             telemetry.as_ref().map(|x| x.handle()),
         );
 
+        let sync_cryptostore_ptr = keystore_container.sync_keystore();
+        let client = client.clone();
+
         if sealing.is_manual_consensus() {
             let commands_stream: Box<dyn Stream<Item = EngineCommand<H256>> + Send + Sync + Unpin> =
                 match sealing {
@@ -489,7 +506,6 @@ where
                 )
                 .expect("failed to create BabeConsensusDataProvider");
 
-            let client_clone = client.clone();
             task_manager.spawn_essential_handle().spawn_blocking(
                 "manual-seal",
                 Some("block-authoring"),
@@ -501,8 +517,14 @@ where
                     commands_stream,
                     select_chain,
                     consensus_data_provider: Some(Box::new(babe_consensus_data_provider)),
-                    create_inherent_data_providers: move |_, _| {
-                        let client = client_clone.clone();
+                    create_inherent_data_providers: move |parent, _| {
+                        let client = client.clone();
+                        let distance_dir = distance_dir.clone();
+                        let babe_owner_keys =
+                            std::sync::Arc::new(sp_keystore::SyncCryptoStore::sr25519_public_keys(
+                                sync_cryptostore_ptr.as_ref(),
+                                sp_runtime::KeyTypeId(*b"babe"),
+                            ));
                         async move {
                             let timestamp =
                                 manual_seal::consensus::timestamp::SlotTimestampProvider::new_babe(
@@ -512,13 +534,20 @@ where
                             let babe = sp_consensus_babe::inherents::InherentDataProvider::new(
                                 timestamp.slot(),
                             );
-                            Ok((timestamp, babe))
+                            let distance =
+                                dc_distance::create_distance_inherent_data_provider::<
+                                    Block,
+                                    FullClient<RuntimeApi, Executor>,
+                                    FullBackend,
+                                >(
+                                    &*client, parent, distance_dir, &babe_owner_keys.clone()
+                                )?;
+                            Ok((timestamp, babe, distance))
                         }
                     },
                 }),
             );
         } else {
-            let client_clone = client.clone();
             let slot_duration = babe_link.config().slot_duration();
             let babe_config = babe::BabeParams {
                 keystore: keystore_container.sync_keystore(),
@@ -529,12 +558,19 @@ where
                 sync_oracle: network.clone(),
                 justification_sync_link: network.clone(),
                 create_inherent_data_providers: move |parent, ()| {
-                    let client_clone = client_clone.clone();
+                    // This closure is called during each block generation.
+
+                    let client = client.clone();
+                    let distance_dir = distance_dir.clone();
+                    let babe_owner_keys =
+                        std::sync::Arc::new(sp_keystore::SyncCryptoStore::sr25519_public_keys(
+                            sync_cryptostore_ptr.as_ref(),
+                            sp_runtime::KeyTypeId(*b"babe"),
+                        ));
 
                     async move {
                         let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider(
-                            &*client_clone,
-                            parent,
+                            &*client, parent,
                         )?;
 
                         let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
@@ -545,7 +581,15 @@ where
                                     slot_duration,
                                 );
 
-                        Ok((slot, timestamp, uncles))
+                        let distance = dc_distance::create_distance_inherent_data_provider::<
+                            Block,
+                            FullClient<RuntimeApi, Executor>,
+                            FullBackend,
+                        >(
+                            &*client, parent, distance_dir, &babe_owner_keys.clone()
+                        )?;
+
+                        Ok((slot, timestamp, uncles, distance))
                     }
                 },
                 force_authoring,
diff --git a/pallets/README.md b/pallets/README.md
index cf67622f8be75f2895f450418ee77d468db3810d..4e229119e7a0cb4fb333f433b3eb374d1ae87b32 100644
--- a/pallets/README.md
+++ b/pallets/README.md
@@ -10,7 +10,7 @@ These pallets are at the core of Duniter/Äž1 currency
 - **`certification`** Certifications are the "edges" of Duniter's dynamic directed graph. They mean the acceptation of a Licence.
 - **`duniter-account`** Duniter customized the `AccountData` defined in the `Balances` pallet to introduce a `RandomId`.
 - **`duniter-wot`** Merges identities, membership, certifications and distance pallets to implement Duniter Web of Trust.
-- **`duniter-distance`** Offchain worker used to compute distance criterion.
+- **`distance`** Publishes median of distance computation results provided by inherents coming from `distance-oracle` workers.
 - **`identity`** Identities are the "nodes" of Duniter's dynamic directed graph. They are one-to-one mapping to human being.
 - **`membership`** Membership defines the state of identities. They can be member or not of the different WoTs.
 - **`universal-dividend`** UD is at the basis of Äž1 "libre currency". It is both a kind of "basic income" and a measure unit.
diff --git a/pallets/authority-members/src/lib.rs b/pallets/authority-members/src/lib.rs
index 1102c85e7dff2418116e8c2d449fd1fb0b75b7b5..b2387ee4423baf1eb92ec59e24cbf56ef93ad2a2 100644
--- a/pallets/authority-members/src/lib.rs
+++ b/pallets/authority-members/src/lib.rs
@@ -17,6 +17,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![allow(clippy::type_complexity)]
 
+pub mod impls;
 pub mod traits;
 mod types;
 pub mod weights;
@@ -30,17 +31,15 @@ mod tests;
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
 
-pub mod impls;
 pub use impls::*;
-
 pub use pallet::*;
+pub use sp_staking::SessionIndex;
+pub use traits::*;
 pub use types::*;
 pub use weights::WeightInfo;
 
-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..56226bf77eb34459f716c51e18332001838d5352
--- /dev/null
+++ b/pallets/distance/Cargo.toml
@@ -0,0 +1,89 @@
+[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',
+    'pallet-authority-members/std',
+    'pallet-authorship/std',
+    'pallet-identity/std',
+    'pallet-membership/std',
+    'pallet-session/std',
+    'sp-core/std',
+    'sp-distance/std',
+    'sp-runtime/std',
+    'sp-std/std',
+]
+
+[dependencies]
+
+pallet-authority-members = { path = "../authority-members", default-features = false }
+pallet-identity = { path = "../identity", default-features = false }
+pallet-membership = { path = "../membership", default-features = false }
+sp-distance = { path = "../../primitives/distance", 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.32'
+
+[dependencies.frame-system]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.pallet-authorship]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.pallet-session]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-core]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-inherents]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
diff --git a/pallets/distance/README.md b/pallets/distance/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7b34661e1a6bb99892808d29d5aa24b82a7fb4fe
--- /dev/null
+++ b/pallets/distance/README.md
@@ -0,0 +1,47 @@
+# Distance pallet
+
+The distance pallet uses results provided in a file by the `distance-oracle` offchain worker.
+At some point an inherent is called to submit the results of this file to the blockchain.
+The pallet then selects the median of the results (reach perbill) of an evaluation pool and fills the storage with the result status.
+The status of an identity can be:
+
+- inexistant: distance evaluation has not been requested or has expired
+- pending: distance evaluation for this identity has been requested and is waiting two sessions for results
+- valid: distance has been evaluated positively for this identity
+
+The result of the evaluation is used by `duniter-wot` pallet to determine if an identity can get / should loose membership to the web of trust. 
+
+## Process
+
+Any account can request a distance evaluation for a given identity provided it has enough currency to be reserved. In this case, the distance status is marked as pending and in the next session, inherents can start to publish results. 
+
+This is how a result is published:
+
+1. local worker creates a file containing the result of computation
+1. inherent is created with the data from this file
+1. author is registered as an evaluator
+1. the result is added to the current evaluation pool
+1. a flag is set to prevent other distance evaluation in the same block
+
+On each new session:
+
+1. old results set to expire at this session do expire
+1. results from the current pool (previous session's result pool) are taken and for each identity
+    - the median of the distance results for this identity is chosen
+    - if the distance is ok, the distance is marked as valid
+    - if the distance is ko, the result for this identity is removed and reserved currency is slashed (from the account which requested the evaluation)
+
+Then, in other pallets, when a membership is claimed, it is possible to look if there is a valid evaluation of distance for this identity.
+
+## Pools
+
+Evaluation pools are made of two components:
+
+- a set of evaluators
+- a vec of results
+
+The evaluation are separated in three pools (N - 2 is the session index):
+
+- pool number N - 1 % 3: results from the previous session used in the current one (let empty for next session)
+- pool number N + 0 % 3: inherent results are added there
+- pool number N + 1 % 3: identities are added there for evaluation
\ No newline at end of file
diff --git a/pallets/distance/src/lib.rs b/pallets/distance/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..45ee644be46120edc2ea2c1dac8c5dc8864a09f8
--- /dev/null
+++ b/pallets/distance/src/lib.rs
@@ -0,0 +1,461 @@
+// Copyright 2022 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 traits;
+mod types;
+
+pub use pallet::*;
+pub use traits::*;
+pub use types::*;
+
+use frame_support::traits::StorageVersion;
+use pallet_authority_members::SessionIndex;
+use sp_distance::{InherentError, INHERENT_IDENTIFIER};
+use sp_inherents::{InherentData, InherentIdentifier};
+use sp_std::convert::TryInto;
+
+type IdtyIndex = u32;
+
+/// Maximum number of identities to be evaluated in a session
+pub const MAX_EVALUATIONS_PER_SESSION: u32 = 600;
+/// Maximum number of evaluators in a session
+pub const MAX_EVALUATORS_PER_SESSION: u32 = 100;
+
+#[frame_support::pallet]
+pub mod pallet {
+    use super::*;
+    use frame_support::{pallet_prelude::*, traits::ReservableCurrency};
+    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>(PhantomData<T>);
+    #[pallet::config]
+    pub trait Config:
+        frame_system::Config
+        + pallet_authorship::Config
+        + pallet_identity::Config<IdtyIndex = IdtyIndex>
+        + pallet_session::Config
+    {
+        type Currency: ReservableCurrency<Self::AccountId>;
+        /// Amount reserved during evaluation
+        #[pallet::constant]
+        type EvaluationPrice: Get<
+            <Self::Currency as frame_support::traits::Currency<Self::AccountId>>::Balance,
+        >;
+        /// Minimum ratio of accessible referees
+        type MinAccessibleReferees: Get<Perbill>;
+        /// Number of session to keep a positive evaluation result
+        type ResultExpiration: Get<u32>;
+    }
+
+    // STORAGE //
+
+    /// Identities queued for distance evaluation
+    #[pallet::storage]
+    #[pallet::getter(fn evaluation_pool_0)]
+    pub type EvaluationPool0<T: Config> = StorageValue<
+        _,
+        EvaluationPool<
+            <T as frame_system::Config>::AccountId,
+            <T as pallet_identity::Config>::IdtyIndex,
+        >,
+        ValueQuery,
+    >;
+    /// Identities queued for distance evaluation
+    #[pallet::storage]
+    #[pallet::getter(fn evaluation_pool_1)]
+    pub type EvaluationPool1<T: Config> = StorageValue<
+        _,
+        EvaluationPool<
+            <T as frame_system::Config>::AccountId,
+            <T as pallet_identity::Config>::IdtyIndex,
+        >,
+        ValueQuery,
+    >;
+    /// Identities queued for distance evaluation
+    #[pallet::storage]
+    #[pallet::getter(fn evaluation_pool_2)]
+    pub type EvaluationPool2<T: Config> = StorageValue<
+        _,
+        EvaluationPool<
+            <T as frame_system::Config>::AccountId,
+            <T as pallet_identity::Config>::IdtyIndex,
+        >,
+        ValueQuery,
+    >;
+
+    /// Block for which the distance rule must be checked
+    #[pallet::storage]
+    pub type EvaluationBlock<T: Config> =
+        StorageValue<_, <T as frame_system::Config>::Hash, ValueQuery>;
+
+    /// Distance evaluation status by identity
+    ///
+    /// * `.0` is the account who requested an evaluation and reserved the price,
+    ///   for whom the price will be unreserved or slashed when the evaluation completes.
+    /// * `.1` is the status of the evaluation.
+    #[pallet::storage]
+    #[pallet::getter(fn identity_distance_status)]
+    pub type IdentityDistanceStatus<T: Config> = StorageMap<
+        _,
+        Twox64Concat,
+        <T as pallet_identity::Config>::IdtyIndex,
+        (<T as frame_system::Config>::AccountId, DistanceStatus),
+        OptionQuery,
+    >;
+
+    /// Identities by distance status expiration session index
+    #[pallet::storage]
+    #[pallet::getter(fn distance_status_expire_on)]
+    pub type DistanceStatusExpireOn<T: Config> = StorageMap<
+        _,
+        Twox64Concat,
+        u32,
+        BoundedVec<
+            <T as pallet_identity::Config>::IdtyIndex,
+            ConstU32<MAX_EVALUATIONS_PER_SESSION>,
+        >,
+        ValueQuery,
+    >;
+
+    /// Did evaluation get updated in this block?
+    #[pallet::storage]
+    pub(super) type DidUpdate<T: Config> = StorageValue<_, bool, ValueQuery>;
+
+    // session_index % 3:
+    //   storage_id + 0 => pending
+    //   storage_id + 1 => receives results
+    //   storage_id + 2 => receives new identities
+    // (this avoids problems for session_index < 3)
+
+    // ERRORS //
+
+    #[pallet::error]
+    pub enum Error<T> {
+        AlreadyInEvaluation,
+        CannotReserve,
+        ManyEvaluationsByAuthor,
+        ManyEvaluationsInBlock,
+        NoAuthor,
+        NoIdentity,
+        NonEligibleForEvaluation,
+        QueueFull,
+        TooManyEvaluators,
+        WrongResultLength,
+    }
+
+    #[pallet::hooks]
+    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+        /// dummy `on_initialize` to return the weight used in `on_finalize`.
+        fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
+            // weight of `on_finalize`
+            //T::WeightInfo::on_finalize()// TODO uncomment when benchmarking
+            Weight::zero()
+        }
+
+        /// # <weight>
+        /// - `O(1)`
+        /// - 1 storage deletion (codec `O(1)`).
+        /// # </weight>
+        fn on_finalize(_n: BlockNumberFor<T>) {
+            DidUpdate::<T>::take();
+        }
+    }
+
+    // CALLS //
+
+    #[pallet::call]
+    impl<T: Config> Pallet<T> {
+        /// Request an identity to be evaluated
+        #[pallet::weight(1_000_000_000)]
+        pub fn request_distance_evaluation(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
+            let who = ensure_signed(origin)?;
+
+            let idty =
+                pallet_identity::IdentityIndexOf::<T>::get(&who).ok_or(Error::<T>::NoIdentity)?;
+
+            ensure!(
+                IdentityDistanceStatus::<T>::get(idty).is_none(),
+                Error::<T>::AlreadyInEvaluation
+            );
+
+            Pallet::<T>::do_request_distance_evaluation(who, idty)?;
+            Ok(().into())
+        }
+
+        /// (Inherent) Push an evaluation result to the pool
+        #[pallet::weight(1_000_000_000)]
+        pub fn update_evaluation(
+            origin: OriginFor<T>,
+            computation_result: ComputationResult,
+        ) -> DispatchResult {
+            ensure_none(origin)?;
+            ensure!(
+                !DidUpdate::<T>::exists(),
+                Error::<T>::ManyEvaluationsInBlock,
+            );
+            let author = pallet_authorship::Pallet::<T>::author().ok_or(Error::<T>::NoAuthor)?;
+
+            Pallet::<T>::do_update_evaluation(author, computation_result)?;
+
+            DidUpdate::<T>::set(true);
+            Ok(())
+        }
+
+        /// Push an evaluation result to the pool
+        #[pallet::weight(1_000_000_000)]
+        pub fn force_update_evaluation(
+            origin: OriginFor<T>,
+            evaluator: <T as frame_system::Config>::AccountId,
+            computation_result: ComputationResult,
+        ) -> DispatchResult {
+            ensure_root(origin)?;
+
+            Pallet::<T>::do_update_evaluation(evaluator, computation_result)
+        }
+
+        /// Set the distance evaluation status of an identity
+        ///
+        /// Removes the status if `status` is `None`.
+        ///
+        /// * `status.0` is the account for whom the price will be unreserved or slashed
+        ///   when the evaluation completes.
+        /// * `status.1` is the status of the evaluation.
+        #[pallet::weight(1_000_000)]
+        pub fn force_set_distance_status(
+            origin: OriginFor<T>,
+            identity: <T as pallet_identity::Config>::IdtyIndex,
+            status: Option<(<T as frame_system::Config>::AccountId, DistanceStatus)>,
+        ) -> DispatchResult {
+            ensure_root(origin)?;
+
+            IdentityDistanceStatus::<T>::set(identity, status);
+            DistanceStatusExpireOn::<T>::mutate(
+                pallet_session::CurrentIndex::<T>::get() + T::ResultExpiration::get(),
+                move |identities| {
+                    identities
+                        .try_push(identity)
+                        .map_err(|_| Error::<T>::ManyEvaluationsInBlock.into())
+                },
+            )
+        }
+    }
+
+    // INTERNAL FUNCTIONS //
+
+    impl<T: Config> Pallet<T> {
+        /// Mutate the evaluation pool containing:
+        /// * when this session begins: the evaluation results to be applied
+        /// * when this session ends: the evaluation requests
+        fn mutate_current_pool<
+            R,
+            F: FnOnce(
+                &mut EvaluationPool<
+                    <T as frame_system::Config>::AccountId,
+                    <T as pallet_identity::Config>::IdtyIndex,
+                >,
+            ) -> R,
+        >(
+            index: SessionIndex,
+            f: F,
+        ) -> R {
+            match index % 3 {
+                0 => EvaluationPool2::<T>::mutate(f),
+                1 => EvaluationPool0::<T>::mutate(f),
+                2 => EvaluationPool1::<T>::mutate(f),
+                _ => unreachable!("index % 3 < 3"),
+            }
+        }
+        /// Mutate the evaluation pool containing the results sent by evaluators on this session.
+        fn mutate_next_pool<
+            R,
+            F: FnOnce(
+                &mut EvaluationPool<
+                    <T as frame_system::Config>::AccountId,
+                    <T as pallet_identity::Config>::IdtyIndex,
+                >,
+            ) -> R,
+        >(
+            index: SessionIndex,
+            f: F,
+        ) -> R {
+            match index % 3 {
+                0 => EvaluationPool0::<T>::mutate(f),
+                1 => EvaluationPool1::<T>::mutate(f),
+                2 => EvaluationPool2::<T>::mutate(f),
+                _ => unreachable!("index % 3 < 3"),
+            }
+        }
+
+        /// Take (and leave empty) the evaluation pool containing:
+        /// * when this session begins: the evaluation results to be applied
+        /// * when this session ends: the evaluation requests
+        #[allow(clippy::type_complexity)]
+        fn take_current_pool(
+            index: SessionIndex,
+        ) -> EvaluationPool<
+            <T as frame_system::Config>::AccountId,
+            <T as pallet_identity::Config>::IdtyIndex,
+        > {
+            match index % 3 {
+                0 => EvaluationPool2::<T>::take(),
+                1 => EvaluationPool0::<T>::take(),
+                2 => EvaluationPool1::<T>::take(),
+                _ => unreachable!("index % 3 < 3"),
+            }
+        }
+
+        fn do_request_distance_evaluation(
+            who: T::AccountId,
+            idty_index: <T as pallet_identity::Config>::IdtyIndex,
+        ) -> Result<(), DispatchError> {
+            Pallet::<T>::mutate_current_pool(
+                pallet_session::CurrentIndex::<T>::get(),
+                |current_pool| {
+                    ensure!(
+                        current_pool.evaluations.len() < (MAX_EVALUATIONS_PER_SESSION as usize),
+                        Error::<T>::QueueFull
+                    );
+
+                    T::Currency::reserve(&who, <T as Config>::EvaluationPrice::get())?;
+
+                    current_pool
+                        .evaluations
+                        .try_push((idty_index, median::MedianAcc::new()))
+                        .map_err(|_| Error::<T>::QueueFull)?;
+
+                    IdentityDistanceStatus::<T>::insert(idty_index, (who, DistanceStatus::Pending));
+
+                    DistanceStatusExpireOn::<T>::mutate(
+                        pallet_session::CurrentIndex::<T>::get() + T::ResultExpiration::get(),
+                        move |identities| identities.try_push(idty_index).ok(),
+                    );
+
+                    Ok(())
+                },
+            )
+        }
+
+        fn do_update_evaluation(
+            evaluator: <T as frame_system::Config>::AccountId,
+            computation_result: ComputationResult,
+        ) -> DispatchResult {
+            Pallet::<T>::mutate_next_pool(pallet_session::CurrentIndex::<T>::get(), |result_pool| {
+                ensure!(
+                    computation_result.distances.len() == result_pool.evaluations.len(),
+                    Error::<T>::WrongResultLength
+                );
+
+                if result_pool
+                    .evaluators
+                    .try_insert(evaluator)
+                    .map_err(|_| Error::<T>::TooManyEvaluators)?
+                {
+                    for (distance_value, (_identity, median_acc)) in computation_result
+                        .distances
+                        .into_iter()
+                        .zip(result_pool.evaluations.iter_mut())
+                    {
+                        median_acc.push(distance_value);
+                    }
+
+                    Ok(())
+                } else {
+                    Err(Error::<T>::ManyEvaluationsByAuthor.into())
+                }
+            })
+        }
+    }
+
+    impl<T: Config> pallet_authority_members::OnNewSession for Pallet<T> {
+        fn on_new_session(index: SessionIndex) -> Weight {
+            EvaluationBlock::<T>::set(frame_system::Pallet::<T>::parent_hash());
+
+            // Make results expire
+            DistanceStatusExpireOn::<T>::remove(index);
+
+            // Apply the results from the current pool (which was previous session's result pool)
+            // We take the results so the pool is left empty for the new session.
+            #[allow(clippy::type_complexity)]
+            let current_pool: EvaluationPool<
+                <T as frame_system::Config>::AccountId,
+                <T as pallet_identity::Config>::IdtyIndex,
+            > = Pallet::<T>::take_current_pool(index);
+            for (idty, median_acc) in current_pool.evaluations.into_iter() {
+                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() {
+                        IdentityDistanceStatus::<T>::mutate(idty, |entry| {
+                            entry.as_mut().map(|(account_id, status)| {
+                                T::Currency::unreserve(
+                                    account_id,
+                                    <T as Config>::EvaluationPrice::get(),
+                                );
+                                *status = DistanceStatus::Valid;
+                            })
+                        });
+                    } else if let Some((account_id, _status)) =
+                        IdentityDistanceStatus::<T>::take(idty)
+                    {
+                        <T as Config>::Currency::slash_reserved(
+                            &account_id,
+                            <T as Config>::EvaluationPrice::get(),
+                        );
+                    }
+                } else if let Some((account_id, _status)) = IdentityDistanceStatus::<T>::take(idty)
+                {
+                    <T as Config>::Currency::unreserve(
+                        &account_id,
+                        <T as Config>::EvaluationPrice::get(),
+                    );
+                }
+            }
+            Weight::zero()
+        }
+    }
+
+    #[pallet::inherent]
+    impl<T: Config> ProvideInherent for Pallet<T> {
+        type Call = Call<T>;
+        type Error = InherentError;
+
+        const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
+
+        fn create_inherent(data: &InherentData) -> Option<Self::Call> {
+            data.get_data::<ComputationResult>(&INHERENT_IDENTIFIER)
+                .expect("Distance inherent data not correctly encoded")
+                .map(|inherent_data| Call::update_evaluation {
+                    computation_result: inherent_data,
+                })
+        }
+        fn is_inherent(call: &Self::Call) -> bool {
+            matches!(call, Self::Call::update_evaluation { .. })
+        }
+    }
+}
diff --git a/pallets/distance/src/median.rs b/pallets/distance/src/median.rs
new file mode 100644
index 0000000000000000000000000000000000000000..feab0d863176a4d24e33b85856717346a1ec29a7
--- /dev/null
+++ b/pallets/distance/src/median.rs
@@ -0,0 +1,156 @@
+// Copyright 2022 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;
+
+#[derive(Clone, Debug, Decode, Default, Encode, TypeInfo)]
+pub struct MedianAcc<
+    T: Clone + Decode + Encode + Ord + TypeInfo,
+    const S: u32, /*Get<u32> + TypeInfo*/
+> {
+    samples: BoundedVec<(T, u32), ConstU32<S>>,
+    median_index: Option<u32>,
+    median_subindex: u32,
+}
+
+/*impl<T: 'static + Clone + Decode + Encode + Ord + TypeInfo, S: 'static + Get<u32>> TypeInfo
+    for MedianAcc<T, S>
+{
+    type Identity = Self;
+
+    fn type_info() -> scale_info::Type<scale_info::form::MetaForm> {}
+}*/
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum MedianResult<T: Clone + Ord> {
+    One(T),
+    Two(T, T),
+}
+
+impl<T: Clone + Decode + Encode + Ord + TypeInfo, const S: u32 /*Get<u32> + TypeInfo*/>
+    MedianAcc<T, S>
+{
+    pub fn new() -> Self {
+        Self {
+            samples: BoundedVec::default(),
+            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.try_insert(sample_index, (sample, 1)).ok();
+                    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.try_push((sample, 1)).ok();
+            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/traits.rs b/pallets/distance/src/traits.rs
new file mode 100644
index 0000000000000000000000000000000000000000..de9d532d64f4ce64a16fd20fab28455523f18e69
--- /dev/null
+++ b/pallets/distance/src/traits.rs
@@ -0,0 +1,21 @@
+// Copyright 2023 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/>.
+
+pub trait HandleNegativeEvaluation<T: crate::Config> {
+    /// Do something with the reserved amount on the account,
+    /// when distance evaluation result is negative.
+    fn handle_negative_evaluation(account_id: T::AccountId);
+}
diff --git a/pallets/distance/src/types.rs b/pallets/distance/src/types.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8a3613344fd711661fefd1ff854c3dae71b41dab
--- /dev/null
+++ b/pallets/distance/src/types.rs
@@ -0,0 +1,60 @@
+// Copyright 2022 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/>.
+
+pub use crate::{median::*, MAX_EVALUATIONS_PER_SESSION, MAX_EVALUATORS_PER_SESSION};
+pub use sp_distance::ComputationResult;
+
+use codec::{Decode, Encode};
+use frame_support::{pallet_prelude::*, BoundedBTreeSet};
+use sp_runtime::Perbill;
+
+/// Status of the distance evaluation of an identity
+#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+pub enum DistanceStatus {
+    /// Identity is in evaluation.
+    Pending,
+    /// Identity respects the distance
+    Valid,
+}
+
+/// Pool where distance evaluation requests and results are stored
+///
+/// Depending on the pool rotation, this may not be complete, and still be accepting
+/// new evaluation requests (with empty median accumulators) or new evaluations (with evaluators
+/// and new samples in the median accumulators).
+#[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo)]
+pub struct EvaluationPool<AccountId: Ord, IdtyIndex> {
+    /// List of identities with their evaluation result
+    /// The result is the median of all the evaluations.
+    pub evaluations: BoundedVec<
+        (IdtyIndex, MedianAcc<Perbill, MAX_EVALUATORS_PER_SESSION>),
+        ConstU32<MAX_EVALUATIONS_PER_SESSION>,
+    >,
+    /// Evaluators who have published a result
+    /// Its length should be the same as the number of samples
+    /// in each evaluation result `MedianAcc`.
+    /// An evaluator is not allowed to publish twice in a single session.
+    pub evaluators: BoundedBTreeSet<AccountId, ConstU32<MAX_EVALUATORS_PER_SESSION>>,
+}
+
+impl<AccountId: Ord, IdtyIndex> Default for EvaluationPool<AccountId, IdtyIndex> {
+    fn default() -> Self {
+        Self {
+            evaluations: BoundedVec::default(),
+            evaluators: BoundedBTreeSet::new(),
+        }
+    }
+}
diff --git a/pallets/duniter-wot/Cargo.toml b/pallets/duniter-wot/Cargo.toml
index 252e9e8a4c84b25e6931aeb151afab4d2bed03ae..1af0bcfa9e699f9bb1ad5b0a5eb3d33f5f4f9442 100644
--- a/pallets/duniter-wot/Cargo.toml
+++ b/pallets/duniter-wot/Cargo.toml
@@ -18,6 +18,7 @@ std = [
     'frame-system/std',
     'frame-benchmarking/std',
     'pallet-certification/std',
+    'pallet-distance/std',
     'pallet-identity/std',
     'pallet-membership/std',
     'serde',
@@ -32,11 +33,14 @@ try-runtime = ['frame-support/try-runtime']
 [dependencies]
 pallet-certification = { path = "../certification", default-features = false }
 pallet-identity = { path = "../identity", default-features = false }
+pallet-distance = { path = "../distance", default-features = false }
 pallet-membership = { path = "../membership", default-features = false }
 sp-membership = { path = "../../primitives/membership", default-features = false }
 
 # substrate
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+scale-info = { version = "2.1.1", default-features = false, features = [
+    "derive",
+] }
 
 [dependencies.codec]
 default-features = false
diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs
index 6acb51373074b306ae9ce3e301f2372bfbce8a96..832f99678139d1a5d3b6d828316730ce6921e2ad 100644
--- a/pallets/duniter-wot/src/lib.rs
+++ b/pallets/duniter-wot/src/lib.rs
@@ -25,12 +25,16 @@ mod mock;
 #[cfg(test)]
 mod tests;
 
+pub mod traits;
+
 /*#[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;*/
 
 pub use pallet::*;
 pub use types::*;
 
+use traits::*;
+
 use frame_support::dispatch::UnfilteredDispatchable;
 use frame_support::pallet_prelude::*;
 use frame_system::RawOrigin;
@@ -65,6 +69,8 @@ pub mod pallet {
             IdtyRemovalOtherReason = IdtyRemovalWotReason,
         > + pallet_membership::Config<I, IdtyId = IdtyIndex>
     {
+        /// Distance evaluation provider
+        type IsDistanceOk: IsDistanceOk<IdtyIndex>;
         #[pallet::constant]
         type FirstIssuableOn: Get<Self::BlockNumber>;
         #[pallet::constant]
@@ -247,7 +253,8 @@ impl<T: Config<I>, I: 'static> sp_membership::traits::CheckMembershipCallAllowed
     fn check_idty_allowed_to_claim_membership(idty_index: &IdtyIndex) -> Result<(), DispatchError> {
         let idty_cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index);
         ensure!(
-            idty_cert_meta.received_count >= T::MinCertForMembership::get(),
+            idty_cert_meta.received_count >= T::MinCertForMembership::get()
+                && T::IsDistanceOk::is_distance_ok(idty_index),
             Error::<T, I>::IdtyNotAllowedToClaimMembership
         );
         Ok(())
@@ -257,7 +264,8 @@ impl<T: Config<I>, I: 'static> sp_membership::traits::CheckMembershipCallAllowed
     fn check_idty_allowed_to_renew_membership(idty_index: &IdtyIndex) -> Result<(), DispatchError> {
         if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
             ensure!(
-                idty_value.status == IdtyStatus::Validated,
+                idty_value.status == IdtyStatus::Validated
+                    && T::IsDistanceOk::is_distance_ok(idty_index),
                 Error::<T, I>::IdtyNotAllowedToRenewMembership
             );
         } else {
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
index d4e95beaa905f635aabdd73d720e2a71a5617ba9..29fb7731dbd958025f893ab2b6fe5c56591283dd 100644
--- a/pallets/duniter-wot/src/mock.rs
+++ b/pallets/duniter-wot/src/mock.rs
@@ -101,6 +101,7 @@ impl pallet_duniter_wot::Config<Instance1> for Test {
     type MinCertForMembership = MinCertForMembership;
     type MinCertForCreateIdtyRight = MinCertForCreateIdtyRight;
     type FirstIssuableOn = FirstIssuableOn;
+    type IsDistanceOk = crate::traits::DistanceAlwaysOk;
 }
 
 // Identity
@@ -190,6 +191,7 @@ impl pallet_duniter_wot::Config<Instance2> for Test {
     type MinCertForMembership = SmithMinCertForMembership;
     type MinCertForCreateIdtyRight = frame_support::traits::ConstU32<0>;
     type FirstIssuableOn = SmithFirstIssuableOn;
+    type IsDistanceOk = crate::traits::DistanceAlwaysOk;
 }
 
 // SmithMembership
diff --git a/pallets/duniter-wot/src/traits.rs b/pallets/duniter-wot/src/traits.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7c3d7b220a2f46a68bfdef90e19e8420e3b5a219
--- /dev/null
+++ b/pallets/duniter-wot/src/traits.rs
@@ -0,0 +1,27 @@
+// Copyright 2023 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/>.
+
+pub trait IsDistanceOk<IdtyId> {
+    fn is_distance_ok(idty_id: &IdtyId) -> bool;
+}
+
+pub struct DistanceAlwaysOk;
+
+impl<IdtyId> IsDistanceOk<IdtyId> for DistanceAlwaysOk {
+    fn is_distance_ok(_idty_id: &IdtyId) -> bool {
+        true
+    }
+}
diff --git a/primitives/distance/Cargo.toml b/primitives/distance/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..6ee9db25137aa63893a43fbea10b8746c40c319f
--- /dev/null
+++ b/primitives/distance/Cargo.toml
@@ -0,0 +1,67 @@
+[package]
+authors = ['tuxmain <tuxmain@zettascript.org>']
+description = 'primitives for pallet distance.'
+edition = "2021"
+homepage = 'https://duniter.org'
+license = 'AGPL-3.0'
+name = 'sp-distance'
+readme = 'README.md'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '3.0.0'
+
+[features]
+default = ['std']
+std = [
+    'async-trait',
+    'codec/std',
+    'frame-support/std',
+    'serde',
+    'sp-inherents/std',
+    'sp-runtime/std',
+    'sp-std/std',
+    'thiserror'
+]
+try-runtime = ['frame-support/try-runtime']
+
+[dependencies]
+async-trait = { version = "0.1.50", optional = true }
+thiserror = { version = "1.0.30", optional = true }
+
+# 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.32'
+
+[dependencies.serde]
+version = "1.0.101"
+optional = true
+features = ["derive"]
+
+[dependencies.sp-inherents]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+branch = 'duniter-substrate-v0.9.32'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
diff --git a/primitives/distance/src/lib.rs b/primitives/distance/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9972241810489256926e309c3b3a220d991c66bd
--- /dev/null
+++ b/primitives/distance/src/lib.rs
@@ -0,0 +1,110 @@
+// Copyright 2023 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/>.
+
+//! Defines types and traits for users of pallet distance.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+#![allow(clippy::type_complexity)]
+
+use codec::{Decode, Encode};
+use frame_support::RuntimeDebug;
+use scale_info::TypeInfo;
+//#[cfg(feature = "std")]
+//use serde::{Deserialize, Serialize};
+use sp_inherents::{InherentData, InherentIdentifier, IsFatalError};
+use sp_runtime::Perbill;
+use sp_std::vec::Vec;
+#[cfg(feature = "std")]
+use std::marker::PhantomData;
+
+pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"distanc0";
+
+#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)]
+pub struct ComputationResult {
+    pub distances: Vec<Perbill>,
+}
+
+#[derive(Encode, sp_runtime::RuntimeDebug)]
+#[cfg_attr(feature = "std", derive(Decode, thiserror::Error))]
+pub enum InherentError {
+    #[cfg_attr(feature = "std", error("InvalidComputationResultFile"))]
+    InvalidComputationResultFile,
+}
+
+impl IsFatalError for InherentError {
+    fn is_fatal_error(&self) -> bool {
+        match self {
+            InherentError::InvalidComputationResultFile => false,
+        }
+    }
+}
+
+impl InherentError {
+    #[cfg(feature = "std")]
+    pub fn try_from(id: &InherentIdentifier, mut data: &[u8]) -> Option<Self> {
+        if id == &INHERENT_IDENTIFIER {
+            <InherentError as codec::Decode>::decode(&mut data).ok()
+        } else {
+            None
+        }
+    }
+}
+
+#[cfg(feature = "std")]
+pub struct InherentDataProvider<IdtyIndex: Decode + Encode + PartialEq + TypeInfo> {
+    computation_result: Option<ComputationResult>,
+    _p: PhantomData<IdtyIndex>,
+}
+
+#[cfg(feature = "std")]
+impl<IdtyIndex: Decode + Encode + PartialEq + TypeInfo> InherentDataProvider<IdtyIndex> {
+    pub fn new(computation_result: Option<ComputationResult>) -> Self {
+        Self {
+            computation_result,
+            _p: PhantomData,
+        }
+    }
+}
+
+#[cfg(feature = "std")]
+#[async_trait::async_trait]
+impl<IdtyIndex: Decode + Encode + PartialEq + TypeInfo + Send + Sync>
+    sp_inherents::InherentDataProvider for InherentDataProvider<IdtyIndex>
+{
+    fn provide_inherent_data(
+        &self,
+        inherent_data: &mut InherentData,
+    ) -> Result<(), sp_inherents::Error> {
+        if let Some(computation_result) = &self.computation_result {
+            inherent_data.put_data(INHERENT_IDENTIFIER, computation_result)?;
+        }
+        Ok(())
+    }
+
+    async fn try_handle_error(
+        &self,
+        identifier: &InherentIdentifier,
+        error: &[u8],
+    ) -> Option<Result<(), sp_inherents::Error>> {
+        if *identifier != INHERENT_IDENTIFIER {
+            return None;
+        }
+
+        Some(Err(sp_inherents::Error::Application(Box::from(
+            InherentError::try_from(&INHERENT_IDENTIFIER, error)?,
+        ))))
+    }
+}
diff --git a/resources/metadata.scale b/resources/metadata.scale
index 6c236f8d95a610f8b1044687302dd08fea17a14d..11d3bc5da37cff7bbbecf45c200e1d612b5caff4 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 4a7412e77c974df237bface000cb085222d21c18..bb74d5ea4d71688209b85da26743f615f6311027 100644
--- a/runtime/common/Cargo.toml
+++ b/runtime/common/Cargo.toml
@@ -8,11 +8,11 @@ edition = "2021"
 
 [features]
 runtime-benchmarks = [
-	"frame-benchmarking/runtime-benchmarks",
+    "frame-benchmarking/runtime-benchmarks",
     'frame-support/runtime-benchmarks',
     'frame-system-benchmarking/runtime-benchmarks',
     'frame-system/runtime-benchmarks',
-	"pallet-babe/runtime-benchmarks",
+    "pallet-babe/runtime-benchmarks",
     'pallet-balances/runtime-benchmarks',
     'pallet-certification/runtime-benchmarks',
     'pallet-collective/runtime-benchmarks',
@@ -38,6 +38,7 @@ std = [
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
+    'pallet-distance/std',
     'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
     'pallet-grandpa/std',
@@ -50,27 +51,29 @@ std = [
     'pallet-scheduler/std',
     'pallet-timestamp/std',
     'pallet-treasury/std',
-	'pallet-universal-dividend/std',
-	"serde/std",
-	"serde_derive",
+    'pallet-universal-dividend/std',
+    "serde/std",
+    "serde_derive",
     'sp-arithmetic/std',
     'sp-core/std',
+    'sp-distance/std',
     'sp-membership/std',
     'sp-runtime/std',
     'sp-std/std',
     'sp-weights/std',
 ]
 try-runtime = [
-	"frame-support/try-runtime",
-	"frame-system/try-runtime",
-	"pallet-babe/try-runtime",
-	"pallet-grandpa/try-runtime",
+    "frame-support/try-runtime",
+    "frame-system/try-runtime",
+    "pallet-babe/try-runtime",
+    "pallet-grandpa/try-runtime",
 ]
 
 [dependencies]
 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-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 }
@@ -80,12 +83,17 @@ pallet-provide-randomness = { path = '../../pallets/provide-randomness', default
 pallet-upgrade-origin = { path = '../../pallets/upgrade-origin', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
 pallet-session-benchmarking = { path = '../../pallets/session-benchmarking', default-features = false }
+sp-distance = { path = '../../primitives/distance', default-features = false }
 sp-membership = { path = '../../primitives/membership', default-features = false }
 
 # Crates.io
-codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"], default-features = false }
+codec = { package = "parity-scale-codec", version = "3.1.5", features = [
+    "derive",
+], default-features = false }
 log = { version = "0.4.14", default-features = false }
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+scale-info = { version = "2.1.1", default-features = false, features = [
+    "derive",
+] }
 serde = { version = "1.0.101", default-features = false }
 serde_derive = { version = "1.0.101", optional = true }
 smallvec = "1.6.1"
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index 95a6ccabdf9bab3144fbc8163c37e7fbac4de79a..e05a97d4fd88fbb2be9f359cee76934b324ff7b4 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -28,11 +28,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,
 {
-    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();
-        Weight::zero()
+        pallet_distance::Pallet::<Runtime>::on_new_session(index)
     }
 }
 
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index 36c0a294fc48183e8f337bc4eb35ab8d65884991..74093f6b791a008d9b0939b3654a2cb048f4d4f5 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -430,6 +430,7 @@ macro_rules! pallets_config {
         use frame_support::instances::Instance1;
         impl pallet_duniter_wot::Config<Instance1> for Runtime {
             type FirstIssuableOn = WotFirstCertIssuableOn;
+            type IsDistanceOk = common_runtime::providers::MainWotIsDistanceOk<Runtime>;
             type IsSubWot = frame_support::traits::ConstBool<false>;
             type MinCertForMembership = WotMinCertForMembership;
             type MinCertForCreateIdtyRight = WotMinCertForCreateIdtyRight;
@@ -480,12 +481,22 @@ macro_rules! pallets_config {
             type WeightInfo = common_runtime::weights::pallet_certification_cert::WeightInfo<Runtime>;
             type ValidityPeriod = ValidityPeriod;
         }
+        parameter_types! {
+            pub const MinAccessibleReferees: Perbill = Perbill::from_percent(80);
+        }
+        impl pallet_distance::Config for Runtime {
+            type Currency = Balances;
+            type EvaluationPrice = frame_support::traits::ConstU64<1000>;
+            type MinAccessibleReferees = MinAccessibleReferees;
+            type ResultExpiration = frame_support::traits::ConstU32<720>;
+        }
 
         // SMITHS SUB-WOT //
 
         use frame_support::instances::Instance2;
         impl pallet_duniter_wot::Config<Instance2> for Runtime {
             type FirstIssuableOn = SmithWotFirstCertIssuableOn;
+            type IsDistanceOk = pallet_duniter_wot::traits::DistanceAlwaysOk;
             type IsSubWot = frame_support::traits::ConstBool<true>;
             type MinCertForMembership = SmithWotMinCertForMembership;
             type MinCertForCreateIdtyRight = frame_support::traits::ConstU32<0>;
diff --git a/runtime/common/src/providers.rs b/runtime/common/src/providers.rs
index 4582513b97bc8f21a31c73f6add8fa39c78e41dc..151f70ece87da144afce3ebca0f12f04ecba6b3e 100644
--- a/runtime/common/src/providers.rs
+++ b/runtime/common/src/providers.rs
@@ -106,3 +106,18 @@ where
         }
     }
 }
+
+pub struct MainWotIsDistanceOk<T>(PhantomData<T>);
+
+impl<T> pallet_duniter_wot::traits::IsDistanceOk<<T as pallet_identity::Config>::IdtyIndex>
+    for MainWotIsDistanceOk<T>
+where
+    T: pallet_distance::Config,
+{
+    fn is_distance_ok(idty_id: &<T as pallet_identity::Config>::IdtyIndex) -> bool {
+        matches!(
+            pallet_distance::Pallet::<T>::identity_distance_status(idty_id),
+            Some((_, pallet_distance::DistanceStatus::Valid))
+        )
+    }
+}
diff --git a/runtime/g1/Cargo.toml b/runtime/g1/Cargo.toml
index 93b8f3464866b1bdce640138f2745b71094447d2..5f9c149ce3f11ecd39f5da15f9ca4a8fc31e1db2 100644
--- a/runtime/g1/Cargo.toml
+++ b/runtime/g1/Cargo.toml
@@ -43,6 +43,7 @@ std = [
     'pallet-balances/std',
     'pallet-certification/std',
     'pallet-collective/std',
+    'pallet-distance/std',
     'pallet-duniter-test-parameters/std',
     'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
@@ -113,6 +114,7 @@ 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-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 }
@@ -126,10 +128,14 @@ sp-membership = { path = '../../primitives/membership', default-features = false
 pallet-offences = { path = '../../pallets/offences', default-features = false }
 
 # crates.io
-codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"], default-features = false }
+codec = { package = "parity-scale-codec", version = "3.1.5", features = [
+    "derive",
+], default-features = false }
 log = { version = "0.4.17", default-features = false }
 hex-literal = { version = '0.3.1', optional = true }
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+scale-info = { version = "2.1.1", default-features = false, features = [
+    "derive",
+] }
 serde = { version = "1.0.101", optional = true, features = ["derive"] }
 
 # substrate
@@ -139,7 +145,7 @@ frame-executive = { git = 'https://github.com/duniter/substrate', branch = 'duni
 frame-support = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 frame-system = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 frame-system-benchmarking = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', optional = true }
-frame-system-rpc-runtime-api = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false}
+frame-system-rpc-runtime-api = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-atomic-swap = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-authority-discovery = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-authorship = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
diff --git a/runtime/g1/src/lib.rs b/runtime/g1/src/lib.rs
index fdb472726c3ee829d7d7059d740ea1ae08f3fe07..8fc21691c6326b084b6fe61096d683033d31f0ef 100644
--- a/runtime/g1/src/lib.rs
+++ b/runtime/g1/src/lib.rs
@@ -277,6 +277,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::{Pallet, Call, Storage, Inherent} = 44,
 
         // Smith Sub-Wot
         SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50,
diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml
index b5c742c89a7a2d57969662343280f4fda1f8662d..9cb9f382a7d4f7d4c703a061f101522b267f673a 100644
--- a/runtime/gdev/Cargo.toml
+++ b/runtime/gdev/Cargo.toml
@@ -50,7 +50,7 @@ runtime-benchmarks = [
 ]
 std = [
     'codec/std',
-	'common-runtime/std',
+    'common-runtime/std',
     'frame-executive/std',
     'frame-support/std',
     'frame-system-rpc-runtime-api/std',
@@ -64,6 +64,7 @@ std = [
     'pallet-balances/std',
     'pallet-certification/std',
     'pallet-collective/std',
+    'pallet-distance/std',
     'pallet-duniter-test-parameters/std',
     'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
@@ -74,10 +75,10 @@ std = [
     'pallet-provide-randomness/std',
     'pallet-im-online/std',
     'pallet-multisig/std',
-	"pallet-offences/std",
+    "pallet-offences/std",
     'pallet-preimage/std',
     'pallet-proxy/std',
-	"pallet-scheduler/std",
+    "pallet-scheduler/std",
     'pallet-session/std',
     'pallet-sudo/std',
     'pallet-universal-dividend/std',
@@ -87,14 +88,15 @@ std = [
     'pallet-transaction-payment/std',
     'pallet-treasury/std',
     'pallet-utility/std',
-	"serde/std",
-	"serde_derive",
+    "serde/std",
+    "serde_derive",
     'sp-api/std',
     'sp-arithmetic/std',
     'sp-authority-discovery/std',
     'sp-block-builder/std',
     'sp-consensus-babe/std',
     'sp-core/std',
+    'sp-distance/std',
     'sp-inherents/std',
     'sp-offchain/std',
     'sp-membership/std',
@@ -139,6 +141,7 @@ 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-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 }
@@ -150,13 +153,18 @@ pallet-provide-randomness = { path = '../../pallets/provide-randomness', default
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
 pallet-session-benchmarking = { path = '../../pallets/session-benchmarking', default-features = false }
 pallet-upgrade-origin = { path = '../../pallets/upgrade-origin', default-features = false }
+sp-distance = { path = '../../primitives/distance', default-features = false }
 sp-membership = { path = '../../primitives/membership', default-features = false }
 
 # crates.io
-codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"], default-features = false }
+codec = { package = "parity-scale-codec", version = "3.1.5", features = [
+    "derive",
+], default-features = false }
 log = { version = "0.4.17", default-features = false }
 hex-literal = { version = '0.3.1', optional = true }
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+scale-info = { version = "2.1.1", default-features = false, features = [
+    "derive",
+] }
 serde = { version = "1.0.101", default-features = false }
 serde_derive = { version = "1.0.101", optional = true }
 
@@ -165,7 +173,7 @@ frame-try-runtime = { git = 'https://github.com/duniter/substrate', branch = 'du
 frame-executive = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 frame-support = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 frame-system = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
-frame-system-rpc-runtime-api = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false}
+frame-system-rpc-runtime-api = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-atomic-swap = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-authority-discovery = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-authorship = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index dff62b247ed47614a3d3a9419493013910994b3a..67d2dde35a90468bf10781d802e37d368aeb4ad4 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -333,6 +333,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::{Pallet, Call, Storage, Inherent} = 44,
 
         // Smith Sub-Wot
         SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50,
diff --git a/runtime/gdev/tests/common/mod.rs b/runtime/gdev/tests/common/mod.rs
index 4debb039c8c5e28fd57271171869b8ee947a4258..c2d6be1f6a65c053d3dd94f7acf12ae9b4fb7479 100644
--- a/runtime/gdev/tests/common/mod.rs
+++ b/runtime/gdev/tests/common/mod.rs
@@ -22,6 +22,7 @@ use frame_support::instances::{Instance1, Instance2};
 use frame_support::traits::{GenesisBuild, OnFinalize, OnInitialize};
 use gdev_runtime::opaque::SessionKeys;
 use gdev_runtime::*;
+use pallet_authority_members::OnNewSession;
 use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
 use sp_consensus_babe::{AuthorityId as BabeId, Slot};
 use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof};
@@ -319,8 +320,9 @@ fn mock_babe_initialize(n: u32) {
 pub fn run_to_block(n: u32) {
     while System::block_number() < n {
         // Finalize the previous block
-        //Babe::on_finalize(System::block_number());
+        Babe::on_finalize(System::block_number());
         //Timestamp::on_finalize(System::block_number());
+        Distance::on_finalize(System::block_number());
         TransactionPayment::on_finalize(System::block_number());
         Authorship::on_finalize(System::block_number());
         Grandpa::on_finalize(System::block_number());
@@ -329,12 +331,22 @@ pub fn run_to_block(n: u32) {
         System::reset_events();
         System::set_block_number(System::block_number() + 1);
 
+        // Current slot is not incremented by BABE
+        pallet_babe::CurrentSlot::<Runtime>::put(pallet_babe::CurrentSlot::<Runtime>::get() + 1);
+
         // Initialize the new block
         Account::on_initialize(System::block_number());
         Scheduler::on_initialize(System::block_number());
         mock_babe_initialize(System::block_number());
-        Authorship::on_initialize(System::block_number());
         Session::on_initialize(System::block_number());
+        Authorship::on_initialize(System::block_number());
+
+        /*if session_before != session_after {
+            Distance::on_new_session(session_after);
+        } else {
+            use pallet_session::ShouldEndSession;
+            assert!(!Babe::should_end_session(System::block_number()));
+        }*/
 
         UniversalDividend::on_initialize(System::block_number());
         Wot::on_initialize(System::block_number());
@@ -346,6 +358,7 @@ pub fn run_to_block(n: u32) {
         SmithCert::on_initialize(System::block_number());
 
         Timestamp::set_timestamp(System::block_number() as u64 * BLOCK_TIME);
+        Distance::on_initialize(System::block_number());
     }
 }
 
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
index f18dbca93c2d075ec14a1e419190640dc485000b..79b29cb936850abbffd885eff40f7c8d672ca8d3 100644
--- a/runtime/gdev/tests/integration_tests.rs
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -113,7 +113,10 @@ fn test_remove_identity() {
 #[test]
 fn test_validate_identity_when_claim() {
     ExtBuilder::new(1, 3, 4)
-        .with_initial_balances(vec![(AccountKeyring::Ferdie.to_account_id(), 1000)])
+        .with_initial_balances(vec![
+            (AccountKeyring::Eve.to_account_id(), 2000),
+            (AccountKeyring::Ferdie.to_account_id(), 1000),
+        ])
         .build()
         .execute_with(|| {
             run_to_block(1);
@@ -141,6 +144,20 @@ fn test_validate_identity_when_claim() {
                 5
             ));
 
+            assert_ok!(Distance::request_distance_evaluation(
+                frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
+            ));
+
+            run_to_block(51); // Pass 2 sessions
+            assert_ok!(Distance::force_update_evaluation(
+                frame_system::RawOrigin::Root.into(),
+                AccountKeyring::Alice.to_account_id(),
+                pallet_distance::ComputationResult {
+                    distances: vec![Perbill::one()],
+                }
+            ));
+            run_to_block(76); // Pass 1 session
+
             // eve can claim her membership
             assert_ok!(Membership::claim_membership(
                 frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
@@ -181,31 +198,47 @@ fn test_membership_expiry() {
 /// test membership renewal
 #[test]
 fn test_membership_renewal() {
-    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
-        // renew at block 2
-        run_to_block(2);
-        assert_ok!(Membership::renew_membership(
-            frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
-        ));
-        System::assert_has_event(RuntimeEvent::Membership(
-            pallet_membership::Event::MembershipRenewed(1),
-        ));
+    ExtBuilder::new(1, 3, 4)
+        .with_initial_balances(vec![(AccountKeyring::Alice.to_account_id(), 2000)])
+        .build()
+        .execute_with(|| {
+            assert_ok!(Distance::request_distance_evaluation(
+                frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+            ));
 
-        // renew at block 3
-        run_to_block(3);
-        assert_ok!(Membership::renew_membership(
-            frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
-        ));
-        System::assert_has_event(RuntimeEvent::Membership(
-            pallet_membership::Event::MembershipRenewed(1),
-        ));
+            run_to_block(51); // Pass 2 sessions
+            assert_ok!(Distance::force_update_evaluation(
+                frame_system::RawOrigin::Root.into(),
+                AccountKeyring::Alice.to_account_id(),
+                pallet_distance::ComputationResult {
+                    distances: vec![Perbill::one()],
+                }
+            ));
+            run_to_block(76); // Pass 1 session
 
-        // should expire at block 103 = 3+100
-        run_to_block(103);
-        System::assert_has_event(RuntimeEvent::Membership(
-            pallet_membership::Event::MembershipExpired(1),
-        ));
-    });
+            // renew at block 76
+            assert_ok!(Membership::renew_membership(
+                frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+            ));
+            System::assert_has_event(RuntimeEvent::Membership(
+                pallet_membership::Event::MembershipRenewed(1),
+            ));
+
+            // renew at block 77
+            run_to_block(77);
+            assert_ok!(Membership::renew_membership(
+                frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+            ));
+            System::assert_has_event(RuntimeEvent::Membership(
+                pallet_membership::Event::MembershipRenewed(1),
+            ));
+
+            // should expire at block 177 = 77+100
+            run_to_block(177);
+            System::assert_has_event(RuntimeEvent::Membership(
+                pallet_membership::Event::MembershipExpired(1),
+            ));
+        });
 }
 
 // test that UD are auto claimed when identity is removed
@@ -310,6 +343,14 @@ fn test_ud_claimed_membership_on_and_off() {
         ));
 
         // alice claims back her membership
+        assert_ok!(Distance::force_set_distance_status(
+            frame_system::RawOrigin::Root.into(),
+            1,
+            Some((
+                AccountKeyring::Alice.to_account_id(),
+                pallet_distance::DistanceStatus::Valid
+            ))
+        ));
         assert_ok!(Membership::claim_membership(
             frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into()
         ));
@@ -628,6 +669,14 @@ fn test_validate_new_idty_after_few_uds() {
                 2,
                 5,
             ));
+            assert_ok!(Distance::force_set_distance_status(
+                frame_system::RawOrigin::Root.into(),
+                5,
+                Some((
+                    AccountKeyring::Bob.to_account_id(),
+                    pallet_distance::DistanceStatus::Valid
+                ))
+            ));
             assert_ok!(Identity::validate_identity(
                 frame_system::RawOrigin::Signed(AccountKeyring::Bob.to_account_id()).into(),
                 5,
@@ -646,7 +695,7 @@ fn test_validate_new_idty_after_few_uds() {
 }
 
 /// test that newly validated identity gets initialized with the next UD
-// even when the method used is membership claim
+/// even when the method used is membership claim
 #[test]
 fn test_claim_memberhsip_after_few_uds() {
     ExtBuilder::new(1, 3, 4)
@@ -654,7 +703,6 @@ fn test_claim_memberhsip_after_few_uds() {
             (AccountKeyring::Alice.to_account_id(), 1_000),
             (AccountKeyring::Bob.to_account_id(), 1_000),
             (AccountKeyring::Charlie.to_account_id(), 1_000),
-            (AccountKeyring::Eve.to_account_id(), 1_000),
         ])
         .build()
         .execute_with(|| {
@@ -682,6 +730,14 @@ fn test_claim_memberhsip_after_few_uds() {
             ));
 
             // eve should be able to claim her membership
+            assert_ok!(Distance::force_set_distance_status(
+                frame_system::RawOrigin::Root.into(),
+                5,
+                Some((
+                    AccountKeyring::Eve.to_account_id(),
+                    pallet_distance::DistanceStatus::Valid
+                ))
+            ));
             assert_ok!(Membership::claim_membership(
                 frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
             ));
diff --git a/runtime/gtest/Cargo.toml b/runtime/gtest/Cargo.toml
index 43ff07fb3b03ab3e2b01e097023a40821d00ffa6..14fce690eb32837945f11bdd61c19d33092ebb47 100644
--- a/runtime/gtest/Cargo.toml
+++ b/runtime/gtest/Cargo.toml
@@ -49,7 +49,7 @@ runtime-benchmarks = [
 ]
 std = [
     'codec/std',
-	'common-runtime/std',
+    'common-runtime/std',
     'frame-executive/std',
     'frame-support/std',
     'frame-system-rpc-runtime-api/std',
@@ -63,6 +63,7 @@ std = [
     'pallet-balances/std',
     'pallet-certification/std',
     'pallet-collective/std',
+    'pallet-distance/std',
     'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
     'pallet-grandpa/std',
@@ -72,10 +73,10 @@ std = [
     'pallet-provide-randomness/std',
     'pallet-im-online/std',
     'pallet-multisig/std',
-	"pallet-offences/std",
+    "pallet-offences/std",
     'pallet-preimage/std',
     'pallet-proxy/std',
-	"pallet-scheduler/std",
+    "pallet-scheduler/std",
     'pallet-session/std',
     'pallet-sudo/std',
     'pallet-universal-dividend/std',
@@ -85,8 +86,8 @@ std = [
     'pallet-transaction-payment/std',
     'pallet-treasury/std',
     'pallet-utility/std',
-	"serde/std",
-	"serde_derive",
+    "serde/std",
+    "serde_derive",
     'sp-api/std',
     'sp-arithmetic/std',
     'sp-authority-discovery/std',
@@ -136,6 +137,7 @@ 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-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 }
@@ -149,10 +151,14 @@ sp-membership = { path = '../../primitives/membership', default-features = false
 pallet-offences = { path = '../../pallets/offences', default-features = false }
 
 # crates.io
-codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"], default-features = false }
+codec = { package = "parity-scale-codec", version = "3.1.5", features = [
+    "derive",
+], default-features = false }
 log = { version = "0.4.17", default-features = false }
 hex-literal = { version = '0.3.1', optional = true }
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+scale-info = { version = "2.1.1", default-features = false, features = [
+    "derive",
+] }
 serde = { version = "1.0.101", default-features = false }
 serde_derive = { version = "1.0.101", optional = true }
 
@@ -161,7 +167,7 @@ frame-try-runtime = { git = 'https://github.com/duniter/substrate', branch = 'du
 frame-executive = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 frame-support = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 frame-system = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
-frame-system-rpc-runtime-api = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false}
+frame-system-rpc-runtime-api = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-atomic-swap = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-authority-discovery = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
 pallet-authorship = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.32', default-features = false }
diff --git a/runtime/gtest/src/lib.rs b/runtime/gtest/src/lib.rs
index 29ec85aae3d1b53ea59d317d444964f2cae367fd..9722455c45cdc3c48ceaba0dc9128b31cbc89a8b 100644
--- a/runtime/gtest/src/lib.rs
+++ b/runtime/gtest/src/lib.rs
@@ -293,6 +293,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::{Pallet, Call, Storage, Inherent} = 44,
 
         // Smith Sub-Wot
         SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50,