diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ce5414b958737f138f9549f2a2d2a031d5cf5200..327707ff9926ebe9ac4180049235c237fc04c84b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -94,6 +94,7 @@ run_benchmarks:
   tags:
     - podman
 
+# FIXME: "gtest_build"
 gdev_build:
   stage: build
   image: rust:1-bullseye
diff --git a/Cargo.lock b/Cargo.lock
index 7c939dae90fe4114d37d5934cd15ab862df6c7f6..d4e07f05ff14faaeab5e20373e79b117145c8636 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1160,6 +1160,7 @@ dependencies = [
  "pallet-scheduler",
  "pallet-session",
  "pallet-session-benchmarking",
+ "pallet-smith-members",
  "pallet-timestamp",
  "pallet-treasury",
  "pallet-universal-dividend",
@@ -3171,6 +3172,7 @@ dependencies = [
  "pallet-scheduler",
  "pallet-session",
  "pallet-session-benchmarking",
+ "pallet-smith-members",
  "pallet-sudo",
  "pallet-timestamp",
  "pallet-transaction-payment",
@@ -3241,6 +3243,7 @@ dependencies = [
  "pallet-scheduler",
  "pallet-session",
  "pallet-session-benchmarking",
+ "pallet-smith-members",
  "pallet-sudo",
  "pallet-timestamp",
  "pallet-transaction-payment",
@@ -3572,6 +3575,7 @@ dependencies = [
  "pallet-scheduler",
  "pallet-session",
  "pallet-session-benchmarking",
+ "pallet-smith-members",
  "pallet-sudo",
  "pallet-timestamp",
  "pallet-transaction-payment",
@@ -6348,6 +6352,27 @@ dependencies = [
  "sp-std 5.0.0",
 ]
 
+[[package]]
+name = "pallet-smith-members"
+version = "3.0.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "log",
+ "maplit",
+ "pallet-authority-members",
+ "pallet-balances",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std 5.0.0",
+]
+
 [[package]]
 name = "pallet-sudo"
 version = "4.0.0-dev"
diff --git a/Cargo.toml b/Cargo.toml
index 5517414ea929bdcb8445fca79f6b8e9b0f7e711d..362749c15a189ed509b54fa6e311b5075387ad1a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -156,6 +156,7 @@ members = [
     'pallets/membership',
     'pallets/oneshot-account',
     'pallets/authority-members',
+    'pallets/smith-members',
     'pallets/universal-dividend',
     'pallets/upgrade-origin',
     'primitives/membership',
diff --git a/end2end-tests/cucumber-genesis/default.json b/end2end-tests/cucumber-genesis/default.json
index fab39aad614d7f3f631cae19d24dfd757cc567d0..245e91e312e06afca31bf3a5023a5e423c8d2e31 100644
--- a/end2end-tests/cucumber-genesis/default.json
+++ b/end2end-tests/cucumber-genesis/default.json
@@ -56,13 +56,8 @@
     "pending_membership_period": 500,
     "ud_creation_period": 60000,
     "ud_reeval_period": 600000,
-    "smith_cert_period": 15,
     "smith_cert_max_by_issuer": 8,
-    "smith_cert_min_received_cert_to_issue_cert": 2,
-    "smith_cert_validity_period": 1000,
-    "smith_membership_period": 1000,
-    "smith_pending_membership_period": 500,
-    "smith_wot_first_cert_issuable_on": 20,
+    "smith_inactivity_max_duration": 48,
     "smith_wot_min_cert_for_membership": 2,
     "wot_first_cert_issuable_on": 20,
     "wot_min_cert_for_create_idty_right": 2,
diff --git a/end2end-tests/cucumber-genesis/wot.json b/end2end-tests/cucumber-genesis/wot.json
index 4c7183b2a37cd3b82fd4c95ba360cf0025c91ae8..6b1fad67065eb3323c083cc7e0e80ae8ce6098ef 100644
--- a/end2end-tests/cucumber-genesis/wot.json
+++ b/end2end-tests/cucumber-genesis/wot.json
@@ -65,13 +65,8 @@
     "pending_membership_period": 500,
     "ud_creation_period": 60000,
     "ud_reeval_period": 600000,
-    "smith_cert_period": 15,
     "smith_cert_max_by_issuer": 8,
-    "smith_cert_min_received_cert_to_issue_cert": 2,
-    "smith_cert_validity_period": 1000,
-    "smith_membership_period": 1000,
-    "smith_pending_membership_period": 500,
-    "smith_wot_first_cert_issuable_on": 20,
+    "smith_inactivity_max_duration": 48,
     "smith_wot_min_cert_for_membership": 2,
     "wot_first_cert_issuable_on": 20,
     "wot_min_cert_for_create_idty_right": 2,
diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs
index 0639cbfed4d086ba965d2ce4fb8cc15f7c8d37f0..4d80232c6e87564a2a7cfcffb75261c29bd49164 100644
--- a/node/src/chain_spec/gdev.rs
+++ b/node/src/chain_spec/gdev.rs
@@ -24,9 +24,8 @@ use common_runtime::*;
 use gdev_runtime::{
     opaque::SessionKeys, pallet_universal_dividend, parameters, AccountConfig,
     AuthorityMembersConfig, BabeConfig, BalancesConfig, CertConfig, GenesisConfig, IdentityConfig,
-    MembershipConfig, ParametersConfig, QuotaConfig, Runtime, SessionConfig, SmithCertConfig,
-    SmithMembershipConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig,
-    UniversalDividendConfig, WASM_BINARY,
+    MembershipConfig, ParametersConfig, QuotaConfig, Runtime, SessionConfig, SmithMembersConfig,
+    SudoConfig, SystemConfig, TechnicalCommitteeConfig, UniversalDividendConfig, WASM_BINARY,
 };
 use jsonrpsee::core::JsonValue;
 use sc_network::config::MultiaddrWithPeerId;
@@ -39,7 +38,7 @@ use std::{env, fs};
 
 pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;
 
-type GenesisParameters = gdev_runtime::GenesisParameters<u32, u32, u64>;
+type GenesisParameters = gdev_runtime::GenesisParameters<u32, u32, u64, u32>;
 
 const TOKEN_DECIMALS: usize = 2;
 const TOKEN_SYMBOL: &str = "ÄžD";
@@ -94,17 +93,10 @@ fn get_parameters(parameters_from_file: &Option<GenesisParameters>) -> CommonPar
         cert_validity_period: parameters_from_file.cert_validity_period,
         distance_min_accessible_referees: Perbill::from_percent(80), // TODO: generalize
         distance_max_depth: 5,                                       // TODO: generalize
-        smith_sub_wot_first_issuable_on: parameters_from_file.smith_wot_first_cert_issuable_on,
         smith_sub_wot_min_cert_for_membership: parameters_from_file
             .smith_wot_min_cert_for_membership,
-        smith_membership_membership_period: parameters_from_file.smith_membership_period,
-        smith_membership_pending_membership_period: parameters_from_file
-            .smith_pending_membership_period,
-        smith_cert_cert_period: parameters_from_file.smith_cert_period,
         smith_cert_max_by_issuer: parameters_from_file.smith_cert_max_by_issuer,
-        smith_cert_min_received_cert_to_be_able_to_issue_cert: parameters_from_file
-            .smith_cert_min_received_cert_to_issue_cert,
-        smith_cert_validity_period: parameters_from_file.smith_cert_validity_period,
+        smith_inactivity_max_duration: parameters_from_file.smith_inactivity_max_duration,
         cert_cert_period: parameters_from_file.cert_period,
         treasury_spend_period: <Runtime as pallet_treasury::Config>::SpendPeriod::get(),
     }
@@ -290,8 +282,7 @@ fn genesis_data_to_gdev_genesis_conf(
         parameters,
         common_parameters: _,
         session_keys_map,
-        smith_certs_by_receiver,
-        smith_memberships,
+        initial_smiths,
         sudo_key,
         technical_committee_members,
         ud,
@@ -366,13 +357,7 @@ fn genesis_data_to_gdev_genesis_conf(
             certs_by_receiver,
         },
         membership: MembershipConfig { memberships },
-        smith_cert: SmithCertConfig {
-            apply_cert_period_at_genesis: true,
-            certs_by_receiver: smith_certs_by_receiver,
-        },
-        smith_membership: SmithMembershipConfig {
-            memberships: smith_memberships,
-        },
+        smith_members: SmithMembersConfig { initial_smiths },
         universal_dividend: UniversalDividendConfig {
             first_reeval: first_ud_reeval,
             first_ud,
@@ -387,8 +372,6 @@ fn get_local_chain_parameters() -> Option<GenesisParameters> {
     let babe_epoch_duration = get_env("DUNITER_BABE_EPOCH_DURATION", 30) as u64;
     let cert_validity_period = get_env("DUNITER_CERT_VALIDITY_PERIOD", 1_000);
     let membership_period = get_env("DUNITER_MEMBERSHIP_PERIOD", 1_000);
-    let smith_cert_validity_period = get_env("DUNITER_SMITH_CERT_VALIDITY_PERIOD", 1_000);
-    let smith_membership_period = get_env("DUNITER_SMITH_MEMBERSHIP_PERIOD", 1_000);
     let ud_creation_period = get_env("DUNITER_UD_CREATION_PERIOD", 60_000);
     let ud_reeval_period = get_env("DUNITER_UD_REEEVAL_PERIOD", 1_200_000);
     Some(GenesisParameters {
@@ -403,13 +386,8 @@ fn get_local_chain_parameters() -> Option<GenesisParameters> {
         pending_membership_period: 500,
         ud_creation_period,
         ud_reeval_period,
-        smith_cert_period: 15,
         smith_cert_max_by_issuer: 8,
-        smith_cert_min_received_cert_to_issue_cert: 2,
-        smith_cert_validity_period,
-        smith_membership_period,
-        smith_pending_membership_period: 500,
-        smith_wot_first_cert_issuable_on: 20,
+        smith_inactivity_max_duration: 48,
         smith_wot_min_cert_for_membership: 2,
         wot_first_cert_issuable_on: 20,
         wot_min_cert_for_create_idty_right: 2,
diff --git a/node/src/chain_spec/gen_genesis_data.rs b/node/src/chain_spec/gen_genesis_data.rs
index 1813434b7a43e0366d89fc345c163a498102f250..ab9856efe65d8161e595fb68d0cc0b1960c21259 100644
--- a/node/src/chain_spec/gen_genesis_data.rs
+++ b/node/src/chain_spec/gen_genesis_data.rs
@@ -74,8 +74,7 @@ pub struct GenesisData<Parameters: DeserializeOwned, SessionKeys: Decode> {
     pub parameters: Option<Parameters>,
     pub common_parameters: Option<CommonParameters>,
     pub session_keys_map: BTreeMap<AccountId, SessionKeys>,
-    pub smith_certs_by_receiver: BTreeMap<u32, BTreeMap<u32, Option<u32>>>,
-    pub smith_memberships: BTreeMap<u32, MembershipData>,
+    pub initial_smiths: BTreeMap<u32, (bool, Vec<u32>)>,
     pub sudo_key: Option<AccountId>,
     pub technical_committee_members: Vec<AccountId>,
     pub ud: u64,
@@ -235,9 +234,8 @@ struct CliqueSmith {
     session_keys: Option<String>,
 }
 
-struct SmithWoT<SK: Decode> {
-    smith_certs_by_receiver: BTreeMap<u32, BTreeMap<u32, Option<u32>>>,
-    smith_memberships: BTreeMap<u32, sp_membership::MembershipData<u32>>,
+struct SmithMembers<SK: Decode> {
+    initial_smiths_wot: BTreeMap<u32, (bool, Vec<u32>)>,
     session_keys_map:
         BTreeMap<<<MultiSignature as Verify>::Signer as IdentifyAccount>::AccountId, SK>,
 }
@@ -249,7 +247,7 @@ struct GenesisInfo<'a> {
     inactive_identities: &'a HashMap<u32, String>,
     identities: &'a Vec<GenesisIdentity>,
     identity_index: &'a HashMap<u32, String>,
-    smith_memberships: &'a BTreeMap<u32, MembershipData>,
+    initial_smiths: &'a BTreeMap<u32, (bool, Vec<u32>)>,
     counter_online_authorities: &'a u32,
     counter_cert: &'a u32,
     counter_smith_cert: &'a u32,
@@ -395,16 +393,14 @@ where
         was_fatal,
         counter_online_authorities,
         counter_smith_cert,
-        SmithWoT {
-            smith_certs_by_receiver,
-            smith_memberships,
+        SmithMembers {
+            initial_smiths_wot,
             session_keys_map,
         },
     ) = create_smith_wot(
         &mut initial_authorities,
         &identities_v2,
         &smiths,
-        &common_parameters,
         &clique_smiths,
     )?;
     if was_fatal {
@@ -429,7 +425,7 @@ where
     }
 
     // Verify smith certifications coherence
-    for (idty_index, certs) in &smith_certs_by_receiver {
+    for (idty_index, (_online, certs)) in &initial_smiths_wot {
         if certs.len() < common_parameters.smith_sub_wot_min_cert_for_membership as usize {
             log::error!(
                 "[{}] has received only {}/{} smith certifications",
@@ -515,7 +511,7 @@ where
         identities: &identities,
         inactive_identities: &inactive_identities,
         identity_index: &identity_index,
-        smith_memberships: &smith_memberships,
+        initial_smiths: &initial_smiths_wot,
         counter_online_authorities: &counter_online_authorities,
         counter_cert: &counter_cert,
         counter_smith_cert: &counter_smith_cert,
@@ -637,8 +633,8 @@ where
         identities.len() - inactive_identities.len(),
         memberships.len()
     );
-    assert_eq!(smith_memberships.len(), initial_authorities.len());
-    assert_eq!(smith_memberships.len(), session_keys_map.len());
+    assert_eq!(initial_smiths_wot.len(), initial_authorities.len());
+    assert_eq!(initial_smiths_wot.len(), session_keys_map.len());
     assert_eq!(identity_index.len(), identities.len());
     assert_eq!(
         accounts.len(),
@@ -657,7 +653,6 @@ where
         // genesis_certs_min_received => min_cert
         // genesis_memberships_expire_on => membership_period
         // genesis_smith_certs_min_received => smith_min_cert
-        // genesis_smith_memberships_expire_on => smith_membership_period
         let export = GenesisIndexerExport {
             first_ud,
             first_ud_reeval,
@@ -730,8 +725,7 @@ where
         parameters,
         common_parameters: Some(common_parameters),
         session_keys_map,
-        smith_certs_by_receiver,
-        smith_memberships,
+        initial_smiths: initial_smiths_wot,
         sudo_key,
         technical_committee_members,
         ud,
@@ -759,7 +753,7 @@ fn dump_genesis_info(info: GenesisInfo) {
         info.identity_index.len(),
         info.identities.len() - info.inactive_identities.len(),
         info.inactive_identities.len(),
-        info.smith_memberships.len(),
+        info.initial_smiths.len(),
         info.counter_online_authorities,
         info.counter_cert,
         info.counter_smith_cert,
@@ -829,28 +823,15 @@ fn dump_genesis_info(info: GenesisInfo) {
         get_best_unit_and_diviser_for_perbill(p.distance_min_accessible_referees);
     let (distance_max_depth, distance_max_depth_unit) =
         get_best_unit_and_diviser_for_depth(p.distance_max_depth);
-    let (smith_sub_wot_first_issuable_on, smith_sub_wot_first_issuable_on_unit) =
-        get_best_unit_and_diviser_for_blocks(p.smith_sub_wot_first_issuable_on);
-    let (smith_sub_wot_min_cert_for_membership, smith_sub_wot_min_cert_for_membership_unit) =
+    let (smith_members_min_cert_for_membership, smith_members_min_cert_for_membership_unit) =
         get_best_unit_and_diviser_for_certs(p.smith_sub_wot_min_cert_for_membership);
-    let (smith_membership_membership_period, smith_membership_membership_period_unit) =
-        get_best_unit_and_diviser_for_blocks(p.smith_membership_membership_period);
-    let (
-        smith_membership_pending_membership_period,
-        smith_membership_pending_membership_period_unit,
-    ) = get_best_unit_and_diviser_for_blocks(p.smith_membership_pending_membership_period);
-    let (smith_cert_cert_period, smith_cert_cert_period_unit) =
-        get_best_unit_and_diviser_for_blocks(p.smith_cert_cert_period);
-    let (smith_cert_max_by_issuer, smith_cert_max_by_issuer_unit) =
+    let (smith_members_max_by_issuer, smith_members_max_by_issuer_unit) =
         get_best_unit_and_diviser_for_certs(p.smith_cert_max_by_issuer);
-    let (
-        smith_cert_min_received_cert_to_be_able_to_issue_cert,
-        smith_cert_min_received_cert_to_be_able_to_issue_cert_unit,
-    ) = get_best_unit_and_diviser_for_certs(
-        p.smith_cert_min_received_cert_to_be_able_to_issue_cert,
-    );
-    let (smith_cert_validity_period, smith_cert_validity_period_unit) =
-        get_best_unit_and_diviser_for_blocks(p.smith_cert_validity_period);
+    let (smith_members_inactivity_max_duration, smith_members_inactivity_max_duration_unit) =
+        get_best_unit_and_diviser_for_sessions(
+            p.smith_inactivity_max_duration,
+            p.babe_epoch_duration,
+        );
     let (treasury_spend_period, treasury_spend_period_unit) =
         get_best_unit_and_diviser_for_blocks(p.treasury_spend_period);
 
@@ -883,14 +864,9 @@ fn dump_genesis_info(info: GenesisInfo) {
         - cert.validity_period: {} {}
         - distance.min_accessible_referees: {} {}
         - distance.max_depth: {} {},
-        - smith_sub_wot.first_issuable_on: {} {}
-        - smith_sub_wot.min_cert_for_membership: {} {}
-        - smith_membership.membership_period: {} {}
-        - smith_membership.pending_membership_period: {} {}
-        - smith_cert.cert_period: {} {}
-        - smith_cert.max_by_issuer: {} {}
-        - smith_cert.min_received_cert_to_be_able_to_issue_cert: {} {}
-        - smith_cert.validity_period: {} {}
+        - smith_members.min_cert_for_membership: {} {}
+        - smith_members.max_by_issuer: {} {}
+        - smith_members.smith_inactivity_max_duration: {} {}
         - treasury.spend_period: {} {}
         - currency decimals: {}",
         babe_epoch_duration,
@@ -945,22 +921,12 @@ fn dump_genesis_info(info: GenesisInfo) {
         distance_min_accessible_referees_unit,
         distance_max_depth,
         distance_max_depth_unit,
-        smith_sub_wot_first_issuable_on,
-        smith_sub_wot_first_issuable_on_unit,
-        smith_sub_wot_min_cert_for_membership,
-        smith_sub_wot_min_cert_for_membership_unit,
-        smith_membership_membership_period,
-        smith_membership_membership_period_unit,
-        smith_membership_pending_membership_period,
-        smith_membership_pending_membership_period_unit,
-        smith_cert_cert_period,
-        smith_cert_cert_period_unit,
-        smith_cert_max_by_issuer,
-        smith_cert_max_by_issuer_unit,
-        smith_cert_min_received_cert_to_be_able_to_issue_cert,
-        smith_cert_min_received_cert_to_be_able_to_issue_cert_unit,
-        smith_cert_validity_period,
-        smith_cert_validity_period_unit,
+        smith_members_min_cert_for_membership,
+        smith_members_min_cert_for_membership_unit,
+        smith_members_max_by_issuer,
+        smith_members_max_by_issuer_unit,
+        smith_members_inactivity_max_duration,
+        smith_members_inactivity_max_duration_unit,
         treasury_spend_period,
         treasury_spend_period_unit,
         info.common_parameters.decimals,
@@ -979,6 +945,16 @@ fn get_best_unit_and_diviser_for_blocks(duration_in_blocks: u32) -> (f32, String
     get_best_unit_and_diviser_for_ms(duration_in_ms)
 }
 
+fn get_best_unit_and_diviser_for_sessions(
+    duration_in_sessions: u32,
+    babe_epoch_duration_in_blocks: u64,
+) -> (f32, String) {
+    let duration_in_ms = duration_in_sessions as f32
+        * babe_epoch_duration_in_blocks as f32
+        * (MILLISECS_PER_BLOCK as u32) as f32;
+    get_best_unit_and_diviser_for_ms(duration_in_ms)
+}
+
 fn get_best_unit_and_diviser_for_perbill_square(qty: Perbill) -> (f32, String) {
     let qty = f32::sqrt(qty.deconstruct() as f32 / 1_000_000_000f32) * 100f32;
     (qty, "%".to_string())
@@ -1073,16 +1049,14 @@ fn create_smith_wot<SK: Decode>(
     initial_authorities: &mut BTreeMap<u32, (AccountId32, bool)>,
     identities_v2: &HashMap<String, IdentityV2>,
     smiths: &Vec<SmithData>,
-    common_parameters: &CommonParameters,
     clique_smiths: &Option<Vec<CliqueSmith>>,
-) -> Result<(bool, u32, u32, SmithWoT<SK>), String> {
+) -> Result<(bool, u32, u32, SmithMembers<SK>), String> {
     let mut fatal = false;
     let mut counter_online_authorities = 0;
     // counter for smith certifications
     let mut counter_smith_cert = 0;
     let mut smith_certs_by_receiver = BTreeMap::new();
     // smith memberships
-    let mut smith_memberships = BTreeMap::new();
     let mut session_keys_map = BTreeMap::new();
     // Then create the smith WoT
     for smith in smiths {
@@ -1103,16 +1077,7 @@ fn create_smith_wot<SK: Decode>(
                 &smith,
                 identity,
                 &identities_v2_clone,
-                common_parameters,
             )?;
-
-            // smith memberships
-            smith_memberships.insert(
-                identity.index,
-                MembershipData {
-                    expire_on: common_parameters.smith_membership_membership_period,
-                },
-            );
         } else {
             log::error!(
                 "Smith '{}' does not correspond to exising identity",
@@ -1125,9 +1090,18 @@ fn create_smith_wot<SK: Decode>(
         fatal,
         counter_online_authorities,
         counter_smith_cert,
-        SmithWoT {
-            smith_certs_by_receiver,
-            smith_memberships,
+        SmithMembers {
+            initial_smiths_wot: smith_certs_by_receiver
+                .iter()
+                .map(|(k, v)| {
+                    let is_online = initial_authorities
+                        .iter()
+                        .filter(|(k2, (_, online))| *k2 == k && *online)
+                        .count()
+                        > 0;
+                    (*k, (is_online, v.clone()))
+                })
+                .collect(),
             session_keys_map,
         },
     ))
@@ -1549,15 +1523,14 @@ where
 }
 
 fn feed_smith_certs_by_receiver(
-    smith_certs_by_receiver: &mut BTreeMap<u32, BTreeMap<u32, Option<u32>>>,
+    smith_certs_by_receiver: &mut BTreeMap<u32, Vec<u32>>,
     clique_smiths: &Option<Vec<CliqueSmith>>,
     smith: &&SmithData,
     identity: &IdentityV2,
     identities_v2: &HashMap<String, IdentityV2>,
-    common_parameters: &CommonParameters,
 ) -> Result<u32, String> {
     let mut counter_smith_cert = 0;
-    let mut certs = BTreeMap::new();
+    let mut certs = Vec::<u32>::new();
     if clique_smiths.is_some() {
         // All initial smiths are considered to be certifying all each other
         clique_smiths
@@ -1572,7 +1545,7 @@ fn feed_smith_certs_by_receiver(
                         panic!("Identity '{}' does not exist", other_smith.name.as_str())
                     })
                     .index;
-                certs.insert(*issuer_index, None);
+                certs.push(*issuer_index);
                 counter_smith_cert += 1;
             });
     } else {
@@ -1581,10 +1554,7 @@ fn feed_smith_certs_by_receiver(
                 .get(issuer)
                 .ok_or(format!("Identity '{}' does not exist", issuer))?
                 .index;
-            certs.insert(
-                *issuer_index,
-                Some(common_parameters.smith_cert_validity_period),
-            );
+            certs.push(*issuer_index);
             counter_smith_cert += 1;
         }
     }
@@ -1767,11 +1737,11 @@ where
     let genesis_data_wallets_count = 0;
     let inactive_identities = HashMap::new();
 
-    let smith_memberships = (1..=initial_smiths_len)
-        .map(|i| (i as u32, MembershipData { expire_on: 0 }))
-        .collect();
-
-    let (smith_certs_by_receiver, counter_smith_cert) = clique_wot(initial_smiths_len);
+    let initial_smiths_wot: BTreeMap<u32, (bool, Vec<u32>)> = clique_smith_wot(initial_smiths_len);
+    let counter_smith_cert = initial_smiths_wot
+        .iter()
+        .map(|(_, (_, v))| v.len())
+        .sum::<usize>() as u32;
 
     let initial_authorities: BTreeMap<
         u32,
@@ -1808,7 +1778,7 @@ where
         identities: &identities,
         inactive_identities: &inactive_identities,
         identity_index: &identity_index,
-        smith_memberships: &smith_memberships,
+        initial_smiths: &initial_smiths_wot,
         counter_online_authorities: &counter_online_authorities,
         counter_cert: &counter_cert,
         counter_smith_cert: &counter_smith_cert,
@@ -1834,8 +1804,7 @@ where
         parameters,
         common_parameters: None,
         session_keys_map,
-        smith_certs_by_receiver,
-        smith_memberships,
+        initial_smiths: initial_smiths_wot,
         sudo_key: Some(root_key),
         technical_committee_members,
         ud,
@@ -1871,6 +1840,23 @@ fn clique_wot(
     (certs_by_issuer, count)
 }
 
+#[cfg(feature = "gdev")]
+fn clique_smith_wot(initial_identities_len: usize) -> BTreeMap<IdtyIndex, (bool, Vec<IdtyIndex>)> {
+    let mut certs_by_issuer = BTreeMap::new();
+    for i in 1..=initial_identities_len {
+        certs_by_issuer.insert(
+            i as IdtyIndex,
+            (
+                true,
+                (1..=initial_identities_len)
+                    .filter_map(|j| if i != j { Some(j as IdtyIndex) } else { None })
+                    .collect(),
+            ),
+        );
+    }
+    certs_by_issuer
+}
+
 fn check_parameters_consistency(
     wallets: &BTreeMap<PubkeyV1, u64>,
     first_ud: &Option<u64>,
@@ -1999,14 +1985,9 @@ pub struct CommonParameters {
     pub cert_validity_period: u32,
     pub distance_min_accessible_referees: Perbill,
     pub distance_max_depth: u32,
-    pub smith_sub_wot_first_issuable_on: u32,
     pub smith_sub_wot_min_cert_for_membership: u32,
-    pub smith_membership_membership_period: u32,
-    pub smith_membership_pending_membership_period: u32,
-    pub smith_cert_cert_period: u32,
     pub smith_cert_max_by_issuer: u32,
-    pub smith_cert_min_received_cert_to_be_able_to_issue_cert: u32,
-    pub smith_cert_validity_period: u32,
+    pub smith_inactivity_max_duration: u32,
     pub treasury_spend_period: u32,
     // TODO: replace u32 by BlockNumber when appropriate
     pub currency_name: String,
diff --git a/node/src/chain_spec/gtest.rs b/node/src/chain_spec/gtest.rs
index 796b2c7de224df2f3422af8097065389ac3e534c..4b1ee27f2b5b4842cfd04082099e1cb876fef9f8 100644
--- a/node/src/chain_spec/gtest.rs
+++ b/node/src/chain_spec/gtest.rs
@@ -20,12 +20,12 @@ use common_runtime::constants::*;
 use common_runtime::entities::IdtyData;
 use common_runtime::*;
 use frame_benchmarking::frame_support::traits::Get;
+use gtest_runtime::SmithMembersConfig;
 use gtest_runtime::{
     opaque::SessionKeys, pallet_universal_dividend, parameters, AccountConfig, AccountId,
     AuthorityMembersConfig, BabeConfig, BalancesConfig, CertConfig, GenesisConfig, IdentityConfig,
-    ImOnlineId, MembershipConfig, Perbill, QuotaConfig, Runtime, SessionConfig, SmithCertConfig,
-    SmithMembershipConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig,
-    UniversalDividendConfig, WASM_BINARY,
+    ImOnlineId, MembershipConfig, Perbill, QuotaConfig, Runtime, SessionConfig, SudoConfig,
+    SystemConfig, TechnicalCommitteeConfig, UniversalDividendConfig, WASM_BINARY,
 };
 use jsonrpsee::core::JsonValue;
 use sc_consensus_grandpa::AuthorityId as GrandpaId;
@@ -98,15 +98,9 @@ fn get_parameters(_: &Option<GenesisParameters>) -> CommonParameters {
         cert_validity_period: parameters::ValidityPeriod::get(),
         distance_min_accessible_referees: Perbill::from_percent(80), // TODO: generalize
         distance_max_depth: 5,                                       // TODO: generalize
-        smith_sub_wot_first_issuable_on: parameters::SmithWotFirstCertIssuableOn::get(),
         smith_sub_wot_min_cert_for_membership: parameters::SmithWotMinCertForMembership::get(),
-        smith_membership_membership_period: parameters::SmithMembershipPeriod::get(),
-        smith_membership_pending_membership_period: parameters::SmithPendingMembershipPeriod::get(),
-        smith_cert_cert_period: parameters::SmithCertPeriod::get(),
+        smith_inactivity_max_duration: parameters::SmithInactivityMaxDuration::get(),
         smith_cert_max_by_issuer: parameters::SmithMaxByIssuer::get(),
-        smith_cert_min_received_cert_to_be_able_to_issue_cert:
-            parameters::SmithMinReceivedCertToBeAbleToIssueCert::get(),
-        smith_cert_validity_period: parameters::SmithValidityPeriod::get(),
         cert_cert_period: parameters::CertPeriod::get(),
         treasury_spend_period: <Runtime as pallet_treasury::Config>::SpendPeriod::get(),
     }
@@ -239,8 +233,7 @@ fn genesis_data_to_gtest_genesis_conf(
         parameters: _,
         common_parameters: _,
         session_keys_map,
-        smith_certs_by_receiver,
-        smith_memberships,
+        initial_smiths,
         sudo_key,
         technical_committee_members,
         ud,
@@ -313,13 +306,7 @@ fn genesis_data_to_gtest_genesis_conf(
             certs_by_receiver,
         },
         membership: MembershipConfig { memberships },
-        smith_cert: SmithCertConfig {
-            apply_cert_period_at_genesis: true,
-            certs_by_receiver: smith_certs_by_receiver,
-        },
-        smith_membership: SmithMembershipConfig {
-            memberships: smith_memberships,
-        },
+        smith_members: SmithMembersConfig { initial_smiths },
         universal_dividend: UniversalDividendConfig {
             first_reeval: first_ud_reeval,
             first_ud,
diff --git a/pallets/authority-members/src/impls.rs b/pallets/authority-members/src/impls.rs
index ade9f7437bcf80a0e396625d44530c901841dd35..d656f01e6d905427015a02697b026fd54ff036eb 100644
--- a/pallets/authority-members/src/impls.rs
+++ b/pallets/authority-members/src/impls.rs
@@ -20,7 +20,6 @@
 //! The offences are executed here based. The offenders are disconnected and
 //! can be added to a blacklist to avoid futur connection.
 
-#![cfg_attr(not(feature = "std"), no_std)]
 #![allow(clippy::type_complexity)]
 
 use super::pallet::*;
@@ -54,9 +53,8 @@ where
         match strategy {
             SlashStrategy::Blacklist => {
                 for offender in offenders {
-                    Blacklist::<T>::mutate(|blacklist| {
-                        if let Some(member_id) = T::MemberIdOf::convert(offender.offender.0.clone())
-                        {
+                    if let Some(member_id) = T::MemberIdOf::convert(offender.offender.0.clone()) {
+                        Blacklist::<T>::mutate(|blacklist| {
                             if !blacklist.contains(&member_id) {
                                 blacklist.push(member_id);
                                 Self::deposit_event(Event::MemberAddedToBlacklist {
@@ -66,8 +64,8 @@ where
                             }
                             Self::insert_out(member_id);
                             add_db_reads_writes(2, 1);
-                        }
-                    })
+                        });
+                    }
                 }
             }
             SlashStrategy::Disconnect => {
diff --git a/pallets/authority-members/src/lib.rs b/pallets/authority-members/src/lib.rs
index 29c4ecaab49aa3d4c114c5021a892d6bd89fb563..d4ebf6b3fd4a919e055e2f5e72e8c2692e992cf7 100644
--- a/pallets/authority-members/src/lib.rs
+++ b/pallets/authority-members/src/lib.rs
@@ -51,6 +51,7 @@ pub mod pallet {
     use frame_system::pallet_prelude::*;
     use sp_runtime::traits::{Convert, IsMember};
     use sp_std::collections::btree_map::BTreeMap;
+    use sp_std::vec;
 
     /// The current storage version.
     const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
@@ -68,7 +69,8 @@ pub mod pallet {
     {
         type IsMember: IsMember<Self::MemberId>;
         type OnNewSession: OnNewSession;
-        type OnRemovedMember: OnRemovedMember<Self::MemberId>;
+        type OnOutgoingMember: OnOutgoingMember<Self::MemberId>;
+        type OnIncomingMember: OnIncomingMember<Self::MemberId>;
         /// Max number of authorities allowed
         #[pallet::constant]
         type MaxAuthorities: Get<u32>;
@@ -401,7 +403,6 @@ pub mod pallet {
 
             // Emit event
             Self::deposit_event(Event::MemberRemoved { member: member_id });
-            T::OnRemovedMember::on_removed_member(member_id);
         }
         /// perform incoming authorities insertion
         fn insert_in(member_id: T::MemberId) -> bool {
@@ -513,20 +514,23 @@ impl<T: Config> pallet_session::SessionManager<T::ValidatorId> for Pallet<T> {
         let members_ids_to_add = IncomingAuthorities::<T>::take();
         let members_ids_to_del = OutgoingAuthorities::<T>::take();
 
-        if members_ids_to_add.is_empty() {
-            if members_ids_to_del.is_empty() {
-                // when no change to the set of autorities, return None
-                return None;
-            } else {
-                Self::deposit_event(Event::OutgoingAuthorities {
-                    members: members_ids_to_del.clone(),
-                });
-            }
-        } else {
+        if members_ids_to_add.is_empty() && members_ids_to_del.is_empty() {
+            // when no change to the set of autorities, return None
+            return None;
+        }
+
+        for member_id in members_ids_to_add.iter() {
+            T::OnIncomingMember::on_incoming_member(*member_id);
             Self::deposit_event(Event::IncomingAuthorities {
                 members: members_ids_to_add.clone(),
             });
         }
+        for member_id in members_ids_to_del.iter() {
+            T::OnOutgoingMember::on_outgoing_member(*member_id);
+            Self::deposit_event(Event::OutgoingAuthorities {
+                members: members_ids_to_del.clone(),
+            });
+        }
 
         // updates the list of OnlineAuthorities and returns the list of their key
         Some(
diff --git a/pallets/authority-members/src/mock.rs b/pallets/authority-members/src/mock.rs
index d04f0f47f89905eb13f211dcfd58098887743239..4c818534a42d84227b1542ed68dc29f4c449804a 100644
--- a/pallets/authority-members/src/mock.rs
+++ b/pallets/authority-members/src/mock.rs
@@ -156,10 +156,11 @@ impl pallet_authority_members::Config for Test {
     type MemberId = u64;
     type MemberIdOf = ConvertInto;
     type OnNewSession = ();
-    type OnRemovedMember = ();
     type RemoveMemberOrigin = system::EnsureRoot<u64>;
     type RuntimeEvent = RuntimeEvent;
     type WeightInfo = ();
+    type OnIncomingMember = ();
+    type OnOutgoingMember = ();
 }
 
 // Build genesis storage according to the mock runtime.
diff --git a/pallets/authority-members/src/traits.rs b/pallets/authority-members/src/traits.rs
index 81f36396e9e1b5f3cd4baebc3c07c6c4f013365e..2bb98f77d134a8e3e6f6b45c53c88626309ee330 100644
--- a/pallets/authority-members/src/traits.rs
+++ b/pallets/authority-members/src/traits.rs
@@ -24,10 +24,22 @@ impl OnNewSession for () {
     fn on_new_session(_: SessionIndex) {}
 }
 
-pub trait OnRemovedMember<MemberId> {
-    fn on_removed_member(member_id: MemberId);
+/// Handle the consequences of going in the authority set for other pallets.
+/// Typically, a smith won't expire as long as he is in the authority set.
+pub trait OnIncomingMember<MemberId> {
+    fn on_incoming_member(member_id: MemberId);
+}
+/// By default: no consequences
+impl<MemberId> OnIncomingMember<MemberId> for () {
+    fn on_incoming_member(_: MemberId) {}
 }
 
-impl<MemberId> OnRemovedMember<MemberId> for () {
-    fn on_removed_member(_: MemberId) {}
+/// Handle the consequences of going out of authority set for other pallets.
+/// Typically, the smiths are not allowed to stay offline for a too long time.
+pub trait OnOutgoingMember<MemberId> {
+    fn on_outgoing_member(member_id: MemberId);
+}
+/// By default: no consequences
+impl<MemberId> OnOutgoingMember<MemberId> for () {
+    fn on_outgoing_member(_: MemberId) {}
 }
diff --git a/pallets/certification/src/benchmarking.rs b/pallets/certification/src/benchmarking.rs
index 4a4b61a8e812d97c676ae190d43aa5512a0ccfab..553e34846ae9c1a99e68c5ee677ffbd126c50979 100644
--- a/pallets/certification/src/benchmarking.rs
+++ b/pallets/certification/src/benchmarking.rs
@@ -18,7 +18,7 @@
 
 use super::*;
 
-use frame_benchmarking::benchmarks_instance_pallet;
+use frame_benchmarking::benchmarks;
 use frame_benchmarking::Zero;
 use frame_system::RawOrigin;
 use sp_runtime::traits::Convert;
@@ -28,23 +28,23 @@ use maplit::btreemap;
 
 use crate::Pallet;
 
-fn assert_has_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::RuntimeEvent) {
+fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
     frame_system::Pallet::<T>::assert_has_event(generic_event.into());
 }
 
-fn add_certs<T: Config<I>, I: 'static>(i: u32, receiver: T::IdtyIndex) -> Result<(), &'static str> {
-    Pallet::<T, I>::remove_all_certs_received_by(RawOrigin::Root.into(), receiver)?;
+fn add_certs<T: Config>(i: u32, receiver: T::IdtyIndex) -> Result<(), &'static str> {
+    Pallet::<T>::remove_all_certs_received_by(RawOrigin::Root.into(), receiver)?;
     for j in 1..i {
-        Pallet::<T, I>::do_add_cert_checked(j.into(), receiver, false)?;
+        Pallet::<T>::do_add_cert_checked(j.into(), receiver, false)?;
     }
     assert!(
-        CertsByReceiver::<T, I>::get(receiver).len() as u32 == i - 1,
+        CertsByReceiver::<T>::get(receiver).len() as u32 == i - 1,
         "Certs not added",
     );
     Ok(())
 }
 
-benchmarks_instance_pallet! {
+benchmarks! {
     where_clause {
         where
             T::IdtyIndex: From<u32>,
@@ -54,47 +54,47 @@ benchmarks_instance_pallet! {
         let caller: T::AccountId  = T::OwnerKeyOf::convert(issuer).unwrap();
         let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
         let receiver: T::IdtyIndex = 2.into();
-        Pallet::<T, I>::del_cert(RawOrigin::Root.into(), issuer, receiver)?;
-        let issuer_cert: u32 = StorageIdtyCertMeta::<T, I>::get(issuer).issued_count;
-        let receiver_cert: u32 = StorageIdtyCertMeta::<T, I>::get(receiver).received_count;
+        Pallet::<T>::del_cert(RawOrigin::Root.into(), issuer, receiver)?;
+        let issuer_cert: u32 = StorageIdtyCertMeta::<T>::get(issuer).issued_count;
+        let receiver_cert: u32 = StorageIdtyCertMeta::<T>::get(receiver).received_count;
         frame_system::pallet::Pallet::<T>::set_block_number(T::CertPeriod::get());
     }: _<T::RuntimeOrigin>(caller_origin, issuer, receiver)
     verify {
-        assert_has_event::<T, I>(Event::<T, I>::CertAdded{ issuer, receiver }.into());
+        assert_has_event::<T>(Event::<T>::CertAdded{ issuer, receiver }.into());
     }
     del_cert {
         let issuer: T::IdtyIndex = 1.into();
         let receiver: T::IdtyIndex = 0.into();
-        Pallet::<T, I>::do_add_cert_checked(issuer, receiver, false)?;
-        let receiver_cert: u32 = StorageIdtyCertMeta::<T, I>::get(receiver).received_count;
-        let issuer_cert: u32 = StorageIdtyCertMeta::<T, I>::get(issuer).issued_count;
+        Pallet::<T>::do_add_cert_checked(issuer, receiver, false)?;
+        let receiver_cert: u32 = StorageIdtyCertMeta::<T>::get(receiver).received_count;
+        let issuer_cert: u32 = StorageIdtyCertMeta::<T>::get(issuer).issued_count;
     }: _<T::RuntimeOrigin>(RawOrigin::Root.into(), issuer, receiver)
     verify {
-        assert_has_event::<T, I>(Event::<T, I>::CertRemoved{ issuer,  receiver, expiration: false }.into());
+        assert_has_event::<T>(Event::<T>::CertRemoved{ issuer,  receiver, expiration: false }.into());
     }
     remove_all_certs_received_by {
         let receiver: T::IdtyIndex = 0.into();
-        let i in 2..1000 => add_certs::<T, I>(i, receiver)?;
+        let i in 2..1000 => add_certs::<T>(i, receiver)?;
     }: _<T::RuntimeOrigin>(RawOrigin::Root.into(),  receiver)
     verify {
-        assert!(CertsByReceiver::<T, I>::get(receiver).is_empty() );
+        assert!(CertsByReceiver::<T>::get(receiver).is_empty() );
     }
     on_initialize {
-        assert!(StorageCertsRemovableOn::<T, I>::try_get(T::BlockNumber::zero()).is_err());
-    }: {Pallet::<T, I>::on_initialize(T::BlockNumber::zero());}
+        assert!(StorageCertsRemovableOn::<T>::try_get(T::BlockNumber::zero()).is_err());
+    }: {Pallet::<T>::on_initialize(T::BlockNumber::zero());}
     do_remove_cert_noop {
-    }: {Pallet::<T, I>::do_remove_cert(100.into(), 101.into(), Some(T::BlockNumber::zero()));}
+    }: {Pallet::<T>::do_remove_cert(100.into(), 101.into(), Some(T::BlockNumber::zero()));}
     do_remove_cert {
         let issuer: T::IdtyIndex = 1.into();
         let receiver: T::IdtyIndex = 0.into();
-        Pallet::<T, I>::do_add_cert_checked(issuer, receiver, false)?;
-        let issuer_cert: u32 = StorageIdtyCertMeta::<T, I>::get(issuer).issued_count;
-        let receiver_cert: u32 = StorageIdtyCertMeta::<T, I>::get(receiver).received_count;
+        Pallet::<T>::do_add_cert_checked(issuer, receiver, false)?;
+        let issuer_cert: u32 = StorageIdtyCertMeta::<T>::get(issuer).issued_count;
+        let receiver_cert: u32 = StorageIdtyCertMeta::<T>::get(receiver).received_count;
         let block_number = T::ValidityPeriod::get();
         frame_system::pallet::Pallet::<T>::set_block_number(block_number);
-    }: {Pallet::<T, I>::do_remove_cert(issuer, receiver, Some(block_number));}
+    }: {Pallet::<T>::do_remove_cert(issuer, receiver, Some(block_number));}
     verify {
-        assert_has_event::<T, I>(Event::<T, I>::CertRemoved{ issuer,  receiver, expiration: true }.into());
+        assert_has_event::<T>(Event::<T>::CertRemoved{ issuer,  receiver, expiration: true }.into());
     }
 
     impl_benchmark_test_suite!(
diff --git a/pallets/certification/src/lib.rs b/pallets/certification/src/lib.rs
index fd60d814e7e8cef3591f1e174c434637267ec90e..aab81a26417bc6e1c7a4e4459537e121c840e140 100644
--- a/pallets/certification/src/lib.rs
+++ b/pallets/certification/src/lib.rs
@@ -53,10 +53,10 @@ pub mod pallet {
     #[pallet::pallet]
     #[pallet::storage_version(STORAGE_VERSION)]
     #[pallet::without_storage_info]
-    pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
+    pub struct Pallet<T>(PhantomData<T>);
 
     #[pallet::config]
-    pub trait Config<I: 'static = ()>: frame_system::Config {
+    pub trait Config: frame_system::Config {
         #[pallet::constant]
         /// Minimum duration between two certifications issued by the same issuer
         type CertPeriod: Get<Self::BlockNumber>;
@@ -86,8 +86,7 @@ pub mod pallet {
         /// Handler for Removed event
         type OnRemovedCert: OnRemovedCert<Self::IdtyIndex>;
         /// Because this pallet emits events, it depends on the runtime's definition of an event.
-        type RuntimeEvent: From<Event<Self, I>>
-            + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
         /// Type representing the weight of this pallet
         type WeightInfo: WeightInfo;
         #[pallet::constant]
@@ -99,14 +98,14 @@ pub mod pallet {
 
     #[pallet::genesis_config]
     #[allow(clippy::type_complexity)]
-    pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
+    pub struct GenesisConfig<T: Config> {
         pub apply_cert_period_at_genesis: bool,
         pub certs_by_receiver:
             BTreeMap<T::IdtyIndex, BTreeMap<T::IdtyIndex, Option<T::BlockNumber>>>,
     }
 
     #[cfg(feature = "std")]
-    impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> {
+    impl<T: Config> Default for GenesisConfig<T> {
         fn default() -> Self {
             Self {
                 apply_cert_period_at_genesis: false,
@@ -116,7 +115,7 @@ pub mod pallet {
     }
 
     #[pallet::genesis_build]
-    impl<T: Config<I>, I: 'static> GenesisBuild<T, I> for GenesisConfig<T, I> {
+    impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
         fn build(&self) {
             let mut cert_meta_by_issuer =
                 BTreeMap::<T::IdtyIndex, IdtyCertMeta<T::BlockNumber>>::new();
@@ -175,7 +174,7 @@ pub mod pallet {
 
                 // Write CertsByReceiver
                 issuers_.sort();
-                CertsByReceiver::<T, I>::insert(receiver, issuers_);
+                CertsByReceiver::<T>::insert(receiver, issuers_);
             }
 
             // Write StorageIdtyCertMeta
@@ -190,11 +189,11 @@ pub mod pallet {
                     "Identity n°{:?} not respect MinReceivedCertToBeAbleToIssueCert.",
                     issuer
                 );
-                StorageIdtyCertMeta::<T, I>::insert(issuer, cert_meta);
+                StorageIdtyCertMeta::<T>::insert(issuer, cert_meta);
             }
             // Write storage StorageCertsRemovableOn
             for (removable_on, certs) in certs_removable_on {
-                StorageCertsRemovableOn::<T, I>::insert(removable_on, certs);
+                StorageCertsRemovableOn::<T>::insert(removable_on, certs);
             }
         }
     }
@@ -204,26 +203,26 @@ pub mod pallet {
     /// Certifications metada by issuer
     #[pallet::storage]
     #[pallet::getter(fn idty_cert_meta)]
-    pub type StorageIdtyCertMeta<T: Config<I>, I: 'static = ()> =
+    pub type StorageIdtyCertMeta<T: Config> =
         StorageMap<_, Twox64Concat, T::IdtyIndex, IdtyCertMeta<T::BlockNumber>, ValueQuery>;
 
     /// Certifications by receiver
     #[pallet::storage]
     #[pallet::getter(fn certs_by_receiver)]
-    pub type CertsByReceiver<T: Config<I>, I: 'static = ()> =
+    pub type CertsByReceiver<T: Config> =
         StorageMap<_, Twox64Concat, T::IdtyIndex, Vec<(T::IdtyIndex, T::BlockNumber)>, ValueQuery>;
 
     /// Certifications removable on
     #[pallet::storage]
     #[pallet::getter(fn certs_removable_on)]
-    pub type StorageCertsRemovableOn<T: Config<I>, I: 'static = ()> =
+    pub type StorageCertsRemovableOn<T: Config> =
         StorageMap<_, Twox64Concat, T::BlockNumber, Vec<(T::IdtyIndex, T::IdtyIndex)>, OptionQuery>;
 
     // EVENTS //
 
     #[pallet::event]
     #[pallet::generate_deposit(pub(super) fn deposit_event)]
-    pub enum Event<T: Config<I>, I: 'static = ()> {
+    pub enum Event<T: Config> {
         /// A new certification was added.
         CertAdded {
             issuer: T::IdtyIndex,
@@ -245,7 +244,7 @@ pub mod pallet {
     // ERRORS //
 
     #[pallet::error]
-    pub enum Error<T, I = ()> {
+    pub enum Error<T> {
         /// Identity cannot certify itself
         CannotCertifySelf,
         /// Identity has already issued the maximum number of certifications
@@ -259,7 +258,7 @@ pub mod pallet {
     }
 
     #[pallet::hooks]
-    impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
+    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
         fn on_initialize(n: T::BlockNumber) -> Weight {
             Self::prune_certifications(n).saturating_add(T::WeightInfo::on_initialize())
         }
@@ -268,7 +267,7 @@ pub mod pallet {
     // CALLS //
 
     #[pallet::call]
-    impl<T: Config<I>, I: 'static> Pallet<T, I> {
+    impl<T: Config> Pallet<T> {
         /// Add a new certification or renew an existing one
         ///
         /// - `receiver`: the account receiving the certification from the origin
@@ -303,13 +302,13 @@ pub mod pallet {
 
         /// remove all certifications received by an identity (only root)
         #[pallet::call_index(2)]
-        #[pallet::weight(T::WeightInfo::remove_all_certs_received_by(CertsByReceiver::<T, I>::get(idty_index).len() as u32))]
+        #[pallet::weight(T::WeightInfo::remove_all_certs_received_by(CertsByReceiver::<T>::get(idty_index).len() as u32))]
         pub fn remove_all_certs_received_by(
             origin: OriginFor<T>,
             idty_index: T::IdtyIndex,
         ) -> DispatchResultWithPostInfo {
             ensure_root(origin)?;
-            for (issuer, _) in CertsByReceiver::<T, I>::get(idty_index) {
+            for (issuer, _) in CertsByReceiver::<T>::get(idty_index) {
                 Self::do_remove_cert(issuer, idty_index, None);
             }
             Ok(().into())
@@ -318,7 +317,7 @@ pub mod pallet {
 
     // INTERNAL FUNCTIONS //
 
-    impl<T: Config<I>, I: 'static> Pallet<T, I> {
+    impl<T: Config> Pallet<T> {
         /// add a certification without checks
         pub fn do_add_cert_checked(
             issuer: T::IdtyIndex,
@@ -326,29 +325,29 @@ pub mod pallet {
             verify_rules: bool,
         ) -> DispatchResultWithPostInfo {
             // Forbid self cert
-            ensure!(issuer != receiver, Error::<T, I>::CannotCertifySelf);
+            ensure!(issuer != receiver, Error::<T>::CannotCertifySelf);
 
             let block_number = frame_system::pallet::Pallet::<T>::block_number();
 
             if verify_rules {
                 // Verify rule MinReceivedCertToBeAbleToIssueCert
-                let issuer_idty_cert_meta = StorageIdtyCertMeta::<T, I>::get(issuer);
+                let issuer_idty_cert_meta = StorageIdtyCertMeta::<T>::get(issuer);
                 ensure!(
                     issuer_idty_cert_meta.received_count
                         >= T::MinReceivedCertToBeAbleToIssueCert::get(),
-                    Error::<T, I>::NotEnoughCertReceived
+                    Error::<T>::NotEnoughCertReceived
                 );
 
                 // Verify rule MaxByIssuer
                 ensure!(
                     issuer_idty_cert_meta.issued_count < T::MaxByIssuer::get(),
-                    Error::<T, I>::IssuedTooManyCert
+                    Error::<T>::IssuedTooManyCert
                 );
 
                 // Verify rule CertPeriod
                 ensure!(
                     block_number >= issuer_idty_cert_meta.next_issuable_on,
-                    Error::<T, I>::NotRespectCertPeriod
+                    Error::<T>::NotRespectCertPeriod
                 );
             };
 
@@ -362,11 +361,11 @@ pub mod pallet {
         ) -> DispatchResultWithPostInfo {
             // Write StorageCertsRemovableOn
             let removable_on = block_number + T::ValidityPeriod::get();
-            <StorageCertsRemovableOn<T, I>>::append(removable_on, (issuer, receiver));
+            <StorageCertsRemovableOn<T>>::append(removable_on, (issuer, receiver));
 
             // Write CertsByReceiver
             let mut created = false;
-            CertsByReceiver::<T, I>::mutate_exists(receiver, |maybe_issuers| {
+            CertsByReceiver::<T>::mutate_exists(receiver, |maybe_issuers| {
                 let issuers = maybe_issuers.get_or_insert(Vec::with_capacity(0));
                 match issuers.binary_search_by(|(issuer_, _)| issuer_.cmp(&issuer)) {
                     // cert exists, must be renewed
@@ -384,7 +383,7 @@ pub mod pallet {
             if created {
                 // Write StorageIdtyCertMeta for issuer
                 let issuer_issued_count =
-                    StorageIdtyCertMeta::<T, I>::mutate(issuer, |issuer_idty_cert_meta| {
+                    StorageIdtyCertMeta::<T>::mutate(issuer, |issuer_idty_cert_meta| {
                         issuer_idty_cert_meta.issued_count =
                             issuer_idty_cert_meta.issued_count.saturating_add(1);
                         issuer_idty_cert_meta.next_issuable_on =
@@ -394,7 +393,7 @@ pub mod pallet {
 
                 // Write StorageIdtyCertMeta for receiver
                 let receiver_received_count =
-                    <StorageIdtyCertMeta<T, I>>::mutate_exists(receiver, |cert_meta_opt| {
+                    <StorageIdtyCertMeta<T>>::mutate_exists(receiver, |cert_meta_opt| {
                         let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default());
                         cert_meta.received_count = cert_meta.received_count.saturating_add(1);
                         cert_meta.received_count
@@ -410,7 +409,7 @@ pub mod pallet {
                 );
             } else {
                 // Update next_issuable_on in StorageIdtyCertMeta for issuer
-                StorageIdtyCertMeta::<T, I>::mutate(issuer, |issuer_idty_cert_meta| {
+                StorageIdtyCertMeta::<T>::mutate(issuer, |issuer_idty_cert_meta| {
                     issuer_idty_cert_meta.next_issuable_on = block_number + T::CertPeriod::get();
                 });
                 // emit CertRenewed event
@@ -425,7 +424,7 @@ pub mod pallet {
             // See on initialize for the overhead weight accounting
             let mut total_weight = Weight::zero();
 
-            if let Some(certs) = StorageCertsRemovableOn::<T, I>::take(block_number) {
+            if let Some(certs) = StorageCertsRemovableOn::<T>::take(block_number) {
                 for (issuer, receiver) in certs {
                     total_weight += Self::do_remove_cert(issuer, receiver, Some(block_number));
                 }
@@ -442,7 +441,7 @@ pub mod pallet {
         ) -> Weight {
             let mut total_weight = Weight::zero();
             let mut removed = false;
-            CertsByReceiver::<T, I>::mutate_exists(receiver, |issuers_opt| {
+            CertsByReceiver::<T>::mutate_exists(receiver, |issuers_opt| {
                 let issuers = issuers_opt.get_or_insert(Vec::with_capacity(0));
                 if let Ok(index) = issuers.binary_search_by(|(issuer_, _)| issuer_.cmp(&issuer)) {
                     if let Some(block_number) = block_number_opt {
@@ -463,13 +462,13 @@ pub mod pallet {
             });
             if removed {
                 let issuer_issued_count =
-                    <StorageIdtyCertMeta<T, I>>::mutate_exists(issuer, |cert_meta_opt| {
+                    <StorageIdtyCertMeta<T>>::mutate_exists(issuer, |cert_meta_opt| {
                         let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default());
                         cert_meta.issued_count = cert_meta.issued_count.saturating_sub(1);
                         cert_meta.issued_count
                     });
                 let receiver_received_count =
-                    <StorageIdtyCertMeta<T, I>>::mutate_exists(receiver, |cert_meta_opt| {
+                    <StorageIdtyCertMeta<T>>::mutate_exists(receiver, |cert_meta_opt| {
                         let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default());
                         cert_meta.received_count = cert_meta.received_count.saturating_sub(1);
                         cert_meta.received_count
@@ -506,32 +505,32 @@ pub mod pallet {
         ) -> DispatchResult {
             // --- first internal checks
             // 1. Forbid self cert
-            ensure!(issuer != receiver, Error::<T, I>::CannotCertifySelf);
+            ensure!(issuer != receiver, Error::<T>::CannotCertifySelf);
 
             // 2. Verify caller ownership
             let issuer_owner_key =
-                T::OwnerKeyOf::convert(issuer).ok_or(Error::<T, I>::IssuerNotFound)?;
+                T::OwnerKeyOf::convert(issuer).ok_or(Error::<T>::IssuerNotFound)?;
             ensure!(issuer_owner_key == caller_key, DispatchError::BadOrigin);
 
             // 3. Verify rule MinReceivedCertToBeAbleToIssueCert
             // (this number can differ from the one necessary to be member)
-            let issuer_idty_cert_meta = <StorageIdtyCertMeta<T, I>>::get(issuer);
+            let issuer_idty_cert_meta = <StorageIdtyCertMeta<T>>::get(issuer);
             ensure!(
                 issuer_idty_cert_meta.received_count
                     >= T::MinReceivedCertToBeAbleToIssueCert::get(),
-                Error::<T, I>::NotEnoughCertReceived
+                Error::<T>::NotEnoughCertReceived
             );
 
             // 4. Verify rule MaxByIssuer
             ensure!(
                 issuer_idty_cert_meta.issued_count < T::MaxByIssuer::get(),
-                Error::<T, I>::IssuedTooManyCert
+                Error::<T>::IssuedTooManyCert
             );
 
             // 5. Verify rule CertPeriod
             ensure!(
                 block_number >= issuer_idty_cert_meta.next_issuable_on,
-                Error::<T, I>::NotRespectCertPeriod
+                Error::<T>::NotRespectCertPeriod
             );
 
             // --- then external checks
@@ -546,9 +545,9 @@ pub mod pallet {
 }
 
 // implement setting next_issuable_on for certification period
-impl<T: Config<I>, I: 'static> SetNextIssuableOn<T::BlockNumber, T::IdtyIndex> for Pallet<T, I> {
+impl<T: Config> SetNextIssuableOn<T::BlockNumber, T::IdtyIndex> for Pallet<T> {
     fn set_next_issuable_on(idty_index: T::IdtyIndex, next_issuable_on: T::BlockNumber) {
-        <StorageIdtyCertMeta<T, I>>::mutate_exists(idty_index, |cert_meta_opt| {
+        <StorageIdtyCertMeta<T>>::mutate_exists(idty_index, |cert_meta_opt| {
             let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default());
             cert_meta.next_issuable_on = next_issuable_on;
         });
diff --git a/pallets/certification/src/tests.rs b/pallets/certification/src/tests.rs
index cf09fa72de745ddf9eafd3eaa9718866b196cfcd..c1abd06b9df5ea8d9c16ea9cdbdde820f02e776e 100644
--- a/pallets/certification/src/tests.rs
+++ b/pallets/certification/src/tests.rs
@@ -29,7 +29,7 @@ fn test_must_receive_cert_before_can_issue() {
     .execute_with(|| {
         assert_eq!(
             DefaultCertification::add_cert(RuntimeOrigin::signed(0), 0, 1),
-            Err(Error::<Test, _>::NotEnoughCertReceived.into())
+            Err(Error::<Test>::NotEnoughCertReceived.into())
         );
     });
 }
@@ -50,7 +50,7 @@ fn test_cannot_certify_self() {
 
         assert_eq!(
             DefaultCertification::add_cert(RuntimeOrigin::signed(0), 0, 0),
-            Err(Error::<Test, _>::CannotCertifySelf.into())
+            Err(Error::<Test>::CannotCertifySelf.into())
         );
     });
 }
@@ -152,7 +152,7 @@ fn test_cert_period() {
         );
         assert_eq!(
             DefaultCertification::add_cert(RuntimeOrigin::signed(0), 0, 3),
-            Err(Error::<Test, _>::NotRespectCertPeriod.into())
+            Err(Error::<Test>::NotRespectCertPeriod.into())
         );
         run_to_block(CertPeriod::get());
         assert_ok!(DefaultCertification::add_cert(
@@ -163,7 +163,7 @@ fn test_cert_period() {
         run_to_block(CertPeriod::get() + 1);
         assert_eq!(
             DefaultCertification::add_cert(RuntimeOrigin::signed(0), 0, 4),
-            Err(Error::<Test, _>::NotRespectCertPeriod.into())
+            Err(Error::<Test>::NotRespectCertPeriod.into())
         );
         run_to_block((2 * CertPeriod::get()) + 1);
         assert_ok!(DefaultCertification::add_cert(
@@ -290,7 +290,7 @@ fn test_cert_renewal_cert_delay() {
         // try to renew again
         assert_noop!(
             DefaultCertification::add_cert(RuntimeOrigin::signed(1), 1, 0),
-            Error::<Test, _>::NotRespectCertPeriod,
+            Error::<Test>::NotRespectCertPeriod,
         );
         // no renewal event should be emitted
         assert_eq!(System::events().last(), None);
diff --git a/pallets/distance/src/mock.rs b/pallets/distance/src/mock.rs
index bcdbd095db31767691af200b13e0358a73ef8b2c..ef477a8c8fb954bf324b2b0936b092492ff05831 100644
--- a/pallets/distance/src/mock.rs
+++ b/pallets/distance/src/mock.rs
@@ -185,10 +185,11 @@ impl pallet_authority_members::Config for Test {
     type MemberId = u32;
     type MemberIdOf = IdentityIndexOf<Self>;
     type OnNewSession = ();
-    type OnRemovedMember = ();
     type RemoveMemberOrigin = system::EnsureRoot<AccountId>;
     type RuntimeEvent = RuntimeEvent;
     type WeightInfo = ();
+    type OnOutgoingMember = ();
+    type OnIncomingMember = ();
 }
 
 parameter_types! {
diff --git a/pallets/duniter-test-parameters/src/lib.rs b/pallets/duniter-test-parameters/src/lib.rs
index 0f75c3296a6272358c75333984b7f7bae308c24f..4da26974ba7202c4dce8476d415e965d54276878 100644
--- a/pallets/duniter-test-parameters/src/lib.rs
+++ b/pallets/duniter-test-parameters/src/lib.rs
@@ -35,6 +35,7 @@ pub mod types {
         BlockNumber: Default + Parameter,
         CertCount: Default + Parameter,
         PeriodCount: Default + Parameter,
+        SessionCount: Default + Parameter,
     > {
         pub babe_epoch_duration: PeriodCount,
         pub cert_period: BlockNumber,
@@ -47,14 +48,9 @@ pub mod types {
         pub pending_membership_period: BlockNumber,
         pub ud_creation_period: PeriodCount,
         pub ud_reeval_period: PeriodCount,
-        pub smith_cert_period: BlockNumber,
         pub smith_cert_max_by_issuer: CertCount,
-        pub smith_cert_min_received_cert_to_issue_cert: CertCount,
-        pub smith_cert_validity_period: BlockNumber,
-        pub smith_membership_period: BlockNumber,
-        pub smith_pending_membership_period: BlockNumber,
-        pub smith_wot_first_cert_issuable_on: BlockNumber,
         pub smith_wot_min_cert_for_membership: CertCount,
+        pub smith_inactivity_max_duration: SessionCount,
         pub wot_first_cert_issuable_on: BlockNumber,
         pub wot_min_cert_for_create_idty_right: CertCount,
         pub wot_min_cert_for_membership: CertCount,
@@ -81,20 +77,24 @@ pub mod pallet {
     pub trait Config: frame_system::Config {
         type CertCount: Default + MaybeSerializeDeserialize + Parameter;
         type PeriodCount: Default + MaybeSerializeDeserialize + Parameter;
+        type SessionCount: Default + MaybeSerializeDeserialize + Parameter;
     }
 
     // STORAGE //
 
     #[pallet::storage]
     #[pallet::getter(fn parameters)]
-    pub type ParametersStorage<T: Config> =
-        StorageValue<_, Parameters<T::BlockNumber, T::CertCount, T::PeriodCount>, ValueQuery>;
+    pub type ParametersStorage<T: Config> = StorageValue<
+        _,
+        Parameters<T::BlockNumber, T::CertCount, T::PeriodCount, T::SessionCount>,
+        ValueQuery,
+    >;
 
     // GENESIS
 
     #[pallet::genesis_config]
     pub struct GenesisConfig<T: Config> {
-        pub parameters: Parameters<T::BlockNumber, T::CertCount, T::PeriodCount>,
+        pub parameters: Parameters<T::BlockNumber, T::CertCount, T::PeriodCount, T::SessionCount>,
     }
 
     #[cfg(feature = "std")]
diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs
index 41ad8db138320591f987b6a4c00870164d03bd62..eb127c0cc0979c1064910b791c89d70df89f44b5 100644
--- a/pallets/duniter-wot/src/lib.rs
+++ b/pallets/duniter-wot/src/lib.rs
@@ -36,7 +36,6 @@ use frame_support::pallet_prelude::*;
 use pallet_certification::traits::SetNextIssuableOn;
 use pallet_identity::{IdtyEvent, IdtyStatus};
 use pallet_membership::MembershipRemovalReason;
-use sp_runtime::traits::IsMember;
 
 type IdtyIndex = u32;
 
@@ -51,24 +50,22 @@ pub mod pallet {
     #[pallet::pallet]
     #[pallet::storage_version(STORAGE_VERSION)]
     #[pallet::without_storage_info]
-    pub struct Pallet<T, I = ()>(_);
+    pub struct Pallet<T>(_);
 
     // CONFIG //
 
     #[pallet::config]
-    pub trait Config<I: 'static = ()>:
+    pub trait Config:
         frame_system::Config
-        + pallet_certification::Config<I, IdtyIndex = IdtyIndex>
+        + pallet_certification::Config<IdtyIndex = IdtyIndex>
         + pallet_identity::Config<IdtyIndex = IdtyIndex>
-        + pallet_membership::Config<I, IdtyId = IdtyIndex>
+        + pallet_membership::Config<IdtyId = IdtyIndex>
     {
         /// Distance evaluation provider
         type IsDistanceOk: IsDistanceOk<IdtyIndex>;
         #[pallet::constant]
         type FirstIssuableOn: Get<Self::BlockNumber>;
         #[pallet::constant]
-        type IsSubWot: Get<bool>;
-        #[pallet::constant]
         type MinCertForMembership: Get<u32>;
         #[pallet::constant]
         type MinCertForCreateIdtyRight: Get<u32>;
@@ -76,10 +73,10 @@ pub mod pallet {
 
     // INTERNAL FUNCTIONS //
 
-    impl<T: Config<I>, I: 'static> Pallet<T, I> {
+    impl<T: Config> Pallet<T> {
         pub(super) fn do_apply_first_issuable_on(idty_index: IdtyIndex) {
             let block_number = frame_system::pallet::Pallet::<T>::block_number();
-            pallet_certification::Pallet::<T, I>::set_next_issuable_on(
+            pallet_certification::Pallet::<T>::set_next_issuable_on(
                 idty_index,
                 block_number + T::FirstIssuableOn::get(),
             );
@@ -89,7 +86,7 @@ pub mod pallet {
     // ERRORS //
 
     #[pallet::error]
-    pub enum Error<T, I = ()> {
+    pub enum Error<T> {
         /// Insufficient certifications received to claim membership.
         NotEnoughCertsToClaimMembership,
         /// Distance is invalid.
@@ -126,61 +123,37 @@ pub mod pallet {
 }
 
 // implement identity call checks
-impl<AccountId, T: Config<I>, I: 'static> pallet_identity::traits::CheckIdtyCallAllowed<T>
-    for Pallet<T, I>
+impl<AccountId, T: Config> pallet_identity::traits::CheckIdtyCallAllowed<T> for Pallet<T>
 where
-    T: frame_system::Config<AccountId = AccountId> + pallet_membership::Config<I>,
+    T: frame_system::Config<AccountId = AccountId> + pallet_membership::Config,
 {
     // identity creation checks
     fn check_create_identity(creator: IdtyIndex) -> Result<(), DispatchError> {
-        // main WoT constraints
-        if !T::IsSubWot::get() {
-            let cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(creator);
-            // perform all checks
-            // 1. check that identity has the right to create an identity
-            // identity can be member with 5 certifications and still not reach identity creation threshold which could be higher (6, 7...)
-            ensure!(
-                cert_meta.received_count >= T::MinCertForCreateIdtyRight::get(),
-                Error::<T, I>::NotEnoughReceivedCertsToCreateIdty
-            );
-            // 2. check that issuer can emit one more certification
-            // (this is only a partial check)
-            ensure!(
-                cert_meta.issued_count < T::MaxByIssuer::get(),
-                Error::<T, I>::MaxEmittedCertsReached
-            );
-            // 3. check that issuer respects certification creation period
-            ensure!(
-                cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number(),
-                Error::<T, I>::IdtyCreationPeriodNotRespected
-            );
-        }
-        // TODO (#136) make these trait implementation work on instances rather than static to avoid checking IsSubWot
-        // smith subwot can never prevent from creating identity
-        Ok(())
-    }
-
-    // identity change owner key cheks
-    fn change_owner_key(idty_index: IdtyIndex) -> Result<(), DispatchError> {
-        // sub WoT prevents from changing identity
-        if T::IsSubWot::get() {
-            ensure!(
-                !pallet_membership::Pallet::<T, I>::is_member(&idty_index),
-                Error::<T, I>::NotAllowedToChangeIdtyAddress
-            );
-        }
-        // no constraints for main wot
+        let cert_meta = pallet_certification::Pallet::<T>::idty_cert_meta(creator);
+        // perform all checks
+        // 1. check that identity has the right to create an identity
+        // identity can be member with 5 certifications and still not reach identity creation threshold which could be higher (6, 7...)
+        ensure!(
+            cert_meta.received_count >= T::MinCertForCreateIdtyRight::get(),
+            Error::<T>::NotEnoughReceivedCertsToCreateIdty
+        );
+        // 2. check that issuer can emit one more certification
+        // (this is only a partial check)
+        ensure!(
+            cert_meta.issued_count < T::MaxByIssuer::get(),
+            Error::<T>::MaxEmittedCertsReached
+        );
+        // 3. check that issuer respects certification creation period
+        ensure!(
+            cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number(),
+            Error::<T>::IdtyCreationPeriodNotRespected
+        );
         Ok(())
     }
 }
 
 // implement cert call checks
-impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<IdtyIndex>
-    for Pallet<T, I>
-// TODO (#136) add the following where clause once checks can be done on pallet instance
-// where
-//     T: pallet_membership::Config<I>,
-{
+impl<T: Config> pallet_certification::traits::CheckCertAllowed<IdtyIndex> for Pallet<T> {
     // check the following:
     // - issuer has identity
     // - issuer identity is member
@@ -192,10 +165,10 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<Id
         if let Some(issuer_data) = pallet_identity::Pallet::<T>::identity(issuer) {
             ensure!(
                 issuer_data.status == IdtyStatus::Member,
-                Error::<T, I>::IssuerNotMember
+                Error::<T>::IssuerNotMember
             );
         } else {
-            return Err(Error::<T, I>::IdtyNotFound.into());
+            return Err(Error::<T>::IdtyNotFound.into());
         }
 
         // receiver checks
@@ -204,26 +177,24 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<Id
             match receiver_data.status {
                 // able to receive cert
                 IdtyStatus::Unvalidated | IdtyStatus::Member | IdtyStatus::NotMember => {}
-                IdtyStatus::Unconfirmed => return Err(Error::<T, I>::CertToUnconfirmed.into()),
-                IdtyStatus::Revoked => return Err(Error::<T, I>::CertToRevoked.into()),
+                IdtyStatus::Unconfirmed => return Err(Error::<T>::CertToUnconfirmed.into()),
+                IdtyStatus::Revoked => return Err(Error::<T>::CertToRevoked.into()),
             };
         } else {
-            return Err(Error::<T, I>::IdtyNotFound.into());
+            return Err(Error::<T>::IdtyNotFound.into());
         }
         Ok(())
     }
 }
 
 // implement membership call checks
-impl<T: Config<I>, I: 'static> sp_membership::traits::CheckMembershipCallAllowed<IdtyIndex>
-    for Pallet<T, I>
-{
+impl<T: Config> sp_membership::traits::CheckMembershipCallAllowed<IdtyIndex> for Pallet<T> {
     // membership claim is only possible when enough certs are received (both wots) and distance is ok
     fn check_idty_allowed_to_claim_membership(idty_index: &IdtyIndex) -> Result<(), DispatchError> {
-        let idty_cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index);
+        let idty_cert_meta = pallet_certification::Pallet::<T>::idty_cert_meta(idty_index);
         ensure!(
             idty_cert_meta.received_count >= T::MinCertForMembership::get(),
-            Error::<T, I>::NotEnoughCertsToClaimMembership
+            Error::<T>::NotEnoughCertsToClaimMembership
         );
         T::IsDistanceOk::is_distance_ok(idty_index)?;
         Ok(())
@@ -234,35 +205,31 @@ impl<T: Config<I>, I: 'static> sp_membership::traits::CheckMembershipCallAllowed
         if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
             ensure!(
                 idty_value.status == IdtyStatus::Member,
-                Error::<T, I>::IdtyNotAllowedToRenewMembership
+                Error::<T>::IdtyNotAllowedToRenewMembership
             );
             T::IsDistanceOk::is_distance_ok(idty_index)?;
         } else {
-            return Err(Error::<T, I>::IdtyNotFound.into());
+            return Err(Error::<T>::IdtyNotFound.into());
         }
         Ok(())
     }
 }
 
 // implement membership event handler
-impl<T: Config<I>, I: 'static> sp_membership::traits::OnEvent<IdtyIndex> for Pallet<T, I>
+impl<T: Config> sp_membership::traits::OnEvent<IdtyIndex> for Pallet<T>
 where
-    T: pallet_membership::Config<I>,
+    T: pallet_membership::Config,
 {
     fn on_event(membership_event: &sp_membership::Event<IdtyIndex>) {
         match membership_event {
             sp_membership::Event::<IdtyIndex>::MembershipAdded(idty_index) => {
-                if !T::IsSubWot::get() {
-                    // when main membership is acquired, tell identity
-                    // (only used on first membership acquiry)
-                    pallet_identity::Pallet::<T>::membership_added(*idty_index);
-                }
+                // when main membership is acquired, tell identity
+                // (only used on first membership acquiry)
+                pallet_identity::Pallet::<T>::membership_added(*idty_index);
             }
             sp_membership::Event::<IdtyIndex>::MembershipRemoved(idty_index) => {
-                if !T::IsSubWot::get() {
-                    // when main membership is lost, tell identity
-                    pallet_identity::Pallet::<T>::membership_removed(*idty_index);
-                }
+                // when main membership is lost, tell identity
+                pallet_identity::Pallet::<T>::membership_removed(*idty_index);
             }
             sp_membership::Event::<IdtyIndex>::MembershipRenewed(_) => {}
         }
@@ -270,12 +237,12 @@ where
 }
 
 // implement identity event handler
-impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pallet<T, I> {
+impl<T: Config> pallet_identity::traits::OnIdtyChange<T> for Pallet<T> {
     fn on_idty_change(idty_index: IdtyIndex, idty_event: &IdtyEvent<T>) {
         match idty_event {
             // identity just has been created, a cert must be added
             IdtyEvent::Created { creator, .. } => {
-                if let Err(e) = <pallet_certification::Pallet<T, I>>::do_add_cert_checked(
+                if let Err(e) = <pallet_certification::Pallet<T>>::do_add_cert_checked(
                     *creator, idty_index, true,
                 ) {
                     sp_std::if_std! {
@@ -288,7 +255,7 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall
             // if identity is removed also remove certs
             IdtyEvent::Removed { status } => {
                 // try remove membership in any case
-                <pallet_membership::Pallet<T, I>>::do_remove_membership(
+                <pallet_membership::Pallet<T>>::do_remove_membership(
                     idty_index,
                     MembershipRemovalReason::Revoked,
                 );
@@ -297,7 +264,7 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall
                 match status {
                     IdtyStatus::Unconfirmed | IdtyStatus::Unvalidated => {
                         if let Err(e) =
-                            <pallet_certification::Pallet<T, I>>::remove_all_certs_received_by(
+                            <pallet_certification::Pallet<T>>::remove_all_certs_received_by(
                                 frame_system::Origin::<T>::Root.into(),
                                 idty_index,
                             )
@@ -321,7 +288,7 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall
 
 // implement certification event handlers
 // new cert handler
-impl<T: Config<I>, I: 'static> pallet_certification::traits::OnNewcert<IdtyIndex> for Pallet<T, I> {
+impl<T: Config> pallet_certification::traits::OnNewcert<IdtyIndex> for Pallet<T> {
     fn on_new_cert(
         _issuer: IdtyIndex,
         _issuer_issued_count: u32,
@@ -335,9 +302,7 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnNewcert<IdtyIndex
 }
 
 // remove cert handler
-impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyIndex>
-    for Pallet<T, I>
-{
+impl<T: Config> pallet_certification::traits::OnRemovedCert<IdtyIndex> for Pallet<T> {
     fn on_removed_cert(
         _issuer: IdtyIndex,
         _issuer_issued_count: u32,
@@ -346,10 +311,10 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyI
         _expiration: bool,
     ) {
         if receiver_received_count < T::MinCertForMembership::get()
-            && pallet_membership::Pallet::<T, I>::is_member(&receiver)
+            && pallet_membership::Pallet::<T>::is_member(&receiver)
         {
             // expire receiver membership
-            <pallet_membership::Pallet<T, I>>::do_remove_membership(
+            <pallet_membership::Pallet<T>>::do_remove_membership(
                 receiver,
                 MembershipRemovalReason::NotEnoughCerts,
             )
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
index 268a6bf01a9805254cdf1d0c70ee90cafc8a668a..c043ef76448f72bcf18013fd168b8d9c232c1bee 100644
--- a/pallets/duniter-wot/src/mock.rs
+++ b/pallets/duniter-wot/src/mock.rs
@@ -46,13 +46,10 @@ frame_support::construct_runtime!(
         UncheckedExtrinsic = UncheckedExtrinsic,
     {
         System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
-        DuniterWot: pallet_duniter_wot::<Instance1>::{Pallet},
+        DuniterWot: pallet_duniter_wot::{Pallet},
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>},
-        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>},
-        Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>},
-        SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet},
-        SmithMembership: pallet_membership::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>},
-        SmithCert: pallet_certification::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>},
+        Membership: pallet_membership::{Pallet, Call, Config<T>, Storage, Event<T>},
+        Cert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>},
     }
 );
 
@@ -96,8 +93,7 @@ parameter_types! {
     pub const FirstIssuableOn: u64 = 2;
 }
 
-impl pallet_duniter_wot::Config<Instance1> for Test {
-    type IsSubWot = frame_support::traits::ConstBool<false>;
+impl pallet_duniter_wot::Config for Test {
     type MinCertForMembership = MinCertForMembership;
     type MinCertForCreateIdtyRight = MinCertForCreateIdtyRight;
     type FirstIssuableOn = FirstIssuableOn;
@@ -124,7 +120,7 @@ impl pallet_identity::traits::IdtyNameValidator for IdtyNameValidatorTestImpl {
 impl pallet_identity::Config for Test {
     type ChangeOwnerKeyPeriod = ChangeOwnerKeyPeriod;
     type ConfirmPeriod = ConfirmPeriod;
-    type CheckIdtyCallAllowed = (DuniterWot, SmithSubWot);
+    type CheckIdtyCallAllowed = DuniterWot;
     type IdtyCreationPeriod = IdtyCreationPeriod;
     type ValidationPeriod = ValidationPeriod;
     type AutorevocationPeriod = AutorevocationPeriod;
@@ -135,7 +131,7 @@ impl pallet_identity::Config for Test {
     type AccountLinker = ();
     type Signer = UintAuthorityId;
     type Signature = TestSignature;
-    type OnIdtyChange = (DuniterWot, SmithSubWot);
+    type OnIdtyChange = DuniterWot;
     type RuntimeEvent = RuntimeEvent;
     type WeightInfo = ();
 }
@@ -145,7 +141,7 @@ parameter_types! {
     pub const MembershipPeriod: u64 = 8;
 }
 
-impl pallet_membership::Config<Instance1> for Test {
+impl pallet_membership::Config for Test {
     type CheckMembershipCallAllowed = DuniterWot;
     type IdtyId = IdtyIndex;
     type IdtyIdOf = IdentityIndexOf<Self>;
@@ -166,7 +162,7 @@ parameter_types! {
     pub const ValidityPeriod: u64 = 20;
 }
 
-impl pallet_certification::Config<Instance1> for Test {
+impl pallet_certification::Config for Test {
     type CertPeriod = CertPeriod;
     type IdtyIndex = IdtyIndex;
     type OwnerKeyOf = Identity;
@@ -180,68 +176,10 @@ impl pallet_certification::Config<Instance1> for Test {
     type ValidityPeriod = ValidityPeriod;
 }
 
-// SMITHS SUB-WOT //
-
-parameter_types! {
-    pub const SmithMinCertForMembership: u32 = 2;
-    pub const SmithFirstIssuableOn: u64 = 2;
-}
-
-impl pallet_duniter_wot::Config<Instance2> for Test {
-    type IsSubWot = frame_support::traits::ConstBool<true>;
-    type MinCertForMembership = SmithMinCertForMembership;
-    type MinCertForCreateIdtyRight = frame_support::traits::ConstU32<0>;
-    type FirstIssuableOn = SmithFirstIssuableOn;
-    type IsDistanceOk = crate::traits::DistanceAlwaysOk;
-}
-
-// SmithMembership
-parameter_types! {
-    pub const SmithMembershipPeriod: u64 = 20;
-}
-
-impl pallet_membership::Config<Instance2> for Test {
-    type CheckMembershipCallAllowed = SmithSubWot;
-    type IdtyId = IdtyIndex;
-    type IdtyIdOf = IdentityIndexOf<Self>;
-    type AccountIdOf = ();
-    type MembershipPeriod = SmithMembershipPeriod;
-    type OnEvent = SmithSubWot;
-    type WeightInfo = ();
-    type RuntimeEvent = RuntimeEvent;
-    #[cfg(feature = "runtime-benchmarks")]
-    type BenchmarkSetupHandler = ();
-}
-
-// SmithCert
-parameter_types! {
-    pub const SmithMaxByIssuer: u8 = 8;
-    pub const SmithMinReceivedCertToBeAbleToIssueCert: u32 = 2;
-    pub const SmithCertPeriod: u64 = 2;
-    pub const SmithValidityPeriod: u64 = 10;
-}
-
-impl pallet_certification::Config<Instance2> for Test {
-    type CertPeriod = SmithCertPeriod;
-    type IdtyIndex = IdtyIndex;
-    type OwnerKeyOf = Identity;
-    type CheckCertAllowed = SmithSubWot;
-    type MaxByIssuer = SmithMaxByIssuer;
-    type MinReceivedCertToBeAbleToIssueCert = SmithMinReceivedCertToBeAbleToIssueCert;
-    type OnNewcert = SmithSubWot;
-    type OnRemovedCert = SmithSubWot;
-    type RuntimeEvent = RuntimeEvent;
-    type WeightInfo = ();
-    type ValidityPeriod = SmithValidityPeriod;
-}
-
 pub const NAMES: [&str; 6] = ["Alice", "Bob", "Charlie", "Dave", "Eve", "Ferdie"];
 
 // Build genesis storage according to the mock runtime.
-pub fn new_test_ext(
-    initial_identities_len: usize,
-    initial_smiths_len: usize,
-) -> sp_io::TestExternalities {
+pub fn new_test_ext(initial_identities_len: usize) -> sp_io::TestExternalities {
     let mut t = frame_system::GenesisConfig::default()
         .build_storage::<Test>()
         .unwrap();
@@ -265,7 +203,7 @@ pub fn new_test_ext(
     .assimilate_storage(&mut t)
     .unwrap();
 
-    pallet_membership::GenesisConfig::<Test, Instance1> {
+    pallet_membership::GenesisConfig::<Test> {
         memberships: (1..=initial_identities_len)
             .map(|i| {
                 (
@@ -280,35 +218,13 @@ pub fn new_test_ext(
     .assimilate_storage(&mut t)
     .unwrap();
 
-    pallet_certification::GenesisConfig::<Test, Instance1> {
+    pallet_certification::GenesisConfig::<Test> {
         apply_cert_period_at_genesis: true,
         certs_by_receiver: clique_wot(initial_identities_len, ValidityPeriod::get()),
     }
     .assimilate_storage(&mut t)
     .unwrap();
 
-    pallet_membership::GenesisConfig::<Test, Instance2> {
-        memberships: (1..=initial_smiths_len)
-            .map(|i| {
-                (
-                    i as u32,
-                    sp_membership::MembershipData {
-                        expire_on: SmithMembershipPeriod::get(),
-                    },
-                )
-            })
-            .collect(),
-    }
-    .assimilate_storage(&mut t)
-    .unwrap();
-
-    pallet_certification::GenesisConfig::<Test, Instance2> {
-        apply_cert_period_at_genesis: true,
-        certs_by_receiver: clique_wot(initial_smiths_len, SmithValidityPeriod::get()),
-    }
-    .assimilate_storage(&mut t)
-    .unwrap();
-
     frame_support::BasicExternalities::execute_with_storage(&mut t, || {
         // manually increment genesis identities sufficient counter
         // In real world, this is done by pallet-identity
@@ -330,9 +246,6 @@ pub fn run_to_block(n: u64) {
         Identity::on_finalize(System::block_number());
         Membership::on_finalize(System::block_number());
         Cert::on_finalize(System::block_number());
-        SmithSubWot::on_finalize(System::block_number());
-        SmithMembership::on_finalize(System::block_number());
-        SmithCert::on_finalize(System::block_number());
         System::on_finalize(System::block_number());
         // reset events and change block number
         System::reset_events();
@@ -343,9 +256,6 @@ pub fn run_to_block(n: u64) {
         Identity::on_initialize(System::block_number());
         Membership::on_initialize(System::block_number());
         Cert::on_initialize(System::block_number());
-        SmithSubWot::on_initialize(System::block_number());
-        SmithMembership::on_initialize(System::block_number());
-        SmithCert::on_initialize(System::block_number());
     }
 }
 
diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs
index 3645f1979fca7d946fbddf0b408c7361467d9f3e..2b86ee97f6dd1258126a035a3ca166a95b13eb69 100644
--- a/pallets/duniter-wot/src/tests.rs
+++ b/pallets/duniter-wot/src/tests.rs
@@ -17,11 +17,9 @@
 use crate::mock::*;
 use crate::pallet as pallet_duniter_wot;
 use codec::Encode;
-use frame_support::instances::{Instance1, Instance2};
 use frame_support::{assert_noop, assert_ok};
 use pallet_identity::{
-    IdtyIndexAccountIdPayload, IdtyName, IdtyStatus, RevocationPayload, RevocationReason,
-    NEW_OWNER_KEY_PAYLOAD_PREFIX, REVOCATION_PAYLOAD_PREFIX,
+    IdtyName, IdtyStatus, RevocationPayload, RevocationReason, REVOCATION_PAYLOAD_PREFIX,
 };
 use pallet_membership::MembershipRemovalReason;
 use sp_runtime::testing::TestSignature;
@@ -30,13 +28,13 @@ use sp_runtime::testing::TestSignature;
 /// and good identity and certification metadate
 #[test]
 fn test_genesis_build() {
-    new_test_ext(3, 2).execute_with(|| {
+    new_test_ext(3).execute_with(|| {
         run_to_block(1);
         // Verify state
         assert_eq!(Identity::identities_count(), 3);
         assert_eq!(Identity::identity(1).unwrap().next_creatable_identity_on, 0);
         assert_eq!(
-            pallet_certification::Pallet::<Test, Instance1>::idty_cert_meta(1).next_issuable_on,
+            pallet_certification::Pallet::<Test>::idty_cert_meta(1).next_issuable_on,
             2
         );
     });
@@ -45,7 +43,7 @@ fn test_genesis_build() {
 /// test that Alice is not able to create an identity when she received too few certs (2 of 4)
 #[test]
 fn test_creator_not_allowed_to_create_idty() {
-    new_test_ext(3, 2).execute_with(|| {
+    new_test_ext(3).execute_with(|| {
         run_to_block(1);
 
         // Alice did not receive enough certs
@@ -53,7 +51,7 @@ fn test_creator_not_allowed_to_create_idty() {
         // because Alice.next_issuable_on = 2)
         assert_noop!(
             Identity::create_identity(RuntimeOrigin::signed(1), 4),
-            pallet_duniter_wot::Error::<Test, Instance1>::NotEnoughReceivedCertsToCreateIdty
+            pallet_duniter_wot::Error::<Test>::NotEnoughReceivedCertsToCreateIdty
         );
     });
 }
@@ -61,123 +59,21 @@ fn test_creator_not_allowed_to_create_idty() {
 /// test that Alice is able to create an identity when she received enough certs (4)
 #[test]
 fn test_creator_allowed_to_create_idty() {
-    new_test_ext(5, 2).execute_with(|| {
+    new_test_ext(5).execute_with(|| {
         run_to_block(2);
 
         // Alice should be able to create an identity
         assert_ok!(
             Identity::create_identity(RuntimeOrigin::signed(1), 6),
-            // pallet_duniter_wot::Error::<Test, Instance1>::NotEnoughReceivedCertsToCreateIdty
+            // pallet_duniter_wot::Error::<Test>::NotEnoughReceivedCertsToCreateIdty
         );
     });
 }
 
-/// test smith joining workflow
-#[test]
-fn test_join_smiths() {
-    new_test_ext(5, 3).execute_with(|| {
-        run_to_block(2);
-
-        // Alice should be able to send a smith cert to Dave
-        run_to_block(3);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 4));
-
-        // Bob should be able to send a smith cert to Dave
-        run_to_block(4);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 4));
-
-        // Dave should be able to claim his membership
-        run_to_block(4);
-        assert_ok!(SmithMembership::claim_membership(RuntimeOrigin::signed(4),));
-        System::assert_has_event(RuntimeEvent::SmithMembership(
-            pallet_membership::Event::MembershipAdded {
-                member: 4,
-                expire_on: 4
-                    + <Test as pallet_membership::Config<Instance2>>::MembershipPeriod::get(),
-            },
-        ));
-    });
-}
-
-/// test smith membership expiry after cert expiration
-#[test]
-fn test_smith_certs_expirations_should_expire_smith_membership() {
-    new_test_ext(5, 3).execute_with(|| {
-        // After block #10, alice membership should be revoked due to smith certs expiration
-        run_to_block(10);
-        System::assert_has_event(RuntimeEvent::SmithMembership(
-            pallet_membership::Event::MembershipRemoved {
-                member: 1,
-                reason: MembershipRemovalReason::NotEnoughCerts,
-            },
-        ));
-    });
-}
-
-/// test that smith can not change owner key
-#[test]
-fn test_smith_member_cant_change_its_idty_address() {
-    new_test_ext(5, 3).execute_with(|| {
-        run_to_block(2);
-
-        let genesis_hash = System::block_hash(0);
-        let new_key_payload = IdtyIndexAccountIdPayload {
-            genesis_hash: &genesis_hash,
-            idty_index: 3u32,
-            old_owner_key: &3u64,
-        };
-
-        // Identity 3 can't change it's address
-        assert_noop!(
-            Identity::change_owner_key(
-                RuntimeOrigin::signed(3),
-                13,
-                TestSignature(13, (NEW_OWNER_KEY_PAYLOAD_PREFIX, new_key_payload).encode())
-            ),
-            pallet_duniter_wot::Error::<Test, Instance2>::NotAllowedToChangeIdtyAddress
-        );
-    });
-}
-
-/// members of the smith subwot can revoke their identity
-#[test]
-fn test_smith_member_can_revoke_its_idty() {
-    new_test_ext(5, 3).execute_with(|| {
-        run_to_block(2);
-
-        let revocation_payload = RevocationPayload {
-            idty_index: 3u32,
-            genesis_hash: System::block_hash(0),
-        };
-
-        // Identity 3 can't change it's address
-        assert_ok!(Identity::revoke_identity(
-            RuntimeOrigin::signed(3),
-            3,
-            3,
-            TestSignature(3, (REVOCATION_PAYLOAD_PREFIX, revocation_payload).encode())
-        ));
-        // membership should be removed
-        System::assert_has_event(RuntimeEvent::Membership(
-            pallet_membership::Event::MembershipRemoved {
-                member: 3,
-                reason: pallet_membership::MembershipRemovalReason::Revoked,
-            },
-        ));
-        // smith membership should be removed as well
-        System::assert_has_event(RuntimeEvent::SmithMembership(
-            pallet_membership::Event::MembershipRemoved {
-                member: 3,
-                reason: pallet_membership::MembershipRemovalReason::Revoked,
-            },
-        ));
-    });
-}
-
 /// test identity creation and that a first cert is emitted
 #[test]
 fn test_create_idty_ok() {
-    new_test_ext(5, 2).execute_with(|| {
+    new_test_ext(5).execute_with(|| {
         run_to_block(2);
 
         // Alice should be able to create an identity at block #2
@@ -205,7 +101,7 @@ fn test_create_idty_ok() {
 /// test identity validation
 #[test]
 fn test_new_idty_validation() {
-    new_test_ext(5, 2).execute_with(|| {
+    new_test_ext(5).execute_with(|| {
         // Alice creates Ferdie identity
         run_to_block(2);
         assert_ok!(Identity::create_identity(RuntimeOrigin::signed(1), 6));
@@ -231,8 +127,7 @@ fn test_new_idty_validation() {
         System::assert_has_event(RuntimeEvent::Membership(
             pallet_membership::Event::MembershipAdded {
                 member: 6,
-                expire_on: 5
-                    + <Test as pallet_membership::Config<Instance1>>::MembershipPeriod::get(),
+                expire_on: 5 + <Test as pallet_membership::Config>::MembershipPeriod::get(),
             },
         ));
         System::assert_has_event(RuntimeEvent::Identity(
@@ -258,7 +153,7 @@ fn test_new_idty_validation() {
 /// test that Ferdie can confirm an identity created for him by Alice
 #[test]
 fn test_confirm_idty_ok() {
-    new_test_ext(5, 2).execute_with(|| {
+    new_test_ext(5).execute_with(|| {
         run_to_block(2);
 
         // Alice creates Ferdie identity
@@ -282,11 +177,10 @@ fn test_confirm_idty_ok() {
 }
 
 /// test identity revocation
-/// - a smith ca not revoke his identity
 /// - anyone can submit a revocation certificate signed by bob
 #[test]
 fn test_revoke_idty() {
-    new_test_ext(5, 1).execute_with(|| {
+    new_test_ext(5).execute_with(|| {
         run_to_block(2);
 
         // Alice identity can be revoked
@@ -313,13 +207,6 @@ fn test_revoke_idty() {
                 reason: pallet_membership::MembershipRemovalReason::Revoked,
             },
         ));
-        // and her smith membership should be removed as well
-        System::assert_has_event(RuntimeEvent::SmithMembership(
-            pallet_membership::Event::MembershipRemoved {
-                member: 1,
-                reason: pallet_membership::MembershipRemovalReason::Revoked,
-            },
-        ));
 
         // Anyone should be able to submit Bob revocation certificate
         assert_ok!(Identity::revoke_identity(
@@ -351,7 +238,7 @@ fn test_revoke_idty() {
 /// test that expired membership lose the identity after a delay
 #[test]
 fn test_idty_membership_expire() {
-    new_test_ext(3, 2).execute_with(|| {
+    new_test_ext(3).execute_with(|| {
         run_to_block(4);
 
         // Alice renews her membership
@@ -411,7 +298,7 @@ fn test_idty_membership_expire() {
         // Alice can't certify revoked identity
         assert_noop!(
             Cert::add_cert(RuntimeOrigin::signed(1), 1, 3),
-            pallet_duniter_wot::Error::<Test, Instance1>::CertToRevoked
+            pallet_duniter_wot::Error::<Test>::CertToRevoked
         );
 
         run_to_block(21);
@@ -424,7 +311,7 @@ fn test_idty_membership_expire() {
         // Alice can't certify removed identity
         assert_noop!(
             Cert::add_cert(RuntimeOrigin::signed(1), 1, 3),
-            pallet_duniter_wot::Error::<Test, Instance1>::IdtyNotFound
+            pallet_duniter_wot::Error::<Test>::IdtyNotFound
         );
     });
 }
@@ -432,7 +319,7 @@ fn test_idty_membership_expire() {
 /// when an identity is confirmed and not validated, the certification received should be removed
 #[test]
 fn test_unvalidated_idty_certs_removal() {
-    new_test_ext(5, 2).execute_with(|| {
+    new_test_ext(5).execute_with(|| {
         // Alice creates Ferdie identity
         run_to_block(2);
         assert_ok!(Identity::create_identity(RuntimeOrigin::signed(1), 6));
@@ -455,50 +342,24 @@ fn test_unvalidated_idty_certs_removal() {
 /// test what happens when certification expire
 #[test]
 fn test_certification_expire() {
-    new_test_ext(3, 3).execute_with(|| {
+    new_test_ext(3).execute_with(|| {
         // smith cert Bob → Alice not renewed
         // cert Bob → Alice not renewed
         // --- BLOCK 2 ---
         run_to_block(2);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 2));
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 3));
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 1));
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(1), 1, 2));
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(2), 2, 3));
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 1));
         // --- BLOCK 4 ---
         run_to_block(4);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 3));
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 2));
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(1), 1, 3));
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 2));
         // --- BLOCK 7 ---
         run_to_block(7);
-        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(1)));
-        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(2)));
-        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(3)));
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1)));
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2)));
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(3)));
 
-        // smith cert Bob → Alice expires at block 10
-        run_to_block(10);
-        // println!("{:?}", System::events());
-        System::assert_has_event(RuntimeEvent::SmithCert(
-            pallet_certification::Event::CertRemoved {
-                issuer: 2,   // Bob
-                receiver: 1, // Alice
-                expiration: true,
-            },
-        ));
-        // in consequence, since Alice has only 1/2 smith certification remaining, she looses smith membership
-        System::assert_has_event(RuntimeEvent::SmithMembership(
-            pallet_membership::Event::MembershipRemoved {
-                member: 1,
-                reason: MembershipRemovalReason::NotEnoughCerts,
-            },
-        ));
-
         // --- BLOCK 14 ---
         run_to_block(14);
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1)));
@@ -532,13 +393,13 @@ fn test_certification_expire() {
         // Alice can not renew her membership which does not exist
         assert_noop!(
             Membership::renew_membership(RuntimeOrigin::signed(1)),
-            pallet_membership::Error::<Test, Instance1>::MembershipNotFound
+            pallet_membership::Error::<Test>::MembershipNotFound
         );
 
         // Alice can not claim her membership because she does not have enough certifications
         assert_noop!(
             Membership::claim_membership(RuntimeOrigin::signed(1)),
-            pallet_duniter_wot::Error::<Test, Instance1>::NotEnoughCertsToClaimMembership
+            pallet_duniter_wot::Error::<Test>::NotEnoughCertsToClaimMembership
         );
 
         // --- BLOCK 23 ---
@@ -559,78 +420,27 @@ fn test_certification_expire() {
 // - when source or target membership is pending (both wot)
 #[test]
 fn test_cert_can_not_be_issued() {
-    new_test_ext(4, 3).execute_with(|| {
+    new_test_ext(4).execute_with(|| {
         // smith cert Bob → Alice not renewed
         // cert Bob → Alice not renewed
         // --- BLOCK 2 ---
         run_to_block(2);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 2)); // +10
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 3)); // +10
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 1)); // +10
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(1), 1, 2)); // +20
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(2), 2, 3)); // +20
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 4)); // +20
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(4), 4, 1)); // +20
                                                                     // --- BLOCK 4 ---
         run_to_block(4);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 3)); // +10
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 2)); // +10
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(2), 2, 4)); // +20
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 2)); // +20
         assert_ok!(Cert::add_cert(RuntimeOrigin::signed(4), 4, 3)); // +20
                                                                     // --- BLOCK 7 ---
         run_to_block(7);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 1)); // +10
-        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(1))); // +20
-        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(2))); // +20
-        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(3))); // +20
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); // + 8
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); // + 8
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(3))); // + 8
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(4))); // + 8
 
-        // smith cert Bob → Alice expires at block 10
-        run_to_block(10);
-        // println!("{:?}", System::events());
-        System::assert_has_event(RuntimeEvent::SmithCert(
-            pallet_certification::Event::CertRemoved {
-                issuer: 2,   // Bob
-                receiver: 1, // Alice
-                expiration: true,
-            },
-        ));
-        // in consequence, since Alice has only 1/2 smith certification remaining, she looses smith membership
-        System::assert_has_event(RuntimeEvent::SmithMembership(
-            pallet_membership::Event::MembershipRemoved {
-                member: 1,
-                reason: MembershipRemovalReason::NotEnoughCerts,
-            },
-        ));
-
-        run_to_block(11);
-        // Dave should be able to receive a smith cert since
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 4));
-        // Bob renews his smith certification towards Alice
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 1));
-        // now Alice has enough certs
-        assert_eq!(
-            SmithCert::idty_cert_meta(1),
-            pallet_certification::IdtyCertMeta {
-                issued_count: 2, // → Bob, → Charlie
-                // since Alice got back to min number of received certs to be able to issue cert
-                // her next_issuable_on was updated to block_number (11) + cert_period (2)
-                next_issuable_on: 13, // 11 + 2
-                received_count: 2     // ← Bob, ← Charlie
-            }
-        );
-
-        // because Alice did not claim membership, she is not member at this point
-        assert_eq!(SmithMembership::membership(1), None);
-        run_to_block(13);
-        // /!\ COUNTERINTUITIVE BEHAVIOR
-        // Alice is not smith member, she should not be able to issue cert
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 2));
-
         run_to_block(14);
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); // + 8
         assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); // + 8
@@ -669,54 +479,3 @@ fn test_cert_can_not_be_issued() {
         // she would have been able to emit a cert without being member
     })
 }
-
-/// test non smith identity can not emit smith cert
-#[test]
-fn test_non_smith_can_not_issue_smith_cert() {
-    new_test_ext(4, 3).execute_with(|| {
-        assert_noop!(
-            SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1),
-            pallet_certification::Error::<Test, Instance2>::NotEnoughCertReceived
-        );
-    })
-}
-
-/// FIXME this test should not fail with NotRespectCertPeriod but NotSmith or somthing like that
-/// test non smith identity can not emit smith cert
-#[test]
-fn test_non_smith_with_certs_can_not_issue_smith_cert() {
-    new_test_ext(4, 3).execute_with(|| {
-        run_to_block(2);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 4));
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 4));
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 4));
-        assert_noop!(
-            SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1),
-            pallet_certification::Error::<Test, Instance2>::NotRespectCertPeriod
-        );
-    })
-}
-
-/// FIXME this test should not succeed because Dave should not be able to issue cert
-/// after revocation of his smith membership
-/// test non smith identity can not emit smith cert
-#[test]
-fn test_revoked_smith_with_certs_can_not_issue_smith_cert() {
-    new_test_ext(4, 3).execute_with(|| {
-        run_to_block(2);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 4));
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 4));
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 4));
-        assert_ok!(SmithMembership::claim_membership(RuntimeOrigin::signed(4)));
-        assert_noop!(
-            SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1),
-            pallet_certification::Error::<Test, Instance2>::NotRespectCertPeriod
-        );
-        run_to_block(4);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1),);
-        run_to_block(5);
-        assert_ok!(SmithMembership::revoke_membership(RuntimeOrigin::signed(4)));
-        run_to_block(6);
-        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1),);
-    })
-}
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index c9656a498241438b2cb16196ae8398b6090f7359..01998e0c5dc056155f3059575c3939b71c320c16 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -410,8 +410,6 @@ pub mod pallet {
                 Error::<T>::OwnerKeyAlreadyUsed
             );
 
-            T::CheckIdtyCallAllowed::change_owner_key(idty_index)?;
-
             let block_number = frame_system::Pallet::<T>::block_number();
             let maybe_old_old_owner_key =
                 if let Some((old_owner_key, last_change)) = idty_value.old_owner_key {
diff --git a/pallets/identity/src/traits.rs b/pallets/identity/src/traits.rs
index 925714813793a69a99b22438043e3cc92ab60a4c..6a1b457c1850bef852ac42bc0c160fc759b3f039 100644
--- a/pallets/identity/src/traits.rs
+++ b/pallets/identity/src/traits.rs
@@ -20,7 +20,6 @@ use impl_trait_for_tuples::impl_for_tuples;
 
 pub trait CheckIdtyCallAllowed<T: Config> {
     fn check_create_identity(creator: T::IdtyIndex) -> Result<(), DispatchError>;
-    fn change_owner_key(idty_index: T::IdtyIndex) -> Result<(), DispatchError>;
 }
 
 #[impl_for_tuples(5)]
@@ -29,10 +28,6 @@ impl<T: Config> CheckIdtyCallAllowed<T> for Tuple {
         for_tuples!( #( Tuple::check_create_identity(creator)?; )* );
         Ok(())
     }
-    fn change_owner_key(idty_index: T::IdtyIndex) -> Result<(), DispatchError> {
-        for_tuples!( #( Tuple::change_owner_key(idty_index)?; )* );
-        Ok(())
-    }
 }
 
 pub trait IdtyNameValidator {
diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs
index 20120f25c68a99791db7ca3ef76b2d0b26ad0b97..f8bff333c804b2a17f0152703ea267861d45cc0e 100644
--- a/pallets/identity/src/types.rs
+++ b/pallets/identity/src/types.rs
@@ -38,6 +38,7 @@ pub enum IdtyEvent<T: crate::Config> {
     /// removing an identity (unvalidated or revoked)
     // pallet wot removes associated certifications if status is not revoked
     // pallet quota removes associated quota
+    // pallet smith-members exclude smith
     Removed { status: IdtyStatus },
     // TODO add a way to unlink accounts corresponding to revoked or removed identities
 }
diff --git a/pallets/membership/src/benchmarking.rs b/pallets/membership/src/benchmarking.rs
index d07f4661b788592244c6d290103126cc5bac0192..1bdf5edf6c75666c3c2fc1acd901d2b3ad642733 100644
--- a/pallets/membership/src/benchmarking.rs
+++ b/pallets/membership/src/benchmarking.rs
@@ -18,7 +18,7 @@
 
 use super::*;
 
-use frame_benchmarking::benchmarks_instance_pallet;
+use frame_benchmarking::benchmarks;
 use frame_system::pallet_prelude::BlockNumberFor;
 use frame_system::RawOrigin;
 use sp_runtime::traits::{Convert, One};
@@ -28,11 +28,11 @@ use maplit::btreemap;
 
 use crate::Pallet;
 
-fn assert_has_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::RuntimeEvent) {
+fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
     frame_system::Pallet::<T>::assert_has_event(generic_event.into());
 }
 
-benchmarks_instance_pallet! {
+benchmarks! {
     where_clause {
         where
             T::IdtyId: From<u32>,
@@ -42,13 +42,13 @@ benchmarks_instance_pallet! {
     // claim membership
     claim_membership {
         let idty: T::IdtyId = 3.into();
-        Membership::<T, I>::take(idty);
+        Membership::<T>::take(idty);
         let caller: T::AccountId = T::AccountIdOf::convert(idty).unwrap();
         let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
         T::BenchmarkSetupHandler::force_status_ok(&idty, &caller);
     }: _<T::RuntimeOrigin>(caller_origin)
     verify {
-        assert_has_event::<T, I>(Event::<T, I>::MembershipAdded{member: idty, expire_on: BlockNumberFor::<T>::one() + T::MembershipPeriod::get()}.into());
+        assert_has_event::<T>(Event::<T>::MembershipAdded{member: idty, expire_on: BlockNumberFor::<T>::one() + T::MembershipPeriod::get()}.into());
     }
 
     // renew membership
@@ -59,7 +59,7 @@ benchmarks_instance_pallet! {
         T::BenchmarkSetupHandler::force_status_ok(&idty, &caller);
     }: _<T::RuntimeOrigin>(caller_origin)
     verify {
-        assert_has_event::<T, I>(Event::<T, I>::MembershipAdded{member: idty, expire_on: BlockNumberFor::<T>::one() + T::MembershipPeriod::get()}.into());
+        assert_has_event::<T>(Event::<T>::MembershipAdded{member: idty, expire_on: BlockNumberFor::<T>::one() + T::MembershipPeriod::get()}.into());
     }
 
     // revoke membership
@@ -70,12 +70,12 @@ benchmarks_instance_pallet! {
         frame_system::pallet::Pallet::<T>::set_block_number(10_000_000.into()); // Arbitrarily high, to be in the worst case of wot instance.
     }: _<T::RuntimeOrigin>(caller_origin)
     verify {
-        assert_has_event::<T, I>(Event::<T, I>::MembershipRemoved{member: idty, reason: MembershipRemovalReason::Revoked}.into());
+        assert_has_event::<T>(Event::<T>::MembershipRemoved{member: idty, reason: MembershipRemovalReason::Revoked}.into());
     }
 
     // Base weight of an empty initialize
     on_initialize {
-    }: {Pallet::<T, I>::on_initialize(BlockNumberFor::<T>::zero());}
+    }: {Pallet::<T>::on_initialize(BlockNumberFor::<T>::zero());}
 
     expire_memberships {
         let i in 0..3; // Limited by the number of validators
@@ -86,14 +86,14 @@ benchmarks_instance_pallet! {
         let mut idties: Vec<T::IdtyId> = Vec::new();
         for j in 1..i+1 {
             let j: T::IdtyId = j.into();
-            Membership::<T, I>::insert(j, MembershipData::<T::BlockNumber>::default());
+            Membership::<T>::insert(j, MembershipData::<T::BlockNumber>::default());
             idties.push(j);
         }
-        MembershipsExpireOn::<T, I>::insert(block_number, idties);
-        assert_eq!(MembershipsExpireOn::<T, I>::get(block_number).len(), i as usize);
-    }: {Pallet::<T, I>::expire_memberships(block_number);}
+        MembershipsExpireOn::<T>::insert(block_number, idties);
+        assert_eq!(MembershipsExpireOn::<T>::get(block_number).len(), i as usize);
+    }: {Pallet::<T>::expire_memberships(block_number);}
     verify {
-        assert_eq!(MembershipsExpireOn::<T, I>::get(block_number).len(), 0_usize);
+        assert_eq!(MembershipsExpireOn::<T>::get(block_number).len(), 0_usize);
     }
 
     impl_benchmark_test_suite!(
diff --git a/pallets/membership/src/lib.rs b/pallets/membership/src/lib.rs
index 08bbb81ad94295f46691fde78233a633b42ad687..cba39e37ee5abb5fc058fcdea588e74f7dced747 100644
--- a/pallets/membership/src/lib.rs
+++ b/pallets/membership/src/lib.rs
@@ -79,12 +79,12 @@ pub mod pallet {
     #[pallet::pallet]
     #[pallet::storage_version(STORAGE_VERSION)]
     #[pallet::without_storage_info]
-    pub struct Pallet<T, I = ()>(_);
+    pub struct Pallet<T>(_);
 
     // CONFIG //
 
     #[pallet::config]
-    pub trait Config<I: 'static = ()>: frame_system::Config {
+    pub trait Config: frame_system::Config {
         /// Ask the runtime whether the identity can perform membership operations
         type CheckMembershipCallAllowed: CheckMembershipCallAllowed<Self::IdtyId>;
         /// Something that identifies an identity
@@ -99,8 +99,7 @@ pub mod pallet {
         /// On event handler
         type OnEvent: OnEvent<Self::IdtyId>;
         /// Because this pallet emits events, it depends on the runtime's definition of an event.
-        type RuntimeEvent: From<Event<Self, I>>
-            + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
         type WeightInfo: WeightInfo;
         #[cfg(feature = "runtime-benchmarks")]
         type BenchmarkSetupHandler: SetupBenchmark<Self::IdtyId, Self::AccountId>;
@@ -109,12 +108,12 @@ pub mod pallet {
     // GENESIS STUFF //
 
     #[pallet::genesis_config]
-    pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
+    pub struct GenesisConfig<T: Config> {
         pub memberships: BTreeMap<T::IdtyId, MembershipData<T::BlockNumber>>,
     }
 
     #[cfg(feature = "std")]
-    impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> {
+    impl<T: Config> Default for GenesisConfig<T> {
         fn default() -> Self {
             Self {
                 memberships: Default::default(),
@@ -123,11 +122,11 @@ pub mod pallet {
     }
 
     #[pallet::genesis_build]
-    impl<T: Config<I>, I: 'static> GenesisBuild<T, I> for GenesisConfig<T, I> {
+    impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
         fn build(&self) {
             for (idty_id, membership_data) in &self.memberships {
-                MembershipsExpireOn::<T, I>::append(membership_data.expire_on, idty_id);
-                Membership::<T, I>::insert(idty_id, membership_data);
+                MembershipsExpireOn::<T>::append(membership_data.expire_on, idty_id);
+                Membership::<T>::insert(idty_id, membership_data);
             }
         }
     }
@@ -138,20 +137,20 @@ pub mod pallet {
     // (expiration block for instance)
     #[pallet::storage]
     #[pallet::getter(fn membership)]
-    pub type Membership<T: Config<I>, I: 'static = ()> =
+    pub type Membership<T: Config> =
         CountedStorageMap<_, Twox64Concat, T::IdtyId, MembershipData<T::BlockNumber>, OptionQuery>;
 
     /// maps block number to the list of identity id set to expire at this block
     #[pallet::storage]
     #[pallet::getter(fn memberships_expire_on)]
-    pub type MembershipsExpireOn<T: Config<I>, I: 'static = ()> =
+    pub type MembershipsExpireOn<T: Config> =
         StorageMap<_, Twox64Concat, T::BlockNumber, Vec<T::IdtyId>, ValueQuery>;
 
     // EVENTS //
 
     #[pallet::event]
     #[pallet::generate_deposit(pub(super) fn deposit_event)]
-    pub enum Event<T: Config<I>, I: 'static = ()> {
+    pub enum Event<T: Config> {
         /// A membership was added.
         MembershipAdded {
             member: T::IdtyId,
@@ -167,7 +166,7 @@ pub mod pallet {
     // ERRORS//
 
     #[pallet::error]
-    pub enum Error<T, I = ()> {
+    pub enum Error<T> {
         /// Identity ID not found.
         IdtyIdNotFound,
         /// Membership already acquired.
@@ -179,7 +178,7 @@ pub mod pallet {
     // HOOKS //
 
     #[pallet::hooks]
-    impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
+    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
         fn on_initialize(n: T::BlockNumber) -> Weight {
             if n > T::BlockNumber::zero() {
                 T::WeightInfo::on_initialize().saturating_add(Self::expire_memberships(n))
@@ -192,7 +191,7 @@ pub mod pallet {
     // CALLS //
 
     #[pallet::call]
-    impl<T: Config<I>, I: 'static> Pallet<T, I> {
+    impl<T: Config> Pallet<T> {
         /// claim membership
         /// it must fullfill the requirements (certs, distance)
         /// TODO #159 for main wot claim_membership is called automatically when distance is evaluated positively
@@ -215,7 +214,7 @@ pub mod pallet {
             // Verify phase
             let idty_id = Self::get_idty_id(origin)?;
             let membership_data =
-                Membership::<T, I>::get(idty_id).ok_or(Error::<T, I>::MembershipNotFound)?;
+                Membership::<T>::get(idty_id).ok_or(Error::<T>::MembershipNotFound)?;
 
             T::CheckMembershipCallAllowed::check_idty_allowed_to_renew_membership(&idty_id)?;
 
@@ -244,14 +243,14 @@ pub mod pallet {
 
     // INTERNAL FUNCTIONS //
 
-    impl<T: Config<I>, I: 'static> Pallet<T, I> {
+    impl<T: Config> Pallet<T> {
         /// unschedule membership expiry
         fn unschedule_membership_expiry(idty_id: T::IdtyId, block_number: T::BlockNumber) {
-            let mut scheduled = MembershipsExpireOn::<T, I>::get(block_number);
+            let mut scheduled = MembershipsExpireOn::<T>::get(block_number);
 
             if let Some(pos) = scheduled.iter().position(|x| *x == idty_id) {
                 scheduled.swap_remove(pos);
-                MembershipsExpireOn::<T, I>::set(block_number, scheduled);
+                MembershipsExpireOn::<T>::set(block_number, scheduled);
             }
         }
         /// schedule membership expiry
@@ -259,8 +258,8 @@ pub mod pallet {
             let block_number = frame_system::pallet::Pallet::<T>::block_number();
             let expire_on = block_number + T::MembershipPeriod::get();
 
-            Membership::<T, I>::insert(idty_id, MembershipData { expire_on });
-            MembershipsExpireOn::<T, I>::append(expire_on, idty_id);
+            Membership::<T>::insert(idty_id, MembershipData { expire_on });
+            MembershipsExpireOn::<T>::append(expire_on, idty_id);
             Self::deposit_event(Event::MembershipAdded {
                 member: idty_id,
                 expire_on,
@@ -282,7 +281,7 @@ pub mod pallet {
 
         /// perform membership removal
         pub fn do_remove_membership(idty_id: T::IdtyId, reason: MembershipRemovalReason) {
-            if let Some(membership_data) = Membership::<T, I>::take(idty_id) {
+            if let Some(membership_data) = Membership::<T>::take(idty_id) {
                 Self::unschedule_membership_expiry(idty_id, membership_data.expire_on);
                 Self::deposit_event(Event::MembershipRemoved {
                     member: idty_id,
@@ -295,7 +294,7 @@ pub mod pallet {
         /// check the origin and get identity id if valid
         fn get_idty_id(origin: OriginFor<T>) -> Result<T::IdtyId, DispatchError> {
             if let Ok(RawOrigin::Signed(account_id)) = origin.into() {
-                T::IdtyIdOf::convert(account_id).ok_or_else(|| Error::<T, I>::IdtyIdNotFound.into())
+                T::IdtyIdOf::convert(account_id).ok_or_else(|| Error::<T>::IdtyIdNotFound.into())
             } else {
                 Err(BadOrigin.into())
             }
@@ -305,7 +304,7 @@ pub mod pallet {
         pub fn expire_memberships(block_number: T::BlockNumber) -> Weight {
             let mut expired_idty_count = 0u32;
 
-            for idty_id in MembershipsExpireOn::<T, I>::take(block_number) {
+            for idty_id in MembershipsExpireOn::<T>::take(block_number) {
                 // remove membership (take)
                 Self::do_remove_membership(idty_id, MembershipRemovalReason::Expired);
                 expired_idty_count += 1;
@@ -314,22 +313,22 @@ pub mod pallet {
         }
 
         /// check if identity is member
-        pub(super) fn is_member(idty_id: &T::IdtyId) -> bool {
-            Membership::<T, I>::contains_key(idty_id)
+        pub fn is_member(idty_id: &T::IdtyId) -> bool {
+            Membership::<T>::contains_key(idty_id)
         }
     }
 }
 
 // implement traits
 
-impl<T: Config<I>, I: 'static> sp_runtime::traits::IsMember<T::IdtyId> for Pallet<T, I> {
+impl<T: Config> sp_runtime::traits::IsMember<T::IdtyId> for Pallet<T> {
     fn is_member(idty_id: &T::IdtyId) -> bool {
         Self::is_member(idty_id)
     }
 }
 
-impl<T: Config<I>, I: 'static> MembersCount for Pallet<T, I> {
+impl<T: Config> MembersCount for Pallet<T> {
     fn members_count() -> u32 {
-        Membership::<T, I>::count()
+        Membership::<T>::count()
     }
 }
diff --git a/pallets/membership/src/tests.rs b/pallets/membership/src/tests.rs
index d3ea561676c7df75c9037da79ec8b5f2a47b232b..53da60336bb6cefa94a5897836a38871929f7503 100644
--- a/pallets/membership/src/tests.rs
+++ b/pallets/membership/src/tests.rs
@@ -106,7 +106,7 @@ fn test_membership_renewal_nope() {
         // Membership 1 can not be renewed
         assert_noop!(
             DefaultMembership::renew_membership(RuntimeOrigin::signed(1)),
-            Error::<Test, _>::MembershipNotFound,
+            Error::<Test>::MembershipNotFound,
         );
         run_to_block(3);
         assert!(!DefaultMembership::is_member(&1));
diff --git a/pallets/smith-members/Cargo.toml b/pallets/smith-members/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..5ced90e2c20a197003523b374e1bcf7928d904c0
--- /dev/null
+++ b/pallets/smith-members/Cargo.toml
@@ -0,0 +1,56 @@
+[package]
+name = "pallet-smith-members"
+authors = ["c-geek <https://forum.duniter.org/u/cgeek>"]
+description = 'duniter pallet to handle offences.'
+edition = "2021"
+homepage = 'https://duniter.org'
+license = 'AGPL-3.0'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '3.0.0'
+readme = "README.md"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"], default-features = false }
+log = { version = "0.4.17", default-features = false }
+scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+serde = { version = "1.0.101", default-features = false, optional = true }
+pallet-authority-members = { path = "../authority-members", default-features = false }
+frame-support = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false }
+frame-system = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false }
+pallet-balances = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false }
+sp-runtime = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false }
+sp-staking = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false }
+sp-std = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false }
+
+[dev-dependencies]
+maplit = "1.0.2"
+sp-core = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false }
+sp-io = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42' }
+
+[features]
+default = ["std"]
+std = [
+	"codec/std",
+	"frame-support/std",
+	"frame-system/std",
+	'frame-benchmarking/std',
+	"log/std",
+	"pallet-balances/std",
+	"pallet-authority-members/std",
+	"scale-info/std",
+	"serde",
+	"sp-runtime/std",
+	"sp-staking/std",
+	"sp-std/std",
+]
+runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
+try-runtime = ["frame-support/try-runtime"]
+
+[dependencies.frame-benchmarking]
+default-features = false
+git = 'https://github.com/duniter/substrate'
+optional = true
+branch = 'duniter-substrate-v0.9.42'
\ No newline at end of file
diff --git a/pallets/smith-members/README.md b/pallets/smith-members/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..655534a2a74d357c3d0f856dd3e4de6493eddd44
--- /dev/null
+++ b/pallets/smith-members/README.md
@@ -0,0 +1,3 @@
+# Duniter smith pallet
+
+The bridge between `identity` and `authority-members` pallet.
\ No newline at end of file
diff --git a/pallets/smith-members/src/benchmarking.rs b/pallets/smith-members/src/benchmarking.rs
new file mode 100644
index 0000000000000000000000000000000000000000..071d73905ff8d416f472eca8b5700dccb65d975f
--- /dev/null
+++ b/pallets/smith-members/src/benchmarking.rs
@@ -0,0 +1,105 @@
+// Copyright 2021-2023 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg(feature = "runtime-benchmarks")]
+
+use super::*;
+
+use frame_benchmarking::benchmarks;
+use frame_system::RawOrigin;
+use sp_runtime::traits::Convert;
+
+#[cfg(test)]
+use maplit::btreemap;
+
+use crate::Pallet;
+
+fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
+    frame_system::Pallet::<T>::assert_has_event(generic_event.into());
+}
+
+benchmarks! {
+    where_clause {
+        where
+            T::IdtyIndex: From<u32>
+    }
+    invite_smith {
+        let issuer: T::IdtyIndex = 1.into();
+        let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap();
+        Pallet::<T>::on_smith_goes_online(1.into());
+        let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
+        let receiver: T::IdtyIndex = 4.into();
+    }: _<T::RuntimeOrigin>(caller_origin, receiver)
+    verify {
+        assert_has_event::<T>(Event::<T>::InvitationSent{
+            idty_index: receiver,
+            invited_by: issuer,
+        }.into());
+    }
+    accept_invitation {
+        // Worst case preparation
+        let issuer: T::IdtyIndex = 1.into();
+        let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap();
+        Pallet::<T>::on_smith_goes_online(1.into());
+        let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
+        let receiver: T::IdtyIndex = 4.into();
+        Pallet::<T>::invite_smith(caller_origin, receiver)?;
+        // test
+        let issuer: T::IdtyIndex = 4.into();
+        let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap();
+        let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
+    }: _<T::RuntimeOrigin>(caller_origin)
+    verify {
+        assert_has_event::<T>(Event::<T>::InvitationAccepted{
+            idty_index: receiver,
+        }.into());
+    }
+    certify_smith {
+        // Worst case preparation
+        let issuer: T::IdtyIndex = 1.into();
+        let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap();
+        Pallet::<T>::on_smith_goes_online(1.into());
+        let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
+        let receiver: T::IdtyIndex = 4.into();
+        Pallet::<T>::invite_smith(caller_origin, receiver)?;
+        let issuer: T::IdtyIndex = receiver;
+        let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap();
+        let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
+        Pallet::<T>::accept_invitation(caller_origin)?;
+        // test
+        let issuer: T::IdtyIndex = 1.into();
+        let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap();
+        let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
+    }: _<T::RuntimeOrigin>(caller_origin, receiver)
+    verify {
+        assert_has_event::<T>(Event::<T>::CertificationReceived{
+            idty_index: receiver,
+            issued_by: issuer,
+        }.into());
+    }
+
+    impl_benchmark_test_suite!(
+        Pallet,
+        crate::mock::new_test_ext(GenesisConfig {
+            initial_smiths: btreemap![
+                1 => (false, vec![2, 3]),
+                2 => (false, vec![1, 3]),
+                3 => (false, vec![1, 2]),
+            ],
+        }),
+        crate::mock::Runtime
+    );
+}
diff --git a/pallets/smith-members/src/impls.rs b/pallets/smith-members/src/impls.rs
new file mode 100644
index 0000000000000000000000000000000000000000..95a1e49dfd63d25acd45e8a5b5f7c983bad89aef
--- /dev/null
+++ b/pallets/smith-members/src/impls.rs
@@ -0,0 +1,28 @@
+use crate::{Config, CurrentSession, Pallet};
+use pallet_authority_members::SessionIndex;
+use sp_runtime::traits::Convert;
+
+impl<T: Config> pallet_authority_members::OnOutgoingMember<T::MemberId> for Pallet<T> {
+    fn on_outgoing_member(member_id: T::MemberId) {
+        if let Some(member_id) = T::IdtyIdOfAuthorityId::convert(member_id) {
+            Pallet::<T>::on_smith_goes_offline(member_id);
+        }
+    }
+}
+
+/// As long as a Smith is in the authority set, he will not expire.
+impl<T: Config> pallet_authority_members::OnIncomingMember<T::MemberId> for Pallet<T> {
+    fn on_incoming_member(member_id: T::MemberId) {
+        if let Some(member_id) = T::IdtyIdOfAuthorityId::convert(member_id) {
+            Pallet::<T>::on_smith_goes_online(member_id);
+        }
+    }
+}
+
+///
+impl<T: Config> pallet_authority_members::OnNewSession for Pallet<T> {
+    fn on_new_session(index: SessionIndex) {
+        CurrentSession::<T>::put(index);
+        Pallet::<T>::on_exclude_expired_smiths(index);
+    }
+}
diff --git a/pallets/smith-members/src/lib.rs b/pallets/smith-members/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..95dd31177915c5dd19b8872c363c7c524ee39d52
--- /dev/null
+++ b/pallets/smith-members/src/lib.rs
@@ -0,0 +1,552 @@
+// Copyright 2021-2023 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(test)]
+mod mock;
+
+#[cfg(test)]
+mod tests;
+
+mod impls;
+pub mod traits;
+mod types;
+pub mod weights;
+
+#[cfg(feature = "runtime-benchmarks")]
+mod benchmarking;
+
+use codec::{Codec, Decode, Encode};
+use frame_support::dispatch::{DispatchResultWithPostInfo, TypeInfo};
+use frame_support::pallet_prelude::Get;
+use frame_support::{ensure, RuntimeDebug};
+use frame_system::ensure_signed;
+use frame_system::pallet_prelude::OriginFor;
+use sp_runtime::traits::AtLeast32BitUnsigned;
+use sp_runtime::traits::IsMember;
+use sp_std::fmt::Debug;
+use sp_std::prelude::*;
+
+use crate::traits::OnSmithDelete;
+pub use crate::weights::WeightInfo;
+pub use pallet::*;
+use pallet_authority_members::SessionIndex;
+pub use types::*;
+
+#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+pub enum SmithRemovalReason {
+    LostMembership,
+    OfflineTooLong,
+    Blacklisted,
+}
+
+#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+pub enum SmithStatus {
+    /// The identity has been invited by a smith but has not accepted yet
+    Invited,
+    /// The identity has accepted to eventually become a smith
+    Pending,
+    /// The identity has reached the requirements to become a smith and can now goGoOnline() or invite/certify other smiths
+    Smith,
+    /// The identity has been removed from the smiths set but is kept to keep track of its certifications
+    Excluded,
+}
+
+#[frame_support::pallet]
+pub mod pallet {
+    use super::*;
+    use frame_support::pallet_prelude::*;
+    use frame_support::traits::StorageVersion;
+    use pallet_authority_members::SessionIndex;
+    use sp_runtime::traits::{Convert, IsMember};
+    use sp_std::collections::btree_map::BTreeMap;
+    use sp_std::vec;
+    use sp_std::vec::Vec;
+
+    const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
+    #[pallet::pallet]
+    #[pallet::storage_version(STORAGE_VERSION)]
+    #[pallet::without_storage_info]
+    pub struct Pallet<T>(_);
+
+    /// The pallet's config trait.
+    #[pallet::config]
+    pub trait Config: frame_system::Config {
+        /// To only allow WoT members to be invited
+        type IsWoTMember: IsMember<Self::IdtyIndex>;
+        /// Notify when a smith is removed (for authority-members to react)
+        type OnSmithDelete: traits::OnSmithDelete<Self::IdtyIndex>;
+        /// The overarching event type.
+        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+        /// A short identity index.
+        type IdtyIndex: Parameter
+            + Member
+            + AtLeast32BitUnsigned
+            + Codec
+            + Default
+            + Copy
+            + MaybeSerializeDeserialize
+            + Debug
+            + MaxEncodedLen;
+        /// Identifier for an authority-member
+        type MemberId: Copy + Ord + MaybeSerializeDeserialize + Parameter;
+        /// Something that gives the IdtyId of an AccountId
+        type IdtyIdOf: Convert<Self::AccountId, Option<Self::IdtyIndex>>;
+        /// Something that give the owner key of an identity
+        type OwnerKeyOf: Convert<Self::IdtyIndex, Option<Self::AccountId>>;
+        /// Something that gives the IdtyId of an AccountId
+        type IdtyIdOfAuthorityId: Convert<Self::MemberId, Option<Self::IdtyIndex>>;
+        /// Maximum number of active certifications by issuer
+        #[pallet::constant]
+        type MaxByIssuer: Get<u32>;
+        /// Minimum number of certifications to become a Smith
+        #[pallet::constant]
+        type MinCertForMembership: Get<u32>;
+        /// Maximum duration of inactivity before a smith is removed
+        #[pallet::constant]
+        type SmithInactivityMaxDuration: Get<u32>;
+        /// Type representing the weight of this pallet
+        type WeightInfo: WeightInfo;
+    }
+
+    /// Events type.
+    #[pallet::event]
+    #[pallet::generate_deposit(pub(super) fn deposit_event)]
+    pub enum Event<T: Config> {
+        /// An identity is being inivited to become a smith
+        InvitationSent {
+            idty_index: T::IdtyIndex,
+            invited_by: T::IdtyIndex,
+        },
+        /// The invitation has been accepted
+        InvitationAccepted { idty_index: T::IdtyIndex },
+        /// Certification received
+        CertificationReceived {
+            idty_index: T::IdtyIndex,
+            issued_by: T::IdtyIndex,
+        },
+        /// A smith gathered enough certifications to become an authority (can call `go_online()`).
+        PromotedToSmith { idty_index: T::IdtyIndex },
+        /// A smith has been removed from the smiths set
+        SmithExcluded { idty_index: T::IdtyIndex },
+    }
+
+    #[pallet::genesis_config]
+    pub struct GenesisConfig<T: Config> {
+        pub initial_smiths: BTreeMap<T::IdtyIndex, (bool, Vec<T::IdtyIndex>)>,
+    }
+
+    #[cfg(feature = "std")]
+    impl<T: Config> Default for GenesisConfig<T> {
+        fn default() -> Self {
+            Self {
+                initial_smiths: Default::default(),
+            }
+        }
+    }
+
+    #[pallet::genesis_build]
+    impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
+        fn build(&self) {
+            CurrentSession::<T>::put(0);
+            let mut cert_meta_by_issuer = BTreeMap::<T::IdtyIndex, Vec<T::IdtyIndex>>::new();
+            for (receiver, (is_online, issuers)) in &self.initial_smiths {
+                // Forbid self-cert
+                assert!(
+                    !issuers.contains(receiver),
+                    "Identity cannot certify it-self."
+                );
+
+                let mut issuers_: Vec<_> = Vec::with_capacity(issuers.len());
+                for issuer in issuers {
+                    // Count issued certs
+                    cert_meta_by_issuer
+                        .entry(*issuer)
+                        .or_insert(vec![])
+                        .push(*receiver);
+                    issuers_.push(*issuer);
+                }
+
+                // Write CertsByReceiver
+                issuers_.sort();
+                let issuers_count = issuers_.len();
+                let smith_status = if issuers_count >= T::MinCertForMembership::get() as usize {
+                    SmithStatus::Smith
+                } else {
+                    SmithStatus::Pending
+                };
+                Smiths::<T>::insert(
+                    receiver,
+                    SmithMeta {
+                        status: smith_status,
+                        expires_on: if *is_online {
+                            None
+                        } else {
+                            Some(CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get())
+                        },
+                        issued_certs: vec![],
+                        received_certs: issuers_,
+                    },
+                );
+                ExpiresOn::<T>::append(
+                    CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get(),
+                    receiver,
+                );
+            }
+
+            for (issuer, issued_certs) in cert_meta_by_issuer {
+                // Write CertsByIssuer
+                Smiths::<T>::mutate(issuer, |maybe_smith_meta| {
+                    if let Some(smith_meta) = maybe_smith_meta {
+                        smith_meta.issued_certs = issued_certs;
+                    }
+                });
+            }
+        }
+    }
+
+    /// maps identity index to smith status
+    #[pallet::storage]
+    #[pallet::getter(fn smiths)]
+    pub type Smiths<T: Config> =
+        StorageMap<_, Twox64Concat, T::IdtyIndex, SmithMeta<T::IdtyIndex>, OptionQuery>;
+
+    /// maps session index to possible smith removals
+    #[pallet::storage]
+    #[pallet::getter(fn expires_on)]
+    pub type ExpiresOn<T: Config> =
+        StorageMap<_, Twox64Concat, SessionIndex, Vec<T::IdtyIndex>, OptionQuery>;
+
+    /// stores the current session index
+    #[pallet::storage]
+    #[pallet::getter(fn current_session)]
+    pub type CurrentSession<T: Config> = StorageValue<_, SessionIndex, ValueQuery>;
+
+    // ERRORS //
+
+    #[pallet::error]
+    pub enum Error<T> {
+        /// Issuer of anything (invitation, acceptance, certification) must have an identity ID
+        OriginMustHaveAnIdentity,
+        /// Issuer must be known as a potential smith
+        OriginHasNeverBeenInvited,
+        /// Invitation is reseverd to smiths
+        InvitationIsASmithPrivilege,
+        /// Invitation is reseverd to online smiths
+        InvitationIsAOnlineSmithPrivilege,
+        /// Invitation must not have been accepted yet
+        InvitationAlreadyAccepted,
+        /// Invitation of an already known smith is forbidden except if it has been excluded
+        InvitationOfExistingNonExcluded,
+        /// Invitation of a non-member (of the WoT) is forbidden
+        InvitationOfNonMember,
+        /// Certification cannot be made on someone who has not accepted an invitation
+        CertificationMustBeAgreed,
+        /// Certification cannot be made on excluded
+        CertificationOnExcludedIsForbidden,
+        /// Issuer must be a smith
+        CertificationIsASmithPrivilege,
+        /// Only online smiths can certify
+        CertificationIsAOnlineSmithPrivilege,
+        /// Smith cannot certify itself
+        CertificationOfSelfIsForbidden,
+        /// Receiver must be invited by another smith
+        CertificationReceiverMustHaveBeenInvited,
+        /// Receiver must not already have this certification
+        CertificationAlreadyExists,
+        /// A smith has a limited stock of certifications
+        CertificationStockFullyConsumed,
+    }
+
+    #[pallet::call]
+    impl<T: Config> Pallet<T> {
+        #[pallet::call_index(0)]
+        #[pallet::weight(T::WeightInfo::invite_smith())]
+        pub fn invite_smith(
+            origin: OriginFor<T>,
+            receiver: T::IdtyIndex,
+        ) -> DispatchResultWithPostInfo {
+            let who = ensure_signed(origin.clone())?;
+            let issuer =
+                T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?;
+            Self::check_invite_smith(issuer, receiver)?;
+            Self::do_invite_smith(issuer, receiver);
+            Ok(().into())
+        }
+
+        #[pallet::call_index(1)]
+        #[pallet::weight(T::WeightInfo::accept_invitation())]
+        pub fn accept_invitation(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
+            let who = ensure_signed(origin.clone())?;
+            let receiver =
+                T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?;
+            Self::check_accept_invitation(receiver)?;
+            Self::do_accept_invitation(receiver)?;
+            Ok(().into())
+        }
+
+        #[pallet::call_index(2)]
+        #[pallet::weight(T::WeightInfo::certify_smith())]
+        pub fn certify_smith(
+            origin: OriginFor<T>,
+            receiver: T::IdtyIndex,
+        ) -> DispatchResultWithPostInfo {
+            let who = ensure_signed(origin)?;
+            let issuer =
+                T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?;
+            Self::check_certify_smith(issuer, receiver)?;
+            Self::do_certify_smith(receiver, issuer);
+            Ok(().into())
+        }
+    }
+}
+
+impl<T: Config> Pallet<T> {
+    fn check_invite_smith(
+        issuer: T::IdtyIndex,
+        receiver: T::IdtyIndex,
+    ) -> DispatchResultWithPostInfo {
+        let issuer = Smiths::<T>::get(issuer).ok_or(Error::<T>::OriginHasNeverBeenInvited)?;
+        ensure!(
+            issuer.status == SmithStatus::Smith,
+            Error::<T>::InvitationIsASmithPrivilege
+        );
+        ensure!(
+            issuer.expires_on.is_none(),
+            Error::<T>::InvitationIsAOnlineSmithPrivilege
+        );
+        if let Some(receiver_meta) = Smiths::<T>::get(receiver) {
+            ensure!(
+                receiver_meta.status == SmithStatus::Excluded,
+                Error::<T>::InvitationOfExistingNonExcluded
+            );
+        }
+        ensure!(
+            T::IsWoTMember::is_member(&receiver),
+            Error::<T>::InvitationOfNonMember
+        );
+
+        Ok(().into())
+    }
+
+    fn do_invite_smith(issuer: T::IdtyIndex, receiver: T::IdtyIndex) {
+        let new_expires_on = CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get();
+        let mut existing = Smiths::<T>::get(receiver).unwrap_or_default();
+        existing.status = SmithStatus::Invited;
+        existing.expires_on = Some(new_expires_on);
+        existing.received_certs = vec![];
+        Smiths::<T>::insert(receiver, existing);
+        ExpiresOn::<T>::append(new_expires_on, receiver);
+        Self::deposit_event(Event::<T>::InvitationSent {
+            idty_index: receiver,
+            invited_by: issuer,
+        });
+    }
+
+    fn check_accept_invitation(receiver: T::IdtyIndex) -> DispatchResultWithPostInfo {
+        let pretender_status = Smiths::<T>::get(receiver)
+            .ok_or(Error::<T>::OriginHasNeverBeenInvited)?
+            .status;
+        ensure!(
+            pretender_status == SmithStatus::Invited,
+            Error::<T>::InvitationAlreadyAccepted
+        );
+        Ok(().into())
+    }
+
+    fn do_accept_invitation(receiver: T::IdtyIndex) -> DispatchResultWithPostInfo {
+        Smiths::<T>::mutate(receiver, |maybe_smith_meta| {
+            if let Some(smith_meta) = maybe_smith_meta {
+                smith_meta.status = SmithStatus::Pending;
+            }
+        });
+        Self::deposit_event(Event::<T>::InvitationAccepted {
+            idty_index: receiver,
+        });
+        Ok(().into())
+    }
+
+    fn check_certify_smith(
+        issuer_index: T::IdtyIndex,
+        receiver_index: T::IdtyIndex,
+    ) -> DispatchResultWithPostInfo {
+        ensure!(
+            issuer_index != receiver_index,
+            Error::<T>::CertificationOfSelfIsForbidden
+        );
+        let issuer = Smiths::<T>::get(issuer_index).ok_or(Error::<T>::OriginHasNeverBeenInvited)?;
+        ensure!(
+            issuer.status == SmithStatus::Smith,
+            Error::<T>::CertificationIsASmithPrivilege
+        );
+        ensure!(
+            issuer.expires_on.is_none(),
+            Error::<T>::CertificationIsAOnlineSmithPrivilege
+        );
+        let issued_certs = issuer.issued_certs.len();
+        ensure!(
+            issued_certs < T::MaxByIssuer::get() as usize,
+            Error::<T>::CertificationStockFullyConsumed
+        );
+        let receiver = Smiths::<T>::get(receiver_index)
+            .ok_or(Error::<T>::CertificationReceiverMustHaveBeenInvited)?;
+        ensure!(
+            receiver.status != SmithStatus::Invited,
+            Error::<T>::CertificationMustBeAgreed
+        );
+        ensure!(
+            receiver.status != SmithStatus::Excluded,
+            Error::<T>::CertificationOnExcludedIsForbidden
+        );
+        ensure!(
+            receiver
+                .received_certs
+                .binary_search(&issuer_index)
+                .is_err(),
+            Error::<T>::CertificationAlreadyExists
+        );
+
+        Ok(().into())
+    }
+
+    fn do_certify_smith(receiver: T::IdtyIndex, issuer: T::IdtyIndex) {
+        Smiths::<T>::mutate(issuer, |maybe_smith_meta| {
+            if let Some(smith_meta) = maybe_smith_meta {
+                smith_meta.issued_certs.push(receiver);
+                smith_meta.issued_certs.sort();
+            }
+        });
+        Smiths::<T>::mutate(receiver, |maybe_smith_meta| {
+            if let Some(smith_meta) = maybe_smith_meta {
+                smith_meta.received_certs.push(issuer);
+                smith_meta.received_certs.sort();
+                smith_meta.status =
+                    if smith_meta.received_certs.len() >= T::MinCertForMembership::get() as usize {
+                        SmithStatus::Smith
+                    } else {
+                        SmithStatus::Pending
+                    };
+                // expiry postponed
+                let new_expires_on =
+                    CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get();
+                smith_meta.expires_on = Some(new_expires_on);
+                Self::deposit_event(Event::<T>::CertificationReceived {
+                    idty_index: receiver,
+                    issued_by: issuer,
+                });
+                if smith_meta.status == SmithStatus::Smith {
+                    Self::deposit_event(Event::<T>::PromotedToSmith {
+                        idty_index: receiver,
+                    });
+                }
+                // TODO: unschedule old expiry
+            }
+        });
+    }
+
+    fn on_exclude_expired_smiths(at: SessionIndex) {
+        if let Some(smiths_to_remove) = ExpiresOn::<T>::get(at) {
+            for smith in smiths_to_remove {
+                if let Some(smith_meta) = Smiths::<T>::get(smith) {
+                    if let Some(expires_on) = smith_meta.expires_on {
+                        if expires_on == at {
+                            Self::_do_exclude_smith(smith, SmithRemovalReason::OfflineTooLong);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn on_removed_wot_member(idty_index: T::IdtyIndex) {
+        if Smiths::<T>::get(idty_index).is_some() {
+            Self::_do_exclude_smith(idty_index, SmithRemovalReason::LostMembership);
+        }
+    }
+
+    fn _do_exclude_smith(idty_index: T::IdtyIndex, reason: SmithRemovalReason) {
+        let mut lost_certs = vec![];
+        Smiths::<T>::mutate(idty_index, |maybe_smith_meta| {
+            if let Some(smith_meta) = maybe_smith_meta {
+                smith_meta.expires_on = None;
+                smith_meta.status = SmithStatus::Excluded;
+                for cert in &smith_meta.received_certs {
+                    lost_certs.push(*cert);
+                }
+                smith_meta.received_certs = vec![];
+                // N.B.: the issued certs are kept in case the smith joins back
+            }
+        });
+        // We remove the lost certs from their issuer's stock
+        for lost_cert in lost_certs {
+            Smiths::<T>::mutate(lost_cert, |maybe_smith_meta| {
+                if let Some(smith_meta) = maybe_smith_meta {
+                    if let Ok(index) = smith_meta.issued_certs.binary_search(&idty_index) {
+                        smith_meta.issued_certs.remove(index);
+                    }
+                }
+            });
+        }
+        // Deletion done: notify (authority-members) for cascading
+        T::OnSmithDelete::on_smith_delete(idty_index, reason);
+        Self::deposit_event(Event::<T>::SmithExcluded { idty_index });
+    }
+
+    pub fn on_smith_goes_online(idty_index: T::IdtyIndex) {
+        if let Some(smith_meta) = Smiths::<T>::get(idty_index) {
+            if smith_meta.expires_on.is_some() {
+                Smiths::<T>::mutate(idty_index, |maybe_smith_meta| {
+                    if let Some(smith_meta) = maybe_smith_meta {
+                        // As long as the smith is online, it cannot expire
+                        smith_meta.expires_on = None;
+                        // FIXME: unschedule old expiry
+                    }
+                });
+            }
+        }
+    }
+
+    pub fn on_smith_goes_offline(idty_index: T::IdtyIndex) {
+        if let Some(smith_meta) = Smiths::<T>::get(idty_index) {
+            if smith_meta.expires_on.is_none() {
+                Smiths::<T>::mutate(idty_index, |maybe_smith_meta| {
+                    if let Some(smith_meta) = maybe_smith_meta {
+                        // As long as the smith is online, it cannot expire
+                        let new_expires_on =
+                            CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get();
+                        smith_meta.expires_on = Some(new_expires_on);
+                        ExpiresOn::<T>::append(new_expires_on, idty_index);
+                    }
+                });
+            }
+        }
+    }
+
+    fn provide_is_member(idty_id: &T::IdtyIndex) -> bool {
+        let Some(smith) = Smiths::<T>::get(idty_id) else {
+            return false;
+        };
+        smith.status == SmithStatus::Smith
+    }
+}
+
+impl<T: Config> sp_runtime::traits::IsMember<T::IdtyIndex> for Pallet<T> {
+    fn is_member(idty_id: &T::IdtyIndex) -> bool {
+        Self::provide_is_member(idty_id)
+    }
+}
diff --git a/pallets/smith-members/src/mock.rs b/pallets/smith-members/src/mock.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cd2398e4dc2ed48618d6f24b50b0186e3d34bba2
--- /dev/null
+++ b/pallets/smith-members/src/mock.rs
@@ -0,0 +1,123 @@
+// Copyright 2021-2023 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg(test)]
+
+use crate::{self as pallet_smith_members};
+use frame_support::pallet_prelude::Hooks;
+use frame_support::{
+    parameter_types,
+    traits::{ConstU32, ConstU64},
+    weights::{constants::RocksDbWeight, Weight},
+};
+use sp_core::H256;
+use sp_runtime::traits::{ConvertInto, IsMember};
+use sp_runtime::{
+    testing::Header,
+    traits::{BlakeTwo256, IdentityLookup},
+    BuildStorage, Perbill,
+};
+
+parameter_types! {
+    pub static OnOffencePerbill: Vec<Perbill> = Default::default();
+    pub static OffenceWeight: Weight = Default::default();
+}
+
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
+type Block = frame_system::mocking::MockBlock<Runtime>;
+
+frame_support::construct_runtime!(
+    pub struct Runtime where
+        Block = Block,
+        NodeBlock = Block,
+        UncheckedExtrinsic = UncheckedExtrinsic,
+    {
+        System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
+        Smith: pallet_smith_members::{Pallet, Config<T>, Storage, Event<T>},
+    }
+);
+
+impl frame_system::Config for Runtime {
+    type BaseCallFilter = frame_support::traits::Everything;
+    type BlockWeights = ();
+    type BlockLength = ();
+    type DbWeight = RocksDbWeight;
+    type RuntimeOrigin = RuntimeOrigin;
+    type Index = u64;
+    type BlockNumber = u64;
+    type RuntimeCall = RuntimeCall;
+    type Hash = H256;
+    type Hashing = BlakeTwo256;
+    type AccountId = u64;
+    type Lookup = IdentityLookup<Self::AccountId>;
+    type Header = Header;
+    type RuntimeEvent = RuntimeEvent;
+    type BlockHashCount = ConstU64<250>;
+    type Version = ();
+    type PalletInfo = PalletInfo;
+    type AccountData = ();
+    type OnNewAccount = ();
+    type OnKilledAccount = ();
+    type SystemWeightInfo = ();
+    type SS58Prefix = ();
+    type OnSetCode = ();
+    type MaxConsumers = ConstU32<16>;
+}
+
+pub struct EveryoneExceptIdZero;
+impl IsMember<u64> for EveryoneExceptIdZero {
+    fn is_member(member_id: &u64) -> bool {
+        member_id != &0 && member_id != &10
+    }
+}
+
+impl pallet_smith_members::Config for Runtime {
+    type RuntimeEvent = RuntimeEvent;
+    type IdtyIndex = u64;
+    type IsWoTMember = EveryoneExceptIdZero;
+    type IdtyIdOf = ConvertInto;
+    type MinCertForMembership = ConstU32<2>;
+    type MaxByIssuer = ConstU32<3>;
+    type SmithInactivityMaxDuration = ConstU32<5>;
+    type OnSmithDelete = ();
+    type IdtyIdOfAuthorityId = ConvertInto;
+    type MemberId = u64;
+    type OwnerKeyOf = ConvertInto;
+    type WeightInfo = ();
+}
+
+pub fn new_test_ext(
+    genesis_config: crate::pallet::GenesisConfig<Runtime>,
+) -> sp_io::TestExternalities {
+    GenesisConfig {
+        system: SystemConfig::default(),
+        smith: genesis_config,
+    }
+    .build_storage()
+    .unwrap()
+    .into()
+}
+
+pub fn run_to_block(n: u64) {
+    while System::block_number() < n {
+        Smith::on_finalize(System::block_number());
+        System::on_finalize(System::block_number());
+        System::reset_events();
+        System::set_block_number(System::block_number() + 1);
+        System::on_initialize(System::block_number());
+        Smith::on_initialize(System::block_number());
+    }
+}
diff --git a/pallets/smith-members/src/tests.rs b/pallets/smith-members/src/tests.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a843a17a962cdf2f5e2d044ac283ee6695ba5760
--- /dev/null
+++ b/pallets/smith-members/src/tests.rs
@@ -0,0 +1,577 @@
+// Copyright 2021-2023 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg(test)]
+
+use super::*;
+use crate::mock::{new_test_ext, run_to_block, Runtime, RuntimeEvent, RuntimeOrigin, System};
+use frame_support::{assert_err, assert_ok};
+
+use crate::SmithStatus::{Excluded, Invited, Pending, Smith};
+#[cfg(test)]
+use maplit::btreemap;
+use pallet_authority_members::OnNewSession;
+
+#[test]
+fn process_to_become_a_smith_and_lose_it() {
+    new_test_ext(GenesisConfig {
+        initial_smiths: btreemap![
+            1 => (false, vec![2, 3, 4]),
+            2 => (false, vec![3, 4]),
+            3 => (false, vec![]),
+            4 => (false, vec![]),
+        ],
+    })
+    .execute_with(|| {
+        // Go online to be able to invite+certify
+        Pallet::<Runtime>::on_smith_goes_online(1);
+        Pallet::<Runtime>::on_smith_goes_online(2);
+        // Events cannot be recorded on genesis
+        run_to_block(1);
+        // State before
+        assert_eq!(Smiths::<Runtime>::get(5), None);
+        // Try to invite
+        assert_ok!(Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 5));
+        System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::InvitationSent {
+            idty_index: 5,
+            invited_by: 1,
+        }));
+        // Accept invitation
+        assert_ok!(Pallet::<Runtime>::accept_invitation(RuntimeOrigin::signed(
+            5
+        )));
+        System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::InvitationAccepted {
+            idty_index: 5,
+        }));
+        // State after
+        assert_eq!(
+            Smiths::<Runtime>::get(5).unwrap(),
+            SmithMeta {
+                status: SmithStatus::Pending,
+                expires_on: Some(5),
+                issued_certs: vec![],
+                received_certs: vec![],
+            }
+        );
+        // Then certification 1/2
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(1),
+            5
+        ));
+        System::assert_has_event(RuntimeEvent::Smith(
+            Event::<Runtime>::CertificationReceived {
+                idty_index: 5,
+                issued_by: 1,
+            },
+        ));
+        assert_eq!(
+            Smiths::<Runtime>::get(5).unwrap(),
+            SmithMeta {
+                status: SmithStatus::Pending,
+                expires_on: Some(5),
+                issued_certs: vec![],
+                received_certs: vec![1],
+            }
+        );
+        // Then certification 2/2
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(2),
+            5
+        ));
+        System::assert_has_event(RuntimeEvent::Smith(
+            Event::<Runtime>::CertificationReceived {
+                idty_index: 5,
+                issued_by: 1,
+            },
+        ));
+        System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::PromotedToSmith {
+            idty_index: 5,
+        }));
+        assert_eq!(
+            Smiths::<Runtime>::get(5).unwrap(),
+            SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: Some(5),
+                issued_certs: vec![],
+                received_certs: vec![1, 2],
+            }
+        );
+        // Go online to be able to invite+certify
+        Pallet::<Runtime>::on_smith_goes_offline(1);
+        Pallet::<Runtime>::on_smith_goes_offline(2);
+
+        // On session 4 everything if fine
+        Pallet::<Runtime>::on_new_session(4);
+        assert!(Smiths::<Runtime>::get(1).is_some());
+        assert!(Smiths::<Runtime>::get(2).is_some());
+        assert!(Smiths::<Runtime>::get(5).is_some());
+        // On session 5 no more smiths because of lack of activity
+        Pallet::<Runtime>::on_new_session(5);
+        System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::SmithExcluded {
+            idty_index: 1,
+        }));
+        System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::SmithExcluded {
+            idty_index: 2,
+        }));
+        System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::SmithExcluded {
+            idty_index: 5,
+        }));
+        assert_eq!(
+            Smiths::<Runtime>::get(1),
+            Some(SmithMeta {
+                status: SmithStatus::Excluded,
+                expires_on: None,
+                issued_certs: vec![],
+                received_certs: vec![]
+            })
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(2),
+            Some(SmithMeta {
+                status: SmithStatus::Excluded,
+                expires_on: None,
+                issued_certs: vec![],
+                received_certs: vec![]
+            })
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(5),
+            Some(SmithMeta {
+                status: SmithStatus::Excluded,
+                expires_on: None,
+                issued_certs: vec![],
+                received_certs: vec![]
+            })
+        );
+    });
+}
+
+#[test]
+fn should_have_checks_on_certify() {
+    new_test_ext(GenesisConfig {
+        initial_smiths: btreemap![
+            1 => (false, vec![2, 3, 4]),
+            2 => (false, vec![3, 4]),
+            3 => (false, vec![4]),
+            4 => (false, vec![1, 2]),
+        ],
+    })
+    .execute_with(|| {
+        // Go online to be able to invite+certify
+        Pallet::<Runtime>::on_smith_goes_online(1);
+        // Initially
+        assert_eq!(
+            Smiths::<Runtime>::get(1).unwrap(),
+            SmithMeta {
+                status: Smith,
+                expires_on: None,
+                issued_certs: vec![4],
+                received_certs: vec![2, 3, 4],
+            }
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(2).unwrap(),
+            SmithMeta {
+                status: Smith,
+                expires_on: Some(5),
+                issued_certs: vec![1, 4],
+                received_certs: vec![3, 4],
+            }
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(3).unwrap(),
+            SmithMeta {
+                status: Pending,
+                expires_on: Some(5),
+                issued_certs: vec![1, 2],
+                received_certs: vec![4],
+            }
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(4).unwrap(),
+            SmithMeta {
+                status: Smith,
+                expires_on: Some(5),
+                issued_certs: vec![1, 2, 3],
+                received_certs: vec![1, 2],
+            }
+        );
+
+        // Tries all possible errors
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(0), 1),
+            Error::<Runtime>::OriginHasNeverBeenInvited
+        );
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 1),
+            Error::<Runtime>::CertificationOfSelfIsForbidden
+        );
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(3), 5),
+            Error::<Runtime>::CertificationIsASmithPrivilege
+        );
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 6),
+            Error::<Runtime>::CertificationReceiverMustHaveBeenInvited
+        );
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 4),
+            Error::<Runtime>::CertificationAlreadyExists
+        );
+
+        // #3: state before
+        assert_eq!(
+            Smiths::<Runtime>::get(3).unwrap(),
+            SmithMeta {
+                status: Pending,
+                expires_on: Some(5),
+                issued_certs: vec![1, 2],
+                received_certs: vec![4],
+            }
+        );
+        // Try to certify #3
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(1),
+            3
+        ));
+        // #3: state after
+        assert_eq!(
+            Smiths::<Runtime>::get(3).unwrap(),
+            SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: Some(5),
+                issued_certs: vec![1, 2],
+                received_certs: vec![1, 4],
+            }
+        );
+    });
+}
+
+#[test]
+fn smith_activity_postpones_expiration() {
+    new_test_ext(GenesisConfig {
+        initial_smiths: btreemap![
+            1 => (false, vec![2, 3, 4]),
+            2 => (false, vec![3, 4]),
+            3 => (false, vec![]),
+            4 => (false, vec![])
+        ],
+    })
+    .execute_with(|| {
+        // On session 4 everything is fine
+        Pallet::<Runtime>::on_new_session(4);
+        assert!(Smiths::<Runtime>::get(1).is_some());
+        assert!(Smiths::<Runtime>::get(2).is_some());
+
+        // Smith #2 is online but not #1
+        Pallet::<Runtime>::on_smith_goes_online(2);
+
+        // On session 5: exclusion for lack of activity
+        Pallet::<Runtime>::on_new_session(5);
+        assert_eq!(
+            Smiths::<Runtime>::get(1),
+            Some(SmithMeta {
+                status: SmithStatus::Excluded,
+                expires_on: None,
+                issued_certs: vec![],
+                received_certs: vec![]
+            })
+        );
+        // issued_certs is empty because #1 was excluded
+        assert_eq!(
+            Smiths::<Runtime>::get(2),
+            Some(SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: None,
+                issued_certs: vec![],
+                received_certs: vec![3, 4],
+            })
+        );
+
+        // Smith #2 goes offline
+        Pallet::<Runtime>::on_new_session(6);
+        Pallet::<Runtime>::on_smith_goes_offline(2);
+        assert_eq!(
+            Smiths::<Runtime>::get(2),
+            Some(SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: Some(11),
+                issued_certs: vec![],
+                received_certs: vec![3, 4],
+            })
+        );
+        // Still not expired on session 10
+        Pallet::<Runtime>::on_new_session(10);
+        assert_eq!(
+            Smiths::<Runtime>::get(2),
+            Some(SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: Some(11),
+                issued_certs: vec![],
+                received_certs: vec![3, 4],
+            })
+        );
+        // But expired on session 11
+        Pallet::<Runtime>::on_new_session(11);
+        assert_eq!(
+            Smiths::<Runtime>::get(1),
+            Some(SmithMeta {
+                status: SmithStatus::Excluded,
+                expires_on: None,
+                issued_certs: vec![],
+                received_certs: vec![]
+            })
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(2),
+            Some(SmithMeta {
+                status: SmithStatus::Excluded,
+                expires_on: None,
+                issued_certs: vec![],
+                received_certs: vec![]
+            })
+        );
+    });
+}
+
+#[test]
+fn smith_coming_back_recovers_its_issued_certs() {
+    new_test_ext(GenesisConfig {
+        initial_smiths: btreemap![
+            1 => (false, vec![2, 3, 4]),
+            2 => (false, vec![3, 4]),
+            3 => (false, vec![1, 4]),
+            4 => (false, vec![]),
+        ],
+    })
+    .execute_with(|| {
+        // Not activity for Smith #2
+        Pallet::<Runtime>::on_smith_goes_online(1);
+        Pallet::<Runtime>::on_smith_goes_online(3);
+        Pallet::<Runtime>::on_smith_goes_online(4);
+        // Smith #2 gets excluded
+        Pallet::<Runtime>::on_new_session(5);
+        // The issued certs are preserved
+        assert_eq!(
+            Smiths::<Runtime>::get(2),
+            Some(SmithMeta {
+                status: Excluded,
+                expires_on: None,
+                issued_certs: vec![1],
+                received_certs: vec![]
+            })
+        );
+        // Smith #2 comes back
+        assert_ok!(Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 2));
+        assert_ok!(Pallet::<Runtime>::accept_invitation(RuntimeOrigin::signed(
+            2
+        )));
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(1),
+            2
+        ));
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(3),
+            2
+        ));
+        // Smith #2 is back with its issued certs recovered, but not its received certs
+        assert_eq!(
+            Smiths::<Runtime>::get(2),
+            Some(SmithMeta {
+                status: Smith,
+                expires_on: Some(10),
+                issued_certs: vec![1],
+                received_certs: vec![1, 3]
+            })
+        );
+        Pallet::<Runtime>::on_smith_goes_online(2);
+        // We can verify it with the stock rule
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(2),
+            3
+        ));
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(2),
+            4
+        ));
+        // Max stock is reached (3 = 1 recovered + 2 new)
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(2), 5),
+            Error::<Runtime>::CertificationStockFullyConsumed
+        );
+    });
+}
+
+#[test]
+fn certifying_on_different_status() {
+    new_test_ext(GenesisConfig {
+        initial_smiths: btreemap![
+            1 => (false, vec![2, 3, 4]),
+            2 => (false, vec![3, 4]),
+            3 => (false, vec![1, 2]),
+            4 => (false, vec![]),
+        ],
+    })
+    .execute_with(|| {
+        // Go online to be able to invite+certify
+        Pallet::<Runtime>::on_smith_goes_online(1);
+        Pallet::<Runtime>::on_smith_goes_online(2);
+        Pallet::<Runtime>::on_smith_goes_online(3);
+        // State before
+        assert_eq!(Smiths::<Runtime>::get(5), None);
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5),
+            Error::<Runtime>::CertificationReceiverMustHaveBeenInvited
+        );
+
+        // After invitation
+        assert_ok!(Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 5));
+        assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Invited);
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5),
+            Error::<Runtime>::CertificationMustBeAgreed
+        );
+
+        // After acceptation
+        assert_ok!(Pallet::<Runtime>::accept_invitation(RuntimeOrigin::signed(
+            5
+        )));
+        assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Pending);
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(1),
+            5
+        ));
+        assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Pending);
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(2),
+            5
+        ));
+        assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Smith);
+
+        // After being a smith
+        assert_ok!(Pallet::<Runtime>::certify_smith(
+            RuntimeOrigin::signed(3),
+            5
+        ));
+
+        Pallet::<Runtime>::on_smith_goes_online(1);
+        Pallet::<Runtime>::on_smith_goes_online(2);
+        Pallet::<Runtime>::on_new_session(5);
+        assert_eq!(Smiths::<Runtime>::get(1).unwrap().status, Smith);
+        assert_eq!(Smiths::<Runtime>::get(2).unwrap().status, Smith);
+        assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Excluded);
+
+        // After being excluded
+        assert_err!(
+            Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5),
+            Error::<Runtime>::CertificationOnExcludedIsForbidden
+        );
+    });
+}
+
+#[test]
+fn invitation_on_non_wot_member() {
+    new_test_ext(GenesisConfig {
+        initial_smiths: btreemap![
+            1 => (false, vec![2, 3, 4]),
+            2 => (false, vec![3, 4]),
+            3 => (false, vec![1, 2]),
+            4 => (false, vec![]),
+        ],
+    })
+    .execute_with(|| {
+        // Go online to be able to invite+certify
+        Pallet::<Runtime>::on_smith_goes_online(1);
+        // State before
+        assert_eq!(Smiths::<Runtime>::get(10), None);
+
+        // After invitation
+        assert_err!(
+            Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 10),
+            Error::<Runtime>::InvitationOfNonMember
+        );
+    });
+}
+
+#[test]
+fn losing_wot_membership_cascades_to_smith_members() {
+    new_test_ext(GenesisConfig {
+        initial_smiths: btreemap![
+            1 => (false, vec![2, 3, 4]),
+            2 => (false, vec![3, 4]),
+            3 => (false, vec![1, 2]),
+            4 => (false, vec![]),
+        ],
+    })
+    .execute_with(|| {
+        // State before
+        assert_eq!(
+            Smiths::<Runtime>::get(1),
+            Some(SmithMeta {
+                status: Smith,
+                expires_on: Some(5),
+                issued_certs: vec![3],
+                received_certs: vec![2, 3, 4],
+            })
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(1).unwrap().issued_certs,
+            Vec::<u64>::from([3])
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(2).unwrap().issued_certs,
+            Vec::<u64>::from([1, 3])
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(3).unwrap().issued_certs,
+            Vec::<u64>::from([1, 2])
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(4).unwrap().issued_certs,
+            Vec::<u64>::from([1, 2])
+        );
+
+        Pallet::<Runtime>::on_removed_wot_member(1);
+
+        // Excluded
+        assert_eq!(
+            Smiths::<Runtime>::get(1),
+            Some(SmithMeta {
+                status: Excluded,
+                expires_on: None,
+                issued_certs: vec![3],
+                received_certs: vec![],
+            })
+        );
+        // Issued certifications updated for certifiers of 1
+        assert_eq!(
+            Smiths::<Runtime>::get(1).unwrap().issued_certs,
+            Vec::<u64>::from([3])
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(2).unwrap().issued_certs,
+            Vec::<u64>::from([3])
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(3).unwrap().issued_certs,
+            Vec::<u64>::from([2])
+        );
+        assert_eq!(
+            Smiths::<Runtime>::get(4).unwrap().issued_certs,
+            Vec::<u64>::from([2])
+        );
+    });
+}
diff --git a/pallets/smith-members/src/traits.rs b/pallets/smith-members/src/traits.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f59b6fc1c775e15ba69e32704da9238516a18db4
--- /dev/null
+++ b/pallets/smith-members/src/traits.rs
@@ -0,0 +1,8 @@
+use crate::SmithRemovalReason;
+
+pub trait OnSmithDelete<IdtyIndex> {
+    fn on_smith_delete(idty_index: IdtyIndex, reason: SmithRemovalReason);
+}
+impl<IdtyIndex> OnSmithDelete<IdtyIndex> for () {
+    fn on_smith_delete(_: IdtyIndex, _: SmithRemovalReason) {}
+}
diff --git a/pallets/smith-members/src/types.rs b/pallets/smith-members/src/types.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fcccd3468e8c6577e3dc68d9781fc3decc7b5c58
--- /dev/null
+++ b/pallets/smith-members/src/types.rs
@@ -0,0 +1,49 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+//! Various basic types for use in the identity pallet.
+
+use crate::SmithStatus;
+use codec::{Decode, Encode};
+use frame_support::pallet_prelude::*;
+use scale_info::TypeInfo;
+use sp_staking::SessionIndex;
+use sp_std::vec::Vec;
+
+/// certification metadata attached to an identity
+#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+pub struct SmithMeta<IdtyIndex> {
+    /// current status of the smith
+    pub status: SmithStatus,
+    /// the session at which the smith will expire (for lack of validation activity)
+    pub expires_on: Option<SessionIndex>,
+    /// the certifications issued to other smiths
+    pub issued_certs: Vec<IdtyIndex>,
+    /// the certifications received from other smiths
+    pub received_certs: Vec<IdtyIndex>,
+}
+
+/// By default, a smith has the least possible privileges
+impl<IdtyIndex> Default for SmithMeta<IdtyIndex> {
+    fn default() -> Self {
+        Self {
+            status: SmithStatus::Excluded,
+            expires_on: None,
+            issued_certs: Vec::<IdtyIndex>::new(),
+            received_certs: Vec::<IdtyIndex>::new(),
+        }
+    }
+}
diff --git a/pallets/smith-members/src/weights.rs b/pallets/smith-members/src/weights.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b18e0cef9fe76aa09afbd4b3544cfcd21652ac0d
--- /dev/null
+++ b/pallets/smith-members/src/weights.rs
@@ -0,0 +1,38 @@
+// Copyright 2021-2023 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+#![allow(clippy::unnecessary_cast)]
+
+use frame_support::weights::Weight;
+
+/// Weight functions needed for pallet.
+pub trait WeightInfo {
+    fn invite_smith() -> Weight;
+    fn accept_invitation() -> Weight;
+    fn certify_smith() -> Weight;
+}
+
+impl WeightInfo for () {
+    fn invite_smith() -> Weight {
+        Weight::zero()
+    }
+    fn accept_invitation() -> Weight {
+        Weight::zero()
+    }
+    fn certify_smith() -> Weight {
+        Weight::zero()
+    }
+}
diff --git a/resources/gdev.yaml b/resources/gdev.yaml
index 80296c9699bd4309bd795bcd3ea1e1bc74075a78..a901457535966732d744522220a1b26ce5dfe1ee 100644
--- a/resources/gdev.yaml
+++ b/resources/gdev.yaml
@@ -41,20 +41,10 @@ parameters:
   wot_min_cert_for_create_idty_right: 3
 
   # ----- SMITH WOT -----
-  # Duration to wait between two emitted certifications, in blocks. 14400 blocks = 24h = 1 day.
-  smith_cert_period: 14400
   # Maximum quantity of currently valid certifications emitted by a same issuer. 15 certs.
   smith_cert_max_by_issuer: 15
-  # Minimum quantity of smith certifications received to be able to smith certify someone else.
-  smith_cert_min_received_cert_to_issue_cert: 3
-  # Validity duration of a certification, in blocks. 2102400 blocks = 146 days.
-  smith_cert_validity_period: 2102400
-  # Validity duration of a membership. 1051200 blocks = 73 days.
-  smith_membership_period: 1051200
-  # Validity duration of a pending membership. 172800 blocks = 12 days.
-  smith_pending_membership_period: 172800
-  # Delay a new smith member must observe before being able to emit a smith certification. 14400 blocks = 24h = 1 day.
-  smith_wot_first_cert_issuable_on: 14400
+  # Maximum duration a smith can be offline without being excluded
+  smith_inactivity_max_duration: 48
   # Number of required received smith certs to become a smith member
   smith_wot_min_cert_for_membership: 3
 
diff --git a/resources/metadata.scale b/resources/metadata.scale
index 86dc5fa76adcc7628a8dd62903866e06603f0719..d9b927842841c74ddf26cd400b3b4a304a3c6eeb 100644
Binary files a/resources/metadata.scale and b/resources/metadata.scale differ
diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml
index 620eb3c8c23fbc1ebbc97cec505f161934325897..04ca8dd0cb301d281b95f7a23ae3e6821c12f2d4 100644
--- a/runtime/common/Cargo.toml
+++ b/runtime/common/Cargo.toml
@@ -35,6 +35,7 @@ std = [
     'frame-system/std',
     'log/std',
     'pallet-authority-members/std',
+    'pallet-smith-members/std',
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
@@ -73,6 +74,7 @@ try-runtime = [
 [dependencies]
 duniter-primitives = { path = '../../primitives/duniter', default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
+pallet-smith-members = { path = '../../pallets/smith-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-distance = { path = "../../pallets/distance", default-features = false }
 pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false }
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index 8cb679c6680d6a74ac760d6a4556dc6744fbc4df..c529252726f47da3cdfd6754e6b067047bd63d56 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -17,9 +17,8 @@
 use super::entities::*;
 use super::{AccountId, IdtyIndex};
 use frame_support::dispatch::UnfilteredDispatchable;
-use frame_support::instances::{Instance1, Instance2};
 use frame_support::pallet_prelude::Weight;
-use frame_support::Parameter;
+use pallet_smith_members::SmithRemovalReason;
 
 // new session handler
 pub struct OnNewSessionHandler<Runtime>(core::marker::PhantomData<Runtime>);
@@ -39,7 +38,8 @@ impl<
         Inner: sp_membership::traits::OnEvent<IdtyIndex>,
         Runtime: frame_system::Config<AccountId = AccountId>
             + pallet_identity::Config<IdtyData = IdtyData, IdtyIndex = IdtyIndex>
-            + pallet_membership::Config<Instance1>
+            + pallet_membership::Config
+            + pallet_smith_members::Config<IdtyIndex = IdtyIndex>
             + pallet_universal_dividend::Config,
     > sp_membership::traits::OnEvent<IdtyIndex> for OnMembershipEventHandler<Inner, Runtime>
 {
@@ -55,6 +55,7 @@ impl<
                         );
                     }
                 }
+                pallet_smith_members::Pallet::<Runtime>::on_removed_wot_member(*idty_index);
             }
             // when main membership is acquired, it starts getting right to UD
             sp_membership::Event::MembershipAdded(idty_index) => {
@@ -75,60 +76,6 @@ impl<
     }
 }
 
-// smith membership event handler
-pub struct OnSmithMembershipEventHandler<Inner, Runtime>(
-    core::marker::PhantomData<(Inner, Runtime)>,
-);
-impl<
-        IdtyIndex: Copy + Parameter,
-        Inner: sp_membership::traits::OnEvent<IdtyIndex>,
-        Runtime: frame_system::Config<AccountId = AccountId>
-            + pallet_identity::Config<IdtyIndex = IdtyIndex>
-            + pallet_authority_members::Config<MemberId = IdtyIndex>
-            + pallet_membership::Config<Instance2>,
-    > sp_membership::traits::OnEvent<IdtyIndex> for OnSmithMembershipEventHandler<Inner, Runtime>
-{
-    fn on_event(membership_event: &sp_membership::Event<IdtyIndex>) {
-        (match membership_event {
-            sp_membership::Event::MembershipAdded(_idty_index) => {
-                // nothing when smith membership acquired
-                // user will have to claim authority membership
-            }
-            sp_membership::Event::MembershipRemoved(idty_index) => {
-                let call = pallet_authority_members::Call::<Runtime>::remove_member {
-                    member_id: *idty_index,
-                };
-                if let Err(e) =
-                    call.dispatch_bypass_filter(frame_system::Origin::<Runtime>::Root.into())
-                {
-                    sp_std::if_std! {
-                        println!("faid to remove member: {:?}", e)
-                    }
-                }
-            }
-            _ => (),
-        });
-        Inner::on_event(membership_event)
-    }
-}
-
-// authority member removal handler
-// TODO refac smith wot
-// or document the link between smith membership and authority member
-pub struct OnRemovedAuthorityMemberHandler<Runtime>(core::marker::PhantomData<Runtime>);
-impl<Runtime> pallet_authority_members::traits::OnRemovedMember<IdtyIndex>
-    for OnRemovedAuthorityMemberHandler<Runtime>
-where
-    Runtime: frame_system::Config + pallet_membership::Config<Instance2, IdtyId = IdtyIndex>,
-{
-    fn on_removed_member(idty_index: IdtyIndex) {
-        pallet_membership::Pallet::<Runtime, Instance2>::do_remove_membership(
-            idty_index,
-            pallet_membership::MembershipRemovalReason::System,
-        );
-    }
-}
-
 // spend treasury handler
 pub struct TreasurySpendFunds<Runtime>(core::marker::PhantomData<Runtime>);
 impl<Runtime> pallet_treasury::SpendFunds<Runtime> for TreasurySpendFunds<Runtime>
@@ -144,3 +91,21 @@ where
         *missed_any = true;
     }
 }
+
+pub struct OnSmithDeletedHandler<Runtime>(core::marker::PhantomData<Runtime>);
+impl<Runtime> pallet_smith_members::traits::OnSmithDelete<Runtime::MemberId>
+    for OnSmithDeletedHandler<Runtime>
+where
+    Runtime: pallet_authority_members::Config,
+{
+    fn on_smith_delete(idty_index: Runtime::MemberId, _reason: SmithRemovalReason) {
+        let call = pallet_authority_members::Call::<Runtime>::remove_member {
+            member_id: idty_index,
+        };
+        if let Err(e) = call.dispatch_bypass_filter(frame_system::Origin::<Runtime>::Root.into()) {
+            sp_std::if_std! {
+                println!("faid to remove member: {:?}", e)
+            }
+        }
+    }
+}
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index e61c1996d27c25bf6d78855917b6e09e5b954944..f1cfbf2995723fa7e5fdd2bae33afb1dfeea721b 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -236,14 +236,15 @@ macro_rules! pallets_config {
         }
         impl pallet_authority_members::Config for Runtime {
             type RuntimeEvent = RuntimeEvent;
-            type IsMember = SmithMembership;
+            type IsMember = SmithMembers;
             type OnNewSession = OnNewSessionHandler<Runtime>;
-            type OnRemovedMember = OnRemovedAuthorityMemberHandler<Runtime>;
             type MemberId = IdtyIndex;
             type MemberIdOf = common_runtime::providers::IdentityIndexOf<Self>;
             type MaxAuthorities = MaxAuthorities;
             type RemoveMemberOrigin = EnsureRoot<Self::AccountId>;
 			type WeightInfo = common_runtime::weights::pallet_authority_members::WeightInfo<Runtime>;
+            type OnIncomingMember = SmithMembers;
+            type OnOutgoingMember = SmithMembers;
         }
         impl pallet_authorship::Config for Runtime {
             type EventHandler = ImOnline;
@@ -453,11 +454,9 @@ macro_rules! pallets_config {
 
         // WEB OF TRUST //
 
-        use frame_support::instances::Instance1;
-        impl pallet_duniter_wot::Config<Instance1> for Runtime {
+        impl pallet_duniter_wot::Config for Runtime {
             type FirstIssuableOn = WotFirstCertIssuableOn;
             type IsDistanceOk = common_runtime::providers::MainWotIsDistanceOk<Runtime>;
-            type IsSubWot = frame_support::traits::ConstBool<false>;
             type MinCertForMembership = WotMinCertForMembership;
             type MinCertForCreateIdtyRight = WotMinCertForCreateIdtyRight;
         }
@@ -473,7 +472,7 @@ macro_rules! pallets_config {
             type ValidationPeriod = ValidationPeriod;
             type AutorevocationPeriod = AutorevocationPeriod;
             type DeletionPeriod = DeletionPeriod;
-            type CheckIdtyCallAllowed = (Wot, SmithSubWot);
+            type CheckIdtyCallAllowed = Wot;
             type IdtyCreationPeriod = IdtyCreationPeriod;
 			type IdtyData = IdtyData;
             type IdtyIndex = IdtyIndex;
@@ -481,12 +480,12 @@ macro_rules! pallets_config {
             type IdtyNameValidator = IdtyNameValidatorImpl;
             type Signer = <Signature as sp_runtime::traits::Verify>::Signer;
 			type Signature = Signature;
-            type OnIdtyChange = (Wot, SmithSubWot, Quota);
+            type OnIdtyChange = (Wot, Quota);
             type RuntimeEvent = RuntimeEvent;
             type WeightInfo = common_runtime::weights::pallet_identity::WeightInfo<Runtime>;
         }
 
-        impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime {
+        impl pallet_membership::Config for Runtime {
             type CheckMembershipCallAllowed = Wot;
             type IdtyId = IdtyIndex;
             type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>;
@@ -499,7 +498,7 @@ macro_rules! pallets_config {
             type BenchmarkSetupHandler = common_runtime::providers::BenchmarkSetupHandler<Runtime>;
         }
 
-        impl pallet_certification::Config<Instance1> for Runtime {
+        impl pallet_certification::Config for Runtime {
             type CertPeriod = CertPeriod;
             type IdtyIndex = IdtyIndex;
             type OwnerKeyOf = Identity;
@@ -525,42 +524,21 @@ macro_rules! pallets_config {
             type WeightInfo = common_runtime::weights::pallet_distance::WeightInfo<Runtime>;
         }
 
-        // SMITHS SUB-WOT //
-
-        use frame_support::instances::Instance2;
-        impl pallet_duniter_wot::Config<Instance2> for Runtime {
-            type FirstIssuableOn = SmithWotFirstCertIssuableOn;
-            type IsDistanceOk = pallet_duniter_wot::traits::DistanceAlwaysOk;
-            type IsSubWot = frame_support::traits::ConstBool<true>;
-            type MinCertForMembership = SmithWotMinCertForMembership;
-            type MinCertForCreateIdtyRight = frame_support::traits::ConstU32<0>;
-        }
-
-        impl pallet_membership::Config<Instance2> for Runtime {
-            type CheckMembershipCallAllowed = SmithSubWot;
-            type IdtyId = IdtyIndex;
-            type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>;
-            type AccountIdOf = common_runtime::providers::IdentityAccountIdProvider<Self>;
-            type MembershipPeriod = SmithMembershipPeriod;
-            type OnEvent = OnSmithMembershipEventHandler<SmithSubWot, Runtime>;
+        // SMITH-MEMBERS
+        impl pallet_smith_members::Config for Runtime {
             type RuntimeEvent = RuntimeEvent;
-            type WeightInfo = common_runtime::weights::pallet_membership_smith_membership::WeightInfo<Runtime>;
-            #[cfg(feature = "runtime-benchmarks")]
-            type BenchmarkSetupHandler = common_runtime::providers::BenchmarkSetupHandler<Runtime>;
-        }
-
-        impl pallet_certification::Config<Instance2> for Runtime {
-            type CertPeriod = SmithCertPeriod;
             type IdtyIndex = IdtyIndex;
-            type OwnerKeyOf = Identity;
-            type CheckCertAllowed = SmithSubWot;
+            type IsWoTMember = common_runtime::providers::IsWoTMemberProvider<Runtime>;
+            type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>;
+            type MinCertForMembership = SmithWotMinCertForMembership;
             type MaxByIssuer = SmithMaxByIssuer;
-            type MinReceivedCertToBeAbleToIssueCert = SmithMinReceivedCertToBeAbleToIssueCert;
-            type OnNewcert = SmithSubWot;
-            type OnRemovedCert = SmithSubWot;
-            type RuntimeEvent = RuntimeEvent;
-            type WeightInfo = common_runtime::weights::pallet_certification_smith_cert::WeightInfo<Runtime>;
-            type ValidityPeriod = SmithValidityPeriod;
+            type SmithInactivityMaxDuration = SmithInactivityMaxDuration;
+            type OnSmithDelete = OnSmithDeletedHandler<Runtime>;
+            type IdtyIdOfAuthorityId = sp_runtime::traits::ConvertInto;
+            type MemberId = IdtyIndex;
+            type WeightInfo = common_runtime::weights::pallet_smith_members::WeightInfo<Runtime>;
+            // TODO: remove as it is only used for benchmarking
+            type OwnerKeyOf = Identity;
         }
 
         pub struct TechnicalCommitteeDefaultVote;
diff --git a/runtime/common/src/providers.rs b/runtime/common/src/providers.rs
index 1518c1060e265e01dd49ba6a02e1b1418405a93a..ca631988e74cfd3b19417be348605c4bd58d5574 100644
--- a/runtime/common/src/providers.rs
+++ b/runtime/common/src/providers.rs
@@ -76,7 +76,7 @@ pub struct MainWotIsDistanceOk<T>(PhantomData<T>);
 impl<T> pallet_duniter_wot::traits::IsDistanceOk<<T as pallet_identity::Config>::IdtyIndex>
     for MainWotIsDistanceOk<T>
 where
-    T: pallet_distance::Config + pallet_duniter_wot::Config<frame_support::instances::Instance1>,
+    T: pallet_distance::Config + pallet_duniter_wot::Config,
 {
     fn is_distance_ok(
         idty_id: &<T as pallet_identity::Config>::IdtyIndex,
@@ -84,11 +84,27 @@ where
         match pallet_distance::Pallet::<T>::identity_distance_status(idty_id) {
             Some((_, status)) => match status {
                 pallet_distance::DistanceStatus::Valid => Ok(()),
-                pallet_distance::DistanceStatus::Invalid => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceIsInvalid.into()),
-                pallet_distance::DistanceStatus::Pending => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceEvaluationPending.into()),
+                pallet_distance::DistanceStatus::Invalid => {
+                    Err(pallet_duniter_wot::Error::<T>::DistanceIsInvalid.into())
+                }
+                pallet_distance::DistanceStatus::Pending => {
+                    Err(pallet_duniter_wot::Error::<T>::DistanceEvaluationPending.into())
+                }
             },
-			None => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceEvaluationNotRequested.into()),
-		}
+            None => Err(pallet_duniter_wot::Error::<T>::DistanceEvaluationNotRequested.into()),
+        }
+    }
+}
+
+pub struct IsWoTMemberProvider<T>(PhantomData<T>);
+impl<T: pallet_smith_members::Config>
+    sp_runtime::traits::IsMember<<T as pallet_membership::Config>::IdtyId>
+    for IsWoTMemberProvider<T>
+where
+    T: pallet_distance::Config + pallet_membership::Config,
+{
+    fn is_member(idty_id: &T::IdtyId) -> bool {
+        pallet_membership::Pallet::<T>::is_member(idty_id)
     }
 }
 
@@ -102,8 +118,8 @@ macro_rules! impl_benchmark_setup_handler {
         impl<T> $t for BenchmarkSetupHandler<T>
         where
             T: pallet_distance::Config,
-            T: pallet_certification::Config<frame_support::instances::Instance1>,
-            <T as pallet_certification::Config<frame_support::instances::Instance1>>::IdtyIndex: From<u32>,
+            T: pallet_certification::Config,
+            <T as pallet_certification::Config>::IdtyIndex: From<u32>,
         {
             fn force_status_ok(
                 idty_id: &IdtyIndex,
@@ -115,7 +131,11 @@ macro_rules! impl_benchmark_setup_handler {
                 );
             }
             fn add_cert(issuer: &IdtyIndex, receiver: &IdtyIndex) {
-                let _ = pallet_certification::Pallet::<T, frame_support::instances::Instance1>::do_add_cert_checked((*issuer).into(), (*receiver).into(), false);
+                let _ = pallet_certification::Pallet::<T>::do_add_cert_checked(
+                    (*issuer).into(),
+                    (*receiver).into(),
+                    false,
+                );
             }
         }
     };
diff --git a/runtime/common/src/weights.rs b/runtime/common/src/weights.rs
index 60201d11e1e880b00a73b7a0042abd3315d76cf4..bf1e188a998c36de5146576e3317b1f0627d16b4 100644
--- a/runtime/common/src/weights.rs
+++ b/runtime/common/src/weights.rs
@@ -44,8 +44,7 @@ pub mod pallet_duniter_account;
 pub mod pallet_quota;
 pub mod pallet_oneshot_account;
 pub mod pallet_certification_cert;
-pub mod pallet_certification_smith_cert;
 pub mod pallet_membership_membership;
-pub mod pallet_membership_smith_membership;
+pub mod pallet_smith_members;
 pub mod pallet_authority_members;
 pub mod paritydb_weights;
diff --git a/runtime/common/src/weights/pallet_certification_smith_cert.rs b/runtime/common/src/weights/pallet_certification_smith_cert.rs
deleted file mode 100644
index 7403ec2d9d9d0ad2b5eaca27b031942da3ce8477..0000000000000000000000000000000000000000
--- a/runtime/common/src/weights/pallet_certification_smith_cert.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2021-2022 Axiom-Team
-//
-// This file is part of Duniter-v2S.
-//
-// Duniter-v2S is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, version 3 of the License.
-//
-// Duniter-v2S is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
-
-//! Autogenerated weights for `pallet_certification`
-//!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-12-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `bgallois-ms7d43`, CPU: `12th Gen Intel(R) Core(TM) i3-12100F`
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
-
-// Executed Command:
-// target/release/duniter
-// benchmark
-// pallet
-// --chain=dev
-// --steps=50
-// --repeat=20
-// --pallet=*
-// --extrinsic=*
-// --execution=wasm
-// --wasm-execution=compiled
-// --heap-pages=4096
-// --header=file_header.txt
-// --output=runtime/common/src/weights/
-
-#![cfg_attr(rustfmt, rustfmt_skip)]
-#![allow(unused_parens)]
-#![allow(unused_imports)]
-#![allow(missing_docs)]
-
-use frame_support::{traits::Get, weights::Weight};
-use core::marker::PhantomData;
-
-/// Weight functions for `pallet_certification`.
-pub struct WeightInfo<T>(PhantomData<T>);
-impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T> {
-	/// Storage: Identity Identities (r:2 w:0)
-	/// Proof Skipped: Identity Identities (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithCert StorageIdtyCertMeta (r:2 w:2)
-	/// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Parameters ParametersStorage (r:1 w:0)
-	/// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: SmithCert StorageCertsRemovableOn (r:1 w:1)
-	/// Proof Skipped: SmithCert StorageCertsRemovableOn (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithCert CertsByReceiver (r:1 w:1)
-	/// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured)
-	fn add_cert() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `769`
-		//  Estimated: `6709`
-		// Minimum execution time: 38_312_000 picoseconds.
-		Weight::from_parts(39_872_000, 0)
-			.saturating_add(Weight::from_parts(0, 6709))
-			.saturating_add(T::DbWeight::get().reads(7))
-			.saturating_add(T::DbWeight::get().writes(4))
-	}
-	/// Storage: SmithCert CertsByReceiver (r:1 w:1)
-	/// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithCert StorageIdtyCertMeta (r:2 w:2)
-	/// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Parameters ParametersStorage (r:1 w:0)
-	/// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: SmithMembership Membership (r:1 w:0)
-	/// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured)
-	fn del_cert() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `638`
-		//  Estimated: `6578`
-		// Minimum execution time: 25_005_000 picoseconds.
-		Weight::from_parts(26_178_000, 0)
-			.saturating_add(Weight::from_parts(0, 6578))
-			.saturating_add(T::DbWeight::get().reads(5))
-			.saturating_add(T::DbWeight::get().writes(3))
-	}
-	/// Storage: SmithCert CertsByReceiver (r:1 w:1)
-	/// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithCert StorageIdtyCertMeta (r:1000 w:1000)
-	/// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Parameters ParametersStorage (r:1 w:0)
-	/// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: SmithMembership Membership (r:1 w:0)
-	/// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured)
-	/// The range of component `i` is `[2, 1000]`.
-	/// The range of component `i` is `[2, 1000]`.
-	fn remove_all_certs_received_by(i: u32, ) -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `546 + i * (35 ±0)`
-		//  Estimated: `4020 + i * (2511 ±0)`
-		// Minimum execution time: 26_616_000 picoseconds.
-		Weight::from_parts(27_240_000, 0)
-			.saturating_add(Weight::from_parts(0, 4020))
-			// Standard Error: 15_842
-			.saturating_add(Weight::from_parts(10_835_042, 0).saturating_mul(i.into()))
-			.saturating_add(T::DbWeight::get().reads(3))
-			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into())))
-			.saturating_add(T::DbWeight::get().writes(1))
-			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into())))
-			.saturating_add(Weight::from_parts(0, 2511).saturating_mul(i.into()))
-	}
-	/// Storage: SmithCert StorageCertsRemovableOn (r:1 w:0)
-	/// Proof Skipped: SmithCert StorageCertsRemovableOn (max_values: None, max_size: None, mode: Measured)
-	fn on_initialize() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `181`
-		//  Estimated: `3646`
-		// Minimum execution time: 4_084_000 picoseconds.
-		Weight::from_parts(4_316_000, 0)
-			.saturating_add(Weight::from_parts(0, 3646))
-			.saturating_add(T::DbWeight::get().reads(1))
-	}
-	/// Storage: SmithCert CertsByReceiver (r:1 w:1)
-	/// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured)
-	fn do_remove_cert_noop() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `235`
-		//  Estimated: `3700`
-		// Minimum execution time: 5_261_000 picoseconds.
-		Weight::from_parts(5_742_000, 0)
-			.saturating_add(Weight::from_parts(0, 3700))
-			.saturating_add(T::DbWeight::get().reads(1))
-			.saturating_add(T::DbWeight::get().writes(1))
-	}
-	/// Storage: SmithCert CertsByReceiver (r:1 w:1)
-	/// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithCert StorageIdtyCertMeta (r:2 w:2)
-	/// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Parameters ParametersStorage (r:1 w:0)
-	/// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: SmithMembership Membership (r:1 w:0)
-	/// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured)
-	fn do_remove_cert() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `638`
-		//  Estimated: `6578`
-		// Minimum execution time: 22_342_000 picoseconds.
-		Weight::from_parts(23_355_000, 0)
-			.saturating_add(Weight::from_parts(0, 6578))
-			.saturating_add(T::DbWeight::get().reads(5))
-			.saturating_add(T::DbWeight::get().writes(3))
-	}
-}
diff --git a/runtime/common/src/weights/pallet_membership_smith_membership.rs b/runtime/common/src/weights/pallet_membership_smith_membership.rs
deleted file mode 100644
index d0bd9f66811ae0a58d7d101a6250d6cf0e86eea9..0000000000000000000000000000000000000000
--- a/runtime/common/src/weights/pallet_membership_smith_membership.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2021-2022 Axiom-Team
-//
-// This file is part of Duniter-v2S.
-//
-// Duniter-v2S is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, version 3 of the License.
-//
-// Duniter-v2S is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
-
-//! Autogenerated weights for `pallet_membership`
-//!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-12-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `bgallois-ms7d43`, CPU: `12th Gen Intel(R) Core(TM) i3-12100F`
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
-
-// Executed Command:
-// target/release/duniter
-// benchmark
-// pallet
-// --chain=dev
-// --steps=50
-// --repeat=20
-// --pallet=*
-// --extrinsic=*
-// --execution=wasm
-// --wasm-execution=compiled
-// --heap-pages=4096
-// --header=file_header.txt
-// --output=runtime/common/src/weights/
-
-#![cfg_attr(rustfmt, rustfmt_skip)]
-#![allow(unused_parens)]
-#![allow(unused_imports)]
-#![allow(missing_docs)]
-
-use frame_support::{traits::Get, weights::Weight};
-use core::marker::PhantomData;
-
-/// Weight functions for `pallet_membership`.
-pub struct WeightInfo<T>(PhantomData<T>);
-impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
-	/// Storage: Identity IdentityIndexOf (r:1 w:0)
-	/// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithCert StorageIdtyCertMeta (r:1 w:0)
-	/// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Parameters ParametersStorage (r:1 w:0)
-	/// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: SmithMembership Membership (r:1 w:1)
-	/// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithMembership CounterForMembership (r:1 w:1)
-	/// Proof: SmithMembership CounterForMembership (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
-	/// Storage: SmithMembership MembershipsExpireOn (r:1 w:1)
-	/// Proof Skipped: SmithMembership MembershipsExpireOn (max_values: None, max_size: None, mode: Measured)
-	fn claim_membership() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `704`
-		//  Estimated: `4169`
-		// Minimum execution time: 27_429_000 picoseconds.
-		Weight::from_parts(28_797_000, 0)
-			.saturating_add(Weight::from_parts(0, 4169))
-			.saturating_add(T::DbWeight::get().reads(6))
-			.saturating_add(T::DbWeight::get().writes(3))
-	}
-	/// Storage: Identity IdentityIndexOf (r:1 w:0)
-	/// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithMembership Membership (r:1 w:1)
-	/// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Identity Identities (r:1 w:0)
-	/// Proof Skipped: Identity Identities (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithMembership MembershipsExpireOn (r:2 w:2)
-	/// Proof Skipped: SmithMembership MembershipsExpireOn (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Parameters ParametersStorage (r:1 w:0)
-	/// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured)
-	fn renew_membership() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `717`
-		//  Estimated: `6657`
-		// Minimum execution time: 28_139_000 picoseconds.
-		Weight::from_parts(28_982_000, 0)
-			.saturating_add(Weight::from_parts(0, 6657))
-			.saturating_add(T::DbWeight::get().reads(6))
-			.saturating_add(T::DbWeight::get().writes(3))
-	}
-	/// Storage: Identity IdentityIndexOf (r:1 w:0)
-	/// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithMembership Membership (r:1 w:1)
-	/// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithMembership CounterForMembership (r:1 w:1)
-	/// Proof: SmithMembership CounterForMembership (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
-	/// Storage: SmithMembership MembershipsExpireOn (r:1 w:1)
-	/// Proof Skipped: SmithMembership MembershipsExpireOn (max_values: None, max_size: None, mode: Measured)
-	/// Storage: AuthorityMembers Members (r:1 w:1)
-	/// Proof Skipped: AuthorityMembers Members (max_values: None, max_size: None, mode: Measured)
-	/// Storage: AuthorityMembers OnlineAuthorities (r:1 w:1)
-	/// Proof Skipped: AuthorityMembers OnlineAuthorities (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: AuthorityMembers AuthoritiesCounter (r:1 w:1)
-	/// Proof Skipped: AuthorityMembers AuthoritiesCounter (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: AuthorityMembers IncomingAuthorities (r:1 w:1)
-	/// Proof Skipped: AuthorityMembers IncomingAuthorities (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Session NextKeys (r:1 w:1)
-	/// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured)
-	/// Storage: System Account (r:1 w:1)
-	/// Proof: System Account (max_values: None, max_size: Some(126), added: 2601, mode: MaxEncodedLen)
-	/// Storage: Session KeyOwner (r:0 w:4)
-	/// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured)
-	fn revoke_membership() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `1183`
-		//  Estimated: `4648`
-		// Minimum execution time: 60_153_000 picoseconds.
-		Weight::from_parts(62_834_000, 0)
-			.saturating_add(Weight::from_parts(0, 4648))
-			.saturating_add(T::DbWeight::get().reads(10))
-			.saturating_add(T::DbWeight::get().writes(13))
-	}
-	fn on_initialize() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `0`
-		//  Estimated: `0`
-		// Minimum execution time: 133_000 picoseconds.
-		Weight::from_parts(157_000, 0)
-			.saturating_add(Weight::from_parts(0, 0))
-	}
-	/// Storage: SmithMembership MembershipsExpireOn (r:2 w:2)
-	/// Proof Skipped: SmithMembership MembershipsExpireOn (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithMembership Membership (r:3 w:3)
-	/// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured)
-	/// Storage: SmithMembership CounterForMembership (r:1 w:1)
-	/// Proof: SmithMembership CounterForMembership (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
-	/// Storage: AuthorityMembers Members (r:3 w:3)
-	/// Proof Skipped: AuthorityMembers Members (max_values: None, max_size: None, mode: Measured)
-	/// Storage: AuthorityMembers OnlineAuthorities (r:1 w:1)
-	/// Proof Skipped: AuthorityMembers OnlineAuthorities (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: AuthorityMembers OutgoingAuthorities (r:1 w:1)
-	/// Proof Skipped: AuthorityMembers OutgoingAuthorities (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: AuthorityMembers AuthoritiesCounter (r:1 w:1)
-	/// Proof Skipped: AuthorityMembers AuthoritiesCounter (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: AuthorityMembers IncomingAuthorities (r:1 w:1)
-	/// Proof Skipped: AuthorityMembers IncomingAuthorities (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Session NextKeys (r:3 w:3)
-	/// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured)
-	/// Storage: System Account (r:3 w:3)
-	/// Proof: System Account (max_values: None, max_size: Some(126), added: 2601, mode: MaxEncodedLen)
-	/// Storage: Session KeyOwner (r:0 w:12)
-	/// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured)
-	/// The range of component `i` is `[0, 3]`.
-	/// The range of component `i` is `[0, 3]`.
-	fn expire_memberships(i: u32, ) -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `133 + i * (515 ±0)`
-		//  Estimated: `4157 + i * (2692 ±0)`
-		// Minimum execution time: 4_794_000 picoseconds.
-		Weight::from_parts(9_091_363, 0)
-			.saturating_add(Weight::from_parts(0, 4157))
-			// Standard Error: 191_583
-			.saturating_add(Weight::from_parts(46_909_320, 0).saturating_mul(i.into()))
-			.saturating_add(T::DbWeight::get().reads(2))
-			.saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(i.into())))
-			.saturating_add(T::DbWeight::get().writes(2))
-			.saturating_add(T::DbWeight::get().writes((11_u64).saturating_mul(i.into())))
-			.saturating_add(Weight::from_parts(0, 2692).saturating_mul(i.into()))
-	}
-}
diff --git a/runtime/common/src/weights/pallet_smith_members.rs b/runtime/common/src/weights/pallet_smith_members.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a0c5d8bda61e2c89b577347e220cf7b04355ecc5
--- /dev/null
+++ b/runtime/common/src/weights/pallet_smith_members.rs
@@ -0,0 +1,105 @@
+// Copyright 2021-2022 Axiom-Team
+//
+// This file is part of Duniter-v2S.
+//
+// Duniter-v2S is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Duniter-v2S is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
+
+//! Autogenerated weights for `pallet_smith_members`
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: 2023-12-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! HOSTNAME: `MacBook-Pro-de-Cedric.local`, CPU: `<UNKNOWN>`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
+
+// Executed Command:
+// ./target/release/duniter
+// benchmark
+// pallet
+// --chain=dev
+// --steps=50
+// --repeat=20
+// --pallet=pallet-smith-members
+// --extrinsic=*
+// --execution=wasm
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --header=./file_header.txt
+// --output=./runtime/common/src/weights/
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(missing_docs)]
+
+use frame_support::{traits::Get, weights::Weight};
+use core::marker::PhantomData;
+
+/// Weight functions for `pallet_smith_members`.
+pub struct WeightInfo<T>(PhantomData<T>);
+impl<T: frame_system::Config> pallet_smith_members::WeightInfo for WeightInfo<T> {
+	/// Storage: Identity IdentityIndexOf (r:1 w:0)
+	/// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured)
+	/// Storage: SmithMembers Smiths (r:2 w:1)
+	/// Proof Skipped: SmithMembers Smiths (max_values: None, max_size: None, mode: Measured)
+	/// Storage: Membership Membership (r:1 w:0)
+	/// Proof Skipped: Membership Membership (max_values: None, max_size: None, mode: Measured)
+	/// Storage: SmithMembers CurrentSession (r:1 w:0)
+	/// Proof Skipped: SmithMembers CurrentSession (max_values: Some(1), max_size: None, mode: Measured)
+	/// Storage: Parameters ParametersStorage (r:1 w:0)
+	/// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured)
+	/// Storage: SmithMembers ExpiresOn (r:1 w:1)
+	/// Proof Skipped: SmithMembers ExpiresOn (max_values: None, max_size: None, mode: Measured)
+	fn invite_smith() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `731`
+		//  Estimated: `6671`
+		// Minimum execution time: 28_000_000 picoseconds.
+		Weight::from_parts(28_000_000, 0)
+			.saturating_add(Weight::from_parts(0, 6671))
+			.saturating_add(T::DbWeight::get().reads(7))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: Identity IdentityIndexOf (r:1 w:0)
+	/// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured)
+	/// Storage: SmithMembers Smiths (r:1 w:1)
+	/// Proof Skipped: SmithMembers Smiths (max_values: None, max_size: None, mode: Measured)
+	fn accept_invitation() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `463`
+		//  Estimated: `3928`
+		// Minimum execution time: 15_000_000 picoseconds.
+		Weight::from_parts(15_000_000, 0)
+			.saturating_add(Weight::from_parts(0, 3928))
+			.saturating_add(T::DbWeight::get().reads(2))
+			.saturating_add(T::DbWeight::get().writes(1))
+	}
+	/// Storage: Identity IdentityIndexOf (r:1 w:0)
+	/// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured)
+	/// Storage: SmithMembers Smiths (r:2 w:2)
+	/// Proof Skipped: SmithMembers Smiths (max_values: None, max_size: None, mode: Measured)
+	/// Storage: Parameters ParametersStorage (r:1 w:0)
+	/// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured)
+	/// Storage: SmithMembers CurrentSession (r:1 w:0)
+	/// Proof Skipped: SmithMembers CurrentSession (max_values: Some(1), max_size: None, mode: Measured)
+	fn certify_smith() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `576`
+		//  Estimated: `6516`
+		// Minimum execution time: 24_000_000 picoseconds.
+		Weight::from_parts(26_000_000, 0)
+			.saturating_add(Weight::from_parts(0, 6516))
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+}
diff --git a/runtime/g1/Cargo.toml b/runtime/g1/Cargo.toml
index e96b7a0843152daba2cc0b0414dda1942e52494e..65207b28d2d50149694689d9dd2ba701d6fb339a 100644
--- a/runtime/g1/Cargo.toml
+++ b/runtime/g1/Cargo.toml
@@ -23,6 +23,7 @@ runtime-benchmarks = [
     'frame-system/runtime-benchmarks',
     'hex-literal',
     'pallet-authority-members/runtime-benchmarks',
+    'pallet-smith-members/runtime-benchmarks',
     'pallet-babe/runtime-benchmarks',
     'pallet-balances/runtime-benchmarks',
     'pallet-certification/runtime-benchmarks',
@@ -61,6 +62,7 @@ std = [
     'log/std',
     'pallet-authority-discovery/std',
     'pallet-authority-members/std',
+    'pallet-smith-members/std',
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
@@ -134,6 +136,7 @@ sp-keyring = { git = 'https://github.com/duniter/substrate', branch = 'duniter-s
 # local
 common-runtime = { path = "../common", default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
+pallet-smith-members = { path = '../../pallets/smith-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-distance = { path = "../../pallets/distance", default-features = false }
 pallet-duniter-test-parameters = { path = '../../pallets/duniter-test-parameters', default-features = false }
diff --git a/runtime/g1/src/lib.rs b/runtime/g1/src/lib.rs
index 8cef6bfcb4ef5219da5aa82056d79b3f256c8cf8..695fb3d39694e9decde7144b01f7de75d38d4d2c 100644
--- a/runtime/g1/src/lib.rs
+++ b/runtime/g1/src/lib.rs
@@ -66,6 +66,7 @@ use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
 
 // A few exports that help ease life for downstream crates.
+use frame_support::instances::Instance2;
 pub use frame_support::{
     construct_runtime, parameter_types,
     traits::{EqualPrivilegeOnly, KeyOwnerProofSystem, Randomness},
@@ -139,7 +140,6 @@ pub type TechnicalCommitteeInstance = Instance2;
 mod benches {
     define_benchmarks!(
         [pallet_certification, Cert]
-        [pallet_certification, SmithCert]
         [pallet_distance, Distance]
         [pallet_oneshot_account, OneshotAccount]
         [pallet_universal_dividend, UniversalDividend]
@@ -148,7 +148,7 @@ mod benches {
         [pallet_duniter_account, Account]
         [pallet_identity, Identity]
         [pallet_membership, Membership]
-        [pallet_membership, SmithMembership]
+        [pallet_smith_members, SmithMembers]
         [pallet_authority_members, AuthorityMembers]
         // Substrate
         [pallet_balances, Balances]
@@ -214,7 +214,9 @@ impl frame_support::traits::InstanceFilter<RuntimeCall> for ProxyType {
                 // Some calls are never authorized from a proxied account
                 !matches!(
                     c,
-                    RuntimeCall::Cert(..) | RuntimeCall::Identity(..) | RuntimeCall::SmithCert(..)
+                    RuntimeCall::Cert(..)
+                        | RuntimeCall::Identity(..)
+                        | RuntimeCall::SmithMembers(..)
                 )
             }
             ProxyType::TransferOnly => {
@@ -263,14 +265,15 @@ construct_runtime!(
         Quota: pallet_quota::{Pallet, Storage, Config<T>, Event<T>} = 66,
 
         // Consensus support.
-        AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
-        Authorship: pallet_authorship::{Pallet, Storage} = 11,
-        Offences: pallet_offences::{Pallet, Storage, Event} = 12,
-        Historical: session_historical::{Pallet} = 13,
-        Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 14,
-        Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 15,
-        ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 16,
-        AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 17,
+        SmithMembers: pallet_smith_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
+        AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 11,
+        Authorship: pallet_authorship::{Pallet, Storage} = 12,
+        Offences: pallet_offences::{Pallet, Storage, Event} = 13,
+        Historical: session_historical::{Pallet} = 14,
+        Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 15,
+        Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 16,
+        ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 17,
+        AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 18,
 
         // Governance stuff.
         Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>} = 20,
@@ -282,24 +285,19 @@ construct_runtime!(
         UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 30,
 
         // Web Of Trust
-        Wot: pallet_duniter_wot::<Instance1>::{Pallet} = 40,
+        Wot: pallet_duniter_wot::{Pallet} = 40,
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 41,
-        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 42,
-        Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 43,
+        Membership: pallet_membership::{Pallet, Call, Config<T>, Storage, Event<T>} = 42,
+        Cert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>} = 43,
         Distance: pallet_distance::{Pallet, Call, Storage, Inherent, Event<T>} = 44,
 
-        // Smith Sub-Wot
-        SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50,
-        SmithMembership: pallet_membership::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
-        SmithCert: pallet_certification::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53,
-
         // Utilities
-        AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60,
-        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61,
-        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62,
-        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63,
-        Utility: pallet_utility::{Pallet, Call, Event} = 64,
-        Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 65,
+        AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 50,
+        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 51,
+        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 52,
+        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 53,
+        Utility: pallet_utility::{Pallet, Call, Event} = 54,
+        Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 55,
     }
 );
 
diff --git a/runtime/g1/src/parameters.rs b/runtime/g1/src/parameters.rs
index 11315f7fce15a178460901522ace74a2a33b977b..22ef4efa43e1bf4424bbd86c5b6bf00daeb62586 100644
--- a/runtime/g1/src/parameters.rs
+++ b/runtime/g1/src/parameters.rs
@@ -117,26 +117,13 @@ parameter_types! {
 }
 
 /******************/
-/* SMITHS SUB-WOT */
+/* SMITH-MEMBERS */
 /******************/
 
 parameter_types! {
-    pub const SmithWotFirstCertIssuableOn: BlockNumber = 30 * DAYS;
     pub const SmithWotMinCertForMembership: u32 = 3;
-}
-
-// Membership
-parameter_types! {
-    pub const SmithMembershipPeriod: BlockNumber = 73 * DAYS;
-    pub const SmithPendingMembershipPeriod: BlockNumber = 12 * DAYS;
-}
-
-// Certification
-parameter_types! {
-    pub const SmithCertPeriod: BlockNumber = 5 * DAYS;
     pub const SmithMaxByIssuer: u32 = 12;
-    pub const SmithMinReceivedCertToBeAbleToIssueCert: u32 = 5;
-    pub const SmithValidityPeriod: BlockNumber = 146 * DAYS;
+    pub const SmithInactivityMaxDuration: u32 = 48;
 }
 
 /*************/
diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml
index 976999d23464736b73a55792f68b3feef4b686d4..716482251ac1f1a734150a12717684cd25317179 100644
--- a/runtime/gdev/Cargo.toml
+++ b/runtime/gdev/Cargo.toml
@@ -23,6 +23,7 @@ runtime-benchmarks = [
     'frame-system/runtime-benchmarks',
     'hex-literal',
     'pallet-authority-members/runtime-benchmarks',
+    'pallet-smith-members/runtime-benchmarks',
     'pallet-babe/runtime-benchmarks',
     'pallet-balances/runtime-benchmarks',
     'pallet-certification/runtime-benchmarks',
@@ -62,6 +63,7 @@ std = [
     'pallet-atomic-swap/std',
     'pallet-authority-discovery/std',
     'pallet-authority-members/std',
+    'pallet-smith-members/std',
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
@@ -141,6 +143,7 @@ sp-staking = { git = 'https://github.com/duniter/substrate', branch = 'duniter-s
 # local
 common-runtime = { path = "../common", default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
+pallet-smith-members = { path = '../../pallets/smith-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-distance = { path = "../../pallets/distance", default-features = false }
 pallet-duniter-test-parameters = { path = '../../pallets/duniter-test-parameters', default-features = false }
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index 5b13dec4398a09ea8847f73c876dc4892c8d5c39..544ae962dc7ce8ffe38c59f0cc464501475152fd 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -67,6 +67,7 @@ use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
 
 // A few exports that help ease life for downstream crates.
+use frame_support::instances::Instance2;
 pub use frame_support::{
     construct_runtime, parameter_types,
     traits::{EqualPrivilegeOnly, KeyOwnerProofSystem, Randomness},
@@ -141,7 +142,6 @@ pub type TechnicalCommitteeInstance = Instance2;
 mod benches {
     define_benchmarks!(
         [pallet_certification, Cert]
-        [pallet_certification, SmithCert]
         [pallet_distance, Distance]
         [pallet_oneshot_account, OneshotAccount]
         [pallet_universal_dividend, UniversalDividend]
@@ -151,7 +151,7 @@ mod benches {
         [pallet_quota, Quota]
         [pallet_identity, Identity]
         [pallet_membership, Membership]
-        [pallet_membership, SmithMembership]
+        [pallet_smith_members, SmithMembers]
         [pallet_authority_members, AuthorityMembers]
         // Substrate
         [pallet_balances, Balances]
@@ -218,7 +218,9 @@ impl frame_support::traits::InstanceFilter<RuntimeCall> for ProxyType {
                 // Some calls are never authorized from a proxied account
                 !matches!(
                     c,
-                    RuntimeCall::Cert(..) | RuntimeCall::Identity(..) | RuntimeCall::SmithCert(..)
+                    RuntimeCall::Cert(..)
+                        | RuntimeCall::Identity(..)
+                        | RuntimeCall::SmithMembers(..)
                 )
             }
             ProxyType::TransferOnly => {
@@ -261,20 +263,16 @@ common_runtime::pallets_config! {
     pub type WotMinCertForMembership = pallet_duniter_test_parameters::WotMinCertForMembership<Runtime>;
     pub type WotMinCertForCreateIdtyRight =
         pallet_duniter_test_parameters::WotMinCertForCreateIdtyRight<Runtime>;
-    pub type SmithCertPeriod = pallet_duniter_test_parameters::SmithCertPeriod<Runtime>;
     pub type SmithMaxByIssuer = pallet_duniter_test_parameters::SmithCertMaxByIssuer<Runtime>;
-    pub type SmithMinReceivedCertToBeAbleToIssueCert =
-        pallet_duniter_test_parameters::SmithCertMinReceivedCertToIssueCert<Runtime>;
-    pub type SmithValidityPeriod = pallet_duniter_test_parameters::SmithCertValidityPeriod<Runtime>;
-    pub type SmithMembershipPeriod = pallet_duniter_test_parameters::SmithMembershipPeriod<Runtime>;
-    pub type SmithWotFirstCertIssuableOn =
-        pallet_duniter_test_parameters::SmithWotFirstCertIssuableOn<Runtime>;
     pub type SmithWotMinCertForMembership =
         pallet_duniter_test_parameters::SmithWotMinCertForMembership<Runtime>;
+    pub type SmithInactivityMaxDuration =
+        pallet_duniter_test_parameters::SmithInactivityMaxDuration<Runtime>;
 
     impl pallet_duniter_test_parameters::Config for Runtime {
         type CertCount = u32;
         type PeriodCount = Balance;
+        type SessionCount = u32;
     }
 
     impl pallet_sudo::Config for Runtime {
@@ -309,14 +307,15 @@ construct_runtime!(
         Quota: pallet_quota::{Pallet, Storage, Config<T>, Event<T>} = 66,
 
         // Consensus support
-        AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
-        Authorship: pallet_authorship::{Pallet, Storage} = 11,
-        Offences: pallet_offences::{Pallet, Storage, Event} = 12,
-        Historical: session_historical::{Pallet} = 13,
-        Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 14,
-        Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 15,
-        ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 16,
-        AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 17,
+        SmithMembers: pallet_smith_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
+        AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 11,
+        Authorship: pallet_authorship::{Pallet, Storage} = 12,
+        Offences: pallet_offences::{Pallet, Storage, Event} = 13,
+        Historical: session_historical::{Pallet} = 14,
+        Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 15,
+        Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 16,
+        ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 17,
+        AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 18,
 
         // Governance stuff
         Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>} = 20,
@@ -328,24 +327,19 @@ construct_runtime!(
         UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 30,
 
         // Web Of Trust
-        Wot: pallet_duniter_wot::<Instance1>::{Pallet} = 40,
+        Wot: pallet_duniter_wot::{Pallet} = 40,
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 41,
-        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 42,
-        Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 43,
+        Membership: pallet_membership::{Pallet, Call, Config<T>, Storage, Event<T>} = 42,
+        Cert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>} = 43,
         Distance: pallet_distance::{Pallet, Call, Storage, Inherent, Event<T>} = 44,
 
-        // Smith Sub-Wot
-        SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50,
-        SmithMembership: pallet_membership::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
-        SmithCert: pallet_certification::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53,
-
         // Utilities
-        AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60,
-        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61,
-        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62,
-        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63,
-        Utility: pallet_utility::{Pallet, Call, Event} = 64,
-        Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 65,
+        AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 50,
+        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 51,
+        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 52,
+        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 53,
+        Utility: pallet_utility::{Pallet, Call, Event} = 54,
+        Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 55,
     }
 );
 
diff --git a/runtime/gdev/tests/common/mod.rs b/runtime/gdev/tests/common/mod.rs
index 5c20cd6ab0b337c6989ae8eb1640c836b5424c27..a74493b34a02f8f680be2c32712341314b1858fe 100644
--- a/runtime/gdev/tests/common/mod.rs
+++ b/runtime/gdev/tests/common/mod.rs
@@ -18,11 +18,11 @@
 
 use common_runtime::constants::*;
 use common_runtime::*;
-use frame_support::instances::{Instance1, Instance2};
 use frame_support::traits::{GenesisBuild, OnFinalize, OnInitialize};
 use gdev_runtime::opaque::SessionKeys;
 use gdev_runtime::*;
 use pallet_authority_members::OnNewSession;
+use pallet_smith_members::SmithMeta;
 use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
 use sp_consensus_babe::{AuthorityId as BabeId, Slot};
 use sp_consensus_babe::{VrfOutput, VrfProof};
@@ -54,7 +54,7 @@ pub struct ExtBuilder {
     initial_authorities_len: usize,
     initial_identities: BTreeMap<IdtyName, AccountId>,
     initial_smiths: Vec<AuthorityKeys>,
-    parameters: GenesisParameters<u32, u32, Balance>,
+    parameters: GenesisParameters<u32, u32, Balance, u32>,
 }
 
 impl ExtBuilder {
@@ -108,14 +108,9 @@ impl ExtBuilder {
                 pending_membership_period: 500,
                 ud_creation_period: 60_000,
                 ud_reeval_period: 60_000 * 20,
-                smith_cert_period: 15,
                 smith_cert_max_by_issuer: 8,
-                smith_cert_min_received_cert_to_issue_cert: 2,
-                smith_cert_validity_period: 1_000,
-                smith_membership_period: 1_000,
-                smith_pending_membership_period: 500,
-                smith_wot_first_cert_issuable_on: 20,
                 smith_wot_min_cert_for_membership: 2,
+                smith_inactivity_max_duration: 48,
                 wot_first_cert_issuable_on: 20,
                 wot_min_cert_for_create_idty_right: 2,
                 wot_min_cert_for_membership: 2,
@@ -142,7 +137,7 @@ impl ExtBuilder {
     }*/
 
     pub fn change_parameters<
-        F: Fn(&mut pallet_duniter_test_parameters::Parameters<u32, u32, Balance>),
+        F: Fn(&mut pallet_duniter_test_parameters::Parameters<u32, u32, Balance, u32>),
     >(
         mut self,
         f: F,
@@ -251,7 +246,7 @@ impl ExtBuilder {
         .assimilate_storage(&mut t)
         .unwrap();
 
-        pallet_membership::GenesisConfig::<Runtime, Instance1> {
+        pallet_membership::GenesisConfig::<Runtime> {
             memberships: (1..=initial_identities.len())
                 .map(|i| {
                     (
@@ -266,7 +261,7 @@ impl ExtBuilder {
         .assimilate_storage(&mut t)
         .unwrap();
 
-        pallet_certification::GenesisConfig::<Runtime, Instance1> {
+        pallet_certification::GenesisConfig::<Runtime> {
             certs_by_receiver: clique_wot(
                 initial_identities.len(),
                 parameters.cert_validity_period,
@@ -276,27 +271,8 @@ impl ExtBuilder {
         .assimilate_storage(&mut t)
         .unwrap();
 
-        pallet_membership::GenesisConfig::<Runtime, Instance2> {
-            memberships: (1..=initial_smiths.len())
-                .map(|i| {
-                    (
-                        i as u32,
-                        MembershipData {
-                            expire_on: parameters.smith_membership_period,
-                        },
-                    )
-                })
-                .collect(),
-        }
-        .assimilate_storage(&mut t)
-        .unwrap();
-
-        pallet_certification::GenesisConfig::<Runtime, Instance2> {
-            apply_cert_period_at_genesis: false,
-            certs_by_receiver: clique_wot(
-                initial_smiths.len(),
-                parameters.smith_cert_validity_period,
-            ),
+        pallet_smith_members::GenesisConfig::<Runtime> {
+            initial_smiths: clique_smith_wot(initial_smiths.len()),
         }
         .assimilate_storage(&mut t)
         .unwrap();
@@ -393,9 +369,6 @@ pub fn run_to_block(n: u32) {
         Identity::on_initialize(System::block_number());
         Membership::on_initialize(System::block_number());
         Cert::on_initialize(System::block_number());
-        SmithSubWot::on_initialize(System::block_number());
-        SmithMembership::on_initialize(System::block_number());
-        SmithCert::on_initialize(System::block_number());
 
         Timestamp::set_timestamp(System::block_number() as u64 * BLOCK_TIME);
         Distance::on_initialize(System::block_number());
@@ -476,6 +449,22 @@ fn clique_wot(
     certs_by_issuer
 }
 
+fn clique_smith_wot(initial_identities_len: usize) -> BTreeMap<IdtyIndex, (bool, Vec<IdtyIndex>)> {
+    let mut certs_by_issuer = BTreeMap::new();
+    for i in 1..=initial_identities_len {
+        certs_by_issuer.insert(
+            i as IdtyIndex,
+            (
+                true,
+                (1..=initial_identities_len)
+                    .filter_map(|j| if i != j { Some(j as IdtyIndex) } else { None })
+                    .collect(),
+            ),
+        );
+    }
+    certs_by_issuer
+}
+
 fn session_keys(
     babe: BabeId,
     grandpa: GrandpaId,
diff --git a/runtime/gdev/tests/fixme_tests.rs b/runtime/gdev/tests/fixme_tests.rs
index 028f23600ccebc7d1258815fb514717706143eaf..1ab0bd7a7c799d9ed6b9c8be655bb38106d3c7ad 100644
--- a/runtime/gdev/tests/fixme_tests.rs
+++ b/runtime/gdev/tests/fixme_tests.rs
@@ -43,10 +43,7 @@ fn can_still_issue_cert_when_membership_lost() {
         run_to_block(1);
 
         // expire Bob membership
-        Membership::do_remove_membership(
-            2,
-            MembershipRemovalReason::System
-        );
+        Membership::do_remove_membership(2, MembershipRemovalReason::System);
         System::assert_has_event(RuntimeEvent::Membership(
             pallet_membership::Event::MembershipRemoved {
                 member: 2,
@@ -55,12 +52,13 @@ fn can_still_issue_cert_when_membership_lost() {
         ));
 
         // fixed :)
-        assert_noop!(Cert::add_cert(
-            frame_system::RawOrigin::Signed(AccountKeyring::Bob.to_account_id()).into(),
+        assert_noop!(
+            Cert::add_cert(
+                frame_system::RawOrigin::Signed(AccountKeyring::Bob.to_account_id()).into(),
                 2, // Bob
                 3, // Charlie
             ),
-            pallet_duniter_wot::Error::<gdev_runtime::Runtime, pallet_certification::Instance1>::IssuerNotMember
+            pallet_duniter_wot::Error::<gdev_runtime::Runtime>::IssuerNotMember
         );
         // // not anymore
         // System::assert_has_event(RuntimeEvent::Cert(
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
index ef4dce191d85262ad341243a4758665bf623895f..ca90f99258221aa6cbadc7b9e7442c1e74b067e6 100644
--- a/runtime/gdev/tests/integration_tests.rs
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -17,13 +17,14 @@
 mod common;
 
 use common::*;
-use frame_support::instances::Instance1;
 use frame_support::traits::StoredMap;
 use frame_support::traits::{Get, PalletInfo, StorageInfo, StorageInfoTrait};
-use frame_support::{assert_noop, assert_ok};
+use frame_support::{assert_err, assert_noop, assert_ok};
 use frame_support::{StorageHasher, Twox128};
 use gdev_runtime::*;
+use pallet_identity::{RevocationPayload, REVOCATION_PAYLOAD_PREFIX};
 use pallet_membership::MembershipRemovalReason;
+use pallet_smith_members::{SmithMeta, SmithStatus};
 use sp_core::Encode;
 use sp_keyring::AccountKeyring;
 use sp_runtime::MultiAddress;
@@ -367,9 +368,7 @@ fn test_validate_identity_when_claim() {
             System::assert_has_event(RuntimeEvent::Membership(
                 pallet_membership::Event::MembershipAdded {
                     member: 5,
-                    expire_on: 76
-                        + <Runtime as pallet_membership::Config<Instance1>>::MembershipPeriod::get(
-                        ),
+                    expire_on: 76 + <Runtime as pallet_membership::Config>::MembershipPeriod::get(),
                 },
             ));
             // not possible anymore to validate identity of someone else
@@ -392,6 +391,7 @@ fn test_membership_expiry() {
     });
 }
 
+// TODO: use change_parameter to change autorevocation period
 #[test]
 #[ignore = "long to go to autorevocation period"]
 fn test_membership_expiry_with_identity_removal() {
@@ -445,9 +445,7 @@ fn test_membership_renewal() {
             System::assert_has_event(RuntimeEvent::Membership(
                 pallet_membership::Event::MembershipAdded {
                     member: 1,
-                    expire_on: 76
-                        + <Runtime as pallet_membership::Config<Instance1>>::MembershipPeriod::get(
-                        ),
+                    expire_on: 76 + <Runtime as pallet_membership::Config>::MembershipPeriod::get(),
                 },
             ));
 
@@ -459,9 +457,7 @@ fn test_membership_renewal() {
             System::assert_has_event(RuntimeEvent::Membership(
                 pallet_membership::Event::MembershipAdded {
                     member: 1,
-                    expire_on: 77
-                        + <Runtime as pallet_membership::Config<Instance1>>::MembershipPeriod::get(
-                        ),
+                    expire_on: 77 + <Runtime as pallet_membership::Config>::MembershipPeriod::get(),
                 },
             ));
 
@@ -602,8 +598,7 @@ fn test_ud_claimed_membership_on_and_off() {
         System::assert_has_event(RuntimeEvent::Membership(
             pallet_membership::Event::MembershipAdded {
                 member: 1,
-                expire_on: 14
-                    + <Runtime as pallet_membership::Config<Instance1>>::MembershipPeriod::get(),
+                expire_on: 14 + <Runtime as pallet_membership::Config>::MembershipPeriod::get(),
             },
         ));
 
@@ -647,12 +642,6 @@ fn test_revoke_smith_identity() {
 
         Identity::do_revoke_identity(3, pallet_identity::RevocationReason::Root);
         // Verify events
-        System::assert_has_event(RuntimeEvent::SmithMembership(
-            pallet_membership::Event::MembershipRemoved {
-                member: 3,
-                reason: MembershipRemovalReason::Revoked,
-            },
-        ));
         System::assert_has_event(RuntimeEvent::AuthorityMembers(
             pallet_authority_members::Event::MemberRemoved { member: 3 },
         ));
@@ -679,26 +668,33 @@ fn test_smith_certification() {
     ExtBuilder::new(1, 3, 4).build().execute_with(|| {
         run_to_block(1);
 
-        // alice can renew smith cert to bob
-        assert_ok!(SmithCert::add_cert(
-            frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
-            1, // alice
-            2  // bob
-        ));
+        assert_noop!(
+            SmithMembers::certify_smith(
+                frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+                2
+            ),
+            pallet_smith_members::Error::<Runtime>::CertificationAlreadyExists
+        );
 
-        // charlie can not add new cert to eve (no identity)
         assert_noop!(
-            SmithCert::add_cert(
-                frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into(),
-                3, // charlie
-                5  // eve
+            SmithMembers::certify_smith(
+                frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+                4
             ),
-            // SmithSubWot::Error::IdtyNotFound,
-            pallet_duniter_wot::Error::<gdev_runtime::Runtime, pallet_certification::Instance2>::IdtyNotFound,
+            pallet_smith_members::Error::<Runtime>::CertificationReceiverMustHaveBeenInvited
         );
     });
 }
 
+fn create_dummy_session_keys() -> gdev_runtime::opaque::SessionKeys {
+    gdev_runtime::opaque::SessionKeys {
+        grandpa: sp_core::ed25519::Public([0u8; 32]).into(),
+        babe: sp_core::sr25519::Public([0u8; 32]).into(),
+        im_online: sp_core::sr25519::Public([0u8; 32]).into(),
+        authority_discovery: sp_core::sr25519::Public([0u8; 32]).into(),
+    }
+}
+
 /// test the full process to join smith from main wot member to authority member
 #[test]
 fn test_smith_process() {
@@ -711,6 +707,8 @@ fn test_smith_process() {
             let alice = AccountKeyring::Alice.to_account_id();
             let bob = AccountKeyring::Bob.to_account_id();
             let charlie = AccountKeyring::Charlie.to_account_id();
+            let dave = AccountKeyring::Dave.to_account_id();
+            let dummy_session_keys = create_dummy_session_keys();
 
             // Eve can not request smith membership because not member of the smith wot
             // no more membership request
@@ -718,45 +716,53 @@ fn test_smith_process() {
             // Dave can request smith membership (currently optional)
             // no more membership request
 
-            // Alice Bob and Charlie can certify Dave
-            assert_ok!(SmithCert::add_cert(
-                frame_system::RawOrigin::Signed(alice).into(),
-                1,
+            assert_ok!(SmithMembers::invite_smith(
+                frame_system::RawOrigin::Signed(alice.clone()).into(),
                 4
             ));
-            assert_ok!(SmithCert::add_cert(
-                frame_system::RawOrigin::Signed(bob).into(),
-                2,
+            assert_ok!(SmithMembers::accept_invitation(
+                frame_system::RawOrigin::Signed(dave).into(),
+            ));
+
+            // Dave cannot (yet) set his session keys
+            assert_err!(
+                AuthorityMembers::set_session_keys(
+                    frame_system::RawOrigin::Signed(AccountKeyring::Dave.to_account_id()).into(),
+                    dummy_session_keys.clone()
+                ),
+                pallet_authority_members::Error::<Runtime>::NotMember
+            );
+
+            // Alice Bob and Charlie can certify Dave
+            assert_ok!(SmithMembers::certify_smith(
+                frame_system::RawOrigin::Signed(alice.clone()).into(),
                 4
             ));
-            assert_ok!(SmithCert::add_cert(
-                frame_system::RawOrigin::Signed(charlie).into(),
-                3,
+            assert_ok!(SmithMembers::certify_smith(
+                frame_system::RawOrigin::Signed(bob.clone()).into(),
                 4
             ));
-
-            // with these three smith certs, Dave can claim membership
-            assert_ok!(SmithMembership::claim_membership(
-                frame_system::RawOrigin::Signed(AccountKeyring::Dave.to_account_id()).into(),
+            assert_ok!(SmithMembers::certify_smith(
+                frame_system::RawOrigin::Signed(charlie.clone()).into(),
+                4
             ));
 
+            // with these three smith certs, Dave has become smith
             // Dave is then member of the smith wot
             assert_eq!(
-                SmithMembership::membership(4),
-                Some(sp_membership::MembershipData {
-                    expire_on: 1001, // 1 + 1000
+                SmithMembers::smiths(4),
+                Some(pallet_smith_members::SmithMeta {
+                    status: SmithStatus::Smith,
+                    expires_on: Some(48),
+                    issued_certs: vec![],
+                    received_certs: vec![1, 2, 3],
                 })
             );
 
             // Dave can set his (dummy) session keys
             assert_ok!(AuthorityMembers::set_session_keys(
                 frame_system::RawOrigin::Signed(AccountKeyring::Dave.to_account_id()).into(),
-                gdev_runtime::opaque::SessionKeys {
-                    grandpa: sp_core::ed25519::Public([0u8; 32]).into(),
-                    babe: sp_core::sr25519::Public([0u8; 32]).into(),
-                    im_online: sp_core::sr25519::Public([0u8; 32]).into(),
-                    authority_discovery: sp_core::sr25519::Public([0u8; 32]).into(),
-                }
+                dummy_session_keys
             ));
 
             // Dave can go online
@@ -1235,14 +1241,26 @@ fn test_link_account() {
 fn test_change_owner_key() {
     ExtBuilder::new(1, 3, 4).build().execute_with(|| {
         let genesis_hash = System::block_hash(0);
-        let dave = AccountKeyring::Dave.to_account_id();
+        let charlie = AccountKeyring::Charlie.to_account_id();
         let ferdie = AccountKeyring::Ferdie.to_account_id();
-        let payload = (b"icok", genesis_hash, 4u32, dave.clone()).encode();
+        let payload = (b"icok", genesis_hash, 3u32, charlie.clone()).encode();
         let signature = AccountKeyring::Ferdie.sign(&payload);
 
+        SmithMembers::on_smith_goes_offline(3);
+        // Charlie is now offline smith
+        assert_eq!(
+            SmithMembers::smiths(3),
+            Some(SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: Some(48),
+                issued_certs: vec![1, 2],
+                received_certs: vec![1, 2]
+            })
+        );
+
         assert_eq!(
-            frame_system::Pallet::<Runtime>::get(&dave).linked_idty,
-            Some(4)
+            frame_system::Pallet::<Runtime>::get(&charlie).linked_idty,
+            Some(3)
         );
         assert_eq!(
             frame_system::Pallet::<Runtime>::get(&ferdie).linked_idty,
@@ -1250,17 +1268,123 @@ fn test_change_owner_key() {
         );
         // Dave can change his owner key to Ferdie's
         assert_ok!(Identity::change_owner_key(
-            frame_system::RawOrigin::Signed(dave.clone()).into(),
+            frame_system::RawOrigin::Signed(charlie.clone()).into(),
             ferdie.clone(),
             signature.into()
         ));
         assert_eq!(
             frame_system::Pallet::<Runtime>::get(&ferdie).linked_idty,
-            Some(4)
+            Some(3)
+        );
+
+        // Charlie is still an offline smith
+        assert_eq!(
+            SmithMembers::smiths(3),
+            Some(SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: Some(48),
+                issued_certs: vec![1, 2],
+                received_certs: vec![1, 2]
+            })
+        );
+
+        // Ferdie can set its session_keys and go online
+        frame_system::Pallet::<Runtime>::inc_providers(&ferdie);
+        assert_ok!(AuthorityMembers::set_session_keys(
+            frame_system::RawOrigin::Signed(AccountKeyring::Ferdie.to_account_id()).into(),
+            create_dummy_session_keys()
+        ));
+        assert_ok!(AuthorityMembers::go_online(
+            frame_system::RawOrigin::Signed(AccountKeyring::Ferdie.to_account_id()).into()
+        ));
+
+        // Charlie is still an offline smith
+        assert_eq!(
+            SmithMembers::smiths(3),
+            Some(SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: Some(48),
+                issued_certs: vec![1, 2],
+                received_certs: vec![1, 2]
+            })
+        );
+
+        run_to_block(25);
+
+        System::assert_has_event(RuntimeEvent::AuthorityMembers(
+            pallet_authority_members::Event::IncomingAuthorities { members: vec![3] },
+        ));
+        System::assert_has_event(RuntimeEvent::AuthorityMembers(
+            pallet_authority_members::Event::OutgoingAuthorities { members: vec![1] },
+        ));
+
+        // "Charlie" (idty 3) is now online because its identity is mapped to Ferdies's key
+        assert_eq!(
+            SmithMembers::smiths(3),
+            Some(SmithMeta {
+                status: SmithStatus::Smith,
+                expires_on: None,
+                issued_certs: vec![1, 2],
+                received_certs: vec![1, 2]
+            })
         );
     })
 }
 
+/// members of the smith subwot can revoke their identity
+#[test]
+fn test_smith_member_can_revoke_its_idty() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        run_to_block(2);
+
+        // Charlie goes online
+        frame_system::Pallet::<Runtime>::inc_providers(&AccountKeyring::Charlie.to_account_id());
+        assert_ok!(AuthorityMembers::set_session_keys(
+            frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into(),
+            create_dummy_session_keys()
+        ));
+        assert_ok!(AuthorityMembers::go_online(
+            frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into()
+        ));
+
+        run_to_block(25);
+
+        // Charlie is in the authority members
+        System::assert_has_event(RuntimeEvent::AuthorityMembers(
+            pallet_authority_members::Event::IncomingAuthorities { members: vec![3] },
+        ));
+        // Charlie is not going out
+        assert!(!pallet_authority_members::OutgoingAuthorities::<Runtime>::get().contains(&3));
+
+        let revocation_payload = RevocationPayload {
+            idty_index: 3u32,
+            genesis_hash: System::block_hash(0),
+        };
+        let signature =
+            AccountKeyring::Charlie.sign(&(REVOCATION_PAYLOAD_PREFIX, revocation_payload).encode());
+
+        assert_ok!(Identity::revoke_identity(
+            frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into(),
+            3,
+            AccountKeyring::Charlie.to_account_id(),
+            signature.into()
+        ));
+        // membership should be removed
+        System::assert_has_event(RuntimeEvent::Membership(
+            pallet_membership::Event::MembershipRemoved {
+                member: 3,
+                reason: MembershipRemovalReason::Revoked,
+            },
+        ));
+        // smith membership should be removed as well
+        System::assert_has_event(RuntimeEvent::SmithMembers(
+            pallet_smith_members::Event::SmithExcluded { idty_index: 3 },
+        ));
+        // Now Charlie is going out
+        assert!(pallet_authority_members::OutgoingAuthorities::<Runtime>::get().contains(&3));
+    });
+}
+
 /// test genesis account of identity is linked to identity
 // (and account without identity is not linked)
 #[test]
@@ -1328,11 +1452,10 @@ fn test_new_account_linked() {
     })
 }
 #[test]
+#[ignore = "what was this test supposed to do?"]
 fn smith_data_problem() {
     ExtBuilder::new(1, 3, 4)
-        .change_parameters(|parameters| {
-            parameters.smith_cert_validity_period = 3;
-        })
+        .change_parameters(|_parameters| {})
         .build()
         .execute_with(|| {
             run_to_block(4);
diff --git a/runtime/gtest/Cargo.toml b/runtime/gtest/Cargo.toml
index 8f59a6ad6a39b54c0c0ca276e78ef76b5b346eb6..8e90489b73d8d7c6afd25dac6a15ca39ae03e524 100644
--- a/runtime/gtest/Cargo.toml
+++ b/runtime/gtest/Cargo.toml
@@ -23,6 +23,7 @@ runtime-benchmarks = [
     'frame-system/runtime-benchmarks',
     'hex-literal',
     'pallet-authority-members/runtime-benchmarks',
+    'pallet-smith-members/runtime-benchmarks',
     'pallet-babe/runtime-benchmarks',
     'pallet-balances/runtime-benchmarks',
     'pallet-certification/runtime-benchmarks',
@@ -60,6 +61,7 @@ std = [
     'pallet-atomic-swap/std',
     'pallet-authority-discovery/std',
     'pallet-authority-members/std',
+    'pallet-smith-members/std',
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
@@ -137,6 +139,7 @@ sp-keyring = { git = 'https://github.com/duniter/substrate', branch = 'duniter-s
 # local
 common-runtime = { path = "../common", default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
+pallet-smith-members = { path = '../../pallets/smith-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-distance = { path = "../../pallets/distance", default-features = false }
 pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false }
diff --git a/runtime/gtest/src/lib.rs b/runtime/gtest/src/lib.rs
index 88fbd282f83728cf10ee03e282715b7ec34ebf67..374cc0d7999e5b709b8e886bfa1d8f5db7e55f3a 100644
--- a/runtime/gtest/src/lib.rs
+++ b/runtime/gtest/src/lib.rs
@@ -66,6 +66,7 @@ use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
 
 // A few exports that help ease life for downstream crates.
+use frame_support::instances::Instance2;
 pub use frame_support::{
     construct_runtime, parameter_types,
     traits::{EqualPrivilegeOnly, KeyOwnerProofSystem, Randomness},
@@ -140,7 +141,6 @@ pub type TechnicalCommitteeInstance = Instance2;
 mod benches {
     define_benchmarks!(
         [pallet_certification, Cert]
-        [pallet_certification, SmithCert]
         [pallet_distance, Distance]
         [pallet_oneshot_account, OneshotAccount]
         [pallet_universal_dividend, UniversalDividend]
@@ -149,7 +149,7 @@ mod benches {
         [pallet_duniter_account, Account]
         [pallet_identity, Identity]
         [pallet_membership, Membership]
-        [pallet_membership, SmithMembership]
+        [pallet_smith_members, SmithMembers]
         [pallet_authority_members, AuthorityMembers]
         // Substrate
         [pallet_balances, Balances]
@@ -211,7 +211,9 @@ impl frame_support::traits::InstanceFilter<RuntimeCall> for ProxyType {
                 // Some calls are never authorized from a proxied account
                 !matches!(
                     c,
-                    RuntimeCall::Cert(..) | RuntimeCall::Identity(..) | RuntimeCall::SmithCert(..)
+                    RuntimeCall::Cert(..)
+                        | RuntimeCall::Identity(..)
+                        | RuntimeCall::SmithMembers(..)
                 )
             }
             ProxyType::TransferOnly => {
@@ -268,14 +270,15 @@ construct_runtime!(
         Quota: pallet_quota::{Pallet, Storage, Config<T>, Event<T>} = 66,
 
         // Consensus support
-        AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
-        Authorship: pallet_authorship::{Pallet, Storage} = 11,
-        Offences: pallet_offences::{Pallet, Storage, Event} = 12,
-        Historical: session_historical::{Pallet} = 13,
-        Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 14,
-        Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 15,
-        ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 16,
-        AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 17,
+        SmithMembers: pallet_smith_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
+        AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 11,
+        Authorship: pallet_authorship::{Pallet, Storage} = 12,
+        Offences: pallet_offences::{Pallet, Storage, Event} = 13,
+        Historical: session_historical::{Pallet} = 14,
+        Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 15,
+        Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 16,
+        ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 17,
+        AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 18,
 
         // Governance stuff
         Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>} = 20,
@@ -287,24 +290,19 @@ construct_runtime!(
         UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 30,
 
         // Web Of Trust
-        Wot: pallet_duniter_wot::<Instance1>::{Pallet} = 40,
+        Wot: pallet_duniter_wot::{Pallet} = 40,
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 41,
-        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 42,
-        Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 43,
+        Membership: pallet_membership::{Pallet, Call, Config<T>, Storage, Event<T>} = 42,
+        Cert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>} = 43,
         Distance: pallet_distance::{Pallet, Call, Storage, Inherent, Event<T>} = 44,
 
-        // Smith Sub-Wot
-        SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50,
-        SmithMembership: pallet_membership::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
-        SmithCert: pallet_certification::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53,
-
         // Utilities
-        AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60,
-        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61,
-        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62,
-        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63,
-        Utility: pallet_utility::{Pallet, Call, Event} = 64,
-        Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 65,
+        AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 50,
+        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 51,
+        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 52,
+        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 53,
+        Utility: pallet_utility::{Pallet, Call, Event} = 54,
+        Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 55,
     }
 );
 
diff --git a/runtime/gtest/src/parameters.rs b/runtime/gtest/src/parameters.rs
index 443e8cffa589424a5ed1fb69d40121c312e356ea..252ae211a2571ead87fa67ab4d13f64b98ae8c88 100644
--- a/runtime/gtest/src/parameters.rs
+++ b/runtime/gtest/src/parameters.rs
@@ -118,26 +118,13 @@ parameter_types! {
 }
 
 /******************/
-/* SMITHS SUB-WOT */
+/* SMITH-MEMBERS */
 /******************/
 
 parameter_types! {
-    pub const SmithWotFirstCertIssuableOn: BlockNumber = DAYS;
     pub const SmithWotMinCertForMembership: u32 = 3;
-}
-
-// Membership
-parameter_types! {
-    pub const SmithMembershipPeriod: BlockNumber = 73 * DAYS;
-    pub const SmithPendingMembershipPeriod: BlockNumber = 12 * DAYS;
-}
-
-// Certification
-parameter_types! {
-    pub const SmithCertPeriod: BlockNumber = DAYS;
     pub const SmithMaxByIssuer: u32 = 100;
-    pub const SmithMinReceivedCertToBeAbleToIssueCert: u32 = 5;
-    pub const SmithValidityPeriod: BlockNumber = 146 * DAYS;
+    pub const SmithInactivityMaxDuration: u32 = 48;
 }
 
 /*************/