diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..d88507ad4c04a6e02f98f523cb80d604bc47e202
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,162 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'lc-core'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=lc-core"
+                ],
+                "filter": {
+                    "name": "lc-core",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug executable 'lc-core'",
+            "cargo": {
+                "args": [
+                    "build"
+                ],
+                "filter": {
+                    "name": "lc-core",
+                    "kind": "bin"
+                }
+            },
+            "args": [
+                "--tmp",
+                "--dev",
+                "--execution",
+                "Native"
+            ],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in executable 'lc-core'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--bin=lc-core",
+                    "--package=lc-core"
+                ],
+                "filter": {
+                    "name": "lc-core",
+                    "kind": "bin"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'lc-core-runtime'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=lc-core-runtime"
+                ],
+                "filter": {
+                    "name": "lc-core-runtime",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'pallet-certification'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=pallet-certification"
+                ],
+                "filter": {
+                    "name": "pallet-certification",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'pallet-identity'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=pallet-identity"
+                ],
+                "filter": {
+                    "name": "pallet-identity",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'pallet-ud-accounts-storage'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=pallet-ud-accounts-storage"
+                ],
+                "filter": {
+                    "name": "pallet-ud-accounts-storage",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'pallet-universal-dividend'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=pallet-universal-dividend"
+                ],
+                "filter": {
+                    "name": "pallet-universal-dividend",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index a4a7b4dc8711c03b0f1e7dc35b92bc1b08a9dd42..cf72eb9c26befcb121af3a4592d6a3fd73650a69 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2742,6 +2742,7 @@ dependencies = [
  "hex-literal",
  "pallet-aura",
  "pallet-balances",
+ "pallet-certification",
  "pallet-grandpa",
  "pallet-identity",
  "pallet-randomness-collective-flip",
@@ -3910,6 +3911,7 @@ dependencies = [
  "frame-benchmarking",
  "frame-support",
  "frame-system",
+ "maplit",
  "parity-scale-codec",
  "serde",
  "sp-core",
diff --git a/Cargo.toml b/Cargo.toml
index 615b817ae92db66717f200a3d79befeb33d2ae79..d286a46fe00811cf7e7c406d0de4d935c5b96fe1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,5 +7,7 @@ members = [
     'pallets/universal-dividend',
     'runtime',
 ]
+[profile.dev]
+opt-level = 3
 [profile.release]
 panic = 'unwind'
diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs
index 25f0d7c110f94089b33ece2d43534196fb3f4f89..a0a53294af87230069e92242985d60a94f921331 100644
--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -1,7 +1,7 @@
 use lc_core_runtime::{
     AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, IdentityConfig, IdtyDid,
-    IdtyRight, IdtyValue, Planet, Signature, SudoConfig, SystemConfig, UdAccountsStorageConfig,
-    UniversalDividendConfig, WASM_BINARY,
+    IdtyIndex, IdtyRight, IdtyValue, Planet, Signature, StrongCertConfig, SudoConfig, SystemConfig,
+    UdAccountsStorageConfig, UniversalDividendConfig, WASM_BINARY,
 };
 use maplit::btreemap;
 use sc_service::ChainType;
@@ -9,7 +9,7 @@ use sp_consensus_aura::sr25519::AuthorityId as AuraId;
 use sp_core::{sr25519, Pair, Public};
 use sp_finality_grandpa::AuthorityId as GrandpaId;
 use sp_runtime::traits::{IdentifyAccount, Verify};
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, BTreeSet};
 
 /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
 pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;
@@ -183,11 +183,26 @@ fn testnet_genesis(
         identity: IdentityConfig {
             identities: initial_identities
                 .iter()
-                .map(|(did, account)| {
-                    IdtyValue::new_valid(*did, account.clone(), vec![IdtyRight::Ud])
+                .map(|(did, account)| IdtyValue {
+                    did: *did,
+                    expire_on: lc_core_runtime::MaxInactivityPeriod::get(),
+                    owner_key: account.clone(),
+                    removable_on: 0,
+                    renewable_on: lc_core_runtime::StrongCertRenewablePeriod::get(),
+                    rights: vec![
+                        (IdtyRight::CreateIdty, None),
+                        (IdtyRight::StrongCert, None),
+                        (IdtyRight::Ud, None),
+                    ],
+                    status: lc_core_runtime::IdtyStatus::Validated,
+                    data: Default::default(),
                 })
                 .collect(),
         },
+        strong_cert: StrongCertConfig {
+            certs_by_issuer: clique_wot(initial_identities.len()),
+            phantom: std::marker::PhantomData,
+        },
         ud_accounts_storage: UdAccountsStorageConfig {
             ud_accounts: initial_identities.values().cloned().collect(),
         },
@@ -197,3 +212,16 @@ fn testnet_genesis(
         },
     }
 }
+
+fn clique_wot(initial_identities_len: usize) -> BTreeMap<IdtyIndex, BTreeSet<IdtyIndex>> {
+    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) } else { None })
+                .collect(),
+        );
+    }
+    certs_by_issuer
+}
diff --git a/pallets/certification/Cargo.toml b/pallets/certification/Cargo.toml
index cc07b102da453d464a28a9e2bfed83d68e77e290..150f3ac7cfb34349c2224e7ad883936198049b85 100644
--- a/pallets/certification/Cargo.toml
+++ b/pallets/certification/Cargo.toml
@@ -75,6 +75,9 @@ version = '1.0.119'
 
 ### DEV ###
 
+[dev-dependencies.maplit]
+version = '1.0.2'
+
 [dev-dependencies.sp-io]
 default-features = false
 git = 'https://github.com/paritytech/substrate.git'
diff --git a/pallets/certification/src/lib.rs b/pallets/certification/src/lib.rs
index 56e834d340f3f0299296a5b062e745a5378574cb..acda6feeec04af665fd3f2324273a5312220a14a 100644
--- a/pallets/certification/src/lib.rs
+++ b/pallets/certification/src/lib.rs
@@ -21,19 +21,23 @@ pub mod traits;
 #[cfg(test)]
 mod mock;
 
+#[cfg(test)]
+mod tests;
+
 pub use pallet::*;
 
 use crate::traits::*;
 use codec::Codec;
 use sp_runtime::traits::{AtLeast32BitUnsigned, Zero};
-use sp_std::collections::btree_map::BTreeMap;
-use sp_std::collections::btree_set::BTreeSet;
-use sp_std::fmt::Debug;
+use sp_std::{
+    collections::{btree_map::BTreeMap, btree_set::BTreeSet},
+    fmt::Debug,
+    vec::Vec,
+};
 
 pub mod pallet {
     use super::*;
     use frame_support::pallet_prelude::*;
-    //use frame_system::pallet_prelude::*;
 
     /// Configure the pallet by specifying the parameters and types on which it depends.
     pub trait Config<I: Instance = DefaultInstance>: frame_system::Config {
@@ -166,7 +170,7 @@ pub mod pallet {
                 let mut certs_by_receiver = BTreeMap::<T::IdtyIndex, Vec<T::IdtyIndex>>::new();
                 for (issuer, receivers) in &config.certs_by_issuer {
                     assert!(!receivers.contains(issuer), "Identity cannot tcertify it-self.");
-                    assert!(!receivers.len() <= T::MaxByIssuer::get() as usize, "Identity n°{:?} exceed MaxByIssuer.", issuer);
+                    assert!(!receivers.len() >= T::MaxByIssuer::get() as usize, "Identity n°{:?} exceed MaxByIssuer.", issuer);
 
                     cert_meta_by_issuer.insert(*issuer, IdtyCertMeta {
                         issued_count: receivers.len() as u8,
@@ -221,11 +225,13 @@ pub mod pallet {
             #[weight = 0]
             pub fn add_cert(origin, issuer: T::IdtyIndex, receiver: T::IdtyIndex) {
                 T::AddCertOrigin::ensure_origin((origin, issuer, receiver))?;
+                frame_support::runtime_print!("add_cert({:?}, {:?}): origin OK", issuer, receiver);
 
                 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) {
                     // Verify rules CertPeriod and MaxByIssuer
+                    frame_support::runtime_print!("add_cert({:?}, {:?}): Verify rules CertPeriod and MaxByIssuer", issuer, receiver);
                     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() {
@@ -233,6 +239,7 @@ pub mod pallet {
                     }
 
                     // Verify rule RenewablePeriod
+                    frame_support::runtime_print!("add_cert({:?}, {:?}): Verify rule RenewablePeriod", issuer, receiver);
                     let create = if let Ok(CertValue { chainable_on, .. }) = <StorageCertsByIssuer<T, I>>::try_get(issuer, receiver) {
                         if chainable_on > block_number {
                             return Err(Error::<T, I>::NotRespectRenewablePeriod.into());
@@ -255,6 +262,7 @@ pub mod pallet {
                 };
 
                 // 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());
                     cert_meta.received_count = cert_meta.received_count.saturating_add(1);
@@ -273,7 +281,7 @@ pub mod pallet {
                 if create {
                     // Write StorageCertsByReceiver
                     <StorageCertsByReceiver<T, I>>::mutate_exists(receiver, |issuers_opt| {
-                        let issuers = issuers_opt.get_or_insert(vec![]);
+                        let issuers = issuers_opt.get_or_insert(Vec::with_capacity(0));
                         if let Err(index) = issuers.binary_search(&issuer) {
                             issuers.insert(index, issuer);
                         }
diff --git a/pallets/certification/src/mock.rs b/pallets/certification/src/mock.rs
index 3f9841c78480e523d610b25eb75c455d51bbd505..948ee9200c0208d0a1044fc19fc3d70e2cc6f852 100644
--- a/pallets/certification/src/mock.rs
+++ b/pallets/certification/src/mock.rs
@@ -30,7 +30,7 @@ use sp_runtime::{
 type AccountId = u64;
 type BlockNumber = u64;
 type Block = frame_system::mocking::MockBlock<Test>;
-type IdtyIndex = u64;
+pub type IdtyIndex = u64;
 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
 
 // Configure a mock runtime to test the pallet.
@@ -76,18 +76,13 @@ impl system::Config for Test {
     type OnSetCode = ();
 }
 
-parameter_types! {
-    pub const MaxByIssuer: u8 = 3;
-    pub const RenewablePeriod: BlockNumber = 2;
-    pub const CertPeriod: u64 = 2;
-    pub const ValidityPeriod: u64 = 5;
-}
-
 pub struct EnsureRoot;
 impl frame_support::traits::EnsureOrigin<(Origin, IdtyIndex, IdtyIndex)> for EnsureRoot {
     type Success = ();
 
-    fn try_origin(o: (Origin, IdtyIndex, IdtyIndex)) -> Result<Self::Success, (Origin, IdtyIndex, IdtyIndex)> {
+    fn try_origin(
+        o: (Origin, IdtyIndex, IdtyIndex),
+    ) -> Result<Self::Success, (Origin, IdtyIndex, IdtyIndex)> {
         match o.0.clone().into() {
             Ok(system::RawOrigin::Root) => Ok(()),
             _ => Err(o),
@@ -95,6 +90,13 @@ impl frame_support::traits::EnsureOrigin<(Origin, IdtyIndex, IdtyIndex)> for Ens
     }
 }
 
+parameter_types! {
+    pub const MaxByIssuer: u8 = 3;
+    pub const RenewablePeriod: BlockNumber = 4;
+    pub const CertPeriod: u64 = 2;
+    pub const ValidityPeriod: u64 = 10;
+}
+
 impl pallet_certification::Config for Test {
     type AddCertOrigin = EnsureRoot;
     type CertPeriod = CertPeriod;
diff --git a/pallets/certification/src/tests.rs b/pallets/certification/src/tests.rs
index aadb17e7653daaa4ed408f771d6bccd3ac2747c0..3cc28928f68f86f483d75fcb5f452e3cb3771ce5 100644
--- a/pallets/certification/src/tests.rs
+++ b/pallets/certification/src/tests.rs
@@ -14,89 +14,70 @@
 // 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::IdtyIndex;
 use crate::mock::*;
 use crate::Error;
-use frame_support::assert_err;
 use frame_support::assert_ok;
 use frame_system::{EventRecord, Phase};
+use maplit::{btreemap, btreeset};
+use sp_std::collections::btree_map::BTreeMap;
 
 #[test]
-fn test_no_certs() {
-    let certifications = Vec::with_capacity(0);
-    new_test_ext(DefaultCertificationConfig { certifications }).execute_with(|| {
-        //assert_eq!(DefaultCertification::identities_count(), 0);
+fn test_must_receive_cert_before_can_issue() {
+    new_test_ext(DefaultCertificationConfig {
+        certs_by_issuer: BTreeMap::new(),
+        phantom: core::marker::PhantomData,
+    })
+    .execute_with(|| {
+        assert_eq!(
+            DefaultCertification::add_cert(Origin::root(), 0, 1),
+            Err(Error::<Test, _>::IdtyMustReceiveCertsBeforeCanIssue.into())
+        );
     });
 }
-/*
-#[test]
-fn test_two_identities() {
-    let identities = vec![
-        crate::IdtyValue {
-            did: Did(0),
-            owner_key: 1,
-            removable_on: None,
-            rights: vec![(Right::Right2, Some(10))],
-            status: crate::IdtyStatus::Validated,
-            data: (),
-        },
-        crate::IdtyValue {
-            did: Did(1),
-            owner_key: 2,
-            removable_on: None,
-            rights: vec![(Right::Right1, Some(20))],
-            status: crate::IdtyStatus::Validated,
-            data: (),
-        },
-    ];
-
-    new_test_ext(IdentityConfig { identities }).execute_with(|| {
-        // Should have two identities
-        assert_eq!(Identity::identities_count(), 2);
 
-        // We need to initialize at least one block before any call
-        run_to_block(1);
-
-        // Add right Right1 for Did(0)
-        // Should succes and trigger the correct event
-        assert_ok!(Identity::add_right(Origin::root(), 0, Right::Right1));
-        let events = System::events();
-        assert_eq!(events.len(), 1);
+#[test]
+fn test_cert_period() {
+    new_test_ext(DefaultCertificationConfig {
+        certs_by_issuer: btreemap![0 => btreeset![1]],
+        phantom: core::marker::PhantomData,
+    })
+    .execute_with(|| {
         assert_eq!(
-            events[0],
-            EventRecord {
-                phase: Phase::Initialization,
-                event: Event::Identity(crate::Event::IdtyAcquireRight(Did(0), Right::Right1)),
-                topics: vec![],
-            }
+            DefaultCertification::add_cert(Origin::root(), 0, 2),
+            Err(Error::<Test, _>::NotRespectCertPeriod.into())
         );
-        // Add right Right2 for Did(0)
-        // Should fail because Did(0) already have this right
-        assert_err!(
-            Identity::add_right(Origin::root(), 0, Right::Right2),
-            Error::<Test>::RightAlreadyAdded
+        run_to_block(CertPeriod::get());
+        assert_ok!(DefaultCertification::add_cert(Origin::root(), 0, 2));
+        run_to_block(CertPeriod::get() + 1);
+        assert_eq!(
+            DefaultCertification::add_cert(Origin::root(), 0, 3),
+            Err(Error::<Test, _>::NotRespectCertPeriod.into())
         );
+        run_to_block((2 * CertPeriod::get()) + 1);
+        assert_ok!(DefaultCertification::add_cert(Origin::root(), 0, 3));
+    });
+}
 
-        run_to_block(3);
-
-        // Delete right Right1 for Did(1)
-        // Should succes and trigger the correct event
-        assert_ok!(Identity::del_right(Origin::root(), 1, Right::Right1));
-        let events = System::events();
-        assert_eq!(events.len(), 2);
+#[test]
+fn test_renewable_period() {
+    new_test_ext(DefaultCertificationConfig {
+        certs_by_issuer: btreemap![0 => btreeset![1]],
+        phantom: core::marker::PhantomData,
+    })
+    .execute_with(|| {
+        run_to_block(CertPeriod::get());
         assert_eq!(
-            events[1],
-            EventRecord {
-                phase: Phase::Initialization,
-                event: Event::Identity(crate::Event::IdtyLostRight(Did(1), Right::Right1)),
-                topics: vec![],
-            }
+            DefaultCertification::add_cert(Origin::root(), 0, 1),
+            Err(Error::<Test, _>::NotRespectRenewablePeriod.into())
         );
-
-        // The Did(1) identity has no more rights, the inactivity period must start to run
-        let idty2 = Identity::identity(1);
-        assert!(idty2.rights.is_empty());
-        assert_eq!(idty2.removable_on, Some(7));
+        run_to_block(RenewablePeriod::get());
+        assert_ok!(DefaultCertification::add_cert(Origin::root(), 0, 1));
+        run_to_block(RenewablePeriod::get() + CertPeriod::get());
+        assert_eq!(
+            DefaultCertification::add_cert(Origin::root(), 0, 1),
+            Err(Error::<Test, _>::NotRespectRenewablePeriod.into())
+        );
+        run_to_block((2 * RenewablePeriod::get()) + 1);
+        assert_ok!(DefaultCertification::add_cert(Origin::root(), 0, 1));
     });
 }
-*/
\ No newline at end of file
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index 7e5d88833c4cb3fbf1fa2004c52e46c6877322fc..d1e9f52a3f9ebd9d256e184de0194c6d17a0f49e 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -60,7 +60,7 @@ pub mod pallet {
         /// Management of the authorizations of the different calls. (The default implementation only allows root)
         type EnsureIdtyCallAllowed: EnsureIdtyCallAllowed<Self>;
         ///  Identity custom data
-        type IdtyData: IdtyData;
+        type IdtyData: Parameter + Member + MaybeSerializeDeserialize + Debug + Default;
         /// Identity decentralized identifier
         type IdtyDid: IdtyDid;
         /// A short identity index.
@@ -78,17 +78,18 @@ pub mod pallet {
         /// Rights that an identity can have
         type IdtyRight: IdtyRight;
         /// On identity confirmed by it's owner
-        type OnIdtyConfirmed: OnIdtyConfirmed<Self>;
-        /// On identity removed
-        type OnIdtyRemoved: OnIdtyRemoved<Self>;
-        /// On identity validated
-        type OnIdtyValidated: OnIdtyValidated<Self>;
+        type OnIdtyChange: OnIdtyChange<Self>;
         /// On right key change
         type OnRightKeyChange: OnRightKeyChange<Self>;
         #[pallet::constant]
         /// Maximum period of inactivity, after this period, the identity is permanently deleted
         type MaxInactivityPeriod: Get<Self::BlockNumber>;
         #[pallet::constant]
+        /// Maximum period with no rights, after this period, the identity is permanently deleted
+        type MaxNoRightPeriod: Get<Self::BlockNumber>;
+        /// Duration after which an identity is renewable
+        type RenewablePeriod: Get<Self::BlockNumber>;
+        #[pallet::constant]
         /// Period after which a non-validated identity is deleted
         type ValidationPeriod: Get<Self::BlockNumber>;
     }
@@ -118,6 +119,7 @@ pub mod pallet {
         Created,
         ConfirmedByOwner,
         Validated,
+        Expired,
     }
     impl Default for IdtyStatus {
         fn default() -> Self {
@@ -129,34 +131,23 @@ pub mod pallet {
     #[derive(Encode, Decode, Clone, PartialEq, Eq)]
     pub struct IdtyValue<T: Config> {
         pub did: T::IdtyDid,
+        pub expire_on: T::BlockNumber,
         pub owner_key: T::AccountId,
-        pub removable_on: Option<T::BlockNumber>,
+        pub removable_on: T::BlockNumber,
+        pub renewable_on: T::BlockNumber,
         pub rights: Vec<(T::IdtyRight, Option<T::AccountId>)>,
         pub status: IdtyStatus,
         pub data: T::IdtyData,
     }
-    impl<T: Config> IdtyValue<T> {
-        pub fn new_valid(
-            did: T::IdtyDid,
-            owner_key: T::AccountId,
-            rights: Vec<T::IdtyRight>,
-        ) -> Self {
-            Self {
-                did,
-                owner_key,
-                removable_on: None,
-                rights: rights.into_iter().map(|right| (right, None)).collect(),
-                status: IdtyStatus::Validated,
-                data: T::IdtyData::default(),
-            }
-        }
-    }
     impl<T: Config> Default for IdtyValue<T> {
         fn default() -> Self {
             Self {
                 did: Default::default(),
+                expire_on: frame_system::Pallet::<T>::block_number()
+                    + T::MaxInactivityPeriod::get(),
                 owner_key: Default::default(),
-                removable_on: None,
+                removable_on: T::BlockNumber::zero(),
+                renewable_on: frame_system::Pallet::<T>::block_number() + T::RenewablePeriod::get(),
                 rights: Default::default(),
                 status: Default::default(),
                 data: Default::default(),
@@ -167,7 +158,7 @@ pub mod pallet {
         pub fn get_right_key(&self, right: T::IdtyRight) -> Option<T::AccountId> {
             if let Ok(index) = self
                 .rights
-                .binary_search_by(|(right_, _)| right.cmp(right_))
+                .binary_search_by(|(right_, _)| right_.cmp(&right))
             {
                 if self.rights[index].1.is_some() {
                     self.rights[index].1.clone()
@@ -205,6 +196,12 @@ pub mod pallet {
     #[pallet::getter(fn identities_count)]
     pub(super) type IdentitiesCount<T: Config> = StorageValue<_, u64, ValueQuery>;
 
+    /// Identities by expiration block
+    #[pallet::storage]
+    #[pallet::getter(fn expire_on)]
+    pub type IdentitiesExpireOn<T: Config> =
+        StorageMap<_, Blake2_128Concat, T::BlockNumber, Vec<T::IdtyIndex>, ValueQuery>;
+
     /// Identities by removed block
     #[pallet::storage]
     #[pallet::getter(fn removable_on)]
@@ -244,12 +241,12 @@ pub mod pallet {
                 );
                 if idty_value.status == IdtyStatus::Validated {
                     if idty_value.rights.is_empty() {
-                        assert!(idty_value.removable_on.is_some());
+                        assert!(idty_value.removable_on > T::BlockNumber::zero());
                     } else {
-                        assert!(idty_value.removable_on.is_none());
+                        assert!(idty_value.removable_on == T::BlockNumber::zero());
                     }
                 } else {
-                    assert!(idty_value.removable_on.is_some());
+                    assert!(idty_value.removable_on > T::BlockNumber::zero());
                     assert!(idty_value.rights.is_empty())
                 }
                 dids.insert(idty_value.did);
@@ -263,9 +260,9 @@ pub mod pallet {
             <IdentitiesCount<T>>::put(self.identities.len() as u64);
             for idty_value in &identities {
                 let idty_index = Pallet::<T>::get_next_idty_index();
-                if let Some(removable_on) = idty_value.removable_on {
+                if idty_value.removable_on > T::BlockNumber::zero() {
                     <IdentitiesRemovableOn<T>>::append(
-                        removable_on,
+                        idty_value.removable_on,
                         (idty_index, idty_value.status),
                     )
                 }
@@ -279,7 +276,11 @@ pub mod pallet {
     #[pallet::hooks]
     impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
         fn on_initialize(n: T::BlockNumber) -> Weight {
-            Self::prune_identities(n)
+            if n > T::BlockNumber::zero() {
+                Self::expire_identities(n) + Self::prune_identities(n)
+            } else {
+                0
+            }
         }
     }
 
@@ -304,9 +305,9 @@ pub mod pallet {
         /// An identity has been validated
         /// [idty]
         IdtyValidated(T::IdtyDid),
-        /// An identity was declared dead
+        /// An identity was renewed by it's owner
         /// [idty]
-        IdtyDead(T::IdtyDid),
+        IdtyRenewed(T::IdtyDid),
         /// An identity has acquired a new right
         /// [idty, right]
         IdtyAcquireRight(T::IdtyDid, T::IdtyRight),
@@ -337,9 +338,8 @@ pub mod pallet {
             idty_did: T::IdtyDid,
             owner_key: T::AccountId,
         ) -> DispatchResultWithPostInfo {
-            if !T::EnsureIdtyCallAllowed::create_identity(origin, creator, &idty_did, &owner_key) {
-                return Err(Error::<T>::IdtyCreationNotAllowed.into());
-            }
+            let idty_data =
+                T::EnsureIdtyCallAllowed::create_identity(origin, creator, &idty_did, &owner_key)?;
             if <IdentitiesByDid<T>>::contains_key(&idty_did) {
                 return Err(Error::<T>::IdtyAlreadyExist.into());
             }
@@ -352,15 +352,20 @@ pub mod pallet {
                 idty_index,
                 IdtyValue {
                     did: idty_did,
+                    expire_on: T::BlockNumber::zero(),
                     owner_key: owner_key.clone(),
-                    removable_on: Some(removable_on),
-                    ..Default::default()
+                    removable_on,
+                    renewable_on: T::BlockNumber::zero(),
+                    rights: Vec::with_capacity(0),
+                    status: IdtyStatus::Created,
+                    data: idty_data,
                 },
             );
             <IdentitiesByDid<T>>::insert(idty_did, idty_index);
             IdentitiesRemovableOn::<T>::append(removable_on, (idty_index, IdtyStatus::Created));
             Self::inc_identities_counter();
             Self::deposit_event(Event::IdtyCreated(idty_did, owner_key));
+            T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Created { creator });
             Ok(().into())
         }
         #[pallet::weight(0)]
@@ -378,18 +383,22 @@ pub mod pallet {
                     }
 
                     let block_number = frame_system::pallet::Pallet::<T>::block_number();
+                    let expire_on = block_number + T::MaxInactivityPeriod::get();
                     let removable_on = block_number + T::ValidationPeriod::get();
-                    idty_value.removable_on = Some(removable_on);
+                    let renewable_on = block_number + T::RenewablePeriod::get();
+                    idty_value.expire_on = expire_on;
+                    idty_value.removable_on = removable_on;
+                    idty_value.renewable_on = renewable_on;
                     idty_value.status = IdtyStatus::ConfirmedByOwner;
-                    let owner_key = idty_value.owner_key.clone();
 
                     <Identities<T>>::insert(idty_index, idty_value);
+                    IdentitiesExpireOn::<T>::append(expire_on, idty_index);
                     IdentitiesRemovableOn::<T>::append(
                         removable_on,
                         (idty_index, IdtyStatus::ConfirmedByOwner),
                     );
                     Self::deposit_event(Event::IdtyConfirmed(idty_did));
-                    T::OnIdtyConfirmed::on_idty_confirmed(idty_did, owner_key, removable_on);
+                    T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Confirmed);
                     Ok(().into())
                 } else {
                     Err(Error::<T>::RequireToBeOwner.into())
@@ -399,6 +408,48 @@ pub mod pallet {
             }
         }
         #[pallet::weight(0)]
+        pub fn renew_identity(
+            origin: OriginFor<T>,
+            idty_did: T::IdtyDid,
+            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 block_number = frame_system::pallet::Pallet::<T>::block_number();
+                            if idty_value.renewable_on > block_number {
+                                return Err(Error::<T>::IdtyNotYetRenewable.into());
+                            }
+                            let expire_on = block_number + T::MaxInactivityPeriod::get();
+                            let renewable_on = block_number + T::RenewablePeriod::get();
+                            idty_value.expire_on = expire_on;
+                            idty_value.renewable_on = renewable_on;
+                            let old_status = idty_value.status;
+                            idty_value.status = IdtyStatus::Validated;
+
+                            <Identities<T>>::insert(idty_index, idty_value);
+                            IdentitiesExpireOn::<T>::append(expire_on, idty_index);
+                            Self::deposit_event(Event::IdtyRenewed(idty_did));
+                            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,
@@ -410,10 +461,9 @@ pub mod pallet {
                     IdtyStatus::Created => Err(Error::<T>::IdtyNotConfirmedByOwner.into()),
                     IdtyStatus::ConfirmedByOwner => {
                         let block_number = frame_system::pallet::Pallet::<T>::block_number();
-                        let removable_on = block_number + T::MaxInactivityPeriod::get();
-                        idty_value.removable_on = Some(removable_on);
+                        let removable_on = block_number + T::MaxNoRightPeriod::get();
+                        idty_value.removable_on = removable_on;
                         idty_value.status = IdtyStatus::Validated;
-                        let owner_key = idty_value.owner_key.clone();
                         let did = idty_value.did;
 
                         <Identities<T>>::insert(idty_index, idty_value);
@@ -422,10 +472,12 @@ pub mod pallet {
                             (idty_index, IdtyStatus::Validated),
                         );
                         Self::deposit_event(Event::IdtyValidated(did));
-                        T::OnIdtyValidated::on_idty_validated(idty_index, owner_key)?;
+                        T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Validated);
                         Ok(().into())
                     }
-                    IdtyStatus::Validated => Err(Error::<T>::IdtyAlreadyValidated.into()),
+                    IdtyStatus::Validated | IdtyStatus::Expired => {
+                        Err(Error::<T>::IdtyAlreadyValidated.into())
+                    }
                 }
             } else {
                 Err(Error::<T>::IdtyNotFound.into())
@@ -443,21 +495,31 @@ pub mod pallet {
                 match idty_value.status {
                     IdtyStatus::Created => Err(Error::<T>::IdtyNotConfirmedByOwner.into()),
                     IdtyStatus::ConfirmedByOwner => {
-                        idty_value.removable_on = None;
+                        idty_value.removable_on = T::BlockNumber::zero();
                         idty_value.rights = rights.iter().map(|right| (*right, None)).collect();
                         idty_value.status = IdtyStatus::Validated;
-                        let owner_key = idty_value.owner_key.clone();
                         let did = idty_value.did;
+                        let owner_key = idty_value.owner_key.clone();
 
                         <Identities<T>>::insert(idty_index, idty_value);
                         Self::deposit_event(Event::IdtyValidated(did));
+                        T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Validated);
                         for right in rights {
                             Self::deposit_event(Event::IdtyAcquireRight(did, right));
+                            if right.allow_owner_key() {
+                                T::OnRightKeyChange::on_right_key_change(
+                                    idty_index,
+                                    right,
+                                    None,
+                                    Some(owner_key.clone()),
+                                );
+                            }
                         }
-                        T::OnIdtyValidated::on_idty_validated(idty_index, owner_key)?;
                         Ok(().into())
                     }
-                    IdtyStatus::Validated => Err(Error::<T>::IdtyAlreadyValidated.into()),
+                    IdtyStatus::Validated | IdtyStatus::Expired => {
+                        Err(Error::<T>::IdtyAlreadyValidated.into())
+                    }
                 }
             } else {
                 Err(Error::<T>::IdtyNotFound.into())
@@ -478,7 +540,7 @@ pub mod pallet {
 
                 if let Err(index) = idty_value
                     .rights
-                    .binary_search_by(|(right_, _)| right.cmp(right_))
+                    .binary_search_by(|(right_, _)| right_.cmp(&right))
                 {
                     let did = idty_value.did;
                     let new_key = if right.allow_owner_key() {
@@ -487,7 +549,7 @@ pub mod pallet {
                         None
                     };
 
-                    idty_value.removable_on = None;
+                    idty_value.removable_on = T::BlockNumber::zero();
                     idty_value.rights.insert(index, (right, None));
                     <Identities<T>>::insert(idty_index, idty_value);
                     Self::deposit_event(Event::<T>::IdtyAcquireRight(did, right));
@@ -517,7 +579,7 @@ pub mod pallet {
 
                 if let Ok(index) = idty_value
                     .rights
-                    .binary_search_by(|(right_, _)| right.cmp(right_))
+                    .binary_search_by(|(right_, _)| right_.cmp(&right))
                 {
                     let did = idty_value.did;
                     let old_key_opt = if let Some(ref subkey) = idty_value.rights[index].1 {
@@ -531,8 +593,8 @@ pub mod pallet {
 
                     if idty_value.rights.is_empty() {
                         let block_number = frame_system::pallet::Pallet::<T>::block_number();
-                        let removable_on = block_number + T::MaxInactivityPeriod::get();
-                        idty_value.removable_on = Some(removable_on);
+                        let removable_on = block_number + T::MaxNoRightPeriod::get();
+                        idty_value.removable_on = removable_on;
                         <IdentitiesRemovableOn<T>>::append(
                             removable_on,
                             (idty_index, IdtyStatus::Validated),
@@ -574,7 +636,7 @@ pub mod pallet {
 
                     if let Ok(index) = idty_value
                         .rights
-                        .binary_search_by(|(right_, _)| right.cmp(right_))
+                        .binary_search_by(|(right_, _)| right_.cmp(&right))
                     {
                         let did = idty_value.did;
                         let old_subkey_opt = idty_value.rights[index].1.clone();
@@ -631,6 +693,8 @@ pub mod pallet {
         IdtyNotFound,
         /// Identity not validated
         IdtyNotValidated,
+        /// Identity not yet renewable
+        IdtyNotYetRenewable,
         /// This operation requires to be the owner of the identity
         RequireToBeOwner,
         /// Right already added
@@ -639,6 +703,16 @@ pub mod pallet {
         RightNotExist,
     }
 
+    // PUBLIC FUNCTIONS //
+
+    impl<T: Config> Pallet<T> {
+        pub fn set_idty_data(idty_index: T::IdtyIndex, idty_data: T::IdtyData) {
+            Identities::<T>::mutate_exists(idty_index, |idty_val| {
+                idty_val.get_or_insert(IdtyValue::default()).data = idty_data;
+            });
+        }
+    }
+
     // INTERNAL FUNCTIONS //
 
     impl<T: Config> Pallet<T> {
@@ -654,8 +728,8 @@ pub mod pallet {
                 <NextIdtyIndex<T>>::put(next_index.saturating_add(T::IdtyIndex::one()));
                 next_index
             } else {
-                <NextIdtyIndex<T>>::put(T::IdtyIndex::one());
-                T::IdtyIndex::zero()
+                <NextIdtyIndex<T>>::put(T::IdtyIndex::one() + T::IdtyIndex::one());
+                T::IdtyIndex::one()
             }
         }
         fn inc_identities_counter() {
@@ -665,6 +739,31 @@ pub mod pallet {
                 <IdentitiesCount<T>>::put(1);
             }
         }
+        fn expire_identities(block_number: T::BlockNumber) -> Weight {
+            let mut total_weight: Weight = 0;
+
+            use frame_support::storage::generator::StorageMap as _;
+            if let Some(identities_index) = IdentitiesExpireOn::<T>::from_query_to_optional_value(
+                IdentitiesExpireOn::<T>::take(block_number),
+            ) {
+                for idty_index in identities_index {
+                    if let Ok(idty_val) = <Identities<T>>::try_get(idty_index) {
+                        if idty_val.expire_on == block_number {
+                            <Identities<T>>::mutate_exists(idty_index, |idty_val_opt| {
+                                idty_val_opt.get_or_insert(IdtyValue::default()).rights =
+                                    Vec::with_capacity(0);
+                                idty_val_opt.get_or_insert(IdtyValue::default()).status =
+                                    IdtyStatus::Expired;
+                            });
+                            total_weight +=
+                                T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Expired);
+                        }
+                    }
+                }
+            }
+
+            total_weight
+        }
         fn prune_identities(block_number: T::BlockNumber) -> Weight {
             let mut total_weight: Weight = 0;
 
@@ -674,18 +773,13 @@ pub mod pallet {
             ) {
                 for (idty_index, idty_status) in identities {
                     if let Ok(idty_val) = <Identities<T>>::try_get(idty_index) {
-                        if idty_val.removable_on == Some(block_number)
-                            && idty_val.status == idty_status
-                        {
+                        if idty_val.removable_on == block_number && idty_val.status == idty_status {
                             let did = idty_val.did;
                             <Identities<T>>::remove(idty_index);
                             <IdentitiesByDid<T>>::remove(did);
                             Self::dec_identities_counter();
-                            total_weight += T::OnIdtyRemoved::on_idty_removed(
-                                idty_index,
-                                did,
-                                idty_val.owner_key,
-                            );
+                            total_weight +=
+                                T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Removed);
                         }
                     }
                 }
diff --git a/pallets/identity/src/mock.rs b/pallets/identity/src/mock.rs
index c8973aaad3dda9388f69f140ddcd050868ea0f3f..47310db1e9a12ad242180d6ab18bf239293167a6 100644
--- a/pallets/identity/src/mock.rs
+++ b/pallets/identity/src/mock.rs
@@ -101,7 +101,9 @@ impl system::Config for Test {
 
 parameter_types! {
     pub const ConfirmPeriod: u64 = 2;
-    pub const MaxInactivityPeriod: u64 = 4;
+    pub const MaxInactivityPeriod: u64 = 5;
+    pub const MaxNoRightPeriod: u64 = 4;
+    pub const RenewablePeriod: u64 = 3;
     pub const ValidationPeriod: u64 = 2;
 }
 
@@ -116,11 +118,11 @@ impl pallet_identity::Config for Test {
     type IdtyIndex = u64;
     type IdtyValidationOrigin = system::EnsureRoot<AccountId>;
     type IdtyRight = IdtyRight;
-    type OnIdtyConfirmed = ();
-    type OnIdtyRemoved = ();
-    type OnIdtyValidated = ();
+    type OnIdtyChange = ();
     type OnRightKeyChange = ();
     type MaxInactivityPeriod = MaxInactivityPeriod;
+    type MaxNoRightPeriod = MaxNoRightPeriod;
+    type RenewablePeriod = RenewablePeriod;
     type ValidationPeriod = ValidationPeriod;
 }
 
diff --git a/pallets/identity/src/tests.rs b/pallets/identity/src/tests.rs
index ba8efc3fe27fc92b15c496e694e633b929ae9292..b40d194edefefaef82d8bd818a7da56c261496da 100644
--- a/pallets/identity/src/tests.rs
+++ b/pallets/identity/src/tests.rs
@@ -35,16 +35,20 @@ fn test_two_identities() {
     let identities = vec![
         crate::IdtyValue {
             did: Did(0),
+            expire_on: 5,
             owner_key: 1,
-            removable_on: None,
+            removable_on: 0,
+            renewable_on: 3,
             rights: vec![(Right::Right2, Some(10))],
             status: crate::IdtyStatus::Validated,
             data: (),
         },
         crate::IdtyValue {
             did: Did(1),
+            expire_on: 5,
             owner_key: 2,
-            removable_on: None,
+            removable_on: 0,
+            renewable_on: 3,
             rights: vec![(Right::Right1, Some(20))],
             status: crate::IdtyStatus::Validated,
             data: (),
@@ -97,6 +101,6 @@ fn test_two_identities() {
         // The Did(1) identity has no more rights, the inactivity period must start to run
         let idty2 = Identity::identity(1);
         assert!(idty2.rights.is_empty());
-        assert_eq!(idty2.removable_on, Some(7));
+        assert_eq!(idty2.removable_on, 7);
     });
 }
diff --git a/pallets/identity/src/traits.rs b/pallets/identity/src/traits.rs
index 92dba5318f4d097784851b4b450dcf6cc0e733ed..a61a475e2a65d12eec1aa56172a681d625ff5bae 100644
--- a/pallets/identity/src/traits.rs
+++ b/pallets/identity/src/traits.rs
@@ -15,7 +15,7 @@
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
 use crate::*;
-use frame_support::pallet_prelude::*;
+use frame_support::{dispatch::DispatchError, pallet_prelude::*};
 use frame_system::pallet_prelude::*;
 use sp_runtime::traits::MaybeSerializeDeserialize;
 use sp_std::fmt::Debug;
@@ -26,7 +26,7 @@ pub trait EnsureIdtyCallAllowed<T: Config> {
         creator: T::IdtyIndex,
         idty_did: &T::IdtyDid,
         idty_owner_key: &T::AccountId,
-    ) -> bool;
+    ) -> Result<T::IdtyData, DispatchError>;
 }
 impl<T: Config> EnsureIdtyCallAllowed<T> for () {
     fn create_identity(
@@ -34,21 +34,14 @@ impl<T: Config> EnsureIdtyCallAllowed<T> for () {
         _creator: T::IdtyIndex,
         _idty_did: &T::IdtyDid,
         _idty_owner_key: &T::AccountId,
-    ) -> bool {
-        ensure_root(origin).is_ok()
+    ) -> Result<T::IdtyData, DispatchError> {
+        match ensure_root(origin) {
+            Ok(()) => Ok(T::IdtyData::default()),
+            Err(_) => Err(DispatchError::BadOrigin),
+        }
     }
 }
 
-pub trait IdtyData:
-    frame_support::Parameter
-    + frame_support::pallet_prelude::Member
-    + MaybeSerializeDeserialize
-    + Debug
-    + Default
-{
-}
-impl IdtyData for () {}
-
 pub trait IdtyDid:
     frame_support::Parameter
     + frame_support::pallet_prelude::Member
@@ -72,50 +65,19 @@ pub trait IdtyRight:
     fn allow_owner_key(self) -> bool;
 }
 
-pub trait OnIdtyConfirmed<T: Config> {
-    fn on_idty_confirmed(
-        idty_did: T::IdtyDid,
-        owner_key: T::AccountId,
-        removable_on: T::BlockNumber,
-    );
-}
-impl<T: Config> OnIdtyConfirmed<T> for () {
-    fn on_idty_confirmed(
-        _idty_did: T::IdtyDid,
-        _owner_key: T::AccountId,
-        _removable_on: T::BlockNumber,
-    ) {
-    }
-}
-
-pub trait OnIdtyValidated<T: Config> {
-    fn on_idty_validated(
-        idty_index: T::IdtyIndex,
-        owner_key: T::AccountId,
-    ) -> DispatchResultWithPostInfo;
-}
-impl<T: Config> OnIdtyValidated<T> for () {
-    fn on_idty_validated(
-        _idty_index: T::IdtyIndex,
-        _owner_key: T::AccountId,
-    ) -> DispatchResultWithPostInfo {
-        Ok(().into())
-    }
+pub enum IdtyEvent<T: Config> {
+    Created { creator: T::IdtyIndex },
+    Confirmed,
+    Validated,
+    Expired,
+    Removed,
 }
 
-pub trait OnIdtyRemoved<T: Config> {
-    fn on_idty_removed(
-        idty_index: T::IdtyIndex,
-        idty_did: T::IdtyDid,
-        owner_key: T::AccountId,
-    ) -> Weight;
+pub trait OnIdtyChange<T: Config> {
+    fn on_idty_change(idty_index: T::IdtyIndex, idty_event: IdtyEvent<T>) -> Weight;
 }
-impl<T: Config> OnIdtyRemoved<T> for () {
-    fn on_idty_removed(
-        _idty_index: T::IdtyIndex,
-        _idty_did: T::IdtyDid,
-        _owner_key: T::AccountId,
-    ) -> Weight {
+impl<T: Config> OnIdtyChange<T> for () {
+    fn on_idty_change(_idty_index: T::IdtyIndex, _idty_event: IdtyEvent<T>) -> Weight {
         0
     }
 }
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index 1ea14d770defb9ea24bd2f1aa2a2bf94cc2ebc30..6787d2e025211625b66672d2b6b8a433cc38470f 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -35,6 +35,8 @@ std = [
     'frame-system/std',
     'pallet-aura/std',
     'pallet-balances/std',
+    'pallet-certification/std',
+    'pallet-identity/std',
     'pallet-grandpa/std',
     'pallet-randomness-collective-flip/std',
     'pallet-sudo/std',
@@ -116,6 +118,10 @@ git = 'https://github.com/paritytech/substrate.git'
 tag = 'monthly-2021-07'
 version = '3.0.0'
 
+[dependencies.pallet-certification]
+default-features = false
+path = '../pallets/certification'
+
 [dependencies.pallet-grandpa]
 default-features = false
 git = 'https://github.com/paritytech/substrate.git'
diff --git a/runtime/src/authorizations.rs b/runtime/src/authorizations.rs
index d293b1f6666a806452f7bb5002827ef66e2c7e54..b8c04d959278569f528a14829473748db2c2e5fe 100644
--- a/runtime/src/authorizations.rs
+++ b/runtime/src/authorizations.rs
@@ -14,7 +14,15 @@
 // 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::{AccountId, Identity, IdtyDid, IdtyIndex, IdtyRight, Origin, Runtime};
+use crate::{
+    AccountId, BlockNumber, Identity, IdtyData, IdtyDid, IdtyIndex, IdtyRight, Origin, Runtime,
+    StrongCert, System,
+};
+use frame_support::pallet_prelude::DispatchError;
+use frame_support::traits::EnsureOrigin;
+use pallet_identity::IdtyStatus;
+
+const IDTY_CREATE_PERIOD: BlockNumber = 100;
 
 pub struct EnsureIdtyCallAllowedImpl;
 impl pallet_identity::traits::EnsureIdtyCallAllowed<Runtime> for EnsureIdtyCallAllowedImpl {
@@ -23,19 +31,89 @@ impl pallet_identity::traits::EnsureIdtyCallAllowed<Runtime> for EnsureIdtyCallA
         creator: IdtyIndex,
         _idty_did: &IdtyDid,
         _idty_owner_key: &AccountId,
-    ) -> bool {
+    ) -> Result<IdtyData, DispatchError> {
+        let block_number = System::block_number();
+        let creator_idty_data = IdtyData {
+            can_create_on: block_number + IDTY_CREATE_PERIOD,
+        };
+        let new_idty_data = IdtyData { can_create_on: 0 };
         match origin.into() {
-            Ok(frame_system::RawOrigin::Root) => true,
+            Ok(frame_system::RawOrigin::Root) => {
+                Identity::set_idty_data(creator, creator_idty_data);
+                Ok(new_idty_data)
+            }
             Ok(frame_system::RawOrigin::Signed(signer)) => {
                 let creator_idty = Identity::identity(creator);
 
                 if let Some(authorized_key) = creator_idty.get_right_key(IdtyRight::CreateIdty) {
-                    signer == authorized_key
+                    if signer != authorized_key {
+                        frame_support::runtime_print!("signer != authorized_key");
+                        Err(DispatchError::Other("signer != authorized_key"))
+                    } else if !StrongCert::is_idty_allowed_to_create_cert(creator) {
+                        frame_support::runtime_print!("not allowed to create cert");
+                        Err(DispatchError::Other("not allowed to create cert"))
+                    } else if creator_idty.data.can_create_on > System::block_number() {
+                        frame_support::runtime_print!("Not respect IdtyCreatePeriod");
+                        Err(DispatchError::Other("Not respect IdtyCreatePeriod"))
+                    } else {
+                        Identity::set_idty_data(creator, creator_idty_data);
+                        Ok(new_idty_data)
+                    }
+                } else {
+                    frame_support::runtime_print!("Idty not have right CreateIdty");
+                    Err(DispatchError::Other("Idty not have right CreateIdty"))
+                }
+            }
+            _ => {
+                frame_support::runtime_print!("Origin neither root or signed");
+                Err(DispatchError::Other("Origin neither root or signed"))
+            }
+        }
+    }
+}
+
+pub struct AddStrongCertOrigin;
+impl EnsureOrigin<(Origin, IdtyIndex, IdtyIndex)> for AddStrongCertOrigin {
+    type Success = ();
+
+    fn try_origin(
+        o: (Origin, IdtyIndex, IdtyIndex),
+    ) -> Result<Self::Success, (Origin, IdtyIndex, IdtyIndex)> {
+        match o.0.clone().into() {
+            Ok(frame_system::RawOrigin::Root) => Ok(()),
+            Ok(frame_system::RawOrigin::Signed(who)) => {
+                let issuer = Identity::identity(o.1);
+                if let Some(allowed_key) = issuer.get_right_key(IdtyRight::StrongCert) {
+                    if who == allowed_key {
+                        let receiver = Identity::identity(o.2);
+                        match receiver.status {
+                            IdtyStatus::ConfirmedByOwner | IdtyStatus::Validated => Ok(()),
+                            IdtyStatus::Created | IdtyStatus::Expired => Err(o),
+                        }
+                    } else {
+                        // Bad key
+                        Err(o)
+                    }
                 } else {
-                    false
+                    // Issuer has not right StrongCert
+                    Err(o)
                 }
             }
-            _ => false,
+            _ => Err(o),
+        }
+    }
+}
+
+pub struct DelStrongCertOrigin;
+impl EnsureOrigin<(Origin, IdtyIndex, IdtyIndex)> for DelStrongCertOrigin {
+    type Success = ();
+
+    fn try_origin(
+        o: (Origin, IdtyIndex, IdtyIndex),
+    ) -> Result<Self::Success, (Origin, IdtyIndex, IdtyIndex)> {
+        match o.0.clone().into() {
+            Ok(frame_system::RawOrigin::Root) => Ok(()),
+            _ => Err(o),
         }
     }
 }
diff --git a/runtime/src/entities.rs b/runtime/src/entities.rs
index d60d8b4086cf15f780b8e0ed3f25c772d0def88c..ba9b8f91ff9fd973a4717f04e5a5ff21467c27e8 100644
--- a/runtime/src/entities.rs
+++ b/runtime/src/entities.rs
@@ -14,6 +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::BlockNumber;
 use frame_support::pallet_prelude::*;
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
@@ -35,8 +36,8 @@ impl Default for IdtyRight {
 impl pallet_identity::traits::IdtyRight for IdtyRight {
     fn allow_owner_key(self) -> bool {
         match self {
-            Self::CreateIdty | Self::LightCert | Self::Ud => true,
-            IdtyRight::StrongCert => false,
+            Self::CreateIdty | Self::LightCert | IdtyRight::StrongCert | Self::Ud => true,
+            //IdtyRight::StrongCert => false,
             //_ => false,
         }
     }
@@ -84,6 +85,12 @@ impl Ord for IdtyDid {
 }
 impl pallet_identity::traits::IdtyDid for IdtyDid {}
 
+#[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
+#[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, RuntimeDebug)]
+pub struct IdtyData {
+    pub can_create_on: BlockNumber,
+}
+
 #[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
 #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
 pub enum Planet {
diff --git a/runtime/src/handlers.rs b/runtime/src/handlers.rs
index 2eaab7ed1be1fc5b5027f973e9101936b6743a13..04ad4d9f5e0ee080154a6b50c0bec0defd10c514 100644
--- a/runtime/src/handlers.rs
+++ b/runtime/src/handlers.rs
@@ -14,16 +14,30 @@
 // 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::{AccountId, Identity, IdtyIndex, IdtyRight, Origin, Runtime, UdAccountsStorage};
-use frame_support::pallet_prelude::DispatchResultWithPostInfo;
+use super::{
+    AccountId, Identity, IdtyIndex, IdtyRight, Origin, Runtime, StrongCert, UdAccountsStorage,
+    Weight,
+};
+use pallet_identity::traits::IdtyEvent;
 
-pub struct OnIdtyValidatedHandler;
-impl pallet_identity::traits::OnIdtyValidated<Runtime> for OnIdtyValidatedHandler {
-    fn on_idty_validated(
-        idty_index: IdtyIndex,
-        _owner_key: AccountId,
-    ) -> DispatchResultWithPostInfo {
-        Identity::add_right(Origin::root(), idty_index, IdtyRight::Ud)
+const MIN_STRONG_CERT_FOR_UD: u32 = 2;
+const MIN_STRONG_CERT_FOR_STRONG_CERT: u32 = 3;
+
+pub struct OnIdtyChangeHandler;
+impl pallet_identity::traits::OnIdtyChange<Runtime> for OnIdtyChangeHandler {
+    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 _ = StrongCert::add_cert(Origin::root(), creator, idty_index);
+            }
+            IdtyEvent::Confirmed => {}
+            IdtyEvent::Validated => {}
+            IdtyEvent::Expired => {}
+            IdtyEvent::Removed => {}
+        };
+        total_weight
     }
 }
 
@@ -43,3 +57,49 @@ impl pallet_identity::traits::OnRightKeyChange<Runtime> for OnRightKeyChangeHand
         };
     }
 }
+
+pub struct OnNewStrongCertHandler;
+impl pallet_certification::traits::OnNewcert<IdtyIndex> for OnNewStrongCertHandler {
+    fn on_new_cert(
+        _issuer: IdtyIndex,
+        _issuer_issued_count: u8,
+        receiver: IdtyIndex,
+        receiver_received_count: u32,
+    ) -> frame_support::dispatch::Weight {
+        let total_weight = 0;
+        match receiver_received_count {
+            MIN_STRONG_CERT_FOR_UD => {
+                // total_weight += Identity::WeightInfo::add_right();
+                let _ = Identity::validate_identity_and_add_rights(
+                    Origin::root(),
+                    receiver,
+                    sp_std::vec![IdtyRight::Ud],
+                );
+            }
+            MIN_STRONG_CERT_FOR_STRONG_CERT => {
+                // total_weight += Identity::WeightInfo::add_right();
+                let _ = Identity::add_right(Origin::root(), receiver, IdtyRight::StrongCert);
+            }
+            _ => {}
+        }
+        total_weight
+    }
+}
+
+pub struct OnRemovedStrongCertHandler;
+impl pallet_certification::traits::OnRemovedCert<IdtyIndex> for OnRemovedStrongCertHandler {
+    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 _ = Identity::del_right(Origin::root(), receiver, IdtyRight::Ud);
+        }
+        total_weight
+    }
+}
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 2e3423d19f9e4ed8edfd53969ceb11e4827334cf..5f5e8bcc19c02082ef8eedb521a25ef00ae70787 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -26,9 +26,9 @@ mod authorizations;
 mod entities;
 mod handlers;
 
-pub use crate::entities::{IdtyDid, IdtyRight, Planet};
+pub use crate::entities::{IdtyData, IdtyDid, IdtyRight, Planet};
 pub use pallet_balances::Call as BalancesCall;
-pub use pallet_identity::IdtyValue;
+pub use pallet_identity::{IdtyStatus, IdtyValue};
 pub use pallet_timestamp::Call as TimestampCall;
 use pallet_transaction_payment::CurrencyAdapter;
 pub use pallet_universal_dividend;
@@ -140,6 +140,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 ///
 /// Change this to adjust the block time.
 pub const MILLISECS_PER_BLOCK: u64 = 6000;
+pub const SECS_PER_BLOCK: u64 = MILLISECS_PER_BLOCK / 1_000;
 
 // NOTE: Currently it is not possible to change the slot duration after the chain has started.
 //       Attempting to do so will brick block production.
@@ -149,8 +150,9 @@ pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
 pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
 pub const HOURS: BlockNumber = MINUTES * 60;
 pub const DAYS: BlockNumber = HOURS * 24;
-pub const MONTHS: BlockNumber = DAYS * 30;
-pub const YEARS: BlockNumber = MONTHS * 12;
+const SECS_PER_YEAR: u64 = 31_557_600; // (365.25 * 24 * 60 * 60)
+pub const MONTHS: BlockNumber = (SECS_PER_YEAR / (12 * SECS_PER_BLOCK)) as BlockNumber;
+pub const YEARS: BlockNumber = (SECS_PER_YEAR / SECS_PER_BLOCK) as BlockNumber;
 
 /// The version information used to identify this runtime when compiled natively.
 #[cfg(feature = "std")]
@@ -321,7 +323,9 @@ impl pallet_sudo::Config for Runtime {
 
 parameter_types! {
     pub const ConfirmPeriod: BlockNumber = 12 * HOURS;
-    pub const MaxInactivityPeriod: BlockNumber = 1 * YEARS;
+    pub const MaxInactivityPeriod: BlockNumber = YEARS;
+    pub const MaxNoRightPeriod: BlockNumber = YEARS;
+    pub const IdtyRenewablePeriod: BlockNumber = 6 * MONTHS;
     pub const ValidationPeriod: BlockNumber = 2 * MONTHS;
 }
 
@@ -332,19 +336,42 @@ impl pallet_identity::Config for Runtime {
     type AddRightOrigin = EnsureRoot<Self::AccountId>;
     type DelRightOrigin = EnsureRoot<Self::AccountId>;
     type EnsureIdtyCallAllowed = crate::authorizations::EnsureIdtyCallAllowedImpl;
-    type IdtyData = ();
+    type IdtyData = IdtyData;
     type IdtyDid = IdtyDid;
     type IdtyIndex = IdtyIndex;
     type IdtyValidationOrigin = EnsureRoot<Self::AccountId>;
     type IdtyRight = IdtyRight;
-    type OnIdtyConfirmed = ();
-    type OnIdtyRemoved = ();
-    type OnIdtyValidated = crate::handlers::OnIdtyValidatedHandler;
+    type OnIdtyChange = crate::handlers::OnIdtyChangeHandler;
     type OnRightKeyChange = OnRightKeyChangeHandler;
     type MaxInactivityPeriod = MaxInactivityPeriod;
+    type MaxNoRightPeriod = MaxNoRightPeriod;
+    type RenewablePeriod = IdtyRenewablePeriod;
     type ValidationPeriod = ValidationPeriod;
 }
 
+// PALLET CERTIFICATION
+
+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;
+}
+
+/// Configure the pallet certification
+impl pallet_certification::Config for Runtime {
+    type AddCertOrigin = crate::authorizations::AddStrongCertOrigin;
+    type CertPeriod = CertPeriod;
+    type DelCertOrigin = crate::authorizations::DelStrongCertOrigin;
+    type Event = Event;
+    type IdtyIndex = IdtyIndex;
+    type MaxByIssuer = MaxByIssuer;
+    type OnNewcert = crate::handlers::OnNewStrongCertHandler;
+    type OnRemovedCert = crate::handlers::OnRemovedStrongCertHandler;
+    type RenewablePeriod = StrongCertRenewablePeriod;
+    type ValidityPeriod = ValidityPeriod;
+}
+
 // PALLET UNIVERSAL DIVIDEND
 
 parameter_types! {
@@ -365,7 +392,7 @@ impl Get<Vec<AccountId>> for UdAccountsProvider {
 
 /// Configure the pallet universal-dividend in pallets/universal-dividend.
 impl pallet_universal_dividend::Config for Runtime {
-    const UD_CREATION_PERIOD: Self::BlockNumber = 10;
+    const UD_CREATION_PERIOD: Self::BlockNumber = 20;
     const UD_REEVAL_PERIOD: Balance = 10;
     const UD_REEVAL_PERIOD_IN_BLOCKS: Self::BlockNumber =
         Self::UD_CREATION_PERIOD * Self::UD_REEVAL_PERIOD as Self::BlockNumber;
@@ -398,6 +425,7 @@ construct_runtime!(
         UdAccountsStorage: pallet_ud_accounts_storage::{Pallet, Config<T>, Storage},
         UniversalDividend: pallet_universal_dividend::{Pallet, Config<T>, Storage, Event<T>},
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>},
+        StrongCert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>},
     }
 );
 
diff --git a/types-bundle/types_definition.json b/types-bundle/types_definition.json
index defb1c71896dd263841348742d7090ec59928664..d9d3f34bfac2deb48c78402f489d48a84cb77067 100644
--- a/types-bundle/types_definition.json
+++ b/types-bundle/types_definition.json
@@ -1,9 +1,16 @@
 {
     "Balance": "u64",
-    "Planet": {
-        "_enum": [
-            "Earth"
-        ]
+    "CertValue": {
+        "chainable_on": "BlockNumber",
+        "removable_on": "BlockNumber"
+    },
+    "IdtyCertMeta": {
+        "issued_count": "u8",
+        "next_issuable_on": "BlockNumber",
+        "received_count": "u32"
+    },
+    "IdtyData": {
+        "can_create_on": "BlockNumber"
     },
     "IdtyCertMeta": {
         "issued_count": "u8",
@@ -34,9 +41,17 @@
     },
     "IdtyValue": {
         "did": "IdtyDid",
+        "expire_on": "BlockNumber",
         "owner_key": "AccountId",
-        "removable_on": "Option<BlockNumber>",
+        "removable_on": "BlockNumber",
+        "renewable_on": "BlockNumber",
         "rights": "Vec<(T::IdtyRight, Option<T::AccountId>)>",
         "status": "IdtyStatus",
+        "data":  "IdtyData"
+    },
+    "Planet": {
+        "_enum": [
+            "Earth"
+        ]
     }
 }