From b3f3487d7bce2b1613dceb15afc4a6293c9cbc60 Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Tue, 25 Jan 2022 20:51:27 +0100
Subject: [PATCH] feat(certs): don't ask for idty index anymore

---
 pallets/certification/src/lib.rs     | 180 +++++++++++++++++----------
 pallets/certification/src/mock.rs    |   4 +-
 pallets/certification/src/tests.rs   |  32 ++---
 pallets/certification/src/traits.rs  |  10 ++
 pallets/certification/src/types.rs   |   2 +-
 pallets/duniter-wot/src/lib.rs       |  71 +++++++----
 pallets/duniter-wot/src/mock.rs      |   6 +-
 pallets/duniter-wot/src/tests.rs     |  12 +-
 pallets/duniter-wot/src/types.rs     |  77 +-----------
 pallets/identity/src/lib.rs          |   6 +
 pallets/membership/src/lib.rs        |   1 +
 runtime/common/src/pallets_config.rs |   8 +-
 runtime/gdev/src/lib.rs              |  92 +++++++-------
 13 files changed, 257 insertions(+), 244 deletions(-)

diff --git a/pallets/certification/src/lib.rs b/pallets/certification/src/lib.rs
index 82571189f..a1d6063bb 100644
--- a/pallets/certification/src/lib.rs
+++ b/pallets/certification/src/lib.rs
@@ -39,7 +39,7 @@ pub mod pallet {
     use super::*;
     use frame_support::pallet_prelude::*;
     use frame_system::pallet_prelude::*;
-    use sp_runtime::traits::Saturating;
+    use sp_runtime::traits::{Convert, Saturating};
     use sp_std::collections::btree_map::BTreeMap;
 
     /// The current storage version.
@@ -52,13 +52,9 @@ pub mod pallet {
 
     #[pallet::config]
     pub trait Config<I: 'static = ()>: frame_system::Config {
-        /// Origin allowed to add a certification
-        type AddCertOrigin: EnsureOrigin<(Self::Origin, Self::IdtyIndex, Self::IdtyIndex)>;
         #[pallet::constant]
         /// Minimum duration between two certifications issued by the same issuer
         type CertPeriod: Get<Self::BlockNumber>;
-        /// Origin allowed to delete a certification
-        type DelCertOrigin: EnsureOrigin<(Self::Origin, Self::IdtyIndex, Self::IdtyIndex)>;
         /// Because this pallet emits events, it depends on the runtime's definition of an event.
         type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;
         /// A short identity index.
@@ -71,6 +67,10 @@ pub mod pallet {
             + MaybeSerializeDeserialize
             + Debug
             + MaxEncodedLen;
+        /// Something that give the IdtyIndex on an account id
+        type IdtyIndexOf: Convert<Self::AccountId, Option<Self::IdtyIndex>>;
+        ///
+        type IsCertAllowed: IsCertAllowed<Self::IdtyIndex>;
         #[pallet::constant]
         /// Maximum number of active certifications by issuer
         type MaxByIssuer: Get<u32>;
@@ -199,7 +199,7 @@ pub mod pallet {
     #[pallet::storage]
     #[pallet::getter(fn idty_cert_meta)]
     pub type StorageIdtyCertMeta<T: Config<I>, I: 'static = ()> =
-        StorageMap<_, Twox64Concat, T::IdtyIndex, IdtyCertMeta<T::BlockNumber>, OptionQuery>;
+        StorageMap<_, Twox64Concat, T::IdtyIndex, IdtyCertMeta<T::BlockNumber>, ValueQuery>;
 
     /// Certifications by issuer
     #[pallet::storage]
@@ -259,10 +259,16 @@ pub mod pallet {
 
     #[pallet::error]
     pub enum Error<T, I = ()> {
+        /// Certification non autorisée
+        CertNotAllowed,
+        /// Issuer not found
+        IssuerNotFound,
         /// An identity must receive certifications before it can issue them.
         IdtyMustReceiveCertsBeforeCanIssue,
         /// This identity has already issued the maximum number of certifications
         IssuedTooManyCert,
+        /// Receiver not found
+        ReceiverNotFound,
         /// Not enough certifications received
         NotEnoughCertReceived,
         /// This certification has already been issued or renewed recently
@@ -283,26 +289,22 @@ pub mod pallet {
     #[pallet::call]
     impl<T: Config<I>, I: 'static> Pallet<T, I> {
         #[pallet::weight(0)]
-        pub fn add_cert(
+        pub fn force_add_cert(
             origin: OriginFor<T>,
             issuer: T::IdtyIndex,
             receiver: T::IdtyIndex,
+            verify_rules: bool,
         ) -> DispatchResultWithPostInfo {
-            T::AddCertOrigin::ensure_origin((origin, issuer, receiver))?;
-            frame_support::runtime_print!("add_cert({:?}, {:?}): origin OK", issuer, receiver);
+            ensure_root(origin)?;
 
             let block_number = frame_system::pallet::Pallet::<T>::block_number();
 
-            let (create, issuer_issued_count) = if let Ok(mut issuer_idty_cert_meta) =
-                <StorageIdtyCertMeta<T, I>>::try_get(issuer)
-            {
+            let create = if verify_rules {
+                let issuer_idty_cert_meta = <StorageIdtyCertMeta<T, I>>::get(issuer);
+                if issuer_idty_cert_meta.received_count == 0 {
+                    return Err(Error::<T, I>::IdtyMustReceiveCertsBeforeCanIssue.into());
+                }
                 // Verify rules CertPeriod and MaxByIssuer
-                frame_support::runtime_print!(
-                    "add_cert({:?}, {:?}): Verify rules CertPeriod and MaxByIssuer",
-                    issuer,
-                    receiver
-                );
-
                 if issuer_idty_cert_meta.received_count
                     < T::MinReceivedCertToBeAbleToIssueCert::get()
                 {
@@ -314,12 +316,7 @@ pub mod pallet {
                 }
 
                 // Verify rule CertRenewablePeriod
-                frame_support::runtime_print!(
-                    "add_cert({:?}, {:?}): Verify rule CertRenewablePeriod",
-                    issuer,
-                    receiver
-                );
-                let create = if let Ok(CertValue { renewable_on, .. }) =
+                if let Ok(CertValue { renewable_on, .. }) =
                     <StorageCertsByIssuer<T, I>>::try_get(issuer, receiver)
                 {
                     if renewable_on > block_number {
@@ -328,27 +325,102 @@ pub mod pallet {
                     false
                 } else {
                     true
-                };
+                }
+            } else {
+                !StorageCertsByIssuer::<T, I>::contains_key(issuer, receiver)
+            };
 
-                // Write StorageIdtyCertMeta for issuer
-                issuer_idty_cert_meta.issued_count =
-                    issuer_idty_cert_meta.issued_count.saturating_add(1);
-                let issuer_issued_count = issuer_idty_cert_meta.issued_count;
-                issuer_idty_cert_meta.next_issuable_on = block_number + T::CertPeriod::get();
-                <StorageIdtyCertMeta<T, I>>::insert(issuer, issuer_idty_cert_meta);
+            Self::do_add_cert(block_number, create, issuer, receiver)
+        }
+        #[pallet::weight(0)]
+        pub fn add_cert(
+            origin: OriginFor<T>,
+            receiver: T::AccountId,
+        ) -> DispatchResultWithPostInfo {
+            let who = ensure_signed(origin)?;
+            let issuer = T::IdtyIndexOf::convert(who).ok_or(Error::<T, I>::IssuerNotFound)?;
+            let receiver =
+                T::IdtyIndexOf::convert(receiver).ok_or(Error::<T, I>::ReceiverNotFound)?;
+            if !T::IsCertAllowed::is_cert_allowed(issuer, receiver) {
+                return Err(Error::<T, I>::CertNotAllowed.into());
+            }
 
-                (create, issuer_issued_count)
-            } else {
-                // An identity must receive certifications before it can issue them.
+            let issuer_idty_cert_meta = <StorageIdtyCertMeta<T, I>>::get(issuer);
+            if issuer_idty_cert_meta.received_count == 0 {
                 return Err(Error::<T, I>::IdtyMustReceiveCertsBeforeCanIssue.into());
+            }
+
+            let block_number = frame_system::pallet::Pallet::<T>::block_number();
+
+            // Verify rules CertPeriod and MaxByIssuer
+            if issuer_idty_cert_meta.received_count < T::MinReceivedCertToBeAbleToIssueCert::get() {
+                return Err(Error::<T, I>::NotEnoughCertReceived.into());
+            } else if issuer_idty_cert_meta.next_issuable_on > block_number {
+                return Err(Error::<T, I>::NotRespectCertPeriod.into());
+            } else if issuer_idty_cert_meta.issued_count >= T::MaxByIssuer::get() {
+                return Err(Error::<T, I>::IssuedTooManyCert.into());
+            }
+
+            // Verify rule CertRenewablePeriod
+            let create = if let Ok(CertValue { renewable_on, .. }) =
+                <StorageCertsByIssuer<T, I>>::try_get(issuer, receiver)
+            {
+                if renewable_on > block_number {
+                    return Err(Error::<T, I>::NotRespectRenewablePeriod.into());
+                }
+                false
+            } else {
+                true
             };
 
+            Self::do_add_cert(block_number, create, issuer, receiver)
+        }
+
+        #[pallet::weight(0)]
+        pub fn del_cert(
+            origin: OriginFor<T>,
+            issuer: T::IdtyIndex,
+            receiver: T::IdtyIndex,
+        ) -> DispatchResultWithPostInfo {
+            ensure_root(origin)?;
+            Self::remove_cert_inner(issuer, receiver, None);
+            Ok(().into())
+        }
+
+        #[pallet::weight(0)]
+        pub fn remove_all_certs_received_by(
+            origin: OriginFor<T>,
+            idty_index: T::IdtyIndex,
+        ) -> DispatchResultWithPostInfo {
+            ensure_root(origin)?;
+            if let Ok(issuers) = <StorageCertsByReceiver<T, I>>::try_get(idty_index) {
+                for issuer in issuers {
+                    Self::remove_cert_inner(issuer, idty_index, None);
+                }
+            }
+            Ok(().into())
+        }
+    }
+
+    // INTERNAL FUNCTIONS //
+
+    impl<T: Config<I>, I: 'static> Pallet<T, I> {
+        fn do_add_cert(
+            block_number: T::BlockNumber,
+            create: bool,
+            issuer: T::IdtyIndex,
+            receiver: T::IdtyIndex,
+        ) -> DispatchResultWithPostInfo {
+            // Write StorageIdtyCertMeta for issuer
+            let issuer_issued_count =
+                StorageIdtyCertMeta::<T, I>::mutate(issuer, |issuer_idty_cert_meta| {
+                    issuer_idty_cert_meta.issued_count =
+                        issuer_idty_cert_meta.issued_count.saturating_add(1);
+                    issuer_idty_cert_meta.next_issuable_on = block_number + T::CertPeriod::get();
+                    issuer_idty_cert_meta.issued_count
+                });
+
             // Write StorageIdtyCertMeta for receiver
-            frame_support::runtime_print!(
-                "add_cert({:?}, {:?}): Write StorageIdtyCertMeta for receiver",
-                issuer,
-                receiver
-            );
             let receiver_received_count =
                 <StorageIdtyCertMeta<T, I>>::mutate_exists(receiver, |cert_meta_opt| {
                     let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default());
@@ -390,36 +462,6 @@ pub mod pallet {
 
             Ok(().into())
         }
-
-        #[pallet::weight(0)]
-        pub fn del_cert(
-            origin: OriginFor<T>,
-            issuer: T::IdtyIndex,
-            receiver: T::IdtyIndex,
-        ) -> DispatchResultWithPostInfo {
-            T::DelCertOrigin::ensure_origin((origin, issuer, receiver))?;
-            Self::remove_cert_inner(issuer, receiver, None);
-            Ok(().into())
-        }
-
-        #[pallet::weight(0)]
-        pub fn remove_all_certs_received_by(
-            origin: OriginFor<T>,
-            idty_index: T::IdtyIndex,
-        ) -> DispatchResultWithPostInfo {
-            ensure_root(origin)?;
-            if let Ok(issuers) = <StorageCertsByReceiver<T, I>>::try_get(idty_index) {
-                for issuer in issuers {
-                    Self::remove_cert_inner(issuer, idty_index, None);
-                }
-            }
-            Ok(().into())
-        }
-    }
-
-    // INTERNAL FUNCTIONS //
-
-    impl<T: Config<I>, I: 'static> Pallet<T, I> {
         fn prune_certifications(block_number: T::BlockNumber) -> Weight {
             let mut total_weight: Weight = 0;
 
diff --git a/pallets/certification/src/mock.rs b/pallets/certification/src/mock.rs
index 53cd1347a..b33804637 100644
--- a/pallets/certification/src/mock.rs
+++ b/pallets/certification/src/mock.rs
@@ -100,11 +100,11 @@ parameter_types! {
 }
 
 impl pallet_certification::Config for Test {
-    type AddCertOrigin = EnsureRoot;
     type CertPeriod = CertPeriod;
-    type DelCertOrigin = EnsureRoot;
     type Event = Event;
     type IdtyIndex = IdtyIndex;
+    type IdtyIndexOf = sp_runtime::traits::ConvertInto;
+    type IsCertAllowed = ();
     type MaxByIssuer = MaxByIssuer;
     type MinReceivedCertToBeAbleToIssueCert = MinReceivedCertToBeAbleToIssueCert;
     type OnNewcert = ();
diff --git a/pallets/certification/src/tests.rs b/pallets/certification/src/tests.rs
index 030a6d6d3..25b32f01b 100644
--- a/pallets/certification/src/tests.rs
+++ b/pallets/certification/src/tests.rs
@@ -30,7 +30,7 @@ fn test_must_receive_cert_before_can_issue() {
     })
     .execute_with(|| {
         assert_eq!(
-            DefaultCertification::add_cert(Origin::root(), 0, 1),
+            DefaultCertification::add_cert(Origin::signed(0), 1),
             Err(Error::<Test, _>::IdtyMustReceiveCertsBeforeCanIssue.into())
         );
     });
@@ -60,29 +60,29 @@ fn test_genesis_build() {
         // Verify state of idty 0
         assert_eq!(
             DefaultCertification::idty_cert_meta(0),
-            Some(crate::IdtyCertMeta {
+            crate::IdtyCertMeta {
                 issued_count: 2,
                 next_issuable_on: 2,
                 received_count: 2,
-            })
+            }
         );
         // Verify state of idty 1
         assert_eq!(
             DefaultCertification::idty_cert_meta(1),
-            Some(crate::IdtyCertMeta {
+            crate::IdtyCertMeta {
                 issued_count: 2,
                 next_issuable_on: 0,
                 received_count: 2,
-            })
+            }
         );
         // Verify state of idty 2
         assert_eq!(
             DefaultCertification::idty_cert_meta(2),
-            Some(crate::IdtyCertMeta {
+            crate::IdtyCertMeta {
                 issued_count: 2,
                 next_issuable_on: 1,
                 received_count: 2,
-            })
+            }
         );
         // Cert 2->1 must be removable at block #3
         assert_eq!(
@@ -91,7 +91,7 @@ fn test_genesis_build() {
         );
         // Cert 2->0 cannot be renewed before #5
         assert_eq!(
-            DefaultCertification::add_cert(Origin::root(), 2, 0),
+            DefaultCertification::add_cert(Origin::signed(2), 0),
             Err(Error::<Test, _>::NotRespectRenewablePeriod.into())
         );
 
@@ -122,18 +122,18 @@ fn test_cert_period() {
     })
     .execute_with(|| {
         assert_eq!(
-            DefaultCertification::add_cert(Origin::root(), 0, 2),
+            DefaultCertification::add_cert(Origin::signed(0), 2),
             Err(Error::<Test, _>::NotRespectCertPeriod.into())
         );
         run_to_block(CertPeriod::get());
-        assert_ok!(DefaultCertification::add_cert(Origin::root(), 0, 2));
+        assert_ok!(DefaultCertification::add_cert(Origin::signed(0), 2));
         run_to_block(CertPeriod::get() + 1);
         assert_eq!(
-            DefaultCertification::add_cert(Origin::root(), 0, 3),
+            DefaultCertification::add_cert(Origin::signed(0), 3),
             Err(Error::<Test, _>::NotRespectCertPeriod.into())
         );
         run_to_block((2 * CertPeriod::get()) + 1);
-        assert_ok!(DefaultCertification::add_cert(Origin::root(), 0, 3));
+        assert_ok!(DefaultCertification::add_cert(Origin::signed(0), 3));
     });
 }
 
@@ -150,17 +150,17 @@ fn test_renewable_period() {
     .execute_with(|| {
         run_to_block(CertPeriod::get());
         assert_eq!(
-            DefaultCertification::add_cert(Origin::root(), 0, 1),
+            DefaultCertification::add_cert(Origin::signed(0), 1),
             Err(Error::<Test, _>::NotRespectRenewablePeriod.into())
         );
         run_to_block(RenewablePeriod::get());
-        assert_ok!(DefaultCertification::add_cert(Origin::root(), 0, 1));
+        assert_ok!(DefaultCertification::add_cert(Origin::signed(0), 1));
         run_to_block(RenewablePeriod::get() + CertPeriod::get());
         assert_eq!(
-            DefaultCertification::add_cert(Origin::root(), 0, 1),
+            DefaultCertification::add_cert(Origin::signed(0), 1),
             Err(Error::<Test, _>::NotRespectRenewablePeriod.into())
         );
         run_to_block((2 * RenewablePeriod::get()) + 1);
-        assert_ok!(DefaultCertification::add_cert(Origin::root(), 0, 1));
+        assert_ok!(DefaultCertification::add_cert(Origin::signed(0), 1));
     });
 }
diff --git a/pallets/certification/src/traits.rs b/pallets/certification/src/traits.rs
index cde9ade86..ebcd7aef4 100644
--- a/pallets/certification/src/traits.rs
+++ b/pallets/certification/src/traits.rs
@@ -14,6 +14,16 @@
 // 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 IsCertAllowed<IdtyIndex> {
+    fn is_cert_allowed(issuer: IdtyIndex, receiver: IdtyIndex) -> bool;
+}
+
+impl<IdtyIndex> IsCertAllowed<IdtyIndex> for () {
+    fn is_cert_allowed(_issuer: IdtyIndex, _receiver: IdtyIndex) -> bool {
+        true
+    }
+}
+
 pub trait OnNewcert<IdtyIndex> {
     fn on_new_cert(
         issuer: IdtyIndex,
diff --git a/pallets/certification/src/types.rs b/pallets/certification/src/types.rs
index daf5d954f..d1b858f9f 100644
--- a/pallets/certification/src/types.rs
+++ b/pallets/certification/src/types.rs
@@ -27,7 +27,7 @@ pub struct CertValue<BlockNumber> {
 }
 
 #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
-pub struct IdtyCertMeta<BlockNumber> {
+pub struct IdtyCertMeta<BlockNumber: Default> {
     pub issued_count: u32,
     pub next_issuable_on: BlockNumber,
     pub received_count: u32,
diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs
index f74ff0d0b..b2e70823f 100644
--- a/pallets/duniter-wot/src/lib.rs
+++ b/pallets/duniter-wot/src/lib.rs
@@ -131,13 +131,10 @@ where
         + pallet_membership::Config<I, MetaData = MembershipMetaData<AccountId>>,
 {
     fn can_create_identity(creator: IdtyIndex) -> bool {
-        if let Some(cert_meta) = pallet_certification::Pallet::<T, I>::idty_cert_meta(creator) {
-            cert_meta.received_count >= T::MinCertForCreateIdtyRight::get()
-                && cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number()
-                && cert_meta.issued_count < T::MaxByIssuer::get()
-        } else {
-            false
-        }
+        let cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(creator);
+        cert_meta.received_count >= T::MinCertForCreateIdtyRight::get()
+            && cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number()
+            && cert_meta.issued_count < T::MaxByIssuer::get()
     }
     fn can_confirm_identity(idty_index: IdtyIndex, owner_key: AccountId) -> bool {
         pallet_membership::Pallet::<T, I>::request_membership(
@@ -156,6 +153,39 @@ where
     }
 }
 
+impl<T: Config<I>, I: 'static> pallet_certification::traits::IsCertAllowed<IdtyIndex>
+    for Pallet<T, I>
+{
+    fn is_cert_allowed(issuer: IdtyIndex, receiver: IdtyIndex) -> bool {
+        if let Some(issuer_data) = pallet_identity::Pallet::<T>::identity(issuer) {
+            if issuer_data.status != IdtyStatus::Validated {
+                return false;
+            }
+            if let Some(receiver_data) = pallet_identity::Pallet::<T>::identity(receiver) {
+                match receiver_data.status {
+                    IdtyStatus::ConfirmedByOwner => true,
+                    IdtyStatus::Created => false,
+                    IdtyStatus::Disabled => {
+                        pallet_membership::Pallet::<T, I>::is_in_pending_memberships(receiver)
+                    }
+                    IdtyStatus::Validated => {
+                        pallet_membership::Pallet::<T, I>::is_member(&receiver)
+                            || pallet_membership::Pallet::<T, I>::is_in_pending_memberships(
+                                receiver,
+                            )
+                    }
+                }
+            } else {
+                // Receiver not found
+                false
+            }
+        } else {
+            // Issuer not found
+            false
+        }
+    }
+}
+
 impl<T: Config<I>, I: 'static> sp_membership::traits::IsIdtyAllowedToRenewMembership<IdtyIndex>
     for Pallet<T, I>
 {
@@ -207,20 +237,18 @@ where
             }
             sp_membership::Event::<IdtyIndex, MetaData>::MembershipRenewed(_) => {}
             sp_membership::Event::<IdtyIndex, MetaData>::MembershipRequested(idty_index) => {
-                if let Some(idty_cert_meta) =
-                    pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index)
-                {
-                    let received_count = idty_cert_meta.received_count;
+                let idty_cert_meta =
+                    pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index);
+                let received_count = idty_cert_meta.received_count;
 
-                    // TODO insert `receiver` in distance queue if received_count >= MinCertForMembership
-                    if received_count >= T::MinCertForMembership::get() as u32 {
-                        // TODO insert `receiver` in distance queue
-                        if Self::dispath_idty_call(pallet_identity::Call::validate_identity {
-                            idty_index: *idty_index,
-                        }) && received_count == T::MinReceivedCertToBeAbleToIssueCert::get()
-                        {
-                            Self::do_apply_first_issuable_on(*idty_index);
-                        }
+                // TODO insert `receiver` in distance queue if received_count >= MinCertForMembership
+                if received_count >= T::MinCertForMembership::get() as u32 {
+                    // TODO insert `receiver` in distance queue
+                    if Self::dispath_idty_call(pallet_identity::Call::validate_identity {
+                        idty_index: *idty_index,
+                    }) && received_count == T::MinReceivedCertToBeAbleToIssueCert::get()
+                    {
+                        Self::do_apply_first_issuable_on(*idty_index);
                     }
                 }
             }
@@ -239,10 +267,11 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall
     fn on_idty_change(idty_index: IdtyIndex, idty_event: IdtyEvent<T>) -> Weight {
         match idty_event {
             IdtyEvent::Created { creator } => {
-                if let Err(e) = <pallet_certification::Pallet<T, I>>::add_cert(
+                if let Err(e) = <pallet_certification::Pallet<T, I>>::force_add_cert(
                     frame_system::Origin::<T>::Root.into(),
                     creator,
                     idty_index,
+                    true,
                 ) {
                     sp_std::if_std! {
                         println!("{:?}", e)
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
index 8534b70dc..e0683621f 100644
--- a/pallets/duniter-wot/src/mock.rs
+++ b/pallets/duniter-wot/src/mock.rs
@@ -148,18 +148,18 @@ impl pallet_membership::Config<Instance1> for Test {
 // Cert
 parameter_types! {
     pub const MaxByIssuer: u8 = 8;
-    pub const MinReceivedCertToBeAbleToIssueCert: u32 = 3;
+    pub const MinReceivedCertToBeAbleToIssueCert: u32 = 2;
     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::AddCertOrigin<Test, Instance1>;
     type CertPeriod = CertPeriod;
-    type DelCertOrigin = pallet_duniter_wot::DelCertOrigin<Test, Instance1>;
     type Event = Event;
     type IdtyIndex = IdtyIndex;
+    type IdtyIndexOf = Identity;
+    type IsCertAllowed = DuniterWot;
     type MaxByIssuer = MaxByIssuer;
     type MinReceivedCertToBeAbleToIssueCert = MinReceivedCertToBeAbleToIssueCert;
     type OnNewcert = DuniterWot;
diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs
index 8176a1e17..8d420ccee 100644
--- a/pallets/duniter-wot/src/tests.rs
+++ b/pallets/duniter-wot/src/tests.rs
@@ -19,7 +19,6 @@ use crate::mock::*;
 use crate::WotDiff;
 use frame_support::assert_err;
 use frame_support::assert_ok;
-use frame_support::error::BadOrigin;
 use frame_support::instances::Instance1;
 use frame_system::{EventRecord, Phase};
 use pallet_identity::{IdtyName, IdtyStatus};
@@ -32,9 +31,7 @@ fn test_genesis_build() {
         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,
+            pallet_certification::Pallet::<Test, Instance1>::idty_cert_meta(1).next_issuable_on,
             2
         );
     });
@@ -110,7 +107,7 @@ fn test_new_idty_validation() {
 
         // Bob should be able to certify Ferdie
         run_to_block(4);
-        assert_ok!(Cert::add_cert(Origin::signed(2), 2, 6));
+        assert_ok!(Cert::add_cert(Origin::signed(2), 6));
 
         let events = System::events();
         // 3 events should have occurred: NewCert, MembershipAcquired and IdtyValidated
@@ -229,7 +226,10 @@ fn test_idty_membership_expire_them_requested() {
         assert_eq!(Identity::identity(3).unwrap().status, IdtyStatus::Disabled);
 
         // Alice can't renew it's cert to Charlie
-        assert_err!(Cert::add_cert(Origin::signed(1), 1, 3), BadOrigin);
+        assert_err!(
+            Cert::add_cert(Origin::signed(1), 3),
+            pallet_certification::Error::<Test, Instance1>::CertNotAllowed
+        );
 
         // Charlie should be able to request membership
         run_to_block(6);
diff --git a/pallets/duniter-wot/src/types.rs b/pallets/duniter-wot/src/types.rs
index 639eda216..c70663fb2 100644
--- a/pallets/duniter-wot/src/types.rs
+++ b/pallets/duniter-wot/src/types.rs
@@ -14,83 +14,8 @@
 // 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::{Config, IdtyIndex};
+use crate::IdtyIndex;
 use frame_support::pallet_prelude::*;
-use pallet_identity::IdtyStatus;
-use sp_membership::traits::IsInPendingMemberships;
-use sp_runtime::traits::IsMember;
-
-pub struct AddCertOrigin<T, I>(core::marker::PhantomData<(T, I)>);
-impl<T: Config<I>, I: 'static> EnsureOrigin<(T::Origin, IdtyIndex, IdtyIndex)>
-    for AddCertOrigin<T, I>
-{
-    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(idty_index) = pallet_identity::Pallet::<T>::identity_index_of(who) {
-                    if o.1 == idty_index {
-                        if let Some(receiver) = pallet_identity::Pallet::<T>::identity(o.2) {
-                            match receiver.status {
-                                IdtyStatus::ConfirmedByOwner => Ok(()),
-                                IdtyStatus::Created => Err(o),
-                                IdtyStatus::Disabled => {
-                                    if pallet_membership::Pallet::<T, I>::is_in_pending_memberships(o.2)
-                                    {
-                                        Ok(())
-                                    } else {
-                                        Err(o)
-                                    }
-                                }
-                                IdtyStatus::Validated => {
-                                    if pallet_membership::Pallet::<T, I>::is_member(&o.2)
-                                        || pallet_membership::Pallet::<T, I>::is_in_pending_memberships(
-                                            o.2,
-                                        )
-                                    {
-                                        Ok(())
-                                    } else {
-                                        Err(o)
-                                    }
-                                }
-                            }
-                        } else {
-                            // Receiver not found
-                            Err(o)
-                        }
-                    } else {
-                        // Bad key
-                        Err(o)
-                    }
-                } else {
-                    // Issuer not found
-                    Err(o)
-                }
-            }
-            _ => Err(o),
-        }
-    }
-}
-
-pub struct DelCertOrigin<T, I>(core::marker::PhantomData<(T, I)>);
-impl<T: Config<I>, I: 'static> EnsureOrigin<(T::Origin, IdtyIndex, IdtyIndex)>
-    for DelCertOrigin<T, I>
-{
-    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),
-        }
-    }
-}
 
 #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)]
 pub struct MembershipMetaData<AccountId>(pub AccountId);
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index 34e80c90c..9e3b7f54b 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -229,6 +229,10 @@ pub mod pallet {
             let creator_idty_val =
                 Identities::<T>::try_get(&creator).map_err(|_| Error::<T>::IdtyNotFound)?;
 
+            if IdentityIndexOf::<T>::contains_key(&owner_key) {
+                return Err(Error::<T>::IdtyAlreadyCreated.into());
+            }
+
             if !T::EnsureIdtyCallAllowed::can_create_identity(creator) {
                 return Err(Error::<T>::CreatorNotAllowedToCreateIdty.into());
             }
@@ -418,6 +422,8 @@ pub mod pallet {
         CreatorNotAllowedToCreateIdty,
         /// Identity already confirmed
         IdtyAlreadyConfirmed,
+        /// Identity already created
+        IdtyAlreadyCreated,
         /// Identity already validated
         IdtyAlreadyValidated,
         /// You are not allowed to create a new identity now
diff --git a/pallets/membership/src/lib.rs b/pallets/membership/src/lib.rs
index 69b98c6f3..ee6b19d28 100644
--- a/pallets/membership/src/lib.rs
+++ b/pallets/membership/src/lib.rs
@@ -67,6 +67,7 @@ pub mod pallet {
         type ExternalizeMembershipStorage: Get<bool>;
         /// Something that identifies an identity
         type IdtyId: Copy + MaybeSerializeDeserialize + Parameter + Ord;
+        /// Something that give the IdtyId on an account id
         type IdtyIdOf: Convert<Self::AccountId, Option<Self::IdtyId>>;
         /// Optional metadata
         type MetaData: Parameter + Validate<Self::AccountId>;
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index 4bf4251a0..53a3ff52b 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -312,11 +312,11 @@ macro_rules! pallets_config {
 		}
 
 		impl pallet_certification::Config<Instance1> for Runtime {
-			type AddCertOrigin = pallet_duniter_wot::AddCertOrigin<Runtime, Instance1>;
 			type CertPeriod = CertPeriod;
-			type DelCertOrigin = pallet_duniter_wot::DelCertOrigin<Runtime, Instance1>;
 			type Event = Event;
 			type IdtyIndex = IdtyIndex;
+			type IdtyIndexOf = Identity;
+			type IsCertAllowed = Wot;
 			type MaxByIssuer = MaxByIssuer;
 			type MinReceivedCertToBeAbleToIssueCert = MinReceivedCertToBeAbleToIssueCert;
 			type OnNewcert = Wot;
@@ -352,11 +352,11 @@ macro_rules! pallets_config {
 		}
 
 		impl pallet_certification::Config<Instance2> for Runtime {
-			type AddCertOrigin = pallet_duniter_wot::AddCertOrigin<Runtime, Instance2>;
 			type CertPeriod = SmithCertPeriod;
-			type DelCertOrigin = pallet_duniter_wot::DelCertOrigin<Runtime, Instance2>;
 			type Event = Event;
 			type IdtyIndex = IdtyIndex;
+			type IdtyIndexOf = Identity;
+			type IsCertAllowed = SmithsSubWot;
 			type MaxByIssuer = SmithMaxByIssuer;
 			type MinReceivedCertToBeAbleToIssueCert = SmithMinReceivedCertToBeAbleToIssueCert;
 			type OnNewcert = SmithsSubWot;
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index 9532d549f..e1c00d78c 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -138,53 +138,53 @@ impl frame_support::traits::Contains<Call> for BaseCallFilter {
 
 // Configure FRAME pallets to include in runtime.
 common_runtime::pallets_config! {
-// Dynamic parameters
-pub type EpochDuration = pallet_duniter_test_parameters::BabeEpochDuration<Runtime>;
-pub type CertPeriod = pallet_duniter_test_parameters::CertPeriod<Runtime>;
-pub type MaxByIssuer = pallet_duniter_test_parameters::CertMaxByIssuer<Runtime>;
-pub type MinReceivedCertToBeAbleToIssueCert =
-    pallet_duniter_test_parameters::CertMinReceivedCertToIssueCert<Runtime>;
-pub type CertRenewablePeriod = pallet_duniter_test_parameters::CertRenewablePeriod<Runtime>;
-pub type ValidityPeriod = pallet_duniter_test_parameters::CertValidityPeriod<Runtime>;
-pub type ConfirmPeriod = pallet_duniter_test_parameters::IdtyConfirmPeriod<Runtime>;
-pub type IdtyCreationPeriod = pallet_duniter_test_parameters::IdtyCreationPeriod<Runtime>;
-pub type MaxDisabledPeriod = pallet_duniter_test_parameters::IdtyMaxDisabledPeriod<Runtime>;
-pub type MembershipPeriod = pallet_duniter_test_parameters::MembershipPeriod<Runtime>;
-pub type RenewablePeriod = pallet_duniter_test_parameters::MembershipRenewablePeriod<Runtime>;
-pub type PendingMembershipPeriod = pallet_duniter_test_parameters::PendingMembershipPeriod<Runtime>;
-pub type UdCreationPeriod = pallet_duniter_test_parameters::UdCreationPeriod<Runtime>;
-pub type UdFirstReeval = pallet_duniter_test_parameters::UdFirstReeval<Runtime>;
-pub type UdReevalPeriod = pallet_duniter_test_parameters::UdReevalPeriod<Runtime>;
-pub type UdReevalPeriodInBlocks = pallet_duniter_test_parameters::UdReevalPeriodInBlocks<Runtime>;
-pub type WotFirstCertIssuableOn = pallet_duniter_test_parameters::WotFirstCertIssuableOn<Runtime>;
-pub type WotMinCertForMembership = pallet_duniter_test_parameters::WotMinCertForMembership<Runtime>;
-pub type WotMinCertForCreateIdtyRight =
-    pallet_duniter_test_parameters::WotMinCertForCreateIdtyRight<Runtime>;
-pub type SmithCertPeriod = pallet_duniter_test_parameters::SmithCertPeriod<Runtime>;
-pub type SmithMaxByIssuer = pallet_duniter_test_parameters::SmithCertMaxByIssuer<Runtime>;
-pub type SmithMinReceivedCertToBeAbleToIssueCert =
-    pallet_duniter_test_parameters::SmithCertMinReceivedCertToIssueCert<Runtime>;
-pub type SmithCertRenewablePeriod =
-    pallet_duniter_test_parameters::SmithCertRenewablePeriod<Runtime>;
-pub type SmithValidityPeriod = pallet_duniter_test_parameters::SmithCertValidityPeriod<Runtime>;
-pub type SmithMembershipPeriod = pallet_duniter_test_parameters::SmithMembershipPeriod<Runtime>;
-pub type SmithPendingMembershipPeriod =
-    pallet_duniter_test_parameters::SmithPendingMembershipPeriod<Runtime>;
-pub type SmithRenewablePeriod =
-    pallet_duniter_test_parameters::SmithMembershipRenewablePeriod<Runtime>;
-pub type SmithsWotFirstCertIssuableOn =
-    pallet_duniter_test_parameters::SmithsWotFirstCertIssuableOn<Runtime>;
-pub type SmithsWotMinCertForMembership =
-    pallet_duniter_test_parameters::SmithsWotMinCertForMembership<Runtime>;
+    // Dynamic parameters
+    pub type EpochDuration = pallet_duniter_test_parameters::BabeEpochDuration<Runtime>;
+    pub type CertPeriod = pallet_duniter_test_parameters::CertPeriod<Runtime>;
+    pub type MaxByIssuer = pallet_duniter_test_parameters::CertMaxByIssuer<Runtime>;
+    pub type MinReceivedCertToBeAbleToIssueCert =
+        pallet_duniter_test_parameters::CertMinReceivedCertToIssueCert<Runtime>;
+    pub type CertRenewablePeriod = pallet_duniter_test_parameters::CertRenewablePeriod<Runtime>;
+    pub type ValidityPeriod = pallet_duniter_test_parameters::CertValidityPeriod<Runtime>;
+    pub type ConfirmPeriod = pallet_duniter_test_parameters::IdtyConfirmPeriod<Runtime>;
+    pub type IdtyCreationPeriod = pallet_duniter_test_parameters::IdtyCreationPeriod<Runtime>;
+    pub type MaxDisabledPeriod = pallet_duniter_test_parameters::IdtyMaxDisabledPeriod<Runtime>;
+    pub type MembershipPeriod = pallet_duniter_test_parameters::MembershipPeriod<Runtime>;
+    pub type RenewablePeriod = pallet_duniter_test_parameters::MembershipRenewablePeriod<Runtime>;
+    pub type PendingMembershipPeriod = pallet_duniter_test_parameters::PendingMembershipPeriod<Runtime>;
+    pub type UdCreationPeriod = pallet_duniter_test_parameters::UdCreationPeriod<Runtime>;
+    pub type UdFirstReeval = pallet_duniter_test_parameters::UdFirstReeval<Runtime>;
+    pub type UdReevalPeriod = pallet_duniter_test_parameters::UdReevalPeriod<Runtime>;
+    pub type UdReevalPeriodInBlocks = pallet_duniter_test_parameters::UdReevalPeriodInBlocks<Runtime>;
+    pub type WotFirstCertIssuableOn = pallet_duniter_test_parameters::WotFirstCertIssuableOn<Runtime>;
+    pub type WotMinCertForMembership = pallet_duniter_test_parameters::WotMinCertForMembership<Runtime>;
+    pub type WotMinCertForCreateIdtyRight =
+        pallet_duniter_test_parameters::WotMinCertForCreateIdtyRight<Runtime>;
+    pub type SmithCertPeriod = pallet_duniter_test_parameters::SmithCertPeriod<Runtime>;
+    pub type SmithMaxByIssuer = pallet_duniter_test_parameters::SmithCertMaxByIssuer<Runtime>;
+    pub type SmithMinReceivedCertToBeAbleToIssueCert =
+        pallet_duniter_test_parameters::SmithCertMinReceivedCertToIssueCert<Runtime>;
+    pub type SmithCertRenewablePeriod =
+        pallet_duniter_test_parameters::SmithCertRenewablePeriod<Runtime>;
+    pub type SmithValidityPeriod = pallet_duniter_test_parameters::SmithCertValidityPeriod<Runtime>;
+    pub type SmithMembershipPeriod = pallet_duniter_test_parameters::SmithMembershipPeriod<Runtime>;
+    pub type SmithPendingMembershipPeriod =
+        pallet_duniter_test_parameters::SmithPendingMembershipPeriod<Runtime>;
+    pub type SmithRenewablePeriod =
+        pallet_duniter_test_parameters::SmithMembershipRenewablePeriod<Runtime>;
+    pub type SmithsWotFirstCertIssuableOn =
+        pallet_duniter_test_parameters::SmithsWotFirstCertIssuableOn<Runtime>;
+    pub type SmithsWotMinCertForMembership =
+        pallet_duniter_test_parameters::SmithsWotMinCertForMembership<Runtime>;
 
-impl pallet_duniter_test_parameters::Config for Runtime {
-    type CertCount = u32;
-    type PeriodCount = Balance;
-}
-impl pallet_sudo::Config for Runtime {
-    type Event = Event;
-    type Call = Call;
-}
+    impl pallet_duniter_test_parameters::Config for Runtime {
+        type CertCount = u32;
+        type PeriodCount = Balance;
+    }
+    impl pallet_sudo::Config for Runtime {
+        type Event = Event;
+        type Call = Call;
+    }
 }
 
 // Create the runtime by composing the FRAME pallets that were previously configured.
-- 
GitLab