diff --git a/Cargo.lock b/Cargo.lock
index d36ea327c769176277a2048a22c802886ab28153..072734445face7a5adf2cca89ffb99c580498f1b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,7 +132,6 @@ dependencies = [
  "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -228,7 +227,6 @@ dependencies = [
 name = "duniter-core"
 version = "0.1.0-a0.1"
 dependencies = [
- "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "duniter-blockchain 0.1.0-a0.1",
  "duniter-conf 0.1.0-a0.1",
@@ -236,17 +234,13 @@ dependencies = [
  "duniter-message 0.1.0-a0.1",
  "duniter-module 0.1.0-a0.1",
  "duniter-network 0.1.0-a0.1",
- "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "simplelog 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -322,6 +316,7 @@ dependencies = [
  "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -358,6 +353,7 @@ dependencies = [
  "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -380,6 +376,7 @@ dependencies = [
  "duniter-tui 0.1.0-a0.1",
  "durs-ws2p 0.1.0-a0.1",
  "durs-ws2p-v1-legacy 0.1.0-a0.1",
+ "structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -395,6 +392,7 @@ dependencies = [
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -437,6 +435,7 @@ dependencies = [
  "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "ws 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -958,6 +957,25 @@ name = "strsim"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "structopt"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt-derive 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "syn"
 version = "0.11.11"
@@ -1177,11 +1195,6 @@ dependencies = [
  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "yaml-rust"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [metadata]
 "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
@@ -1272,6 +1285,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum sqlite3-src 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "46e0bc115b563b1ee6c665ef895b56bf488522f57d1c6571887547c57c8f5a88"
 "checksum sqlite3-sys 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71fec807a1534bd13eeaaec396175d67c79bdc68df55e18a452726ec62a8fb08"
 "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
+"checksum structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8e9ad6a11096cbecdcca0cc6aa403fdfdbaeda2fb3323a39c98e6a166a1e45a"
+"checksum structopt-derive 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4cbce8ccdc62166bd594c14396a3242bf94c337a51dbfa9be1076dd74b3db2af"
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
 "checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d"
 "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
@@ -1301,4 +1316,3 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 "checksum ws 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ccf752fee5350ca505fdb0b34d503b17d1528bd867561b7aa91d6ea750d5e972"
 "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
-"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"
diff --git a/Cargo.toml b/Cargo.toml
index 8e8d7b437b3f4ff8074a889a640bc17f4c31e09f..60a612ea17bcba1f4ea104e8e468a896ec7ab306 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,14 +7,16 @@ license = "AGPL-3.0"
 
 [dependencies]
 duniter-core = { path = "./core" }
-duniter-tui = { path = "./tui", optional = true }
 durs-ws2p = { path = "./ws2p" }
 durs-ws2p-v1-legacy = { path = "./ws2p-v1-legacy" }
+structopt= "0.2.*"
+
+[target.'cfg(unix)'.dependencies]
+duniter-tui = { path = "./tui" }
 
 [features]
-default = ["tui","ssl"]
+default = ["ssl"]
 ssl = ["durs-ws2p-v1-legacy/ssl"]
-tui = ["duniter-tui"]
 # Treat warnings as a build error.
 strict = []
 
diff --git a/blockchain/apply_valid_block.rs b/blockchain/apply_valid_block.rs
index 32f477adb347eda1c8704086ae9624cc0c2ad6a5..f731e93a41da8ffc6e86621cc5333ea33e1b0066 100644
--- a/blockchain/apply_valid_block.rs
+++ b/blockchain/apply_valid_block.rs
@@ -71,7 +71,8 @@ pub fn apply_valid_block<W: WebOfTrust>(
             wot_db
                 .write(|db| {
                     db.add_node();
-                }).expect("Fail to write in WotDB");
+                })
+                .expect("Fail to write in WotDB");
             wot_index.insert(pubkey, wotb_id);
             wot_dbs_requests.push(WotsDBsWriteQuery::CreateIdentity(
                 wotb_id,
@@ -86,7 +87,8 @@ pub fn apply_valid_block<W: WebOfTrust>(
             wot_db
                 .write(|db| {
                     db.set_enabled(wotb_id, true);
-                }).expect("Fail to write in WotDB");
+                })
+                .expect("Fail to write in WotDB");
             wot_dbs_requests.push(WotsDBsWriteQuery::RenewalIdentity(
                 joiner.issuers()[0],
                 wotb_id,
@@ -102,7 +104,8 @@ pub fn apply_valid_block<W: WebOfTrust>(
             wot_db
                 .write(|db| {
                     db.set_enabled(wotb_id, true);
-                }).expect("Fail to write in WotDB");
+                })
+                .expect("Fail to write in WotDB");
             wot_dbs_requests.push(WotsDBsWriteQuery::RenewalIdentity(
                 pubkey,
                 wotb_id,
@@ -120,7 +123,8 @@ pub fn apply_valid_block<W: WebOfTrust>(
         wot_db
             .write(|db| {
                 db.set_enabled(*wot_id, false);
-            }).expect("Fail to write in WotDB");
+            })
+            .expect("Fail to write in WotDB");
         wot_dbs_requests.push(WotsDBsWriteQuery::ExcludeIdentity(
             exclusion,
             block.blockstamp(),
@@ -136,7 +140,8 @@ pub fn apply_valid_block<W: WebOfTrust>(
         wot_db
             .write(|db| {
                 db.set_enabled(*wot_id, false);
-            }).expect("Fail to write in WotDB");
+            })
+            .expect("Fail to write in WotDB");
         wot_dbs_requests.push(WotsDBsWriteQuery::RevokeIdentity(
             compact_revoc.issuer,
             block.blockstamp(),
@@ -158,7 +163,8 @@ pub fn apply_valid_block<W: WebOfTrust>(
                         wotb_node_from.0, wotb_node_to.0, result
                     ),
                 }
-            }).expect("Fail to write in WotDB");
+            })
+            .expect("Fail to write in WotDB");
         wot_dbs_requests.push(WotsDBsWriteQuery::CreateCert(
             compact_cert.issuer,
             wotb_node_from,
@@ -182,7 +188,8 @@ pub fn apply_valid_block<W: WebOfTrust>(
                         RemLinkResult::Removed(_) => {}
                         _ => panic!("Fail to rem_link {}->{} : {:?}", source.0, target.0, result),
                     }
-                }).expect("Fail to write in WotDB");
+                })
+                .expect("Fail to write in WotDB");
         }
     }
     if let Some(du_amount) = block.dividend {
@@ -208,53 +215,53 @@ pub fn apply_valid_block<W: WebOfTrust>(
     }
 
     /*// Calculate the state of the wot
-        if !wot_events.is_empty() && verif_level != SyncVerificationLevel::FastSync() {
-            // Calculate sentries_count
-            let sentries_count = wot.get_sentries(3).len();
-            // Calculate average_density
-            let average_density = calculate_average_density::<W>(&wot);
-            let sentry_requirement =
-                get_sentry_requirement(block.members_count, G1_PARAMS.step_max);
-            // Calculate distances and connectivities
-            let (average_distance, distances, average_connectivity, connectivities) =
-                compute_distances::<W>(
-                    &wot,
-                    sentry_requirement,
-                    G1_PARAMS.step_max,
-                    G1_PARAMS.x_percent,
-                );
-            // Calculate centralities and average_centrality
-            let centralities =
-                calculate_distance_stress_centralities::<W>(&wot, G1_PARAMS.step_max);
-            let average_centrality =
-                (centralities.iter().sum::<u64>() as f64 / centralities.len() as f64) as usize;
-            // Register the state of the wot
-            let max_connectivity = currency_params.max_connectivity();
-            duniter_dal::register_wot_state(
-                db,
-                &WotState {
-                    block_number: block.number.0,
-                    block_hash: block.hash.expect("Fail to get block hash").to_string(),
-                    sentries_count,
-                    average_density,
-                    average_distance,
-                    distances,
-                    average_connectivity,
-                    connectivities: connectivities
-                        .iter()
-                        .map(|c| {
-                            if *c > max_connectivity {
-                                max_connectivity
-                            } else {
-                                *c
-                            }
-                        })
-                        .collect(),
-                    average_centrality,
-                    centralities,
-                },
+    if !wot_events.is_empty() && verif_level != SyncVerificationLevel::FastSync() {
+        // Calculate sentries_count
+        let sentries_count = wot.get_sentries(3).len();
+        // Calculate average_density
+        let average_density = calculate_average_density::<W>(&wot);
+        let sentry_requirement =
+            get_sentry_requirement(block.members_count, G1_PARAMS.step_max);
+        // Calculate distances and connectivities
+        let (average_distance, distances, average_connectivity, connectivities) =
+            compute_distances::<W>(
+                &wot,
+                sentry_requirement,
+                G1_PARAMS.step_max,
+                G1_PARAMS.x_percent,
             );
-        }*/
+        // Calculate centralities and average_centrality
+        let centralities =
+            calculate_distance_stress_centralities::<W>(&wot, G1_PARAMS.step_max);
+        let average_centrality =
+            (centralities.iter().sum::<u64>() as f64 / centralities.len() as f64) as usize;
+        // Register the state of the wot
+        let max_connectivity = currency_params.max_connectivity();
+        duniter_dal::register_wot_state(
+            db,
+            &WotState {
+                block_number: block.number.0,
+                block_hash: block.hash.expect("Fail to get block hash").to_string(),
+                sentries_count,
+                average_density,
+                average_distance,
+                distances,
+                average_connectivity,
+                connectivities: connectivities
+                    .iter()
+                    .map(|c| {
+                        if *c > max_connectivity {
+                            max_connectivity
+                        } else {
+                            *c
+                        }
+                    })
+                    .collect(),
+                average_centrality,
+                centralities,
+            },
+        );
+    }*/
     // Create DALBlock
     let mut block = block.clone();
     let previous_blockcstamp = block.previous_blockstamp();
diff --git a/blockchain/check_and_apply_block.rs b/blockchain/check_and_apply_block.rs
index 62366dd6548a25fbd6b6d7e8b4e44cafb7662834..9851bf29fcd754eb51ad09e17e4948eb86e45eff 100644
--- a/blockchain/check_and_apply_block.rs
+++ b/blockchain/check_and_apply_block.rs
@@ -155,7 +155,8 @@ pub fn check_and_apply_block<W: WebOfTrust>(
                         None,
                         false,
                         false,
-                    ).expect("duniter_dal::writers::block::write() : DALError")
+                    )
+                    .expect("duniter_dal::writers::block::write() : DALError")
                 }
                 Block::LocalBlock(block_doc) => {
                     let old_fork_id = None;
@@ -173,7 +174,8 @@ pub fn check_and_apply_block<W: WebOfTrust>(
                         old_fork_id,
                         false,
                         false,
-                    ).expect("duniter_dal::writers::block::write() : DALError")
+                    )
+                    .expect("duniter_dal::writers::block::write() : DALError")
                 }
             };
         } else {
diff --git a/blockchain/dbex.rs b/blockchain/dbex.rs
index 9c09b6aa80fe02dd308d7f103f8dcc5e920e0af8..5ee9908efa21706be19c766f7133d724c608710e 100644
--- a/blockchain/dbex.rs
+++ b/blockchain/dbex.rs
@@ -73,7 +73,7 @@ pub fn dbex_tx<DC: DuniterConf>(profile: &str, conf: &DC, _csv: bool, query: &DB
     println!(
         "Databases loaded in {}.{:03} seconds.",
         load_dbs_duration.as_secs(),
-        load_dbs_duration.subsec_nanos() / 1_000_000
+        load_dbs_duration.subsec_millis()
     );
     let req_process_begin = SystemTime::now();
     match *query {
@@ -83,7 +83,8 @@ pub fn dbex_tx<DC: DuniterConf>(profile: &str, conf: &DC, _csv: bool, query: &DB
             } else if let Some(pubkey) = duniter_dal::identity::get_pubkey_from_uid(
                 &wot_databases.identities_db,
                 address_str,
-            ).expect("get_uid : DALError")
+            )
+            .expect("get_uid : DALError")
             {
                 pubkey
             } else {
@@ -94,7 +95,8 @@ pub fn dbex_tx<DC: DuniterConf>(profile: &str, conf: &DC, _csv: bool, query: &DB
             let address_balance = duniter_dal::balance::get_address_balance(
                 &currency_databases.balances_db,
                 &address,
-            ).expect("get_address_balance : DALError")
+            )
+            .expect("get_address_balance : DALError")
             .expect("Address not found in balances DB.");
             println!(
                 "Balance={},{} Ğ1",
@@ -110,7 +112,7 @@ pub fn dbex_tx<DC: DuniterConf>(profile: &str, conf: &DC, _csv: bool, query: &DB
     println!(
         "Request processed in  {}.{:06} seconds.",
         req_process_duration.as_secs(),
-        req_process_duration.subsec_nanos() / 1_000
+        req_process_duration.subsec_micros()
     );
 }
 
@@ -129,7 +131,7 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DB
     println!(
         "Databases loaded in {}.{:03} seconds.",
         load_dbs_duration.as_secs(),
-        load_dbs_duration.subsec_nanos() / 1_000_000
+        load_dbs_duration.subsec_millis()
     );
 
     // Get currency parameters
@@ -151,7 +153,8 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DB
             db.iter()
                 .map(|(_, idty)| (idty.wot_id, String::from(idty.idty_doc.username())))
                 .collect()
-        }).expect("Fail to read IdentitiesDB !");
+        })
+        .expect("Fail to read IdentitiesDB !");
 
     // Open wot db
     let wot_db = open_wot_db::<RustyWebOfTrust>(Some(&db_path)).expect("Fail to open WotDB !");
@@ -185,10 +188,13 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DB
                                             step_max: currency_params.step_max as u32,
                                             x_percent: currency_params.x_percent,
                                         },
-                                    ).expect("Fail to get distance !"),
+                                    )
+                                    .expect("Fail to get distance !"),
                             )
-                        }).collect()
-                }).expect("Fail to read WotDB");
+                        })
+                        .collect()
+                })
+                .expect("Fail to read WotDB");
             let compute_distances_duration = SystemTime::now()
                 .duration_since(compute_distances_begin)
                 .expect("duration_since error");
@@ -215,7 +221,7 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DB
             println!(
                 "compute_distances_duration = {},{:03}.",
                 compute_distances_duration.as_secs(),
-                compute_distances_duration.subsec_nanos() / 1_000_000
+                compute_distances_duration.subsec_millis()
             );
         }
         DBExWotQuery::ExpireMembers(ref reverse) => {
@@ -231,7 +237,8 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DB
                             .map(|(block_id, dal_block)| (*block_id, dal_block.block.median_time))
                             .collect(),
                     )
-                }).expect("Fail to read blockchain db");
+                })
+                .expect("Fail to read blockchain db");
             // Get expire_dates
             let min_created_ms_time = current_bc_time - currency_params.ms_validity;
             let mut expire_dates: Vec<(NodeId, u64)> = wot_databases
@@ -250,7 +257,8 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DB
                         }
                     }
                     expire_dates
-                }).expect("Fail to read ms db");
+                })
+                .expect("Fail to read ms db");
             if *reverse {
                 expire_dates.sort_unstable_by(|(_, d1), (_, d2)| d1.cmp(&d2));
             } else {
@@ -284,7 +292,8 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DB
                                 x_percent: currency_params.x_percent,
                             },
                         )
-                    }).expect("Fail to read WotDB")
+                    })
+                    .expect("Fail to read WotDB")
                     .expect("Fail to get distance !");
                 let distance_percent: f64 =
                     f64::from(distance_datas.success) / f64::from(distance_datas.sentries) * 100.0;
@@ -301,7 +310,8 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DB
                     let source_uid = duniter_dal::identity::get_uid(
                         &wot_databases.identities_db,
                         *(wot_reverse_index[&source]),
-                    ).expect("get_uid() : DALError")
+                    )
+                    .expect("get_uid() : DALError")
                     .expect("Not found source_uid !");
                     println!("{}: {}", i + 1, source_uid);
                 }
diff --git a/blockchain/lib.rs b/blockchain/lib.rs
index 8bf1fc90f9d549f8b1cc3c6242d019277fab2c0c..82d44187b27d3de253e29bb74e21e4736c33b9a8 100644
--- a/blockchain/lib.rs
+++ b/blockchain/lib.rs
@@ -16,7 +16,7 @@
 //! Module managing the Duniter blockchain.
 
 #![cfg_attr(feature = "strict", deny(warnings))]
-#![cfg_attr(feature = "cargo-clippy", allow(duration_subsec))]
+//#![cfg_attr(feature = "cargo-clippy", allow(duration_subsec))]
 #![deny(
     missing_docs,
     missing_debug_implementations,
@@ -73,10 +73,10 @@ use duniter_dal::*;
 use duniter_documents::blockchain::v10::documents::{BlockDocument, V10Document};
 use duniter_documents::blockchain::{BlockchainProtocol, Document};
 use duniter_documents::*;
-use duniter_message::DuniterMessage;
+use duniter_message::*;
 use duniter_module::*;
 use duniter_network::{
-    NetworkBlock, NetworkDocument, NetworkEvent, NetworkRequest, NetworkResponse, NodeFullId,
+    NetworkBlock, NetworkDocument, NetworkEvent, NetworkResponse, NodeFullId, OldNetworkRequest,
 };
 use duniter_wotb::data::rusty::RustyWebOfTrust;
 use duniter_wotb::operations::distance::RustyDistanceCalculator;
@@ -94,8 +94,8 @@ pub static DISTANCE_CALCULATOR: &'static RustyDistanceCalculator = &RustyDistanc
 /// Blockchain Module
 #[derive(Debug)]
 pub struct BlockchainModule {
-    /// Subscribers
-    pub followers: Vec<mpsc::Sender<DuniterMessage>>,
+    /// Rooter sender
+    pub rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
     /// Name of the user datas profile
     pub profile: String,
     /// Currency
@@ -146,11 +146,12 @@ pub enum CompletedBlockError {
 
 impl BlockchainModule {
     /// Return module identifier
-    pub fn id() -> ModuleId {
-        ModuleId(String::from("blockchain"))
+    pub fn name() -> ModuleStaticName {
+        ModuleStaticName("blockchain")
     }
     /// Loading blockchain configuration
     pub fn load_blockchain_conf<DC: DuniterConf>(
+        rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
         profile: &str,
         conf: &DC,
         _keys: RequiredKeysContent,
@@ -183,7 +184,7 @@ impl BlockchainModule {
 
         // Instanciate BlockchainModule
         BlockchainModule {
-            followers: Vec::new(),
+            rooter_sender,
             profile: profile.to_string(),
             currency: conf.currency(),
             currency_params,
@@ -220,22 +221,22 @@ impl BlockchainModule {
         sync::sync_ts(profile, conf, db_ts_path, cautious, verif_inner_hash);
     }
     /// Request chunk from network (chunk = group of blocks)
-    fn request_chunk(&self, req_id: ModuleReqId, from: u32) -> (ModuleReqId, NetworkRequest) {
-        let req = NetworkRequest::GetBlocks(
-            ModuleReqFullId(BlockchainModule::id(), req_id),
+    fn request_chunk(&self, req_id: ModuleReqId, from: u32) -> (ModuleReqId, OldNetworkRequest) {
+        let req = OldNetworkRequest::GetBlocks(
+            ModuleReqFullId(BlockchainModule::name(), req_id),
             NodeFullId::default(),
             *CHUNK_SIZE,
             from,
         );
-        (self.request_network(&req), req)
+        (self.request_network(req_id, &req), req)
     }
     /// Requests blocks from current to `to`
     fn request_blocks_to(
         &self,
-        pending_network_requests: &HashMap<ModuleReqId, NetworkRequest>,
+        pending_network_requests: &HashMap<ModuleReqId, OldNetworkRequest>,
         current_blockstamp: &Blockstamp,
         to: BlockId,
-    ) -> HashMap<ModuleReqId, NetworkRequest> {
+    ) -> HashMap<ModuleReqId, OldNetworkRequest> {
         let mut from = if *current_blockstamp == Blockstamp::default() {
             0
         } else {
@@ -268,37 +269,36 @@ impl BlockchainModule {
         requests_ids
     }
     /// Send network request
-    fn request_network(&self, request: &NetworkRequest) -> ModuleReqId {
-        for follower in &self.followers {
-            if follower
-                .send(DuniterMessage::NetworkRequest(request.clone()))
-                .is_err()
-            {
-                debug!("BlockchainModule : one follower is unreachable !");
-            }
-        }
+    fn request_network(&self, _req_id: ModuleReqId, request: &OldNetworkRequest) -> ModuleReqId {
+        self.rooter_sender
+            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+                DursMsgReceiver::Role(ModuleRole::InterNodesNetwork),
+                DursMsgContent::OldNetworkRequest(*request),
+            )))
+            .unwrap_or_else(|_| panic!("Fail to send OldNetworkRequest to rooter"));
         request.get_req_id()
     }
     /// Send blockchain event
     fn send_event(&self, event: &DALEvent) {
-        for follower in &self.followers {
-            if follower
-                .send(DuniterMessage::DALEvent(event.clone()))
-                .is_err()
-            {
-                // Handle error
-            }
-        }
+        let module_event = match event {
+            DALEvent::StackUpValidBlock(_, _) => ModuleEvent::NewValidBlock,
+            DALEvent::RevertBlocks(_) => ModuleEvent::RevertBlocks,
+            _ => return,
+        };
+        self.rooter_sender
+            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+                DursMsgReceiver::Event(module_event),
+                DursMsgContent::DALEvent(event.clone()),
+            )))
+            .unwrap_or_else(|_| panic!("Fail to send DalEvent to rooter"));
     }
-    fn send_req_response(&self, response: &DALResponse) {
-        for follower in &self.followers {
-            if follower
-                .send(DuniterMessage::DALResponse(Box::new(response.clone())))
-                .is_err()
-            {
-                // Handle error
-            }
-        }
+    fn send_req_response(&self, requester: DursMsgReceiver, response: &DALResponse) {
+        self.rooter_sender
+            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+                requester,
+                DursMsgContent::DALResponse(Box::new(response.clone())),
+            )))
+            .unwrap_or_else(|_| panic!("Fail to send ReqRes to rooter"));
     }
     fn receive_network_documents<W: WebOfTrust>(
         &mut self,
@@ -359,7 +359,8 @@ impl BlockchainModule {
                             self.forks_states = duniter_dal::block::get_forks(
                                 &self.blocks_databases.forks_db,
                                 current_blockstamp,
-                            ).expect("get_forks() : DALError");
+                            )
+                            .expect("get_forks() : DALError");
                             save_blocks_dbs = true;
                             if !wot_dbs_reqs.is_empty() {
                                 save_wots_dbs = true;
@@ -463,7 +464,8 @@ impl BlockchainModule {
                 self.forks_states = duniter_dal::block::get_forks(
                     &self.blocks_databases.forks_db,
                     current_blockstamp,
-                ).expect("get_forks() : DALError");
+                )
+                .expect("get_forks() : DALError");
                 // Apply db requests
                 bc_db_query
                     .apply(&self.blocks_databases, false)
@@ -500,7 +502,7 @@ impl BlockchainModule {
         current_blockstamp
     }
     /// Start blockchain module.
-    pub fn start_blockchain(&mut self, blockchain_receiver: &mpsc::Receiver<DuniterMessage>) -> () {
+    pub fn start_blockchain(&mut self, blockchain_receiver: &mpsc::Receiver<DursMsg>) -> () {
         info!("BlockchainModule::start_blockchain()");
 
         // Get dbs path
@@ -523,16 +525,17 @@ impl BlockchainModule {
         // Init datas
         let mut last_get_stackables_blocks = UNIX_EPOCH;
         let mut last_request_blocks = UNIX_EPOCH;
-        let mut pending_network_requests: HashMap<ModuleReqId, NetworkRequest> = HashMap::new();
+        let mut pending_network_requests: HashMap<ModuleReqId, OldNetworkRequest> = HashMap::new();
         let mut consensus = Blockstamp::default();
 
         loop {
             // Request Consensus
-            let req = NetworkRequest::GetConsensus(ModuleReqFullId(
-                BlockchainModule::id(),
+            let req = OldNetworkRequest::GetConsensus(ModuleReqFullId(
+                BlockchainModule::name(),
                 ModuleReqId(pending_network_requests.len() as u32),
             ));
-            let req_id = self.request_network(&req);
+            let req_id =
+                self.request_network(ModuleReqId(pending_network_requests.len() as u32), &req);
             pending_network_requests.insert(req_id, req);
             // Request Blocks
             let now = SystemTime::now();
@@ -567,77 +570,80 @@ impl BlockchainModule {
                 }
             }
             match blockchain_receiver.recv_timeout(Duration::from_millis(1000)) {
-                Ok(ref message) => match *message {
-                    DuniterMessage::Followers(ref new_followers) => {
-                        info!("Blockchain module receive followers !");
-                        for new_follower in new_followers {
-                            self.followers.push(new_follower.clone());
-                        }
-                    }
-                    DuniterMessage::DALRequest(ref dal_request) => match *dal_request {
-                        DALRequest::BlockchainRequest(ref blockchain_req) => {
-                            match *blockchain_req {
-                                DALReqBlockchain::CurrentBlock(ref requester_full_id) => {
-                                    debug!("BlockchainModule : receive DALReqBc::CurrentBlock()");
+                Ok(ref message) => {
+                    match (*message).1 {
+                        DursMsgContent::Request(ref request) => {
+                            if let DursReqContent::DALRequest(ref dal_request) = request.content {
+                                match dal_request {
+                                    DALRequest::BlockchainRequest(ref blockchain_req) => {
+                                        match *blockchain_req {
+                                            DALReqBlockchain::CurrentBlock() => {
+                                                debug!("BlockchainModule : receive DALReqBc::CurrentBlock()");
 
-                                    if let Some(current_block) =
-                                        DALBlock::get_block(
-                                            &self.blocks_databases.blockchain_db,
-                                            None,
-                                            &current_blockstamp,
-                                        ).expect(
-                                            "Fatal error : get_block : fail to read LocalBlockchainV10DB !",
-                                        ) {
-                                        debug!("BlockchainModule : send_req_response(CurrentBlock({}))", current_blockstamp);
-                                        self.send_req_response(&DALResponse::Blockchain(Box::new(
-                                            DALResBlockchain::CurrentBlock(
-                                                requester_full_id.clone(),
-                                                Box::new(current_block.block),
-                                                current_blockstamp,
+                                                if let Some(current_block) =
+                                            DALBlock::get_block(
+                                                &self.blocks_databases.blockchain_db,
+                                                None,
+                                                &current_blockstamp,
+                                            ).expect(
+                                                "Fatal error : get_block : fail to read LocalBlockchainV10DB !",
+                                            ) {
+                                            debug!("BlockchainModule : send_req_response(CurrentBlock({}))", current_blockstamp);
+                                            self.send_req_response(DursMsgReceiver::One(request.requester), &DALResponse::Blockchain(Box::new(
+                                                DALResBlockchain::CurrentBlock(
+                                                    request.id,
+                                                    Box::new(current_block.block),
+                                                    current_blockstamp,
+                                                ),
+                                            )));
+                                        } else {
+                                            warn!("BlockchainModule : Req : fail to get current_block in bdd !");
+                                        }
+                                            }
+                                            DALReqBlockchain::UIDs(ref pubkeys) => {
+                                                self.send_req_response(DursMsgReceiver::One(request.requester), &DALResponse::Blockchain(Box::new(
+                                            DALResBlockchain::UIDs(
+                                                request.id,
+                                                pubkeys
+                                                    .iter()
+                                                    .map(|p| {
+                                                        (
+                                                            *p,
+                                                            duniter_dal::identity::get_uid(&self.wot_databases.identities_db, *p)
+                                                                .expect("Fatal error : get_uid : Fail to read WotV10DB !")
+                                                        )
+                                                    })
+                                                    .collect(),
                                             ),
                                         )));
-                                    } else {
-                                        warn!("BlockchainModule : Req : fail to get current_block in bdd !");
+                                            }
+                                            _ => {}
+                                        }
                                     }
+                                    DALRequest::PendingsRequest(ref _pending_req) => {}
                                 }
-                                DALReqBlockchain::UIDs(ref pubkeys) => {
-                                    self.send_req_response(&DALResponse::Blockchain(Box::new(
-                                        DALResBlockchain::UIDs(
-                                            pubkeys
-                                                .iter()
-                                                .map(|p| {
-                                                    (
-                                                        *p,
-                                                        duniter_dal::identity::get_uid(&self.wot_databases.identities_db, *p)
-                                                            .expect("Fatal error : get_uid : Fail to read WotV10DB !")
-                                                    )
-                                                })
-                                                .collect(),
-                                        ),
-                                    )));
-                                }
-                                _ => {}
                             }
                         }
-                        DALRequest::PendingsRequest(ref _pending_req) => {}
-                    },
-                    DuniterMessage::NetworkEvent(ref network_event) => match *network_event {
-                        NetworkEvent::ReceiveDocuments(ref network_docs) => {
-                            let new_current_blockstamp = self.receive_network_documents(
-                                network_docs,
-                                &current_blockstamp,
-                                &mut wotb_index,
-                                &wot_db,
-                            );
-                            current_blockstamp = new_current_blockstamp;
-                        }
-                        NetworkEvent::ReqResponse(ref network_response) => {
+                        DursMsgContent::NetworkEvent(ref network_event) => match *network_event {
+                            NetworkEvent::ReceiveDocuments(ref network_docs) => {
+                                let new_current_blockstamp = self.receive_network_documents(
+                                    network_docs,
+                                    &current_blockstamp,
+                                    &mut wotb_index,
+                                    &wot_db,
+                                );
+                                current_blockstamp = new_current_blockstamp;
+                            }
+                            NetworkEvent::ReceiveHeads(_) => {}
+                            _ => {}
+                        },
+                        DursMsgContent::NetworkResponse(ref network_response) => {
                             debug!("BlockchainModule : receive NetworkEvent::ReqResponse() !");
                             if let Some(request) =
                                 pending_network_requests.remove(&network_response.get_req_id())
                             {
                                 match request {
-                                    NetworkRequest::GetConsensus(_) => {
+                                    OldNetworkRequest::GetConsensus(_) => {
                                         if let NetworkResponse::Consensus(_, response) =
                                             *network_response.deref()
                                         {
@@ -650,11 +656,13 @@ impl BlockchainModule {
                                                     let last_dal_block_id =
                                                         BlockId(current_blockstamp.id.0 - 1);
                                                     let last_dal_block = self
-                                                        .blocks_databases
-                                                        .blockchain_db
-                                                        .read(|db| db.get(&last_dal_block_id).cloned())
-                                                        .expect("Fail to read blockchain DB.")
-                                                        .expect("Fatal error : not foutn last dal block !");
+                                                    .blocks_databases
+                                                    .blockchain_db
+                                                    .read(|db| db.get(&last_dal_block_id).cloned())
+                                                    .expect("Fail to read blockchain DB.")
+                                                    .expect(
+                                                        "Fatal error : not foutn last dal block !",
+                                                    );
                                                     revert_block::revert_block(
                                                         &last_dal_block,
                                                         &mut wotb_index,
@@ -665,12 +673,13 @@ impl BlockchainModule {
                                                             .tx_db
                                                             .read(|db| db.clone())
                                                             .expect("Fail to read TxDB."),
-                                                    ).expect("Fail to revert block");
+                                                    )
+                                                    .expect("Fail to revert block");
                                                 }
                                             }
                                         }
                                     }
-                                    NetworkRequest::GetBlocks(_, _, _, _) => {
+                                    OldNetworkRequest::GetBlocks(_, _, _, _) => {
                                         if let NetworkResponse::Chunk(_, _, ref blocks) =
                                             *network_response.deref()
                                         {
@@ -686,7 +695,8 @@ impl BlockchainModule {
                                                 self.forks_states = duniter_dal::block::get_forks(
                                                     &self.blocks_databases.forks_db,
                                                     current_blockstamp,
-                                                ).expect("get_forks() : DALError");
+                                                )
+                                                .expect("get_forks() : DALError");
                                             }
                                         }
                                     }
@@ -694,14 +704,13 @@ impl BlockchainModule {
                                 }
                             }
                         }
+                        DursMsgContent::ReceiveDocsFromClient(ref docs) => {
+                            self.receive_documents(docs);
+                        }
+                        DursMsgContent::Stop() => break,
                         _ => {}
-                    },
-                    DuniterMessage::ReceiveDocsFromClient(ref docs) => {
-                        self.receive_documents(docs);
                     }
-                    DuniterMessage::Stop() => break,
-                    _ => {}
-                },
+                }
                 Err(e) => match e {
                     mpsc::RecvTimeoutError::Disconnected => {
                         panic!("Disconnected blockchain module !");
@@ -722,7 +731,8 @@ impl BlockchainModule {
                         &self.blocks_databases.forks_db,
                         &self.blocks_databases.forks_blocks_db,
                         &current_blockstamp,
-                    ).expect("Fatal error : Fail to read ForksV10DB !");
+                    )
+                    .expect("Fatal error : Fail to read ForksV10DB !");
                     if stackable_blocks.is_empty() {
                         break;
                     } else {
@@ -781,7 +791,8 @@ impl BlockchainModule {
                                     &self.blocks_databases.forks_db,
                                     &self.blocks_databases.forks_blocks_db,
                                     stackable_block.fork_id,
-                                ).expect("delete_fork() : DALError");
+                                )
+                                .expect("delete_fork() : DALError");
                                 // Update forks states
                                 self.forks_states[stackable_block.fork_id.0] = ForkStatus::Free();
                             }
diff --git a/blockchain/revert_block.rs b/blockchain/revert_block.rs
index eabcb9f5334fa6b22f858706fe7b6f8eba780888..4ac1e0f48bebd0cfdfc1ade1033dd60e41e271cc 100644
--- a/blockchain/revert_block.rs
+++ b/blockchain/revert_block.rs
@@ -62,7 +62,8 @@ pub fn revert_block<W: WebOfTrust>(
         .map(|tx_enum| match *tx_enum {
             TxDocOrTxHash::TxHash(ref tx_hash) => txs[tx_hash].clone(),
             TxDocOrTxHash::TxDoc(ref _dal_tx) => panic!("Try to revert not reduce block !"),
-        }).collect();
+        })
+        .collect();
 
     // Revert reduce block
     block.compute_inner_hash();
@@ -108,7 +109,8 @@ pub fn revert_block<W: WebOfTrust>(
                         NewLinkResult::Ok(_) => {}
                         _ => panic!("Fail to add_link {}->{} : {:?}", source.0, target.0, result),
                     }
-                }).expect("Fail to write in WotDB");
+                })
+                .expect("Fail to write in WotDB");
             wot_dbs_requests.push(WotsDBsWriteQuery::RevertExpireCert(
                 source,
                 target,
@@ -132,7 +134,8 @@ pub fn revert_block<W: WebOfTrust>(
                         wotb_node_from.0, wotb_node_to.0, result
                     ),
                 }
-            }).expect("Fail to write in WotDB");
+            })
+            .expect("Fail to write in WotDB");
         wot_dbs_requests.push(WotsDBsWriteQuery::RevertCert(
             compact_cert,
             wotb_node_from,
@@ -151,7 +154,8 @@ pub fn revert_block<W: WebOfTrust>(
         wot_db
             .write(|db| {
                 db.set_enabled(*wot_id, false);
-            }).expect("Fail to write in WotDB");
+            })
+            .expect("Fail to write in WotDB");
         wot_dbs_requests.push(WotsDBsWriteQuery::RevertRevokeIdentity(
             compact_revoc.issuer,
             block.blockstamp(),
@@ -168,7 +172,8 @@ pub fn revert_block<W: WebOfTrust>(
         wot_db
             .write(|db| {
                 db.set_enabled(*wot_id, false);
-            }).expect("Fail to write in WotDB");
+            })
+            .expect("Fail to write in WotDB");
         wot_dbs_requests.push(WotsDBsWriteQuery::RevertExcludeIdentity(
             exclusion,
             block.blockstamp(),
@@ -187,7 +192,8 @@ pub fn revert_block<W: WebOfTrust>(
             wot_db
                 .write(|db| {
                     db.set_enabled(wotb_id, true);
-                }).expect("Fail to write in WotDB");
+                })
+                .expect("Fail to write in WotDB");
             wot_dbs_requests.push(WotsDBsWriteQuery::RevertRenewalIdentity(
                 pubkey,
                 wotb_id,
@@ -204,7 +210,8 @@ pub fn revert_block<W: WebOfTrust>(
             wot_db
                 .write(|db| {
                     db.rem_node();
-                }).expect("Fail to write in WotDB");
+                })
+                .expect("Fail to write in WotDB");
             wot_index.remove(&pubkey);
             wot_dbs_requests.push(WotsDBsWriteQuery::RevertCreateIdentity(pubkey));
         } else {
@@ -213,7 +220,8 @@ pub fn revert_block<W: WebOfTrust>(
             wot_db
                 .write(|db| {
                     db.set_enabled(wotb_id, true);
-                }).expect("Fail to write in WotDB");
+                })
+                .expect("Fail to write in WotDB");
             wot_dbs_requests.push(WotsDBsWriteQuery::RevertRenewalIdentity(
                 joiner.issuers()[0],
                 wotb_id,
diff --git a/blockchain/sync.rs b/blockchain/sync.rs
index 5fa7e31299119eb3e793738fc97f7a1a436ed07d..1bcd942b4a3c49c6809676b3f6c5474c38cc4471 100644
--- a/blockchain/sync.rs
+++ b/blockchain/sync.rs
@@ -234,7 +234,7 @@ pub fn sync_ts<DC: DuniterConf>(
         info!(
             "ts_job_duration={},{:03} seconds.",
             ts_job_duration.as_secs(),
-            ts_job_duration.subsec_nanos() / 1_000_000
+            ts_job_duration.subsec_millis()
         );
     });
 
@@ -263,6 +263,9 @@ pub fn sync_ts<DC: DuniterConf>(
     // Open blocks databases
     let databases = BlocksV10DBs::open(Some(&db_path));
 
+    // Open wot databases
+    let wot_databases = WotsV10DBs::open(Some(&db_path));
+
     // Get local current blockstamp
     debug!("Get local current blockstamp...");
     let mut current_blockstamp: Blockstamp = duniter_dal::block::get_current_blockstamp(&databases)
@@ -270,10 +273,6 @@ pub fn sync_ts<DC: DuniterConf>(
         .unwrap_or_default();
     debug!("Success to get local current blockstamp.");
 
-    // Instanciate blockchain module
-    let blockchain_module =
-        BlockchainModule::load_blockchain_conf(profile, &conf, RequiredKeysContent::None());
-
     // Node is already synchronized ?
     if target_blockstamp.id.0 < current_blockstamp.id.0 {
         println!("Your duniter-rs node is already synchronized.");
@@ -282,7 +281,7 @@ pub fn sync_ts<DC: DuniterConf>(
 
     // Get wotb index
     let mut wotb_index: HashMap<PubKey, NodeId> =
-        DALIdentity::get_wotb_index(&blockchain_module.wot_databases.identities_db)
+        DALIdentity::get_wotb_index(&wot_databases.identities_db)
             .expect("Fatal eror : get_wotb_index : Fail to read blockchain databases");
 
     // Start sync
@@ -345,32 +344,33 @@ pub fn sync_ts<DC: DuniterConf>(
         // Indexing blockchain meta datas
         info!("Indexing blockchain meta datas...");
         /*let blockchain_meta_datas: HashMap<PreviousBlockstamp, BlockHash> = databases
-            .blockchain_db
-            .read(|db| {
-                let mut blockchain_meta_datas: HashMap<
-                    PreviousBlockstamp,
-                    BlockHash,
-                > = HashMap::new();
-                for dal_block in db.values() {
-                    let block_previous_hash = if dal_block.block.number.0 == 0 {
-                        PreviousBlockstamp::default()
-                    } else {
-                        PreviousBlockstamp {
-                            id: BlockId(dal_block.block.number.0 - 1),
-                            hash: BlockHash(dal_block.block.previous_hash),
-                        }
-                    };
-                    blockchain_meta_datas
-                        .insert(block_previous_hash, dal_block.block.expect("Try to get hash of an uncompleted or reduce block !"));
-                }
+        .blockchain_db
+        .read(|db| {
+            let mut blockchain_meta_datas: HashMap<
+                PreviousBlockstamp,
+                BlockHash,
+            > = HashMap::new();
+            for dal_block in db.values() {
+                let block_previous_hash = if dal_block.block.number.0 == 0 {
+                    PreviousBlockstamp::default()
+                } else {
+                    PreviousBlockstamp {
+                        id: BlockId(dal_block.block.number.0 - 1),
+                        hash: BlockHash(dal_block.block.previous_hash),
+                    }
+                };
                 blockchain_meta_datas
-            })
-            .expect("Indexing blockchain meta datas : DALError");*/
+                    .insert(block_previous_hash, dal_block.block.expect("Try to get hash of an uncompleted or reduce block !"));
+            }
+            blockchain_meta_datas
+        })
+        .expect("Indexing blockchain meta datas : DALError");*/
         databases
             .forks_db
             .write(|db| {
                 db.insert(ForkId(0), blockchain_meta_datas);
-            }).expect("Indexing blockchain meta datas : DALError");
+            })
+            .expect("Indexing blockchain meta datas : DALError");
 
         // Increment progress bar (last chunk)
         apply_pb.inc();
@@ -387,7 +387,7 @@ pub fn sync_ts<DC: DuniterConf>(
         info!(
             "blocks_job_duration={},{:03} seconds.",
             blocks_job_duration.as_secs(),
-            blocks_job_duration.subsec_nanos() / 1_000_000
+            blocks_job_duration.subsec_millis()
         );
     });
 
@@ -429,7 +429,7 @@ pub fn sync_ts<DC: DuniterConf>(
         info!(
             "wot_job_duration={},{:03} seconds.",
             wot_job_duration.as_secs(),
-            wot_job_duration.subsec_nanos() / 1_000_000
+            wot_job_duration.subsec_millis()
         );
     });
 
@@ -466,7 +466,7 @@ pub fn sync_ts<DC: DuniterConf>(
         info!(
             "tx_job_duration={},{:03} seconds.",
             tx_job_duration.as_secs(),
-            tx_job_duration.subsec_nanos() / 1_000_000
+            tx_job_duration.subsec_millis()
         );
     });
     let main_job_begin = SystemTime::now();
@@ -505,7 +505,8 @@ pub fn sync_ts<DC: DuniterConf>(
                     .write(|db| {
                         db.0 = block_doc.currency.clone();
                         db.1 = block_doc.parameters.unwrap();
-                    }).expect("fail to write in params DB");
+                    })
+                    .expect("fail to write in params DB");
                 currency_params = CurrencyParameters::from((
                     block_doc.currency.clone(),
                     block_doc.parameters.unwrap(),
@@ -568,13 +569,15 @@ pub fn sync_ts<DC: DuniterConf>(
                                 db.get(&created_block_id).cloned().unwrap_or_default();
                             created_certs.insert((*source, *target));
                             db.insert(*created_block_id, created_certs);
-                        }).expect("RustBreakError : please reset data and resync !");
+                        })
+                        .expect("RustBreakError : please reset data and resync !");
                 }
                 sender_wot_thread
                     .send(SyncJobsMess::WotsDBsWriteQuery(
                         req.clone(),
                         Box::new(currency_params),
-                    )).expect(
+                    ))
+                    .expect(
                         "Fail to communicate with tx worker thread, please reset data & resync !",
                     )
             }
@@ -628,17 +631,17 @@ pub fn sync_ts<DC: DuniterConf>(
     info!(
         "main_job_duration={},{:03} seconds.",
         main_job_duration.as_secs(),
-        main_job_duration.subsec_nanos() / 1_000_000
+        main_job_duration.subsec_millis()
     );
     info!(
         "all_complete_block_duration={},{:03} seconds.",
         all_complete_block_duration.as_secs(),
-        all_complete_block_duration.subsec_nanos() / 1_000_000
+        all_complete_block_duration.subsec_millis()
     );
     info!(
         "all_apply_valid_block_duration={},{:03} seconds.",
         all_apply_valid_block_duration.as_secs(),
-        all_apply_valid_block_duration.subsec_nanos() / 1_000_000
+        all_apply_valid_block_duration.subsec_millis()
     );
 
     // Wait recv two finish signals
@@ -659,12 +662,12 @@ pub fn sync_ts<DC: DuniterConf>(
         "Sync {} blocks in {}.{:03} seconds.",
         current_blockstamp.id.0 + 1,
         sync_duration.as_secs(),
-        sync_duration.subsec_nanos() / 1_000_000,
+        sync_duration.subsec_millis(),
     );
     info!(
         "Sync {} blocks in {}.{:03} seconds.",
         current_blockstamp.id.0 + 1,
         sync_duration.as_secs(),
-        sync_duration.subsec_nanos() / 1_000_000,
+        sync_duration.subsec_millis(),
     );
 }
diff --git a/blockchain/ts_parsers.rs b/blockchain/ts_parsers.rs
index 27782b1cbcbe1db3d066d8a8bc6f9ce5fb2376db..e41c1f009fd4b4bed8e0155f957e8acf4d5706f4 100644
--- a/blockchain/ts_parsers.rs
+++ b/blockchain/ts_parsers.rs
@@ -47,7 +47,8 @@ pub fn parse_ts_block(row: &[sqlite::Value]) -> NetworkBlock {
         issuer: PubKey::Ed25519(
             ed25519::PublicKey::from_base58(
                 row[4].as_string().expect("Fail to parse block issuer"),
-            ).expect("Failt to parse block issuer (2)"),
+            )
+            .expect("Failt to parse block issuer (2)"),
         ),
     };
     let previous_header = if current_header.number.0 > 0 {
@@ -58,14 +59,16 @@ pub fn parse_ts_block(row: &[sqlite::Value]) -> NetworkBlock {
                     row[6]
                         .as_string()
                         .expect("Fail to parse block previous hash"),
-                ).expect("Fail to parse block previous hash (2)"),
+                )
+                .expect("Fail to parse block previous hash (2)"),
             ),
             issuer: PubKey::Ed25519(
                 ed25519::PublicKey::from_base58(
                     row[7]
                         .as_string()
                         .expect("Fail to parse previous block issuer"),
-                ).expect("Fail to parse previous block issuer (2)"),
+                )
+                .expect("Fail to parse previous block issuer (2)"),
             ),
         })
     } else {
@@ -157,17 +160,20 @@ pub fn parse_ts_block(row: &[sqlite::Value]) -> NetworkBlock {
             currency,
             MembershipType::In(),
             row[21].as_string().expect("Fail to parse joiners"),
-        ).expect("Fail to parse joiners (2)"),
+        )
+        .expect("Fail to parse joiners (2)"),
         actives: parse_memberships(
             currency,
             MembershipType::In(),
             row[22].as_string().expect("Fail to parse actives"),
-        ).expect("Fail to parse actives (2)"),
+        )
+        .expect("Fail to parse actives (2)"),
         leavers: parse_memberships(
             currency,
             MembershipType::In(),
             row[23].as_string().expect("Fail to parse leavers"),
-        ).expect("Fail to parse leavers (2)"),
+        )
+        .expect("Fail to parse leavers (2)"),
         revoked: Vec::new(),
         excluded: excluded
             .as_array()
@@ -178,9 +184,11 @@ pub fn parse_ts_block(row: &[sqlite::Value]) -> NetworkBlock {
                 PubKey::Ed25519(
                     ed25519::PublicKey::from_base58(
                         e.as_str().expect("Fail to parse excluded (4)"),
-                    ).expect("Fail to parse excluded (5)"),
+                    )
+                    .expect("Fail to parse excluded (5)"),
                 )
-            }).collect(),
+            })
+            .collect(),
         certifications: Vec::new(),
         transactions,
         inner_hash_and_nonce_str: String::new(),
@@ -250,11 +258,13 @@ pub fn parse_memberships(
                 currency,
                 membership_type,
                 raw_memberships.as_array().unwrap(),
-            ).iter()
+            )
+            .iter()
             .map(|m| {
                 m.clone()
                     .expect("Fatal error : Fail to parse membership from local DB !")
-            }).collect(),
+            })
+            .collect(),
         );
     }
     None
@@ -288,7 +298,8 @@ pub fn parse_memberships_from_json_value(
             } else {
                 Err(MembershipParseError::WrongFormat())
             }
-        }).collect()
+        })
+        .collect()
 }
 
 /// Parse transaction from json value
@@ -343,7 +354,8 @@ pub fn parse_transaction(
                 output
                     .as_str()
                     .unwrap_or_else(|| panic!("Fail to parse output : {:?}", output)),
-            ).unwrap_or_else(|_| panic!("Fail to parse output : {:?}", output)),
+            )
+            .unwrap_or_else(|_| panic!("Fail to parse output : {:?}", output)),
         );
     }
     let signatures_array = source.get("signatures")?.as_array()?;
diff --git a/conf/lib.rs b/conf/lib.rs
index c75889d29c18fcc4935722e5373c53c81800a859..3b3125380abbc4bef72cfc4c42f4d6c775e69d3c 100644
--- a/conf/lib.rs
+++ b/conf/lib.rs
@@ -42,7 +42,7 @@ extern crate rand;
 extern crate serde;
 use duniter_crypto::keys::*;
 use duniter_documents::CurrencyName;
-use duniter_module::{DuniterConf, ModuleId, RequiredKeys, RequiredKeysContent};
+use duniter_module::{DuniterConf, ModuleName, RequiredKeys, RequiredKeysContent};
 use rand::Rng;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 use std::collections::HashSet;
@@ -62,9 +62,9 @@ pub enum ChangeGlobalConf {
     /// Change currency
     ChangeCurrency(CurrencyName),
     /// Disable module
-    DisableModule(ModuleId),
+    DisableModule(ModuleName),
     /// Enable module
-    EnableModule(ModuleId),
+    EnableModule(ModuleName),
     /// None
     None(),
 }
@@ -79,9 +79,9 @@ pub struct DuRsConfV1 {
     /// Configuration of modules in json format (obtained from the conf.json file)
     pub modules: serde_json::Value,
     /// Disabled modules
-    pub disabled: HashSet<ModuleId>,
+    pub disabled: HashSet<ModuleName>,
     /// Enabled modules
-    pub enabled: HashSet<ModuleId>,
+    pub enabled: HashSet<ModuleName>,
 }
 
 impl Default for DuRsConfV1 {
@@ -136,7 +136,7 @@ impl DuniterConf for DuRsConf {
             _ => panic!("Fail to load duniter conf : conf version not supported !"),
         }
     }
-    fn disable(&mut self, module: ModuleId) {
+    fn disable(&mut self, module: ModuleName) {
         match *self {
             DuRsConf::V1(ref mut conf_v1) => {
                 conf_v1.disabled.insert(module.clone());
@@ -145,7 +145,7 @@ impl DuniterConf for DuRsConf {
             _ => panic!("Fail to load duniter conf : conf version not supported !"),
         }
     }
-    fn enable(&mut self, module: ModuleId) {
+    fn enable(&mut self, module: ModuleName) {
         match *self {
             DuRsConf::V1(ref mut conf_v1) => {
                 conf_v1.disabled.remove(&module);
@@ -154,13 +154,13 @@ impl DuniterConf for DuRsConf {
             _ => panic!("Fail to load duniter conf : conf version not supported !"),
         }
     }
-    fn disabled_modules(&self) -> HashSet<ModuleId> {
+    fn disabled_modules(&self) -> HashSet<ModuleName> {
         match *self {
             DuRsConf::V1(ref conf_v1) => conf_v1.disabled.clone(),
             _ => panic!("Fail to load duniter conf : conf version not supported !"),
         }
     }
-    fn enabled_modules(&self) -> HashSet<ModuleId> {
+    fn enabled_modules(&self) -> HashSet<ModuleName> {
         match *self {
             DuRsConf::V1(ref conf_v1) => conf_v1.enabled.clone(),
             _ => panic!("Fail to load duniter conf : conf version not supported !"),
@@ -172,6 +172,25 @@ impl DuniterConf for DuRsConf {
             _ => panic!("Fail to load duniter conf : conf version not supported !"),
         }
     }
+    fn set_module_conf(&mut self, module_id: String, new_module_conf: serde_json::Value) {
+        match *self {
+            DuRsConf::V1(ref mut conf_v1) => {
+                if conf_v1.modules.is_null() {
+                    let mut new_modules_conf = serde_json::Map::with_capacity(1);
+                    new_modules_conf.insert(module_id, new_module_conf);
+                    conf_v1.modules = serde_json::value::to_value(new_modules_conf)
+                        .expect("Fail to create map of new modules conf !");
+                } else {
+                    conf_v1
+                        .modules
+                        .as_object_mut()
+                        .expect("Conf file currupted !")
+                        .insert(module_id, new_module_conf);
+                }
+            }
+            _ => panic!("Fail to set duniter conf : conf version not supported !"),
+        }
+    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 550ca8c00b9b808ddf00f82942006c66f00aa3c9..c811e362203ed761a5d50a51ac18a535304285ab 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -9,7 +9,6 @@ license = "AGPL-3.0"
 path = "lib.rs"
 
 [dependencies]
-clap = {version = "2.31.2", features = ["yaml"]}
 dirs = "1.0.2"
 duniter-blockchain = { path = "../blockchain" }
 duniter-conf = { path = "../conf" }
@@ -17,17 +16,13 @@ duniter-crypto = { path = "../crypto" }
 duniter-message =  { path = "../message" }
 duniter-module = { path = "../module" }
 duniter-network = { path = "../network" }
-lazy_static = "1.0.*"
 log = "0.4.*"
 log-panics = "2.0.*"
-rand = "0.4.*"
-regex = "1.0.*"
-rust-crypto = "0.2.*"
 serde = "1.0.*"
 serde_derive = "1.0.*"
 serde_json = "1.0.*"
 simplelog = "0.5.*"
-sqlite = "0.23.*"
+structopt= "0.2.*"
 threadpool = "1.7.*"
 
 [features]
diff --git a/core/cli/dbex.rs b/core/cli/dbex.rs
new file mode 100644
index 0000000000000000000000000000000000000000..180f204dbed8bc55e9cc094d7a93dc00b865d7f8
--- /dev/null
+++ b/core/cli/dbex.rs
@@ -0,0 +1,95 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program 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, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Durs-core cli : dbex subcommands.
+
+extern crate structopt;
+
+#[derive(StructOpt, Debug, Clone)]
+#[structopt(
+    name = "dbex",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// durs databases explorer
+pub struct DbExOpt {
+    #[structopt(short = "c", long = "csv")]
+    /// csv output
+    pub csv: bool,
+    #[structopt(subcommand)]
+    /// DbExSubCommand
+    pub subcommand: DbExSubCommand,
+}
+
+#[derive(StructOpt, Debug, Clone)]
+/// dbex subcommands
+pub enum DbExSubCommand {
+    #[structopt(
+        name = "distance",
+        raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+    )]
+    /// durs databases explorer (distances datas)
+    DistanceOpt(DistanceOpt),
+    #[structopt(
+        name = "members",
+        raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+    )]
+    /// durs databases explorer (members datas)
+    MembersOpt(MembersOpt),
+    #[structopt(
+        name = "member",
+        raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+    )]
+    /// durs databases explorer (member datas)
+    MemberOpt(MemberOpt),
+    #[structopt(
+        name = "balance",
+        raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+    )]
+    /// durs databases explorer (balances datas)
+    BalanceOpt(BalanceOpt),
+}
+
+#[derive(StructOpt, Debug, Copy, Clone)]
+/// DistanceOpt
+pub struct DistanceOpt {
+    #[structopt(short = "r", long = "reverse")]
+    /// reverse order
+    pub reverse: bool,
+}
+
+#[derive(StructOpt, Debug, Copy, Clone)]
+/// MembersOpt
+pub struct MembersOpt {
+    #[structopt(short = "r", long = "reverse")]
+    /// reverse order
+    pub reverse: bool,
+    #[structopt(short = "e", long = "expire")]
+    /// show members expire date
+    pub expire: bool,
+}
+
+#[derive(StructOpt, Debug, Clone)]
+/// MemberOpt
+pub struct MemberOpt {
+    /// choose member uid
+    pub uid: String,
+}
+
+#[derive(StructOpt, Debug, Clone)]
+/// BalanceOpt
+pub struct BalanceOpt {
+    /// public key or uid
+    pub address: String,
+}
diff --git a/core/cli/mod.rs b/core/cli/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..268211e6518df045c9577fe0135eef36c801fdc6
--- /dev/null
+++ b/core/cli/mod.rs
@@ -0,0 +1,109 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program 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, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Define durs-core cli subcommands options.
+
+extern crate structopt;
+
+pub mod dbex;
+pub mod modules;
+pub mod reset;
+pub mod start;
+pub mod sync;
+
+pub use dbex::*;
+use log::Level;
+pub use modules::*;
+pub use reset::*;
+pub use start::*;
+pub use sync::*;
+
+/*/// Inject core subcommands
+pub fn inject_core_subcommands<'a, 'b>(
+    core_cli_conf_without_subcommands: App<'a, 'b>,
+) -> App<'a, 'b> {
+    core_cli_conf_without_subcommands.subcommands(vec![
+        EnableOpt::clap(),
+        DisableOpt::clap(),
+        ListModulesOpt::clap(),
+        StartOpt::clap(),
+        SyncOpt::clap(),
+        SyncTsOpt::clap(),
+    ])
+}*/
+
+#[derive(StructOpt, Debug)]
+#[structopt(
+    name = "durs",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// Rust implementation of Duniter
+pub struct DursOpt {
+    #[structopt(short = "p", long = "profile")]
+    /// Set a custom user datas folder
+    profile_name: Option<String>,
+    #[structopt(short = "l", long = "logs", raw(next_line_help = "true"))]
+    /// Set the level of logs verbosity. (Default is INFO).
+    /// Possible values : [OFF, ERROR, WARN, INFO, DEBUG, TRACE]
+    logs_level: Option<Level>,
+    #[structopt(subcommand)]
+    /// CoreSubCommand
+    cmd: CoreSubCommand,
+}
+
+#[derive(StructOpt, Debug)]
+/// Core cli subcommands
+pub enum CoreSubCommand {
+    #[structopt(name = "enable")]
+    /// Enable some module
+    EnableOpt(EnableOpt),
+    #[structopt(name = "disable")]
+    /// Disable some module
+    DisableOpt(DisableOpt),
+    #[structopt(name = "modules")]
+    /// list modules
+    ListModulesOpt(ListModulesOpt),
+    #[structopt(name = "start")]
+    /// start durs server
+    StartOpt(StartOpt),
+    #[structopt(name = "sync")]
+    /// synchronization from network
+    SyncOpt(SyncOpt),
+    #[structopt(name = "sync_ts")]
+    /// synchronization via a duniter-ts database
+    SyncTsOpt(SyncTsOpt),
+    /// reset data or conf or all
+    #[structopt(
+        name = "reset",
+        raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+    )]
+    ResetOpt(ResetOpt),
+    /// durs databases explorer
+    #[structopt(
+        name = "dbex",
+        raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+    )]
+    DbExOpt(DbExOpt),
+}
+
+/// InvalidInput
+#[derive(Debug, Copy, Clone)]
+pub struct InvalidInput(&'static str);
+
+impl ToString for InvalidInput {
+    fn to_string(&self) -> String {
+        String::from(self.0)
+    }
+}
diff --git a/core/cli/modules.rs b/core/cli/modules.rs
new file mode 100644
index 0000000000000000000000000000000000000000..258aad17657b4a019b6a392eae78b54575faaec1
--- /dev/null
+++ b/core/cli/modules.rs
@@ -0,0 +1,86 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program 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, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Durs-core cli : modules manager subcommands.
+
+extern crate structopt;
+
+use duniter_module::*;
+use std::collections::HashSet;
+
+#[derive(StructOpt, Debug)]
+#[structopt(
+    name = "enable",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// Enable some module
+pub struct EnableOpt {
+    #[structopt(parse(from_str))]
+    /// The module name to enable
+    pub module_name: ModuleName,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(
+    name = "disable",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// Disable some module
+pub struct DisableOpt {
+    #[structopt(parse(from_str))]
+    /// The module name to disable
+    pub module_name: ModuleName,
+}
+
+#[derive(StructOpt, Debug, Copy, Clone)]
+#[structopt(
+    name = "modules",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// list module
+pub struct ListModulesOpt {
+    #[structopt(short = "d")]
+    /// list only disabled modules
+    pub disabled: bool,
+    #[structopt(short = "e")]
+    /// list only enabled modules
+    pub enabled: bool,
+    #[structopt(short = "n")]
+    /// list only network modules
+    pub network: bool,
+    #[structopt(short = "s")]
+    /// list only modules having access to the secret member key
+    pub secret: bool,
+}
+
+impl ListModulesOpt {
+    /// Extract modules filters from cli options
+    pub fn get_filters(self) -> HashSet<ModulesFilter> {
+        let mut filters = HashSet::with_capacity(4);
+        if self.disabled {
+            filters.insert(ModulesFilter::Enabled(false));
+        }
+        if self.enabled {
+            filters.insert(ModulesFilter::Enabled(true));
+        }
+        if self.network {
+            filters.insert(ModulesFilter::Network());
+        }
+        if self.secret {
+            filters.insert(ModulesFilter::RequireMemberPrivKey());
+        }
+        filters
+    }
+}
diff --git a/core/cli/reset.rs b/core/cli/reset.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0b112cf2a72112f60ade1af1266667db84937fe5
--- /dev/null
+++ b/core/cli/reset.rs
@@ -0,0 +1,52 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program 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, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Durs-core cli : reset subcommand.
+
+extern crate structopt;
+
+use cli::InvalidInput;
+use std::str::FromStr;
+
+#[derive(StructOpt, Debug, Copy, Clone)]
+/// start durs server
+pub struct ResetOpt {
+    /// choose type datas to reset
+    pub reset_type: ResetType,
+}
+
+#[derive(Debug, Copy, Clone)]
+/// Reset type
+pub enum ResetType {
+    /// Reset datas
+    Datas,
+    /// Reset configuration
+    Conf,
+    /// Reset all
+    All,
+}
+
+impl FromStr for ResetType {
+    type Err = InvalidInput;
+
+    fn from_str(source: &str) -> Result<Self, Self::Err> {
+        match source {
+            "data" => Ok(ResetType::Datas),
+            "conf" => Ok(ResetType::Conf),
+            "all" => Ok(ResetType::All),
+            _ => Err(InvalidInput("Values accepted are : data, conf, all.")),
+        }
+    }
+}
diff --git a/core/cli/start.rs b/core/cli/start.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4d9528594aaf0b7972093a23de7ed2672f162626
--- /dev/null
+++ b/core/cli/start.rs
@@ -0,0 +1,26 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program 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, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Durs-core cli : start subcommands.
+
+extern crate structopt;
+
+#[derive(StructOpt, Debug, Copy, Clone)]
+#[structopt(
+    name = "start",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// start durs server
+pub struct StartOpt {}
diff --git a/core/cli/sync.rs b/core/cli/sync.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d462e2d64705ee6af15fe07cccb2b886e2a38b61
--- /dev/null
+++ b/core/cli/sync.rs
@@ -0,0 +1,56 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program 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, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Durs-core cli : sync subcommands.
+
+extern crate structopt;
+
+#[derive(StructOpt, Debug, Clone)]
+#[structopt(
+    name = "sync",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// synchronization from network
+pub struct SyncOpt {
+    /// The domain name or ip address of the node from which to synchronize.
+    pub host: String,
+    /// The port number of the node from which to synchronize.
+    pub port: u16,
+    /// The endpoint path of the node from which to synchronize.
+    pub path: Option<String>,
+    #[structopt(short = "c", long = "cautious")]
+    /// cautious mode (check all protocol rules, very slow)
+    pub cautious_mode: bool,
+    #[structopt(short = "u", long = "unsafe")]
+    /// unsafe mode (not check blocks inner hashs, very dangerous)
+    pub unsafe_mode: bool,
+}
+
+#[derive(StructOpt, Debug, Clone)]
+#[structopt(
+    name = "sync",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// synchronization via a duniter-ts database
+pub struct SyncTsOpt {
+    /// Set the ts profile to use
+    pub ts_profile: Option<String>,
+    #[structopt(short = "c", long = "cautious")]
+    /// cautious mode (check all protocol rules, very slow)
+    pub cautious_mode: bool,
+    #[structopt(short = "u", long = "unsafe")]
+    /// unsafe mode (not check blocks inner hashs, very dangerous)
+    pub unsafe_mode: bool,
+}
diff --git a/core/lib.rs b/core/lib.rs
index 783d34762d1bbe78099636f17dca01fa515aa140..9f46712eec87d3a2cc0820aeaaac14559dec2d6d 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -16,10 +16,9 @@
 //! Crate containing Duniter-rust core.
 
 #![cfg_attr(feature = "strict", deny(warnings))]
-#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
+//#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
 #![deny(
     missing_docs,
-    missing_debug_implementations,
     missing_copy_implementations,
     trivial_casts,
     trivial_numeric_casts,
@@ -29,11 +28,10 @@
     unused_qualifications
 )]
 
-#[macro_use]
-extern crate clap;
-
 #[macro_use]
 extern crate log;
+#[macro_use]
+extern crate structopt;
 
 extern crate dirs;
 extern crate duniter_blockchain;
@@ -45,53 +43,74 @@ extern crate duniter_network;
 extern crate log_panics;
 extern crate serde_json;
 extern crate simplelog;
-extern crate sqlite;
 extern crate threadpool;
 
 pub mod change_conf;
+pub mod cli;
+pub mod rooter;
 
-use clap::{App, ArgMatches};
 use duniter_blockchain::{BlockchainModule, DBExQuery, DBExTxQuery, DBExWotQuery};
 pub use duniter_conf::{ChangeGlobalConf, DuRsConf, DuniterKeyPairs};
-use duniter_message::DuniterMessage;
+use duniter_message::*;
 use duniter_module::*;
-use duniter_network::{NetworkModule, SyncEndpoint};
+use duniter_network::{NetworkModule, SyncEndpoint, SyncParams};
 use log::Level;
 use simplelog::*;
-use std::collections::HashSet;
+//use std::error::Error;
+//use std::fmt::{Debug, Formatter};
+use cli::*;
 use std::fs;
 use std::fs::{File, OpenOptions};
 use std::sync::mpsc;
-use std::thread;
-use std::time::Duration;
+use structopt::clap::{App, ArgMatches};
+use structopt::StructOpt;
 use threadpool::ThreadPool;
 
+/// Number of thread in plugins ThreadPool
+pub static THREAD_POOL_SIZE: &'static usize = &2;
+
 #[derive(Debug, Clone)]
 /// User command
 pub enum UserCommand {
     /// Start
     Start(),
     /// Sync (SyncEndpoint)
-    Sync(SyncEndpoint),
+    Sync(SyncParams),
     /// List modules
-    ListModules(HashSet<ModulesFilter>),
-    /// Other command
-    Other(),
+    ListModules(ListModulesOpt),
+    /// Unknow command
+    UnknowCommand(String),
 }
 
-#[derive(Debug)]
+/// TupleApp
+#[derive(Clone)]
+pub struct TupleApp<'b, 'a: 'b>(&'b App<'a, 'b>);
+
+/*impl<'b, 'a: 'b> Debug for TupleApp<'a, 'b> {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        write!(f, "TupleApp()")
+    }
+}*/
+
+#[derive(Clone)]
 /// Duniter Core Datas
-pub struct DuniterCore<DC: DuniterConf> {
+pub struct DuniterCore<'a, 'b: 'a, DC: DuniterConf> {
+    /// Command line configuration
+    pub cli_conf: TupleApp<'a, 'b>,
+    /// Command line arguments parsing by clap
+    pub cli_args: Option<ArgMatches<'a>>,
+    /// Plugins command line configuration
+    pub plugins_cli_conf: Vec<App<'b, 'a>>,
     /// Does the entered command require to launch server ?
-    pub user_command: UserCommand,
+    pub user_command: Option<UserCommand>,
     /// Software meta datas
     pub soft_meta_datas: SoftwareMetaDatas<DC>,
     /// Keypairs
-    pub keypairs: DuniterKeyPairs,
+    pub keypairs: Option<DuniterKeyPairs>,
     /// Run duration. Zero = infinite duration.
     pub run_duration_in_secs: u64,
     /// Sender channel of rooter thread
-    pub rooter_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>,
+    pub rooter_sender: Option<mpsc::Sender<RooterThreadMessage<DursMsg>>>,
     ///  Count the number of plugged modules
     pub modules_count: usize,
     ///  Count the number of plugged network modules
@@ -100,210 +119,208 @@ pub struct DuniterCore<DC: DuniterConf> {
     pub thread_pool: ThreadPool,
 }
 
-impl DuniterCore<DuRsConf> {
-    /// Instantiate Duniter classic node
+impl<'a, 'b: 'a> DuniterCore<'b, 'a, DuRsConf> {
+    /// Instantiate Duniter node
     pub fn new(
         soft_name: &'static str,
         soft_version: &'static str,
-    ) -> Option<DuniterCore<DuRsConf>> {
-        DuniterCore::new_specialized_node(soft_name, soft_version, 0, vec![], vec![], None)
-    }
-    /// Instantiate Duniter specialize node
-    pub fn new_specialized_node<'a, 'b>(
-        soft_name: &'static str,
-        soft_version: &'static str,
+        cli_conf: &'a App<'b, 'a>,
         run_duration_in_secs: u64,
-        external_followers: Vec<mpsc::Sender<DuniterMessage>>,
-        sup_apps: Vec<App<'a, 'b>>,
-        sup_apps_fn: Option<&Fn(&str, &ArgMatches) -> ()>,
-    ) -> Option<DuniterCore<DuRsConf>> {
+    ) -> DuniterCore<'b, 'a, DuRsConf> {
         // Get cli conf
-        let yaml = load_yaml!("./cli/en.yml");
-        let cli_conf = App::from_yaml(yaml);
-
-        // Math command line arguments
-        let cli_args = if !sup_apps.is_empty() {
+        //let yaml = load_yaml!("./cli/en.yml");
+        //let cli_conf = TupleApp(App::from_yaml(yaml));
+        DuniterCore {
+            cli_conf: TupleApp(cli_conf),
+            cli_args: None,
+            plugins_cli_conf: vec![],
+            user_command: None,
+            soft_meta_datas: SoftwareMetaDatas {
+                soft_name,
+                soft_version,
+                profile: String::from("default"),
+                conf: DuRsConf::default(),
+            },
+            keypairs: None,
+            run_duration_in_secs,
+            rooter_sender: None,
+            modules_count: 0,
+            network_modules_count: 0,
+            thread_pool: ThreadPool::new(*THREAD_POOL_SIZE),
+        }
+    }
+    /// Execute user command
+    pub fn match_user_command(&mut self) -> bool {
+        self.match_specialize_user_command(vec![], None, vec![])
+    }
+    /// Execute specialize user command
+    pub fn match_specialize_user_command(
+        &mut self,
+        sup_apps: Vec<App<'a, 'b>>,
+        sup_apps_fn: Option<&Fn(&str, &ArgMatches) -> bool>,
+        external_followers: Vec<mpsc::Sender<DursMsgContent>>,
+    ) -> bool {
+        // Inject core subcommands
+        //let core_cli_conf = inject_core_subcommands(self.cli_conf.0.clone());
+        let core_cli_conf = self.cli_conf.0.clone();
+        // Inject plugins subcommands
+        let cli_conf = if !self.plugins_cli_conf.is_empty() {
+            core_cli_conf.subcommands(self.plugins_cli_conf.clone())
+        } else {
+            core_cli_conf
+        };
+        // Inject specialize node subcommands a Math command line arguments
+        self.cli_args = Some(if !sup_apps.is_empty() {
             cli_conf.subcommands(sup_apps).get_matches()
         } else {
             cli_conf.get_matches()
-        };
-
+        });
+        let cli_args = self.cli_args.clone().expect("cli_args must be Some !");
         // Get datas profile name
         let profile = match_profile(&cli_args);
 
         // Init logger
-        init_logger(profile.as_str(), soft_name, &cli_args);
+        init_logger(profile.as_str(), self.soft_meta_datas.soft_name, &cli_args);
 
         // Print panic! in logs
-        log_panics::init();
+        //log_panics::init();
 
         // Load global conf
         let (conf, keypairs) = duniter_conf::load_conf(profile.as_str());
         info!("Success to load global conf.");
 
-        // Define SoftwareMetaDatas
-        let soft_meta_datas = SoftwareMetaDatas {
-            soft_name,
-            soft_version,
-            profile: profile.clone(),
-            conf: conf.clone(),
-        };
+        // save profile and conf
+        self.soft_meta_datas.profile = profile.clone();
+        self.soft_meta_datas.conf = conf.clone();
+
+        // Save keypairs
+        self.keypairs = Some(keypairs);
 
         /*
          * COMMAND LINE PROCESSING
          */
         if let Some(matches) = cli_args.subcommand_matches("disable") {
-            let module_name = matches
-                .value_of("MODULE_NAME")
-                .expect("disable: you must enter a module name !")
-                .to_string();
+            let opts = DisableOpt::from_clap(matches);
             change_conf::change_global_conf(
                 &profile,
                 conf,
-                ChangeGlobalConf::DisableModule(ModuleId(module_name)),
+                ChangeGlobalConf::DisableModule(opts.module_name),
             );
-            None
+            false
         } else if let Some(matches) = cli_args.subcommand_matches("enable") {
-            let module_name = matches
-                .value_of("MODULE_NAME")
-                .expect("enable: you must enter a module name !")
-                .to_string();
+            let opts = EnableOpt::from_clap(matches);
             change_conf::change_global_conf(
                 &profile,
                 conf,
-                ChangeGlobalConf::EnableModule(ModuleId(module_name)),
+                ChangeGlobalConf::EnableModule(opts.module_name),
             );
-            None
+            false
         } else if let Some(matches) = cli_args.subcommand_matches("modules") {
-            let mut filters = HashSet::new();
-            if matches.is_present("disabled") {
-                filters.insert(ModulesFilter::Enabled(false));
-            } else if matches.is_present("enabled") {
-                filters.insert(ModulesFilter::Enabled(true));
-            }
-            if matches.is_present("network") {
-                filters.insert(ModulesFilter::Network());
-            }
-            if matches.is_present("secret") {
-                filters.insert(ModulesFilter::RequireMemberPrivKey());
-            }
-            Some(list_modules(soft_meta_datas, keypairs, filters))
+            // Store user command
+            self.user_command = Some(UserCommand::ListModules(ListModulesOpt::from_clap(matches)));
+
+            // Start rooter thread
+            self.rooter_sender = Some(rooter::start_rooter::<DuRsConf>(0, vec![]));
+            true
         } else if let Some(_matches) = cli_args.subcommand_matches("start") {
-            Some(start(
-                soft_meta_datas,
-                keypairs,
-                run_duration_in_secs,
+            // Store user command
+            self.user_command = Some(UserCommand::Start());
+
+            // Start rooter thread
+            self.rooter_sender = Some(rooter::start_rooter::<DuRsConf>(
+                self.run_duration_in_secs,
                 external_followers,
-            ))
+            ));
+            true
         } else if let Some(matches) = cli_args.subcommand_matches("sync") {
-            let domain_or_ip = matches
-                .value_of("DOMAIN_OR_IP")
-                .expect("sync: you must enter a domain name or ip address !")
-                .to_string();
-            let port: u16 = matches
-                .value_of("PORT")
-                .expect("sync: you must enter a port number !")
-                .parse()
-                .expect("sync: port : you must enter an integer value !");
-            let path = if let Some(path) = matches.value_of("PATH") {
-                Some(path.to_string())
-            } else {
-                None
-            };
+            let opts = SyncOpt::from_clap(matches);
             let sync_endpoint = SyncEndpoint {
-                domain_or_ip,
-                port,
-                path,
+                domain_or_ip: opts.host,
+                port: opts.port,
+                path: opts.path,
                 tls: false,
             };
-            Some(sync(
-                soft_meta_datas,
-                keypairs,
+            // Store sync command parameters
+            self.user_command = Some(UserCommand::Sync(SyncParams {
                 sync_endpoint,
-                matches.is_present("cautious"),
-                !matches.is_present("unsafe"),
-            ))
+                cautious: opts.cautious_mode,
+                verif_hashs: opts.unsafe_mode,
+            }));
+            // Start rooter thread
+            self.rooter_sender = Some(rooter::start_rooter::<DuRsConf>(0, vec![]));
+            true
         } else if let Some(matches) = cli_args.subcommand_matches("sync_ts") {
-            let ts_profile = matches.value_of("TS_PROFILE").unwrap_or("duniter_default");
+            let opts = SyncTsOpt::from_clap(matches);
+            let ts_profile = opts
+                .ts_profile
+                .unwrap_or_else(|| String::from("duniter_default"));
             sync_ts(
                 profile.as_str(),
                 &conf,
-                ts_profile,
-                matches.is_present("cautious"),
-                !matches.is_present("unsafe"),
+                &ts_profile,
+                opts.cautious_mode,
+                opts.unsafe_mode,
             );
-            None
+            false
         } else if let Some(matches) = cli_args.subcommand_matches("dbex") {
-            let csv = matches.is_present("csv");
-            if let Some(distances_matches) = matches.subcommand_matches("distances") {
-                dbex(
+            let opts = DbExOpt::from_clap(matches);
+            match opts.subcommand {
+                DbExSubCommand::DistanceOpt(distance_opts) => dbex(
                     profile.as_str(),
                     &conf,
-                    csv,
-                    &DBExQuery::WotQuery(DBExWotQuery::AllDistances(
-                        distances_matches.is_present("reverse"),
-                    )),
-                );
-            } else if let Some(member_matches) = matches.subcommand_matches("member") {
-                let uid = member_matches.value_of("UID").unwrap_or("");
-                dbex(
+                    opts.csv,
+                    &DBExQuery::WotQuery(DBExWotQuery::AllDistances(distance_opts.reverse)),
+                ),
+                DbExSubCommand::MemberOpt(member_opts) => dbex(
                     profile.as_str(),
                     &conf,
-                    csv,
-                    &DBExQuery::WotQuery(DBExWotQuery::MemberDatas(String::from(uid))),
-                );
-            } else if let Some(members_matches) = matches.subcommand_matches("members") {
-                if members_matches.is_present("expire") {
-                    dbex(
-                        profile.as_str(),
-                        &conf,
-                        csv,
-                        &DBExQuery::WotQuery(DBExWotQuery::ExpireMembers(
-                            members_matches.is_present("reverse"),
-                        )),
-                    );
-                } else {
-                    dbex(
-                        profile.as_str(),
-                        &conf,
-                        csv,
-                        &DBExQuery::WotQuery(DBExWotQuery::ListMembers(
-                            members_matches.is_present("reverse"),
-                        )),
-                    );
+                    opts.csv,
+                    &DBExQuery::WotQuery(DBExWotQuery::MemberDatas(member_opts.uid)),
+                ),
+                DbExSubCommand::MembersOpt(members_opts) => {
+                    if members_opts.expire {
+                        dbex(
+                            profile.as_str(),
+                            &conf,
+                            opts.csv,
+                            &DBExQuery::WotQuery(DBExWotQuery::ExpireMembers(members_opts.reverse)),
+                        );
+                    } else {
+                        dbex(
+                            profile.as_str(),
+                            &conf,
+                            opts.csv,
+                            &DBExQuery::WotQuery(DBExWotQuery::ListMembers(members_opts.reverse)),
+                        );
+                    }
                 }
-            } else if let Some(balance_matches) = matches.subcommand_matches("balance") {
-                let address = balance_matches.value_of("ADDRESS").unwrap_or("");
-                dbex(
+                DbExSubCommand::BalanceOpt(balance_opts) => dbex(
                     &profile,
                     &conf,
-                    csv,
-                    &DBExQuery::TxQuery(DBExTxQuery::Balance(String::from(address))),
-                );
+                    opts.csv,
+                    &DBExQuery::TxQuery(DBExTxQuery::Balance(balance_opts.address)),
+                ),
             }
-            None
+            false
         } else if let Some(matches) = cli_args.subcommand_matches("reset") {
+            let opts = ResetOpt::from_clap(matches);
             let mut profile_path = match dirs::config_dir() {
                 Some(path) => path,
                 None => panic!("Impossible to get user config directory !"),
             };
-            profile_path.push(".config");
             profile_path.push(duniter_conf::get_user_datas_folder());
             profile_path.push(profile.clone());
             if !profile_path.as_path().exists() {
                 panic!(format!("Error : {} profile don't exist !", profile));
             }
-            match matches
-                .value_of("DATAS_TYPE")
-                .expect("cli param DATAS_TYPE is missing !")
-            {
-                "data" => {
+            match opts.reset_type {
+                ResetType::Datas => {
                     let mut currency_datas_path = profile_path.clone();
                     currency_datas_path.push("g1");
                     fs::remove_dir_all(currency_datas_path.as_path())
                         .expect("Fail to remove all currency datas !");
                 }
-                "conf" => {
+                ResetType::Conf => {
                     let mut conf_file_path = profile_path.clone();
                     conf_file_path.push("conf.json");
                     fs::remove_file(conf_file_path.as_path()).expect("Fail to remove conf file !");
@@ -312,45 +329,62 @@ impl DuniterCore<DuRsConf> {
                     fs::remove_file(conf_keys_path.as_path())
                         .expect("Fail to remove keypairs file !");
                 }
-                "all" => {
+                ResetType::All => {
                     fs::remove_dir_all(profile_path.as_path())
                         .expect("Fail to remove all profile datas !");
                 }
-                _ => {}
             }
-            None
-        } else if let Some(sup_apps_fn) = sup_apps_fn {
-            sup_apps_fn(profile.as_str(), &cli_args);
-            None
+            false
+        } else if let Some(unknow_subcommand) = cli_args.subcommand_name() {
+            let mut module_subcommand = true;
+            if let Some(sup_apps_fn) = sup_apps_fn {
+                if sup_apps_fn(profile.as_str(), &cli_args) {
+                    module_subcommand = false;
+                }
+            }
+            if module_subcommand {
+                self.user_command =
+                    Some(UserCommand::UnknowCommand(String::from(unknow_subcommand)));
+                true
+            } else {
+                false
+            }
         } else {
-            panic!("unknow sub-command !")
+            println!("Please use a subcommand. -h for help.");
+            false
         }
     }
-    /// Start blockchain module
-    pub fn start_blockchain(&self) {
+    /// Start core (=blockchain module)
+    pub fn start_core(&self) {
         if self.network_modules_count == 0 {
             panic!("You must plug at least one network layer !");
         }
-        if let UserCommand::Start() = self.user_command {
-            thread::sleep(Duration::from_secs(2));
+        if let Some(UserCommand::Start()) = self.user_command {
             // Create blockchain module channel
             let (blockchain_sender, blockchain_receiver): (
-                mpsc::Sender<DuniterMessage>,
-                mpsc::Receiver<DuniterMessage>,
+                mpsc::Sender<DursMsg>,
+                mpsc::Receiver<DursMsg>,
             ) = mpsc::channel();
 
+            let rooter_sender = if let Some(ref rooter_sender) = self.rooter_sender {
+                rooter_sender
+            } else {
+                panic!("Try to start core without rooter_sender !");
+            };
+
             // Send blockchain sender to rooter thread
-            self.rooter_sender
-                .send(RooterThreadMessage::ModuleSender(blockchain_sender))
+            rooter_sender
+                .send(RooterThreadMessage::ModuleSender(
+                    BlockchainModule::name(),
+                    blockchain_sender,
+                    vec![ModuleRole::BlockchainDatas, ModuleRole::BlockValidation],
+                    vec![ModuleEvent::NewBlockFromNetwork],
+                ))
                 .expect("Fatal error: fail to send blockchain sender to rooter thread !");
 
-            // Send modules_count to rooter thread
-            self.rooter_sender
-                .send(RooterThreadMessage::ModulesCount(self.modules_count + 1))
-                .expect("Fatal error: fail to send modules count to rooter thread !");
-
             // Instantiate blockchain module and load is conf
             let mut blockchain_module = BlockchainModule::load_blockchain_conf(
+                rooter_sender.clone(),
                 &self.soft_meta_datas.profile,
                 &self.soft_meta_datas.conf,
                 RequiredKeysContent::MemberKeyPair(None),
@@ -362,306 +396,182 @@ impl DuniterCore<DuRsConf> {
         }
     }
     /// Plug a network module
-    pub fn plug_network<NM: NetworkModule<DuRsConf, DuniterMessage>>(&mut self) {
-        let enabled = enabled::<DuRsConf, DuniterMessage, NM>(&self.soft_meta_datas.conf);
+    pub fn plug_network<NM: NetworkModule<DuRsConf, DursMsg>>(&mut self) {
+        let enabled = enabled::<DuRsConf, DursMsg, NM>(&self.soft_meta_datas.conf);
         if enabled {
-            if let UserCommand::Start() = self.user_command {
-                self.network_modules_count += 1;
-                self.plug::<NM>();
-            } else if let UserCommand::Sync(ref sync_endpoint) = self.user_command {
-                self.network_modules_count += 1;
+            self.network_modules_count += 1;
+            if let Some(UserCommand::Sync(ref network_sync)) = self.user_command {
                 // Start module in a new thread
-                let rooter_sender = self.rooter_sender.clone();
+                let rooter_sender = self
+                    .rooter_sender
+                    .clone()
+                    .expect("Try to start a core without rooter_sender !");
                 let soft_meta_datas = self.soft_meta_datas.clone();
                 let module_conf_json = self
                     .soft_meta_datas
                     .conf
                     .clone()
                     .modules()
-                    .get(&NM::id().to_string().as_str())
+                    .get(&NM::name().to_string().as_str())
                     .cloned();
                 let keypairs = self.keypairs;
-                let sync_endpoint = sync_endpoint.clone();
+                let sync_params = network_sync.clone();
                 self.thread_pool.execute(move || {
                     // Load module conf and keys
-                    let (module_conf, required_keys) =
-                        load_module_conf_and_keys::<NM>(module_conf_json, keypairs);
+                    let (module_conf, required_keys) = get_module_conf_and_keys::<NM>(
+                        module_conf_json,
+                        keypairs.expect("Try to plug addon into a core without keypair !"),
+                    );
                     NM::sync(
                         &soft_meta_datas,
                         required_keys,
                         module_conf,
                         rooter_sender,
-                        sync_endpoint,
-                    ).unwrap_or_else(|_| {
+                        sync_params,
+                    )
+                    .unwrap_or_else(|_| {
                         panic!(
                             "Fatal error : fail to load {} Module !",
-                            NM::id().to_string()
+                            NM::name().to_string()
                         )
                     });
                 });
                 self.modules_count += 1;
-                info!("Success to load {} module.", NM::id().to_string());
-            }
-        }
-        if let UserCommand::ListModules(ref filters) = self.user_command {
-            if module_valid_filters::<DuRsConf, DuniterMessage, NM>(
-                &self.soft_meta_datas.conf,
-                filters,
-                true,
-            ) {
-                if enabled {
-                    println!("{}", NM::id().to_string());
-                } else {
-                    println!("{} (disabled)", NM::id().to_string());
-                }
+                info!("Success to load {} module.", NM::name().to_string());
+            } else {
+                self.plug_::<NM>(true);
             }
+        } else {
+            self.plug_::<NM>(true);
         }
     }
+
+    /// Inject cli subcommand
+    pub fn inject_cli_subcommand<M: DuniterModule<DuRsConf, DursMsg>>(&mut self) {
+        //self.cli_conf = TupleApp(&self.cli_conf.0.clone().subcommand(M::ModuleOpt::clap()));
+        self.plugins_cli_conf.push(M::ModuleOpt::clap());
+    }
+
+    /// Plug a module
+    pub fn plug<M: DuniterModule<DuRsConf, DursMsg>>(&mut self) {
+        self.plug_::<M>(false);
+    }
+
     /// Plug a module
-    pub fn plug<M: DuniterModule<DuRsConf, DuniterMessage>>(&mut self) {
-        let enabled = enabled::<DuRsConf, DuniterMessage, M>(&self.soft_meta_datas.conf);
+    fn plug_<M: DuniterModule<DuRsConf, DursMsg>>(&mut self, is_network_module: bool) {
+        let enabled = enabled::<DuRsConf, DursMsg, M>(&self.soft_meta_datas.conf);
         if enabled {
-            if let UserCommand::Start() = self.user_command {
+            if let Some(UserCommand::Start()) = self.user_command {
                 // Start module in a new thread
-                let rooter_sender_clone = self.rooter_sender.clone();
+                let rooter_sender_clone = self
+                    .rooter_sender
+                    .clone()
+                    .expect("Try to start a core without rooter_sender !");
                 let soft_meta_datas = self.soft_meta_datas.clone();
                 let module_conf_json = self
                     .soft_meta_datas
                     .conf
                     .clone()
                     .modules()
-                    .get(&M::id().to_string().as_str())
+                    .get(&M::name().to_string().as_str())
                     .cloned();
                 let keypairs = self.keypairs;
                 self.thread_pool.execute(move || {
                     // Load module conf and keys
-                    let (module_conf, required_keys) =
-                        load_module_conf_and_keys::<M>(module_conf_json, keypairs);
+                    let (module_conf, required_keys) = get_module_conf_and_keys::<M>(
+                        module_conf_json,
+                        keypairs.expect("Try to plug addon into a core without keypair !"),
+                    );
                     M::start(
                         &soft_meta_datas,
                         required_keys,
                         module_conf,
                         rooter_sender_clone,
                         false,
-                    ).unwrap_or_else(|_| {
+                    )
+                    .unwrap_or_else(|_| {
                         panic!(
                             "Fatal error : fail to load {} Module !",
-                            M::id().to_string()
+                            M::name().to_string()
                         )
                     });
                 });
                 self.modules_count += 1;
-                info!("Success to load {} module.", M::id().to_string());
+                info!("Success to load {} module.", M::name().to_string());
+            } else if let Some(UserCommand::UnknowCommand(ref subcommand)) = self.user_command {
+                if M::have_subcommand() && *subcommand == M::name().to_string() {
+                    // Math command line arguments
+                    if let Some(subcommand_args) = self
+                        .cli_args
+                        .clone()
+                        .expect("cli_args must be Some !")
+                        .subcommand_matches(M::name().to_string())
+                    {
+                        // Load module conf and keys
+                        let module_conf_json = self
+                            .soft_meta_datas
+                            .conf
+                            .clone()
+                            .modules()
+                            .get(&M::name().to_string().as_str())
+                            .cloned();
+                        let (_conf, keypairs) =
+                            duniter_conf::load_conf(self.soft_meta_datas.profile.as_str());
+                        let (module_conf, required_keys) =
+                            get_module_conf_and_keys::<M>(module_conf_json, keypairs);
+                        // Execute module subcommand
+                        M::exec_subcommand(
+                            &self.soft_meta_datas,
+                            required_keys, //required_keys,
+                            module_conf,   //module_conf,
+                            M::ModuleOpt::from_clap(subcommand_args),
+                        );
+                    }
+                }
             }
         }
-        if let UserCommand::ListModules(ref filters) = self.user_command {
-            if module_valid_filters::<DuRsConf, DuniterMessage, M>(
+        if let Some(UserCommand::ListModules(ref options)) = self.user_command {
+            if module_valid_filters::<DuRsConf, DursMsg, M, std::collections::hash_map::RandomState>(
                 &self.soft_meta_datas.conf,
-                filters,
-                false,
+                &options.get_filters(),
+                is_network_module,
             ) {
                 if enabled {
-                    println!("{}", M::id().to_string());
+                    println!("{}", M::name().to_string());
                 } else {
-                    println!("{} (disabled)", M::id().to_string());
+                    println!("{} (disabled)", M::name().to_string());
                 }
             }
         }
     }
 }
 
-/// Load module conf and keys
-pub fn load_module_conf_and_keys<M: DuniterModule<DuRsConf, DuniterMessage>>(
+/// Get module conf and keys
+pub fn get_module_conf_and_keys<M: DuniterModule<DuRsConf, DursMsg>>(
     module_conf_json: Option<serde_json::Value>,
     keypairs: DuniterKeyPairs,
 ) -> (M::ModuleConf, RequiredKeysContent) {
-    let module_conf = if let Some(module_conf_json) = module_conf_json {
+    (
+        get_module_conf::<M>(module_conf_json),
+        DuniterKeyPairs::get_required_keys_content(M::ask_required_keys(), keypairs),
+    )
+}
+
+/// get module conf
+pub fn get_module_conf<M: DuniterModule<DuRsConf, DursMsg>>(
+    module_conf_json: Option<serde_json::Value>,
+) -> M::ModuleConf {
+    if let Some(module_conf_json) = module_conf_json {
         serde_json::from_str(module_conf_json.to_string().as_str())
-            .unwrap_or_else(|_| panic!("Fail to parse conf of module {}", M::id().to_string()))
+            .unwrap_or_else(|_| panic!("Fail to parse conf of module {}", M::name().to_string()))
     } else {
         M::ModuleConf::default()
-    };
-    let required_keys =
-        DuniterKeyPairs::get_required_keys_content(M::ask_required_keys(), keypairs);
-
-    (module_conf, required_keys)
+    }
 }
 
 /// Match cli option --profile
 pub fn match_profile(cli_args: &ArgMatches) -> String {
-    String::from(cli_args.value_of("profile").unwrap_or("default"))
-}
-
-/// List modules
-pub fn list_modules<DC: DuniterConf>(
-    soft_meta_datas: SoftwareMetaDatas<DC>,
-    keypairs: DuniterKeyPairs,
-    modules_filter: HashSet<ModulesFilter>,
-) -> DuniterCore<DC> {
-    // Start rooter thread
-    let rooter_sender = start_rooter::<DC>(0, vec![]);
-
-    // Instanciate DuniterCore
-    DuniterCore {
-        user_command: UserCommand::ListModules(modules_filter),
-        soft_meta_datas,
-        keypairs,
-        run_duration_in_secs: 0,
-        rooter_sender,
-        modules_count: 0,
-        network_modules_count: 0,
-        thread_pool: ThreadPool::new(2),
-    }
-}
-
-/// Start rooter thread
-pub fn start_rooter<DC: DuniterConf>(
-    run_duration_in_secs: u64,
-    external_followers: Vec<mpsc::Sender<DuniterMessage>>,
-) -> mpsc::Sender<RooterThreadMessage<DuniterMessage>> {
-    // Create senders channel
-    let (rooter_sender, main_receiver): (
-        mpsc::Sender<RooterThreadMessage<DuniterMessage>>,
-        mpsc::Receiver<RooterThreadMessage<DuniterMessage>>,
-    ) = mpsc::channel();
-
-    // Create rooter thread
-    thread::spawn(move || {
-        // Wait to receiver modules senders
-        let mut modules_senders: Vec<mpsc::Sender<DuniterMessage>> = Vec::new();
-        let mut modules_count_expected = None;
-        while modules_count_expected.is_none()
-            || modules_senders.len() < modules_count_expected.expect("safe unwrap") + 1
-        {
-            match main_receiver.recv_timeout(Duration::from_secs(20)) {
-                Ok(mess) => {
-                    match mess {
-                        RooterThreadMessage::ModuleSender(module_sender) => {
-                            // Subscribe this module to all others modules
-                            for other_module in modules_senders.clone() {
-                                if other_module
-                                    .send(DuniterMessage::Followers(vec![module_sender.clone()]))
-                                    .is_err()
-                                {
-                                    panic!("Fatal error : fail to send all modules senders to all modules !");
-                                }
-                            }
-                            // Subcribe this module to all external_followers
-                            for external_follower in external_followers.clone() {
-                                if external_follower
-                                    .send(DuniterMessage::Followers(vec![module_sender.clone()]))
-                                    .is_err()
-                                {
-                                    panic!("Fatal error : fail to send all modules senders to all external_followers !");
-                                }
-                            }
-                            // Subscribe all other modules to this module
-                            if module_sender
-                                .send(DuniterMessage::Followers(modules_senders.clone()))
-                                .is_err()
-                            {
-                                panic!("Fatal error : fail to send all modules senders to all modules !");
-                            }
-                            // Subcribe all external_followers to this module
-                            if module_sender
-                                .send(DuniterMessage::Followers(external_followers.clone()))
-                                .is_err()
-                            {
-                                panic!("Fatal error : fail to send all external_followers to all modules !");
-                            }
-                            // Push this module to modules_senders list
-                            modules_senders.push(module_sender);
-                            // Log the number of modules_senders received
-                            info!(
-                                "Rooter thread receive {} module senders",
-                                modules_senders.len()
-                            );
-                        }
-                        RooterThreadMessage::ModulesCount(modules_count) => {
-                            info!("Rooter thread receive ModulesCount({})", modules_count);
-                            if modules_senders.len() == modules_count {
-                                break;
-                            } else if modules_senders.len() < modules_count {
-                                modules_count_expected = Some(modules_count);
-                            } else {
-                                panic!("Fatal error : Receive more modules_sender than expected !")
-                            }
-                        }
-                    }
-                }
-                Err(e) => match e {
-                    mpsc::RecvTimeoutError::Timeout => {
-                        panic!("Fatal error : not receive all modules_senders after 20 secs !")
-                    }
-                    mpsc::RecvTimeoutError::Disconnected => {
-                        panic!("Fatal error : rooter thread disconnnected !")
-                    }
-                },
-            }
-        }
-        info!("Receive all modules senders.");
-        if run_duration_in_secs > 0 {
-            thread::sleep(Duration::from_secs(run_duration_in_secs));
-            // Send DuniterMessage::Stop() to all modules
-            for sender in modules_senders {
-                if sender.send(DuniterMessage::Stop()).is_err() {
-                    panic!("Fail to send Stop() message to one module !")
-                }
-            }
-            thread::sleep(Duration::from_secs(2));
-        }
-    });
-
-    rooter_sender
-}
-
-/// Launch duniter server
-pub fn start<DC: DuniterConf>(
-    soft_meta_datas: SoftwareMetaDatas<DC>,
-    keypairs: DuniterKeyPairs,
-    run_duration_in_secs: u64,
-    external_followers: Vec<mpsc::Sender<DuniterMessage>>,
-) -> DuniterCore<DC> {
-    info!("Starting Duniter-rs...");
-
-    // Start rooter thread
-    let rooter_sender = start_rooter::<DC>(run_duration_in_secs, external_followers);
-
-    // Instanciate DuniterCore
-    DuniterCore {
-        user_command: UserCommand::Start(),
-        soft_meta_datas,
-        keypairs,
-        run_duration_in_secs,
-        rooter_sender,
-        modules_count: 0,
-        network_modules_count: 0,
-        thread_pool: ThreadPool::new(2),
-    }
-}
-
-/// Launch synchronisation from network
-pub fn sync<DC: DuniterConf>(
-    soft_meta_datas: SoftwareMetaDatas<DC>,
-    keypairs: DuniterKeyPairs,
-    sync_endpoint: SyncEndpoint,
-    _cautious: bool,
-    _verif_hashs: bool,
-) -> DuniterCore<DC> {
-    // Start rooter thread
-    let rooter_sender = start_rooter::<DC>(0, vec![]);
-
-    // Instanciate DuniterCore
-    DuniterCore {
-        user_command: UserCommand::Sync(sync_endpoint),
-        soft_meta_datas,
-        keypairs,
-        run_duration_in_secs: 0,
-        rooter_sender,
-        modules_count: 0,
-        network_modules_count: 0,
-        thread_pool: ThreadPool::new(2),
-    }
+    String::from(cli_args.value_of("profile_name").unwrap_or("default"))
 }
 
 /// Launch synchronisation from a duniter-ts database
@@ -689,7 +599,6 @@ pub fn init_logger(profile: &str, soft_name: &'static str, cli_args: &ArgMatches
         Some(path) => path,
         None => panic!("Fatal error : Impossible to get user config directory"),
     };
-    log_file_path.push(".config");
     if !log_file_path.as_path().exists() {
         fs::create_dir(log_file_path.as_path()).expect("Impossible to create ~/.config dir !");
     }
@@ -707,7 +616,7 @@ pub fn init_logger(profile: &str, soft_name: &'static str, cli_args: &ArgMatches
     log_file_path.push(format!("{}.log", soft_name));
 
     // Get log level
-    let log_level = match cli_args.value_of("logs").unwrap_or("i") {
+    let log_level = match cli_args.value_of("logs_level").unwrap_or("i") {
         "e" | "error" => Level::Error,
         "w" | "warn" => Level::Warn,
         "i" | "info" => Level::Info,
@@ -731,7 +640,8 @@ pub fn init_logger(profile: &str, soft_name: &'static str, cli_args: &ArgMatches
             log_file_path
                 .to_str()
                 .expect("Fatal error : fail to get log file path !"),
-        ).expect("Fatal error : fail to create log file path !");
+        )
+        .expect("Fatal error : fail to create log file path !");
     }
 
     CombinedLogger::init(vec![WriteLogger::new(
@@ -744,6 +654,10 @@ pub fn init_logger(profile: &str, soft_name: &'static str, cli_args: &ArgMatches
                 log_file_path
                     .to_str()
                     .expect("Fatal error : fail to get log file path !"),
-            ).expect("Fatal error : fail to open log file !"),
-    )]).expect("Fatal error : fail to init logger !");
+            )
+            .expect("Fatal error : fail to open log file !"),
+    )])
+    .expect("Fatal error : fail to init logger !");
+
+    info!("Successfully init logger");
 }
diff --git a/core/rooter.rs b/core/rooter.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2eab64f2a8360d68f0501e481ccb79332a13f374
--- /dev/null
+++ b/core/rooter.rs
@@ -0,0 +1,390 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program 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, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Relay messages between durs modules.
+
+use duniter_message::*;
+use duniter_module::*;
+use std::collections::HashMap;
+use std::sync::mpsc;
+use std::sync::mpsc::RecvTimeoutError;
+use std::thread;
+use std::time::Duration;
+use std::time::SystemTime;
+
+/// Start broadcasting thread
+fn start_broadcasting_thread(
+    start_time: SystemTime,
+    run_duration_in_secs: u64,
+    receiver: &mpsc::Receiver<RooterThreadMessage<DursMsg>>,
+    external_followers: &[mpsc::Sender<DursMsgContent>],
+) {
+    // Define variables
+    let mut modules_senders: HashMap<ModuleStaticName, mpsc::Sender<DursMsg>> = HashMap::new();
+    let mut pool_msgs: HashMap<DursMsgReceiver, Vec<DursMsgContent>> = HashMap::new();
+    let mut events_subscriptions: HashMap<ModuleEvent, Vec<ModuleStaticName>> = HashMap::new();
+    let mut roles: HashMap<ModuleRole, Vec<ModuleStaticName>> = HashMap::new();
+
+    loop {
+        match receiver.recv_timeout(Duration::from_secs(1)) {
+            Ok(mess) => {
+                match mess {
+                    RooterThreadMessage::ModuleSender(
+                        module_static_name,
+                        module_sender,
+                        sender_roles,
+                        events_subscription,
+                    ) => {
+                        // For all events
+                        for event in events_subscription {
+                            // Send pending message of this event
+                            for msg in pool_msgs
+                                .get(&DursMsgReceiver::Event(event))
+                                .unwrap_or(&Vec::with_capacity(0))
+                            {
+                                module_sender
+                                    .send(DursMsg(DursMsgReceiver::Event(event), msg.clone()))
+                                    .unwrap_or_else(|_| {
+                                        panic!(
+                                            "Fatal error: fail to relay DursMsg to {:?} !",
+                                            module_static_name
+                                        )
+                                    });
+                            }
+                            // Store event subscription
+                            events_subscriptions
+                                .entry(event)
+                                .or_insert_with(Vec::new)
+                                .push(module_static_name);
+                        }
+                        // For all roles
+                        for role in sender_roles {
+                            // Send pending message for this role
+                            for msg in pool_msgs
+                                .get(&DursMsgReceiver::Role(role))
+                                .unwrap_or(&Vec::with_capacity(0))
+                            {
+                                module_sender
+                                    .send(DursMsg(DursMsgReceiver::Role(role), msg.clone()))
+                                    .unwrap_or_else(|_| {
+                                        panic!(
+                                            "Fatal error: fail to relay DursMsg to {:?} !",
+                                            module_static_name
+                                        )
+                                    });
+                            }
+                            // Store sender roles
+                            roles
+                                .entry(role)
+                                .or_insert_with(Vec::new)
+                                .push(module_static_name);
+                        }
+                        // Add this sender to modules_senders
+                        modules_senders.insert(module_static_name, module_sender);
+                    }
+                    RooterThreadMessage::ModuleMessage(msg) => match msg.0 {
+                        DursMsgReceiver::One(_) => {}
+                        DursMsgReceiver::All => {
+                            for (module_static_name, module_sender) in &modules_senders {
+                                module_sender.send(msg.clone()).unwrap_or_else(|_| {
+                                    panic!(
+                                        "Fatal error: fail to relay DursMsg to {:?} !",
+                                        module_static_name
+                                    )
+                                });
+                            }
+                            // Detect stop message
+                            let stop = if let DursMsgContent::Stop() = msg.1 {
+                                true
+                            } else {
+                                false
+                            };
+                            // Send message to external followers
+                            for external_follower in external_followers {
+                                external_follower.send(msg.1.clone()).expect(
+                                    "Fatal error: fail to relay DursMsg to external followers !",
+                                );
+                            }
+                            // Send message to all modules
+                            send_msg_to_several_receivers(
+                                msg,
+                                &modules_senders
+                                    .keys()
+                                    .cloned()
+                                    .collect::<Vec<ModuleStaticName>>(),
+                                &modules_senders,
+                            );
+                            // Stop thread if its requested
+                            if stop {
+                                break;
+                            }
+                        }
+                        DursMsgReceiver::Event(event) => {
+                            // the node to be started less than 20 seconds ago,
+                            // keep the message in memory to be able to send it back to modules not yet plugged
+                            store_msg_in_pool(
+                                start_time,
+                                run_duration_in_secs,
+                                msg.clone(),
+                                &mut pool_msgs,
+                            );
+                            // Get list of receivers
+                            let receivers = events_subscriptions
+                                .get(&event)
+                                .unwrap_or(&Vec::with_capacity(0))
+                                .to_vec();
+                            // Send msg to receivers
+                            send_msg_to_several_receivers(msg, &receivers, &modules_senders)
+                        }
+                        DursMsgReceiver::Role(role) => {
+                            // If the node to be started less than 20 seconds ago,
+                            // keep the message in memory to be able to send it back to modules not yet plugged
+                            store_msg_in_pool(
+                                start_time,
+                                run_duration_in_secs,
+                                msg.clone(),
+                                &mut pool_msgs,
+                            );
+                            // Get list of receivers
+                            let receivers =
+                                roles.get(&role).unwrap_or(&Vec::with_capacity(0)).to_vec();
+                            // Send msg to receivers
+                            send_msg_to_several_receivers(msg, &receivers, &modules_senders)
+                        }
+                    },
+                }
+            }
+            Err(e) => match e {
+                RecvTimeoutError::Timeout => continue,
+                RecvTimeoutError::Disconnected => {
+                    panic!("Fatal error : rooter thread disconnnected !")
+                }
+            },
+        }
+    }
+}
+
+/// Send msg to several receivers
+fn send_msg_to_several_receivers(
+    msg: DursMsg,
+    receivers: &[ModuleStaticName],
+    modules_senders: &HashMap<ModuleStaticName, mpsc::Sender<DursMsg>>,
+) {
+    // Send message by copy To all modules that subscribed to this event
+    for module_static_name in &receivers[1..] {
+        if let Some(module_sender) = modules_senders.get(module_static_name) {
+            module_sender.send(msg.clone()).unwrap_or_else(|_| {
+                panic!(
+                    "Fatal error: fail to relay DursMsg to {:?} !",
+                    module_static_name
+                )
+            });
+        }
+    }
+    // Send message by move to the last module to be revceive
+    if !receivers.is_empty() {
+        if let Some(module_sender) = modules_senders.get(&receivers[0]) {
+            module_sender.send(msg).unwrap_or_else(|_| {
+                panic!("Fatal error: fail to relay DursMsg to {:?} !", receivers[0])
+            });
+        }
+    }
+}
+
+/// If the node to be started less than 20 seconds ago,
+/// keep the message in memory to be able to send it back to modules not yet plugged
+fn store_msg_in_pool(
+    start_time: SystemTime,
+    run_duration_in_secs: u64,
+    msg: DursMsg,
+    pool_msgs: &mut HashMap<DursMsgReceiver, Vec<DursMsgContent>>,
+) {
+    if run_duration_in_secs > 0
+        && SystemTime::now()
+            .duration_since(start_time)
+            .expect("Duration error !")
+            .as_secs()
+            < 20
+    {
+        pool_msgs.entry(msg.0).or_insert_with(Vec::new).push(msg.1);
+    } else if !pool_msgs.is_empty() {
+        // Clear pool_msgs
+        pool_msgs.clear();
+    }
+}
+
+/// Start rooter thread
+pub fn start_rooter<DC: DuniterConf>(
+    run_duration_in_secs: u64,
+    external_followers: Vec<mpsc::Sender<DursMsgContent>>,
+) -> mpsc::Sender<RooterThreadMessage<DursMsg>> {
+    let start_time = SystemTime::now();
+
+    // Create rooter channel
+    let (rooter_sender, rooter_receiver): (
+        mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        mpsc::Receiver<RooterThreadMessage<DursMsg>>,
+    ) = mpsc::channel();
+
+    // Create rooter thread
+    thread::spawn(move || {
+        // Create broadcasting thread channel
+        let (broadcasting_sender, broadcasting_receiver): (
+            mpsc::Sender<RooterThreadMessage<DursMsg>>,
+            mpsc::Receiver<RooterThreadMessage<DursMsg>>,
+        ) = mpsc::channel();
+
+        // Create broadcasting thread
+        thread::spawn(move || {
+            start_broadcasting_thread(
+                start_time,
+                run_duration_in_secs,
+                &broadcasting_receiver,
+                &external_followers,
+            );
+        });
+
+        // Define variables
+        let mut modules_senders: HashMap<ModuleStaticName, mpsc::Sender<DursMsg>> = HashMap::new();
+        let mut pool_msgs: HashMap<ModuleStaticName, Vec<DursMsgContent>> = HashMap::new();
+
+        // Wait to receiver modules senders
+        loop {
+            match rooter_receiver.recv_timeout(Duration::from_secs(1)) {
+                Ok(mess) => {
+                    match mess {
+                        RooterThreadMessage::ModuleSender(
+                            module_static_name,
+                            module_sender,
+                            events_subscription,
+                            sender_roles,
+                        ) => {
+                            // Send pending messages destined specifically to this module
+                            if let Some(msgs) = pool_msgs.remove(&module_static_name) {
+                                for msg in msgs {
+                                    module_sender
+                                        .send(DursMsg(
+                                            DursMsgReceiver::One(module_static_name),
+                                            msg,
+                                        ))
+                                        .unwrap_or_else(|_| {
+                                            panic!(
+                                                "Fatal error: fail to relay DursMsg to {:?} !",
+                                                module_static_name
+                                            )
+                                        });
+                                }
+                            }
+                            // Add this sender to modules_senders
+                            modules_senders.insert(module_static_name, module_sender.clone());
+                            // Relay to broadcasting thread
+                            broadcasting_sender
+                                .send(RooterThreadMessage::ModuleSender(
+                                    module_static_name,
+                                    module_sender,
+                                    events_subscription,
+                                    sender_roles,
+                                ))
+                                .expect("Fail to relay message to broadcasting thread !");
+                            // Log the number of modules_senders received
+                            info!(
+                                "Rooter thread receive {} module senders",
+                                modules_senders.len()
+                            );
+                        }
+                        RooterThreadMessage::ModuleMessage(msg) => {
+                            trace!("Rooter thread receive ModuleMessage({:?})", msg);
+                            match msg.0 {
+                                DursMsgReceiver::All => {
+                                    let stop = if let DursMsgContent::Stop() = msg.1 {
+                                        true
+                                    } else {
+                                        false
+                                    };
+                                    broadcasting_sender
+                                        .send(RooterThreadMessage::ModuleMessage(msg))
+                                        .expect("Fail to relay message to broadcasting thread !");
+                                    if stop {
+                                        break;
+                                    }
+                                }
+                                DursMsgReceiver::Role(_module_role) => broadcasting_sender
+                                    .send(RooterThreadMessage::ModuleMessage(msg))
+                                    .expect("Fail to relay message to broadcasting thread !"),
+                                DursMsgReceiver::Event(_module_event) => broadcasting_sender
+                                    .send(RooterThreadMessage::ModuleMessage(msg))
+                                    .expect("Fail to relay message to broadcasting thread !"),
+                                DursMsgReceiver::One(module_static_name) => {
+                                    if let Some(module_sender) =
+                                        modules_senders.get(&module_static_name)
+                                    {
+                                        module_sender.send(msg).unwrap_or_else(|_| {
+                                            panic!(
+                                                "Fatal error: fail to relay DursMsg to {:?} !",
+                                                module_static_name
+                                            )
+                                        });
+                                    } else if SystemTime::now()
+                                        .duration_since(start_time)
+                                        .expect("Duration error !")
+                                        .as_secs()
+                                        < 20
+                                    {
+                                        pool_msgs
+                                            .entry(module_static_name)
+                                            .or_insert_with(Vec::new)
+                                            .push(msg.1);
+                                    } else {
+                                        if !pool_msgs.is_empty() {
+                                            pool_msgs = HashMap::with_capacity(0);
+                                        }
+                                        warn!(
+                                            "Message for unknow receiver : {:?}.",
+                                            module_static_name
+                                        );
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                Err(e) => match e {
+                    RecvTimeoutError::Timeout => continue,
+                    RecvTimeoutError::Disconnected => {
+                        panic!("Fatal error : rooter thread disconnnected !")
+                    }
+                },
+            }
+            if run_duration_in_secs > 0
+                && SystemTime::now()
+                    .duration_since(start_time)
+                    .expect("Duration error !")
+                    .as_secs()
+                    > run_duration_in_secs
+            {
+                broadcasting_sender
+                    .send(RooterThreadMessage::ModuleMessage(DursMsg(
+                        DursMsgReceiver::All,
+                        DursMsgContent::Stop(),
+                    )))
+                    .expect("Fail to relay stop message to broadcasting thread !");
+                break;
+            }
+        }
+        info!("Rooter thread stop.")
+    });
+
+    rooter_sender
+}
diff --git a/crypto/keys/bin_signable.rs b/crypto/keys/bin_signable.rs
index 3c572131ba63f4659149dd725f96f5c5165c08ad..40d2055b10eea22b39adf8112f9fe614355b5c61 100644
--- a/crypto/keys/bin_signable.rs
+++ b/crypto/keys/bin_signable.rs
@@ -90,7 +90,6 @@ pub trait BinSignable<'de>: Serialize + Deserialize<'de> {
                         } else {
                             self.compute_hash()?
                         };
-                        println!("DEBUG: verified hash={:?}", hash.0);
                         if pubkey.verify(&hash.0, &sig) {
                             Ok(())
                         } else {
diff --git a/crypto/keys/ed25519.rs b/crypto/keys/ed25519.rs
index 3e36cc38d0b620963b1a67e02d1173dcfb5924d6..a3dda669133b7f03147d929af4571d75211d9488 100644
--- a/crypto/keys/ed25519.rs
+++ b/crypto/keys/ed25519.rs
@@ -66,11 +66,11 @@ impl<'de> Deserialize<'de> for Signature {
     where
         D: Deserializer<'de>,
     {
-        struct ArrayVisitor<u8> {
+        struct ArrayVisitor {
             element: PhantomData<u8>,
         }
 
-        impl<'de, u8> Visitor<'de> for ArrayVisitor<u8> {
+        impl<'de> Visitor<'de> for ArrayVisitor {
             type Value = Signature;
 
             fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
@@ -91,7 +91,7 @@ impl<'de> Deserialize<'de> for Signature {
             }
         }
 
-        let visitor: ArrayVisitor<u8> = ArrayVisitor {
+        let visitor: ArrayVisitor = ArrayVisitor {
             element: PhantomData,
         };
         deserializer.deserialize_tuple(64, visitor)
@@ -478,13 +478,15 @@ mod tests {
         assert_eq!(
             super::PrivateKey::from_base58(
                 "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9",
-            ).unwrap_err(),
+            )
+            .unwrap_err(),
             BaseConvertionError::InvalidKeyLendth(53, 64)
         );
         assert_eq!(
             super::PrivateKey::from_base58(
                 "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9<<",
-            ).unwrap_err(),
+            )
+            .unwrap_err(),
             BaseConvertionError::InvalidCharacter('<', 73)
         );
     }
@@ -538,14 +540,16 @@ mod tests {
             super::Signature::from_base64(
                 "YmhlaW9iaHNlcGlvaGVvaXNlcGl2ZXBvdm5pc2V2c2JlaW9idmVpb3Zqc\
                  2V2Z3BpaHNlamVwZ25qZXNqb2dwZWpnaW9zZXNkdnNic3JicmJyZGJyZGI=",
-            ).unwrap_err(),
+            )
+            .unwrap_err(),
             BaseConvertionError::InvalidKeyLendth(86, 64)
         );
         assert_eq!(
             super::Signature::from_base64(
                 "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
                  mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAgdha<<",
-            ).unwrap_err(),
+            )
+            .unwrap_err(),
             BaseConvertionError::InvalidCharacter('<', 89)
         );
     }
@@ -558,12 +562,14 @@ mod tests {
         let prikey = super::PrivateKey::from_base58(
             "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt\
              5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-        ).unwrap();
+        )
+        .unwrap();
 
         let expected_signature = super::Signature::from_base64(
             "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FG\
              MMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
-        ).unwrap();
+        )
+        .unwrap();
 
         let message = "Version: 10
 Type: Identity
diff --git a/crypto/keys/mod.rs b/crypto/keys/mod.rs
index b110b95eb32c5c7d91bca71f7732eccb0231a8cb..02eeab5d0e28a917e9a282b061b43824350b34df 100644
--- a/crypto/keys/mod.rs
+++ b/crypto/keys/mod.rs
@@ -286,11 +286,13 @@ impl PublicKey for PubKey {
     }
     fn verify(&self, message: &[u8], signature: &Self::Signature) -> bool {
         match *self {
-            PubKey::Ed25519(ed25519_pubkey) => if let Sig::Ed25519(ed25519_sig) = signature {
-                ed25519_pubkey.verify(message, ed25519_sig)
-            } else {
-                panic!("Try to verify a signature with public key of a different algorithm !\nSignature={:?}\nPublickey={:?}", signature, self)
-            },
+            PubKey::Ed25519(ed25519_pubkey) => {
+                if let Sig::Ed25519(ed25519_sig) = signature {
+                    ed25519_pubkey.verify(message, ed25519_sig)
+                } else {
+                    panic!("Try to verify a signature with public key of a different algorithm !\nSignature={:?}\nPublickey={:?}", signature, self)
+                }
+            }
             PubKey::Schnorr() => panic!("Schnorr algo not yet supported !"),
         }
     }
@@ -440,11 +442,13 @@ impl KeyPair for KeyPairEnum {
     }
     fn verify(&self, message: &[u8], signature: &Sig) -> bool {
         match *self {
-            KeyPairEnum::Ed25519(ed25519_keypair) => if let Sig::Ed25519(ed25519_sig) = signature {
-                ed25519_keypair.verify(message, ed25519_sig)
-            } else {
-                panic!("Try to verify a signature with key pair of a different algorithm !\nSignature={:?}\nKeyPair={:?}", signature, self)
-            },
+            KeyPairEnum::Ed25519(ed25519_keypair) => {
+                if let Sig::Ed25519(ed25519_sig) = signature {
+                    ed25519_keypair.verify(message, ed25519_sig)
+                } else {
+                    panic!("Try to verify a signature with key pair of a different algorithm !\nSignature={:?}\nKeyPair={:?}", signature, self)
+                }
+            }
             KeyPairEnum::Schnorr() => panic!("Schnorr algo not yet supported !"),
         }
     }
diff --git a/crypto/lib.rs b/crypto/lib.rs
index 3620eb994bb08f6ec328d1e3aa412e0b2418d565..c478012c6ae72a63dad28079f775c0bccaf3a2f7 100644
--- a/crypto/lib.rs
+++ b/crypto/lib.rs
@@ -16,7 +16,6 @@
 //! Provide wrappers for cryptographic building blocks used by Duniter.
 
 #![cfg_attr(feature = "strict", deny(warnings))]
-#![cfg_attr(feature = "cargo-clippy", allow(builtin_type_shadow))]
 #![deny(
     missing_docs,
     missing_debug_implementations,
diff --git a/dal/block.rs b/dal/block.rs
index 532aa9f3bf5bea74d150d03b7d036e8360ba4af5..8ca38a5388f0b3b7e21a325c3bed44d3bf363670 100644
--- a/dal/block.rs
+++ b/dal/block.rs
@@ -392,7 +392,7 @@ impl DALBlock {
                 median_index = self.block.issuers_count - 1;
             }
             self.median_frame = current_frame_vec[median_index];
-
+            
             // Calculate second tiercile index
             let mut second_tiercile_index = match self.block.issuers_count % 3 {
                 1 | 2 => (self.block.issuers_count as f64 * (2.0 / 3.0)) as usize + 1,
diff --git a/dal/dal_requests.rs b/dal/dal_requests.rs
index bc90b8c90f8980a422ee1026eded82ee347785d7..52fc8383f1bacf147dad27372376629fd7d3951d 100644
--- a/dal/dal_requests.rs
+++ b/dal/dal_requests.rs
@@ -16,7 +16,7 @@
 extern crate duniter_module;
 extern crate serde;
 
-use self::duniter_module::ModuleReqFullId;
+use self::duniter_module::ModuleReqId;
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::*;
 use duniter_documents::blockchain::v10::documents::{
@@ -25,26 +25,26 @@ use duniter_documents::blockchain::v10::documents::{
 use duniter_documents::Blockstamp;
 use std::collections::HashMap;
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
 /// Inter-module DAL request for pool data
 pub enum DALReqPendings {
     /// All pending identities with their pending certifications
-    AllPendingIdentities(ModuleReqFullId, usize),
+    AllPendingIdentities(usize),
     /// All pending identities without their pending certifications
-    AllPendingIdentitiesWithoutCerts(ModuleReqFullId, usize),
+    AllPendingIdentitiesWithoutCerts(usize),
     /// All pending datas for given pubkey
-    PendingWotDatasForPubkey(ModuleReqFullId, PubKey),
+    PendingWotDatasForPubkey(PubKey),
 }
 
 #[derive(Debug, Clone, PartialEq)]
 /// Inter-module DAL request for blockchain data
 pub enum DALReqBlockchain {
     /// Current block
-    CurrentBlock(ModuleReqFullId),
+    CurrentBlock(),
     /// Block by number
-    BlockByNumber(ModuleReqFullId, u64),
+    BlockByNumber(u64),
     /// Chunk (block pack)
-    Chunk(ModuleReqFullId, u64, usize),
+    Chunk(u64, usize),
     /// Usernames corresponding to the public keys in parameter
     UIDs(Vec<PubKey>),
 }
@@ -77,24 +77,24 @@ pub struct PendingIdtyDatas {
 /// Response to a DALReqPendings request
 pub enum DALResPendings {
     /// All pending identities with their pending certifications
-    AllPendingIdentities(HashMap<Hash, PendingIdtyDatas>),
+    AllPendingIdentities(ModuleReqId, HashMap<Hash, PendingIdtyDatas>),
     /// All pending identities without their pending certifications
-    AllPendingIdentitiesWithoutCerts(HashMap<Hash, PendingIdtyDatas>),
+    AllPendingIdentitiesWithoutCerts(ModuleReqId, HashMap<Hash, PendingIdtyDatas>),
     /// All pending datas for given pubkey
-    PendingWotDatasForPubkey(Box<PendingIdtyDatas>),
+    PendingWotDatasForPubkey(ModuleReqId, Box<PendingIdtyDatas>),
 }
 
 #[derive(Debug, Clone)]
 /// Response to a DALReqBlockchain request
 pub enum DALResBlockchain {
     /// Current block
-    CurrentBlock(ModuleReqFullId, Box<BlockDocument>, Blockstamp),
+    CurrentBlock(ModuleReqId, Box<BlockDocument>, Blockstamp),
     /// Block by number
-    BlockByNumber(ModuleReqFullId, Box<BlockDocument>),
+    BlockByNumber(ModuleReqId, Box<BlockDocument>),
     /// Chunk (block pack)
-    Chunk(ModuleReqFullId, Vec<BlockDocument>),
+    Chunk(ModuleReqId, Vec<BlockDocument>),
     /// Usernames corresponding to the public keys in parameter
-    UIDs(HashMap<PubKey, Option<String>>),
+    UIDs(ModuleReqId, HashMap<PubKey, Option<String>>),
 }
 
 #[derive(Debug, Clone)]
@@ -103,5 +103,5 @@ pub enum DALResponse {
     /// Response to a DALReqBlockchain request
     Blockchain(Box<DALResBlockchain>),
     /// Response to a DALReqPendings request
-    Pendings(ModuleReqFullId, Box<DALResPendings>),
+    Pendings(Box<DALResPendings>),
 }
diff --git a/dal/identity.rs b/dal/identity.rs
index c2af1aca008d66967f1ecb330c539bb596949234..03467a869814d51c3314612337b4d8791b9b1880 100644
--- a/dal/identity.rs
+++ b/dal/identity.rs
@@ -170,11 +170,13 @@ impl DALIdentity {
                 DALIdentityState::ExpireMember(renewed_counts) => {
                     DALIdentityState::ExplicitExpireRevoked(renewed_counts)
                 }
-                DALIdentityState::Member(renewed_counts) => if explicit {
-                    DALIdentityState::ExplicitRevoked(renewed_counts)
-                } else {
-                    DALIdentityState::ImplicitRevoked(renewed_counts)
-                },
+                DALIdentityState::Member(renewed_counts) => {
+                    if explicit {
+                        DALIdentityState::ExplicitRevoked(renewed_counts)
+                    } else {
+                        DALIdentityState::ImplicitRevoked(renewed_counts)
+                    }
+                }
                 _ => panic!("Try to revert revoke an already revoked idty !"),
             }
         };
diff --git a/dal/lib.rs b/dal/lib.rs
index d7c837568b80907c8b6786a76c9e01934ab8e166..853442a607d310b8b10a2445ec0b2aa986d4d414 100644
--- a/dal/lib.rs
+++ b/dal/lib.rs
@@ -16,7 +16,7 @@
 //! Datas Access Layer
 
 #![cfg_attr(feature = "strict", deny(warnings))]
-#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
+//#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
 #![cfg_attr(feature = "exp", allow(warnings))]
 #![deny(
     missing_docs,
diff --git a/dal/tools.rs b/dal/tools.rs
index 43950523ac4bbf8c05e19257e10be6311fc0e6d0..b3509912f6ec8d926565c071b81537cc5690dcda 100644
--- a/dal/tools.rs
+++ b/dal/tools.rs
@@ -113,7 +113,8 @@ pub fn compute_distances<T: WebOfTrust + Sync>(
                     step_max,
                     x_percent,
                 },
-            ).expect("Fatal Error: compute_distance return None !");
+            )
+            .expect("Fatal Error: compute_distance return None !");
         let mut distance = ((f64::from(distance_datas.success)
             / (x_percent * f64::from(distance_datas.sentries)))
             * 100.0) as usize;
diff --git a/dal/writers/block.rs b/dal/writers/block.rs
index 03c556722c7814e9ebbc790eb59c08b10b8ae4ee..d447ad41666b55d09ebb301e736b9c21a422b59a 100644
--- a/dal/writers/block.rs
+++ b/dal/writers/block.rs
@@ -101,7 +101,8 @@ pub fn write(
         forks_db
             .write(|db| {
                 db.insert(ForkId(0), blockchain_meta_datas);
-            }).expect("Write blockchain meta datas : DALError");
+            })
+            .expect("Write blockchain meta datas : DALError");
     }
     Ok(())
 }
diff --git a/dal/writers/dividend.rs b/dal/writers/dividend.rs
index e5d64193c7dbf4de63ca53b7cb80fcc07d9bc021..648240fbecc6b8c7d9b86a8a99efe78f3b87d9d3 100644
--- a/dal/writers/dividend.rs
+++ b/dal/writers/dividend.rs
@@ -50,7 +50,8 @@ pub fn create_du(
                     *pubkey,
                     db.get(&UTXOConditionsGroup::Single(
                         TransactionOutputCondition::Sig(*pubkey),
-                    )).cloned()
+                    ))
+                    .cloned()
                     .unwrap_or_default(),
                 );
             }
@@ -66,7 +67,8 @@ pub fn create_du(
                 *balance + *du_amount
             };
             (*pubkey, (new_balance, utxos_indexs.clone()))
-        }).collect();
+        })
+        .collect();
     // Write new members balance
     balances_db.write(|db| {
         for (pubkey, (balance, utxos_indexs)) in members_balances {
diff --git a/dal/writers/transaction.rs b/dal/writers/transaction.rs
index 634c471d9e7cd51dc88400239a4d1af9bd0c93b3..6fb57faaef3608f834048fe83d7b136b36b31cfb 100644
--- a/dal/writers/transaction.rs
+++ b/dal/writers/transaction.rs
@@ -141,7 +141,8 @@ pub fn revert_tx(dbs: &CurrencyV10DBs, dal_tx: &DALTxV10) -> Result<(), DALError
                 SourceIndexV10::UTXO(UTXOIndexV10(hash, tx_index)),
                 SourceAmount(tx_amout, tx_amout_base),
             ),
-        }).collect();
+        })
+        .collect();
     // Find adress of recreated sources
     let recreated_adress: HashMap<UTXOConditionsGroup, (SourceAmount, HashSet<UTXOIndexV10>)> =
         dbs.utxos_db.read(|db| {
@@ -256,7 +257,8 @@ pub fn apply_and_write_tx(
                 SourceIndexV10::UTXO(UTXOIndexV10(hash, tx_index)),
                 SourceAmount(tx_amout, tx_amout_base),
             ),
-        }).collect();
+        })
+        .collect();
     // Find adress of consumed sources
     let consumed_adress: HashMap<UTXOConditionsGroup, (SourceAmount, HashSet<UTXOIndexV10>)> =
         dbs.utxos_db.read(|db| {
@@ -423,7 +425,8 @@ mod tests {
         ).unwrap());
         let block = Blockstamp::from_string(
             "50-00001DAA4559FEDB8320D1040B0F22B631459F36F237A0D9BC1EB923C12A12E7",
-        ).unwrap();
+        )
+        .unwrap();
         let builder = TransactionDocumentBuilder {
             currency: "g1",
             blockstamp: &block,
@@ -432,7 +435,8 @@ mod tests {
             inputs: &vec![
                 TransactionInput::parse_from_str(
                     "1000:0:D:2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ:1",
-                ).expect("fail to parse input !"),
+                )
+                .expect("fail to parse input !"),
             ],
             unlocks: &vec![
                 TransactionInputUnlocks::parse_from_str("0:SIG(0)")
@@ -441,10 +445,12 @@ mod tests {
             outputs: &vec![
                 TransactionOutput::parse_from_str(
                     "1:0:SIG(Com8rJukCozHZyFao6AheSsfDQdPApxQRnz7QYFf64mm)",
-                ).expect("fail to parse output !"),
+                )
+                .expect("fail to parse output !"),
                 TransactionOutput::parse_from_str(
                     "999:0:SIG(2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ)",
-                ).expect("fail to parse output !"),
+                )
+                .expect("fail to parse output !"),
             ],
             comment: "TEST",
             hash: None,
@@ -472,15 +478,18 @@ mod tests {
             BlockId(1),
             &vec![tx_doc.issuers()[0], tortue_pubkey],
             false,
-        ).expect("Fail to create first g1 UD !");
+        )
+        .expect("Fail to create first g1 UD !");
         // Check members balance
         let cgeek_new_balance = currency_dbs
             .balances_db
             .read(|db| {
                 db.get(&UTXOConditionsGroup::Single(
                     TransactionOutputCondition::Sig(tx_doc.issuers()[0]),
-                )).cloned()
-            }).expect("Fail to read cgeek new balance")
+                ))
+                .cloned()
+            })
+            .expect("Fail to read cgeek new balance")
             .expect("Error : cgeek is not referenced in balances_db !");
         assert_eq!(cgeek_new_balance.0, SourceAmount(TxAmount(1000), TxBase(0)));
         let tortue_new_balance = currency_dbs
@@ -488,8 +497,10 @@ mod tests {
             .read(|db| {
                 db.get(&UTXOConditionsGroup::Single(
                     TransactionOutputCondition::Sig(tortue_pubkey),
-                )).cloned()
-            }).expect("Fail to read receiver new balance")
+                ))
+                .cloned()
+            })
+            .expect("Fail to read receiver new balance")
             .expect("Error : receiver is not referenced in balances_db !");
         assert_eq!(
             tortue_new_balance.0,
@@ -503,8 +514,10 @@ mod tests {
             .read(|db| {
                 db.get(&UTXOConditionsGroup::Single(
                     TransactionOutputCondition::Sig(tx_doc.issuers()[0]),
-                )).cloned()
-            }).expect("Fail to read cgeek new balance")
+                ))
+                .cloned()
+            })
+            .expect("Fail to read cgeek new balance")
             .expect("Error : cgeek is not referenced in balances_db !");
         assert_eq!(cgeek_new_balance.0, SourceAmount(TxAmount(999), TxBase(0)));
 
@@ -514,8 +527,10 @@ mod tests {
             .read(|db| {
                 db.get(&UTXOConditionsGroup::Single(
                     TransactionOutputCondition::Sig(tortue_pubkey),
-                )).cloned()
-            }).expect("Fail to read receiver new balance")
+                ))
+                .cloned()
+            })
+            .expect("Fail to read receiver new balance")
             .expect("Error : receiver is not referenced in balances_db !");
         assert_eq!(
             receiver_new_balance.0,
@@ -529,7 +544,8 @@ mod tests {
                 tx_doc: tx_doc.clone(),
                 sources_destroyed: HashSet::with_capacity(0),
             },
-        ).expect("Fail to revert first g1 tx");
+        )
+        .expect("Fail to revert first g1 tx");
 
         // Check issuer new balance
         let cgeek_new_balance = currency_dbs
@@ -537,8 +553,10 @@ mod tests {
             .read(|db| {
                 db.get(&UTXOConditionsGroup::Single(
                     TransactionOutputCondition::Sig(tx_doc.issuers()[0]),
-                )).cloned()
-            }).expect("Fail to read cgeek new balance")
+                ))
+                .cloned()
+            })
+            .expect("Fail to read cgeek new balance")
             .expect("Error : cgeek is not referenced in balances_db !");
         assert_eq!(cgeek_new_balance.0, SourceAmount(TxAmount(1000), TxBase(0)));
 
@@ -548,8 +566,10 @@ mod tests {
             .read(|db| {
                 db.get(&UTXOConditionsGroup::Single(
                     TransactionOutputCondition::Sig(tortue_pubkey),
-                )).cloned()
-            }).expect("Fail to read receiver new balance")
+                ))
+                .cloned()
+            })
+            .expect("Fail to read receiver new balance")
             .expect("Error : receiver is not referenced in balances_db !");
         assert_eq!(
             receiver_new_balance.0,
diff --git a/documents/blockchain/mod.rs b/documents/blockchain/mod.rs
index 4ddea4f316c2dcbec5c72265242e2da8d3e1bdfd..64edf826a48de9a18793acf829dde9dd8735e0bd 100644
--- a/documents/blockchain/mod.rs
+++ b/documents/blockchain/mod.rs
@@ -202,7 +202,8 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
             ed25519::Signature::from_base64(
                 "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
                  mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
-            ).unwrap(),
+            )
+            .unwrap(),
         );
 
         // incorrect pair
@@ -215,7 +216,8 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
             ed25519::Signature::from_base64(
                 "1eubHHbuNfilHHH0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
                  mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
-            ).unwrap(),
+            )
+            .unwrap(),
         );
 
         {
diff --git a/documents/blockchain/v10/documents/certification.rs b/documents/blockchain/v10/documents/certification.rs
index 0d2b889e0f0dd89cee75dc4ab0904af685a7b93c..e03213f00917646239df20f8d8270860efa8c172 100644
--- a/documents/blockchain/v10/documents/certification.rs
+++ b/documents/blockchain/v10/documents/certification.rs
@@ -301,7 +301,8 @@ mod tests {
 
         let identity_blockstamp = Blockstamp::from_string(
             "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
-        ).unwrap();
+        )
+        .unwrap();
 
         let identity_sig = Sig::Ed25519(ed25519::Signature::from_base64(
             "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
@@ -309,7 +310,8 @@ mod tests {
 
         let blockstamp = Blockstamp::from_string(
             "36-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B865",
-        ).unwrap();
+        )
+        .unwrap();
 
         let builder = CertificationDocumentBuilder {
             currency: "duniter_unit_test_currency",
@@ -378,11 +380,11 @@ CertTimestamp: 167884-0001DFCA28002A8C96575E53B8CEF8317453A7B0BA255542CCF0EC8AB5
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid());
         /*assert_eq!(
-                doc.generate_compact_text(),
-                "2sZF6j2PkxBDNAqUde7Dgo5x3crkerZpQ4rBqqJGn8QT:\
-                7jzkd8GiFnpys4X7mP78w2Y3y3kwdK6fVSLEaojd3aH9:99956:\
-                Hkps1QU4HxIcNXKT8YmprYTVByBhPP1U2tIM7Z8wENzLKIWAvQClkAvBE7pW9dnVa18sJIJhVZUcRrPAZfmjBA=="
-            );*/
+            doc.generate_compact_text(),
+            "2sZF6j2PkxBDNAqUde7Dgo5x3crkerZpQ4rBqqJGn8QT:\
+            7jzkd8GiFnpys4X7mP78w2Y3y3kwdK6fVSLEaojd3aH9:99956:\
+            Hkps1QU4HxIcNXKT8YmprYTVByBhPP1U2tIM7Z8wENzLKIWAvQClkAvBE7pW9dnVa18sJIJhVZUcRrPAZfmjBA=="
+        );*/
         } else {
             panic!("Wrong document type");
         }
diff --git a/documents/blockchain/v10/documents/identity.rs b/documents/blockchain/v10/documents/identity.rs
index efa612facf7dca786bd8a87c2588a8305a94b949..4eacf71e517e38cf909d46a1c5ccc4ef4a621dfc 100644
--- a/documents/blockchain/v10/documents/identity.rs
+++ b/documents/blockchain/v10/documents/identity.rs
@@ -254,19 +254,22 @@ mod tests {
             ed25519::PrivateKey::from_base58(
                 "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5G\
                  iERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-            ).unwrap(),
+            )
+            .unwrap(),
         );
 
         let sig = Sig::Ed25519(
             ed25519::Signature::from_base64(
                 "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGM\
                  MmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
-            ).unwrap(),
+            )
+            .unwrap(),
         );
 
         let block = Blockstamp::from_string(
             "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
-        ).unwrap();
+        )
+        .unwrap();
 
         let builder = IdentityDocumentBuilder {
             currency: "duniter_unit_test_currency",
diff --git a/documents/blockchain/v10/documents/membership.rs b/documents/blockchain/v10/documents/membership.rs
index 2d30391a8c2431b6e5f6ef6665bb7cc3e88bda5f..3e3fb554a114a3b3bca72af5167c073e4795680a 100644
--- a/documents/blockchain/v10/documents/membership.rs
+++ b/documents/blockchain/v10/documents/membership.rs
@@ -29,7 +29,8 @@ lazy_static! {
          Membership: (?P<membership>(IN|OUT))\n\
          UserID: (?P<ity_user>[[:alnum:]_-]+)\n\
          CertTS: (?P<ity_block>[0-9]+-[0-9A-F]{64})\n$"
-    ).unwrap();
+    )
+    .unwrap();
 }
 
 /// Type of a Membership.
@@ -320,19 +321,22 @@ mod tests {
             ed25519::PrivateKey::from_base58(
                 "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5G\
                  iERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-            ).unwrap(),
+            )
+            .unwrap(),
         );
 
         let sig = Sig::Ed25519(
             ed25519::Signature::from_base64(
                 "s2hUbokkibTAWGEwErw6hyXSWlWFQ2UWs2PWx8d/kkEl\
                  AyuuWaQq4Tsonuweh1xn4AC1TVWt4yMR3WrDdkhnAw==",
-            ).unwrap(),
+            )
+            .unwrap(),
         );
 
         let block = Blockstamp::from_string(
             "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
-        ).unwrap();
+        )
+        .unwrap();
 
         let builder = MembershipDocumentBuilder {
             currency: "duniter_unit_test_currency",
diff --git a/documents/blockchain/v10/documents/mod.rs b/documents/blockchain/v10/documents/mod.rs
index 1cb541650b0479fc316bee80c4a27391db113044..3e3d2137834cf3b39e400e49c0858e4b84306538 100644
--- a/documents/blockchain/v10/documents/mod.rs
+++ b/documents/blockchain/v10/documents/mod.rs
@@ -49,7 +49,8 @@ lazy_static! {
          Currency: (?P<currency>[[:alnum:] _-]+)\n\
          (?P<body>(?:.*\n)+?))\
          (?P<sigs>([[:alnum:]+/=]+\n)*([[:alnum:]+/=]+))$"
-    ).unwrap();
+    )
+    .unwrap();
     static ref SIGNATURES_REGEX: Regex = Regex::new("[[:alnum:]+/=]+\n?").unwrap();
 }
 
@@ -321,7 +322,8 @@ SoKwoa8PFfCDJWZ6dNCv7XstezHcc2BbKiJgVDXv82R5zYR83nis9dShLgWJ5w48noVUHimdngzYQneN
 42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
 2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX
 2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk"
-                ).count(),
+                )
+                .count(),
             3
         );
 
@@ -331,7 +333,8 @@ SoKwoa8PFfCDJWZ6dNCv7XstezHcc2BbKiJgVDXv82R5zYR83nis9dShLgWJ5w48noVUHimdngzYQneN
                     "
 42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
 2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk"
-                ).count(),
+                )
+                .count(),
             2
         );
     }
diff --git a/documents/blockchain/v10/documents/revocation.rs b/documents/blockchain/v10/documents/revocation.rs
index 41032871f1e1a3236e62e31d4b86906057162a40..2b059615dd288fe146d215be1dfb0bbe1382554c 100644
--- a/documents/blockchain/v10/documents/revocation.rs
+++ b/documents/blockchain/v10/documents/revocation.rs
@@ -252,7 +252,8 @@ mod tests {
             ed25519::PrivateKey::from_base58(
                 "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5G\
                  iERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-            ).unwrap(),
+            )
+            .unwrap(),
         );
 
         let sig = Sig::Ed25519(ed25519::Signature::from_base64(
@@ -261,7 +262,8 @@ mod tests {
 
         let identity_blockstamp = Blockstamp::from_string(
             "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
-        ).unwrap();
+        )
+        .unwrap();
 
         let identity_sig = Sig::Ed25519(ed25519::Signature::from_base64(
             "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
diff --git a/documents/blockchain/v10/documents/transaction.rs b/documents/blockchain/v10/documents/transaction.rs
index 30b0207acc95b7e366f3736b2f0b677fdb3866ab..94006b10d83835b2bff23022c92aeffeaa6d087c 100644
--- a/documents/blockchain/v10/documents/transaction.rs
+++ b/documents/blockchain/v10/documents/transaction.rs
@@ -825,7 +825,8 @@ mod tests {
             ed25519::PrivateKey::from_base58(
                 "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5G\
                  iERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-            ).unwrap(),
+            )
+            .unwrap(),
         );
 
         let sig = Sig::Ed25519(ed25519::Signature::from_base64(
@@ -834,7 +835,8 @@ mod tests {
 
         let block = Blockstamp::from_string(
             "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
-        ).unwrap();
+        )
+        .unwrap();
 
         let builder = TransactionDocumentBuilder {
             currency: "duniter_unit_test_currency",
@@ -844,7 +846,8 @@ mod tests {
             inputs: &vec![
                 TransactionInput::parse_from_str(
                     "10:0:D:DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV:0",
-                ).expect("fail to parse input !"),
+                )
+                .expect("fail to parse input !"),
             ],
             unlocks: &vec![
                 TransactionInputUnlocks::parse_from_str("0:SIG(0)")
@@ -853,7 +856,8 @@ mod tests {
             outputs: &vec![
                 TransactionOutput::parse_from_str(
                     "10:0:SIG(FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa)",
-                ).expect("fail to parse output !"),
+                )
+                .expect("fail to parse output !"),
             ],
             comment: "test",
             hash: None,
@@ -885,7 +889,8 @@ mod tests {
 
         let block = Blockstamp::from_string(
             "60-00001FE00410FCD5991EDD18AA7DDF15F4C8393A64FA92A1DB1C1CA2E220128D",
-        ).unwrap();
+        )
+        .unwrap();
 
         let builder = TransactionDocumentBuilder {
             currency: "g1",
@@ -895,7 +900,8 @@ mod tests {
             inputs: &vec![
                 TransactionInput::parse_from_str(
                     "950:0:T:2CF1ACD8FE8DC93EE39A1D55881C50D87C55892AE8E4DB71D4EBAB3D412AA8FD:1",
-                ).expect("fail to parse input !"),
+                )
+                .expect("fail to parse input !"),
             ],
             unlocks: &vec![
                 TransactionInputUnlocks::parse_from_str("0:SIG(0)")
@@ -904,10 +910,12 @@ mod tests {
             outputs: &vec![
                 TransactionOutput::parse_from_str(
                     "30:0:SIG(38MEAZN68Pz1DTvT3tqgxx4yQP6snJCQhPqEFxbDk4aE)",
-                ).expect("fail to parse output !"),
+                )
+                .expect("fail to parse output !"),
                 TransactionOutput::parse_from_str(
                     "920:0:SIG(FEkbc4BfJukSWnCU6Hed6dgwwTuPFTVdgz5LpL4iHr9J)",
-                ).expect("fail to parse output !"),
+                )
+                .expect("fail to parse output !"),
             ],
             comment: "Pour cesium merci",
             hash: None,
diff --git a/message/lib.rs b/message/lib.rs
index b4bc903f3361139e416e199d6cb3c1ea6bdfbfcc..c2143f494df34a1343bd7dd6a9955490963562bf 100644
--- a/message/lib.rs
+++ b/message/lib.rs
@@ -37,40 +37,55 @@ extern crate duniter_network;
 extern crate serde;
 extern crate serde_json;
 
-use std::sync::mpsc;
-
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::Sig;
 use duniter_dal::dal_event::DALEvent;
 use duniter_dal::dal_requests::{DALRequest, DALResponse};
 use duniter_documents::blockchain::BlockchainProtocol;
 use duniter_documents::BlockId;
-use duniter_module::{ModuleId, ModuleMessage};
-use duniter_network::{NetworkEvent, NetworkRequest};
+use duniter_module::*;
+use duniter_network::{NetworkEvent, NetworkResponse, OldNetworkRequest};
+
+#[derive(Debug, Clone)]
+/// Message exchanged between Durs modules
+pub struct DursMsg(pub DursMsgReceiver, pub DursMsgContent);
+
+impl ModuleMessage for DursMsg {}
+
+/// The recipient of a message
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum DursMsgReceiver {
+    /// Message for all modules
+    All,
+    /// Message for one specific module
+    One(ModuleStaticName),
+    /// Message for all modules who play a specific role
+    Role(ModuleRole),
+    /// Message for all modules that are subscribed to a specific type of event
+    Event(ModuleEvent),
+}
 
 #[derive(Debug, Clone)]
-/// Message exchanged between Duniter-rs modules
-pub enum DuniterMessage {
+/// Content of message exchanged between Durs modules
+pub enum DursMsgContent {
+    /// Request
+    Request(DursReq),
     /// Brut text message
     Text(String),
     /// Brut binary message
     Binary(Vec<u8>),
     /// New configuration of a module to save
-    SaveNewModuleConf(ModuleId, serde_json::Value),
-    /// Subscriptions to the module feed
-    Followers(Vec<mpsc::Sender<DuniterMessage>>),
-    /// Blockchain datas request
-    DALRequest(DALRequest),
+    SaveNewModuleConf(ModuleName, serde_json::Value),
     /// Response of DALRequest
     DALResponse(Box<DALResponse>),
     /// Blockchain event
     DALEvent(DALEvent),
     /// Request to the network module
-    NetworkRequest(NetworkRequest),
+    OldNetworkRequest(OldNetworkRequest),
     /// Network event
     NetworkEvent(NetworkEvent),
-    /// Request to the pow module
-    ProverRequest(BlockId, Hash),
+    /// Response of OldNetworkRequest
+    NetworkResponse(NetworkResponse),
     /// Pow module response
     ProverResponse(BlockId, Sig, u64),
     /// Client API event
@@ -79,4 +94,28 @@ pub enum DuniterMessage {
     Stop(),
 }
 
-impl ModuleMessage for DuniterMessage {}
+#[derive(Debug, Clone)]
+/// Durs modules requests
+pub struct DursReq {
+    /// Requester
+    pub requester: ModuleStaticName,
+    /// Request unique id
+    pub id: ModuleReqId,
+    /// Request content
+    pub content: DursReqContent,
+}
+
+#[derive(Debug, Clone)]
+/// Modules request content
+pub enum DursReqContent {
+    /// Network request (Not yet implemented)
+    NetworkRequest(),
+    /// Blockchain datas request
+    DALRequest(DALRequest),
+    /// Request to the pow module
+    ProverRequest(BlockId, Hash),
+    /// Brut text request
+    Text(String),
+    /// Brut binary request
+    Binary(Vec<u8>),
+}
diff --git a/module/Cargo.toml b/module/Cargo.toml
index 37f5d5afb9f318f097c5a50404ed2961a1c68bef..89d17afb5c1a09de22449253c27b7d618e9d6f6b 100644
--- a/module/Cargo.toml
+++ b/module/Cargo.toml
@@ -14,6 +14,7 @@ duniter-documents = { path = "../documents" }
 serde = "1.0.*"
 serde_derive = "1.0.*"
 serde_json = "1.0.*"
+structopt= "0.2.*"
 
 [features]
 # Treat warnings as a build error.
diff --git a/module/lib.rs b/module/lib.rs
index 2122c1a2afa8ffb0882174378d6eaed223d31da1..009c00acb55eb5cf4c9db8db54dbf851fbc5e37d 100644
--- a/module/lib.rs
+++ b/module/lib.rs
@@ -17,7 +17,6 @@
 //! as well as the DuniterModule trait that all modules must implement.
 
 #![cfg_attr(feature = "strict", deny(warnings))]
-#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
 #![deny(
     missing_docs,
     missing_debug_implementations,
@@ -37,6 +36,7 @@ extern crate duniter_crypto;
 extern crate duniter_documents;
 extern crate serde;
 extern crate serde_json;
+extern crate structopt;
 
 use duniter_crypto::keys::{KeyPair, KeyPairEnum};
 use duniter_documents::CurrencyName;
@@ -45,12 +45,36 @@ use serde::ser::{Serialize, Serializer};
 use std::collections::HashSet;
 use std::fmt::Debug;
 use std::sync::mpsc;
+//use structopt::clap::ArgMatches;
+use structopt::StructOpt;
+
+#[derive(Copy, Clone, Deserialize, Debug, PartialEq, Eq, Hash, Serialize)]
+/// Store module name in static lifetime
+pub struct ModuleStaticName(pub &'static str);
+
+impl ToString for ModuleStaticName {
+    fn to_string(&self) -> String {
+        String::from(self.0)
+    }
+}
 
 #[derive(Clone, Deserialize, Debug, PartialEq, Eq, Hash, Serialize)]
-/// Store module identifier
-pub struct ModuleId(pub String);
+/// Store module name
+pub struct ModuleName(pub String);
+
+impl From<ModuleStaticName> for ModuleName {
+    fn from(source: ModuleStaticName) -> Self {
+        ModuleName(String::from(source.0))
+    }
+}
+
+impl<'a> From<&'a str> for ModuleName {
+    fn from(source: &str) -> Self {
+        ModuleName(String::from(source))
+    }
+}
 
-impl ToString for ModuleId {
+impl ToString for ModuleName {
     fn to_string(&self) -> String {
         self.0.clone()
     }
@@ -69,10 +93,10 @@ impl Serialize for ModuleReqId {
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 /// Several modules can simultaneously send requests with the same identifier.
 /// To identify each request in a unique way, we must therefore also take into account the identifier of the module performing the request.
-pub struct ModuleReqFullId(pub ModuleId, pub ModuleReqId);
+pub struct ModuleReqFullId(pub ModuleStaticName, pub ModuleReqId);
 
 impl ToString for ModuleReqFullId {
     fn to_string(&self) -> String {
@@ -91,15 +115,17 @@ pub trait DuniterConf: Clone + Debug + Default + PartialEq + Serialize + Deseria
     /// Get node id
     fn my_node_id(&self) -> u32;
     /// Disable a module
-    fn disable(&mut self, module: ModuleId);
+    fn disable(&mut self, module: ModuleName);
     /// Enable a module
-    fn enable(&mut self, module: ModuleId);
+    fn enable(&mut self, module: ModuleName);
     /// Get disabled modules
-    fn disabled_modules(&self) -> HashSet<ModuleId>;
+    fn disabled_modules(&self) -> HashSet<ModuleName>;
     /// Get enabled modules
-    fn enabled_modules(&self) -> HashSet<ModuleId>;
+    fn enabled_modules(&self) -> HashSet<ModuleName>;
     /// Get modules conf
     fn modules(&self) -> serde_json::Value;
+    /// Change module conf
+    fn set_module_conf(&mut self, module_id: String, new_module_conf: serde_json::Value);
 }
 
 /// Sofware meta datas
@@ -119,6 +145,58 @@ pub struct SoftwareMetaDatas<DC: DuniterConf> {
 /// provided that this type implements the ModuleMessage trait.
 pub trait ModuleMessage: Clone + Debug {}
 
+/// List of the different roles that can be assigned to a module.
+/// This role list allows a module to send a message to all modules playing a specific role without knowing their name.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum ModuleRole {
+    /// Manages the blockchain data (include forks datas)
+    BlockchainDatas,
+    /// Checks if a block complies with the entire blockchain protocol
+    BlockValidation,
+    /// Generates the content of the next block
+    BlockGeneration,
+    /// Manage pending data for the wot
+    WotPool,
+    /// Manage pending data for the currency (transactions and scripts)
+    CurrencyPool,
+    /// Manages the network between nodes implementing the DUP protocol
+    InterNodesNetwork,
+    /// Communicates with client software
+    ClientsNetwork,
+    /// Communicates with the node user
+    UserInterface,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+///List of the different types of events that can be generated by a module.
+/// This list allows the different modules to subscribe only to the types of events that interest them
+pub enum ModuleEvent {
+    /// A new block has been received from the network
+    NewBlockFromNetwork,
+    /// A new transaction has been received from a client software.
+    NewTxFromNetwork,
+    /// A new wot document has been received from a network.
+    NewWotDocFromNetwork,
+    /// A new valid block has been added to the local blockchain
+    NewValidBlock,
+    /// A new valid block issued by the local node has been added to the local blockchain
+    NewValidBlockFromSelf,
+    /// A new non-isolated fork is in the local database
+    NewFork,
+    /// Blockchain rooling back
+    RevertBlocks,
+    /// A new transaction has been integrated into the local waiting room
+    NewTxinPool,
+    /// A new wot document has been integrated into the local waiting room
+    NewWotDocInPool,
+    /// A new valid HEAD has been received from the network
+    NewValidHeadFromNetwork,
+    /// Change in connections with other nodes (disconnection of a connection or establishment of a new connection)
+    ConnectionsChangeNodeNetwork,
+    /// A new valid peer record has been received from the network
+    NewValidPeerFromNodeNetwork,
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 /// Type returned by module initialization function
 pub enum ModuleInitError {
@@ -132,9 +210,14 @@ pub enum ModuleInitError {
 /// Type sent by each module to the rooter during initialization
 pub enum RooterThreadMessage<M: ModuleMessage> {
     /// Channel on which the module listens
-    ModuleSender(mpsc::Sender<M>),
-    /// When the number of plugged modules is known, the rooter thread must be informed of the number of modules it must connect between them.
-    ModulesCount(usize),
+    ModuleSender(
+        ModuleStaticName,
+        mpsc::Sender<M>,
+        Vec<ModuleRole>,
+        Vec<ModuleEvent>,
+    ),
+    /// Module message
+    ModuleMessage(M),
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -186,8 +269,8 @@ pub fn enabled<DC: DuniterConf, Mess: ModuleMessage, M: DuniterModule<DC, Mess>>
     let enabled_modules = conf.enabled_modules();
     match M::priority() {
         ModulePriority::Essential() => true,
-        ModulePriority::Recommended() => !disabled_modules.contains(&M::id()),
-        ModulePriority::Optional() => enabled_modules.contains(&M::id()),
+        ModulePriority::Recommended() => !disabled_modules.contains(&ModuleName::from(M::name())),
+        ModulePriority::Optional() => enabled_modules.contains(&ModuleName::from(M::name())),
     }
 }
 
@@ -204,9 +287,14 @@ pub enum ModulesFilter {
 }
 
 /// Returns true only if the module checks all filters
-pub fn module_valid_filters<DC: DuniterConf, Mess: ModuleMessage, M: DuniterModule<DC, Mess>>(
+pub fn module_valid_filters<
+    DC: DuniterConf,
+    Mess: ModuleMessage,
+    M: DuniterModule<DC, Mess>,
+    S: ::std::hash::BuildHasher,
+>(
     conf: &DC,
-    filters: &HashSet<ModulesFilter>,
+    filters: &HashSet<ModulesFilter, S>,
     network_module: bool,
 ) -> bool {
     if filters.contains(&ModulesFilter::Network()) && !network_module {
@@ -230,13 +318,26 @@ pub fn module_valid_filters<DC: DuniterConf, Mess: ModuleMessage, M: DuniterModu
 pub trait DuniterModule<DC: DuniterConf, M: ModuleMessage> {
     /// Module configuration
     type ModuleConf: Clone + Debug + Default + DeserializeOwned + Send + Serialize + Sync;
+    /// Module subcommand options
+    type ModuleOpt: StructOpt;
 
-    /// Returns the module identifier
-    fn id() -> ModuleId;
+    /// Returns the module name
+    fn name() -> ModuleStaticName;
     /// Returns the module priority
     fn priority() -> ModulePriority;
     /// Indicates which keys the module needs
     fn ask_required_keys() -> RequiredKeys;
+    /// Define if module have a cli subcommand
+    fn have_subcommand() -> bool {
+        false
+    }
+    /// Execute injected subcommand
+    fn exec_subcommand(
+        soft_meta_datas: &SoftwareMetaDatas<DC>,
+        keys: RequiredKeysContent,
+        module_conf: Self::ModuleConf,
+        subcommand_args: Self::ModuleOpt,
+    ) -> ();
     /// Launch the module
     fn start(
         soft_meta_datas: &SoftwareMetaDatas<DC>,
diff --git a/network/lib.rs b/network/lib.rs
index 90eef25982cbe2bf9e28aa371235379316eec110..4a0ed49cb6d8d5f695c5857712e7a8bb7efc7098 100644
--- a/network/lib.rs
+++ b/network/lib.rs
@@ -85,10 +85,21 @@ pub trait NetworkModule<DC: DuniterConf, M: ModuleMessage>: ApiModule<DC, M> {
         keys: RequiredKeysContent,
         module_conf: <Self as DuniterModule<DC, M>>::ModuleConf,
         main_sender: mpsc::Sender<RooterThreadMessage<M>>,
-        sync_endpoint: SyncEndpoint,
+        sync_params: SyncParams,
     ) -> Result<(), ModuleInitError>;
 }
 
+/// SyncParams
+#[derive(Debug, Clone)]
+pub struct SyncParams {
+    /// Synchronisation endpoint
+    pub sync_endpoint: SyncEndpoint,
+    /// Cautious flag
+    pub cautious: bool,
+    /// VERIF_HASHS flag
+    pub verif_hashs: bool,
+}
+
 #[derive(Debug, Clone)]
 /// Synchronisation endpoint
 pub struct SyncEndpoint {
@@ -246,12 +257,12 @@ pub enum NetworkConsensusError {
     Fork(),
 }
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
 /// Type containing a request addressed to the network module
-pub enum NetworkRequest {
+pub enum OldNetworkRequest {
     /// Get a current block of a specific node
     GetCurrent(ModuleReqFullId, NodeFullId),
-    //GetBlock(ModuleReqFullId, NodeFullId, u64),
+    //GetBlock(NodeFullId, u64),
     /// Get a blocks chunk from specified node
     GetBlocks(ModuleReqFullId, NodeFullId, u32, u32),
     /// Get pending wot documents from specified node
@@ -264,16 +275,16 @@ pub enum NetworkRequest {
     GetEndpoints(ModuleReqFullId),
 }
 
-impl NetworkRequest {
+impl OldNetworkRequest {
     /// Get request full identitifier
     pub fn get_req_full_id(&self) -> ModuleReqFullId {
         match *self {
-            NetworkRequest::GetCurrent(ref req_id, _)
-            | NetworkRequest::GetBlocks(ref req_id, _, _, _)
-            | NetworkRequest::GetRequirementsPending(ref req_id, _, _)
-            | NetworkRequest::GetConsensus(ref req_id)
-            | NetworkRequest::GetHeadsCache(ref req_id)
-            | NetworkRequest::GetEndpoints(ref req_id) => req_id.clone(),
+            OldNetworkRequest::GetCurrent(ref req_id, _)
+            | OldNetworkRequest::GetBlocks(ref req_id, _, _, _)
+            | OldNetworkRequest::GetRequirementsPending(ref req_id, _, _)
+            | OldNetworkRequest::GetConsensus(ref req_id)
+            | OldNetworkRequest::GetHeadsCache(ref req_id)
+            | OldNetworkRequest::GetEndpoints(ref req_id) => *req_id,
         }
     }
     /// Get request identitifier
@@ -284,7 +295,7 @@ impl NetworkRequest {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 /// Type returned when the network module does not get a satisfying answer to a request
-pub enum NetworkRequestError {
+pub enum OldNetworkRequestError {
     /// Receiving an invalid format response
     WrongFormat(),
     /// Unknow error
@@ -321,7 +332,7 @@ impl NetworkResponse {
             | NetworkResponse::Chunk(ref req_id, _, _)
             | NetworkResponse::PendingDocuments(ref req_id, _)
             | NetworkResponse::Consensus(ref req_id, _)
-            | NetworkResponse::HeadsCache(ref req_id, _) => req_id.clone(),
+            | NetworkResponse::HeadsCache(ref req_id, _) => *req_id,
         }
     }
     /// Get request identifier
@@ -333,8 +344,6 @@ impl NetworkResponse {
 #[derive(Debug, Clone)]
 /// Type containing a network event, each time a network event occurs it's relayed to all modules
 pub enum NetworkEvent {
-    /// Receiving a response to a network request
-    ReqResponse(Box<NetworkResponse>),
     /// A connection has changed state(`u32` is the new state, `Option<String>` est l'uid du noeud)
     ConnectionStateChange(NodeFullId, u32, Option<String>, String),
     /// Receiving Pending Documents
diff --git a/network/network_head_v3.rs b/network/network_head_v3.rs
index 99ac157f48bfa8165809f07a4b5aec9d041977e2..b227b94b1d4ce0f0195a2e32fee488f5e0af62dd 100644
--- a/network/network_head_v3.rs
+++ b/network/network_head_v3.rs
@@ -166,7 +166,8 @@ mod tests {
                 pubkey: PubKey::Ed25519(keypair1().public_key()),
                 blockstamp: Blockstamp::from_string(
                     "50-000005B1CEB4EC5245EF7E33101A330A1C9A358EC45A25FC13F78BB58C9E7370",
-                ).unwrap(),
+                )
+                .unwrap(),
                 software: String::from("durs"),
                 soft_version: String::from("0.1.0-a0.1"),
                 signature: None,
diff --git a/network/network_peer.rs b/network/network_peer.rs
index 8a62a434ed2aa3730b27c2f5b8fb91714a7cdbc1..d0b7bf9f30acc55155456c3811f43129bd857364 100644
--- a/network/network_peer.rs
+++ b/network/network_peer.rs
@@ -194,7 +194,8 @@ mod tests {
             node_id: NodeId(0),
             blockstamp: Blockstamp::from_string(
                 "50-000005B1CEB4EC5245EF7E33101A330A1C9A358EC45A25FC13F78BB58C9E7370",
-            ).unwrap(),
+            )
+            .unwrap(),
             endpoints: vec![
                 EndpointEnum::V2(create_endpoint_v2()),
                 EndpointEnum::V2(create_second_endpoint_v2()),
diff --git a/src/main.rs b/src/main.rs
index b4e8bb10093c4f7d188cacdf4991f96a19b3aefd..14bb6220dfe44e2388defddf5221acae6e052b93 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -29,42 +29,101 @@
 )]
 
 extern crate duniter_core;
-#[cfg(feature = "tui")]
+#[cfg(unix)]
 extern crate duniter_tui;
 extern crate durs_ws2p_v1_legacy;
 //extern crate durs_ws2p;
+extern crate structopt;
 
-pub use duniter_core::DuRsConf;
-pub use duniter_core::DuniterCore;
-#[cfg(feature = "tui")]
+pub use duniter_core::{cli::DursOpt, DuRsConf, DuniterCore, UserCommand};
+#[cfg(unix)]
 pub use duniter_tui::TuiModule;
 pub use durs_ws2p_v1_legacy::WS2PModule;
 //pub use durs_ws2p::WS2Pv2Module;
+use structopt::StructOpt;
 
 /// Main function
+#[cfg(unix)]
+#[cfg(not(target_arch = "arm"))]
 fn main() {
     // Get software name and version
     let soft_name = env!("CARGO_PKG_NAME");
     let soft_version = env!("CARGO_PKG_VERSION");
 
-    // Run duniter core
-    if let Some(mut duniter_core) = DuniterCore::<DuRsConf>::new(soft_name, soft_version) {
+    // Instantiate duniter core
+    let clap_app = DursOpt::clap();
+    let mut duniter_core = DuniterCore::<DuRsConf>::new(soft_name, soft_version, &clap_app, 0);
+
+    // Inject plugins subcommands
+    //duniter_core.inject_cli_subcommand::<GvaModule>();
+    duniter_core.inject_cli_subcommand::<TuiModule>();
+    duniter_core.inject_cli_subcommand::<WS2PModule>();
+
+    // Match user command
+    if duniter_core.match_user_command() {
+        // Plug all plugins
+        //duniter_core.plug::<GuiModule>();
+        //duniter_core.plug::<GvaModule>();
+        //duniter_core.plug::<PoolModule>();
+        //duniter_core.plug::<PowModule>();
+        duniter_core.plug::<TuiModule>();
+        duniter_core.plug_network::<WS2PModule>();
+        duniter_core.start_core();
+    }
+}
+#[cfg(unix)]
+#[cfg(target_arch = "arm")]
+fn main() {
+    // Get software name and version
+    let soft_name = env!("CARGO_PKG_NAME");
+    let soft_version = env!("CARGO_PKG_VERSION");
+
+    // Instantiate duniter core
+    let clap_app = DursOpt::clap();
+    let mut duniter_core = DuniterCore::<DuRsConf>::new(soft_name, soft_version, &clap_app, 0);
+
+    // Inject plugins subcommands
+    //duniter_core.inject_cli_subcommand::<DasaModule>();
+    //duniter_core.inject_cli_subcommand::<GvaModule>();
+    duniter_core.inject_cli_subcommand::<TuiModule>();
+    duniter_core.inject_cli_subcommand::<WS2PModule>();
+
+    // Match user command
+    if duniter_core.match_user_command() {
+        // Plug all plugins
         //duniter_core.plug::<DasaModule>();
         //duniter_core.plug::<GuiModule>();
         //duniter_core.plug::<GvaModule>();
         //duniter_core.plug::<PoolModule>();
         //duniter_core.plug::<PowModule>();
-        plug_tui_module(&mut duniter_core);
+        duniter_core.plug::<TuiModule>();
         duniter_core.plug_network::<WS2PModule>();
-        //duniter_core.plug_network::<WS2Pv2Module>();
-        duniter_core.start_blockchain();
-    };
+        duniter_core.start_core();
+    }
 }
+#[cfg(windows)]
+fn main() {
+    // Get software name and version
+    let soft_name = env!("CARGO_PKG_NAME");
+    let soft_version = env!("CARGO_PKG_VERSION");
+
+    // Instantiate duniter core
+    let clap_app = DursOpt::clap();
+    let mut duniter_core = DuniterCore::<DuRsConf>::new(soft_name, soft_version, &clap_app, 0);
+
+    // Inject plugins subcommands
+    //duniter_core.inject_cli_subcommand::<GvaModule>();
+    duniter_core.inject_cli_subcommand::<WS2PModule>();
 
-/// Plug TUI Module
-#[cfg(feature = "tui")]
-fn plug_tui_module(duniter_core: &mut DuniterCore<DuRsConf>) {
-    duniter_core.plug::<TuiModule>();
+    // Match user command
+    if duniter_core.match_user_command() {
+        // Plug all plugins
+        //duniter_core.plug::<DasaModule>();
+        //duniter_core.plug::<GuiModule>();
+        //duniter_core.plug::<GvaModule>();
+        //duniter_core.plug::<PoolModule>();
+        //duniter_core.plug::<PowModule>();
+        duniter_core.plug_network::<WS2PModule>();
+        duniter_core.start_core();
+    }
 }
-#[cfg(not(feature = "tui"))]
-fn plug_tui_module(_duniter_core: &mut DuniterCore<DuRsConf>) {}
diff --git a/tui/Cargo.toml b/tui/Cargo.toml
index 3e7c9c00f52d8fac2bfa0437175a75f03c07df5b..044e90e971096e286a320ecc45cd311b4df6e86a 100644
--- a/tui/Cargo.toml
+++ b/tui/Cargo.toml
@@ -20,6 +20,7 @@ log = "0.4.*"
 serde = "1.0.*"
 serde_derive = "1.0.*"
 serde_json = "1.0.*"
+structopt= "0.2.*"
 termion = "1.5.*"
 
 [features]
diff --git a/tui/lib.rs b/tui/lib.rs
index 67fa4b46af949ecf2a5d8e3978028d00230eb8c5..18cd3a7f4d6f259f1e635e9510fa9517d53f9925 100644
--- a/tui/lib.rs
+++ b/tui/lib.rs
@@ -33,6 +33,8 @@
 extern crate log;
 #[macro_use]
 extern crate serde_derive;
+#[macro_use]
+extern crate structopt;
 
 extern crate duniter_conf;
 extern crate duniter_crypto;
@@ -42,11 +44,12 @@ extern crate duniter_message;
 extern crate duniter_module;
 extern crate duniter_network;
 extern crate serde;
+extern crate serde_json;
 extern crate termion;
 
 use duniter_conf::DuRsConf;
 use duniter_dal::dal_event::DALEvent;
-use duniter_message::DuniterMessage;
+use duniter_message::*;
 use duniter_module::*;
 use duniter_network::network_head::NetworkHead;
 use duniter_network::{NetworkEvent, NodeFullId};
@@ -61,13 +64,17 @@ use termion::input::{MouseTerminal, TermRead};
 use termion::raw::{IntoRawMode, RawTerminal};
 use termion::{clear, color, cursor, style};
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
 /// Tui Module Configuration (For future use)
-pub struct TuiConf {}
+pub struct TuiConf {
+    test_fake_conf_field: String,
+}
 
 impl Default for TuiConf {
     fn default() -> Self {
-        TuiConf {}
+        TuiConf {
+            test_fake_conf_field: String::from("default"),
+        }
     }
 }
 
@@ -75,7 +82,7 @@ impl Default for TuiConf {
 /// Format of messages received by the tui module
 pub enum TuiMess {
     /// Message from another module
-    DuniterMessage(Box<DuniterMessage>),
+    DursMsg(Box<DursMsg>),
     /// Message from stdin (user event)
     TermionEvent(Event),
 }
@@ -84,6 +91,17 @@ pub enum TuiMess {
 /// Tui module
 pub struct TuiModule {}
 
+#[derive(StructOpt, Debug, Clone)]
+#[structopt(
+    name = "tui",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// Tui subcommand options
+pub struct TuiOpt {
+    /// Change test conf fake field
+    pub new_conf_field: String,
+}
+
 #[derive(Debug, Clone)]
 /// Network connexion (data to display)
 pub struct Connection {
@@ -99,7 +117,7 @@ pub struct Connection {
 /// Data that the Tui module needs to cache
 pub struct TuiModuleDatas {
     /// Sender of all other modules
-    pub followers: Vec<mpsc::Sender<DuniterMessage>>,
+    pub followers: Vec<mpsc::Sender<DursMsgContent>>,
     /// HEADs cache content
     pub heads_cache: HashMap<NodeFullId, NetworkHead>,
     /// Position of the 1st head displayed on the screen
@@ -164,7 +182,8 @@ impl TuiModuleDatas {
             color::Bg(color::Black),
             clear::All,
             cursor::Goto(1, 1)
-        ).unwrap();
+        )
+        .unwrap();
 
         // Draw headers
         let mut line = 1;
@@ -174,7 +193,8 @@ impl TuiModuleDatas {
             cursor::Goto(1, line),
             color::Fg(color::White),
             out_established_conns.len()
-        ).unwrap();
+        )
+        .unwrap();
         line += 1;
         write!(
             stdout,
@@ -182,7 +202,8 @@ impl TuiModuleDatas {
             cursor::Goto(1, line),
             color::Fg(color::White),
             style::Italic,
-        ).unwrap();
+        )
+        .unwrap();
 
         // Draw inter-nodes established connections
         if out_established_conns.is_empty() {
@@ -193,7 +214,8 @@ impl TuiModuleDatas {
                 cursor::Goto(2, line),
                 color::Fg(color::Red),
                 style::Bold,
-            ).unwrap();
+            )
+            .unwrap();
         } else {
             for (ref node_full_id, ref uid, ref url) in out_established_conns {
                 line += 1;
@@ -209,7 +231,8 @@ impl TuiModuleDatas {
                     node_full_id.to_human_string(),
                     uid_string,
                     url,
-                ).unwrap();
+                )
+                .unwrap();
             }
         }
 
@@ -226,7 +249,8 @@ impl TuiModuleDatas {
             out_trying_conns_count,
             out_denial_conns_count,
             out_disconnected_conns_count,
-        ).unwrap();
+        )
+        .unwrap();
 
         // Draw separated line
         line += 1;
@@ -240,7 +264,8 @@ impl TuiModuleDatas {
             cursor::Goto(1, line),
             color::Fg(color::White),
             separated_line,
-        ).unwrap();
+        )
+        .unwrap();
 
         // Draw HEADs
         line += 1;
@@ -250,7 +275,8 @@ impl TuiModuleDatas {
             cursor::Goto(1, line),
             color::Fg(color::White),
             heads.len()
-        ).unwrap();
+        )
+        .unwrap();
         line += 1;
         if heads_index > 0 {
             write!(
@@ -258,14 +284,16 @@ impl TuiModuleDatas {
                 "{}{}/\\",
                 cursor::Goto(35, line),
                 color::Fg(color::Green),
-            ).unwrap();
+            )
+            .unwrap();
         } else {
             write!(
                 stdout,
                 "{}{}/\\",
                 cursor::Goto(35, line),
                 color::Fg(color::Black),
-            ).unwrap();
+            )
+            .unwrap();
         }
         line += 1;
         write!(
@@ -284,7 +312,8 @@ impl TuiModuleDatas {
                         cursor::Goto(1, line),
                         color::Fg(color::Blue),
                         head.to_human_string(w as usize),
-                    ).unwrap();
+                    )
+                    .unwrap();
                 } else {
                     write!(
                         stdout,
@@ -292,7 +321,8 @@ impl TuiModuleDatas {
                         cursor::Goto(1, line),
                         color::Fg(color::Green),
                         head.to_human_string(w as usize),
-                    ).unwrap();
+                    )
+                    .unwrap();
                 }
             } else {
                 break;
@@ -305,14 +335,16 @@ impl TuiModuleDatas {
                 "{}{}\\/",
                 cursor::Goto(35, line),
                 color::Fg(color::Green),
-            ).unwrap();
+            )
+            .unwrap();
         } else {
             write!(
                 stdout,
                 "{}{}\\/",
                 cursor::Goto(35, line),
                 color::Fg(color::Black),
-            ).unwrap();
+            )
+            .unwrap();
         }
 
         // Draw footer
@@ -335,7 +367,8 @@ impl TuiModuleDatas {
             color::Bg(color::Blue),
             color::Fg(color::White),
             runtime_str,
-        ).unwrap();
+        )
+        .unwrap();
         write!(
             stdout,
             "{}{}{}q : quit{}",
@@ -343,7 +376,8 @@ impl TuiModuleDatas {
             color::Bg(color::Blue),
             color::Fg(color::White),
             cursor::Hide,
-        ).unwrap();
+        )
+        .unwrap();
 
         // Flush stdout (i.e. make the output appear).
         stdout.flush().unwrap();
@@ -356,11 +390,12 @@ impl Default for TuiModule {
     }
 }
 
-impl DuniterModule<DuRsConf, DuniterMessage> for TuiModule {
+impl DuniterModule<DuRsConf, DursMsg> for TuiModule {
     type ModuleConf = TuiConf;
+    type ModuleOpt = TuiOpt;
 
-    fn id() -> ModuleId {
-        ModuleId(String::from("tui"))
+    fn name() -> ModuleStaticName {
+        ModuleStaticName("tui")
     }
     fn priority() -> ModulePriority {
         ModulePriority::Recommended()
@@ -368,11 +403,35 @@ impl DuniterModule<DuRsConf, DuniterMessage> for TuiModule {
     fn ask_required_keys() -> RequiredKeys {
         RequiredKeys::None()
     }
+    fn have_subcommand() -> bool {
+        true
+    }
+    fn exec_subcommand(
+        soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
+        _keys: RequiredKeysContent,
+        module_conf: Self::ModuleConf,
+        subcommand_args: TuiOpt,
+    ) -> () {
+        let mut conf = soft_meta_datas.conf.clone();
+        let new_tui_conf = TuiConf {
+            test_fake_conf_field: subcommand_args.new_conf_field.clone(),
+        };
+        conf.set_module_conf(
+            Self::name().to_string(),
+            serde_json::value::to_value(new_tui_conf).expect("Fail to jsonifie TuiConf !"),
+        );
+        duniter_conf::write_conf_file(&soft_meta_datas.profile, &conf)
+            .expect("Fail to write new Tui conf file ! ");
+        println!(
+            "Succesfully exec tui subcommand whit terminal name : {} and conf={:?}!",
+            subcommand_args.new_conf_field, module_conf
+        )
+    }
     fn start(
         _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         _keys: RequiredKeysContent,
         _conf: Self::ModuleConf,
-        main_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>,
+        main_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
         load_conf_only: bool,
     ) -> Result<(), ModuleInitError> {
         let start_time = SystemTime::now(); //: DateTime<Utc> = Utc::now();
@@ -397,32 +456,47 @@ impl DuniterModule<DuRsConf, DuniterMessage> for TuiModule {
 
         // Create proxy channel
         let (proxy_sender, proxy_receiver): (
-            mpsc::Sender<DuniterMessage>,
-            mpsc::Receiver<DuniterMessage>,
+            mpsc::Sender<DursMsg>,
+            mpsc::Receiver<DursMsg>,
         ) = mpsc::channel();
 
-        // Launch a proxy thread that transform DuniterMessage() to TuiMess::DuniterMessage(DuniterMessage())
+        // Launch a proxy thread that transform DursMsgContent() to TuiMess::DursMsgContent(DursMsgContent())
         let tui_sender_clone = tui_sender.clone();
         thread::spawn(move || {
             // Send proxy sender to main
             main_sender
-                .send(RooterThreadMessage::ModuleSender(proxy_sender))
+                .send(RooterThreadMessage::ModuleSender(
+                    TuiModule::name(),
+                    proxy_sender,
+                    vec![ModuleRole::UserInterface],
+                    vec![
+                        ModuleEvent::NewValidBlock,
+                        ModuleEvent::ConnectionsChangeNodeNetwork,
+                        ModuleEvent::NewValidHeadFromNetwork,
+                        ModuleEvent::NewValidPeerFromNodeNetwork,
+                    ],
+                ))
                 .expect("Fatal error : tui module fail to send is sender channel !");
             debug!("Send tui sender to main thread.");
             loop {
                 match proxy_receiver.recv() {
-                    Ok(message) => match tui_sender_clone
-                        .send(TuiMess::DuniterMessage(Box::new(message.clone())))
-                    {
-                        Ok(_) => {
-                            if let DuniterMessage::Stop() = message {
-                                break;
-                            };
-                        }
-                        Err(_) => {
-                            debug!("tui proxy : fail to relay DuniterMessage to tui main thread !")
+                    Ok(message) => {
+                        let stop = if let DursMsg(_, DursMsgContent::Stop()) = message {
+                            true
+                        } else {
+                            false
+                        };
+                        match tui_sender_clone.send(TuiMess::DursMsg(Box::new(message))) {
+                            Ok(_) => {
+                                if stop {
+                                    break;
+                                };
+                            }
+                            Err(_) => {
+                                debug!("tui proxy : fail to relay DursMsg to tui main thread !")
+                            }
                         }
-                    },
+                    }
                     Err(e) => {
                         warn!("{}", e);
                         break;
@@ -455,7 +529,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for TuiModule {
                 tui_sender
                     .send(TuiMess::TermionEvent(
                         c.expect("error to read stdin event !"),
-                    )).expect("Fatal error : tui stdin thread module fail to send message !");
+                    ))
+                    .expect("Fatal error : tui stdin thread module fail to send message !");
                 trace!("Send stdin event to tui main thread.");
             }
         });
@@ -466,79 +541,69 @@ impl DuniterModule<DuRsConf, DuniterMessage> for TuiModule {
             // Get messages
             match tui_receiver.recv_timeout(Duration::from_millis(250)) {
                 Ok(ref message) => match *message {
-                    TuiMess::DuniterMessage(ref duniter_message) => {
-                        match *duniter_message.deref() {
-                            DuniterMessage::Stop() => {
-                                writeln!(
-                                    stdout,
-                                    "{}{}{}{}{}",
-                                    color::Fg(color::Reset),
-                                    cursor::Goto(1, 1),
-                                    color::Bg(color::Reset),
-                                    cursor::Show,
-                                    clear::All,
-                                ).unwrap();
-                                let _result_stop_propagation: Result<
+                    TuiMess::DursMsg(ref duniter_message) => match (*duniter_message.deref()).1 {
+                        DursMsgContent::Stop() => {
+                            writeln!(
+                                stdout,
+                                "{}{}{}{}{}",
+                                color::Fg(color::Reset),
+                                cursor::Goto(1, 1),
+                                color::Bg(color::Reset),
+                                cursor::Show,
+                                clear::All,
+                            )
+                            .unwrap();
+                            let _result_stop_propagation: Result<
                                 (),
-                                mpsc::SendError<DuniterMessage>,
+                                mpsc::SendError<DursMsgContent>,
                             > = tui
                                 .followers
                                 .iter()
-                                .map(|f| f.send(DuniterMessage::Stop()))
+                                .map(|f| f.send(DursMsgContent::Stop()))
                                 .collect();
-                                break;
+                            break;
+                        }
+                        DursMsgContent::DALEvent(ref dal_event) => match *dal_event {
+                            DALEvent::StackUpValidBlock(ref _block, ref _blockstamp) => {}
+                            DALEvent::RevertBlocks(ref _blocks) => {}
+                            _ => {}
+                        },
+                        DursMsgContent::NetworkEvent(ref network_event) => match *network_event {
+                            NetworkEvent::ConnectionStateChange(
+                                ref node_full_id,
+                                ref status,
+                                ref uid,
+                                ref url,
+                            ) => {
+                                if let Some(conn) = tui.connections_status.get(&node_full_id) {
+                                    if *status == 12 && (*conn).status != 12 {
+                                        tui.established_conns_count += 1;
+                                    } else if *status != 12
+                                        && (*conn).status == 12
+                                        && tui.established_conns_count > 0
+                                    {
+                                        tui.established_conns_count -= 1;
+                                    }
+                                };
+                                tui.connections_status.insert(
+                                    *node_full_id,
+                                    Connection {
+                                        status: *status,
+                                        url: url.clone(),
+                                        uid: uid.clone(),
+                                    },
+                                );
                             }
-                            DuniterMessage::Followers(ref new_followers) => {
-                                info!("Tui module receive followers !");
-                                for new_follower in new_followers {
-                                    debug!("TuiModule : push one follower.");
-                                    tui.followers.push(new_follower.clone());
-                                }
+                            NetworkEvent::ReceiveHeads(ref heads) => {
+                                heads
+                                    .iter()
+                                    .map(|h| tui.heads_cache.insert(h.node_full_id(), h.clone()))
+                                    .for_each(drop);
                             }
-                            DuniterMessage::DALEvent(ref dal_event) => match *dal_event {
-                                DALEvent::StackUpValidBlock(ref _block, ref _blockstamp) => {}
-                                DALEvent::RevertBlocks(ref _blocks) => {}
-                                _ => {}
-                            },
-                            DuniterMessage::NetworkEvent(ref network_event) => match *network_event
-                            {
-                                NetworkEvent::ConnectionStateChange(
-                                    ref node_full_id,
-                                    ref status,
-                                    ref uid,
-                                    ref url,
-                                ) => {
-                                    if let Some(conn) = tui.connections_status.get(&node_full_id) {
-                                        if *status == 12 && (*conn).status != 12 {
-                                            tui.established_conns_count += 1;
-                                        } else if *status != 12
-                                            && (*conn).status == 12
-                                            && tui.established_conns_count > 0
-                                        {
-                                            tui.established_conns_count -= 1;
-                                        }
-                                    };
-                                    tui.connections_status.insert(
-                                        *node_full_id,
-                                        Connection {
-                                            status: *status,
-                                            url: url.clone(),
-                                            uid: uid.clone(),
-                                        },
-                                    );
-                                }
-                                NetworkEvent::ReceiveHeads(ref heads) => {
-                                    heads
-                                        .iter()
-                                        .map(|h| {
-                                            tui.heads_cache.insert(h.node_full_id(), h.clone())
-                                        }).for_each(drop);
-                                }
-                                _ => {}
-                            },
                             _ => {}
-                        }
-                    }
+                        },
+                        _ => {}
+                    },
                     TuiMess::TermionEvent(ref term_event) => match *term_event {
                         Event::Key(Key::Char('q')) => {
                             // Exit
@@ -550,14 +615,15 @@ impl DuniterModule<DuRsConf, DuniterMessage> for TuiModule {
                                 color::Bg(color::Reset),
                                 cursor::Show,
                                 clear::All,
-                            ).unwrap();
+                            )
+                            .unwrap();
                             let _result_stop_propagation: Result<
                                 (),
-                                mpsc::SendError<DuniterMessage>,
+                                mpsc::SendError<DursMsgContent>,
                             > = tui
                                 .followers
                                 .iter()
-                                .map(|f| f.send(DuniterMessage::Stop()))
+                                .map(|f| f.send(DursMsgContent::Stop()))
                                 .collect();
                             break;
                         }
diff --git a/wotb/data/rusty.rs b/wotb/data/rusty.rs
index 35cbaed96401f739d2673e3301cd3785ce9dec9e..22cdd86612fa5e8fd2e51d02f17195572e1844a7 100644
--- a/wotb/data/rusty.rs
+++ b/wotb/data/rusty.rs
@@ -199,7 +199,8 @@ impl WebOfTrust for RustyWebOfTrust {
                 n.enabled
                     && n.issued_count >= sentry_requirement
                     && n.links_source.len() >= sentry_requirement
-            }).map(|(i, _)| NodeId(i))
+            })
+            .map(|(i, _)| NodeId(i))
             .collect()
     }
 
@@ -211,7 +212,8 @@ impl WebOfTrust for RustyWebOfTrust {
                 n.enabled
                     && (n.issued_count < sentry_requirement
                         || n.links_source.len() < sentry_requirement)
-            }).map(|(i, _)| NodeId(i))
+            })
+            .map(|(i, _)| NodeId(i))
             .collect()
     }
 }
diff --git a/wotb/lib.rs b/wotb/lib.rs
index d8d324e9552b69f7c2688554470d43f2e88e2c08..3926037bfc22061f3f942d610f0fc797807c2337 100644
--- a/wotb/lib.rs
+++ b/wotb/lib.rs
@@ -497,7 +497,8 @@ mod tests {
                     &wot,
                     &[0b0000_0000, 0b0000_0001, 0b0000_0001, 0b0000_0000],
                     "test.wot"
-                ).unwrap(),
+                )
+                .unwrap(),
             ()
         );
 
diff --git a/wotb/operations/distance.rs b/wotb/operations/distance.rs
index 14105d595399b71915c84cb088c6a90fdaa7954c..46949ad205c0760554d1ee0f4267bd44196f2c0b 100644
--- a/wotb/operations/distance.rs
+++ b/wotb/operations/distance.rs
@@ -93,7 +93,8 @@ impl<T: WebOfTrust + Sync> DistanceCalculator<T> for RustyDistanceCalculator {
                         .filter(|source| !area.contains(source))
                         .cloned()
                         .collect::<HashSet<_>>()
-                }).reduce(HashSet::new, |mut acc, sources| {
+                })
+                .reduce(HashSet::new, |mut acc, sources| {
                     for source in sources {
                         acc.insert(source);
                     }
diff --git a/ws2p-messages/lib.rs b/ws2p-messages/lib.rs
index e7e0e9c602a46089e16d8c4df5875a3b8a73bcbd..1588f275e38dd34b9485c3882b096dee74deb6c8 100644
--- a/ws2p-messages/lib.rs
+++ b/ws2p-messages/lib.rs
@@ -109,7 +109,8 @@ mod tests {
             node_id: NodeId(0),
             blockstamp: Blockstamp::from_string(
                 "50-000005B1CEB4EC5245EF7E33101A330A1C9A358EC45A25FC13F78BB58C9E7370",
-            ).unwrap(),
+            )
+            .unwrap(),
             endpoints: vec![create_endpoint_v11(), create_second_endpoint_v11()],
             sig: None,
         }
@@ -168,14 +169,15 @@ mod tests {
 
         let blockstamp = Blockstamp::from_string(
             "36-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B865",
-        ).unwrap();
+        )
+        .unwrap();
 
         CompactCertificationDocument {
             issuer: PubKey::Ed25519(
                 ed25519::PublicKey::from_base58("4tNQ7d9pj2Da5wUVoW9mFn7JjuPoowF977au8DdhEjVR")
                     .unwrap(),
             ),
-            target: target,
+            target,
             block_number: blockstamp.id,
             signature: sig,
         }
diff --git a/ws2p-messages/v2/connect.rs b/ws2p-messages/v2/connect.rs
index 3ed23827ad012a8215e1887c8ccb28e2778cb215..f1ad97ae6b54c8ba0dd310dc63f7c6e75df6e385 100644
--- a/ws2p-messages/v2/connect.rs
+++ b/ws2p-messages/v2/connect.rs
@@ -98,14 +98,16 @@ mod tests {
         let connect_msg = WS2Pv2ConnectMsg {
             challenge: Hash::from_hex(
                 "000007722B243094269E548F600BD34D73449F7578C05BD370A6D301D20B5F10",
-            ).unwrap(),
+            )
+            .unwrap(),
             api_features: WS2PFeatures(vec![7u8]),
             flags_queries: WS2PConnectFlags(vec![]),
             peer_card: Some(peer),
             chunkstamp: Some(
                 Blockstamp::from_string(
                     "499-000011BABEEE1020B1F6B2627E2BC1C35BCD24375E114349634404D2C266D84F",
-                ).unwrap(),
+                )
+                .unwrap(),
             ),
         };
         test_ws2p_message(WS2Pv0MessagePayload::Connect(Box::new(connect_msg)));
diff --git a/ws2p-messages/v2/ok.rs b/ws2p-messages/v2/ok.rs
index e442e373aac0b413b0f4b81b8075692a0cbe8858..e480524975988f82afe27642ea6e986f7a02a1e9 100644
--- a/ws2p-messages/v2/ok.rs
+++ b/ws2p-messages/v2/ok.rs
@@ -59,14 +59,17 @@ mod tests {
             sync_target: Some(WS2Pv2SyncTarget {
                 target_blockstamp: Blockstamp::from_string(
                     "500-000011BABEEE1020B1F6B2627E2BC1C35BCD24375E114349634404D2C266D84F",
-                ).unwrap(),
+                )
+                .unwrap(),
                 chunks_hash: vec![
                     Hash::from_hex(
                         "000007722B243094269E548F600BD34D73449F7578C05BD370A6D301D20B5F10",
-                    ).unwrap(),
+                    )
+                    .unwrap(),
                     Hash::from_hex(
                         "0000095FD4C8EA96DE2844E3A4B62FD18761E9B4C13A74FAB716A4C81F438D91",
-                    ).unwrap(),
+                    )
+                    .unwrap(),
                 ],
             }),
         };
diff --git a/ws2p-messages/v2/req_responses.rs b/ws2p-messages/v2/req_responses.rs
index 0a46a21d786298cc88cee8dc4de059d161b88238..ed81adbc5cfc62e6d4d2dd133284877f4e025aff 100644
--- a/ws2p-messages/v2/req_responses.rs
+++ b/ws2p-messages/v2/req_responses.rs
@@ -88,7 +88,8 @@ mod tests {
     fn test_ws2p_message_req_res_current() {
         let blockstamp = Blockstamp::from_string(
             "499-000011BABEEE1020B1F6B2627E2BC1C35BCD24375E114349634404D2C266D84F",
-        ).unwrap();
+        )
+        .unwrap();
         let response = WS2Pv2ReqRes {
             id: 28,
             body: WS2Pv2ReqResBody::Current(blockstamp),
diff --git a/ws2p-messages/v2/requests.rs b/ws2p-messages/v2/requests.rs
index 3290ceaa4006473e64f16727e244e09aaad7292a..e160f7e126a4683348e8a04db77cf103b41c0e19 100644
--- a/ws2p-messages/v2/requests.rs
+++ b/ws2p-messages/v2/requests.rs
@@ -81,7 +81,8 @@ mod tests {
     fn test_ws2p_message_request() {
         let chunkstamp = Blockstamp::from_string(
             "499-000011BABEEE1020B1F6B2627E2BC1C35BCD24375E114349634404D2C266D84F",
-        ).unwrap();
+        )
+        .unwrap();
         let request = WS2Pv2Request {
             id: 27,
             body: WS2Pv2RequestBody::ChunkByHash(chunkstamp),
diff --git a/ws2p-v1-legacy/Cargo.toml b/ws2p-v1-legacy/Cargo.toml
index b8c414717834e5e1b7dff2cf2d3c9122fabe720a..3df5308efa61a620d54d3d7a78dba9913c5e322f 100644
--- a/ws2p-v1-legacy/Cargo.toml
+++ b/ws2p-v1-legacy/Cargo.toml
@@ -27,6 +27,7 @@ sqlite = "0.23.*"
 serde = "1.0.*"
 serde_derive = "1.0.*"
 serde_json = "1.0.*"
+structopt= "0.2.*"
 ws = { version = "0.7.*", features = ["permessage-deflate"] }
 
 [features]
diff --git a/ws2p-v1-legacy/clippy.toml b/ws2p-v1-legacy/clippy.toml
new file mode 100644
index 0000000000000000000000000000000000000000..e02f006add50da81398cc2451bd748c47c7bdf9d
--- /dev/null
+++ b/ws2p-v1-legacy/clippy.toml
@@ -0,0 +1 @@
+cyclomatic-complexity-threshold = 75
\ No newline at end of file
diff --git a/ws2p-v1-legacy/datas.rs b/ws2p-v1-legacy/datas.rs
index b163718542c8cc13d1df5f11654cf618eccac28f..6658c6232df2a20ea8c1c6a1cd9904578bc6b848 100644
--- a/ws2p-v1-legacy/datas.rs
+++ b/ws2p-v1-legacy/datas.rs
@@ -17,7 +17,7 @@ use constants::*;
 use duniter_crypto::keys::*;
 use duniter_dal::dal_requests::DALRequest;
 use duniter_documents::Blockstamp;
-use duniter_message::DuniterMessage;
+use duniter_message::*;
 use duniter_network::network_endpoint::*;
 use duniter_network::network_head::*;
 use duniter_network::*;
@@ -27,7 +27,7 @@ use *;
 
 #[derive(Debug)]
 pub struct WS2PModuleDatas {
-    pub followers: Vec<mpsc::Sender<DuniterMessage>>,
+    pub rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
     pub currency: Option<String>,
     pub key_pair: Option<KeyPairEnum>,
     pub conf: WS2PConf,
@@ -38,10 +38,12 @@ pub struct WS2PModuleDatas {
     ),
     pub ws2p_endpoints: HashMap<NodeFullId, (EndpointEnum, WS2PConnectionState)>,
     pub websockets: HashMap<NodeFullId, WsSender>,
-    pub requests_awaiting_response: HashMap<ModuleReqId, (NetworkRequest, NodeFullId, SystemTime)>,
+    pub requests_awaiting_response:
+        HashMap<ModuleReqId, (OldNetworkRequest, NodeFullId, SystemTime)>,
     pub heads_cache: HashMap<NodeFullId, NetworkHead>,
     pub my_head: Option<NetworkHead>,
     pub uids_cache: HashMap<PubKey, String>,
+    pub count_dal_requests: u32,
 }
 
 impl WS2PModuleDatas {
@@ -58,27 +60,59 @@ impl WS2PModuleDatas {
         }
         Ok(conn)
     }
-    pub fn send_dal_request(&self, req: &DALRequest) {
-        for follower in &self.followers {
-            if follower
-                .send(DuniterMessage::DALRequest(req.clone()))
-                .is_err()
-            {
-                // handle error
-            }
+    pub fn send_dal_request(&mut self, req: &DALRequest) {
+        self.count_dal_requests += 1;
+        if self.count_dal_requests == std::u32::MAX {
+            self.count_dal_requests = 0;
         }
+        self.rooter_sender
+            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+                DursMsgReceiver::Role(ModuleRole::BlockchainDatas),
+                DursMsgContent::Request(DursReq {
+                    requester: WS2PModule::name(),
+                    id: ModuleReqId(self.count_dal_requests),
+                    content: DursReqContent::DALRequest(req.clone()),
+                }),
+            )))
+            .expect("Fail to send message to rooter !");
+    }
+    pub fn send_network_req_response(
+        &self,
+        requester: ModuleStaticName,
+        response: NetworkResponse,
+    ) {
+        self.rooter_sender
+            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+                DursMsgReceiver::One(requester),
+                DursMsgContent::NetworkResponse(response),
+            )))
+            .expect("Fail to send message to rooter !");
     }
     pub fn send_network_event(&self, event: &NetworkEvent) {
-        for follower in &self.followers {
-            match follower.send(DuniterMessage::NetworkEvent(event.clone())) {
-                Ok(_) => {
-                    debug!("Send NetworkEvent to one follower.");
-                }
-                Err(_) => {
-                    warn!("Fail to send NetworkEvent to one follower !");
+        let module_event = match event {
+            NetworkEvent::ConnectionStateChange(_, _, _, _) => {
+                ModuleEvent::ConnectionsChangeNodeNetwork
+            }
+            NetworkEvent::ReceiveDocuments(network_docs) => {
+                if !network_docs.is_empty() {
+                    match network_docs[0] {
+                        NetworkDocument::Block(_) => ModuleEvent::NewBlockFromNetwork,
+                        NetworkDocument::Transaction(_) => ModuleEvent::NewTxFromNetwork,
+                        _ => ModuleEvent::NewWotDocFromNetwork,
+                    }
+                } else {
+                    return;
                 }
             }
-        }
+            NetworkEvent::ReceiveHeads(_) => ModuleEvent::NewValidHeadFromNetwork,
+            NetworkEvent::ReceivePeers(_) => ModuleEvent::NewValidPeerFromNodeNetwork,
+        };
+        self.rooter_sender
+            .send(RooterThreadMessage::ModuleMessage(DursMsg(
+                DursMsgReceiver::Event(module_event),
+                DursMsgContent::NetworkEvent(event.clone()),
+            )))
+            .expect("Fail to send network event to rooter !");
     }
     pub fn get_network_consensus(&self) -> Result<Blockstamp, NetworkConsensusError> {
         let mut count_known_blockstamps = 0;
@@ -184,7 +218,8 @@ impl WS2PModuleDatas {
                         &endpoint
                             .node_full_id()
                             .expect("WS2P: Fail to get ep.node_full_id() !"),
-                    ).expect("WS2P: Fail to get_mut() a ws2p_endpoint !")
+                    )
+                    .expect("WS2P: Fail to get_mut() a ws2p_endpoint !")
                     .1 = WS2PConnectionState::NeverTry;
             }
             None => {
@@ -267,12 +302,13 @@ impl WS2PModuleDatas {
                     .expect("WS2P: Fail to get mut ep !")
                     .1 = new_con_state;
                 if let WS2PConnectionState::AckMessOk = self.ws2p_endpoints[&ws2p_full_id].1 {
-                    trace!("DEBUG : Send: {:#?}", r);
+                    trace!("Send: {:#?}", r);
                     self.websockets
                         .get_mut(&ws2p_full_id)
                         .unwrap_or_else(|| {
                             panic!("Fatal error : no websocket for {} !", ws2p_full_id)
-                        }).0
+                        })
+                        .0
                         .send(Message::text(r))
                         .expect("WS2P: Fail to send Message in websocket !");
                 }
@@ -327,7 +363,7 @@ impl WS2PModuleDatas {
                     {
                         return WS2PSignal::ReqResponse(
                             req_id,
-                            ws2p_request.clone(),
+                            *ws2p_request,
                             *recipient_fulld_id,
                             response,
                         );
@@ -409,15 +445,15 @@ impl WS2PModuleDatas {
 
     /*pub fn send_request_to_all_connections(
         &mut self,
-        ws2p_request: &NetworkRequest,
+        ws2p_request: &OldNetworkRequest,
     ) -> Result<(), SendRequestError> {
         let mut count_successful_sending: usize = 0;
         let mut errors: Vec<ws::Error> = Vec::new();
         match *ws2p_request {
-            NetworkRequest::GetCurrent(req_full_id, _receiver) => {
+            OldNetworkRequest::GetCurrent(req_full_id, _receiver) => {
                 for (ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() {
                     if let WS2PConnectionState::Established = state {
-                        let ws2p_request = NetworkRequest::GetCurrent(
+                        let ws2p_request = OldNetworkRequest::GetCurrent(
                             ModuleReqFullId(
                                 req_full_id.0,
                                 ModuleReqId(
@@ -435,41 +471,41 @@ impl WS2PModuleDatas {
                     }
                 }
             }
-            /* NetworkRequest::GetBlock(req_full_id, number) => {} */
-            NetworkRequest::GetBlocks(_req_full_id, _receiver, _count, _from_number) => {}
-            NetworkRequest::GetRequirementsPending(req_full_id, _receiver, min_cert) => {
-                for (ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() {
-                    if let WS2PConnectionState::Established = state {
-                        let ws2p_request = NetworkRequest::GetRequirementsPending(
-                            ModuleReqFullId(
-                                req_full_id.0,
-                                ModuleReqId(self.requests_awaiting_response.len() as u32),
-                            ),
-                            ws2p_full_id,
-                            min_cert,
-                        );
-                        match self.send_request_to_specific_node(&ws2p_full_id, &ws2p_request) {
-                            Ok(_) => count_successful_sending += 1,
-                            Err(e) => errors.push(e),
-                        };
-                    }
-                }
-            }
-            _ => {
-                return Err(SendRequestError::RequestTypeMustNotBeTransmitted());
-            }
-        }
-        debug!("count_successful_sending = {}", count_successful_sending);
-        if !errors.is_empty() {
-            return Err(SendRequestError::WSError(count_successful_sending, errors));
-        }
-        Ok(())
+            /* OldNetworkRequest::GetBlock(req_full_id, number) => {} */
+    OldNetworkRequest::GetBlocks(_req_full_id, _receiver, _count, _from_number) => {}
+    OldNetworkRequest::GetRequirementsPending(req_full_id, _receiver, min_cert) => {
+    for (ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() {
+    if let WS2PConnectionState::Established = state {
+    let ws2p_request = OldNetworkRequest::GetRequirementsPending(
+    ModuleReqFullId(
+    req_full_id.0,
+    ModuleReqId(self.requests_awaiting_response.len() as u32),
+    ),
+    ws2p_full_id,
+    min_cert,
+    );
+    match self.send_request_to_specific_node(&ws2p_full_id, &ws2p_request) {
+    Ok(_) => count_successful_sending += 1,
+    Err(e) => errors.push(e),
+    };
+    }
+    }
+    }
+    _ => {
+    return Err(SendRequestError::RequestTypeMustNotBeTransmitted());
+    }
+    }
+    debug!("count_successful_sending = {}", count_successful_sending);
+    if !errors.is_empty() {
+    return Err(SendRequestError::WSError(count_successful_sending, errors));
+    }
+    Ok(())
     }*/
 
     pub fn send_request_to_specific_node(
         &mut self,
         receiver_ws2p_full_id: &NodeFullId,
-        ws2p_request: &NetworkRequest,
+        ws2p_request: &OldNetworkRequest,
     ) -> ws::Result<()> {
         self.websockets
             .get_mut(receiver_ws2p_full_id)
@@ -480,11 +516,7 @@ impl WS2PModuleDatas {
             ))?;
         self.requests_awaiting_response.insert(
             ws2p_request.get_req_id(),
-            (
-                ws2p_request.clone(),
-                *receiver_ws2p_full_id,
-                SystemTime::now(),
-            ),
+            (*ws2p_request, *receiver_ws2p_full_id, SystemTime::now()),
         );
         debug!(
             "send request {} to {}",
diff --git a/ws2p-v1-legacy/lib.rs b/ws2p-v1-legacy/lib.rs
index e9fc2140de438ded492a9c8ec97c5e9115d13274..8cb51d201479890a1242383585c7bb774e6c2f7b 100644
--- a/ws2p-v1-legacy/lib.rs
+++ b/ws2p-v1-legacy/lib.rs
@@ -16,7 +16,6 @@
 //! WebSocketToPeer API for the Duniter project.
 
 #![cfg_attr(feature = "strict", deny(warnings))]
-#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
 #![deny(
     missing_debug_implementations,
     missing_copy_implementations,
@@ -36,6 +35,8 @@ extern crate log;
 extern crate serde_derive;
 #[macro_use]
 extern crate serde_json;
+#[macro_use]
+extern crate structopt;
 
 extern crate byteorder;
 extern crate duniter_conf;
@@ -70,7 +71,7 @@ use duniter_crypto::keys::*;
 use duniter_dal::dal_event::DALEvent;
 use duniter_dal::dal_requests::{DALReqBlockchain, DALRequest, DALResBlockchain, DALResponse};
 use duniter_documents::Blockstamp;
-use duniter_message::DuniterMessage;
+use duniter_message::*;
 use duniter_module::*;
 use duniter_network::network_endpoint::*;
 use duniter_network::network_head::*;
@@ -106,23 +107,27 @@ impl Default for WS2PConf {
                     PubKey::Ed25519(
                         ed25519::PublicKey::from_base58(
                             "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
-                        ).unwrap(),
+                        )
+                        .unwrap(),
                     ),
                     0,
                     0,
                     1u16,
-                ).unwrap(),
+                )
+                .unwrap(),
                 EndpointEnum::parse_from_raw(
                     "WS2P b48824f0 g1.monnaielibreoccitanie.org 443 /ws2p",
                     PubKey::Ed25519(
                         ed25519::PublicKey::from_base58(
                             "7v2J4badvfWQ6qwRdCwhhJfAsmKwoxRUNpJHiJHj7zef",
-                        ).unwrap(),
+                        )
+                        .unwrap(),
                     ),
                     0,
                     0,
                     1u16,
-                ).unwrap(),
+                )
+                .unwrap(),
             ],
         }
     }
@@ -141,7 +146,12 @@ pub enum WS2PSignal {
     PeerCard(NodeFullId, serde_json::Value, Vec<EndpointEnum>),
     Heads(NodeFullId, Vec<NetworkHead>),
     Document(NodeFullId, NetworkDocument),
-    ReqResponse(ModuleReqId, NetworkRequest, NodeFullId, serde_json::Value),
+    ReqResponse(
+        ModuleReqId,
+        OldNetworkRequest,
+        NodeFullId,
+        serde_json::Value,
+    ),
     Empty,
     NoConnection,
 }
@@ -163,7 +173,7 @@ pub struct WS2PModule {}
 
 #[derive(Debug)]
 pub enum WS2PThreadSignal {
-    DuniterMessage(Box<DuniterMessage>),
+    DursMsg(Box<DursMsg>),
     WS2PConnectionMessage(WS2PConnectionMessage),
 }
 
@@ -190,7 +200,7 @@ pub enum WS2PFeaturesParseError {
     UnknowApiFeature(String),
 }
 
-impl ApiModule<DuRsConf, DuniterMessage> for WS2PModule {
+impl ApiModule<DuRsConf, DursMsg> for WS2PModule {
     type ParseErr = WS2PFeaturesParseError;
     /// Parse raw api features
     fn parse_raw_api_features(str_features: &str) -> Result<ApiFeatures, Self::ParseErr> {
@@ -212,13 +222,13 @@ impl ApiModule<DuRsConf, DuniterMessage> for WS2PModule {
     }
 }
 
-impl NetworkModule<DuRsConf, DuniterMessage> for WS2PModule {
+impl NetworkModule<DuRsConf, DursMsg> for WS2PModule {
     fn sync(
         _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         _keys: RequiredKeysContent,
         _conf: WS2PConf,
-        _main_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>,
-        _sync_endpoint: SyncEndpoint,
+        _main_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        _sync_params: SyncParams,
     ) -> Result<(), ModuleInitError> {
         println!("Downlaod blockchain from network...");
         println!("Error : not yet implemented !");
@@ -226,11 +236,20 @@ impl NetworkModule<DuRsConf, DuniterMessage> for WS2PModule {
     }
 }
 
-impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
+#[derive(StructOpt, Debug, Copy, Clone)]
+#[structopt(
+    name = "ws2p",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// WS2Pv1 subcommand options
+pub struct WS2POpt {}
+
+impl DuniterModule<DuRsConf, DursMsg> for WS2PModule {
     type ModuleConf = WS2PConf;
+    type ModuleOpt = WS2POpt;
 
-    fn id() -> ModuleId {
-        ModuleId(String::from("ws2p"))
+    fn name() -> ModuleStaticName {
+        ModuleStaticName("ws2p")
     }
     fn priority() -> ModulePriority {
         ModulePriority::Essential()
@@ -238,11 +257,22 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
     fn ask_required_keys() -> RequiredKeys {
         RequiredKeys::NetworkKeyPair()
     }
+    fn have_subcommand() -> bool {
+        true
+    }
+    fn exec_subcommand(
+        _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
+        _keys: RequiredKeysContent,
+        _module_conf: Self::ModuleConf,
+        _subcommand_args: WS2POpt,
+    ) -> () {
+        println!("Succesfully exec ws2p subcommand !")
+    }
     fn start(
         soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         keys: RequiredKeysContent,
         conf: WS2PConf,
-        rooter_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>,
+        rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
         load_conf_only: bool,
     ) -> Result<(), ModuleInitError> {
         // Get start time
@@ -250,7 +280,7 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
 
         // Define WS2PModuleDatas
         let mut ws2p_module = WS2PModuleDatas {
-            followers: Vec::new(),
+            rooter_sender: rooter_sender.clone(),
             key_pair: None,
             currency: None,
             conf,
@@ -262,6 +292,7 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
             heads_cache: HashMap::new(),
             my_head: None,
             uids_cache: HashMap::new(),
+            count_dal_requests: 0,
         };
 
         // load conf
@@ -287,27 +318,41 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
 
         // Create proxy channel
         let (proxy_sender, proxy_receiver): (
-            mpsc::Sender<DuniterMessage>,
-            mpsc::Receiver<DuniterMessage>,
+            mpsc::Sender<DursMsg>,
+            mpsc::Receiver<DursMsg>,
         ) = mpsc::channel();
         let proxy_sender_clone = proxy_sender.clone();
 
-        // Launch a proxy thread that transform DuniterMessage to WS2PThreadSignal(DuniterMessage)
+        // Launch a proxy thread that transform DursMsg to WS2PThreadSignal(DursMsg)
         thread::spawn(move || {
             // Send proxy sender to main
             rooter_sender
-                .send(RooterThreadMessage::ModuleSender(proxy_sender_clone))
+                .send(RooterThreadMessage::ModuleSender(
+                    WS2PModule::name(),
+                    proxy_sender_clone,
+                    vec![ModuleRole::InterNodesNetwork],
+                    vec![
+                        ModuleEvent::NewValidBlock,
+                        ModuleEvent::NewWotDocInPool,
+                        ModuleEvent::NewTxinPool,
+                    ],
+                ))
                 .expect("Fatal error : ws2p module fail to send is sender channel !");
             debug!("Send ws2p sender to main thread.");
             loop {
                 match proxy_receiver.recv() {
                     Ok(message) => {
+                        let stop = if let DursMsgContent::Stop() = message.1 {
+                            true
+                        } else {
+                            false
+                        };
                         ws2p_sender_clone
-                            .send(WS2PThreadSignal::DuniterMessage(Box::new(message.clone())))
+                            .send(WS2PThreadSignal::DursMsg(Box::new(message)))
                             .expect(
-                                "Fatal error : fail to relay DuniterMessage to ws2p main thread !",
+                                "Fatal error : fail to relay DursMsgContent to ws2p main thread !",
                             );
-                        if let DuniterMessage::Stop() = message {
+                        if stop {
                             break;
                         };
                     }
@@ -362,10 +407,10 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                 .recv_timeout(Duration::from_millis(200))
             {
                 Ok(message) => match message {
-                    WS2PThreadSignal::DuniterMessage(ref duniter_mesage) => {
-                        match *duniter_mesage.deref() {
-                            DuniterMessage::Stop() => break,
-                            DuniterMessage::Followers(ref new_followers) => {
+                    WS2PThreadSignal::DursMsg(ref duniter_mesage) => {
+                        match (*duniter_mesage.deref()).1 {
+                            DursMsgContent::Stop() => break,
+                            /*DursMsgContent::Followers(ref new_followers) => {
                                 info!("WS2P module receive followers !");
                                 for new_follower in new_followers {
                                     debug!("WS2PModule : push one follower.");
@@ -375,7 +420,7 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                         ws2p_module.send_dal_request(
                                             &DALRequest::BlockchainRequest(
                                                 DALReqBlockchain::CurrentBlock(ModuleReqFullId(
-                                                    WS2PModule::id(),
+                                                    WS2PModule::name(),
                                                     ModuleReqId(0),
                                                 )),
                                             ),
@@ -398,9 +443,9 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                         );
                                     }
                                 }
-                            }
-                            DuniterMessage::NetworkRequest(ref request) => match *request {
-                                NetworkRequest::GetBlocks(
+                            }*/
+                            DursMsgContent::OldNetworkRequest(ref request) => match *request {
+                                OldNetworkRequest::GetBlocks(
                                     ref req_id,
                                     ref receiver,
                                     ref count,
@@ -437,11 +482,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                             let _blocks_request_result = ws2p_module
                                                 .send_request_to_specific_node(
                                                     &real_receiver,
-                                                    &NetworkRequest::GetBlocks(
-                                                        req_id.clone(),
-                                                        *receiver,
-                                                        *count,
-                                                        *from,
+                                                    &OldNetworkRequest::GetBlocks(
+                                                        *req_id, *receiver, *count, *from,
                                                     ),
                                                 );
                                         }
@@ -449,19 +491,16 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                         let _blocks_request_result = ws2p_module
                                             .send_request_to_specific_node(
                                                 &receiver,
-                                                &NetworkRequest::GetBlocks(
-                                                    req_id.clone(),
-                                                    *receiver,
-                                                    *count,
-                                                    *from,
+                                                &OldNetworkRequest::GetBlocks(
+                                                    *req_id, *receiver, *count, *from,
                                                 ),
                                             );
                                     }
                                 }
-                                NetworkRequest::GetEndpoints(ref _request) => {}
+                                OldNetworkRequest::GetEndpoints(ref _request) => {}
                                 _ => {}
                             },
-                            DuniterMessage::DALEvent(ref dal_event) => match *dal_event {
+                            DursMsgContent::DALEvent(ref dal_event) => match *dal_event {
                                 DALEvent::StackUpValidBlock(ref _block, ref blockstamp) => {
                                     current_blockstamp = *blockstamp;
                                     debug!(
@@ -497,14 +536,16 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                                 "body": {
                                                     "heads": [my_json_head]
                                                 }
-                                            }).to_string(),
+                                            })
+                                                .to_string(),
                                             ))
-                                        }).collect();
+                                        })
+                                        .collect();
                                 }
                                 DALEvent::RevertBlocks(ref _blocks) => {}
                                 _ => {}
                             },
-                            DuniterMessage::DALResponse(ref dal_res) => match *dal_res.deref() {
+                            DursMsgContent::DALResponse(ref dal_res) => match *dal_res.deref() {
                                 DALResponse::Blockchain(ref dal_res_bc) => {
                                     match *dal_res_bc.deref() {
                                         DALResBlockchain::CurrentBlock(
@@ -535,7 +576,7 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                                 ]),
                                             );
                                         }
-                                        DALResBlockchain::UIDs(ref uids) => {
+                                        DALResBlockchain::UIDs(ref _req_id, ref uids) => {
                                             // Add uids to heads
                                             for head in ws2p_module.heads_cache.values_mut() {
                                                 if let Some(uid_option) = uids.get(&head.pubkey()) {
@@ -582,7 +623,7 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                         _ => {}
                                     }
                                 }
-                                DALResponse::Pendings(_, _) => {}
+                                DALResponse::Pendings(_) => {}
                             },
                             _ => {}
                         }
@@ -596,11 +637,11 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                         WS2PSignal::ConnectionEstablished(ws2p_full_id) => {
                             let req_id =
                                 ModuleReqId(ws2p_module.requests_awaiting_response.len() as u32);
-                            let module_id = WS2PModule::id();
+                            let module_id = WS2PModule::name();
                             let _current_request_result = ws2p_module
                                 .send_request_to_specific_node(
                                     &ws2p_full_id,
-                                    &NetworkRequest::GetCurrent(
+                                    &OldNetworkRequest::GetCurrent(
                                         ModuleReqFullId(module_id, req_id),
                                         ws2p_full_id,
                                     ),
@@ -699,7 +740,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                             new_head.set_uid(uid);
                                         }
                                         new_head
-                                    }).collect(),
+                                    })
+                                    .collect(),
                             ));
                         }
                         WS2PSignal::Document(ws2p_full_id, network_doc) => {
@@ -710,22 +752,28 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                         }
                         WS2PSignal::ReqResponse(req_id, req, recipient_full_id, response) => {
                             match req {
-                                NetworkRequest::GetCurrent(ref _req_id, _receiver) => {
+                                OldNetworkRequest::GetCurrent(ref _req_id, _receiver) => {
                                     info!(
                                         "WS2PSignal::ReceiveCurrent({}, {:?}, {:#?})",
                                         req_id.0, req, response
                                     );
                                     if let Some(block) = parse_json_block(&response) {
-                                        ws2p_module.send_network_event(&NetworkEvent::ReqResponse(
-                                            Box::new(NetworkResponse::CurrentBlock(
-                                                ModuleReqFullId(WS2PModule::id(), req_id),
+                                        ws2p_module.send_network_req_response(
+                                            req.get_req_full_id().0,
+                                            NetworkResponse::CurrentBlock(
+                                                ModuleReqFullId(WS2PModule::name(), req_id),
                                                 recipient_full_id,
                                                 Box::new(block),
-                                            )),
-                                        ));
+                                            ),
+                                        );
                                     }
                                 }
-                                NetworkRequest::GetBlocks(ref _req_id, _receiver, _count, from) => {
+                                OldNetworkRequest::GetBlocks(
+                                    ref _req_id,
+                                    _receiver,
+                                    _count,
+                                    from,
+                                ) => {
                                     info!("WS2PSignal::ReceiveChunk({}, {:?})", req_id.0, req);
                                     if response.is_array() {
                                         let mut chunk = Vec::new();
@@ -742,7 +790,7 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                                         );
                                     }
                                 }
-                                NetworkRequest::GetRequirementsPending(
+                                OldNetworkRequest::GetRequirementsPending(
                                     _req_id,
                                     _receiver,
                                     min_cert,
@@ -831,9 +879,9 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                         request_blocks_from += 1;
                     }
                     info!("get chunks from all connections...");
-                    let module_id = WS2PModule::id();
+                    let module_id = WS2PModule::name();
                     let _blocks_request_result =
-                        ws2p_module.send_request_to_all_connections(&NetworkRequest::GetBlocks(
+                        ws2p_module.send_request_to_all_connections(&OldNetworkRequest::GetBlocks(
                             ModuleReqFullId(module_id, ModuleReqId(0 as u32)),
                             NodeFullId::default(),
                             50,
@@ -849,9 +897,9 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                     && SystemTime::now().duration_since(start_time).unwrap() > Duration::new(10, 0)
                 {
                     /*info!("get pending_identities from all connections...");
-                                    let _blocks_request_result = ws2p_module.send_request_to_all_connections(
-                                        &NetworkRequest::GetRequirementsPending(ModuleReqId(0 as u32), 5),
-                                    );*/
+                    let _blocks_request_result = ws2p_module.send_request_to_all_connections(
+                        &OldNetworkRequest::GetRequirementsPending(ModuleReqId(0 as u32), 5),
+                    );*/
                     last_identities_request = SystemTime::now();
                 }
                 // Write pending endpoints
@@ -863,14 +911,14 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule {
                             ws2p_module.ws2p_endpoints.get(&ep_full_id)
                         {
                             /*let dal_endpoint = duniter_dal::endpoint::DALEndpoint::new(
-                                                state.clone() as u32,
-                                                ep.node_uuid().unwrap().0,
-                                                ep.pubkey(),
-                                                duniter_dal::endpoint::string_to_api(&ep.api().0).unwrap(),
-                                                1,
-                                                ep.to_string(),
-                                                received_time.duration_since(UNIX_EPOCH).unwrap(),
-                                            );*/
+                                state.clone() as u32,
+                                ep.node_uuid().unwrap().0,
+                                ep.pubkey(),
+                                duniter_dal::endpoint::string_to_api(&ep.api().0).unwrap(),
+                                1,
+                                ep.to_string(),
+                                received_time.duration_since(UNIX_EPOCH).unwrap(),
+                            );*/
                             ws2p_db::write_endpoint(
                                 &db,
                                 &ep,
@@ -1111,7 +1159,8 @@ mod tests {
             1,
             current_time.as_secs(),
             1,
-        ).expect("Failt to parse test endpoint !");
+        )
+        .expect("Failt to parse test endpoint !");
 
         ws2p_db::write_endpoint(&db, &endpoint, 1, current_time.as_secs());
         let mut written_endpoints =
@@ -1128,8 +1177,8 @@ mod tests {
 
     #[test]
     fn ws2p_requests() {
-        let module_id = WS2PModule::id();
-        let request = NetworkRequest::GetBlocks(
+        let module_id = WS2PModule::name();
+        let request = OldNetworkRequest::GetBlocks(
             ModuleReqFullId(module_id, ModuleReqId(58)),
             NodeFullId::default(),
             50,
diff --git a/ws2p-v1-legacy/parsers/blocks.rs b/ws2p-v1-legacy/parsers/blocks.rs
index 4a8fdc0c972d65508a139f1dd5c7e82be21e0256..ae3aa8dd3ea4b0475bc84275974742830f653e52 100644
--- a/ws2p-v1-legacy/parsers/blocks.rs
+++ b/ws2p-v1-legacy/parsers/blocks.rs
@@ -19,11 +19,13 @@ fn parse_previous_hash(block_number: BlockId, source: &serde_json::Value) -> Opt
             Ok(hash) => Some(hash),
             Err(_) => None,
         },
-        None => if block_number.0 > 0 {
-            None
-        } else {
-            Some(Hash::default())
-        },
+        None => {
+            if block_number.0 > 0 {
+                None
+            } else {
+                Some(Hash::default())
+            }
+        }
     }
 }
 
diff --git a/ws2p-v1-legacy/parsers/identities.rs b/ws2p-v1-legacy/parsers/identities.rs
index 3de01344f5e9d5d4c1f4c17417b64add3d11b84e..ef62335415055c325cef050850d8957efc949fb9 100644
--- a/ws2p-v1-legacy/parsers/identities.rs
+++ b/ws2p-v1-legacy/parsers/identities.rs
@@ -20,7 +20,8 @@ pub fn parse_identities(currency: &str, json_datas: &str) -> Option<Vec<Identity
                 .map(|i| {
                     i.clone()
                         .expect("Fatal error : Fail to parse identity from local DB !")
-                }).collect(),
+                })
+                .collect(),
         );
     }
     None
@@ -50,7 +51,8 @@ pub fn parse_identities_from_json_value(
             } else {
                 Err(IdentityParseError::WrongFormat())
             }
-        }).collect()
+        })
+        .collect()
 }
 
 pub fn parse_compact_identity(
diff --git a/ws2p-v1-legacy/parsers/memberships.rs b/ws2p-v1-legacy/parsers/memberships.rs
index 1d9c76bdbea1fc8b4dc70c5bdc0760a709fcdccd..a193d5e64ea9ed393bd606eb63b85fd4a29d77a2 100644
--- a/ws2p-v1-legacy/parsers/memberships.rs
+++ b/ws2p-v1-legacy/parsers/memberships.rs
@@ -25,11 +25,13 @@ pub fn parse_memberships(
                 currency,
                 membership_type,
                 raw_memberships.as_array().unwrap(),
-            ).iter()
+            )
+            .iter()
             .map(|m| {
                 m.clone()
                     .expect("Fatal error : Fail to parse membership from local DB !")
-            }).collect(),
+            })
+            .collect(),
         );
     }
     None
@@ -62,5 +64,6 @@ pub fn parse_memberships_from_json_value(
             } else {
                 Err(MembershipParseError::WrongFormat())
             }
-        }).collect()
+        })
+        .collect()
 }
diff --git a/ws2p-v1-legacy/parsers/mod.rs b/ws2p-v1-legacy/parsers/mod.rs
index 4865af2852d5b8bc7d4e1040da072e78313533a0..7796b278e480cfc8e02a2530a9d2366ca0d5f949 100644
--- a/ws2p-v1-legacy/parsers/mod.rs
+++ b/ws2p-v1-legacy/parsers/mod.rs
@@ -58,7 +58,8 @@ mod tests {
             currency: "g1",
             blockstamp: &Blockstamp::from_string(
                 "112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
-            ).unwrap(),
+            )
+            .unwrap(),
             locktime: &0,
             issuers: &vec![PubKey::Ed25519(
                 ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2")
@@ -67,12 +68,14 @@ mod tests {
             inputs: &vec![
                 TransactionInput::parse_from_str(
                     "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
-                ).unwrap(),
+                )
+                .unwrap(),
             ],
             outputs: &vec![
                 TransactionOutput::parse_from_str(
                     "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
-                ).unwrap(),
+                )
+                .unwrap(),
             ],
             unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
             comment: "Merci pour la calligraphie ;) de Liam",
@@ -118,7 +121,8 @@ mod tests {
             currency: "g1",
             blockstamp: &Blockstamp::from_string(
                 "58-00005B9167EBA1E32C6EAD42AE7F72D8F14B765D3C9E47D233B553D47C5AEE0C",
-            ).unwrap(),
+            )
+            .unwrap(),
             locktime: &0,
             issuers: &vec![PubKey::Ed25519(
                 ed25519::PublicKey::from_base58("FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD")
@@ -127,15 +131,18 @@ mod tests {
             inputs: &vec![
                 TransactionInput::parse_from_str(
                     "1000:0:D:FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD:1",
-                ).unwrap(),
+                )
+                .unwrap(),
             ],
             outputs: &vec![
                 TransactionOutput::parse_from_str(
                     "3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)",
-                ).unwrap(),
+                )
+                .unwrap(),
                 TransactionOutput::parse_from_str(
                     "997:0:SIG(FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD)",
-                ).unwrap(),
+                )
+                .unwrap(),
             ],
             unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
             comment: "Un petit cafe ;-)",
diff --git a/ws2p-v1-legacy/parsers/transactions.rs b/ws2p-v1-legacy/parsers/transactions.rs
index fdd1dd353470e270e33ee7fb3f76642cd59d3db9..2484034c468f51e66c5fbbf16fb938b818ddb128 100644
--- a/ws2p-v1-legacy/parsers/transactions.rs
+++ b/ws2p-v1-legacy/parsers/transactions.rs
@@ -114,7 +114,8 @@ Merci pour la calligraphie ;) de Liam$\
             currency: "g1",
             blockstamp: &Blockstamp::from_string(
                 "112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
-            ).unwrap(),
+            )
+            .unwrap(),
             locktime: &0,
             issuers: &vec![PubKey::Ed25519(
                 ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2")
@@ -123,12 +124,14 @@ Merci pour la calligraphie ;) de Liam$\
             inputs: &vec![
                 TransactionInput::parse_from_str(
                     "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
-                ).unwrap(),
+                )
+                .unwrap(),
             ],
             outputs: &vec![
                 TransactionOutput::parse_from_str(
                     "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
-                ).unwrap(),
+                )
+                .unwrap(),
             ],
             unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
             comment: "Merci pour la calligraphie ;) de Liam",
diff --git a/ws2p-v1-legacy/ws2p_connection.rs b/ws2p-v1-legacy/ws2p_connection.rs
index cdc43a9160acc32f788add3e952dbea8331d5def..11969541bf44553b647af4e5210b996361b651eb 100644
--- a/ws2p-v1-legacy/ws2p_connection.rs
+++ b/ws2p-v1-legacy/ws2p_connection.rs
@@ -479,45 +479,52 @@ impl WS2PConnectionMetaDatas {
         }
         if let Some(body) = m.get("body") {
             match body.get("name") {
-                Some(s) => if s.is_string() {
-                    match s.as_str().unwrap() {
-                        "BLOCK" => match body.get("block") {
-                            Some(block) => {
-                                if let Some(network_block) = parse_json_block(&block) {
-                                    return WS2PConnectionMessagePayload::Document(
-                                        NetworkDocument::Block(network_block),
-                                    );
-                                } else {
-                                    info!("WS2PSignal: receive invalid block (wrong format).");
-                                };
-                            }
-                            None => return WS2PConnectionMessagePayload::WrongFormatMessage,
-                        },
-                        "HEAD" => match body.get("heads") {
-                            Some(heads) => match heads.as_array() {
-                                Some(heads_array) => {
-                                    return WS2PConnectionMessagePayload::Heads(heads_array.clone())
+                Some(s) => {
+                    if s.is_string() {
+                        match s.as_str().unwrap() {
+                            "BLOCK" => match body.get("block") {
+                                Some(block) => {
+                                    if let Some(network_block) = parse_json_block(&block) {
+                                        return WS2PConnectionMessagePayload::Document(
+                                            NetworkDocument::Block(network_block),
+                                        );
+                                    } else {
+                                        info!("WS2PSignal: receive invalid block (wrong format).");
+                                    };
                                 }
                                 None => return WS2PConnectionMessagePayload::WrongFormatMessage,
                             },
-                            None => return WS2PConnectionMessagePayload::WrongFormatMessage,
-                        },
-                        "PEER" => return self.parse_and_check_peer_message(body),
-                        "CERTIFICATION" => {
-                            trace!("WS2P : Receive CERTIFICATION from {}.", self.node_full_id());
-                            /*return WS2PConnectionMessagePayload::Document(
-                                NetworkDocument::Certification(_)
-                            );*/
-                        }
-                        _ => {
-                            /*trace!(
-                                "WS2P : Receive Unknow Message from {}.",
-                                self.node_full_id()
-                            );*/
-                            return WS2PConnectionMessagePayload::UnknowMessage;
-                        }
-                    };
-                },
+                            "HEAD" => match body.get("heads") {
+                                Some(heads) => match heads.as_array() {
+                                    Some(heads_array) => {
+                                        return WS2PConnectionMessagePayload::Heads(
+                                            heads_array.clone(),
+                                        )
+                                    }
+                                    None => return WS2PConnectionMessagePayload::WrongFormatMessage,
+                                },
+                                None => return WS2PConnectionMessagePayload::WrongFormatMessage,
+                            },
+                            "PEER" => return self.parse_and_check_peer_message(body),
+                            "CERTIFICATION" => {
+                                trace!(
+                                    "WS2P : Receive CERTIFICATION from {}.",
+                                    self.node_full_id()
+                                );
+                                /*return WS2PConnectionMessagePayload::Document(
+                                    NetworkDocument::Certification(_)
+                                );*/
+                            }
+                            _ => {
+                                /*trace!(
+                                    "WS2P : Receive Unknow Message from {}.",
+                                    self.node_full_id()
+                                );*/
+                                return WS2PConnectionMessagePayload::UnknowMessage;
+                            }
+                        };
+                    }
+                }
                 None => {
                     warn!("WS2P Error : invalid format : Body must contain a field name !");
                     return WS2PConnectionMessagePayload::WrongFormatMessage;
diff --git a/ws2p-v1-legacy/ws2p_db.rs b/ws2p-v1-legacy/ws2p_db.rs
index 725347be2659331e049b69db1e96218b38b16bda..88f165a7d7f76f2a2f68eeb017add0e1d841e558 100644
--- a/ws2p-v1-legacy/ws2p_db.rs
+++ b/ws2p-v1-legacy/ws2p_db.rs
@@ -121,7 +121,8 @@ pub fn write_endpoint(
                 "UPDATE endpoints SET status={} WHERE hash_full_id='{}'",
                 endpoint.status(),
                 hash_full_id
-            )).expect("Fail to parse SQL request update endpoint  status !");
+            ))
+            .expect("Fail to parse SQL request update endpoint  status !");
         }
     } else if let EndpointEnum::V1(ref ep_v10) = *endpoint {
         db
diff --git a/ws2p-v1-legacy/ws2p_requests.rs b/ws2p-v1-legacy/ws2p_requests.rs
index 722b0154b8a156a119774775671c41ab1a6f7eb6..72b988418355e759653d73b74a7e0a95a3a51d67 100644
--- a/ws2p-v1-legacy/ws2p_requests.rs
+++ b/ws2p-v1-legacy/ws2p_requests.rs
@@ -3,14 +3,14 @@ extern crate duniter_network;
 extern crate serde;
 extern crate serde_json;
 
-use duniter_network::NetworkRequest;
+use duniter_network::OldNetworkRequest;
 
-pub fn network_request_to_json(request: &NetworkRequest) -> serde_json::Value {
+pub fn network_request_to_json(request: &OldNetworkRequest) -> serde_json::Value {
     let (request_id, request_type, request_params) = match *request {
-        NetworkRequest::GetCurrent(ref req_full_id, _receiver) => {
+        OldNetworkRequest::GetCurrent(ref req_full_id, _receiver) => {
             (req_full_id.1, "CURRENT", json!({}))
         }
-        NetworkRequest::GetBlocks(ref req_full_id, _receiver, count, from_mumber) => (
+        OldNetworkRequest::GetBlocks(ref req_full_id, _receiver, count, from_mumber) => (
             req_full_id.1,
             "BLOCKS_CHUNK",
             json!({
@@ -18,18 +18,18 @@ pub fn network_request_to_json(request: &NetworkRequest) -> serde_json::Value {
                     "fromNumber": from_mumber
                 }),
         ),
-        NetworkRequest::GetRequirementsPending(ref req_full_id, _receiver, min_cert) => (
+        OldNetworkRequest::GetRequirementsPending(ref req_full_id, _receiver, min_cert) => (
             req_full_id.1,
             "WOT_REQUIREMENTS_OF_PENDING",
             json!({ "minCert": min_cert }),
         ),
-        NetworkRequest::GetConsensus(_) => {
+        OldNetworkRequest::GetConsensus(_) => {
             panic!("GetConsensus() request must be not convert to json !");
         }
-        NetworkRequest::GetHeadsCache(_) => {
+        OldNetworkRequest::GetHeadsCache(_) => {
             panic!("GetHeadsCache() request must be not convert to json !");
         }
-        NetworkRequest::GetEndpoints(_) => {
+        OldNetworkRequest::GetEndpoints(_) => {
             panic!("GetEndpoints() request must be not convert to json !");
         }
     };
diff --git a/ws2p/Cargo.toml b/ws2p/Cargo.toml
index 80b49ca3e9700da74ad3117e684ea2540a6b8a8b..9180eefb609fd93b2c9ed855006124170d7d4a3b 100644
--- a/ws2p/Cargo.toml
+++ b/ws2p/Cargo.toml
@@ -18,6 +18,7 @@ durs-ws2p-messages = { path = "../ws2p-messages" }
 log = "0.4.*"
 serde = "1.0.*"
 serde_derive = "1.0.*"
+structopt= "0.2.*"
 
 [features]
 # Treat warnings as a build error.
diff --git a/ws2p/lib.rs b/ws2p/lib.rs
index 14796e5e671c0ad96115c82caf6ce6794e36deba..cbb708c44d2d9d2a6e321a0b5650fcae8efa6274 100644
--- a/ws2p/lib.rs
+++ b/ws2p/lib.rs
@@ -31,6 +31,8 @@
 extern crate log;
 #[macro_use]
 extern crate serde_derive;
+#[macro_use]
+extern crate structopt;
 
 extern crate duniter_conf;
 extern crate duniter_crypto;
@@ -44,7 +46,7 @@ mod constants;
 use constants::*;
 use duniter_conf::DuRsConf;
 use duniter_crypto::keys::*;
-use duniter_message::DuniterMessage;
+use duniter_message::DursMsg;
 use duniter_module::*;
 use duniter_network::network_endpoint::*;
 use duniter_network::*;
@@ -69,23 +71,27 @@ impl Default for WS2PConf {
                     PubKey::Ed25519(
                         ed25519::PublicKey::from_base58(
                             "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
-                        ).unwrap(),
+                        )
+                        .unwrap(),
                     ),
                     0,
                     0,
                     1u16,
-                ).unwrap(),
+                )
+                .unwrap(),
                 EndpointEnum::parse_from_raw(
                     "WS2P b48824f0 g1.monnaielibreoccitanie.org 443 /ws2p",
                     PubKey::Ed25519(
                         ed25519::PublicKey::from_base58(
                             "7v2J4badvfWQ6qwRdCwhhJfAsmKwoxRUNpJHiJHj7zef",
-                        ).unwrap(),
+                        )
+                        .unwrap(),
                     ),
                     0,
                     0,
                     1u16,
-                ).unwrap(),
+                )
+                .unwrap(),
             ],
         }
     }
@@ -108,7 +114,7 @@ pub enum WS2PFeaturesParseError {
     UnknowApiFeature(String),
 }
 
-impl ApiModule<DuRsConf, DuniterMessage> for WS2Pv2Module {
+impl ApiModule<DuRsConf, DursMsg> for WS2Pv2Module {
     type ParseErr = WS2PFeaturesParseError;
     /// Parse raw api features
     fn parse_raw_api_features(str_features: &str) -> Result<ApiFeatures, Self::ParseErr> {
@@ -134,23 +140,32 @@ impl ApiModule<DuRsConf, DuniterMessage> for WS2Pv2Module {
     }
 }
 
-impl NetworkModule<DuRsConf, DuniterMessage> for WS2Pv2Module {
+impl NetworkModule<DuRsConf, DursMsg> for WS2Pv2Module {
     fn sync(
         _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         _keys: RequiredKeysContent,
         _conf: WS2PConf,
-        _main_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>,
-        _sync_endpoint: SyncEndpoint,
+        _main_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
+        _sync_params: SyncParams,
     ) -> Result<(), ModuleInitError> {
         unimplemented!()
     }
 }
 
-impl DuniterModule<DuRsConf, DuniterMessage> for WS2Pv2Module {
+#[derive(StructOpt, Debug, Copy, Clone)]
+#[structopt(
+    name = "ws2p",
+    raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// WS2P subcommand options
+pub struct WS2POpt {}
+
+impl DuniterModule<DuRsConf, DursMsg> for WS2Pv2Module {
     type ModuleConf = WS2PConf;
+    type ModuleOpt = WS2POpt;
 
-    fn id() -> ModuleId {
-        ModuleId(String::from("ws2p"))
+    fn name() -> ModuleStaticName {
+        ModuleStaticName("ws2p")
     }
     fn priority() -> ModulePriority {
         ModulePriority::Essential()
@@ -158,11 +173,22 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2Pv2Module {
     fn ask_required_keys() -> RequiredKeys {
         RequiredKeys::NetworkKeyPair()
     }
+    fn have_subcommand() -> bool {
+        true
+    }
+    fn exec_subcommand(
+        _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
+        _keys: RequiredKeysContent,
+        _module_conf: Self::ModuleConf,
+        _subcommand_args: WS2POpt,
+    ) -> () {
+        println!("Succesfully exec ws2p subcommand !")
+    }
     fn start(
         _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
         _keys: RequiredKeysContent,
         _conf: WS2PConf,
-        _rooter_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>,
+        _rooter_sender: mpsc::Sender<RooterThreadMessage<DursMsg>>,
         _load_conf_only: bool,
     ) -> Result<(), ModuleInitError> {
         unimplemented!()