diff --git a/docs/api/runtime-calls.md b/docs/api/runtime-calls.md
index 2289d6262e1cb43b69ed3128b5ad12575996f079..95ffd53436b05d24801de03d0548b0b4c565bb06 100644
--- a/docs/api/runtime-calls.md
+++ b/docs/api/runtime-calls.md
@@ -13,7 +13,7 @@ through on-chain governance mechanisms.
 
 ## User calls
 
-There are **68** user calls from **21** pallets.
+There are **69** user calls from **21** pallets.
 
 ### Scheduler - 2
 
@@ -652,12 +652,23 @@ change sufficient ref count for given key
 
 ### Membership - 42
 
-#### renew_membership - 3
+#### claim_membership - 1
 
-<details><summary><code>renew_membership(maybe_idty_id)</code></summary>
+<details><summary><code>claim_membership()</code></summary>
+
+```rust
+```
+</details>
+
+
+claim pending membership to become actual memberhip
+the requested membership must fullfill requirements
+
+#### renew_membership - 2
+
+<details><summary><code>renew_membership()</code></summary>
 
 ```rust
-maybe_idty_id: Option<T::IdtyId>
 ```
 </details>
 
@@ -666,7 +677,7 @@ extend the validity period of an active membership
 
 ### Cert - 43
 
-#### add_cert - 1
+#### add_cert - 0
 
 <details><summary><code>add_cert(issuer, receiver)</code></summary>
 
@@ -685,7 +696,7 @@ The origin must be allow to certify.
 
 ### SmithMembership - 52
 
-#### request_membership - 1
+#### request_membership - 0
 
 <details><summary><code>request_membership(metadata)</code></summary>
 
@@ -698,37 +709,34 @@ metadata: T::MetaData
 submit a membership request (must have a declared identity)
 (only available for sub wot, automatic for main wot)
 
-#### claim_membership - 2
+#### claim_membership - 1
 
-<details><summary><code>claim_membership(maybe_idty_id)</code></summary>
+<details><summary><code>claim_membership()</code></summary>
 
 ```rust
-maybe_idty_id: Option<T::IdtyId>
 ```
 </details>
 
 
-claim that the previously requested membership fullfills the requirements
-(only available for sub wot, automatic for main wot)
+claim pending membership to become actual memberhip
+the requested membership must fullfill requirements
 
-#### renew_membership - 3
+#### renew_membership - 2
 
-<details><summary><code>renew_membership(maybe_idty_id)</code></summary>
+<details><summary><code>renew_membership()</code></summary>
 
 ```rust
-maybe_idty_id: Option<T::IdtyId>
 ```
 </details>
 
 
 extend the validity period of an active membership
 
-#### revoke_membership - 4
+#### revoke_membership - 3
 
-<details><summary><code>revoke_membership(maybe_idty_id)</code></summary>
+<details><summary><code>revoke_membership()</code></summary>
 
 ```rust
-maybe_idty_id: Option<T::IdtyId>
 ```
 </details>
 
@@ -738,7 +746,7 @@ revoke an active membership
 
 ### SmithCert - 53
 
-#### add_cert - 1
+#### add_cert - 0
 
 <details><summary><code>add_cert(issuer, receiver)</code></summary>
 
@@ -1353,7 +1361,7 @@ May only be called from `T::RejectOrigin`.
 
 ## Root calls
 
-There are **26** root calls from **12** pallets.
+There are **22** root calls from **10** pallets.
 
 ### System - 0
 
@@ -1637,38 +1645,9 @@ names: Vec<IdtyName>
 
 remove identity names from storage
 
-### Membership - 42
-
-#### force_request_membership - 0
-
-<details><summary><code>force_request_membership(idty_id, metadata)</code></summary>
-
-```rust
-idty_id: T::IdtyId
-metadata: T::MetaData
-```
-</details>
-
-
-request membership without checks
-
 ### Cert - 43
 
-#### force_add_cert - 0
-
-<details><summary><code>force_add_cert(issuer, receiver, verify_rules)</code></summary>
-
-```rust
-issuer: T::IdtyIndex
-receiver: T::IdtyIndex
-verify_rules: bool
-```
-</details>
-
-
-add a certification without checks (only root)
-
-#### del_cert - 2
+#### del_cert - 1
 
 <details><summary><code>del_cert(issuer, receiver)</code></summary>
 
@@ -1681,7 +1660,7 @@ receiver: T::IdtyIndex
 
 remove a certification (only root)
 
-#### remove_all_certs_received_by - 3
+#### remove_all_certs_received_by - 2
 
 <details><summary><code>remove_all_certs_received_by(idty_index)</code></summary>
 
@@ -1693,38 +1672,9 @@ idty_index: T::IdtyIndex
 
 remove all certifications received by an identity (only root)
 
-### SmithMembership - 52
-
-#### force_request_membership - 0
-
-<details><summary><code>force_request_membership(idty_id, metadata)</code></summary>
-
-```rust
-idty_id: T::IdtyId
-metadata: T::MetaData
-```
-</details>
-
-
-request membership without checks
-
 ### SmithCert - 53
 
-#### force_add_cert - 0
-
-<details><summary><code>force_add_cert(issuer, receiver, verify_rules)</code></summary>
-
-```rust
-issuer: T::IdtyIndex
-receiver: T::IdtyIndex
-verify_rules: bool
-```
-</details>
-
-
-add a certification without checks (only root)
-
-#### del_cert - 2
+#### del_cert - 1
 
 <details><summary><code>del_cert(issuer, receiver)</code></summary>
 
@@ -1737,7 +1687,7 @@ receiver: T::IdtyIndex
 
 remove a certification (only root)
 
-#### remove_all_certs_received_by - 3
+#### remove_all_certs_received_by - 2
 
 <details><summary><code>remove_all_certs_received_by(idty_index)</code></summary>
 
@@ -1774,7 +1724,7 @@ The dispatch origin for this call must be _Root_.
 
 ## Disabled calls
 
-There are **7** disabled calls from **3** pallets.
+There are **6** disabled calls from **3** pallets.
 
 ### System - 0
 
@@ -1844,7 +1794,7 @@ usually means being a stash account).
 
 ### Membership - 42
 
-#### request_membership - 1
+#### request_membership - 0
 
 <details><summary><code>request_membership(metadata)</code></summary>
 
@@ -1857,25 +1807,11 @@ metadata: T::MetaData
 submit a membership request (must have a declared identity)
 (only available for sub wot, automatic for main wot)
 
-#### claim_membership - 2
-
-<details><summary><code>claim_membership(maybe_idty_id)</code></summary>
-
-```rust
-maybe_idty_id: Option<T::IdtyId>
-```
-</details>
-
-
-claim that the previously requested membership fullfills the requirements
-(only available for sub wot, automatic for main wot)
-
-#### revoke_membership - 4
+#### revoke_membership - 3
 
-<details><summary><code>revoke_membership(maybe_idty_id)</code></summary>
+<details><summary><code>revoke_membership()</code></summary>
 
 ```rust
-maybe_idty_id: Option<T::IdtyId>
 ```
 </details>
 
diff --git a/pallets/certification/src/benchmarking.rs b/pallets/certification/src/benchmarking.rs
index 65e343a4ef900ff6d28719aef954999c90dc80cb..25f12579e4f83a6ec0002e6ef96ca828f939573d 100644
--- a/pallets/certification/src/benchmarking.rs
+++ b/pallets/certification/src/benchmarking.rs
@@ -34,7 +34,7 @@ fn assert_has_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::R
 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)?;
     for j in 1..i {
-        Pallet::<T, I>::force_add_cert(RawOrigin::Root.into(), j.into(), receiver, false)?;
+        Pallet::<T, I>::do_add_cert_checked(RawOrigin::Root.into(), j.into(), receiver, false)?;
     }
     assert!(
         CertsByReceiver::<T, I>::get(receiver).len() as u32 == i - 1,
@@ -48,16 +48,6 @@ benchmarks_instance_pallet! {
         where
             T::IdtyIndex: From<u32>,
     }
-    force_add_cert {
-        let issuer: T::IdtyIndex = 1.into();
-        let receiver: T::IdtyIndex = 2.into();
-        Pallet::<T, I>::del_cert(RawOrigin::Root.into(), issuer, receiver)?;
-        let receiver_cert: u32 = StorageIdtyCertMeta::<T, I>::get(receiver).received_count;
-        let issuer_cert: u32 = StorageIdtyCertMeta::<T, I>::get(issuer).issued_count;
-    }: _<T::RuntimeOrigin>(RawOrigin::Root.into(), issuer, receiver, true)
-    verify {
-        assert_has_event::<T, I>(Event::<T, I>::NewCert{ issuer: issuer, issuer_issued_count: issuer_cert + 1, receiver: receiver, receiver_received_count: receiver_cert + 1 }.into());
-    }
     add_cert {
         let issuer: T::IdtyIndex = 1.into();
         let caller: T::AccountId  = T::OwnerKeyOf::convert(issuer).unwrap();
@@ -73,7 +63,7 @@ benchmarks_instance_pallet! {
     del_cert {
         let issuer: T::IdtyIndex = 1.into();
         let receiver: T::IdtyIndex = 0.into();
-        Pallet::<T, I>::force_add_cert(RawOrigin::Root.into(), issuer, receiver, false)?;
+        Pallet::<T, I>::do_add_cert_checked(RawOrigin::Root.into(), 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;
     }: _<T::RuntimeOrigin>(RawOrigin::Root.into(), issuer, receiver)
diff --git a/pallets/certification/src/lib.rs b/pallets/certification/src/lib.rs
index b062da444944a9dcf3ed9bde2cb954c45fc3c0b5..f1bcb550a16eb71cd6acf5a9bc64b448b9324f27 100644
--- a/pallets/certification/src/lib.rs
+++ b/pallets/certification/src/lib.rs
@@ -276,45 +276,6 @@ pub mod pallet {
 
     #[pallet::call]
     impl<T: Config<I>, I: 'static> Pallet<T, I> {
-        /// add a certification without checks (only root)
-        #[pallet::weight(T::WeightInfo::force_add_cert())]
-        pub fn force_add_cert(
-            origin: OriginFor<T>,
-            issuer: T::IdtyIndex,
-            receiver: T::IdtyIndex,
-            verify_rules: bool,
-        ) -> DispatchResultWithPostInfo {
-            ensure_root(origin)?;
-
-            // Forbid self cert
-            ensure!(issuer != receiver, Error::<T, I>::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);
-                ensure!(
-                    issuer_idty_cert_meta.received_count
-                        >= T::MinReceivedCertToBeAbleToIssueCert::get(),
-                    Error::<T, I>::NotEnoughCertReceived
-                );
-
-                // Verify rule MaxByIssuer
-                ensure!(
-                    issuer_idty_cert_meta.issued_count < T::MaxByIssuer::get(),
-                    Error::<T, I>::IssuedTooManyCert
-                );
-
-                // Verify rule CertPeriod
-                ensure!(
-                    block_number >= issuer_idty_cert_meta.next_issuable_on,
-                    Error::<T, I>::NotRespectCertPeriod
-                );
-            };
-
-            Self::do_add_cert(block_number, issuer, receiver)
-        }
         /// Add a new certification or renew an existing one
         ///
         /// - `receiver`: the account receiving the certification from the origin
@@ -392,6 +353,41 @@ pub mod pallet {
     // INTERNAL FUNCTIONS //
 
     impl<T: Config<I>, I: 'static> Pallet<T, I> {
+        /// add a certification without checks
+        pub fn do_add_cert_checked(
+            issuer: T::IdtyIndex,
+            receiver: T::IdtyIndex,
+            verify_rules: bool,
+        ) -> DispatchResultWithPostInfo {
+            // Forbid self cert
+            ensure!(issuer != receiver, Error::<T, I>::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);
+                ensure!(
+                    issuer_idty_cert_meta.received_count
+                        >= T::MinReceivedCertToBeAbleToIssueCert::get(),
+                    Error::<T, I>::NotEnoughCertReceived
+                );
+
+                // Verify rule MaxByIssuer
+                ensure!(
+                    issuer_idty_cert_meta.issued_count < T::MaxByIssuer::get(),
+                    Error::<T, I>::IssuedTooManyCert
+                );
+
+                // Verify rule CertPeriod
+                ensure!(
+                    block_number >= issuer_idty_cert_meta.next_issuable_on,
+                    Error::<T, I>::NotRespectCertPeriod
+                );
+            };
+
+            Self::do_add_cert(block_number, issuer, receiver)
+        }
         /// perform cert addition or renewal
         fn do_add_cert(
             block_number: T::BlockNumber,
diff --git a/pallets/certification/src/weights.rs b/pallets/certification/src/weights.rs
index 54665716e423e023d0e38068563f0b7d9cf8d882..2d4ed1c30565b3491f9eae58819f41714654e2dd 100644
--- a/pallets/certification/src/weights.rs
+++ b/pallets/certification/src/weights.rs
@@ -20,7 +20,7 @@ use frame_support::weights::{constants::RocksDbWeight, Weight};
 
 /// Weight functions needed for pallet_universal_dividend.
 pub trait WeightInfo {
-    fn force_add_cert() -> Weight;
+    fn do_add_cert_checked() -> Weight;
     fn add_cert() -> Weight;
     fn del_cert() -> Weight;
     fn remove_all_certs_received_by(i: u32) -> Weight;
@@ -32,7 +32,7 @@ impl WeightInfo for () {
     // Storage: Parameters ParametersStorage (r:1 w:0)
     // Storage: Cert StorageCertsRemovableOn (r:1 w:1)
     // Storage: Cert CertsByReceiver (r:1 w:1)
-    fn force_add_cert() -> Weight {
+    fn do_add_cert_checked() -> Weight {
         // Minimum execution time: 221_467 nanoseconds.
         Weight::from_ref_time(227_833_000 as u64)
             .saturating_add(RocksDbWeight::get().reads(5 as u64))
diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs
index e285dde5d0f2beb6fdd77abb682e2abcb7093eb6..50a41c70b5184d96a8fa1598b958a80cfb32aad1 100644
--- a/pallets/duniter-wot/src/lib.rs
+++ b/pallets/duniter-wot/src/lib.rs
@@ -122,12 +122,14 @@ pub mod pallet {
     }
 }
 
+// implement identity call checks
 impl<AccountId, T: Config<I>, I: 'static> pallet_identity::traits::CheckIdtyCallAllowed<T>
     for Pallet<T, I>
 where
     T: frame_system::Config<AccountId = AccountId> + pallet_membership::Config<I>,
 {
     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
@@ -144,43 +146,44 @@ where
                 Error::<T, I>::IdtyCreationPeriodNotRespected
             );
         }
+        // no constraints for subwot
         Ok(())
     }
     fn check_confirm_identity(idty_index: IdtyIndex) -> Result<(), DispatchError> {
+        // main WoT automatic action
         if !T::IsSubWot::get() {
             pallet_membership::Pallet::<T, I>::force_request_membership(
-                RawOrigin::Root.into(),
                 idty_index,
                 Default::default(),
             )
             .map_err(|e| e.error)?;
         }
+        // no constraints for subwot
         Ok(())
     }
     fn check_validate_identity(idty_index: IdtyIndex) -> Result<(), DispatchError> {
+        // main WoT constraints
         if !T::IsSubWot::get() {
-            // TODO replace this code by the commented one for distance feature
-            /*let idty_cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index);
-            idty_cert_meta.received_count >= T::MinCertForMembership::get() as u32*/
-            // in the main wot, automatically claim membership when the identity is validated
-            pallet_membership::Pallet::<T, I>::claim_membership(
-                RawOrigin::Root.into(),
-                Some(idty_index),
-            )
-            .map_err(|e| e.error)?;
+            // check if identity is allowed to claim membership to the main wot
+            // (will be called automatically after)
+            pallet_membership::Pallet::<T, I>::check_allowed_to_claim(idty_index)?;
         }
+        // no constraints for subwot
         Ok(())
     }
     fn check_change_identity_address(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
         Ok(())
     }
     fn check_remove_identity(idty_index: IdtyIndex) -> Result<(), DispatchError> {
+        // identity can not be removed when member of a subwot (smith in this case)
         if T::IsSubWot::get() {
             ensure!(
                 !pallet_membership::Pallet::<T, I>::is_member(&idty_index),
@@ -191,6 +194,7 @@ where
     }
 }
 
+// implement cert call checks
 impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<IdtyIndex>
     for Pallet<T, I>
 {
@@ -215,7 +219,26 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<Id
     }
 }
 
-impl<T: Config<I>, I: 'static> sp_membership::traits::CheckCallAllowed<IdtyIndex> for Pallet<T, I> {
+// implement membership call checks
+impl<T: Config<I>, I: 'static> sp_membership::traits::CheckMembershipCallAllowed<IdtyIndex>
+    for Pallet<T, I>
+{
+    // membership request is only possible for subwot and when identity is validated
+    fn check_idty_allowed_to_request_membership(
+        idty_index: &IdtyIndex,
+    ) -> Result<(), DispatchError> {
+        if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
+            ensure!(
+                T::IsSubWot::get() && idty_value.status == IdtyStatus::Validated,
+                Error::<T, I>::IdtyNotAllowedToRequestMembership
+            );
+        } else {
+            return Err(Error::<T, I>::IdtyNotFound.into());
+        }
+        Ok(())
+    }
+
+    // membership claim is only possible when enough certs are received (both wots)
     fn check_idty_allowed_to_claim_membership(idty_index: &IdtyIndex) -> Result<(), DispatchError> {
         let idty_cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index);
         ensure!(
@@ -225,6 +248,7 @@ impl<T: Config<I>, I: 'static> sp_membership::traits::CheckCallAllowed<IdtyIndex
         Ok(())
     }
 
+    // membership renewal is only possible when identity is validated
     fn check_idty_allowed_to_renew_membership(idty_index: &IdtyIndex) -> Result<(), DispatchError> {
         if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
             ensure!(
@@ -236,22 +260,9 @@ impl<T: Config<I>, I: 'static> sp_membership::traits::CheckCallAllowed<IdtyIndex
         }
         Ok(())
     }
-
-    fn check_idty_allowed_to_request_membership(
-        idty_index: &IdtyIndex,
-    ) -> Result<(), DispatchError> {
-        if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
-            ensure!(
-                T::IsSubWot::get() && idty_value.status == IdtyStatus::Validated,
-                Error::<T, I>::IdtyNotAllowedToRequestMembership
-            );
-        } else {
-            return Err(Error::<T, I>::IdtyNotFound.into());
-        }
-        Ok(())
-    }
 }
 
+// implement membership event handler
 impl<T: Config<I>, I: 'static, MetaData> sp_membership::traits::OnEvent<IdtyIndex, MetaData>
     for Pallet<T, I>
 where
@@ -259,18 +270,14 @@ where
 {
     fn on_event(membership_event: &sp_membership::Event<IdtyIndex, MetaData>) -> Weight {
         match membership_event {
-            sp_membership::Event::<IdtyIndex, MetaData>::MembershipAcquired(_, _) => {}
-            // Membership expiration cases:
-            // Triggered by the membership pallet: we should remove the identity only for the main
-            // wot
-            sp_membership::Event::<IdtyIndex, MetaData>::MembershipExpired(idty_index) => {
+            sp_membership::Event::<IdtyIndex, MetaData>::MembershipAcquired(idty_index, _) => {
                 if !T::IsSubWot::get() {
-                    Self::dispath_idty_call(pallet_identity::Call::remove_identity {
-                        idty_index: *idty_index,
-                        idty_name: None,
-                    });
+                    // when membership is acquired, validate identity
+                    // (only used on first membership acquiry)
+                    pallet_identity::Pallet::<T>::try_validate_identity(*idty_index);
                 }
             }
+            sp_membership::Event::<IdtyIndex, MetaData>::MembershipExpired(_) => {}
             // Membership revocation cases:
             // - Triggered by main identity removal: the underlying identity will be removed by the
             // caller.
@@ -291,21 +298,23 @@ where
     }
 }
 
+// implement identity event handler
 impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pallet<T, I> {
     fn on_idty_change(idty_index: IdtyIndex, idty_event: &IdtyEvent<T>) -> Weight {
         match idty_event {
             IdtyEvent::Created { creator } => {
-                if let Err(e) = <pallet_certification::Pallet<T, I>>::force_add_cert(
-                    frame_system::Origin::<T>::Root.into(),
-                    *creator,
-                    idty_index,
-                    true,
+                if let Err(e) = <pallet_certification::Pallet<T, I>>::do_add_cert_checked(
+                    *creator, idty_index, true,
                 ) {
                     sp_std::if_std! {
                         println!("fail to force add cert: {:?}", e)
                     }
                 }
             }
+            IdtyEvent::Validated => {
+                // auto claim membership on main wot
+                <pallet_membership::Pallet<T, I>>::try_claim_membership(idty_index);
+            }
             IdtyEvent::Removed { status } => {
                 if *status != IdtyStatus::Validated {
                     if let Err(e) =
@@ -320,12 +329,14 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall
                     }
                 }
             }
-            IdtyEvent::Confirmed | IdtyEvent::Validated | IdtyEvent::ChangedOwnerKey { .. } => {}
+            IdtyEvent::Confirmed | IdtyEvent::ChangedOwnerKey { .. } => {}
         }
         Weight::zero()
     }
 }
 
+// implement certification event handlers
+// new cert handler
 impl<T: Config<I>, I: 'static> pallet_certification::traits::OnNewcert<IdtyIndex> for Pallet<T, I> {
     fn on_new_cert(
         _issuer: IdtyIndex,
@@ -340,6 +351,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>
 {
@@ -354,13 +366,12 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyI
             && pallet_membership::Pallet::<T, I>::is_member(&receiver)
         {
             if T::IsSubWot::get() {
-                // Revoke receiver membership
-                let call = pallet_membership::Call::<T, I>::revoke_membership {
-                    maybe_idty_id: Some(receiver),
-                };
-                if let Err(e) = call.dispatch_bypass_filter(RawOrigin::Root.into()) {
+                // expire receiver membership
+                // it gives him a bit of time to get back enough certs
+                if let Err(e) = <pallet_membership::Pallet<T, I>>::force_expire_membership(receiver)
+                {
                     sp_std::if_std! {
-                        println!("fail to dispatch membership call: {:?}", e)
+                        println!("fail to expire membership: {:?}", e)
                     }
                 }
             } else {
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
index 6b9bf90cf785016ca0029d28a92b13b5a4df5905..a2e645a13ad0d224feb9537529ef129737d0f657 100644
--- a/pallets/duniter-wot/src/mock.rs
+++ b/pallets/duniter-wot/src/mock.rs
@@ -143,7 +143,7 @@ parameter_types! {
 }
 
 impl pallet_membership::Config<Instance1> for Test {
-    type CheckCallAllowed = DuniterWot;
+    type CheckMembershipCallAllowed = DuniterWot;
     type IdtyId = IdtyIndex;
     type IdtyIdOf = IdentityIndexOf<Self>;
     type AccountIdOf = ();
@@ -198,7 +198,7 @@ parameter_types! {
 }
 
 impl pallet_membership::Config<Instance2> for Test {
-    type CheckCallAllowed = SmithSubWot;
+    type CheckMembershipCallAllowed = SmithSubWot;
     type IdtyId = IdtyIndex;
     type IdtyIdOf = IdentityIndexOf<Self>;
     type AccountIdOf = ();
diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs
index 3c51f2f6b500683277837c1db6b8a5dd9db77d37..7f98d970f7f134e5207d1ecbe1771c8ec39c4640 100644
--- a/pallets/duniter-wot/src/tests.rs
+++ b/pallets/duniter-wot/src/tests.rs
@@ -55,6 +55,7 @@ fn test_creator_not_allowed_to_create_idty() {
     });
 }
 
+/// test smith joining workflow
 #[test]
 fn test_join_smiths() {
     new_test_ext(5, 3).execute_with(|| {
@@ -79,27 +80,26 @@ fn test_join_smiths() {
 
         // Then, Dave should be able to claim his membership
         run_to_block(4);
-        assert_ok!(SmithMembership::claim_membership(
-            RuntimeOrigin::signed(4),
-            Some(4)
-        ));
+        assert_ok!(SmithMembership::claim_membership(RuntimeOrigin::signed(4),));
         System::assert_has_event(RuntimeEvent::SmithMembership(
             pallet_membership::Event::MembershipAcquired(4),
         ));
     });
 }
 
+/// test smith membership expiry after cert expiration
 #[test]
-fn test_smith_certs_expirations_should_revoke_smith_membership() {
+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::MembershipRevoked(1),
+            pallet_membership::Event::MembershipExpired(1),
         ));
     });
 }
 
+/// 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(|| {
@@ -124,6 +124,7 @@ fn test_smith_member_cant_change_its_idty_address() {
     });
 }
 
+/// members of the smith subwot can not remove their identity
 #[test]
 fn test_smith_member_cant_revoke_its_idty() {
     new_test_ext(5, 3).execute_with(|| {
@@ -147,6 +148,7 @@ fn test_smith_member_cant_revoke_its_idty() {
     });
 }
 
+/// test identity creation and that a first cert is emitted
 #[test]
 fn test_create_idty_ok() {
     new_test_ext(5, 2).execute_with(|| {
@@ -173,6 +175,7 @@ fn test_create_idty_ok() {
     });
 }
 
+/// test identity validation
 #[test]
 fn test_new_idty_validation() {
     new_test_ext(5, 2).execute_with(|| {
@@ -197,6 +200,12 @@ fn test_new_idty_validation() {
             receiver_received_count: 2,
         }));
 
+        // Ferdie should not be able to claim membership
+        // assert_noop!(
+        //     Membership::claim_membership(RuntimeOrigin::signed(6)),
+        //     pallet_membership::Error::<Test, Instance1>::xxx
+        // );
+
         // Anyone should be able to validate Ferdie identity
         run_to_block(5);
         assert_ok!(Identity::validate_identity(RuntimeOrigin::signed(42), 6));
@@ -301,15 +310,16 @@ fn test_revoke_idty() {
     });
 }
 
+/// test that expired membership lose the identity and can not be certified
 #[test]
-fn test_idty_membership_expire_them_requested() {
+fn test_idty_membership_expire() {
     new_test_ext(3, 2).execute_with(|| {
         run_to_block(4);
 
         // Alice renews her membership
-        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1), None));
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1)));
         // Bob renews his membership
-        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2), None));
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2)));
 
         // Charlie's membership should expire at block #8
         run_to_block(8);
@@ -318,11 +328,22 @@ fn test_idty_membership_expire_them_requested() {
         System::assert_has_event(RuntimeEvent::Membership(
             pallet_membership::Event::MembershipExpired(3),
         ));
+        // membership expiry should not trigger identity removal
+        assert!(!System::events().iter().any(|record| record.event
+            == RuntimeEvent::Identity(pallet_identity::Event::IdtyRemoved { idty_index: 3 })));
+        // it should be moved to pending membership instead
+        assert!(Membership::pending_membership(3).is_some());
+
+        // then pending membership should expire and identity should finally be removed
+        run_to_block(11);
+        System::assert_has_event(RuntimeEvent::Membership(
+            pallet_membership::Event::PendingMembershipExpired(3),
+        ));
         System::assert_has_event(RuntimeEvent::Identity(
             pallet_identity::Event::IdtyRemoved { idty_index: 3 },
         ));
 
-        // Charlie's identity should be removed at block #8
+        // Charlie's identity should be removed at block #11
         assert!(Identity::identity(3).is_none());
 
         // Alice can't renew her cert to Charlie
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index 6307e2d3d3c60ce48070d64f62e002e3d67202ef..06514db7121b3129749770de06ff6521450dc892 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -367,6 +367,7 @@ pub mod pallet {
 
         #[pallet::weight(T::WeightInfo::validate_identity())]
         /// validate the owned identity (must meet the main wot requirements)
+        // automatically claim membership if not done
         pub fn validate_identity(
             origin: OriginFor<T>,
             idty_index: T::IdtyIndex,
@@ -499,6 +500,7 @@ pub mod pallet {
 
             ensure!(
                 if let Some((ref old_owner_key, last_change)) = idty_value.old_owner_key {
+                    // old owner key can also revoke the identity until the period expired
                     revocation_key == idty_value.owner_key
                         || (&revocation_key == old_owner_key
                             && frame_system::Pallet::<T>::block_number()
@@ -509,8 +511,10 @@ pub mod pallet {
                 Error::<T>::InvalidRevocationKey
             );
 
+            // make sure that no wot prevents identity removal
             T::CheckIdtyCallAllowed::check_remove_identity(idty_index)?;
 
+            // then check payload signature
             let genesis_hash = frame_system::Pallet::<T>::block_hash(T::BlockNumber::zero());
             let revocation_payload = RevocationPayload {
                 genesis_hash,
@@ -523,6 +527,7 @@ pub mod pallet {
                 Error::<T>::InvalidRevocationSig
             );
 
+            // finally if all checks pass, remove identity
             Self::do_remove_identity(idty_index);
             Ok(().into())
         }
@@ -639,6 +644,22 @@ pub mod pallet {
     // INTERNAL FUNCTIONS //
 
     impl<T: Config> Pallet<T> {
+        /// try to validate identity
+        // (used when membership is claimed first)
+        pub fn try_validate_identity(idty_index: T::IdtyIndex) {
+            if let Some(mut idty_value) = Identities::<T>::get(idty_index) {
+                // only does something if identity is not yet validated
+                if idty_value.status != IdtyStatus::Validated {
+                    idty_value.removable_on = T::BlockNumber::zero();
+                    idty_value.status = IdtyStatus::Validated;
+
+                    <Identities<T>>::insert(idty_index, idty_value);
+                    Self::deposit_event(Event::IdtyValidated { idty_index });
+                }
+                // already validated, no need to re-validate
+            }
+        }
+
         /// perform identity removal
         pub(super) fn do_remove_identity(idty_index: T::IdtyIndex) -> Weight {
             if let Some(idty_val) = Identities::<T>::get(idty_index) {
diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs
index 58efc4d0ff9f1327a68f302685a2927c82e3bdac..1d633e29399e956f75a3117ce403ac349670a62e 100644
--- a/pallets/identity/src/types.rs
+++ b/pallets/identity/src/types.rs
@@ -75,12 +75,18 @@ impl<'de> serde::Deserialize<'de> for IdtyName {
 
 /// status of the identity
 /// used for temporary period before validation
+/// also used for buffer when losing membership before being deleted
 #[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
 #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
 pub enum IdtyStatus {
+    /// created through a first certification
     Created,
+    /// confirmed by owner with a name published
     ConfirmedByOwner,
+    /// validated by the main web of trust
     Validated,
+    // disabled by the main web of trust, deletion planned
+    // Disabled,
 }
 impl Default for IdtyStatus {
     fn default() -> Self {
diff --git a/pallets/membership/src/benchmarking.rs b/pallets/membership/src/benchmarking.rs
index 0e0daff567c54f258cab599e1fdf221b4664f054..3196d10c52dfe0238103d77be1a0515585dbf0e7 100644
--- a/pallets/membership/src/benchmarking.rs
+++ b/pallets/membership/src/benchmarking.rs
@@ -37,12 +37,6 @@ benchmarks_instance_pallet! {
         where
             T::IdtyId: From<u32>,
     }
-    force_request_membership {
-        let idty: T::IdtyId = 5.into();
-    }: _<T::RuntimeOrigin>(RawOrigin::Root.into(), idty, T::MetaData ::default() )
-    verify {
-        assert_has_event::<T, I>(Event::<T, I>::MembershipRequested(idty).into());
-    }
     request_membership {
         // Dave identity (4)
         // for main wot, no constraints
@@ -57,7 +51,7 @@ benchmarks_instance_pallet! {
         call.dispatch_bypass_filter(caller_origin).ok();
     }
     verify {
-        if T::CheckCallAllowed::check_idty_allowed_to_request_membership(&idty).is_ok() {
+        if T::CheckMembershipCallAllowed::check_idty_allowed_to_request_membership(&idty).is_ok() {
             assert_has_event::<T, I>(Event::<T, I>::MembershipRequested(idty).into());
         }
     }
diff --git a/pallets/membership/src/lib.rs b/pallets/membership/src/lib.rs
index b8beaa20e2178cae4c8a3fc5917780f36100d566..b998ce5b5b35f4eb57910ad69b09dd88fce6ebf3 100644
--- a/pallets/membership/src/lib.rs
+++ b/pallets/membership/src/lib.rs
@@ -63,12 +63,12 @@ pub mod pallet {
     #[pallet::config]
     pub trait Config<I: 'static = ()>: frame_system::Config {
         /// Ask the runtime whether the identity can perform membership operations
-        type CheckCallAllowed: CheckCallAllowed<Self::IdtyId>;
+        type CheckMembershipCallAllowed: CheckMembershipCallAllowed<Self::IdtyId>;
         /// Something that identifies an identity
         type IdtyId: Copy + MaybeSerializeDeserialize + Parameter + Ord;
-        /// Something that give the IdtyId on an account id
+        /// Something that gives the IdtyId of an AccountId
         type IdtyIdOf: Convert<Self::AccountId, Option<Self::IdtyId>>;
-        /// Something that give the  account id on an OdtyId
+        /// Something that gives the AccountId of an IdtyId
         type AccountIdOf: Convert<Self::IdtyId, Option<Self::AccountId>>;
         /// Optional metadata
         type MetaData: Default + Parameter + Validate<Self::AccountId>;
@@ -201,18 +201,6 @@ pub mod pallet {
 
     #[pallet::call]
     impl<T: Config<I>, I: 'static> Pallet<T, I> {
-        /// request membership without checks
-        #[pallet::weight(T::WeightInfo::force_request_membership())]
-        pub fn force_request_membership(
-            origin: OriginFor<T>,
-            idty_id: T::IdtyId,
-            metadata: T::MetaData,
-        ) -> DispatchResultWithPostInfo {
-            ensure_root(origin)?;
-
-            Self::do_request_membership(idty_id, metadata)
-        }
-
         /// submit a membership request (must have a declared identity)
         /// (only available for sub wot, automatic for main wot)
         #[pallet::weight(T::WeightInfo::request_membership())]
@@ -226,56 +214,39 @@ pub mod pallet {
             if !metadata.validate(&who) {
                 return Err(Error::<T, I>::InvalidMetaData.into());
             }
-            T::CheckCallAllowed::check_idty_allowed_to_request_membership(&idty_id)?;
+            T::CheckMembershipCallAllowed::check_idty_allowed_to_request_membership(&idty_id)?;
 
             Self::do_request_membership(idty_id, metadata)
         }
 
-        /// claim that the previously requested membership fullfills the requirements
-        /// (only available for sub wot, automatic for main wot)
+        /// claim pending membership to become actual memberhip
+        /// the requested membership must fullfill requirements
+        // for main wot claim_membership is called automatically when validating identity
         #[pallet::weight(T::WeightInfo::claim_membership())]
-        pub fn claim_membership(
-            origin: OriginFor<T>,
-            maybe_idty_id: Option<T::IdtyId>,
-        ) -> DispatchResultWithPostInfo {
-            // Verify phase
-            let idty_id = Self::ensure_origin_and_get_idty_id(origin, maybe_idty_id)?;
-
-            ensure!(
-                !Membership::<T, I>::contains_key(idty_id),
-                Error::<T, I>::MembershipAlreadyAcquired
-            );
-
-            T::CheckCallAllowed::check_idty_allowed_to_claim_membership(&idty_id)?;
-
-            let metadata = PendingMembership::<T, I>::take(idty_id)
-                .ok_or(Error::<T, I>::MembershipRequestNotFound)?;
-
-            // Apply phase
-            Self::do_renew_membership_inner(idty_id);
-            Self::deposit_event(Event::MembershipAcquired(idty_id));
-            T::OnEvent::on_event(&sp_membership::Event::MembershipAcquired(idty_id, metadata));
+        pub fn claim_membership(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
+            // get identity
+            let idty_id = Self::get_idty_id(origin)?;
 
+            Self::check_allowed_to_claim(idty_id)?;
+            Self::do_claim_membership(idty_id);
             Ok(().into())
         }
 
         /// extend the validity period of an active membership
         #[pallet::weight(T::WeightInfo::renew_membership())]
-        pub fn renew_membership(
-            origin: OriginFor<T>,
-            maybe_idty_id: Option<T::IdtyId>,
-        ) -> DispatchResultWithPostInfo {
+        pub fn renew_membership(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
             // Verify phase
-            let idty_id = Self::ensure_origin_and_get_idty_id(origin, maybe_idty_id)?;
-
-            ensure!(
-                Self::get_membership(&idty_id).is_some(),
-                Error::<T, I>::MembershipNotFound
-            );
+            let idty_id = Self::get_idty_id(origin)?;
+            let membership_data =
+                Membership::<T, I>::get(idty_id).ok_or(Error::<T, I>::MembershipNotFound)?;
 
-            T::CheckCallAllowed::check_idty_allowed_to_renew_membership(&idty_id)?;
+            T::CheckMembershipCallAllowed::check_idty_allowed_to_renew_membership(&idty_id)?;
 
-            let _ = Self::do_renew_membership(idty_id);
+            // apply phase
+            Self::unschedule_membership_expiry(idty_id, membership_data.expire_on);
+            Self::insert_membership_and_schedule_expiry(idty_id);
+            Self::deposit_event(Event::MembershipRenewed(idty_id));
+            T::OnEvent::on_event(&sp_membership::Event::MembershipRenewed(idty_id));
 
             Ok(().into())
         }
@@ -283,18 +254,12 @@ pub mod pallet {
         /// revoke an active membership
         /// (only available for sub wot, automatic for main wot)
         #[pallet::weight(T::WeightInfo::revoke_membership())]
-        pub fn revoke_membership(
-            origin: OriginFor<T>,
-            maybe_idty_id: Option<T::IdtyId>,
-        ) -> DispatchResultWithPostInfo {
+        pub fn revoke_membership(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
             // Verify phase
-            let idty_id = Self::ensure_origin_and_get_idty_id(origin, maybe_idty_id)?;
+            let idty_id = Self::get_idty_id(origin)?;
 
             // Apply phase
-            if Self::remove_membership(&idty_id) {
-                Self::deposit_event(Event::MembershipRevoked(idty_id));
-                T::OnEvent::on_event(&sp_membership::Event::MembershipRevoked(idty_id));
-            }
+            Self::do_revoke_membership(idty_id);
 
             Ok(().into())
         }
@@ -303,27 +268,60 @@ pub mod pallet {
     // INTERNAL FUNCTIONS //
 
     impl<T: Config<I>, I: 'static> Pallet<T, I> {
-        /// perform the membership renewal and emit events
-        pub(super) fn do_renew_membership(idty_id: T::IdtyId) -> Weight {
-            let total_weight = Self::do_renew_membership_inner(idty_id);
-            Self::deposit_event(Event::MembershipRenewed(idty_id));
-            T::OnEvent::on_event(&sp_membership::Event::MembershipRenewed(idty_id));
-            total_weight
+        /// force request membership
+        pub fn force_request_membership(
+            idty_id: T::IdtyId,
+            metadata: T::MetaData,
+        ) -> DispatchResultWithPostInfo {
+            Self::do_request_membership(idty_id, metadata)
         }
-        /// perform the membership renewal
-        fn do_renew_membership_inner(idty_id: T::IdtyId) -> Weight {
+
+        /// force expire membership
+        pub fn force_expire_membership(idty_id: T::IdtyId) -> DispatchResultWithPostInfo {
+            let new_expire_on = frame_system::pallet::Pallet::<T>::block_number()
+                + T::PendingMembershipPeriod::get();
+            Self::do_expire_membership(idty_id, new_expire_on);
+
+            Ok(().into())
+        }
+
+        /// try to claim membership if not already done
+        pub fn try_claim_membership(idty_id: T::IdtyId) {
+            if Self::check_allowed_to_claim(idty_id).is_ok() {
+                Self::do_claim_membership(idty_id);
+            }
+            // else { should not try to claim membership if not allowed}
+        }
+
+        /// force revoke membership
+        pub fn force_revoke_membership(idty_id: T::IdtyId) {
+            Self::do_revoke_membership(idty_id);
+        }
+
+        /// unschedule membership expiry
+        fn unschedule_membership_expiry(idty_id: T::IdtyId, block_number: T::BlockNumber) {
+            let mut scheduled = MembershipsExpireOn::<T, I>::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);
+            }
+        }
+        /// schedule membership expiry
+        fn insert_membership_and_schedule_expiry(idty_id: T::IdtyId) {
             let block_number = frame_system::pallet::Pallet::<T>::block_number();
             let expire_on = block_number + T::MembershipPeriod::get();
 
-            Self::insert_membership(idty_id, MembershipData { expire_on });
+            Membership::<T, I>::insert(idty_id, MembershipData { expire_on });
             MembershipsExpireOn::<T, I>::append(expire_on, idty_id);
-            Weight::zero()
         }
+
         /// perform the membership request
         fn do_request_membership(
             idty_id: T::IdtyId,
             metadata: T::MetaData,
         ) -> DispatchResultWithPostInfo {
+            // checks
             if PendingMembership::<T, I>::contains_key(idty_id) {
                 return Err(Error::<T, I>::MembershipAlreadyRequested.into());
             }
@@ -334,6 +332,7 @@ pub mod pallet {
             let block_number = frame_system::pallet::Pallet::<T>::block_number();
             let expire_on = block_number + T::PendingMembershipPeriod::get();
 
+            // apply membership request
             PendingMembership::<T, I>::insert(idty_id, metadata);
             PendingMembershipsExpireOn::<T, I>::append(expire_on, idty_id);
             Self::deposit_event(Event::MembershipRequested(idty_id));
@@ -341,38 +340,71 @@ pub mod pallet {
 
             Ok(().into())
         }
+
+        /// check that membership can be claimed
+        pub fn check_allowed_to_claim(idty_id: T::IdtyId) -> Result<(), DispatchError> {
+            PendingMembership::<T, I>::get(idty_id)
+                .ok_or(Error::<T, I>::MembershipRequestNotFound)?;
+            // enough certifications and distance rule for example
+            T::CheckMembershipCallAllowed::check_idty_allowed_to_claim_membership(&idty_id)?;
+            Ok(())
+        }
+
+        /// perform membership claim
+        fn do_claim_membership(idty_id: T::IdtyId) {
+            if let Some(metadata) = PendingMembership::<T, I>::take(idty_id) {
+                Self::insert_membership_and_schedule_expiry(idty_id);
+                Self::deposit_event(Event::MembershipAcquired(idty_id));
+                T::OnEvent::on_event(&sp_membership::Event::MembershipAcquired(idty_id, metadata));
+            }
+            // else { unreachable if check_allowed_to_claim called before }
+        }
+
+        /// perform membership revokation
+        fn do_revoke_membership(idty_id: T::IdtyId) {
+            if let Some(membership_data) = Membership::<T, I>::take(idty_id) {
+                Self::unschedule_membership_expiry(idty_id, membership_data.expire_on);
+                Self::deposit_event(Event::MembershipRevoked(idty_id));
+                T::OnEvent::on_event(&sp_membership::Event::MembershipRevoked(idty_id));
+            }
+        }
+
+        /// perform mebership expiration
+        // add pending membership and schedule expiry of pending membership
+        fn do_expire_membership(idty_id: T::IdtyId, expire_on: T::BlockNumber) -> Weight {
+            if Membership::<T, I>::take(idty_id).is_some() {
+                PendingMembership::<T, I>::insert(idty_id, T::MetaData::default());
+                PendingMembershipsExpireOn::<T, I>::append(expire_on, idty_id);
+            } // else should not happen
+
+            Self::deposit_event(Event::MembershipExpired(idty_id));
+            T::OnEvent::on_event(&sp_membership::Event::MembershipExpired(idty_id))
+        }
+
         /// check the origin and get identity id if valid
-        fn ensure_origin_and_get_idty_id(
-            origin: OriginFor<T>,
-            maybe_idty_id: Option<T::IdtyId>,
-        ) -> Result<T::IdtyId, DispatchError> {
-            match origin.into() {
-                Ok(RawOrigin::Root) => {
-                    maybe_idty_id.ok_or_else(|| Error::<T, I>::IdtyIdNotFound.into())
-                }
-                Ok(RawOrigin::Signed(account_id)) => T::IdtyIdOf::convert(account_id)
-                    .ok_or_else(|| Error::<T, I>::IdtyIdNotFound.into()),
-                _ => Err(BadOrigin.into()),
+        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())
+            } else {
+                Err(BadOrigin.into())
             }
         }
-        /// perform the membership expiration if it has not been renewed meanwhile
+        /// perform the membership expiry scheduled at given block
+        // MembershipExpired events should be handeled by main wot and delete identity
+        // expired membership get back to pending membership
         fn expire_memberships(block_number: T::BlockNumber) -> Weight {
             let mut total_weight: Weight = Weight::zero();
+            let new_expire_on = block_number + T::PendingMembershipPeriod::get();
 
             for idty_id in MembershipsExpireOn::<T, I>::take(block_number) {
-                if let Some(member_data) = Self::get_membership(&idty_id) {
-                    if member_data.expire_on == block_number {
-                        Self::remove_membership(&idty_id);
-                        Self::deposit_event(Event::MembershipExpired(idty_id));
-                        total_weight +=
-                            T::OnEvent::on_event(&sp_membership::Event::MembershipExpired(idty_id));
-                    }
-                }
+                // remove membership (take)
+                total_weight += Self::do_expire_membership(idty_id, new_expire_on);
             }
 
             total_weight
         }
         /// perform the expiration of pending membership planned at given block
+        // only expire pending membership if still pending
         fn expire_pending_memberships(block_number: T::BlockNumber) -> Weight {
             let mut total_weight: Weight = Weight::zero();
 
@@ -392,18 +424,6 @@ pub mod pallet {
         pub(super) fn is_member_inner(idty_id: &T::IdtyId) -> bool {
             Membership::<T, I>::contains_key(idty_id)
         }
-        /// insert membership in storage
-        fn insert_membership(idty_id: T::IdtyId, membership_data: MembershipData<T::BlockNumber>) {
-            Membership::<T, I>::insert(idty_id, membership_data);
-        }
-        /// retreive membership from storage
-        fn get_membership(idty_id: &T::IdtyId) -> Option<MembershipData<T::BlockNumber>> {
-            Membership::<T, I>::try_get(idty_id).ok()
-        }
-        /// remove membership from storage
-        fn remove_membership(idty_id: &T::IdtyId) -> bool {
-            Membership::<T, I>::take(idty_id).is_some()
-        }
     }
 }
 
diff --git a/pallets/membership/src/mock.rs b/pallets/membership/src/mock.rs
index e51038e9a57e6b5c0566caf4c6b2c5a9e74dc890..b4a65ac6a33a5779c5fe77df9f95b06a26180393 100644
--- a/pallets/membership/src/mock.rs
+++ b/pallets/membership/src/mock.rs
@@ -83,7 +83,7 @@ parameter_types! {
 }
 
 impl pallet_membership::Config for Test {
-    type CheckCallAllowed = ();
+    type CheckMembershipCallAllowed = ();
     type IdtyId = IdtyId;
     type IdtyIdOf = ConvertInto;
     type AccountIdOf = ConvertInto;
diff --git a/pallets/membership/src/tests.rs b/pallets/membership/src/tests.rs
index b730a80f4474d9d46c11683a250548c055c9da90..f11ab9680a18bc8206a4bb5d8d114781b7235b93 100644
--- a/pallets/membership/src/tests.rs
+++ b/pallets/membership/src/tests.rs
@@ -16,12 +16,15 @@
 
 use crate::mock::*;
 use crate::{Error, Event};
-use frame_support::assert_ok;
+use frame_support::{assert_noop, assert_ok};
 use maplit::btreemap;
 use sp_membership::traits::*;
 use sp_membership::MembershipData;
 use sp_runtime::traits::IsMember;
 
+// alias
+type RtEvent = RuntimeEvent;
+
 fn default_gen_conf() -> DefaultMembershipConfig {
     DefaultMembershipConfig {
         memberships: btreemap![
@@ -49,10 +52,10 @@ fn test_genesis_build() {
 fn test_membership_already_acquired() {
     new_test_ext(default_gen_conf()).execute_with(|| {
         run_to_block(1);
-        // Merbership 0 cannot be reclaimed
-        assert_eq!(
-            DefaultMembership::claim_membership(RuntimeOrigin::signed(0), None),
-            Err(Error::<Test, _>::MembershipAlreadyAcquired.into())
+        // Membership 0 cannot be reclaimed because there is no membership request
+        assert_noop!(
+            DefaultMembership::claim_membership(RuntimeOrigin::signed(0)),
+            Error::<Test, _>::MembershipRequestNotFound
         );
     });
 }
@@ -61,73 +64,97 @@ fn test_membership_already_acquired() {
 fn test_membership_request_not_found() {
     new_test_ext(default_gen_conf()).execute_with(|| {
         run_to_block(1);
-        // Merbership 0 cannot be reclaimed
-        assert_eq!(
-            DefaultMembership::claim_membership(RuntimeOrigin::signed(1), None),
-            Err(Error::<Test, _>::MembershipRequestNotFound.into())
+        // Membership 0 cannot be reclaimed
+        assert_noop!(
+            DefaultMembership::claim_membership(RuntimeOrigin::signed(1)),
+            Error::<Test, _>::MembershipRequestNotFound
         );
     });
 }
 
+/// test membership expiration
+// membership should be moved to pending membership and expire after
 #[test]
-fn test_membership_renewal() {
+fn test_membership_expiration() {
     new_test_ext(default_gen_conf()).execute_with(|| {
+        // Membership 0 should not expired on block #2
         run_to_block(2);
-        // Merbership 0 can be renewable on block #2
-        assert_ok!(DefaultMembership::renew_membership(
-            RuntimeOrigin::signed(0),
-            None
-        ),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::MembershipRenewed(0))
-        );
+        assert!(DefaultMembership::is_member(&0));
+        // Membership 0 should expire on block #3
+        run_to_block(3);
+        assert!(!DefaultMembership::is_member(&0));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipExpired(0)));
+        // it should be added to pending membership and expire on block #6
+        run_to_block(6);
+        System::assert_has_event(RtEvent::DefaultMembership(Event::PendingMembershipExpired(
+            0,
+        )));
     });
 }
 
+/// test membership renewal
+// there is no limit for membership renewal outside wot rules (number of certs, distance rule)
 #[test]
-fn test_membership_expiration() {
+fn test_membership_renewal() {
     new_test_ext(default_gen_conf()).execute_with(|| {
-        // Merbership 0 should not expired on block #2
+        // membership still valid at block 2
         run_to_block(2);
-        assert!(DefaultMembership::is_member(&0),);
-        // Merbership 0 should expire on block #3
+        assert!(DefaultMembership::is_member(&0));
+        // Membership 0 can be renewed
+        assert_ok!(DefaultMembership::renew_membership(RuntimeOrigin::signed(
+            0
+        ),));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipRenewed(0)));
+        // membership should not expire at block 3 to 6 because it has been renewed
         run_to_block(3);
-        assert!(!DefaultMembership::is_member(&0),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::MembershipExpired(0))
+        assert!(DefaultMembership::is_member(&0));
+        run_to_block(6);
+        assert!(DefaultMembership::is_member(&0));
+        // membership should expire at block 7 (2+5)
+        run_to_block(7);
+        assert!(!DefaultMembership::is_member(&0));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipExpired(0)));
+    });
+}
+
+/// test membership renewal for non member identity
+#[test]
+fn test_membership_renewal_nope() {
+    new_test_ext(default_gen_conf()).execute_with(|| {
+        run_to_block(2);
+        assert!(!DefaultMembership::is_member(&1));
+        // Membership 1 can not be renewed
+        assert_noop!(
+            DefaultMembership::renew_membership(RuntimeOrigin::signed(1)),
+            Error::<Test, _>::MembershipNotFound,
         );
+        run_to_block(3);
+        assert!(!DefaultMembership::is_member(&1));
     });
 }
 
+/// test membership revocation
 #[test]
 fn test_membership_revocation() {
     new_test_ext(default_gen_conf()).execute_with(|| {
         run_to_block(1);
-        // Merbership 0 can be revocable on block #1
-        assert_ok!(DefaultMembership::revoke_membership(
-            RuntimeOrigin::signed(0),
-            None
-        ),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::MembershipRevoked(0))
-        );
+        // Membership 0 can be revocable on block #1
+        assert_ok!(DefaultMembership::revoke_membership(RuntimeOrigin::signed(
+            0
+        ),));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipRevoked(0)));
 
         // Membership 0 can re-request membership
         run_to_block(5);
         assert_ok!(DefaultMembership::request_membership(
             RuntimeOrigin::signed(0),
             ()
-        ),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::MembershipRequested(0))
-        );
+        ));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipRequested(0)));
     });
 }
 
+/// test pending membership expiration
 #[test]
 fn test_pending_membership_expiration() {
     new_test_ext(Default::default()).execute_with(|| {
@@ -136,68 +163,58 @@ fn test_pending_membership_expiration() {
         assert_ok!(DefaultMembership::request_membership(
             RuntimeOrigin::signed(0),
             ()
-        ),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::MembershipRequested(0))
-        );
+        ));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipRequested(0)));
 
         // Then, idty 0 shold still in pending memberships until PendingMembershipPeriod ended
         run_to_block(PendingMembershipPeriod::get());
-        assert!(DefaultMembership::is_in_pending_memberships(0),);
+        assert!(DefaultMembership::is_in_pending_memberships(0));
 
         // Then, idty 0 request should expire after PendingMembershipPeriod
         run_to_block(1 + PendingMembershipPeriod::get());
-        assert!(!DefaultMembership::is_in_pending_memberships(0),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::PendingMembershipExpired(0))
-        );
+        assert!(!DefaultMembership::is_in_pending_memberships(0));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::PendingMembershipExpired(
+            0,
+        )));
     })
 }
 
+/// test membership workflow
+// - request membership
+// - claim membership
+// - renew membership
+// - membership expiry
 #[test]
 fn test_membership_workflow() {
     new_test_ext(Default::default()).execute_with(|| {
-        // Idty 0 request membership
+        // - Idty 0 request membership
         run_to_block(1);
         assert_ok!(DefaultMembership::request_membership(
             RuntimeOrigin::signed(0),
             ()
-        ),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::MembershipRequested(0))
-        );
+        ));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipRequested(0)));
 
-        // Then, idty 0 claim membership
+        // - Then, idty 0 claim membership
         run_to_block(2);
-        assert_ok!(DefaultMembership::claim_membership(
-            RuntimeOrigin::signed(0),
-            None
-        ),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::MembershipAcquired(0))
-        );
+        assert_ok!(DefaultMembership::claim_membership(RuntimeOrigin::signed(
+            0
+        ),));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipAcquired(0)));
 
-        // Then, idty 0 claim renewal, should success
+        // - Then, idty 0 claim renewal, should success
         run_to_block(2);
-        assert_ok!(DefaultMembership::renew_membership(
-            RuntimeOrigin::signed(0),
-            None
-        ),);
+        assert_ok!(DefaultMembership::renew_membership(RuntimeOrigin::signed(
+            0
+        ),));
 
-        // Then, idty 0 shoul still member until membership period ended
-        run_to_block(2 + MembershipPeriod::get() - 1);
+        // idty 0 should still be member until membership period ended
+        run_to_block(6); // 2 + 5 - 1
         assert!(DefaultMembership::is_member(&0));
 
-        // Then, idty 0 shoul expire after membership period
-        run_to_block(2 + MembershipPeriod::get());
-        assert!(!DefaultMembership::is_member(&0),);
-        assert_eq!(
-            System::events()[0].event,
-            RuntimeEvent::DefaultMembership(Event::MembershipExpired(0))
-        );
+        // - Then, idty 0 should expire after membership period
+        run_to_block(7); // 2 + 5
+        assert!(!DefaultMembership::is_member(&0));
+        System::assert_has_event(RtEvent::DefaultMembership(Event::MembershipExpired(0)));
     });
 }
diff --git a/primitives/membership/src/traits.rs b/primitives/membership/src/traits.rs
index 9ab0d5b4e953b5d722ebd7c9c8e8bc51aaced363..0480a64f38aff07a12448a012e7860fbcd82c6a8 100644
--- a/primitives/membership/src/traits.rs
+++ b/primitives/membership/src/traits.rs
@@ -16,13 +16,13 @@
 
 use frame_support::pallet_prelude::*;
 
-pub trait CheckCallAllowed<IdtyId> {
+pub trait CheckMembershipCallAllowed<IdtyId> {
     fn check_idty_allowed_to_claim_membership(idty_id: &IdtyId) -> Result<(), DispatchError>;
     fn check_idty_allowed_to_renew_membership(idty_id: &IdtyId) -> Result<(), DispatchError>;
     fn check_idty_allowed_to_request_membership(idty_id: &IdtyId) -> Result<(), DispatchError>;
 }
 
-impl<IdtyId> CheckCallAllowed<IdtyId> for () {
+impl<IdtyId> CheckMembershipCallAllowed<IdtyId> for () {
     fn check_idty_allowed_to_claim_membership(_: &IdtyId) -> Result<(), DispatchError> {
         Ok(())
     }
diff --git a/resources/metadata.scale b/resources/metadata.scale
index 06d4f6891828dfade5738b4d106249ba753edd96..6c236f8d95a610f8b1044687302dd08fea17a14d 100644
Binary files a/resources/metadata.scale and b/resources/metadata.scale differ
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index 2ea464a2fbe5e04e98e7bb2ff7d0ffb8b684f7e9..95a6ccabdf9bab3144fbc8163c37e7fbac4de79a 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -24,6 +24,7 @@ use frame_support::Parameter;
 use pallet_identity::IdtyEvent;
 use sp_runtime::traits::IsMember;
 
+// new session handler
 pub struct OnNewSessionHandler<Runtime>(core::marker::PhantomData<Runtime>);
 impl<Runtime> pallet_authority_members::traits::OnNewSession for OnNewSessionHandler<Runtime>
 where
@@ -35,8 +36,8 @@ where
     }
 }
 
+// identity change runtime handler
 pub struct OnIdtyChangeHandler<Runtime>(core::marker::PhantomData<Runtime>);
-
 impl<T> pallet_identity::traits::OnIdtyChange<T> for OnIdtyChangeHandler<T>
 where
     T: frame_system::Config<AccountId = AccountId>,
@@ -47,14 +48,8 @@ where
     fn on_idty_change(idty_index: IdtyIndex, idty_event: &IdtyEvent<T>) -> Weight {
         match idty_event {
             IdtyEvent::Validated => {
-                pallet_identity::Identities::<T>::mutate_exists(idty_index, |idty_val_opt| {
-                    if let Some(ref mut idty_val) = idty_val_opt {
-                        idty_val.data = IdtyData {
-                            first_eligible_ud:
-                                pallet_universal_dividend::Pallet::<T>::init_first_eligible_ud(),
-                        }
-                    }
-                });
+                // when identity is validated, it starts getting right to UD
+                // but this is handeled by membership event handler (MembershipAcquired)
             }
             IdtyEvent::ChangedOwnerKey { new_owner_key } => {
                 if let Err(e) = pallet_authority_members::Pallet::<T>::change_owner_key(
@@ -73,8 +68,8 @@ where
     }
 }
 
+// membership event runtime handler
 pub struct OnMembershipEventHandler<Inner, Runtime>(core::marker::PhantomData<(Inner, Runtime)>);
-
 impl<
         Inner: sp_membership::traits::OnEvent<IdtyIndex, ()>,
         Runtime: frame_system::Config<AccountId = AccountId>
@@ -85,7 +80,9 @@ impl<
 {
     fn on_event(membership_event: &sp_membership::Event<IdtyIndex, ()>) -> Weight {
         (match membership_event {
-            sp_membership::Event::MembershipRevoked(idty_index) => {
+            // when membership is removed, call on_removed_member handler which auto claims UD
+            sp_membership::Event::MembershipRevoked(idty_index)
+            | sp_membership::Event::MembershipExpired(idty_index) => {
                 if let Some(idty_value) = pallet_identity::Identities::<Runtime>::get(idty_index) {
                     if let Some(first_ud_index) = idty_value.data.first_eligible_ud.into() {
                         pallet_universal_dividend::Pallet::<Runtime>::on_removed_member(
@@ -99,15 +96,31 @@ impl<
                     Runtime::DbWeight::get().reads(1)
                 }
             }
-            _ => Weight::zero(),
+            // when main membership is acquired, it starts getting right to UD
+            sp_membership::Event::MembershipAcquired(idty_index, _) => {
+                pallet_identity::Identities::<Runtime>::mutate_exists(idty_index, |idty_val_opt| {
+                    if let Some(ref mut idty_val) = idty_val_opt {
+                        idty_val.data = IdtyData {
+                            first_eligible_ud:
+                                pallet_universal_dividend::Pallet::<Runtime>::init_first_eligible_ud(
+                                ),
+                        }
+                    }
+                });
+                Weight::zero()
+            }
+            // in other case, ther is nothing to do
+            sp_membership::Event::MembershipRenewed(_)
+            | sp_membership::Event::MembershipRequested(_)
+            | sp_membership::Event::PendingMembershipExpired(_) => Weight::zero(),
         }) + Inner::on_event(membership_event)
     }
 }
 
+// smith membership event handler
 pub struct OnSmithMembershipEventHandler<Inner, Runtime>(
     core::marker::PhantomData<(Inner, Runtime)>,
 );
-
 impl<
         IdtyIndex: Copy + Parameter,
         SessionKeysWrapper: Clone,
@@ -167,6 +180,7 @@ impl<
     }
 }
 
+// authority member removal handler
 pub struct OnRemovedAuthorityMemberHandler<Runtime>(core::marker::PhantomData<Runtime>);
 impl<Runtime> pallet_authority_members::traits::OnRemovedMember<IdtyIndex>
     for OnRemovedAuthorityMemberHandler<Runtime>
@@ -174,18 +188,14 @@ where
     Runtime: frame_system::Config + pallet_membership::Config<Instance2, IdtyId = IdtyIndex>,
 {
     fn on_removed_member(idty_index: IdtyIndex) -> Weight {
-        if let Err(e) = pallet_membership::Pallet::<Runtime, Instance2>::revoke_membership(
-            frame_system::RawOrigin::Root.into(),
-            Some(idty_index),
-        ) {
-            sp_std::if_std! {
-                println!("fail to revoke membership: {:?}", e)
-            }
-        }
+        // TODO investigate why we should remove smith membership when removing authority member
+        pallet_membership::Pallet::<Runtime, Instance2>::force_revoke_membership(idty_index);
+        // TODO investigate why weight zero
         Weight::zero()
     }
 }
 
+// identity removal handler
 pub struct RemoveIdentityConsumersImpl<Runtime>(core::marker::PhantomData<Runtime>);
 impl<Runtime> pallet_identity::traits::RemoveIdentityConsumers<IdtyIndex>
     for RemoveIdentityConsumersImpl<Runtime>
@@ -198,33 +208,16 @@ where
     fn remove_idty_consumers(idty_index: IdtyIndex) -> Weight {
         // Remove smith member
         if pallet_membership::Pallet::<Runtime, Instance2>::is_member(&idty_index) {
-            if let Err(e) = pallet_membership::Pallet::<Runtime, Instance2>::revoke_membership(
-                frame_system::RawOrigin::Root.into(),
-                Some(idty_index),
-            ) {
-                log::error!(
-                    target: "runtime::common",
-                    "Logic error: fail to revoke smith membership in remove_idty_consumers(): {:?}",
-                    e
-                );
-            }
+            pallet_membership::Pallet::<Runtime, Instance2>::force_revoke_membership(idty_index);
         }
         // Remove "classic" member
-        if let Err(e) = pallet_membership::Pallet::<Runtime, Instance1>::revoke_membership(
-            frame_system::RawOrigin::Root.into(),
-            Some(idty_index),
-        ) {
-            log::error!(
-                target: "runtime::common",
-                "Logic error: fail to revoke membership in remove_idty_consumers(): {:?}",
-                e
-            );
-        }
+        pallet_membership::Pallet::<Runtime, Instance1>::force_revoke_membership(idty_index);
 
         Weight::zero()
     }
 }
 
+// spend treasury handler
 pub struct TreasurySpendFunds<Runtime>(core::marker::PhantomData<Runtime>);
 impl<Runtime> pallet_treasury::SpendFunds<Runtime> for TreasurySpendFunds<Runtime>
 where
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index d89fdcb779f922a95a726f44b0c074015dca761e..3aa82401a4d6241deb34ac7b58c0505987abe48d 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -449,7 +449,7 @@ macro_rules! pallets_config {
         }
 
         impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime {
-            type CheckCallAllowed = Wot;
+            type CheckMembershipCallAllowed = Wot;
             type IdtyId = IdtyIndex;
             type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>;
             type AccountIdOf = common_runtime::providers::IdentityAccountIdProvider<Self>;
@@ -486,7 +486,7 @@ macro_rules! pallets_config {
         }
 
         impl pallet_membership::Config<Instance2> for Runtime {
-            type CheckCallAllowed = SmithSubWot;
+            type CheckMembershipCallAllowed = SmithSubWot;
             type IdtyId = IdtyIndex;
             type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>;
             type AccountIdOf = common_runtime::providers::IdentityAccountIdProvider<Self>;
diff --git a/runtime/common/src/weights/pallet_certification_cert.rs b/runtime/common/src/weights/pallet_certification_cert.rs
index 44140695115a66338b96c25d907af876ec43d299..acd4cd7aa9018d5a6e04a77e83e191f25ab6187c 100644
--- a/runtime/common/src/weights/pallet_certification_cert.rs
+++ b/runtime/common/src/weights/pallet_certification_cert.rs
@@ -14,21 +14,21 @@
 // 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 `common_runtime::certification`
+//! Autogenerated weights for `pallet_certification`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-04-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! HOSTNAME: `benjamin-xps139380`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
+//! DATE: 2023-05-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `Hugo`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("gdev-benchmark"), DB CACHE: 1024
 
 // Executed Command:
 // ./target/release/duniter
 // benchmark
 // pallet
-// --chain=dev
+// --chain=gdev-benchmark
 // --steps=50
 // --repeat=20
-// --pallet=common_runtime::certification
+// --pallet=pallet-certification
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
@@ -43,16 +43,16 @@
 use frame_support::{traits::Get, weights::Weight};
 use sp_std::marker::PhantomData;
 
-/// Weight functions for `common_runtime::certification`.
+/// Weight functions for `pallet_certification`.
 pub struct WeightInfo<T>(PhantomData<T>);
 impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T> {
 	// Storage: Cert StorageIdtyCertMeta (r:2 w:2)
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: Cert StorageCertsRemovableOn (r:1 w:1)
 	// Storage: Cert CertsByReceiver (r:1 w:1)
-	fn force_add_cert() -> Weight {
-		// Minimum execution time: 125_388 nanoseconds.
-		Weight::from_ref_time(140_411_000 as u64)
+	fn do_add_cert_checked() -> Weight {
+		// Minimum execution time: 48_363 nanoseconds.
+		Weight::from_ref_time(59_125_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(4 as u64))
 	}
@@ -62,8 +62,8 @@ impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T>
 	// Storage: Cert StorageCertsRemovableOn (r:1 w:1)
 	// Storage: Cert CertsByReceiver (r:1 w:1)
 	fn add_cert() -> Weight {
-		// Minimum execution time: 147_817 nanoseconds.
-		Weight::from_ref_time(153_330_000 as u64)
+		// Minimum execution time: 57_408 nanoseconds.
+		Weight::from_ref_time(69_281_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(7 as u64))
 			.saturating_add(T::DbWeight::get().writes(4 as u64))
 	}
@@ -72,8 +72,8 @@ impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T>
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: Membership Membership (r:1 w:0)
 	fn del_cert() -> Weight {
-		// Minimum execution time: 125_695 nanoseconds.
-		Weight::from_ref_time(150_360_000 as u64)
+		// Minimum execution time: 49_562 nanoseconds.
+		Weight::from_ref_time(61_695_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
@@ -84,10 +84,10 @@ impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T>
 	/// 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 {
-		// Minimum execution time: 129_529 nanoseconds.
-		Weight::from_ref_time(132_136_000 as u64)
-			// Standard Error: 75_161
-			.saturating_add(Weight::from_ref_time(38_016_325 as u64).saturating_mul(i as u64))
+		// Minimum execution time: 49_307 nanoseconds.
+		Weight::from_ref_time(49_926_000 as u64)
+			// Standard Error: 61_521
+			.saturating_add(Weight::from_ref_time(15_865_456 as u64).saturating_mul(i as u64))
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64)))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
diff --git a/runtime/common/src/weights/pallet_certification_smith_cert.rs b/runtime/common/src/weights/pallet_certification_smith_cert.rs
index 024b4b8a5a072227baf782dea642320a11b60226..6f735ab2bc1e8746e9869b468028be48cde89864 100644
--- a/runtime/common/src/weights/pallet_certification_smith_cert.rs
+++ b/runtime/common/src/weights/pallet_certification_smith_cert.rs
@@ -14,21 +14,21 @@
 // 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 `common_runtime::certification`
+//! Autogenerated weights for `pallet_certification`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-04-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! HOSTNAME: `benjamin-xps139380`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
+//! DATE: 2023-05-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `Hugo`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("gdev-benchmark"), DB CACHE: 1024
 
 // Executed Command:
 // ./target/release/duniter
 // benchmark
 // pallet
-// --chain=dev
+// --chain=gdev-benchmark
 // --steps=50
 // --repeat=20
-// --pallet=common_runtime::certification
+// --pallet=pallet-certification
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
@@ -43,16 +43,16 @@
 use frame_support::{traits::Get, weights::Weight};
 use sp_std::marker::PhantomData;
 
-/// Weight functions for `common_runtime::certification`.
+/// Weight functions for `pallet_certification`.
 pub struct WeightInfo<T>(PhantomData<T>);
 impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T> {
 	// Storage: SmithCert StorageIdtyCertMeta (r:2 w:2)
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: SmithCert StorageCertsRemovableOn (r:1 w:1)
 	// Storage: SmithCert CertsByReceiver (r:1 w:1)
-	fn force_add_cert() -> Weight {
-		// Minimum execution time: 125_287 nanoseconds.
-		Weight::from_ref_time(128_059_000 as u64)
+	fn do_add_cert_checked() -> Weight {
+		// Minimum execution time: 57_241 nanoseconds.
+		Weight::from_ref_time(69_631_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(4 as u64))
 	}
@@ -62,8 +62,8 @@ impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T>
 	// Storage: SmithCert StorageCertsRemovableOn (r:1 w:1)
 	// Storage: SmithCert CertsByReceiver (r:1 w:1)
 	fn add_cert() -> Weight {
-		// Minimum execution time: 147_626 nanoseconds.
-		Weight::from_ref_time(152_571_000 as u64)
+		// Minimum execution time: 65_925 nanoseconds.
+		Weight::from_ref_time(79_971_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(7 as u64))
 			.saturating_add(T::DbWeight::get().writes(4 as u64))
 	}
@@ -72,8 +72,8 @@ impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T>
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: SmithMembership Membership (r:1 w:0)
 	fn del_cert() -> Weight {
-		// Minimum execution time: 126_824 nanoseconds.
-		Weight::from_ref_time(130_111_000 as u64)
+		// Minimum execution time: 50_260 nanoseconds.
+		Weight::from_ref_time(62_319_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
@@ -84,10 +84,10 @@ impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T>
 	/// 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 {
-		// Minimum execution time: 130_926 nanoseconds.
-		Weight::from_ref_time(133_225_000 as u64)
-			// Standard Error: 66_989
-			.saturating_add(Weight::from_ref_time(37_841_523 as u64).saturating_mul(i as u64))
+		// Minimum execution time: 50_222 nanoseconds.
+		Weight::from_ref_time(50_794_000 as u64)
+			// Standard Error: 48_765
+			.saturating_add(Weight::from_ref_time(15_587_131 as u64).saturating_mul(i as u64))
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64)))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
diff --git a/runtime/common/src/weights/pallet_identity.rs b/runtime/common/src/weights/pallet_identity.rs
index 8d398bb67fecee565114b62076e49ee60dc0f9a3..f438c79f70232d494bf5c9e8239ee27be2136293 100644
--- a/runtime/common/src/weights/pallet_identity.rs
+++ b/runtime/common/src/weights/pallet_identity.rs
@@ -1,4 +1,4 @@
-// Copyright 2021-2023 Axiom-Team
+// Copyright 2021-2022 Axiom-Team
 //
 // This file is part of Duniter-v2S.
 //
@@ -14,11 +14,11 @@
 // 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 `common_runtime::identity`
+//! Autogenerated weights for `pallet_identity`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-04-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! HOSTNAME: `benjamin-xps139380`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
+//! DATE: 2023-05-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `Hugo`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("gdev-benchmark"), DB CACHE: 1024
 
 // Executed Command:
@@ -28,13 +28,13 @@
 // --chain=gdev-benchmark
 // --steps=50
 // --repeat=20
-// --pallet=common_runtime::identity
+// --pallet=pallet-identity
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
 // --heap-pages=4096
 // --header=./file_header.txt
-// --output=./runtime/common/src/weights/pallet_identity.rs
+// --output=./runtime/common/src/weights/
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
@@ -43,7 +43,7 @@
 use frame_support::{traits::Get, weights::Weight};
 use sp_std::marker::PhantomData;
 
-/// Weight functions for `common_runtime::identity`.
+/// Weight functions for `pallet_identity`.
 pub struct WeightInfo<T>(PhantomData<T>);
 impl<T: frame_system::Config> pallet_identity::WeightInfo for WeightInfo<T> {
 	// Storage: Identity IdentityIndexOf (r:2 w:1)
@@ -57,8 +57,8 @@ impl<T: frame_system::Config> pallet_identity::WeightInfo for WeightInfo<T> {
 	// Storage: Cert StorageCertsRemovableOn (r:1 w:1)
 	// Storage: Cert CertsByReceiver (r:1 w:1)
 	fn create_identity() -> Weight {
-		// Minimum execution time: 440_987 nanoseconds.
-		Weight::from_ref_time(462_747_000 as u64)
+		// Minimum execution time: 121_934 nanoseconds.
+		Weight::from_ref_time(138_522_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(13 as u64))
 			.saturating_add(T::DbWeight::get().writes(11 as u64))
 	}
@@ -70,8 +70,8 @@ impl<T: frame_system::Config> pallet_identity::WeightInfo for WeightInfo<T> {
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: Membership PendingMembershipsExpireOn (r:1 w:1)
 	fn confirm_identity() -> Weight {
-		// Minimum execution time: 186_617 nanoseconds.
-		Weight::from_ref_time(309_527_000 as u64)
+		// Minimum execution time: 86_584 nanoseconds.
+		Weight::from_ref_time(98_246_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(7 as u64))
 			.saturating_add(T::DbWeight::get().writes(4 as u64))
 	}
@@ -84,8 +84,8 @@ impl<T: frame_system::Config> pallet_identity::WeightInfo for WeightInfo<T> {
 	// Storage: Membership MembershipsExpireOn (r:1 w:1)
 	// Storage: UniversalDividend CurrentUdIndex (r:1 w:0)
 	fn validate_identity() -> Weight {
-		// Minimum execution time: 299_920 nanoseconds.
-		Weight::from_ref_time(320_025_000 as u64)
+		// Minimum execution time: 91_201 nanoseconds.
+		Weight::from_ref_time(94_836_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(8 as u64))
 			.saturating_add(T::DbWeight::get().writes(5 as u64))
 	}
@@ -93,29 +93,29 @@ impl<T: frame_system::Config> pallet_identity::WeightInfo for WeightInfo<T> {
 	// Storage: Identity Identities (r:1 w:1)
 	// Storage: SmithMembership Membership (r:1 w:0)
 	// Storage: System BlockHash (r:1 w:0)
-	// Storage: System Account (r:1 w:1)
+	// Storage: System Account (r:2 w:2)
 	// Storage: AuthorityMembers Members (r:1 w:0)
 	fn change_owner_key() -> Weight {
-		// Minimum execution time: 442_260 nanoseconds.
-		Weight::from_ref_time(728_714_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(7 as u64))
-			.saturating_add(T::DbWeight::get().writes(4 as u64))
+		// Minimum execution time: 213_666 nanoseconds.
+		Weight::from_ref_time(247_995_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(8 as u64))
+			.saturating_add(T::DbWeight::get().writes(5 as u64))
 	}
 	// Storage: Identity Identities (r:1 w:1)
 	// Storage: SmithMembership Membership (r:1 w:0)
 	// Storage: System BlockHash (r:1 w:0)
 	// Storage: Membership Membership (r:1 w:1)
 	// Storage: Identity CounterForIdentities (r:1 w:1)
-	// Storage: System Account (r:1 w:1)
+	// Storage: System Account (r:2 w:2)
 	// Storage: Cert CertsByReceiver (r:1 w:1)
 	// Storage: Cert StorageIdtyCertMeta (r:2 w:2)
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: Identity IdentityIndexOf (r:0 w:1)
 	fn revoke_identity() -> Weight {
-		// Minimum execution time: 494_407 nanoseconds.
-		Weight::from_ref_time(800_824_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(10 as u64))
-			.saturating_add(T::DbWeight::get().writes(8 as u64))
+		// Minimum execution time: 227_151 nanoseconds.
+		Weight::from_ref_time(284_771_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(11 as u64))
+			.saturating_add(T::DbWeight::get().writes(9 as u64))
 	}
 	// Storage: Identity Identities (r:1 w:1)
 	// Storage: SmithMembership Membership (r:1 w:0)
@@ -128,24 +128,24 @@ impl<T: frame_system::Config> pallet_identity::WeightInfo for WeightInfo<T> {
 	// Storage: Identity IdentityIndexOf (r:0 w:1)
 	// Storage: Identity IdentitiesNames (r:0 w:1)
 	fn remove_identity() -> Weight {
-		// Minimum execution time: 302_574 nanoseconds.
-		Weight::from_ref_time(504_132_000 as u64)
+		// Minimum execution time: 110_561 nanoseconds.
+		Weight::from_ref_time(119_198_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(9 as u64))
 			.saturating_add(T::DbWeight::get().writes(9 as u64))
 	}
 	// Storage: Identity IdentitiesNames (r:0 w:20)
 	/// The range of component `i` is `[1, 1000]`.
 	fn prune_item_identities_names(i: u32, ) -> Weight {
-		// Minimum execution time: 22_533 nanoseconds.
-		Weight::from_ref_time(282_674_421 as u64)
-			// Standard Error: 170_391
-			.saturating_add(Weight::from_ref_time(5_660_460 as u64).saturating_mul(i as u64))
+		// Minimum execution time: 10_675 nanoseconds.
+		Weight::from_ref_time(10_809_000 as u64)
+			// Standard Error: 3_281
+			.saturating_add(Weight::from_ref_time(1_492_089 as u64).saturating_mul(i as u64))
 			.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64)))
 	}
 	// Storage: System Account (r:1 w:1)
 	fn fix_sufficients() -> Weight {
-		// Minimum execution time: 112_793 nanoseconds.
-		Weight::from_ref_time(122_192_000 as u64)
+		// Minimum execution time: 23_639 nanoseconds.
+		Weight::from_ref_time(29_075_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
diff --git a/runtime/common/src/weights/pallet_membership_membership.rs b/runtime/common/src/weights/pallet_membership_membership.rs
index 799f51a0c1560633e85124c3673957343a829d07..ddbc76f57a19b1cc2edc4948e39522101838c418 100644
--- a/runtime/common/src/weights/pallet_membership_membership.rs
+++ b/runtime/common/src/weights/pallet_membership_membership.rs
@@ -17,18 +17,18 @@
 //! Autogenerated weights for `pallet_membership`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-04-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! HOSTNAME: `benjamin-xps139380`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
+//! DATE: 2023-05-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `Hugo`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("gdev-benchmark"), DB CACHE: 1024
 
 // Executed Command:
-// target/release/duniter
+// ./target/release/duniter
 // benchmark
 // pallet
-// --chain=dev
+// --chain=gdev-benchmark
 // --steps=50
 // --repeat=20
-// --pallet=pallet_membership
+// --pallet=pallet-membership
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
@@ -51,16 +51,16 @@ impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: Membership PendingMembershipsExpireOn (r:1 w:1)
 	fn force_request_membership() -> Weight {
-		// Minimum execution time: 89_725 nanoseconds.
-		Weight::from_ref_time(98_333_000 as u64)
+		// Minimum execution time: 42_024 nanoseconds.
+		Weight::from_ref_time(55_713_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Identity IdentityIndexOf (r:1 w:0)
 	// Storage: Identity Identities (r:1 w:0)
 	fn request_membership() -> Weight {
-		// Minimum execution time: 48_477 nanoseconds.
-		Weight::from_ref_time(50_689_000 as u64)
+		// Minimum execution time: 19_511 nanoseconds.
+		Weight::from_ref_time(37_123_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 	}
 	// Storage: Identity IdentityIndexOf (r:1 w:0)
@@ -71,8 +71,8 @@ impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
 	// Storage: Membership CounterForMembership (r:1 w:1)
 	// Storage: Membership MembershipsExpireOn (r:1 w:1)
 	fn claim_membership() -> Weight {
-		// Minimum execution time: 144_079 nanoseconds.
-		Weight::from_ref_time(146_565_000 as u64)
+		// Minimum execution time: 80_875 nanoseconds.
+		Weight::from_ref_time(117_287_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(7 as u64))
 			.saturating_add(T::DbWeight::get().writes(4 as u64))
 	}
@@ -82,8 +82,8 @@ impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: Membership MembershipsExpireOn (r:1 w:1)
 	fn renew_membership() -> Weight {
-		// Minimum execution time: 120_859 nanoseconds.
-		Weight::from_ref_time(124_222_000 as u64)
+		// Minimum execution time: 69_195 nanoseconds.
+		Weight::from_ref_time(91_620_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
@@ -93,8 +93,8 @@ impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
 	// Storage: Identity Identities (r:1 w:0)
 	// Storage: UniversalDividend CurrentUdIndex (r:1 w:0)
 	fn revoke_membership() -> Weight {
-		// Minimum execution time: 109_486 nanoseconds.
-		Weight::from_ref_time(113_303_000 as u64)
+		// Minimum execution time: 64_419 nanoseconds.
+		Weight::from_ref_time(103_812_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
diff --git a/runtime/common/src/weights/pallet_membership_smith_membership.rs b/runtime/common/src/weights/pallet_membership_smith_membership.rs
index 2ecd9b61ebea89cfb5c195359a9958e9cc22c914..cdc459c197885d84fe14505ef96a0c13d25f72c8 100644
--- a/runtime/common/src/weights/pallet_membership_smith_membership.rs
+++ b/runtime/common/src/weights/pallet_membership_smith_membership.rs
@@ -17,18 +17,18 @@
 //! Autogenerated weights for `pallet_membership`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-04-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! HOSTNAME: `benjamin-xps139380`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
+//! DATE: 2023-05-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `Hugo`, CPU: `Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("gdev-benchmark"), DB CACHE: 1024
 
 // Executed Command:
-// target/release/duniter
+// ./target/release/duniter
 // benchmark
 // pallet
-// --chain=dev
+// --chain=gdev-benchmark
 // --steps=50
 // --repeat=20
-// --pallet=pallet_membership
+// --pallet=pallet-membership
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
@@ -51,22 +51,17 @@ impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: SmithMembership PendingMembershipsExpireOn (r:1 w:1)
 	fn force_request_membership() -> Weight {
-		// Minimum execution time: 96_077 nanoseconds.
-		Weight::from_ref_time(98_570_000 as u64)
+		// Minimum execution time: 42_163 nanoseconds.
+		Weight::from_ref_time(49_619_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Identity IdentityIndexOf (r:1 w:0)
 	// Storage: Identity Identities (r:1 w:0)
-	// Storage: SmithMembership PendingMembership (r:1 w:1)
-	// Storage: SmithMembership Membership (r:1 w:0)
-	// Storage: Parameters ParametersStorage (r:1 w:0)
-	// Storage: SmithMembership PendingMembershipsExpireOn (r:1 w:1)
 	fn request_membership() -> Weight {
-		// Minimum execution time: 122_839 nanoseconds.
-		Weight::from_ref_time(125_861_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(6 as u64))
-			.saturating_add(T::DbWeight::get().writes(2 as u64))
+		// Minimum execution time: 20_399 nanoseconds.
+		Weight::from_ref_time(24_906_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(2 as u64))
 	}
 	// Storage: Identity IdentityIndexOf (r:2 w:0)
 	// Storage: SmithMembership Membership (r:2 w:1)
@@ -76,8 +71,8 @@ impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
 	// Storage: SmithMembership CounterForMembership (r:1 w:1)
 	// Storage: SmithMembership MembershipsExpireOn (r:1 w:1)
 	fn claim_membership() -> Weight {
-		// Minimum execution time: 165_369 nanoseconds.
-		Weight::from_ref_time(167_607_000 as u64)
+		// Minimum execution time: 95_541 nanoseconds.
+		Weight::from_ref_time(157_882_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(9 as u64))
 			.saturating_add(T::DbWeight::get().writes(4 as u64))
 	}
@@ -87,8 +82,8 @@ impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
 	// Storage: Parameters ParametersStorage (r:1 w:0)
 	// Storage: SmithMembership MembershipsExpireOn (r:1 w:1)
 	fn renew_membership() -> Weight {
-		// Minimum execution time: 121_761 nanoseconds.
-		Weight::from_ref_time(125_210_000 as u64)
+		// Minimum execution time: 70_298 nanoseconds.
+		Weight::from_ref_time(109_069_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
@@ -103,8 +98,8 @@ impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> {
 	// Storage: System Account (r:1 w:1)
 	// Storage: Session KeyOwner (r:0 w:4)
 	fn revoke_membership() -> Weight {
-		// Minimum execution time: 234_173 nanoseconds.
-		Weight::from_ref_time(239_334_000 as u64)
+		// Minimum execution time: 138_537 nanoseconds.
+		Weight::from_ref_time(179_540_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(9 as u64))
 			.saturating_add(T::DbWeight::get().writes(12 as u64))
 	}
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index f7cf7b58c7208de5221946b71ea1c1d6937a9e66..90350ab3d19a960342d232d1d1c6e6a366392651 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -168,30 +168,16 @@ mod benches {
 }
 
 pub struct BaseCallFilter;
-#[cfg(not(feature = "runtime-benchmarks"))]
-impl Contains<RuntimeCall> for BaseCallFilter {
-    fn contains(call: &RuntimeCall) -> bool {
-        !matches!(
-            call,
-            /*RuntimeCall::System(
-                frame_system::Call::remark { .. } | frame_system::Call::remark_with_event { .. }
-            ) | */
-            RuntimeCall::Membership(
-                pallet_membership::Call::request_membership { .. }
-                    | pallet_membership::Call::claim_membership { .. }
-                    | pallet_membership::Call::revoke_membership { .. }
-            ) | RuntimeCall::Session(_)
-        )
-    }
-}
-#[cfg(feature = "runtime-benchmarks")]
+
+// implement filter
 impl Contains<RuntimeCall> for BaseCallFilter {
     fn contains(call: &RuntimeCall) -> bool {
         !matches!(
             call,
+            // in main web of trust, membership request and revoke are handeled through identity pallet
+            // the user can not call them directly
             RuntimeCall::Membership(
                 pallet_membership::Call::request_membership { .. }
-                    | pallet_membership::Call::claim_membership { .. }
                     | pallet_membership::Call::revoke_membership { .. }
             ) | RuntimeCall::Session(_)
         )
diff --git a/runtime/gdev/tests/common/mod.rs b/runtime/gdev/tests/common/mod.rs
index 60d0bd62d7fc306cbb76ed08697ad25b8c6a9855..438ffa81fad84b4e9ced32960beeef81171b283b 100644
--- a/runtime/gdev/tests/common/mod.rs
+++ b/runtime/gdev/tests/common/mod.rs
@@ -102,7 +102,7 @@ impl ExtBuilder {
                 cert_validity_period: 10_000,
                 idty_confirm_period: 40,
                 idty_creation_period: 50,
-                membership_period: 1_000,
+                membership_period: 100,
                 pending_membership_period: 500,
                 ud_creation_period: 10,
                 ud_reeval_period: 10 * 20,
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
index 0588a74aabc46df705eca45fcea44c9ab94be44c..22d1fb05626ce146ea8fde5e57fe23c0b0d0af4f 100644
--- a/runtime/gdev/tests/integration_tests.rs
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -26,7 +26,7 @@ use sp_runtime::MultiAddress;
 
 #[test]
 fn verify_treasury_account() {
-    println!("{}", Treasury::account_id());
+    // println!("{}", Treasury::account_id());
 }
 
 #[test]
@@ -81,6 +81,7 @@ fn test_genesis_build() {
     });
 }
 
+/// test calling remove_identity
 #[test]
 fn test_remove_identity() {
     ExtBuilder::new(1, 3, 4).build().execute_with(|| {
@@ -103,6 +104,104 @@ fn test_remove_identity() {
         ));
     });
 }
+
+/// test identity is validated when membership is claimed
+#[test]
+fn test_validate_identity_when_claim() {
+    ExtBuilder::new(1, 3, 4)
+        .with_initial_balances(vec![(AccountKeyring::Ferdie.to_account_id(), 1000)])
+        .build()
+        .execute_with(|| {
+            run_to_block(1);
+            // alice create identity for Eve
+            assert_ok!(Identity::create_identity(
+                frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+                AccountKeyring::Eve.to_account_id(),
+            ));
+            run_to_block(2);
+            // eve confirms her identity
+            assert_ok!(Identity::confirm_identity(
+                frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
+                "Eeeeeveeeee".into(),
+            ));
+            run_to_block(3);
+            // eve gets certified by bob and charlie
+            assert_ok!(Cert::add_cert(
+                frame_system::RawOrigin::Signed(AccountKeyring::Bob.to_account_id()).into(),
+                2,
+                5
+            ));
+            assert_ok!(Cert::add_cert(
+                frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into(),
+                3,
+                5
+            ));
+
+            // eve can claim her membership
+            assert_ok!(Membership::claim_membership(
+                frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
+            ));
+
+            System::assert_has_event(RuntimeEvent::Membership(
+                pallet_membership::Event::MembershipAcquired(5),
+            ));
+
+            // ferdie can not validate eve identity because already validated
+            assert_noop!(
+                Identity::validate_identity(
+                    frame_system::RawOrigin::Signed(AccountKeyring::Ferdie.to_account_id()).into(),
+                    5,
+                ),
+                pallet_identity::Error::<Runtime>::IdtyAlreadyValidated
+            );
+        });
+}
+
+/// test membership expiry
+#[test]
+fn test_membership_expiry() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        run_to_block(100);
+        System::assert_has_event(RuntimeEvent::Membership(
+            pallet_membership::Event::MembershipExpired(1),
+        ));
+        // membership expiry should not trigger identity removal
+        assert!(!System::events().iter().any(|record| record.event
+            == RuntimeEvent::Identity(pallet_identity::Event::IdtyRemoved { idty_index: 1 })));
+    });
+}
+
+/// test membership renewal
+#[test]
+fn test_membership_renewal() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        // renew at block 2
+        run_to_block(2);
+        assert_ok!(Membership::renew_membership(
+            frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+        ));
+        System::assert_has_event(RuntimeEvent::Membership(
+            pallet_membership::Event::MembershipRenewed(1),
+        ));
+
+        // renew at block 3
+        run_to_block(3);
+        assert_ok!(Membership::renew_membership(
+            frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+        ));
+        System::assert_has_event(RuntimeEvent::Membership(
+            pallet_membership::Event::MembershipRenewed(1),
+        ));
+
+        // should expire at block 103 = 3+100
+        run_to_block(103);
+        System::assert_has_event(RuntimeEvent::Membership(
+            pallet_membership::Event::MembershipExpired(1),
+        ));
+    });
+}
+
+// test that UD are auto claimed when identity is removed
 #[test]
 fn test_remove_identity_after_one_ud() {
     ExtBuilder::new(1, 3, 4).build().execute_with(|| {
@@ -147,6 +246,95 @@ fn test_remove_identity_after_one_ud() {
     });
 }
 
+/// test that UD are auto claimed when membership expires
+/// and that claimed UD matches expectations
+#[test]
+fn test_ud_claimed_membership_on_and_off() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        // UD are created every 10 blocks from block 0
+        run_to_block(10);
+        System::assert_has_event(RuntimeEvent::UniversalDividend(
+            pallet_universal_dividend::Event::NewUdCreated {
+                amount: 1000,
+                index: 1,
+                monetary_mass: 4000,
+                members_count: 4,
+            },
+        ));
+        // UD not claimed, still initial balance to 0
+        assert_eq!(
+            Balances::free_balance(AccountKeyring::Alice.to_account_id()),
+            0
+        );
+
+        run_to_block(11);
+        // alice identity expires
+        assert_ok!(Membership::force_expire_membership(1));
+        System::assert_has_event(RuntimeEvent::UniversalDividend(
+            pallet_universal_dividend::Event::UdsAutoPaidAtRemoval {
+                count: 1,
+                total: 1_000,
+                who: AccountKeyring::Alice.to_account_id(),
+            },
+        ));
+        // alice balances should be increased by 1 UD
+        assert_eq!(
+            Balances::free_balance(AccountKeyring::Alice.to_account_id()),
+            1000
+        );
+
+        // UD number 2
+        run_to_block(20);
+        System::assert_has_event(RuntimeEvent::UniversalDividend(
+            pallet_universal_dividend::Event::NewUdCreated {
+                amount: 1000,
+                index: 2,
+                monetary_mass: 7000, // 4000 + 3 × 1000
+                members_count: 3,    // alice is not member at this UD
+            },
+        ));
+
+        // alice claims back her membership
+        assert_ok!(Membership::claim_membership(
+            frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into()
+        ));
+        System::assert_has_event(RuntimeEvent::Membership(
+            pallet_membership::Event::MembershipAcquired(1),
+        ));
+
+        // UD number 3
+        run_to_block(30);
+        System::assert_has_event(RuntimeEvent::UniversalDividend(
+            pallet_universal_dividend::Event::NewUdCreated {
+                amount: 1000,
+                index: 3,
+                monetary_mass: 11000, // 7000 + 4 × 1000
+                members_count: 4,     // alice is member again at this UD
+            },
+        ));
+
+        // one block later, alice claims her new UD
+        run_to_block(31);
+        assert_ok!(UniversalDividend::claim_uds(
+            frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into()
+        ));
+        System::assert_has_event(RuntimeEvent::UniversalDividend(
+            pallet_universal_dividend::Event::UdsClaimed {
+                count: 1,
+                total: 1_000,
+                who: AccountKeyring::Alice.to_account_id(),
+            },
+        ));
+        assert_eq!(
+            Balances::free_balance(AccountKeyring::Alice.to_account_id()),
+            2000 // one more UD
+        );
+
+        // println!("{:?}", System::events());
+    });
+}
+
+/// test when root removes and identity, all consumers should be deleted
 #[test]
 fn test_remove_smith_identity() {
     ExtBuilder::new(1, 3, 4).build().execute_with(|| {
@@ -382,6 +570,7 @@ fn test_create_new_idty_without_founds() {
         });
 }
 
+/// test that newly validated identity gets initialized with the next UD
 #[test]
 fn test_validate_new_idty_after_few_uds() {
     ExtBuilder::new(1, 3, 4)
@@ -425,17 +614,72 @@ fn test_validate_new_idty_after_few_uds() {
                 5,
             ));
 
-            // The new member should have first_eligible_ud equal to one
+            // The new member should have first_eligible_ud equal to three
+            assert!(Identity::identity(5).is_some());
+            assert_eq!(
+                Identity::identity(5).unwrap().data,
+                IdtyData {
+                    // first eligible UD will be at block 30
+                    first_eligible_ud: pallet_universal_dividend::FirstEligibleUd::from(3),
+                }
+            );
+        });
+}
+
+/// test that newly validated identity gets initialized with the next UD
+// even when the method used is membership claim
+#[test]
+fn test_claim_memberhsip_after_few_uds() {
+    ExtBuilder::new(1, 3, 4)
+        .with_initial_balances(vec![
+            (AccountKeyring::Alice.to_account_id(), 1_000),
+            (AccountKeyring::Bob.to_account_id(), 1_000),
+            (AccountKeyring::Charlie.to_account_id(), 1_000),
+            (AccountKeyring::Eve.to_account_id(), 1_000),
+        ])
+        .build()
+        .execute_with(|| {
+            run_to_block(21);
+
+            // Should be able to create an identity
+            assert_ok!(Identity::create_identity(
+                frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+                AccountKeyring::Eve.to_account_id(),
+            ));
+
+            // At next block, the created identity should be confirmed by its owner
+            run_to_block(22);
+            assert_ok!(Identity::confirm_identity(
+                frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
+                pallet_identity::IdtyName::from("Eve"),
+            ));
+
+            // At next block, Bob should be able to certify the new identity
+            run_to_block(23);
+            assert_ok!(Cert::add_cert(
+                frame_system::RawOrigin::Signed(AccountKeyring::Bob.to_account_id()).into(),
+                2,
+                5,
+            ));
+
+            // eve should be able to claim her membership
+            assert_ok!(Membership::claim_membership(
+                frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
+            ));
+
+            // The new member should have first_eligible_ud equal to three
             assert!(Identity::identity(5).is_some());
             assert_eq!(
                 Identity::identity(5).unwrap().data,
                 IdtyData {
+                    // first eligible UD will be at block 30
                     first_eligible_ud: pallet_universal_dividend::FirstEligibleUd::from(3),
                 }
             );
         });
 }
 
+/// test oneshot accounts
 #[test]
 fn test_oneshot_accounts() {
     ExtBuilder::new(1, 3, 4)
diff --git a/xtask/src/gen_calls_doc.rs b/xtask/src/gen_calls_doc.rs
index 775619e038091cdcb9f1692f68f65ec8958acfab..543c880f6ee1f13626bd8119246b9c895053dd21 100644
--- a/xtask/src/gen_calls_doc.rs
+++ b/xtask/src/gen_calls_doc.rs
@@ -128,15 +128,9 @@ impl CallCategory {
                 "Identity",
                 "remove_identity" | "prune_item_identities_names" | "prune_item_identity_index_of",
             ) => Self::Root,
-            ("Membership", "force_request_membership") => Self::Root,
-            ("Membership", "request_membership" | "claim_membership" | "revoke_membership") => {
-                Self::Disabled
-            }
-            ("Cert", "force_add_cert" | "del_cert" | "remove_all_certs_received_by") => Self::Root,
-            ("SmithMembership", "force_request_membership") => Self::Root,
-            ("SmithCert", "force_add_cert" | "del_cert" | "remove_all_certs_received_by") => {
-                Self::Root
-            }
+            ("Membership", "request_membership" | "revoke_membership") => Self::Disabled,
+            ("Cert", "del_cert" | "remove_all_certs_received_by") => Self::Root,
+            ("SmithCert", "del_cert" | "remove_all_certs_received_by") => Self::Root,
             ("TechnicalCommittee", "set_members" | "disapprove_proposal") => Self::Root,
             ("Utility", "dispatch_as") => Self::Root,
             ("Treasury", "approve_proposal" | "reject_proposal") => Self::OtherOrigin,