diff --git a/Cargo.lock b/Cargo.lock
index 1f8f7eb35d0438766c0389b24bffc3df7cfabb8f..7229b35a574771cc7e1debb36081495888a8f63a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -836,6 +836,7 @@ dependencies = [
  "frame-support",
  "frame-system",
  "pallet-certification",
+ "pallet-duniter-wot",
  "pallet-identity",
  "pallet-membership",
  "pallet-session",
@@ -1894,6 +1895,7 @@ dependencies = [
  "pallet-babe",
  "pallet-balances",
  "pallet-certification",
+ "pallet-duniter-wot",
  "pallet-grandpa",
  "pallet-identity",
  "pallet-im-online",
@@ -1920,6 +1922,7 @@ dependencies = [
  "sp-consensus-babe",
  "sp-core",
  "sp-inherents",
+ "sp-membership",
  "sp-offchain",
  "sp-runtime",
  "sp-session",
@@ -1944,6 +1947,7 @@ dependencies = [
  "pallet-babe",
  "pallet-balances",
  "pallet-certification",
+ "pallet-duniter-wot",
  "pallet-grandpa",
  "pallet-identity",
  "pallet-membership",
@@ -1965,6 +1969,7 @@ dependencies = [
  "sp-consensus-babe",
  "sp-core",
  "sp-inherents",
+ "sp-membership",
  "sp-offchain",
  "sp-runtime",
  "sp-session",
@@ -2122,6 +2127,7 @@ dependencies = [
  "pallet-babe",
  "pallet-balances",
  "pallet-certification",
+ "pallet-duniter-wot",
  "pallet-grandpa",
  "pallet-identity",
  "pallet-im-online",
@@ -2148,6 +2154,7 @@ dependencies = [
  "sp-consensus-babe",
  "sp-core",
  "sp-inherents",
+ "sp-membership",
  "sp-offchain",
  "sp-runtime",
  "sp-session",
@@ -4225,6 +4232,26 @@ dependencies = [
  "sp-std",
 ]
 
+[[package]]
+name = "pallet-duniter-wot"
+version = "3.0.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-certification",
+ "pallet-identity",
+ "pallet-membership",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-membership",
+ "sp-runtime",
+ "sp-std",
+]
+
 [[package]]
 name = "pallet-grandpa"
 version = "4.0.0-dev"
@@ -4260,7 +4287,6 @@ dependencies = [
  "serde",
  "sp-core",
  "sp-io",
- "sp-membership",
  "sp-runtime",
  "sp-std",
 ]
@@ -7020,6 +7046,7 @@ dependencies = [
  "parity-scale-codec",
  "scale-info",
  "serde",
+ "sp-runtime",
  "sp-std",
 ]
 
diff --git a/Cargo.toml b/Cargo.toml
index cb8a484d49a4fe25265471c5830371b10327e35b..225f5d1f53d5b95fe4a3da7bfcab380515a49500 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -98,6 +98,7 @@ resolver = "2"
 members = [
 	'integration-tests',
     'pallets/certification',
+    'pallets/duniter-wot',
     'pallets/identity',
 	'pallets/membership',
     'pallets/ud-accounts-storage',
diff --git a/pallets/certification/src/lib.rs b/pallets/certification/src/lib.rs
index a129d24e9edfe843a9f95eccac338d9a65abc681..3462440a0f4d55f6ba3641a9d9f866d920608548 100644
--- a/pallets/certification/src/lib.rs
+++ b/pallets/certification/src/lib.rs
@@ -482,18 +482,6 @@ pub mod pallet {
     }
 }
 
-impl<T: Config<I>, I: 'static> IsIdtyAllowedToCreateCert<T::IdtyIndex> for Pallet<T, I> {
-    fn is_idty_allowed_to_create_cert(idty_index: T::IdtyIndex) -> bool {
-        if let Ok(cert_meta) = <StorageIdtyCertMeta<T, I>>::try_get(idty_index) {
-            use frame_support::traits::Get as _;
-            cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number()
-                && cert_meta.issued_count < T::MaxByIssuer::get()
-        } else {
-            true
-        }
-    }
-}
-
 impl<T: Config<I>, I: 'static> SetNextIssuableOn<T::BlockNumber, T::IdtyIndex> for Pallet<T, I> {
     fn set_next_issuable_on(
         idty_index: T::IdtyIndex,
diff --git a/pallets/certification/src/traits.rs b/pallets/certification/src/traits.rs
index e4ac1e7e0b2a2de65f90af78358f3bb0206e06e3..aea859b01c343aee66dffac5b8f64abc277789ff 100644
--- a/pallets/certification/src/traits.rs
+++ b/pallets/certification/src/traits.rs
@@ -14,10 +14,6 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
-pub trait IsIdtyAllowedToCreateCert<IdtyIndex> {
-    fn is_idty_allowed_to_create_cert(idty_index: IdtyIndex) -> bool;
-}
-
 pub trait OnNewcert<IdtyIndex> {
     fn on_new_cert(
         issuer: IdtyIndex,
diff --git a/pallets/duniter-wot/Cargo.toml b/pallets/duniter-wot/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..e23031d7e3d9224681b513320308250685db5a4c
--- /dev/null
+++ b/pallets/duniter-wot/Cargo.toml
@@ -0,0 +1,93 @@
+[package]
+authors = ['librelois <c@elo.tf>']
+description = 'FRAME pallet duniter wot.'
+edition = '2018'
+homepage = 'https://substrate.dev'
+license = 'AGPL-3.0'
+name = 'pallet-duniter-wot'
+readme = 'README.md'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '3.0.0'
+
+[features]
+default = ['std']
+runtime-benchmarks = ['frame-benchmarking']
+std = [
+    'codec/std',
+    'frame-support/std',
+    'frame-system/std',
+    'frame-benchmarking/std',
+    'pallet-certification/std',
+    'pallet-identity/std',
+    'pallet-membership/std',
+    'serde',
+    'sp-core/std',
+    'sp-membership/std',
+    'sp-runtime/std',
+	'sp-std/std',
+]
+try-runtime = ['frame-support/try-runtime']
+
+[dependencies]
+pallet-certification = { path = "../certification", default-features = false }
+pallet-identity = { path = "../identity", default-features = false }
+pallet-membership = { path = "../membership", default-features = false }
+sp-membership = { path = "../../primitives/membership", default-features = false }
+
+# substrate
+scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+
+[dependencies.codec]
+default-features = false
+features = ['derive']
+package = 'parity-scale-codec'
+version = '2.3.1'
+
+[dependencies.frame-benchmarking]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+optional = true
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.frame-support]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.frame-system]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.serde]
+version = "1.0.101"
+optional = true
+features = ["derive"]
+
+[dependencies.sp-core]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
+[dev-dependencies.serde]
+version = '1.0.119'
+
+### DEV ###
+
+[dev-dependencies.sp-io]
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1f77b043d9716fe54bbd6c0e9f8e75c1b7fb3b39
--- /dev/null
+++ b/pallets/duniter-wot/src/lib.rs
@@ -0,0 +1,356 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+#![allow(clippy::type_complexity)]
+
+//pub mod traits;
+mod types;
+
+#[cfg(test)]
+mod mock;
+
+#[cfg(test)]
+mod tests;
+
+/*#[cfg(feature = "runtime-benchmarks")]
+mod benchmarking;*/
+
+pub use pallet::*;
+pub use types::*;
+
+use frame_support::instances::Instance1;
+use frame_support::pallet_prelude::*;
+use frame_system::RawOrigin;
+use pallet_certification::traits::SetNextIssuableOn;
+use pallet_identity::{IdtyEvent, IdtyStatus};
+use sp_runtime::traits::IsMember;
+
+type IdtyIndex = u32;
+
+#[frame_support::pallet]
+pub mod pallet {
+    use super::*;
+    use frame_support::traits::StorageVersion;
+
+    /// The current storage version.
+    const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
+    #[pallet::pallet]
+    #[pallet::generate_store(pub(super) trait Store)]
+    #[pallet::storage_version(STORAGE_VERSION)]
+    pub struct Pallet<T>(_);
+
+    // CONFIG //
+
+    #[pallet::config]
+    pub trait Config:
+        frame_system::Config
+        + pallet_certification::Config<Instance1, IdtyIndex = IdtyIndex>
+        + pallet_identity::Config<IdtyIndex = IdtyIndex, IdtyRight = IdtyRight>
+        + pallet_membership::Config<Instance1, IdtyId = IdtyIndex>
+    {
+        type MinCertForUdRight: Get<u8>;
+        type MinCertForCertRight: Get<u8>;
+        type MinCertForCreateIdtyRight: Get<u8>;
+        type FirstIssuableOn: Get<Self::BlockNumber>;
+    }
+
+    // INTERNAL FUNCTIONS //
+
+    impl<T: Config> Pallet<T> {
+        pub(super) fn do_apply_first_issuable_on(idty_index: IdtyIndex) {
+            let block_number = frame_system::pallet::Pallet::<T>::block_number();
+            pallet_certification::Pallet::<T, Instance1>::set_next_issuable_on(
+                idty_index,
+                block_number + T::FirstIssuableOn::get(),
+            );
+        }
+        pub(super) fn do_add_cert_right(idty_index: IdtyIndex) {
+            match pallet_identity::Pallet::<T>::add_right(
+                RawOrigin::Root.into(),
+                idty_index,
+                IdtyRight::StrongCert,
+            ) {
+                Ok(_) => {
+                    Self::do_apply_first_issuable_on(idty_index);
+                }
+                Err(e) => {
+                    sp_std::if_std! {
+                        println!("{:?}", e)
+                    }
+                }
+            }
+        }
+        pub(super) fn do_add_rights(idty_index: IdtyIndex, received_cert_count: u32) {
+            if received_cert_count >= T::MinCertForUdRight::get() as u32 {
+                if let Err(e) = pallet_identity::Pallet::<T>::add_right(
+                    RawOrigin::Root.into(),
+                    idty_index,
+                    IdtyRight::Ud,
+                ) {
+                    sp_std::if_std! {
+                        println!("{:?}", e)
+                    }
+                }
+            }
+            if received_cert_count >= T::MinCertForCertRight::get() as u32 {
+                Self::do_add_cert_right(idty_index);
+            }
+            if received_cert_count >= T::MinCertForCreateIdtyRight::get() as u32 {
+                if let Err(e) = pallet_identity::Pallet::<T>::add_right(
+                    RawOrigin::Root.into(),
+                    idty_index,
+                    IdtyRight::CreateIdty,
+                ) {
+                    sp_std::if_std! {
+                        println!("{:?}", e)
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl<T: Config> pallet_identity::traits::EnsureIdtyCallAllowed<T> for Pallet<T> {
+    fn can_create_identity(creator: IdtyIndex) -> bool {
+        if let Some(cert_meta) =
+            pallet_certification::Pallet::<T, Instance1>::idty_cert_meta(creator)
+        {
+            use frame_support::traits::Get as _;
+            cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number()
+                && cert_meta.issued_count < T::MaxByIssuer::get()
+        } else {
+            true
+        }
+    }
+    fn can_confirm_identity(idty_index: IdtyIndex) -> bool {
+        pallet_membership::Pallet::<T, Instance1>::request_membership(
+            RawOrigin::Root.into(),
+            idty_index,
+        )
+        .is_ok()
+    }
+    fn can_validate_identity(idty_index: IdtyIndex) -> bool {
+        pallet_membership::Pallet::<T, Instance1>::claim_membership(
+            RawOrigin::Root.into(),
+            idty_index,
+        )
+        .is_ok()
+    }
+}
+
+impl<T: Config> sp_membership::traits::IsIdtyAllowedToClaimMembership<IdtyIndex> for Pallet<T> {
+    fn is_idty_allowed_to_claim_membership(_: &IdtyIndex) -> bool {
+        false
+    }
+}
+
+impl<T: Config> sp_membership::traits::IsIdtyAllowedToRenewMembership<IdtyIndex> for Pallet<T> {
+    fn is_idty_allowed_to_renew_membership(idty_index: &IdtyIndex) -> bool {
+        if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
+            idty_value.status == IdtyStatus::Validated
+        } else {
+            false
+        }
+    }
+}
+
+impl<T: Config> sp_membership::traits::IsIdtyAllowedToRequestMembership<IdtyIndex> for Pallet<T> {
+    fn is_idty_allowed_to_request_membership(idty_index: &IdtyIndex) -> bool {
+        if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
+            idty_value.status == IdtyStatus::Validated
+        } else {
+            false
+        }
+    }
+}
+
+impl<T: Config> sp_membership::traits::IsOriginAllowedToUseIdty<T::Origin, IdtyIndex>
+    for Pallet<T>
+{
+    fn is_origin_allowed_to_use_idty(
+        origin: &T::Origin,
+        idty_index: &IdtyIndex,
+    ) -> sp_membership::OriginPermission {
+        match origin.clone().into() {
+            Ok(RawOrigin::Root) => sp_membership::OriginPermission::Root,
+            Ok(RawOrigin::Signed(account_id)) => {
+                if let Some(idty_val) = pallet_identity::Pallet::<T>::identity(idty_index) {
+                    if account_id == idty_val.owner_key {
+                        sp_membership::OriginPermission::Allowed
+                    } else {
+                        sp_membership::OriginPermission::Forbidden
+                    }
+                } else {
+                    sp_membership::OriginPermission::Forbidden
+                }
+            }
+            _ => sp_membership::OriginPermission::Forbidden,
+        }
+    }
+}
+
+impl<T: crate::pallet::Config> sp_membership::traits::OnEvent<IdtyIndex> for Pallet<T> {
+    fn on_event(membership_event: sp_membership::Event<IdtyIndex>) -> Weight {
+        match membership_event {
+            sp_membership::Event::<IdtyIndex>::MembershipAcquired(_) => {}
+            sp_membership::Event::<IdtyIndex>::MembershipExpired(idty_index) => {
+                if let Err(e) = pallet_identity::Pallet::<T>::remove_all_rights(
+                    RawOrigin::Root.into(),
+                    idty_index,
+                ) {
+                    sp_std::if_std! {
+                        println!("{:?}", e)
+                    }
+                }
+            }
+            sp_membership::Event::<IdtyIndex>::MembershipRenewed(_) => {}
+            sp_membership::Event::<IdtyIndex>::MembershipRequested(idty_index) => {
+                if let Some(idty_cert_meta) =
+                    pallet_certification::Pallet::<T, Instance1>::idty_cert_meta(idty_index)
+                {
+                    let received_count = idty_cert_meta.received_count;
+
+                    // TODO insert `receiver` in distance queue if received_count >= MinCertForUdRight
+                    Self::do_add_rights(idty_index, received_count);
+                }
+            }
+            sp_membership::Event::<IdtyIndex>::MembershipRevoked(_) => {}
+            sp_membership::Event::<IdtyIndex>::PendingMembershipExpired(idty_index) => {
+                if let Err(e) = pallet_identity::Pallet::<T>::remove_identity(
+                    RawOrigin::Root.into(),
+                    idty_index,
+                ) {
+                    sp_std::if_std! {
+                        println!("{:?}", e)
+                    }
+                }
+            }
+        }
+        0
+    }
+}
+
+impl<T: Config> pallet_identity::traits::OnIdtyChange<T> for Pallet<T> {
+    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, Instance1>>::add_cert(
+                    frame_system::Origin::<T>::Root.into(),
+                    creator,
+                    idty_index,
+                ) {
+                    sp_std::if_std! {
+                        println!("{:?}", e)
+                    }
+                }
+            }
+            IdtyEvent::Confirmed => {}
+            IdtyEvent::Validated => {}
+            IdtyEvent::Removed => {}
+        }
+        0
+    }
+}
+
+impl<T: crate::pallet::Config> pallet_certification::traits::OnNewcert<IdtyIndex> for Pallet<T> {
+    fn on_new_cert(
+        _issuer: IdtyIndex,
+        _issuer_issued_count: u8,
+        receiver: IdtyIndex,
+        receiver_received_count: u32,
+    ) -> Weight {
+        if pallet_membership::Pallet::<T, Instance1>::is_member(&receiver) {
+            Self::do_add_rights(receiver, receiver_received_count);
+        } else if pallet_membership::Pallet::<T, Instance1>::pending_membership(receiver).is_some()
+            && receiver_received_count >= T::MinCertForUdRight::get() as u32
+        {
+            // TODO insert `receiver` in distance queue
+            let mut rights = sp_std::vec![IdtyRight::Ud];
+            let mut cert_right = false;
+            if receiver_received_count >= T::MinCertForCertRight::get() as u32 {
+                rights.push(IdtyRight::StrongCert);
+                cert_right = true;
+            }
+            if receiver_received_count >= T::MinCertForCreateIdtyRight::get() as u32 {
+                rights.push(IdtyRight::CreateIdty);
+            }
+            if let Err(e) = pallet_identity::Pallet::<T>::validate_identity(
+                RawOrigin::Root.into(),
+                receiver,
+                rights,
+            ) {
+                sp_std::if_std! {
+                    println!("{:?}", e)
+                }
+                return 0;
+            }
+
+            if cert_right {
+                Self::do_apply_first_issuable_on(receiver);
+            }
+        }
+        0
+    }
+}
+
+impl<T: crate::pallet::Config> pallet_certification::traits::OnRemovedCert<IdtyIndex>
+    for Pallet<T>
+{
+    fn on_removed_cert(
+        _issuer: IdtyIndex,
+        _issuer_issued_count: u8,
+        receiver: IdtyIndex,
+        receiver_received_count: u32,
+        _expiration: bool,
+    ) -> Weight {
+        if receiver_received_count < T::MinCertForUdRight::get() as u32 {
+            if let Err(e) = pallet_identity::Pallet::<T>::del_right(
+                RawOrigin::Root.into(),
+                receiver,
+                IdtyRight::Ud,
+            ) {
+                sp_std::if_std! {
+                    println!("{:?}", e)
+                }
+            }
+        }
+        if receiver_received_count < T::MinCertForCertRight::get() as u32 {
+            if let Err(e) = pallet_identity::Pallet::<T>::del_right(
+                RawOrigin::Root.into(),
+                receiver,
+                IdtyRight::StrongCert,
+            ) {
+                sp_std::if_std! {
+                    println!("{:?}", e)
+                }
+            }
+        }
+        if receiver_received_count < T::MinCertForCreateIdtyRight::get() as u32 {
+            if let Err(e) = pallet_identity::Pallet::<T>::del_right(
+                RawOrigin::Root.into(),
+                receiver,
+                IdtyRight::CreateIdty,
+            ) {
+                sp_std::if_std! {
+                    println!("{:?}", e)
+                }
+            }
+        }
+        0
+    }
+}
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fabecf7a666b1e79195cc607fd75a45b72b15363
--- /dev/null
+++ b/pallets/duniter-wot/src/mock.rs
@@ -0,0 +1,259 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+use super::*;
+use crate::{self as pallet_duniter_wot};
+use frame_support::{parameter_types, traits::Everything};
+use frame_system as system;
+use sp_core::H256;
+use sp_runtime::{
+    testing::Header,
+    traits::{BlakeTwo256, IdentityLookup},
+    BuildStorage,
+};
+use std::collections::BTreeMap;
+
+type AccountId = u64;
+type Block = frame_system::mocking::MockBlock<Test>;
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
+
+// Configure a mock runtime to test the pallet.
+frame_support::construct_runtime!(
+    pub enum Test where
+        Block = Block,
+        NodeBlock = Block,
+        UncheckedExtrinsic = UncheckedExtrinsic,
+    {
+        System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
+        DuniterWot: pallet_duniter_wot::{Pallet},
+        Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>},
+        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>},
+        Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>},
+    }
+);
+
+// Sstem
+parameter_types! {
+    pub const BlockHashCount: u64 = 250;
+    pub const SS58Prefix: u8 = 42;
+}
+
+impl system::Config for Test {
+    type BaseCallFilter = Everything;
+    type BlockWeights = ();
+    type BlockLength = ();
+    type DbWeight = ();
+    type Origin = Origin;
+    type Call = Call;
+    type Index = u64;
+    type BlockNumber = u64;
+    type Hash = H256;
+    type Hashing = BlakeTwo256;
+    type AccountId = AccountId;
+    type Lookup = IdentityLookup<Self::AccountId>;
+    type Header = Header;
+    type Event = Event;
+    type BlockHashCount = BlockHashCount;
+    type Version = ();
+    type PalletInfo = PalletInfo;
+    type AccountData = ();
+    type OnNewAccount = ();
+    type OnKilledAccount = ();
+    type SystemWeightInfo = ();
+    type SS58Prefix = SS58Prefix;
+    type OnSetCode = ();
+    type MaxConsumers = frame_support::traits::ConstU32<16>;
+}
+
+// DuniterWot
+parameter_types! {
+    pub const MinCertForUdRight: u8 = 2;
+    pub const MinCertForCertRight: u8 = 3;
+    pub const MinCertForCreateIdtyRigh: u8 = 4;
+    pub const FirstIssuableOn: u64 = 2;
+}
+
+impl pallet_duniter_wot::Config for Test {
+    type MinCertForUdRight = MinCertForUdRight;
+    type MinCertForCertRight = MinCertForCertRight;
+    type MinCertForCreateIdtyRight = MinCertForCreateIdtyRigh;
+    type FirstIssuableOn = FirstIssuableOn;
+}
+
+// Identity
+parameter_types! {
+    pub const ConfirmPeriod: u64 = 2;
+    pub const IdtyCreationPeriod: u64 = 3;
+    pub const MaxInactivityPeriod: u64 = 5;
+    pub const MaxNoRightPeriod: u64 = 4;
+    pub const ValidationPeriod: u64 = 2;
+}
+
+pub struct IdtyNameValidatorTestImpl;
+impl pallet_identity::traits::IdtyNameValidator for IdtyNameValidatorTestImpl {
+    fn validate(idty_name: &pallet_identity::IdtyName) -> bool {
+        idty_name.0.len() < 16
+    }
+}
+
+impl pallet_identity::Config for Test {
+    type ConfirmPeriod = ConfirmPeriod;
+    type Event = Event;
+    type AddRightOrigin = system::EnsureRoot<AccountId>;
+    type DelRightOrigin = system::EnsureRoot<AccountId>;
+    type EnsureIdtyCallAllowed = DuniterWot;
+    type IdtyCreationPeriod = IdtyCreationPeriod;
+    type IdtyData = ();
+    type IdtyDataProvider = ();
+    type IdtyNameValidator = IdtyNameValidatorTestImpl;
+    type IdtyIndex = IdtyIndex;
+    type IdtyValidationOrigin = system::EnsureRoot<AccountId>;
+    type IdtyRight = IdtyRight;
+    type IsMember = Membership;
+    type OnIdtyChange = DuniterWot;
+    type OnRightKeyChange = ();
+    type MaxNoRightPeriod = MaxNoRightPeriod;
+}
+
+// Membership
+parameter_types! {
+    pub const ExternalizeMembershipStorage: bool = false;
+    pub const MembershipPeriod: u64 = 5;
+    pub const PendingMembershipPeriod: u64 = 3;
+    pub const RenewablePeriod: u64 = 2;
+    pub const RevocationPeriod: u64 = 4;
+}
+
+impl pallet_membership::Config<Instance1> for Test {
+    type IsIdtyAllowedToClaimMembership = DuniterWot;
+    type IsIdtyAllowedToRenewMembership = DuniterWot;
+    type IsIdtyAllowedToRequestMembership = DuniterWot;
+    type IsOriginAllowedToUseIdty = DuniterWot;
+    type Event = Event;
+    type ExternalizeMembershipStorage = ExternalizeMembershipStorage;
+    type IdtyId = IdtyIndex;
+    type OnEvent = DuniterWot;
+    type MembershipExternalStorage = sp_membership::traits::NoExternalStorage;
+    type MembershipPeriod = MembershipPeriod;
+    type PendingMembershipPeriod = PendingMembershipPeriod;
+    type RenewablePeriod = RenewablePeriod;
+    type RevocationPeriod = RevocationPeriod;
+}
+
+// Cert
+parameter_types! {
+    pub const MaxByIssuer: u8 = 3;
+    pub const CertRenewablePeriod: u64 = 4;
+    pub const CertPeriod: u64 = 2;
+    pub const ValidityPeriod: u64 = 10;
+}
+
+impl pallet_certification::Config<Instance1> for Test {
+    type AddCertOrigin = pallet_duniter_wot::AddStrongCertOrigin<Test>;
+    type CertPeriod = CertPeriod;
+    type DelCertOrigin = pallet_duniter_wot::DelStrongCertOrigin<Test>;
+    type Event = Event;
+    type IdtyIndex = IdtyIndex;
+    type MaxByIssuer = MaxByIssuer;
+    type OnNewcert = DuniterWot;
+    type OnRemovedCert = DuniterWot;
+    type CertRenewablePeriod = CertRenewablePeriod;
+    type ValidityPeriod = ValidityPeriod;
+}
+
+pub const NAMES: [&str; 6] = ["Alice", "Bob", "Charlie", "Dave", "Eve", "Ferdie"];
+
+// Build genesis storage according to the mock runtime.
+pub fn new_test_ext(initial_identities_len: usize) -> sp_io::TestExternalities {
+    GenesisConfig {
+        system: SystemConfig::default(),
+        identity: IdentityConfig {
+            identities: (1..=initial_identities_len)
+                .map(|i| pallet_identity::IdtyValue {
+                    data: (),
+                    owner_key: i as u64,
+                    name: pallet_identity::IdtyName::from(NAMES[i]),
+                    next_creatable_identity_on: 0,
+                    removable_on: 0,
+                    rights: vec![
+                        (IdtyRight::CreateIdty, None),
+                        (IdtyRight::StrongCert, None),
+                        (IdtyRight::Ud, None),
+                    ],
+                    status: pallet_identity::IdtyStatus::Validated,
+                })
+                .collect(),
+        },
+        membership: MembershipConfig {
+            memberships: (1..=initial_identities_len)
+                .map(|i| {
+                    (
+                        i as u32,
+                        sp_membership::MembershipData {
+                            expire_on: MembershipPeriod::get(),
+                            renewable_on: RenewablePeriod::get(),
+                        },
+                    )
+                })
+                .collect(),
+        },
+        cert: CertConfig {
+            certs_by_issuer: clique_wot(initial_identities_len, ValidityPeriod::get()),
+        },
+    }
+    .build_storage()
+    .unwrap()
+    .into()
+}
+
+pub fn run_to_block(n: u64) {
+    while System::block_number() < n {
+        DuniterWot::on_finalize(System::block_number());
+        Identity::on_finalize(System::block_number());
+        Membership::on_finalize(System::block_number());
+        Cert::on_finalize(System::block_number());
+        System::on_finalize(System::block_number());
+        System::reset_events();
+        System::set_block_number(System::block_number() + 1);
+        System::on_initialize(System::block_number());
+        DuniterWot::on_initialize(System::block_number());
+        Identity::on_initialize(System::block_number());
+        Membership::on_initialize(System::block_number());
+        Cert::on_initialize(System::block_number());
+    }
+}
+
+fn clique_wot(
+    initial_identities_len: usize,
+    cert_validity_period: u64,
+) -> BTreeMap<IdtyIndex, BTreeMap<IdtyIndex, u64>> {
+    let mut certs_by_issuer = BTreeMap::new();
+    for i in 1..=initial_identities_len {
+        certs_by_issuer.insert(
+            i as IdtyIndex,
+            (1..=initial_identities_len)
+                .filter_map(|j| {
+                    if i != j {
+                        Some((j as IdtyIndex, cert_validity_period))
+                    } else {
+                        None
+                    }
+                })
+                .collect(),
+        );
+    }
+    certs_by_issuer
+}
diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7b29034e5afb4e8ef76da7275289dc10f47efaff
--- /dev/null
+++ b/pallets/duniter-wot/src/tests.rs
@@ -0,0 +1,217 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+use crate::mock::Identity;
+use crate::mock::*;
+use crate::IdtyRight;
+use frame_support::assert_err;
+use frame_support::assert_ok;
+use frame_support::instances::Instance1;
+use frame_system::{EventRecord, Phase};
+use pallet_identity::{IdtyName, IdtyStatus};
+
+#[test]
+fn test_genesis_build() {
+    new_test_ext(3).execute_with(|| {
+        run_to_block(1);
+        // Verify state
+        assert_eq!(Identity::identities_count(), 3);
+        assert_eq!(Identity::identity(1).unwrap().next_creatable_identity_on, 0);
+        assert_eq!(
+            pallet_certification::Pallet::<Test, Instance1>::idty_cert_meta(1)
+                .unwrap()
+                .next_issuable_on,
+            2
+        );
+    });
+}
+
+#[test]
+fn test_creator_not_allowed_to_create_idty() {
+    new_test_ext(3).execute_with(|| {
+        run_to_block(1);
+
+        // Alice should not be able te create an identity before block #2
+        // because Alice.next_issuable_on = 2
+        assert_err!(
+            Identity::create_identity(Origin::signed(1), 1, IdtyName::from("Dave"), 4),
+            pallet_identity::Error::<Test>::CreatorNotAllowedToCreateIdty
+        );
+    });
+}
+
+#[test]
+fn test_create_idty_ok() {
+    new_test_ext(3).execute_with(|| {
+        run_to_block(2);
+
+        // Alice should be able te create an identity at block #2
+        assert_ok!(Identity::create_identity(
+            Origin::signed(1),
+            1,
+            IdtyName::from("Dave"),
+            4
+        ));
+        // 2 events should have occurred: IdtyCreated and NewCert
+        let events = System::events();
+        assert_eq!(events.len(), 2);
+        assert_eq!(
+            events[0],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Identity(pallet_identity::Event::IdtyCreated(
+                    IdtyName::from("Dave"),
+                    4
+                )),
+                topics: vec![],
+            }
+        );
+        assert_eq!(
+            events[1],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Cert(pallet_certification::Event::NewCert {
+                    issuer: 1,
+                    issuer_issued_count: 3,
+                    receiver: 4,
+                    receiver_received_count: 1
+                }),
+                topics: vec![],
+            }
+        );
+        assert_eq!(Identity::identity(4).unwrap().status, IdtyStatus::Created);
+        assert_eq!(Identity::identity(4).unwrap().removable_on, 4);
+    });
+}
+
+#[test]
+fn test_ud_right_achievement_ok() {
+    new_test_ext(3).execute_with(|| {
+        // Alice create Dave identity
+        run_to_block(2);
+        assert_ok!(Identity::create_identity(
+            Origin::signed(1),
+            1,
+            IdtyName::from("Dave"),
+            4
+        ));
+
+        // Dave confirm it's identity
+        run_to_block(3);
+        assert_ok!(Identity::confirm_identity(
+            Origin::signed(4),
+            IdtyName::from("Dave"),
+            4
+        ));
+
+        // Bob should be able to certify Dave
+        run_to_block(4);
+        assert_ok!(Cert::add_cert(Origin::signed(2), 2, 4));
+
+        let events = System::events();
+        // 3 events should have occurred: NewCert, MembershipAcquired, IdtyValidated and IdtyAcquireRight
+        assert_eq!(events.len(), 4);
+        println!("{:?}", events[2]);
+        assert_eq!(
+            events[0],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Cert(pallet_certification::Event::NewCert {
+                    issuer: 2,
+                    issuer_issued_count: 3,
+                    receiver: 4,
+                    receiver_received_count: 2
+                }),
+                topics: vec![],
+            }
+        );
+        assert_eq!(
+            events[1],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Membership(pallet_membership::Event::MembershipAcquired(4)),
+                topics: vec![],
+            }
+        );
+        assert_eq!(
+            events[2],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Identity(pallet_identity::Event::IdtyValidated(IdtyName::from(
+                    "Dave"
+                ),)),
+                topics: vec![],
+            }
+        );
+        assert_eq!(
+            events[3],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Identity(pallet_identity::Event::IdtyAcquireRight(
+                    IdtyName::from("Dave"),
+                    IdtyRight::Ud
+                )),
+                topics: vec![],
+            }
+        );
+    });
+}
+
+#[test]
+fn test_confirm_idty_ok() {
+    new_test_ext(3).execute_with(|| {
+        run_to_block(2);
+
+        // Alice create Dave identity
+        assert_ok!(Identity::create_identity(
+            Origin::signed(1),
+            1,
+            IdtyName::from("Dave"),
+            4
+        ));
+
+        run_to_block(3);
+
+        // Dave should be able to confirm it's identity
+        assert_ok!(Identity::confirm_identity(
+            Origin::signed(4),
+            IdtyName::from("Dave"),
+            4
+        ));
+        let events = System::events();
+        // 2 events should have occurred: MembershipRequested and IdtyConfirmed
+        assert_eq!(events.len(), 2);
+        //println!("{:?}", events[0]);
+        assert_eq!(
+            events[0],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Membership(pallet_membership::Event::MembershipRequested(4)),
+                topics: vec![],
+            }
+        );
+        assert_eq!(
+            events[1],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Identity(pallet_identity::Event::IdtyConfirmed(IdtyName::from(
+                    "Dave"
+                ),)),
+                topics: vec![],
+            }
+        );
+    });
+}
diff --git a/pallets/duniter-wot/src/types.rs b/pallets/duniter-wot/src/types.rs
new file mode 100644
index 0000000000000000000000000000000000000000..37ae0195bd5f842b7327d53090d68357443426cd
--- /dev/null
+++ b/pallets/duniter-wot/src/types.rs
@@ -0,0 +1,114 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+use pallet_identity::IdtyStatus;
+
+use crate::{Config, IdtyIndex};
+use frame_support::instances::Instance1;
+use frame_support::pallet_prelude::*;
+use scale_info::TypeInfo;
+#[cfg(feature = "std")]
+use serde::{Deserialize, Serialize};
+use sp_runtime::traits::IsMember;
+
+pub struct AddStrongCertOrigin<T>(core::marker::PhantomData<T>);
+impl<T: Config> EnsureOrigin<(T::Origin, IdtyIndex, IdtyIndex)> for AddStrongCertOrigin<T> {
+    type Success = ();
+
+    fn try_origin(
+        o: (T::Origin, IdtyIndex, IdtyIndex),
+    ) -> Result<Self::Success, (T::Origin, IdtyIndex, IdtyIndex)> {
+        match o.0.clone().into() {
+            Ok(frame_system::RawOrigin::Root) => Ok(()),
+            Ok(frame_system::RawOrigin::Signed(who)) => {
+                if let Some(issuer) = pallet_identity::Pallet::<T>::identity(o.1) {
+                    if let Some(allowed_key) = issuer.get_right_key(IdtyRight::StrongCert) {
+                        if who == allowed_key {
+                            if let Some(receiver) = pallet_identity::Pallet::<T>::identity(o.2) {
+                                match receiver.status {
+                                    IdtyStatus::ConfirmedByOwner => Ok(()),
+                                    IdtyStatus::Validated => {
+                                        if pallet_membership::Pallet::<T, Instance1>::is_member(
+                                            &o.2,
+                                        ) || pallet_membership::Pallet::<T, Instance1>::pending_membership(&o.2).is_some() {
+                                            Ok(())
+                                        } else {
+                                            Err(o)
+                                        }
+                                    }
+                                    IdtyStatus::Created => Err(o),
+                                }
+                            } else {
+                                // Receiver not found
+                                Err(o)
+                            }
+                        } else {
+                            // Bad key
+                            Err(o)
+                        }
+                    } else {
+                        // Issuer has not right StrongCert
+                        Err(o)
+                    }
+                } else {
+                    // Issuer not found
+                    Err(o)
+                }
+            }
+            _ => Err(o),
+        }
+    }
+}
+
+pub struct DelStrongCertOrigin<T>(core::marker::PhantomData<T>);
+impl<T: Config> EnsureOrigin<(T::Origin, IdtyIndex, IdtyIndex)> for DelStrongCertOrigin<T> {
+    type Success = ();
+
+    fn try_origin(
+        o: (T::Origin, IdtyIndex, IdtyIndex),
+    ) -> Result<Self::Success, (T::Origin, IdtyIndex, IdtyIndex)> {
+        match o.0.clone().into() {
+            Ok(frame_system::Origin::<T>::Root) => Ok(()),
+            _ => Err(o),
+        }
+    }
+}
+
+#[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
+#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)]
+pub enum IdtyRight {
+    CreateIdty,
+    LightCert,
+    StrongCert,
+    Ud,
+}
+impl Default for IdtyRight {
+    fn default() -> Self {
+        Self::Ud
+    }
+}
+impl pallet_identity::traits::IdtyRight for IdtyRight {
+    fn allow_owner_key(self) -> bool {
+        match self {
+            Self::CreateIdty | Self::LightCert | IdtyRight::StrongCert | Self::Ud => true,
+            //IdtyRight::StrongCert => false,
+            //_ => false,
+        }
+    }
+    fn create_idty_right() -> Self {
+        Self::CreateIdty
+    }
+}
diff --git a/pallets/identity/Cargo.toml b/pallets/identity/Cargo.toml
index d7b804275173c23321b94b0084a87e9b5305039e..8537bccbc4cf0fb71e8c0a062d890b925f774629 100644
--- a/pallets/identity/Cargo.toml
+++ b/pallets/identity/Cargo.toml
@@ -19,14 +19,12 @@ std = [
     'frame-benchmarking/std',
     'serde',
     'sp-core/std',
-    'sp-membership/std',
     'sp-runtime/std',
 	'sp-std/std',
 ]
 try-runtime = ['frame-support/try-runtime']
 
 [dependencies]
-sp-membership = { path = "../../primitives/membership", default-features = false }
 
 # substrate
 scale-info = { version = "1.0", default-features = false, features = ["derive"] }
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index 567ebc9dfef3b06123aeb25e79dd2c52b8d286da..bc596940dca4502bda6f1e5f60b507a216137ed8 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -35,7 +35,6 @@ pub use types::*;
 use crate::traits::*;
 use codec::Codec;
 use frame_support::dispatch::Weight;
-use frame_system::RawOrigin;
 use sp_runtime::traits::{AtLeast32BitUnsigned, One, Saturating, Zero};
 use sp_std::fmt::Debug;
 use sp_std::prelude::*;
@@ -46,7 +45,7 @@ pub mod pallet {
     use frame_support::pallet_prelude::*;
     use frame_support::traits::StorageVersion;
     use frame_system::pallet_prelude::*;
-    use sp_membership::traits::MembershipAction as _;
+    use sp_runtime::traits::IsMember;
 
     /// The current storage version.
     const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
@@ -93,6 +92,8 @@ pub mod pallet {
         type IdtyValidationOrigin: EnsureOrigin<Self::Origin>;
         /// Rights that an identity can have
         type IdtyRight: IdtyRight;
+        ///
+        type IsMember: sp_runtime::traits::IsMember<Self::IdtyIndex>;
         /// On identity confirmed by it's owner
         type OnIdtyChange: OnIdtyChange<Self>;
         /// On right key change
@@ -100,8 +101,6 @@ pub mod pallet {
         #[pallet::constant]
         /// Maximum period with no rights, after this period, the identity is permanently deleted
         type MaxNoRightPeriod: Get<Self::BlockNumber>;
-        ///
-        type Membership: sp_membership::traits::MembershipAction<Self::IdtyIndex, Self::Origin>;
     }
 
     // GENESIS STUFF //
@@ -226,9 +225,6 @@ pub mod pallet {
         /// An identity has been validated
         /// [idty]
         IdtyValidated(IdtyName),
-        /// An identity was renewed by it's owner
-        /// [idty]
-        IdtyRenewed(IdtyName),
         /// An identity has acquired a new right
         /// [idty, right]
         IdtyAcquireRight(IdtyName, T::IdtyRight),
@@ -348,7 +344,9 @@ pub mod pallet {
                     if idty_value.name != idty_name {
                         return Err(Error::<T>::NotSameIdtyName.into());
                     }
-                    T::Membership::request_membership_(RawOrigin::Signed(who).into(), idty_index)?;
+                    if !T::EnsureIdtyCallAllowed::can_confirm_identity(idty_index) {
+                        return Err(Error::<T>::NotAllowedToConfirmIdty.into());
+                    }
 
                     idty_value.status = IdtyStatus::ConfirmedByOwner;
 
@@ -364,56 +362,20 @@ pub mod pallet {
             }
         }
         #[pallet::weight(0)]
-        pub fn renew_identity(
-            origin: OriginFor<T>,
-            idty_name: IdtyName,
-            idty_index: T::IdtyIndex,
-        ) -> DispatchResultWithPostInfo {
-            let who = ensure_signed(origin)?;
-
-            if let Ok(mut idty_value) = <Identities<T>>::try_get(idty_index) {
-                if who == idty_value.owner_key {
-                    match idty_value.status {
-                        IdtyStatus::Created | IdtyStatus::ConfirmedByOwner => {
-                            Err(Error::<T>::IdtyNotValidated.into())
-                        }
-                        IdtyStatus::Validated | IdtyStatus::Expired => {
-                            let _post_info = T::Membership::renew_membership_(
-                                RawOrigin::Signed(who).into(),
-                                idty_index,
-                            )?;
-
-                            let old_status = idty_value.status;
-                            idty_value.status = IdtyStatus::Validated;
-
-                            <Identities<T>>::insert(idty_index, idty_value);
-                            Self::deposit_event(Event::IdtyRenewed(idty_name));
-                            if old_status == IdtyStatus::Expired {
-                                T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Validated);
-                            }
-                            Ok(().into())
-                        }
-                    }
-                } else {
-                    Err(Error::<T>::RequireToBeOwner.into())
-                }
-            } else {
-                Err(Error::<T>::IdtyNotFound.into())
-            }
-        }
-        #[pallet::weight(0)]
         pub fn validate_identity(
             origin: OriginFor<T>,
             idty_index: T::IdtyIndex,
             idty_rights: Vec<T::IdtyRight>,
         ) -> DispatchResultWithPostInfo {
-            T::IdtyValidationOrigin::ensure_origin(origin.clone())?;
+            T::IdtyValidationOrigin::ensure_origin(origin)?;
 
             if let Ok(mut idty_value) = <Identities<T>>::try_get(idty_index) {
                 match idty_value.status {
                     IdtyStatus::Created => Err(Error::<T>::IdtyNotConfirmedByOwner.into()),
                     IdtyStatus::ConfirmedByOwner => {
-                        let _post_info = T::Membership::claim_membership_(origin, idty_index)?;
+                        if !T::EnsureIdtyCallAllowed::can_validate_identity(idty_index) {
+                            return Err(Error::<T>::NotAllowedToValidateIdty.into());
+                        }
 
                         idty_value.removable_on = T::BlockNumber::zero();
                         idty_value.rights =
@@ -446,9 +408,7 @@ pub mod pallet {
                         }
                         Ok(().into())
                     }
-                    IdtyStatus::Validated | IdtyStatus::Expired => {
-                        Err(Error::<T>::IdtyAlreadyValidated.into())
-                    }
+                    IdtyStatus::Validated => Err(Error::<T>::IdtyAlreadyValidated.into()),
                 }
             } else {
                 Err(Error::<T>::IdtyNotFound.into())
@@ -467,6 +427,10 @@ pub mod pallet {
                     return Err(Error::<T>::IdtyNotValidated.into());
                 }
 
+                if !T::IsMember::is_member(&idty_index) {
+                    return Err(Error::<T>::IdtyNotMember.into());
+                }
+
                 if let Err(index) = idty_value
                     .rights
                     .binary_search_by(|(right_, _)| right_.cmp(&right))
@@ -501,49 +465,12 @@ pub mod pallet {
         ) -> DispatchResultWithPostInfo {
             T::DelRightOrigin::ensure_origin(origin)?;
 
-            if let Ok(mut idty_value) = <Identities<T>>::try_get(idty_index) {
+            if let Ok(idty_value) = <Identities<T>>::try_get(idty_index) {
                 if idty_value.status != IdtyStatus::Validated {
                     return Err(Error::<T>::IdtyNotValidated.into());
                 }
 
-                if let Ok(index) = idty_value
-                    .rights
-                    .binary_search_by(|(right_, _)| right_.cmp(&right))
-                {
-                    let name = idty_value.name.clone();
-                    let old_key_opt = if let Some(ref subkey) = idty_value.rights[index].1 {
-                        Some(subkey.clone())
-                    } else if right.allow_owner_key() {
-                        Some(idty_value.owner_key.clone())
-                    } else {
-                        None
-                    };
-                    idty_value.rights.remove(index);
-
-                    if idty_value.rights.is_empty() {
-                        let block_number = frame_system::pallet::Pallet::<T>::block_number();
-                        let removable_on = block_number + T::MaxNoRightPeriod::get();
-                        idty_value.removable_on = removable_on;
-                        <IdentitiesRemovableOn<T>>::append(
-                            removable_on,
-                            (idty_index, IdtyStatus::Validated),
-                        );
-                    }
-
-                    <Identities<T>>::insert(idty_index, idty_value);
-                    Self::deposit_event(Event::<T>::IdtyLostRight(name, right));
-                    if old_key_opt.is_some() {
-                        T::OnRightKeyChange::on_right_key_change(
-                            idty_index,
-                            right,
-                            old_key_opt,
-                            None,
-                        );
-                    }
-                    Ok(().into())
-                } else {
-                    Err(Error::<T>::RightNotExist.into())
-                }
+                Self::do_remove_right(idty_index, idty_value, right)
             } else {
                 Err(Error::<T>::IdtyNotFound.into())
             }
@@ -563,6 +490,10 @@ pub mod pallet {
                         return Err(Error::<T>::IdtyNotValidated.into());
                     }
 
+                    if !T::IsMember::is_member(&idty_index) {
+                        return Err(Error::<T>::IdtyNotMember.into());
+                    }
+
                     if let Ok(index) = idty_value
                         .rights
                         .binary_search_by(|(right_, _)| right_.cmp(&right))
@@ -602,6 +533,35 @@ pub mod pallet {
                 Err(Error::<T>::IdtyNotFound.into())
             }
         }
+
+        #[pallet::weight(0)]
+        pub fn remove_all_rights(
+            origin: OriginFor<T>,
+            idty_index: T::IdtyIndex,
+        ) -> DispatchResultWithPostInfo {
+            ensure_root(origin)?;
+
+            if let Ok(idty_value) = <Identities<T>>::try_get(idty_index) {
+                for (right, _key_opt) in &idty_value.rights {
+                    Self::do_remove_right(idty_index, idty_value.clone(), *right)?;
+                }
+                Ok(().into())
+            } else {
+                Err(Error::<T>::IdtyNotFound.into())
+            }
+        }
+
+        #[pallet::weight(0)]
+        pub fn remove_identity(
+            origin: OriginFor<T>,
+            idty_index: T::IdtyIndex,
+        ) -> DispatchResultWithPostInfo {
+            ensure_root(origin)?;
+
+            Self::do_remove_identity(idty_index);
+
+            Ok(().into())
+        }
     }
 
     // ERRORS //
@@ -628,10 +588,16 @@ pub mod pallet {
         IdtyNotConfirmedByOwner,
         /// Identity not found
         IdtyNotFound,
+        /// Idty not member
+        IdtyNotMember,
         /// Identity not validated
         IdtyNotValidated,
         /// Identity not yet renewable
         IdtyNotYetRenewable,
+        /// Not allowed to confirm identity
+        NotAllowedToConfirmIdty,
+        /// Not allowed to validate identity
+        NotAllowedToValidateIdty,
         /// Not same identity name
         NotSameIdtyName,
         /// This operation requires to be the owner of the identity
@@ -666,32 +632,53 @@ pub mod pallet {
                 panic!("storage corrupted")
             }
         }
-        pub(super) fn do_expire_identity(idty_index: T::IdtyIndex) -> Weight {
-            let mut total_weight: Weight = 0;
-
-            let block_number = frame_system::pallet::Pallet::<T>::block_number();
-            let removable_on = block_number + T::MaxNoRightPeriod::get();
-            <Identities<T>>::mutate_exists(idty_index, |idty_val_opt| {
-                if let Some(ref mut idty_val) = idty_val_opt {
-                    idty_val.removable_on = removable_on;
-                    idty_val.rights = Vec::with_capacity(0);
-                }
-            });
-            <IdentitiesRemovableOn<T>>::append(removable_on, (idty_index, IdtyStatus::Expired));
-            total_weight += T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Expired);
-
-            total_weight
-        }
         pub(super) fn do_remove_identity(idty_index: T::IdtyIndex) -> Weight {
-            let mut total_weight: Weight = 0;
-
             if let Some(idty_val) = <Identities<T>>::take(idty_index) {
                 <IdentitiesByDid<T>>::remove(idty_val.name);
             }
             Self::dec_identities_counter();
-            total_weight += T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Removed);
+            T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Removed);
 
-            total_weight
+            0
+        }
+        pub(super) fn do_remove_right(
+            idty_index: T::IdtyIndex,
+            mut idty_value: IdtyValue<T::AccountId, T::BlockNumber, T::IdtyData, T::IdtyRight>,
+            right: T::IdtyRight,
+        ) -> DispatchResultWithPostInfo {
+            if let Ok(index) = idty_value
+                .rights
+                .binary_search_by(|(right_, _)| right_.cmp(&right))
+            {
+                let name = idty_value.name.clone();
+                let old_key_opt = if let Some(ref subkey) = idty_value.rights[index].1 {
+                    Some(subkey.clone())
+                } else if right.allow_owner_key() {
+                    Some(idty_value.owner_key.clone())
+                } else {
+                    None
+                };
+                idty_value.rights.remove(index);
+
+                if idty_value.rights.is_empty() {
+                    let block_number = frame_system::pallet::Pallet::<T>::block_number();
+                    let removable_on = block_number + T::MaxNoRightPeriod::get();
+                    idty_value.removable_on = removable_on;
+                    <IdentitiesRemovableOn<T>>::append(
+                        removable_on,
+                        (idty_index, IdtyStatus::Validated),
+                    );
+                }
+
+                <Identities<T>>::insert(idty_index, idty_value);
+                Self::deposit_event(Event::<T>::IdtyLostRight(name, right));
+                if old_key_opt.is_some() {
+                    T::OnRightKeyChange::on_right_key_change(idty_index, right, old_key_opt, None);
+                }
+                Ok(().into())
+            } else {
+                Err(Error::<T>::RightNotExist.into())
+            }
         }
         fn get_next_idty_index() -> T::IdtyIndex {
             if let Ok(next_index) = <NextIdtyIndex<T>>::try_get() {
@@ -712,15 +699,10 @@ pub mod pallet {
         fn prune_identities(block_number: T::BlockNumber) -> Weight {
             let mut total_weight: Weight = 0;
 
-            use frame_support::storage::generator::StorageMap as _;
-            if let Some(identities) = IdentitiesRemovableOn::<T>::from_query_to_optional_value(
-                IdentitiesRemovableOn::<T>::take(block_number),
-            ) {
-                for (idty_index, idty_status) in identities {
-                    if let Ok(idty_val) = <Identities<T>>::try_get(idty_index) {
-                        if idty_val.removable_on == block_number && idty_val.status == idty_status {
-                            total_weight += Self::do_remove_identity(idty_index)
-                        }
+            for (idty_index, idty_status) in IdentitiesRemovableOn::<T>::take(block_number) {
+                if let Ok(idty_val) = <Identities<T>>::try_get(idty_index) {
+                    if idty_val.removable_on == block_number && idty_val.status == idty_status {
+                        total_weight += Self::do_remove_identity(idty_index)
                     }
                 }
             }
@@ -729,45 +711,3 @@ pub mod pallet {
         }
     }
 }
-
-impl<T: Config> sp_membership::traits::IsOriginAllowedToUseIdty<T::Origin, T::IdtyIndex>
-    for Pallet<T>
-{
-    fn is_origin_allowed_to_use_idty(
-        origin: &T::Origin,
-        idty_index: &T::IdtyIndex,
-    ) -> sp_membership::OriginPermission {
-        match origin.clone().into() {
-            Ok(RawOrigin::Root) => sp_membership::OriginPermission::Root,
-            Ok(RawOrigin::Signed(account_id)) => {
-                if let Some(idty_val) = Pallet::<T>::identity(idty_index) {
-                    if account_id == idty_val.owner_key {
-                        sp_membership::OriginPermission::Allowed
-                    } else {
-                        sp_membership::OriginPermission::Forbidden
-                    }
-                } else {
-                    sp_membership::OriginPermission::Forbidden
-                }
-            }
-            _ => sp_membership::OriginPermission::Forbidden,
-        }
-    }
-}
-
-impl<T: Config> sp_membership::traits::OnEvent<T::IdtyIndex> for Pallet<T> {
-    fn on_event(membership_event: sp_membership::Event<T::IdtyIndex>) -> Weight {
-        match membership_event {
-            sp_membership::Event::<T::IdtyIndex>::MembershipAcquired(_) => 0,
-            sp_membership::Event::<T::IdtyIndex>::MembershipExpired(idty_index) => {
-                Pallet::<T>::do_expire_identity(idty_index)
-            }
-            sp_membership::Event::<T::IdtyIndex>::MembershipRenewed(_) => 0,
-            sp_membership::Event::<T::IdtyIndex>::MembershipRequested(_) => 0,
-            sp_membership::Event::<T::IdtyIndex>::MembershipRevoked(_) => 0,
-            sp_membership::Event::<T::IdtyIndex>::PendingMembershipExpired(idty_index) => {
-                Pallet::<T>::do_remove_identity(idty_index)
-            }
-        }
-    }
-}
diff --git a/pallets/identity/src/mock.rs b/pallets/identity/src/mock.rs
index 51e77fff10eb56665f9fe620b5aef0fef2a9b7f4..5985e5d53acb97ec79dc3e823ebec65590ca61e5 100644
--- a/pallets/identity/src/mock.rs
+++ b/pallets/identity/src/mock.rs
@@ -28,7 +28,7 @@ use serde::{Deserialize, Serialize};
 use sp_core::H256;
 use sp_runtime::{
     testing::Header,
-    traits::{BlakeTwo256, IdentityLookup},
+    traits::{BlakeTwo256, IdentityLookup, IsMember},
     BuildStorage,
 };
 
@@ -128,6 +128,13 @@ impl pallet_identity::traits::IdtyNameValidator for IdtyNameValidatorTestImpl {
     }
 }
 
+pub struct IsMemberTestImpl;
+impl IsMember<u64> for IsMemberTestImpl {
+    fn is_member(_: &u64) -> bool {
+        true
+    }
+}
+
 impl pallet_identity::Config for Test {
     type ConfirmPeriod = ConfirmPeriod;
     type Event = Event;
@@ -141,10 +148,10 @@ impl pallet_identity::Config for Test {
     type IdtyIndex = u64;
     type IdtyValidationOrigin = system::EnsureRoot<AccountId>;
     type IdtyRight = IdtyRight;
+    type IsMember = IsMemberTestImpl;
     type OnIdtyChange = ();
     type OnRightKeyChange = ();
     type MaxNoRightPeriod = MaxNoRightPeriod;
-    type Membership = ();
 }
 
 // Build genesis storage according to the mock runtime.
diff --git a/pallets/identity/src/traits.rs b/pallets/identity/src/traits.rs
index d5b1e19b7b7383061c14f10669972ca5c92ef244..63594427817d0cf3ab2cc9d9edf995e3ac1fbf6f 100644
--- a/pallets/identity/src/traits.rs
+++ b/pallets/identity/src/traits.rs
@@ -21,10 +21,18 @@ use sp_std::fmt::Debug;
 
 pub trait EnsureIdtyCallAllowed<T: Config> {
     fn can_create_identity(creator: T::IdtyIndex) -> bool;
+    fn can_confirm_identity(idty_index: T::IdtyIndex) -> bool;
+    fn can_validate_identity(idty_index: T::IdtyIndex) -> bool;
 }
 
 impl<T: Config> EnsureIdtyCallAllowed<T> for () {
-    fn can_create_identity(_creator: T::IdtyIndex) -> bool {
+    fn can_create_identity(_: T::IdtyIndex) -> bool {
+        true
+    }
+    fn can_confirm_identity(_: T::IdtyIndex) -> bool {
+        true
+    }
+    fn can_validate_identity(_: T::IdtyIndex) -> bool {
         true
     }
 }
@@ -67,14 +75,6 @@ pub trait IdtyRight:
     fn create_idty_right() -> Self;
 }
 
-pub enum IdtyEvent<T: Config> {
-    Created { creator: T::IdtyIndex },
-    Confirmed,
-    Validated,
-    Expired,
-    Removed,
-}
-
 pub trait OnIdtyChange<T: Config> {
     fn on_idty_change(idty_index: T::IdtyIndex, idty_event: IdtyEvent<T>) -> Weight;
 }
diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs
index b4231157bae636c39221a8d7f7bd10c305c83912..f1f2e8fcd38861dbcc5c9a25e944d2cccf39d21f 100644
--- a/pallets/identity/src/types.rs
+++ b/pallets/identity/src/types.rs
@@ -23,6 +23,13 @@ use scale_info::TypeInfo;
 use serde::{Deserialize, Serialize};
 use sp_std::vec::Vec;
 
+pub enum IdtyEvent<T: crate::Config> {
+    Created { creator: T::IdtyIndex },
+    Confirmed,
+    Validated,
+    Removed,
+}
+
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
 pub struct IdtyName(pub Vec<u8>);
 
@@ -63,7 +70,6 @@ pub enum IdtyStatus {
     Created,
     ConfirmedByOwner,
     Validated,
-    Expired,
 }
 impl Default for IdtyStatus {
     fn default() -> Self {
diff --git a/pallets/membership/src/lib.rs b/pallets/membership/src/lib.rs
index dd93b656e2555bd25dff794d838b72cbd6500eb1..cf4cb466d0bc8126509d9d41c01fc55045efee65 100644
--- a/pallets/membership/src/lib.rs
+++ b/pallets/membership/src/lib.rs
@@ -43,6 +43,7 @@ pub mod pallet {
     use frame_support::pallet_prelude::*;
     use frame_support::traits::StorageVersion;
     use frame_system::pallet_prelude::*;
+    use sp_runtime::traits::IsMember;
 
     /// The current storage version.
     const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
@@ -132,7 +133,7 @@ pub mod pallet {
     #[pallet::storage]
     #[pallet::getter(fn pending_membership)]
     pub type PendingMembership<T: Config<I>, I: 'static = ()> =
-        StorageMap<_, Blake2_128Concat, T::IdtyId, (), OptionQuery>;
+        StorageMap<_, Blake2_128Concat, T::IdtyId, T::BlockNumber, OptionQuery>;
 
     #[pallet::storage]
     #[pallet::getter(fn pending_memberships_expire_on)]
@@ -186,6 +187,8 @@ pub mod pallet {
         IdtyNotAllowedToRenewMembership,
         /// Membership already acquired
         MembershipAlreadyAcquired,
+        /// Membership already requested
+        MembershipAlreadyRequested,
         /// Membership not yet renewable
         MembershipNotYetRenewable,
         /// Membership not found
@@ -238,6 +241,9 @@ pub mod pallet {
             if !allowed {
                 return Err(Error::<T, I>::IdtyNotAllowedToRequestMembership.into());
             }
+            if PendingMembership::<T, I>::contains_key(&idty_id) {
+                return Err(Error::<T, I>::MembershipAlreadyRequested.into());
+            }
             if Membership::<T, I>::contains_key(&idty_id) {
                 return Err(Error::<T, I>::MembershipAlreadyAcquired.into());
             }
@@ -248,7 +254,7 @@ pub mod pallet {
             let block_number = frame_system::pallet::Pallet::<T>::block_number();
             let expire_on = block_number + T::PendingMembershipPeriod::get();
 
-            PendingMembership::<T, I>::insert(idty_id, ());
+            PendingMembership::<T, I>::insert(idty_id, expire_on);
             PendingMembershipsExpireOn::<T, I>::append(expire_on, idty_id);
             Self::deposit_event(Event::MembershipRequested(idty_id));
             T::OnEvent::on_event(sp_membership::Event::MembershipRequested(idty_id));
@@ -261,6 +267,9 @@ pub mod pallet {
             origin: OriginFor<T>,
             idty_id: T::IdtyId,
         ) -> DispatchResultWithPostInfo {
+            if Membership::<T, I>::contains_key(&idty_id) {
+                return Err(Error::<T, I>::MembershipAlreadyAcquired.into());
+            }
             let allowed =
                 match T::IsOriginAllowedToUseIdty::is_origin_allowed_to_use_idty(&origin, &idty_id)
                 {
@@ -482,7 +491,7 @@ impl<T: Config<I>, I: 'static> IsInPendingMemberships<T::IdtyId> for Pallet<T, I
     }
 }
 
-impl<T: Config<I>, I: 'static> IsMember<T::IdtyId> for Pallet<T, I> {
+impl<T: Config<I>, I: 'static> sp_runtime::traits::IsMember<T::IdtyId> for Pallet<T, I> {
     fn is_member(idty_id: &T::IdtyId) -> bool {
         Self::is_member_inner(idty_id)
     }
diff --git a/pallets/membership/src/mock.rs b/pallets/membership/src/mock.rs
index 3a9869bf0189d1d587b428b510181cbd043b8385..14eb7438f10f5f5c83f4662a35bfa694e5b90dda 100644
--- a/pallets/membership/src/mock.rs
+++ b/pallets/membership/src/mock.rs
@@ -109,7 +109,7 @@ impl pallet_membership::Config for Test {
     type ExternalizeMembershipStorage = ExternalizeMembershipStorage;
     type IdtyId = IdtyId;
     type OnEvent = ();
-    type MembershipExternalStorage = ();
+    type MembershipExternalStorage = crate::NoExternalStorage;
     type MembershipPeriod = MembershipPeriod;
     type PendingMembershipPeriod = PendingMembershipPeriod;
     type RenewablePeriod = RenewablePeriod;
diff --git a/pallets/membership/src/tests.rs b/pallets/membership/src/tests.rs
index 0ac4522803238f4fc324c557ff2dad90e5a5f3a2..a40782f21884be07dac2ae0c81eef70e41f8945c 100644
--- a/pallets/membership/src/tests.rs
+++ b/pallets/membership/src/tests.rs
@@ -19,8 +19,9 @@ use crate::mock::*;
 use crate::{Error, Event};
 use frame_support::assert_ok;
 use maplit::btreemap;
-use sp_membership::traits::{IsInPendingMemberships, IsMember};
+use sp_membership::traits::IsInPendingMemberships;
 use sp_membership::MembershipData;
+use sp_runtime::traits::IsMember;
 
 fn default_gen_conf() -> DefaultMembershipConfig {
     DefaultMembershipConfig {
@@ -61,12 +62,24 @@ fn test_membership_not_yet_renewable() {
 }
 
 #[test]
-fn test_membership_request_not_found() {
+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(Origin::signed(0), 0),
+            Err(Error::<Test, _>::MembershipAlreadyAcquired.into())
+        );
+    });
+}
+
+#[test]
+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(Origin::signed(1), 1),
             Err(Error::<Test, _>::MembershipRequestNotFound.into())
         );
     });
diff --git a/primitives/membership/Cargo.toml b/primitives/membership/Cargo.toml
index 29bb6472df273c18669c41966745a521b9561f56..716ad19ae74304847b044749ef8ddfe06823bf45 100644
--- a/primitives/membership/Cargo.toml
+++ b/primitives/membership/Cargo.toml
@@ -15,6 +15,7 @@ std = [
     'codec/std',
     'frame-support/std',
     'serde',
+	'sp-runtime/std',
 	'sp-std/std',
 ]
 try-runtime = ['frame-support/try-runtime']
@@ -40,6 +41,11 @@ version = "1.0.101"
 optional = true
 features = ["derive"]
 
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
 [dependencies.sp-std]
 default-features = false
 git = 'https://github.com/librelois/substrate.git'
diff --git a/primitives/membership/src/traits.rs b/primitives/membership/src/traits.rs
index 580eaa82e35fe0a356eacd0ad1cad54a0ab78a02..e77c8d1434d9cbd8782d5b7b8723e77f48c63b85 100644
--- a/primitives/membership/src/traits.rs
+++ b/primitives/membership/src/traits.rs
@@ -61,16 +61,6 @@ pub trait IsInPendingMemberships<IdtyId> {
     fn is_in_pending_memberships(idty_id: IdtyId) -> bool;
 }
 
-pub trait IsMember<IdtyId> {
-    fn is_member(idty_id: &IdtyId) -> bool;
-}
-
-impl<IdtyId> IsMember<IdtyId> for () {
-    fn is_member(_: &IdtyId) -> bool {
-        false
-    }
-}
-
 pub trait OnEvent<IdtyId> {
     fn on_event(event: crate::Event<IdtyId>) -> Weight;
 }
@@ -116,7 +106,7 @@ impl<IdtyId, Origin> MembershipAction<IdtyId, Origin> for () {
 }
 
 pub trait MembershipExternalStorage<BlockNumber: Decode + Encode + TypeInfo, IdtyId>:
-    IsMember<IdtyId>
+    sp_runtime::traits::IsMember<IdtyId>
 {
     fn insert(idty_id: IdtyId, membership_data: MembershipData<BlockNumber>);
     fn get(idty_id: &IdtyId) -> Option<MembershipData<BlockNumber>>;
@@ -125,8 +115,14 @@ pub trait MembershipExternalStorage<BlockNumber: Decode + Encode + TypeInfo, Idt
 
 static INVALID_CONF_MSG: &str = "invalid pallet configuration: if `MembershipExternalStorage` = (), you must set `ExternalizeMembershipStorage` to `false`.";
 
+pub struct NoExternalStorage;
+impl<IdtyId> sp_runtime::traits::IsMember<IdtyId> for NoExternalStorage {
+    fn is_member(_: &IdtyId) -> bool {
+        panic!("{}", INVALID_CONF_MSG)
+    }
+}
 impl<BlockNumber: Decode + Encode + TypeInfo, IdtyId> MembershipExternalStorage<BlockNumber, IdtyId>
-    for ()
+    for NoExternalStorage
 {
     fn insert(_: IdtyId, _: MembershipData<BlockNumber>) {
         panic!("{}", INVALID_CONF_MSG)
diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml
index c1ba7a8676754fe6dac3cd2da4ce2ee738f12335..07f972d8f166a6a50b84c9908b420408efb2f3a0 100644
--- a/runtime/common/Cargo.toml
+++ b/runtime/common/Cargo.toml
@@ -11,6 +11,7 @@ runtime-benchmarks = [
     'frame-support/runtime-benchmarks',
     'frame-system/runtime-benchmarks',
     'pallet-certification/runtime-benchmarks',
+    'pallet-duniter-wot/runtime-benchmarks',
     'pallet-identity/runtime-benchmarks',
     'pallet-membership/runtime-benchmarks',
     'pallet-ud-accounts-storage/runtime-benchmarks',
@@ -21,6 +22,7 @@ std = [
     'frame-support/std',
     'frame-system/std',
     'pallet-certification/std',
+    'pallet-duniter-wot/std',
     'pallet-identity/std',
     'pallet-membership/std',
     'pallet-ud-accounts-storage/std',
@@ -33,12 +35,15 @@ std = [
 
 [dependencies]
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
+
+# Crates.io
 smallvec = "1.6.1"
 
-# substrate
+# Substrate
 scale-info = { version = "1.0", default-features = false, features = ["derive"] }
 
 [dependencies.codec]
diff --git a/runtime/common/src/authorizations.rs b/runtime/common/src/authorizations.rs
deleted file mode 100644
index d5be8c5a9eea64bec9ffe5ff7bea43ea8acc1233..0000000000000000000000000000000000000000
--- a/runtime/common/src/authorizations.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2021 Axiom-Team
-//
-// This file is part of Substrate-Libre-Currency.
-//
-// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, version 3 of the License.
-//
-// Substrate-Libre-Currency is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
-
-use crate::entities::IdtyRight;
-use crate::{BlockNumber, IdtyIndex};
-use frame_support::traits::EnsureOrigin;
-use pallet_certification::traits::IsIdtyAllowedToCreateCert;
-use pallet_identity::IdtyStatus;
-
-pub struct EnsureIdtyCallAllowedImpl<Runtime, IsIdtyAllowedToCreateCertImpl>(
-    core::marker::PhantomData<(Runtime, IsIdtyAllowedToCreateCertImpl)>,
-);
-impl<
-        Runtime: frame_system::Config<BlockNumber = BlockNumber>
-            + pallet_identity::Config<IdtyIndex = IdtyIndex>,
-        IsIdtyAllowedToCreateCertImpl: IsIdtyAllowedToCreateCert<IdtyIndex>,
-    > pallet_identity::traits::EnsureIdtyCallAllowed<Runtime>
-    for EnsureIdtyCallAllowedImpl<Runtime, IsIdtyAllowedToCreateCertImpl>
-{
-    fn can_create_identity(creator: IdtyIndex) -> bool {
-        IsIdtyAllowedToCreateCertImpl::is_idty_allowed_to_create_cert(creator)
-    }
-}
-
-pub struct AddStrongCertOrigin<Runtime>(core::marker::PhantomData<Runtime>);
-impl<Runtime: pallet_identity::Config<IdtyIndex = IdtyIndex, IdtyRight = IdtyRight>>
-    EnsureOrigin<(Runtime::Origin, IdtyIndex, IdtyIndex)> for AddStrongCertOrigin<Runtime>
-{
-    type Success = ();
-
-    fn try_origin(
-        o: (Runtime::Origin, IdtyIndex, IdtyIndex),
-    ) -> Result<Self::Success, (Runtime::Origin, IdtyIndex, IdtyIndex)> {
-        match o.0.clone().into() {
-            Ok(frame_system::RawOrigin::Root) => Ok(()),
-            Ok(frame_system::RawOrigin::Signed(who)) => {
-                if let Some(issuer) = pallet_identity::Pallet::<Runtime>::identity(o.1) {
-                    if let Some(allowed_key) = issuer.get_right_key(IdtyRight::StrongCert) {
-                        if who == allowed_key {
-                            if let Some(receiver) =
-                                pallet_identity::Pallet::<Runtime>::identity(o.2)
-                            {
-                                match receiver.status {
-                                    IdtyStatus::ConfirmedByOwner | IdtyStatus::Validated => Ok(()),
-                                    IdtyStatus::Created | IdtyStatus::Expired => Err(o),
-                                }
-                            } else {
-                                // Receiver not found
-                                Err(o)
-                            }
-                        } else {
-                            // Bad key
-                            Err(o)
-                        }
-                    } else {
-                        // Issuer has not right StrongCert
-                        Err(o)
-                    }
-                } else {
-                    // Issuer not found
-                    Err(o)
-                }
-            }
-            _ => Err(o),
-        }
-    }
-}
-
-pub struct DelStrongCertOrigin<Runtime>(core::marker::PhantomData<Runtime>);
-impl<Runtime: frame_system::Config> EnsureOrigin<(Runtime::Origin, IdtyIndex, IdtyIndex)>
-    for DelStrongCertOrigin<Runtime>
-{
-    type Success = ();
-
-    fn try_origin(
-        o: (Runtime::Origin, IdtyIndex, IdtyIndex),
-    ) -> Result<Self::Success, (Runtime::Origin, IdtyIndex, IdtyIndex)> {
-        match o.0.clone().into() {
-            Ok(frame_system::Origin::<Runtime>::Root) => Ok(()),
-            _ => Err(o),
-        }
-    }
-}
diff --git a/runtime/common/src/entities.rs b/runtime/common/src/entities.rs
index 0943cd78f6703da376afa3e6cb23f3fcf5181501..068fd129ee6ac4c0dd1824322164d85c29de6930 100644
--- a/runtime/common/src/entities.rs
+++ b/runtime/common/src/entities.rs
@@ -21,32 +21,6 @@ use scale_info::TypeInfo;
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
 
-#[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)]
-pub enum IdtyRight {
-    CreateIdty,
-    LightCert,
-    StrongCert,
-    Ud,
-}
-impl Default for IdtyRight {
-    fn default() -> Self {
-        Self::Ud
-    }
-}
-impl pallet_identity::traits::IdtyRight for IdtyRight {
-    fn allow_owner_key(self) -> bool {
-        match self {
-            Self::CreateIdty | Self::LightCert | IdtyRight::StrongCert | Self::Ud => true,
-            //IdtyRight::StrongCert => false,
-            //_ => false,
-        }
-    }
-    fn create_idty_right() -> Self {
-        Self::CreateIdty
-    }
-}
-
 #[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
 #[derive(
     Encode, Decode, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo,
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index 54406b331676a954c97451b0bb7afb8d1c049e09..63b54fc818f4a9d650a42ba0d68855960c5c3a75 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -14,39 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
-use crate::entities::IdtyRight;
-use crate::BlockNumber;
-use frame_support::instances::Instance1;
-use frame_support::pallet_prelude::Get;
-use frame_support::weights::Weight;
-use pallet_identity::traits::IdtyEvent;
-
-pub struct OnIdtyChangeHandler<Runtime>(core::marker::PhantomData<Runtime>);
-impl<
-        IdtyIndex,
-        Runtime: pallet_identity::Config<IdtyIndex = IdtyIndex>
-            + pallet_certification::Config<Instance1, IdtyIndex = IdtyIndex>,
-    > pallet_identity::traits::OnIdtyChange<Runtime> for OnIdtyChangeHandler<Runtime>
-{
-    fn on_idty_change(idty_index: IdtyIndex, idty_event: IdtyEvent<Runtime>) -> Weight {
-        let total_weight = 0;
-        match idty_event {
-            IdtyEvent::Created { creator } => {
-                // totad_weight += StrongCert::WeightInfo::add_cert();
-                let _ = <pallet_certification::Pallet<Runtime, Instance1>>::add_cert(
-                    frame_system::Origin::<Runtime>::Root.into(),
-                    creator,
-                    idty_index,
-                );
-            }
-            IdtyEvent::Confirmed => {}
-            IdtyEvent::Validated => {}
-            IdtyEvent::Expired => {}
-            IdtyEvent::Removed => {}
-        };
-        total_weight
-    }
-}
+use pallet_duniter_wot::IdtyRight;
 
 pub struct OnRightKeyChangeHandler<Runtime>(core::marker::PhantomData<Runtime>);
 impl<
@@ -72,87 +40,3 @@ impl<
         };
     }
 }
-
-pub struct OnNewStrongCertHandler<
-    FirstIssuableOn,
-    Runtime,
-    SetNextIssuableOnImpl,
-    const MIN_STRONG_CERT_FOR_UD: u32,
-    const MIN_STRONG_CERT_FOR_STRONG_CERT: u32,
->(core::marker::PhantomData<(FirstIssuableOn, Runtime, SetNextIssuableOnImpl)>);
-impl<
-        FirstIssuableOn: Get<BlockNumber>,
-        IdtyIndex: Copy,
-        Runtime: frame_system::Config<BlockNumber = BlockNumber>
-            + pallet_identity::Config<IdtyIndex = IdtyIndex, IdtyRight = IdtyRight>,
-        SetNextIssuableOnImpl: pallet_certification::traits::SetNextIssuableOn<BlockNumber, IdtyIndex>,
-        const MIN_STRONG_CERT_FOR_UD: u32,
-        const MIN_STRONG_CERT_FOR_STRONG_CERT: u32,
-    > pallet_certification::traits::OnNewcert<IdtyIndex>
-    for OnNewStrongCertHandler<
-        FirstIssuableOn,
-        Runtime,
-        SetNextIssuableOnImpl,
-        MIN_STRONG_CERT_FOR_UD,
-        MIN_STRONG_CERT_FOR_STRONG_CERT,
-    >
-{
-    fn on_new_cert(
-        _issuer: IdtyIndex,
-        _issuer_issued_count: u8,
-        receiver: IdtyIndex,
-        receiver_received_count: u32,
-    ) -> frame_support::dispatch::Weight {
-        let total_weight = 0;
-        if receiver_received_count == MIN_STRONG_CERT_FOR_UD {
-            // total_weight += Identity::WeightInfo::add_right();
-            let _ = <pallet_identity::Pallet<Runtime>>::validate_identity(
-                frame_system::Origin::<Runtime>::Root.into(),
-                receiver,
-                sp_std::vec![IdtyRight::Ud],
-            );
-        } else if receiver_received_count == MIN_STRONG_CERT_FOR_STRONG_CERT {
-            // total_weight += Identity::WeightInfo::add_right();
-            let _ = <pallet_identity::Pallet<Runtime>>::add_right(
-                frame_system::Origin::<Runtime>::Root.into(),
-                receiver,
-                IdtyRight::StrongCert,
-            );
-            let _ = SetNextIssuableOnImpl::set_next_issuable_on(
-                receiver,
-                frame_system::Pallet::<Runtime>::block_number() + FirstIssuableOn::get(),
-            );
-        }
-        total_weight
-    }
-}
-
-pub struct OnRemovedStrongCertHandler<Runtime, const MIN_STRONG_CERT_FOR_UD: u32>(
-    core::marker::PhantomData<Runtime>,
-);
-impl<
-        IdtyIndex,
-        Runtime: pallet_identity::Config<IdtyIndex = IdtyIndex, IdtyRight = IdtyRight>,
-        const MIN_STRONG_CERT_FOR_UD: u32,
-    > pallet_certification::traits::OnRemovedCert<IdtyIndex>
-    for OnRemovedStrongCertHandler<Runtime, MIN_STRONG_CERT_FOR_UD>
-{
-    fn on_removed_cert(
-        _issuer: IdtyIndex,
-        _issuer_issued_count: u8,
-        receiver: IdtyIndex,
-        receiver_received_count: u32,
-        _expiration: bool,
-    ) -> frame_support::dispatch::Weight {
-        let total_weight = 0;
-        if receiver_received_count < MIN_STRONG_CERT_FOR_UD {
-            // total_weight += Identity::WeightInfo::del_right();
-            let _ = <pallet_identity::Pallet<Runtime>>::del_right(
-                frame_system::Origin::<Runtime>::Root.into(),
-                receiver,
-                IdtyRight::Ud,
-            );
-        }
-        total_weight
-    }
-}
diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs
index ac789e56f56dcb857e087794291f4a95751808d7..e7f9d336f701ed117f30419722d3a804c6b8166c 100644
--- a/runtime/common/src/lib.rs
+++ b/runtime/common/src/lib.rs
@@ -17,7 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 mod apis;
-pub mod authorizations;
 pub mod constants;
 pub mod entities;
 pub mod fees;
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index 8fb5add3976024f04e99472b2ee4a8cb777bb506..df3e5a6a3846ba8818ece8ecd5d13b54b8dd8dd3 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -184,12 +184,19 @@ macro_rules! pallets_config {
 
 		// WEB OF TRUST //
 
+		impl pallet_duniter_wot::Config for Runtime {
+			type MinCertForUdRight = MinCertForUdRight;
+			type MinCertForCertRight = MinCertForCertRight;
+			type MinCertForCreateIdtyRight = MinCertForCreateIdtyRight;
+			type FirstIssuableOn = FirstIssuableOn;
+		}
+
 		impl pallet_identity::Config for Runtime {
             type ConfirmPeriod = ConfirmPeriod;
             type Event = Event;
             type AddRightOrigin = EnsureRoot<Self::AccountId>;
             type DelRightOrigin = EnsureRoot<Self::AccountId>;
-            type EnsureIdtyCallAllowed = EnsureIdtyCallAllowedImpl<Runtime, StrongCert>;
+            type EnsureIdtyCallAllowed = DuniterWot;
 			type IdtyCreationPeriod = IdtyCreationPeriod;
 			type IdtyDataProvider = ();
             type IdtyData = ();
@@ -197,22 +204,22 @@ macro_rules! pallets_config {
             type IdtyIndex = IdtyIndex;
             type IdtyValidationOrigin = EnsureRoot<Self::AccountId>;
             type IdtyRight = IdtyRight;
-            type OnIdtyChange = OnIdtyChangeHandler<Runtime>;
+			type IsMember = Membership;
+            type OnIdtyChange = DuniterWot;
             type OnRightKeyChange = OnRightKeyChangeHandler<Runtime>;
             type MaxNoRightPeriod = MaxNoRightPeriod;
-			type Membership = Membership;
         }
 
 		impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime {
-			type IsIdtyAllowedToClaimMembership = ();
-			type IsIdtyAllowedToRenewMembership = ();
-			type IsIdtyAllowedToRequestMembership = ();
-			type IsOriginAllowedToUseIdty = Identity;
+			type IsIdtyAllowedToClaimMembership = DuniterWot;
+			type IsIdtyAllowedToRenewMembership = DuniterWot;
+			type IsIdtyAllowedToRequestMembership = DuniterWot;
+			type IsOriginAllowedToUseIdty = DuniterWot;
 			type Event = Event;
 			type ExternalizeMembershipStorage = frame_support::traits::ConstBool<false>;
 			type IdtyId = IdtyIndex;
-			type OnEvent = Identity;
-			type MembershipExternalStorage = ();
+			type OnEvent = DuniterWot;
+			type MembershipExternalStorage = sp_membership::traits::NoExternalStorage;
 			type MembershipPeriod = MembershipPeriod;
 			type PendingMembershipPeriod = PendingMembershipPeriod;
 			type RenewablePeriod = RenewablePeriod;
@@ -220,20 +227,19 @@ macro_rules! pallets_config {
 		}
 
         impl pallet_certification::Config<frame_support::instances::Instance1> for Runtime {
-            type AddCertOrigin = AddStrongCertOrigin<Runtime>;
+            type AddCertOrigin = pallet_duniter_wot::AddStrongCertOrigin<Runtime>;
             type CertPeriod = CertPeriod;
-            type DelCertOrigin = DelStrongCertOrigin<Runtime>;
+            type DelCertOrigin = pallet_duniter_wot::DelStrongCertOrigin<Runtime>;
             type Event = Event;
             type IdtyIndex = IdtyIndex;
             type MaxByIssuer = MaxByIssuer;
-            type OnNewcert =
-                OnNewStrongCertHandler<FirstIssuableOn, Runtime, StrongCert, MIN_STRONG_CERT_FOR_UD, MIN_STRONG_CERT_FOR_STRONG_CERT>;
-            type OnRemovedCert = OnRemovedStrongCertHandler<Runtime, MIN_STRONG_CERT_FOR_UD>;
+            type OnNewcert = DuniterWot;
+            type OnRemovedCert = DuniterWot;
             type CertRenewablePeriod = StrongCertRenewablePeriod;
             type ValidityPeriod = ValidityPeriod;
         }
 
-		// MUNTISIG //
+		// MULTISIG //
 
 		impl pallet_multisig::Config for Runtime {
 			type Event = Event;
diff --git a/runtime/g1/Cargo.toml b/runtime/g1/Cargo.toml
index 53fe0a7647f8fa129bf36310a21f8fdc303e1aec..10bba58dc8a49d3b9366eff5c83a3423916258b6 100644
--- a/runtime/g1/Cargo.toml
+++ b/runtime/g1/Cargo.toml
@@ -36,6 +36,7 @@ std = [
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
+    'pallet-duniter-wot/std',
     'pallet-grandpa/std',
     'pallet-identity/std',
     'pallet-im-online/std',
@@ -58,6 +59,7 @@ std = [
     'sp-core/std',
     'sp-inherents/std',
     'sp-offchain/std',
+    'sp-membership/std',
     'sp-runtime/std',
     'sp-session/std',
     'sp-std/std',
@@ -66,13 +68,15 @@ std = [
 ]
 
 [dependencies]
+common-runtime = { path = "../common", default-features = false }
+common-runtime-except-gdev = { path = "../common-except-gdev", default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
-common-runtime = { path = "../common", default-features = false }
-common-runtime-except-gdev = { path = "../common-except-gdev", default-features = false }
+sp-membership = { path = '../../primitives/membership', default-features = false }
 
 # substrate
 scale-info = { version = "1.0", default-features = false, features = ["derive"] }
diff --git a/runtime/g1/src/lib.rs b/runtime/g1/src/lib.rs
index 8c9a46e1ccae9a80504b7ef3dc8232c15ddc8a01..b5e924e44cb10633e5de872aaf184926e1edd894 100644
--- a/runtime/g1/src/lib.rs
+++ b/runtime/g1/src/lib.rs
@@ -26,12 +26,11 @@ pub mod parameters;
 
 pub use self::parameters::*;
 pub use common_runtime::{
-    constants::*,
-    entities::{IdtyRight, ValidatorFullIdentification},
-    AccountId, Address, Balance, BlockNumber, FullIdentificationOfImpl, Hash, Header, IdtyIndex,
-    IdtyNameValidatorImpl, Index, Signature,
+    constants::*, entities::ValidatorFullIdentification, AccountId, Address, Balance, BlockNumber,
+    FullIdentificationOfImpl, Hash, Header, IdtyIndex, IdtyNameValidatorImpl, Index, Signature,
 };
 pub use pallet_balances::Call as BalancesCall;
+pub use pallet_duniter_wot::IdtyRight;
 pub use pallet_identity::{IdtyStatus, IdtyValue};
 pub use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
 use pallet_session::historical as session_historical;
@@ -42,14 +41,7 @@ pub use pallet_universal_dividend;
 pub use sp_runtime::BuildStorage;
 pub use sp_runtime::{KeyTypeId, Perbill, Permill};
 
-use common_runtime::{
-    authorizations::{AddStrongCertOrigin, DelStrongCertOrigin, EnsureIdtyCallAllowedImpl},
-    handlers::{
-        OnIdtyChangeHandler, OnNewStrongCertHandler, OnRemovedStrongCertHandler,
-        OnRightKeyChangeHandler,
-    },
-    SessionManagerImpl,
-};
+use common_runtime::{handlers::OnRightKeyChangeHandler, SessionManagerImpl};
 use frame_system::EnsureRoot;
 use pallet_grandpa::fg_primitives;
 use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
@@ -143,7 +135,13 @@ pub type Executive = frame_executive::Executive<
 pub struct BaseCallFilter;
 impl frame_support::traits::Contains<Call> for BaseCallFilter {
     fn contains(call: &Call) -> bool {
-        !matches!(call, Call::Membership(_) | Call::Session(_))
+        !matches!(
+            call,
+            Call::Membership(
+                pallet_membership::Call::claim_membership { .. }
+                    | pallet_membership::Call::revoke_membership { .. }
+            ) | Call::Session(_)
+        )
     }
 }
 
@@ -194,9 +192,10 @@ construct_runtime!(
         UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 41,
 
         // Web Of Trust
-        Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 50,
-        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
-        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
+        DuniterWot: pallet_duniter_wot::{Pallet} = 50,
+        Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
+        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53,
 
         // Multisig dispatch.
         Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 60,
diff --git a/runtime/g1/src/parameters.rs b/runtime/g1/src/parameters.rs
index 5e334ce48cf1c1f04afbde88e25d7dba2dc6c7d3..6cfd3ed99e4f013ae5d0a99b5c315f47de002fd3 100644
--- a/runtime/g1/src/parameters.rs
+++ b/runtime/g1/src/parameters.rs
@@ -92,6 +92,12 @@ parameter_types! {
 /* WOT */
 /*******/
 
+parameter_types! {
+    pub MinCertForUdRight: u8 = 5;
+    pub MinCertForCertRight: u8 = 5;
+    pub MinCertForCreateIdtyRight: u8 = 5;
+}
+
 // Identity
 pub const IDTY_CREATE_PERIOD: BlockNumber = 100;
 parameter_types! {
diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml
index 0578b60d7dd22b8195ab74da1ed56bc50b00efde..db07d67d801819144db01ff1dd403cb6603df416 100644
--- a/runtime/gdev/Cargo.toml
+++ b/runtime/gdev/Cargo.toml
@@ -36,6 +36,7 @@ std = [
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
+    'pallet-duniter-wot/std',
     'pallet-identity/std',
     'pallet-membership/std',
     'pallet-grandpa/std',
@@ -54,6 +55,7 @@ std = [
     'sp-core/std',
     'sp-inherents/std',
     'sp-offchain/std',
+    'sp-membership/std',
     'sp-runtime/std',
     'sp-session/std',
     'sp-std/std',
@@ -62,12 +64,14 @@ std = [
 ]
 
 [dependencies]
+common-runtime = { path = "../common", default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
-common-runtime = { path = "../common", default-features = false }
+sp-membership = { path = '../../primitives/membership', default-features = false }
 
 # substrate
 scale-info = { version = "1.0", default-features = false, features = ["derive"] }
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index b394fc9d81d06d532ec2b17e6fca32604fe638e5..468b824821fa760d80008802696f4361854f1262 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -26,10 +26,11 @@ pub mod parameters;
 
 pub use self::parameters::*;
 pub use common_runtime::{
-    constants::*, entities::IdtyRight, AccountId, Address, Balance, BlockNumber, Hash, Header,
-    IdtyIndex, IdtyNameValidatorImpl, Index, Signature,
+    constants::*, AccountId, Address, Balance, BlockNumber, Hash, Header, IdtyIndex,
+    IdtyNameValidatorImpl, Index, Signature,
 };
 pub use pallet_balances::Call as BalancesCall;
+pub use pallet_duniter_wot::IdtyRight;
 pub use pallet_identity::{IdtyStatus, IdtyValue};
 use pallet_transaction_payment::CurrencyAdapter;
 pub use pallet_universal_dividend;
@@ -37,13 +38,7 @@ pub use pallet_universal_dividend;
 pub use sp_runtime::BuildStorage;
 pub use sp_runtime::{Perbill, Permill};
 
-use common_runtime::{
-    authorizations::{AddStrongCertOrigin, DelStrongCertOrigin, EnsureIdtyCallAllowedImpl},
-    handlers::{
-        OnIdtyChangeHandler, OnNewStrongCertHandler, OnRemovedStrongCertHandler,
-        OnRightKeyChangeHandler,
-    },
-};
+use common_runtime::handlers::OnRightKeyChangeHandler;
 use frame_system::EnsureRoot;
 use pallet_grandpa::fg_primitives;
 use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
@@ -135,7 +130,13 @@ pub type Executive = frame_executive::Executive<
 pub struct BaseCallFilter;
 impl frame_support::traits::Contains<Call> for BaseCallFilter {
     fn contains(call: &Call) -> bool {
-        !matches!(call, Call::Membership(_))
+        !matches!(
+            call,
+            Call::Membership(
+                pallet_membership::Call::claim_membership { .. }
+                    | pallet_membership::Call::revoke_membership { .. }
+            )
+        )
     }
 }
 
@@ -175,9 +176,10 @@ construct_runtime!(
         UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 41,
 
         // Web Of Trust
-        Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 50,
-        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
-        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
+        DuniterWot: pallet_duniter_wot::{Pallet} = 50,
+        Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
+        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53,
 
         // Multisig dispatch.
         Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 60,
diff --git a/runtime/gdev/src/parameters.rs b/runtime/gdev/src/parameters.rs
index b6a1697f9c24855547805acb35a0b1ad3bf5607e..b47c41d07cf33c71737527da71e141947e10cc84 100644
--- a/runtime/gdev/src/parameters.rs
+++ b/runtime/gdev/src/parameters.rs
@@ -46,6 +46,13 @@ frame_support::parameter_types! {
     pub const TransactionByteFee: Balance = 0;
 }
 
+// Wot
+parameter_types! {
+    pub MinCertForUdRight: u8 = 2;
+    pub MinCertForCertRight: u8 = 3;
+    pub MinCertForCreateIdtyRight: u8 = 3;
+}
+
 // Identity
 pub const IDTY_CREATE_PERIOD: BlockNumber = 100;
 frame_support::parameter_types! {
@@ -69,7 +76,7 @@ parameter_types! {
     pub const CertPeriod: BlockNumber = 15;
     pub const MaxByIssuer: u8 = 100;
     pub const StrongCertRenewablePeriod: BlockNumber = 50;//6 * MONTHS;
-    pub const ValidityPeriod: BlockNumber = 200;//2 * YEARS;
+    pub const ValidityPeriod: BlockNumber = 2_000;//2 * YEARS;
 }
 
 // Universal dividend
diff --git a/runtime/gtest/Cargo.toml b/runtime/gtest/Cargo.toml
index 3109fb572b38e0ff790ab75ca222143679c22977..307d4537ef32d5f366de6ab5045e35a7c08be7fd 100644
--- a/runtime/gtest/Cargo.toml
+++ b/runtime/gtest/Cargo.toml
@@ -36,6 +36,7 @@ std = [
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
+    'pallet-duniter-wot/std',
     'pallet-grandpa/std',
     'pallet-identity/std',
     'pallet-membership/std',
@@ -58,6 +59,7 @@ std = [
     'sp-core/std',
     'sp-inherents/std',
     'sp-offchain/std',
+    'sp-membership/std',
     'sp-runtime/std',
     'sp-session/std',
     'sp-std/std',
@@ -66,13 +68,15 @@ std = [
 ]
 
 [dependencies]
+common-runtime = { path = "../common", default-features = false }
+common-runtime-except-gdev = { path = "../common-except-gdev", default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
-common-runtime = { path = "../common", default-features = false }
-common-runtime-except-gdev = { path = "../common-except-gdev", default-features = false }
+sp-membership = { path = '../../primitives/membership', default-features = false }
 
 # substrate
 scale-info = { version = "1.0", default-features = false, features = ["derive"] }
diff --git a/runtime/gtest/src/lib.rs b/runtime/gtest/src/lib.rs
index eba0587aa1dfbb00d06a6a2b8080db8695f8f35e..354a96f624321eb8025ffd5180c8620ff09db53b 100644
--- a/runtime/gtest/src/lib.rs
+++ b/runtime/gtest/src/lib.rs
@@ -26,12 +26,11 @@ pub mod parameters;
 
 pub use self::parameters::*;
 pub use common_runtime::{
-    constants::*,
-    entities::{IdtyRight, ValidatorFullIdentification},
-    AccountId, Address, Balance, BlockNumber, FullIdentificationOfImpl, Hash, Header, IdtyIndex,
-    IdtyNameValidatorImpl, Index, Signature,
+    constants::*, entities::ValidatorFullIdentification, AccountId, Address, Balance, BlockNumber,
+    FullIdentificationOfImpl, Hash, Header, IdtyIndex, IdtyNameValidatorImpl, Index, Signature,
 };
 pub use pallet_balances::Call as BalancesCall;
+pub use pallet_duniter_wot::IdtyRight;
 pub use pallet_identity::{IdtyStatus, IdtyValue};
 pub use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
 use pallet_session::historical as session_historical;
@@ -42,14 +41,7 @@ pub use pallet_universal_dividend;
 pub use sp_runtime::BuildStorage;
 pub use sp_runtime::{KeyTypeId, Perbill, Permill};
 
-use common_runtime::{
-    authorizations::{AddStrongCertOrigin, DelStrongCertOrigin, EnsureIdtyCallAllowedImpl},
-    handlers::{
-        OnIdtyChangeHandler, OnNewStrongCertHandler, OnRemovedStrongCertHandler,
-        OnRightKeyChangeHandler,
-    },
-    SessionManagerImpl,
-};
+use common_runtime::{handlers::OnRightKeyChangeHandler, SessionManagerImpl};
 use frame_system::EnsureRoot;
 use pallet_grandpa::fg_primitives;
 use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
@@ -143,7 +135,13 @@ pub type Executive = frame_executive::Executive<
 pub struct BaseCallFilter;
 impl frame_support::traits::Contains<Call> for BaseCallFilter {
     fn contains(call: &Call) -> bool {
-        !matches!(call, Call::Membership(_) | Call::Session(_))
+        !matches!(
+            call,
+            Call::Membership(
+                pallet_membership::Call::claim_membership { .. }
+                    | pallet_membership::Call::revoke_membership { .. }
+            ) | Call::Session(_)
+        )
     }
 }
 
@@ -194,9 +192,10 @@ construct_runtime!(
         UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 41,
 
         // Web Of Trust
-        Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 50,
-        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
-        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
+        DuniterWot: pallet_duniter_wot::{Pallet} = 50,
+        Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
+        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53,
 
         // Multisig dispatch.
         Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 60,
diff --git a/runtime/gtest/src/parameters.rs b/runtime/gtest/src/parameters.rs
index ed4ca96bd7472e4511d8bb33f5350d7758377f65..26eea171d671a0133d68144c443b984bd474c575 100644
--- a/runtime/gtest/src/parameters.rs
+++ b/runtime/gtest/src/parameters.rs
@@ -91,6 +91,12 @@ parameter_types! {
 /* WOT */
 /*******/
 
+parameter_types! {
+    pub MinCertForUdRight: u8 = 5;
+    pub MinCertForCertRight: u8 = 5;
+    pub MinCertForCreateIdtyRight: u8 = 5;
+}
+
 // Identity
 pub const IDTY_CREATE_PERIOD: BlockNumber = 100;
 frame_support::parameter_types! {