From 168228a51a33414e6db24bb3e9ca763afeafd7d7 Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Sun, 20 Feb 2022 02:34:38 +0100
Subject: [PATCH] feat(runtimes): add account random id & provide randomness
 calls

---
 Cargo.lock                              |  42 ++++
 node/src/chain_spec/gdev.rs             |  16 +-
 node/src/chain_spec/gen_genesis_data.rs |   9 +-
 pallets/authority-members/src/lib.rs    |   8 +-
 pallets/authority-members/src/mock.rs   |   1 +
 pallets/authority-members/src/traits.rs |  11 +
 pallets/duniter-account/Cargo.toml      | 104 +++++++++
 pallets/duniter-account/src/lib.rs      | 253 +++++++++++++++++++++
 pallets/duniter-account/src/types.rs    |  48 ++++
 pallets/duniter-wot/src/lib.rs          |   8 +-
 pallets/duniter-wot/src/mock.rs         |  87 ++++---
 pallets/duniter-wot/src/tests.rs        |  22 +-
 pallets/identity/src/lib.rs             |   8 +-
 pallets/identity/src/mock.rs            |  23 +-
 pallets/identity/src/tests.rs           |  12 +-
 pallets/identity/src/types.rs           |   2 +-
 pallets/provide-randomness/Cargo.toml   |  75 ++++++
 pallets/provide-randomness/src/lib.rs   | 290 ++++++++++++++++++++++++
 pallets/provide-randomness/src/types.rs |  36 +++
 resources/metadata.scale                | Bin 99619 -> 112264 bytes
 runtime/common/Cargo.toml               |   4 +
 runtime/common/src/handlers.rs          |  27 +--
 runtime/common/src/pallets_config.rs    |  27 ++-
 runtime/g1/Cargo.toml                   |   7 +-
 runtime/g1/src/lib.rs                   |  19 +-
 runtime/gdev/Cargo.toml                 |   4 +
 runtime/gdev/src/lib.rs                 |  18 +-
 runtime/gdev/tests/integration_tests.rs |   4 +-
 runtime/gtest/Cargo.toml                |   7 +-
 runtime/gtest/src/lib.rs                |  16 +-
 30 files changed, 1057 insertions(+), 131 deletions(-)
 create mode 100644 pallets/duniter-account/Cargo.toml
 create mode 100644 pallets/duniter-account/src/lib.rs
 create mode 100644 pallets/duniter-account/src/types.rs
 create mode 100644 pallets/provide-randomness/Cargo.toml
 create mode 100644 pallets/provide-randomness/src/lib.rs
 create mode 100644 pallets/provide-randomness/src/types.rs

diff --git a/Cargo.lock b/Cargo.lock
index ce9d5ea77..ef4a5bba7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -833,9 +833,11 @@ dependencies = [
  "pallet-authority-members",
  "pallet-balances",
  "pallet-certification",
+ "pallet-duniter-account",
  "pallet-duniter-wot",
  "pallet-identity",
  "pallet-membership",
+ "pallet-provide-randomness",
  "pallet-session",
  "pallet-ud-accounts-storage",
  "parity-scale-codec",
@@ -1953,6 +1955,7 @@ dependencies = [
  "pallet-balances",
  "pallet-certification",
  "pallet-collective",
+ "pallet-duniter-account",
  "pallet-duniter-wot",
  "pallet-grandpa",
  "pallet-identity",
@@ -1960,6 +1963,7 @@ dependencies = [
  "pallet-membership",
  "pallet-multisig",
  "pallet-offences",
+ "pallet-provide-randomness",
  "pallet-proxy",
  "pallet-scheduler",
  "pallet-session",
@@ -2011,6 +2015,7 @@ dependencies = [
  "pallet-balances",
  "pallet-certification",
  "pallet-collective",
+ "pallet-duniter-account",
  "pallet-duniter-test-parameters",
  "pallet-duniter-wot",
  "pallet-grandpa",
@@ -2019,6 +2024,7 @@ dependencies = [
  "pallet-membership",
  "pallet-multisig",
  "pallet-offences",
+ "pallet-provide-randomness",
  "pallet-proxy",
  "pallet-scheduler",
  "pallet-session",
@@ -2212,6 +2218,7 @@ dependencies = [
  "pallet-balances",
  "pallet-certification",
  "pallet-collective",
+ "pallet-duniter-account",
  "pallet-duniter-wot",
  "pallet-grandpa",
  "pallet-identity",
@@ -2219,6 +2226,7 @@ dependencies = [
  "pallet-membership",
  "pallet-multisig",
  "pallet-offences",
+ "pallet-provide-randomness",
  "pallet-proxy",
  "pallet-scheduler",
  "pallet-session",
@@ -4418,6 +4426,25 @@ dependencies = [
  "sp-std",
 ]
 
+[[package]]
+name = "pallet-duniter-account"
+version = "3.0.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "maplit",
+ "pallet-balances",
+ "pallet-provide-randomness",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
 [[package]]
 name = "pallet-duniter-test-parameters"
 version = "3.0.0"
@@ -4571,6 +4598,21 @@ dependencies = [
  "sp-std",
 ]
 
+[[package]]
+name = "pallet-provide-randomness"
+version = "3.0.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
 [[package]]
 name = "pallet-proxy"
 version = "4.0.0-dev"
diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs
index c85139721..2e0e830ce 100644
--- a/node/src/chain_spec/gdev.rs
+++ b/node/src/chain_spec/gdev.rs
@@ -18,10 +18,10 @@ use super::*;
 use common_runtime::constants::*;
 use common_runtime::*;
 use gdev_runtime::{
-    opaque::SessionKeys, AccountId, AuthorityMembersConfig, BabeConfig, BalancesConfig, CertConfig,
-    GenesisConfig, IdentityConfig, ImOnlineId, MembershipConfig, ParametersConfig, SessionConfig,
-    SmithsCertConfig, SmithsMembershipConfig, SudoConfig, SystemConfig, UdAccountsStorageConfig,
-    UniversalDividendConfig, WASM_BINARY,
+    opaque::SessionKeys, AccountConfig, AccountId, AuthorityMembersConfig, BabeConfig,
+    BalancesConfig, CertConfig, GenesisConfig, IdentityConfig, ImOnlineId, MembershipConfig,
+    ParametersConfig, SessionConfig, SmithsCertConfig, SmithsMembershipConfig, SudoConfig,
+    SystemConfig, UdAccountsStorageConfig, UniversalDividendConfig, WASM_BINARY,
 };
 use sc_service::ChainType;
 use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
@@ -239,6 +239,12 @@ fn gen_genesis_conf(
             // Add Wasm runtime to storage.
             code: wasm_binary.to_vec(),
         },
+        account: AccountConfig {
+            accounts: initial_identities
+                .iter()
+                .map(|(_, owner_key)| owner_key.clone())
+                .collect(),
+        },
         parameters: ParametersConfig {
             parameters: GenesisParameters {
                 babe_epoch_duration,
@@ -396,6 +402,7 @@ fn genesis_data_to_gdev_genesis_conf(
     wasm_binary: &[u8],
 ) -> gdev_runtime::GenesisConfig {
     let super::gen_genesis_data::GenesisData {
+        accounts,
         balances,
         certs_by_issuer,
         first_ud,
@@ -416,6 +423,7 @@ fn genesis_data_to_gdev_genesis_conf(
             // Add Wasm runtime to storage.
             code: wasm_binary.to_vec(),
         },
+        account: AccountConfig { accounts },
         parameters: ParametersConfig { parameters },
         authority_discovery: Default::default(),
         authority_members: AuthorityMembersConfig {
diff --git a/node/src/chain_spec/gen_genesis_data.rs b/node/src/chain_spec/gen_genesis_data.rs
index 62d63d952..1176adc1e 100644
--- a/node/src/chain_spec/gen_genesis_data.rs
+++ b/node/src/chain_spec/gen_genesis_data.rs
@@ -17,12 +17,13 @@
 use common_runtime::*;
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
 use sp_core::Decode;
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, BTreeSet};
 
 type MembershipData = sp_membership::MembershipData<u32>;
 
 #[derive(Clone)]
 pub struct GenesisData<Parameters: DeserializeOwned, SessionKeys: Decode> {
+    pub accounts: BTreeSet<AccountId>,
     pub balances: Vec<(AccountId, u64)>,
     pub certs_by_issuer: BTreeMap<u32, BTreeMap<u32, u32>>,
     pub first_ud: u64,
@@ -137,6 +138,7 @@ where
 
     // MONEY AND WOT //
 
+    let mut accounts = BTreeSet::new();
     let mut balances = Vec::new();
     let mut identities_ = Vec::with_capacity(identities.len());
     let mut idty_index: u32 = 1;
@@ -152,6 +154,10 @@ where
         // Money
         if identity.balance >= 100 {
             balances.push((identity.pubkey.clone(), identity.balance));
+        } else {
+            // If an identity has no currency in genesis, its account will not be created,
+            // so it must be created explicitly
+            accounts.insert(identity.pubkey.clone());
         }
         // We must count the money under the existential deposit because what we count is
         // the monetary mass created (for the revaluation of the DU)
@@ -241,6 +247,7 @@ where
     }
 
     let genesis_data = GenesisData {
+        accounts,
         balances,
         certs_by_issuer,
         first_ud,
diff --git a/pallets/authority-members/src/lib.rs b/pallets/authority-members/src/lib.rs
index cb0d6dbbb..f4e5707bc 100644
--- a/pallets/authority-members/src/lib.rs
+++ b/pallets/authority-members/src/lib.rs
@@ -32,6 +32,7 @@ mod benchmarking;*/
 pub use pallet::*;
 pub use types::*;
 
+use self::traits::*;
 use frame_support::traits::Get;
 use sp_runtime::traits::Convert;
 use sp_staking::SessionIndex;
@@ -40,7 +41,6 @@ use sp_std::prelude::*;
 #[frame_support::pallet]
 pub mod pallet {
     use super::*;
-    use crate::traits::OnRemovedMember;
     use frame_support::pallet_prelude::*;
     use frame_support::traits::ValidatorRegistration;
     use frame_support::traits::{StorageVersion, UnfilteredDispatchable};
@@ -66,6 +66,7 @@ pub mod pallet {
         type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
         type KeysWrapper: Parameter + Into<Self::Keys>;
         type IsMember: IsMember<Self::MemberId>;
+        type OnNewSession: OnNewSession;
         type OnRemovedMember: OnRemovedMember<Self::MemberId>;
         /// Max number of authorities allowed
         #[pallet::constant]
@@ -335,10 +336,6 @@ pub mod pallet {
         ) -> DispatchResultWithPostInfo {
             T::RemoveMemberOrigin::ensure_origin(origin)?;
 
-            if !T::IsMember::is_member(&member_id) {
-                return Err(Error::<T>::NotMember.into());
-            }
-
             let member_data = Members::<T>::get(member_id).ok_or(Error::<T>::NotMember)?;
             Self::do_remove_member(member_id, member_data.owner_key);
 
@@ -572,6 +569,7 @@ impl<T: Config> pallet_session::SessionManager<T::ValidatorId> for Pallet<T> {
     /// The session start to be used for validation.
     fn start_session(start_index: SessionIndex) {
         Self::expire_memberships(start_index);
+        T::OnNewSession::on_new_session(start_index);
     }
 }
 
diff --git a/pallets/authority-members/src/mock.rs b/pallets/authority-members/src/mock.rs
index 6f499362f..0d1ae96c8 100644
--- a/pallets/authority-members/src/mock.rs
+++ b/pallets/authority-members/src/mock.rs
@@ -156,6 +156,7 @@ impl pallet_authority_members::Config for Test {
     type MaxOfflineSessions = ConstU32<2>;
     type MemberId = u64;
     type MemberIdOf = ConvertInto;
+    type OnNewSession = ();
     type OnRemovedMember = ();
     type RemoveMemberOrigin = system::EnsureRoot<u64>;
 }
diff --git a/pallets/authority-members/src/traits.rs b/pallets/authority-members/src/traits.rs
index 1d6b05555..1cfb55dcf 100644
--- a/pallets/authority-members/src/traits.rs
+++ b/pallets/authority-members/src/traits.rs
@@ -14,8 +14,19 @@
 // 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::SessionIndex;
 use frame_support::pallet_prelude::Weight;
 
+pub trait OnNewSession {
+    fn on_new_session(index: SessionIndex) -> Weight;
+}
+
+impl OnNewSession for () {
+    fn on_new_session(_: SessionIndex) -> Weight {
+        0
+    }
+}
+
 pub trait OnRemovedMember<MemberId> {
     fn on_removed_member(member_id: MemberId) -> Weight;
 }
diff --git a/pallets/duniter-account/Cargo.toml b/pallets/duniter-account/Cargo.toml
new file mode 100644
index 000000000..c4f48360f
--- /dev/null
+++ b/pallets/duniter-account/Cargo.toml
@@ -0,0 +1,104 @@
+[package]
+authors = ['librelois <c@elo.tf>']
+description = 'FRAME pallet duniter account.'
+edition = '2018'
+homepage = 'https://substrate.dev'
+license = 'AGPL-3.0'
+name = 'pallet-duniter-account'
+readme = 'README.md'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '3.0.0'
+
+[features]
+default = ['std']
+runtime-benchmarks = ['frame-benchmarking']
+std = [
+    'codec/std',
+    'frame-support/std',
+    'frame-system/std',
+    'frame-benchmarking/std',
+    'pallet-balances/std',
+    'pallet-provide-randomness/std',
+    'serde',
+    'sp-core/std',
+    'sp-io/std',
+    'sp-runtime/std',
+	'sp-std/std',
+]
+try-runtime = ['frame-support/try-runtime']
+
+[dependencies]
+# local
+pallet-provide-randomness = { path = "../provide-randomness", default-features = false }
+
+# crates.io
+codec = { package = 'parity-scale-codec', version = "2.3.1", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+
+# substrate
+[dependencies.frame-benchmarking]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+optional = true
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.frame-support]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.frame-system]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.pallet-balances]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.serde]
+version = "1.0.101"
+optional = true
+features = ["derive"]
+
+[dependencies.sp-core]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.sp-io]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
+
+### DEV ###
+
+[dev-dependencies.pallet-balances]
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dev-dependencies.maplit]
+version = '1.0.2'
+
+[dev-dependencies.serde]
+version = '1.0.119'
+
+[dev-dependencies.sp-io]
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
diff --git a/pallets/duniter-account/src/lib.rs b/pallets/duniter-account/src/lib.rs
new file mode 100644
index 000000000..85991c6ed
--- /dev/null
+++ b/pallets/duniter-account/src/lib.rs
@@ -0,0 +1,253 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+mod types;
+
+pub use pallet::*;
+pub use types::*;
+
+use frame_support::pallet_prelude::*;
+use frame_support::traits::{OnUnbalanced, StoredMap};
+use frame_system::pallet_prelude::*;
+use pallet_provide_randomness::RequestId;
+use sp_core::H256;
+use sp_runtime::traits::{Convert, Saturating, Zero};
+
+#[frame_support::pallet]
+pub mod pallet {
+    use super::*;
+    use frame_support::traits::{Currency, ExistenceRequirement, StorageVersion};
+
+    /// The current storage version.
+    const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
+    #[pallet::pallet]
+    #[pallet::generate_store(pub(super) trait Store)]
+    #[pallet::storage_version(STORAGE_VERSION)]
+    #[pallet::without_storage_info]
+    pub struct Pallet<T>(_);
+
+    // CONFIG //
+
+    #[pallet::config]
+    pub trait Config:
+        frame_system::Config<AccountData = AccountData<Self::Balance>>
+        + pallet_balances::Config
+        + pallet_provide_randomness::Config<Currency = pallet_balances::Pallet<Self>>
+    {
+        type AccountIdToSalt: Convert<Self::AccountId, [u8; 32]>;
+        /// The overarching event type.
+        type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
+        type MaxNewAccountsPerBlock: Get<u32>;
+        type NewAccountPrice: Get<Self::Balance>;
+    }
+
+    // STORAGE //
+
+    #[pallet::storage]
+    #[pallet::getter(fn pending_random_id_assignments)]
+    pub type PendingRandomIdAssignments<T: Config> =
+        StorageMap<_, Twox64Concat, RequestId, T::AccountId, OptionQuery>;
+
+    #[pallet::storage]
+    #[pallet::getter(fn pending_new_accounts)]
+    pub type PendingNewAccounts<T: Config> =
+        StorageMap<_, Blake2_128Concat, T::AccountId, (), OptionQuery>;
+
+    // GENESIS STUFF //
+
+    #[pallet::genesis_config]
+    pub struct GenesisConfig<T: Config> {
+        pub accounts: sp_std::collections::btree_set::BTreeSet<T::AccountId>,
+    }
+
+    #[cfg(feature = "std")]
+    impl<T: Config> Default for GenesisConfig<T> {
+        fn default() -> Self {
+            Self {
+                accounts: Default::default(),
+            }
+        }
+    }
+
+    #[pallet::genesis_build]
+    impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
+        fn build(&self) {
+            for account_id in &self.accounts {
+                PendingNewAccounts::<T>::insert(account_id.clone(), ());
+            }
+        }
+    }
+
+    // EVENTS //
+
+    #[pallet::event]
+    #[pallet::generate_deposit(pub(super) fn deposit_event)]
+    pub enum Event<T: Config> {
+        /// Random id assigned
+        /// [account_id, random_id]
+        RandomIdAssigned {
+            account_id: T::AccountId,
+            random_id: H256,
+        },
+    }
+
+    // HOOKS //
+    #[pallet::hooks]
+    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+        fn on_initialize(_: T::BlockNumber) -> Weight {
+            let mut total_weight = 0;
+            for account_id in PendingNewAccounts::<T>::iter_keys()
+                .drain()
+                .take(T::MaxNewAccountsPerBlock::get() as usize)
+            {
+                if frame_system::Pallet::<T>::sufficients(&account_id) > 0 {
+                    // If the account is self-sufficient, it is exempt from account creation fees
+                    let request_id = pallet_provide_randomness::Pallet::<T>::force_request(
+                        pallet_provide_randomness::RandomnessType::RandomnessFromTwoEpochsAgo,
+                        H256(T::AccountIdToSalt::convert(account_id.clone())),
+                    );
+                    PendingRandomIdAssignments::<T>::insert(request_id, account_id);
+                    total_weight += 100_000;
+                } else {
+                    // If the account is not self-sufficient, it must pay the account creation fees
+                    frame_system::Pallet::<T>::inc_providers(&account_id);
+                    let res = T::Currency::withdraw(
+                        &account_id,
+                        T::NewAccountPrice::get(),
+                        frame_support::traits::WithdrawReasons::FEE,
+                        ExistenceRequirement::KeepAlive,
+                    );
+                    if let Ok(imbalance) = res {
+                        // The fees have been collected, we handle the collected amount and we
+                        // request the random id
+                        T::OnUnbalanced::on_unbalanced(imbalance);
+                        let request_id = pallet_provide_randomness::Pallet::<T>::force_request(
+                            pallet_provide_randomness::RandomnessType::RandomnessFromTwoEpochsAgo,
+                            H256(T::AccountIdToSalt::convert(account_id.clone())),
+                        );
+                        PendingRandomIdAssignments::<T>::insert(request_id, account_id);
+                        total_weight += 200_000;
+                    } else {
+                        // The charges could not be deducted, we slash the account
+                        let account_data = frame_system::Pallet::<T>::get(&account_id);
+                        let (imbalance, rest) = pallet_balances::Pallet::<T>::slash(
+                            &account_id,
+                            account_data.free.saturating_add(account_data.reserved),
+                        );
+                        debug_assert!(rest.is_zero());
+                        T::OnUnbalanced::on_unbalanced(imbalance);
+                        total_weight += 300_000;
+                    }
+                }
+            }
+            total_weight
+        }
+    }
+}
+
+impl<T> pallet_provide_randomness::OnFilledRandomness for Pallet<T>
+where
+    T: Config,
+{
+    fn on_filled_randomness(request_id: RequestId, randomness: H256) -> Weight {
+        if let Some(account_id) = PendingRandomIdAssignments::<T>::take(request_id) {
+            // Can only fail if the account has been deleted in the meantime,
+            // but this case does not require any processing
+            let res = frame_system::Pallet::<T>::mutate_exists(&account_id, |maybe_account_data| {
+                if let Some(ref mut account_data) = maybe_account_data {
+                    account_data.random_id = Some(randomness);
+                }
+            });
+            if res.is_ok() {
+                Self::deposit_event(Event::RandomIdAssigned {
+                    account_id,
+                    random_id: randomness,
+                });
+            }
+            200_000
+        } else {
+            100_000
+        }
+    }
+}
+
+impl<T, AccountId, Balance>
+    frame_support::traits::StoredMap<AccountId, pallet_balances::AccountData<Balance>> for Pallet<T>
+where
+    AccountId: Parameter
+        + Member
+        + MaybeSerializeDeserialize
+        + core::fmt::Debug
+        + sp_runtime::traits::MaybeDisplay
+        + Ord
+        + Into<[u8; 32]>
+        + codec::MaxEncodedLen,
+    Balance: Parameter
+        + Member
+        + sp_runtime::traits::AtLeast32BitUnsigned
+        + codec::Codec
+        + Default
+        + Copy
+        + MaybeSerializeDeserialize
+        + core::fmt::Debug
+        + codec::MaxEncodedLen
+        + scale_info::TypeInfo,
+    T: Config
+        + frame_system::Config<AccountId = AccountId, AccountData = AccountData<Balance>>
+        + pallet_balances::Config<Balance = Balance>
+        + pallet_provide_randomness::Config,
+{
+    fn get(k: &AccountId) -> pallet_balances::AccountData<Balance> {
+        frame_system::Account::<T>::get(k).data.into()
+    }
+
+    fn try_mutate_exists<R, E: From<sp_runtime::DispatchError>>(
+        account_id: &AccountId,
+        f: impl FnOnce(&mut Option<pallet_balances::AccountData<Balance>>) -> Result<R, E>,
+    ) -> Result<R, E> {
+        let account = frame_system::Account::<T>::get(account_id);
+        let was_providing = account.data != Default::default();
+        let mut some_data = if was_providing {
+            Some(account.data.into())
+        } else {
+            None
+        };
+        let result = f(&mut some_data)?;
+        let is_providing = some_data.is_some();
+        if !was_providing && is_providing {
+            // If the account does not exist, we should program its creation
+            if !frame_system::Pallet::<T>::account_exists(account_id) {
+                PendingNewAccounts::<T>::insert(account_id, ());
+            }
+        } else if was_providing && !is_providing {
+            match frame_system::Pallet::<T>::dec_providers(account_id)? {
+                frame_system::DecRefStatus::Reaped => return Ok(result),
+                frame_system::DecRefStatus::Exists => {
+                    // Update value as normal...
+                }
+            }
+        } else if !was_providing && !is_providing {
+            return Ok(result);
+        }
+        frame_system::Account::<T>::mutate(account_id, |a| {
+            a.data.set_balances(some_data.unwrap_or_default())
+        });
+        Ok(result)
+    }
+}
diff --git a/pallets/duniter-account/src/types.rs b/pallets/duniter-account/src/types.rs
new file mode 100644
index 000000000..92d5494db
--- /dev/null
+++ b/pallets/duniter-account/src/types.rs
@@ -0,0 +1,48 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+use codec::{Decode, Encode, MaxEncodedLen};
+use frame_support::pallet_prelude::*;
+use scale_info::TypeInfo;
+use sp_core::H256;
+use sp_runtime::traits::Zero;
+
+#[derive(Clone, Decode, Default, Encode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
+pub struct AccountData<Balance> {
+    pub(super) random_id: Option<H256>,
+    pub(super) free: Balance,
+    pub(super) reserved: Balance,
+    fee_frozen: Balance,
+}
+
+impl<Balance: Zero> AccountData<Balance> {
+    pub fn set_balances(&mut self, new_balances: pallet_balances::AccountData<Balance>) {
+        self.free = new_balances.free;
+        self.reserved = new_balances.reserved;
+        self.fee_frozen = new_balances.fee_frozen;
+    }
+}
+
+impl<Balance: Zero> From<AccountData<Balance>> for pallet_balances::AccountData<Balance> {
+    fn from(account_data: AccountData<Balance>) -> Self {
+        Self {
+            free: account_data.free,
+            reserved: account_data.reserved,
+            misc_frozen: Zero::zero(),
+            fee_frozen: account_data.fee_frozen,
+        }
+    }
+}
diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs
index 161ce0b5e..90689c4c4 100644
--- a/pallets/duniter-wot/src/lib.rs
+++ b/pallets/duniter-wot/src/lib.rs
@@ -115,7 +115,7 @@ pub mod pallet {
             if !T::IsSubWot::get() {
                 if let Err(e) = idty_call.dispatch_bypass_filter(RawOrigin::Root.into()) {
                     sp_std::if_std! {
-                        println!("{:?}", e)
+                        println!("fail to dispatch idty call: {:?}", e)
                     }
                     return false;
                 }
@@ -269,7 +269,7 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall
                     true,
                 ) {
                     sp_std::if_std! {
-                        println!("{:?}", e)
+                        println!("fail to force add cert: {:?}", e)
                     }
                 }
             }
@@ -304,7 +304,7 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnNewcert<IdtyIndex
                     Some(receiver),
                 ) {
                     sp_std::if_std! {
-                        println!("{:?}", e)
+                        println!("fail to claim membership: {:?}", e)
                     }
                 }
             } else {
@@ -344,7 +344,7 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyI
                 Some(receiver),
             ) {
                 sp_std::if_std! {
-                    println!("{:?}", e)
+                    println!("fail to revoke membership: {:?}", e)
                 }
             }
         }
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
index da821daa4..123dbf7de 100644
--- a/pallets/duniter-wot/src/mock.rs
+++ b/pallets/duniter-wot/src/mock.rs
@@ -22,7 +22,6 @@ use sp_core::H256;
 use sp_runtime::{
     testing::Header,
     traits::{BlakeTwo256, IdentityLookup},
-    BuildStorage,
 };
 use std::collections::BTreeMap;
 
@@ -45,7 +44,7 @@ frame_support::construct_runtime!(
     }
 );
 
-// Sstem
+// System
 parameter_types! {
     pub const BlockHashCount: u64 = 250;
     pub const SS58Prefix: u8 = 42;
@@ -170,43 +169,57 @@ pub const NAMES: [&str; 6] = ["Alice", "Bob", "Charlie", "Dave", "Eve", "Ferdie"
 
 // Build genesis storage according to the mock runtime.
 pub fn new_test_ext(initial_identities_len: usize) -> sp_io::TestExternalities {
-    GenesisConfig {
-        system: SystemConfig::default(),
-        identity: IdentityConfig {
-            identities: (1..=initial_identities_len)
-                .map(|i| pallet_identity::GenesisIdty {
-                    index: i as u32,
-                    name: pallet_identity::IdtyName::from(NAMES[i - 1]),
-                    value: pallet_identity::IdtyValue {
-                        next_creatable_identity_on: 0,
-                        owner_key: i as u64,
-                        removable_on: 0,
-                        status: pallet_identity::IdtyStatus::Validated,
+    let mut t = frame_system::GenesisConfig::default()
+        .build_storage::<Test>()
+        .unwrap();
+
+    pallet_identity::GenesisConfig::<Test> {
+        identities: (1..=initial_identities_len)
+            .map(|i| pallet_identity::GenesisIdty {
+                index: i as u32,
+                name: pallet_identity::IdtyName::from(NAMES[i - 1]),
+                value: pallet_identity::IdtyValue {
+                    next_creatable_identity_on: 0,
+                    owner_key: i as u64,
+                    removable_on: 0,
+                    status: pallet_identity::IdtyStatus::Validated,
+                },
+            })
+            .collect(),
+    }
+    .assimilate_storage(&mut t)
+    .unwrap();
+
+    pallet_membership::GenesisConfig::<Test, Instance1> {
+        memberships: (1..=initial_identities_len)
+            .map(|i| {
+                (
+                    i as u32,
+                    sp_membership::MembershipData {
+                        expire_on: MembershipPeriod::get(),
+                        renewable_on: RenewablePeriod::get(),
                     },
-                })
-                .collect(),
-        },
-        membership: MembershipConfig {
-            memberships: (1..=initial_identities_len)
-                .map(|i| {
-                    (
-                        i as u32,
-                        sp_membership::MembershipData {
-                            expire_on: MembershipPeriod::get(),
-                            renewable_on: RenewablePeriod::get(),
-                        },
-                    )
-                })
-                .collect(),
-        },
-        cert: CertConfig {
-            certs_by_issuer: clique_wot(initial_identities_len, ValidityPeriod::get()),
-            apply_cert_period_at_genesis: true,
-        },
+                )
+            })
+            .collect(),
+    }
+    .assimilate_storage(&mut t)
+    .unwrap();
+
+    pallet_certification::GenesisConfig::<Test, Instance1> {
+        certs_by_issuer: clique_wot(initial_identities_len, ValidityPeriod::get()),
+        apply_cert_period_at_genesis: true,
     }
-    .build_storage()
-    .unwrap()
-    .into()
+    .assimilate_storage(&mut t)
+    .unwrap();
+
+    frame_support::BasicExternalities::execute_with_storage(&mut t, || {
+        // Some dedicated test account
+        frame_system::Pallet::<Test>::inc_providers(&(initial_identities_len as u64));
+        frame_system::Pallet::<Test>::inc_providers(&(initial_identities_len as u64 + 1));
+    });
+
+    sp_io::TestExternalities::new(t)
 }
 
 pub fn run_to_block(n: u64) {
diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs
index e9f6f4c63..42f255fa8 100644
--- a/pallets/duniter-wot/src/tests.rs
+++ b/pallets/duniter-wot/src/tests.rs
@@ -60,17 +60,9 @@ fn test_create_idty_ok() {
         assert_ok!(Identity::create_identity(Origin::signed(1), 6));
         // 2 events should have occurred: IdtyCreated and NewCert
         let events = System::events();
-        assert_eq!(events.len(), 3);
+        assert_eq!(events.len(), 2);
         assert_eq!(
             events[0],
-            EventRecord {
-                phase: Phase::Initialization,
-                event: Event::System(frame_system::Event::NewAccount { account: 6 }),
-                topics: vec![],
-            }
-        );
-        assert_eq!(
-            events[1],
             EventRecord {
                 phase: Phase::Initialization,
                 event: Event::Identity(pallet_identity::Event::IdtyCreated {
@@ -81,7 +73,7 @@ fn test_create_idty_ok() {
             }
         );
         assert_eq!(
-            events[2],
+            events[1],
             EventRecord {
                 phase: Phase::Initialization,
                 event: Event::Cert(pallet_certification::Event::NewCert {
@@ -222,7 +214,7 @@ fn test_idty_membership_expire_them_requested() {
         run_to_block(5);
         assert!(Membership::membership(3).is_none());
         let events = System::events();
-        assert_eq!(events.len(), 3);
+        assert_eq!(events.len(), 2);
         assert_eq!(
             events[0],
             EventRecord {
@@ -233,14 +225,6 @@ fn test_idty_membership_expire_them_requested() {
         );
         assert_eq!(
             events[1],
-            EventRecord {
-                phase: Phase::Initialization,
-                event: Event::System(frame_system::Event::KilledAccount { account: 3 }),
-                topics: vec![],
-            }
-        );
-        assert_eq!(
-            events[2],
             EventRecord {
                 phase: Phase::Initialization,
                 event: Event::Identity(pallet_identity::Event::IdtyRemoved { idty_index: 3 }),
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index 76d59fd84..00f0ed190 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -144,7 +144,6 @@ pub mod pallet {
                         (idty_index, idty.value.status),
                     )
                 }
-                // frame_system::Pallet::<T>::dec_providers(&account);
                 frame_system::Pallet::<T>::inc_sufficients(&idty.value.owner_key);
                 <Identities<T>>::insert(idty_index, idty.value.clone());
                 IdentitiesNames::<T>::insert(idty.name.clone(), ());
@@ -244,6 +243,11 @@ pub mod pallet {
             let creator_idty_val =
                 Identities::<T>::try_get(&creator).map_err(|_| Error::<T>::IdtyNotFound)?;
 
+            ensure!(
+                frame_system::Pallet::<T>::account_exists(&owner_key),
+                Error::<T>::OwnerAccountNotExist
+            );
+
             if IdentityIndexOf::<T>::contains_key(&owner_key) {
                 return Err(Error::<T>::IdtyAlreadyCreated.into());
             }
@@ -453,6 +457,8 @@ pub mod pallet {
         RightNotExist,
         /// Not respect IdtyCreationPeriod
         NotRespectIdtyCreationPeriod,
+        /// Owner account not exist
+        OwnerAccountNotExist,
     }
 
     // PUBLIC FUNCTIONS //
diff --git a/pallets/identity/src/mock.rs b/pallets/identity/src/mock.rs
index 3d5103e1d..7a19d32d3 100644
--- a/pallets/identity/src/mock.rs
+++ b/pallets/identity/src/mock.rs
@@ -18,14 +18,13 @@ use super::*;
 use crate::{self as pallet_identity};
 use frame_support::{
     parameter_types,
-    traits::{Everything, OnFinalize, OnInitialize},
+    traits::{Everything, GenesisBuild, OnFinalize, OnInitialize},
 };
 use frame_system as system;
 use sp_core::H256;
 use sp_runtime::{
     testing::Header,
     traits::{BlakeTwo256, IdentityLookup, IsMember},
-    BuildStorage,
 };
 
 type AccountId = u64;
@@ -115,13 +114,19 @@ impl pallet_identity::Config for Test {
 
 // Build genesis storage according to the mock runtime.
 pub fn new_test_ext(gen_conf: pallet_identity::GenesisConfig<Test>) -> sp_io::TestExternalities {
-    GenesisConfig {
-        system: SystemConfig::default(),
-        identity: gen_conf,
-    }
-    .build_storage()
-    .unwrap()
-    .into()
+    let mut t = frame_system::GenesisConfig::default()
+        .build_storage::<Test>()
+        .unwrap();
+
+    gen_conf.assimilate_storage(&mut t).unwrap();
+
+    frame_support::BasicExternalities::execute_with_storage(&mut t, || {
+        // Some dedicated test account
+        frame_system::Pallet::<Test>::inc_providers(&2);
+        frame_system::Pallet::<Test>::inc_providers(&3);
+    });
+
+    sp_io::TestExternalities::new(t)
 }
 
 pub fn run_to_block(n: u64) {
diff --git a/pallets/identity/src/tests.rs b/pallets/identity/src/tests.rs
index 462c437ae..885b1cd00 100644
--- a/pallets/identity/src/tests.rs
+++ b/pallets/identity/src/tests.rs
@@ -57,9 +57,9 @@ fn test_create_identity_ok() {
         // Alice should be able te create an identity
         assert_ok!(Identity::create_identity(Origin::signed(1), 2));
         let events = System::events();
-        assert_eq!(events.len(), 2);
+        assert_eq!(events.len(), 1);
         assert_eq!(
-            events[1],
+            events[0],
             EventRecord {
                 phase: Phase::Initialization,
                 event: Event::Identity(crate::Event::IdtyCreated {
@@ -84,9 +84,9 @@ fn test_idty_creation_period() {
         // Alice should be able te create an identity
         assert_ok!(Identity::create_identity(Origin::signed(1), 2));
         let events = System::events();
-        assert_eq!(events.len(), 2);
+        assert_eq!(events.len(), 1);
         assert_eq!(
-            events[1],
+            events[0],
             EventRecord {
                 phase: Phase::Initialization,
                 event: Event::Identity(crate::Event::IdtyCreated {
@@ -109,9 +109,9 @@ fn test_idty_creation_period() {
         run_to_block(4);
         assert_ok!(Identity::create_identity(Origin::signed(1), 3));
         let events = System::events();
-        assert_eq!(events.len(), 2);
+        assert_eq!(events.len(), 1);
         assert_eq!(
-            events[1],
+            events[0],
             EventRecord {
                 phase: Phase::Initialization,
                 event: Event::Identity(crate::Event::IdtyCreated {
diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs
index 629a81ce6..d6991ce60 100644
--- a/pallets/identity/src/types.rs
+++ b/pallets/identity/src/types.rs
@@ -14,7 +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/>.
 
-//! Various basic types for use in the certification pallet.
+//! Various basic types for use in the identity pallet.
 
 use codec::{Decode, Encode};
 use frame_support::pallet_prelude::*;
diff --git a/pallets/provide-randomness/Cargo.toml b/pallets/provide-randomness/Cargo.toml
new file mode 100644
index 000000000..f7d8a9f84
--- /dev/null
+++ b/pallets/provide-randomness/Cargo.toml
@@ -0,0 +1,75 @@
+[package]
+authors = ['librelois <c@elo.tf>']
+description = 'FRAME pallet to provide randomness to users.'
+edition = '2018'
+homepage = 'https://substrate.dev'
+license = 'AGPL-3.0'
+name = 'pallet-provide-randomness'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '3.0.0'
+
+[features]
+default = ['std']
+runtime-benchmarks = ['frame-benchmarking']
+std = [
+    'codec/std',
+    'frame-support/std',
+    'frame-system/std',
+    'frame-benchmarking/std',
+    "sp-core/std",
+    "sp-io/std",
+	"sp-std/std",
+]
+try-runtime = ['frame-support/try-runtime']
+
+[dependencies]
+
+# substrate
+scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+
+[dependencies.codec]
+default-features = false
+features = ['derive']
+package = 'parity-scale-codec'
+version = '2.3.1'
+
+[dependencies.frame-benchmarking]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+optional = true
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.frame-support]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.frame-system]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.sp-core]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.sp-io]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-02'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
diff --git a/pallets/provide-randomness/src/lib.rs b/pallets/provide-randomness/src/lib.rs
new file mode 100644
index 000000000..109076970
--- /dev/null
+++ b/pallets/provide-randomness/src/lib.rs
@@ -0,0 +1,290 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+#![allow(clippy::boxed_local)]
+
+mod types;
+
+use frame_support::pallet_prelude::Weight;
+use sp_core::H256;
+use sp_std::prelude::*;
+
+pub use pallet::*;
+pub use types::*;
+
+pub type RequestId = u64;
+
+pub trait OnFilledRandomness {
+    fn on_filled_randomness(request_id: RequestId, randomness: H256) -> Weight;
+}
+impl OnFilledRandomness for () {
+    fn on_filled_randomness(_: RequestId, _: H256) -> Weight {
+        0
+    }
+}
+
+#[frame_support::pallet]
+pub mod pallet {
+    use super::*;
+    use frame_support::pallet_prelude::*;
+    use frame_support::traits::{
+        Currency, ExistenceRequirement, OnUnbalanced, Randomness, StorageVersion, WithdrawReasons,
+    };
+    use frame_system::pallet_prelude::*;
+    use sp_core::H256;
+
+    pub type BalanceOf<T> =
+        <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
+    pub type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
+        <T as frame_system::Config>::AccountId,
+    >>::NegativeImbalance;
+
+    /// The current storage version.
+    const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
+    #[pallet::pallet]
+    #[pallet::generate_store(pub(super) trait Store)]
+    #[pallet::storage_version(STORAGE_VERSION)]
+    #[pallet::without_storage_info]
+    pub struct Pallet<T>(_);
+
+    /// Configuration trait.
+    #[pallet::config]
+    pub trait Config: frame_system::Config<Hash = H256> {
+        // The currency
+        type Currency: Currency<Self::AccountId>;
+        /// The overarching event type.
+        type Event: From<Event> + IsType<<Self as frame_system::Config>::Event>;
+        /// Maximum number of not yet filled requests
+        #[pallet::constant]
+        type MaxRequests: Get<u32>;
+        /// The price of a request
+        #[pallet::constant]
+        type RequestPrice: Get<BalanceOf<Self>>;
+        /// On filled randomness
+        type OnFilledRandomness: OnFilledRandomness;
+        /// Handler for the unbalanced reduction when the requestor pays fees.
+        type OnUnbalanced: OnUnbalanced<NegativeImbalanceOf<Self>>;
+        /// A safe source of randomness from the current block
+        type CurrentBlockRandomness: Randomness<Option<H256>, Self::BlockNumber>;
+        /// A safe source of randomness from one epoch ago
+        type RandomnessFromOneEpochAgo: Randomness<H256, Self::BlockNumber>;
+    }
+
+    // STORAGE //
+
+    #[pallet::storage]
+    pub(super) type NewEpoch<T: Config> = StorageValue<_, bool, ValueQuery>;
+
+    #[pallet::storage]
+    pub(super) type RequestIdProvider<T: Config> = StorageValue<_, RequestId, ValueQuery>;
+
+    #[pallet::storage]
+    #[pallet::getter(fn requests_ready_at_next_block)]
+    pub type RequestsReadyAtNextBlock<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>;
+
+    #[pallet::storage]
+    #[pallet::getter(fn requests_ready_at_next_epoch)]
+    pub type RequestsReadyAtNextEpoch<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>;
+
+    #[pallet::storage]
+    #[pallet::getter(fn requests_ready_in_two_epochs)]
+    pub type RequestsReadyInTwoEpochs<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>;
+
+    #[pallet::storage]
+    #[pallet::getter(fn requests_ready_in_three_epochs)]
+    pub type RequestsReadyInThreeEpochs<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>;
+
+    #[pallet::storage]
+    #[pallet::getter(fn pending_requests)]
+    pub type PendingRequests<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>;
+
+    #[pallet::storage]
+    #[pallet::getter(fn requests_ids)]
+    pub type RequestsIds<T: Config> =
+        CountedStorageMap<_, Twox64Concat, RequestId, (), OptionQuery>;
+
+    // EVENTS //
+
+    #[pallet::event]
+    #[pallet::generate_deposit(pub(super) fn deposit_event)]
+    pub enum Event {
+        /// Filled randomness
+        FilledRandomness {
+            request_id: RequestId,
+            randomness: H256,
+        },
+        /// Requested randomness
+        RequestedRandomness {
+            request_id: RequestId,
+            salt: H256,
+            r#type: RandomnessType,
+        },
+    }
+
+    // ERRORS //
+
+    #[pallet::error]
+    pub enum Error<T> {
+        /// The queue is full, pleasy retry later
+        FullQueue,
+    }
+
+    // CALLS //
+
+    #[pallet::call]
+    impl<T: Config> Pallet<T> {
+        /// Request a randomness
+        #[pallet::weight(100_000_000)]
+        pub fn request(
+            origin: OriginFor<T>,
+            randomness_type: RandomnessType,
+            salt: H256,
+        ) -> DispatchResult {
+            let who = ensure_signed(origin)?;
+
+            let request_id = Self::do_request(&who, randomness_type, salt)?;
+
+            Self::deposit_event(Event::RequestedRandomness {
+                request_id,
+                salt,
+                r#type: randomness_type,
+            });
+
+            Ok(())
+        }
+    }
+
+    // HOOKS //
+
+    #[pallet::hooks]
+    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+        fn on_initialize(_: T::BlockNumber) -> Weight {
+            let mut total_weight = 0;
+
+            total_weight += 100_000;
+            for Request { request_id, salt } in RequestsReadyAtNextBlock::<T>::take() {
+                let randomness = T::CurrentBlockRandomness::random(salt.as_ref())
+                    .0
+                    .unwrap_or_default();
+                total_weight += T::OnFilledRandomness::on_filled_randomness(request_id, randomness);
+                Self::deposit_event(Event::FilledRandomness {
+                    request_id,
+                    randomness,
+                });
+                total_weight += 100_000;
+            }
+
+            if NewEpoch::<T>::get() {
+                NewEpoch::<T>::put(false);
+                total_weight += 100_000;
+                for Request { request_id, salt } in RequestsReadyAtNextEpoch::<T>::take() {
+                    let randomness = T::RandomnessFromOneEpochAgo::random(salt.as_ref()).0;
+                    total_weight +=
+                        T::OnFilledRandomness::on_filled_randomness(request_id, randomness);
+                    Self::deposit_event(Event::FilledRandomness {
+                        request_id,
+                        randomness,
+                    });
+                    total_weight += 100_000;
+                }
+
+                total_weight += 200_000;
+                let requests_ready_at_next_epoch = RequestsReadyInTwoEpochs::<T>::take();
+                RequestsReadyAtNextEpoch::<T>::put(requests_ready_at_next_epoch);
+
+                total_weight += 200_000;
+                let requests_ready_in_two_epochs = RequestsReadyInThreeEpochs::<T>::take();
+                RequestsReadyInTwoEpochs::<T>::put(requests_ready_in_two_epochs);
+
+                total_weight += 200_000;
+                let requests_ready_in_three_epochs = PendingRequests::<T>::take();
+                RequestsReadyInThreeEpochs::<T>::put(requests_ready_in_three_epochs);
+            }
+
+            total_weight
+        }
+    }
+
+    // PUBLIC FUNCTIONS //
+
+    impl<T: Config> Pallet<T> {
+        pub fn do_request(
+            requestor: &T::AccountId,
+            randomness_type: RandomnessType,
+            salt: H256,
+        ) -> Result<RequestId, DispatchError> {
+            // Verify phase
+            ensure!(
+                RequestsIds::<T>::count() < T::MaxRequests::get(),
+                Error::<T>::FullQueue
+            );
+
+            Self::pay_request(requestor)?;
+
+            // Apply phase
+            Ok(Self::apply_request(randomness_type, salt))
+        }
+        pub fn force_request(randomness_type: RandomnessType, salt: H256) -> RequestId {
+            Self::apply_request(randomness_type, salt)
+        }
+        pub fn on_new_epoch() {
+            NewEpoch::<T>::put(true);
+        }
+    }
+
+    // INTERNAL FUNCTIONS //
+
+    impl<T: Config> Pallet<T> {
+        fn pay_request(requestor: &T::AccountId) -> DispatchResult {
+            let imbalance = T::Currency::withdraw(
+                requestor,
+                T::RequestPrice::get(),
+                WithdrawReasons::FEE,
+                ExistenceRequirement::KeepAlive,
+            )?;
+            T::OnUnbalanced::on_unbalanced(imbalance);
+            Ok(())
+        }
+        fn apply_request(randomness_type: RandomnessType, salt: H256) -> RequestId {
+            let request_id = RequestIdProvider::<T>::mutate(|next_request_id| {
+                core::mem::replace(next_request_id, next_request_id.saturating_add(1))
+            });
+            RequestsIds::<T>::insert(request_id, ());
+            match randomness_type {
+                RandomnessType::RandomnessFromPreviousBlock => {
+                    RequestsReadyAtNextBlock::<T>::append(Request { request_id, salt });
+                }
+                RandomnessType::RandomnessFromOneEpochAgo => {
+                    if NewEpoch::<T>::get() {
+                        RequestsReadyInThreeEpochs::<T>::append(Request { request_id, salt });
+                    } else {
+                        RequestsReadyInTwoEpochs::<T>::append(Request { request_id, salt });
+                    }
+                }
+                RandomnessType::RandomnessFromTwoEpochsAgo => {
+                    if NewEpoch::<T>::get() {
+                        PendingRequests::<T>::append(Request { request_id, salt });
+                    } else {
+                        RequestsReadyInThreeEpochs::<T>::append(Request { request_id, salt });
+                    }
+                }
+            }
+            request_id
+        }
+    }
+}
diff --git a/pallets/provide-randomness/src/types.rs b/pallets/provide-randomness/src/types.rs
new file mode 100644
index 000000000..cb6c3d2a6
--- /dev/null
+++ b/pallets/provide-randomness/src/types.rs
@@ -0,0 +1,36 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+//! Various basic types for use in pallet provide randomness
+
+use super::RequestId;
+use codec::{Decode, Encode};
+use frame_support::pallet_prelude::*;
+use scale_info::TypeInfo;
+use sp_core::H256;
+
+#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)]
+pub enum RandomnessType {
+    RandomnessFromPreviousBlock,
+    RandomnessFromOneEpochAgo,
+    RandomnessFromTwoEpochsAgo,
+}
+
+#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
+pub struct Request {
+    pub request_id: RequestId,
+    pub salt: H256,
+}
diff --git a/resources/metadata.scale b/resources/metadata.scale
index e7cb5e913808755149ae30d7d23c9f3f2befccd8..aaae5189c6cf33378f92a82f949f3f23a0c2ee3c 100644
GIT binary patch
delta 19588
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
II?|^8Uv4A19RL6T

delta 8471
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

diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml
index d664f6723..7a5eeb50b 100644
--- a/runtime/common/Cargo.toml
+++ b/runtime/common/Cargo.toml
@@ -25,9 +25,11 @@ std = [
     'pallet-authority-members/std',
     'pallet-balances/std',
     'pallet-certification/std',
+    'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
     'pallet-identity/std',
     'pallet-membership/std',
+    'pallet-provide-randomness/std',
     'pallet-ud-accounts-storage/std',
     'serde',
     'sp-arithmetic/std',
@@ -40,9 +42,11 @@ std = [
 [dependencies]
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false }
 pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
+pallet-provide-randomness = { path = '../../pallets/provide-randomness', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 sp-membership = { path = '../../primitives/membership', default-features = false }
 
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index f601b2dc5..5e35e8170 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -22,6 +22,17 @@ use frame_support::pallet_prelude::Weight;
 use frame_support::Parameter;
 use sp_runtime::traits::IsMember;
 
+pub struct OnNewSessionHandler<Runtime>(core::marker::PhantomData<Runtime>);
+impl<Runtime> pallet_authority_members::traits::OnNewSession for OnNewSessionHandler<Runtime>
+where
+    Runtime: pallet_provide_randomness::Config,
+{
+    fn on_new_session(_index: sp_staking::SessionIndex) -> Weight {
+        pallet_provide_randomness::Pallet::<Runtime>::on_new_epoch();
+        0
+    }
+}
+
 pub struct OnMembershipEventHandler<Inner, Runtime>(core::marker::PhantomData<(Inner, Runtime)>);
 
 type MembershipMetaData = pallet_duniter_wot::MembershipMetaData<AccountId>;
@@ -92,7 +103,7 @@ impl<
                     frame_system::Origin::<Runtime>::Signed(owner_key.clone()).into(),
                 ) {
                     sp_std::if_std! {
-                        println!("{:?}", e)
+                        println!("fail to set session keys: {:?}", e)
                     }
                 }
                 0
@@ -105,7 +116,7 @@ impl<
                     call.dispatch_bypass_filter(frame_system::Origin::<Runtime>::Root.into())
                 {
                     sp_std::if_std! {
-                        println!("{:?}", e)
+                        println!("faid to remove member: {:?}", e)
                     }
                 }
                 0
@@ -127,7 +138,7 @@ where
             Some(idty_index),
         ) {
             sp_std::if_std! {
-                println!("{:?}", e)
+                println!("fail to revoke membership: {:?}", e)
             }
         }
         0
@@ -146,16 +157,6 @@ where
     fn remove_idty_consumers(idty_index: IdtyIndex) -> Weight {
         // Remove smith member
         if pallet_membership::Pallet::<Runtime, Instance2>::is_member(&idty_index) {
-            if let Err(e) = pallet_authority_members::Pallet::<Runtime>::remove_member(
-                frame_system::RawOrigin::Root.into(),
-                idty_index,
-            ) {
-                log::error!(
-                    target: "runtime::common",
-                    "Logic error: fail to remove authority member in remove_idty_consumers(): {:?}",
-                    e
-                );
-            }
             if let Err(e) = pallet_membership::Pallet::<Runtime, Instance2>::revoke_membership(
                 frame_system::RawOrigin::Root.into(),
                 Some(idty_index),
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index 4a9ae0417..1dae66af8 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -67,7 +67,7 @@ macro_rules! pallets_config {
 			/// What to do if an account is fully reaped from the system.
 			type OnKilledAccount = ();
 			/// The data to be stored in an account.
-			type AccountData = pallet_balances::AccountData<Balance>;
+			type AccountData = pallet_duniter_account::AccountData<Balance>;
 			/// Weight information for the extrinsics of this pallet.
 			type SystemWeightInfo = ();
 			/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
@@ -109,6 +109,15 @@ macro_rules! pallets_config {
 			type NoPreimagePostponement = ();
 		}
 
+		// ACCOUNT //
+
+		impl pallet_duniter_account::Config for Runtime {
+			type AccountIdToSalt = sp_runtime::traits::ConvertInto;
+			type Event = Event;
+			type MaxNewAccountsPerBlock = frame_support::pallet_prelude::ConstU32<100>;
+			type NewAccountPrice = frame_support::traits::ConstU64<200>;
+		}
+
 		// BLOCK CREATION //
 
 		impl pallet_babe::Config for Runtime {
@@ -151,7 +160,7 @@ macro_rules! pallets_config {
 
 		impl pallet_balances::Config for Runtime {
 			type MaxLocks = MaxLocks;
-			type MaxReserves = ();
+			type MaxReserves = frame_support::pallet_prelude::ConstU32<5>;
 			type ReserveIdentifier = [u8; 8];
 			/// The type for recording an account's balance.
 			type Balance = Balance;
@@ -159,7 +168,7 @@ macro_rules! pallets_config {
 			type Event = Event;
 			type DustRemoval = ();
 			type ExistentialDeposit = ExistentialDeposit;
-			type AccountStore = System;
+			type AccountStore = Account;
 			type WeightInfo = common_runtime::weights::pallet_balances::WeightInfo<Runtime>;
 		}
 
@@ -191,6 +200,7 @@ macro_rules! pallets_config {
 			type Event = Event;
 			type KeysWrapper = opaque::SessionKeysWrapper;
 			type IsMember = SmithsMembership;
+			type OnNewSession = OnNewSessionHandler<Runtime>;
 			type OnRemovedMember = OnRemovedAuthorityMemberHandler<Runtime>;
 			type MemberId = IdtyIndex;
 			type MemberIdOf = Identity;
@@ -266,6 +276,17 @@ macro_rules! pallets_config {
 			type ProofLimit = frame_support::traits::ConstU32<255>;
 		}
 
+		impl pallet_provide_randomness::Config for Runtime {
+			type Currency = Balances;
+			type Event = Event;
+			type MaxRequests = frame_support::traits::ConstU32<1_000>;
+			type RequestPrice = frame_support::traits::ConstU64<200>;
+			type OnFilledRandomness = Account;
+			type OnUnbalanced = ();
+			type CurrentBlockRandomness = pallet_babe::CurrentBlockRandomness<Self>;
+			type RandomnessFromOneEpochAgo = pallet_babe::RandomnessFromOneEpochAgo<Self>;
+		}
+
 		parameter_types! {
 			// One storage item; key size 32, value size 8; .
 			pub const ProxyDepositBase: Balance = deposit(1, 8);
diff --git a/runtime/g1/Cargo.toml b/runtime/g1/Cargo.toml
index ce2dac153..1f08a0648 100644
--- a/runtime/g1/Cargo.toml
+++ b/runtime/g1/Cargo.toml
@@ -39,13 +39,15 @@ std = [
     'pallet-balances/std',
     'pallet-certification/std',
     'pallet-collective/std',
+    'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
     'pallet-grandpa/std',
     'pallet-identity/std',
     'pallet-im-online/std',
     'pallet-membership/std',
-    'pallet-proxy/std',
     'pallet-multisig/std',
+	'pallet-provide-randomness/std',
+    'pallet-proxy/std',
     'pallet-session/std',
     'pallet-sudo/std',
     'pallet-universal-dividend/std',
@@ -71,12 +73,15 @@ std = [
 ]
 
 [dependencies]
+# local
 common-runtime = { path = "../common", default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false }
 pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
+pallet-provide-randomness = { path = '../../pallets/provide-randomness', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
 sp-membership = { path = '../../primitives/membership', default-features = false }
diff --git a/runtime/g1/src/lib.rs b/runtime/g1/src/lib.rs
index 6528e2864..ed5a4d9cf 100644
--- a/runtime/g1/src/lib.rs
+++ b/runtime/g1/src/lib.rs
@@ -194,15 +194,15 @@ construct_runtime!(
     {
         // Basic stuff
         System: frame_system::{Pallet, Call, Config, Storage, Event<T>} = 0,
-        Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 1,
+        Account: pallet_duniter_account::{Pallet, Storage, Config<T>, Event<T>} = 1,
+        Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 2,
 
-        // Babe must be before session.
-        Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2,
-
-        Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3,
+        // Block creation
+        Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 3,
+        Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 4,
 
         // Money management
-        Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 5,
+        Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 6,
         TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 32,
 
         // Consensus support.
@@ -236,9 +236,10 @@ construct_runtime!(
 
         // Utilities
         AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60,
-        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 61,
-        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 62,
-        Utility: pallet_utility::{Pallet, Call, Event} = 63,
+        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61,
+        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62,
+        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63,
+        Utility: pallet_utility::{Pallet, Call, Event} = 64,
     }
 );
 
diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml
index fb66fe924..9a325078a 100644
--- a/runtime/gdev/Cargo.toml
+++ b/runtime/gdev/Cargo.toml
@@ -41,10 +41,12 @@ std = [
     'pallet-certification/std',
     'pallet-collective/std',
     'pallet-duniter-test-parameters/std',
+    'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
     'pallet-grandpa/std',
     'pallet-identity/std',
     'pallet-membership/std',
+	'pallet-provide-randomness/std',
     'pallet-im-online/std',
     'pallet-multisig/std',
     'pallet-proxy/std',
@@ -83,9 +85,11 @@ common-runtime = { path = "../common", default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-duniter-test-parameters = { path = '../../pallets/duniter-test-parameters', default-features = false }
+pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false }
 pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
+pallet-provide-randomness = { path = '../../pallets/provide-randomness', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
 pallet-upgrade-origin = { path = '../../pallets/upgrade-origin', default-features = false }
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index 09583583b..c8fb20374 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -247,17 +247,18 @@ construct_runtime!(
     {
         // Basic stuff
         System: frame_system::{Pallet, Call, Config, Storage, Event<T>} = 0,
-        Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 1,
+        Account: pallet_duniter_account::{Pallet, Storage, Config<T>, Event<T>} = 1,
+        Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 2,
 
         // Block creation
-        Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2,
-        Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3,
+        Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 3,
+        Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 4,
 
         // Test parameters
-        Parameters: pallet_duniter_test_parameters::{Pallet, Config<T>, Storage} = 4,
+        Parameters: pallet_duniter_test_parameters::{Pallet, Config<T>, Storage} = 5,
 
         // Money management
-        Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 5,
+        Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 6,
         TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 32,
 
         // Consensus support
@@ -292,9 +293,10 @@ construct_runtime!(
 
         // Utilities
         AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60,
-        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 61,
-        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 62,
-        Utility: pallet_utility::{Pallet, Call, Event} = 63,
+        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61,
+        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62,
+        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63,
+        Utility: pallet_utility::{Pallet, Call, Event} = 64,
     }
 );
 
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
index 655f6186b..215b1152a 100644
--- a/runtime/gdev/tests/integration_tests.rs
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -124,11 +124,11 @@ fn test_remove_smith_identity() {
         assert_eq!(events.len(), 4);
         assert_eq!(
             System::events()[0].event,
-            Event::AuthorityMembers(pallet_authority_members::Event::MemberRemoved(3))
+            Event::SmithsMembership(pallet_membership::Event::MembershipRevoked(3))
         );
         assert_eq!(
             System::events()[1].event,
-            Event::SmithsMembership(pallet_membership::Event::MembershipRevoked(3))
+            Event::AuthorityMembers(pallet_authority_members::Event::MemberRemoved(3))
         );
         assert_eq!(
             System::events()[2].event,
diff --git a/runtime/gtest/Cargo.toml b/runtime/gtest/Cargo.toml
index 5eb92d065..af4827930 100644
--- a/runtime/gtest/Cargo.toml
+++ b/runtime/gtest/Cargo.toml
@@ -39,11 +39,13 @@ std = [
     'pallet-balances/std',
     'pallet-certification/std',
     'pallet-collective/std',
+    'pallet-duniter-account/std',
     'pallet-duniter-wot/std',
     'pallet-grandpa/std',
     'pallet-identity/std',
-    'pallet-membership/std',
     'pallet-im-online/std',
+    'pallet-membership/std',
+	'pallet-provide-randomness/std',
     'pallet-proxy/std',
     'pallet-multisig/std',
     'pallet-session/std',
@@ -71,12 +73,15 @@ std = [
 ]
 
 [dependencies]
+# local
 common-runtime = { path = "../common", default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false }
 pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
+pallet-provide-randomness = { path = '../../pallets/provide-randomness', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
 sp-membership = { path = '../../primitives/membership', default-features = false }
diff --git a/runtime/gtest/src/lib.rs b/runtime/gtest/src/lib.rs
index 211925aa8..49444c2dc 100644
--- a/runtime/gtest/src/lib.rs
+++ b/runtime/gtest/src/lib.rs
@@ -195,14 +195,15 @@ construct_runtime!(
     {
         // Basic stuff
         System: frame_system::{Pallet, Call, Config, Storage, Event<T>} = 0,
-        Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 1,
+        Account: pallet_duniter_account::{Pallet, Storage, Config<T>, Event<T>} = 1,
+        Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 2,
 
         // Block creation
-        Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2,
-        Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3,
+        Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 3,
+        Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 4,
 
         // Money management
-        Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 5,
+        Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 6,
         TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 32,
 
         // Consensus support.
@@ -236,9 +237,10 @@ construct_runtime!(
 
         // Utilities
         AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60,
-        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 61,
-        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 62,
-        Utility: pallet_utility::{Pallet, Call, Event} = 63,
+        Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61,
+        ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62,
+        Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63,
+        Utility: pallet_utility::{Pallet, Call, Event} = 64,
     }
 );
 
-- 
GitLab