Browse Source

runtime: staking-handler: Copy StakeManager and modify dependencies.

Shamil Gadelshin 4 years ago
parent
commit
1909937539
3 changed files with 118 additions and 13 deletions
  1. 0 4
      Cargo.lock
  2. 11 5
      runtime-modules/staking-handler/Cargo.toml
  3. 107 4
      runtime-modules/staking-handler/src/lib.rs

+ 0 - 4
Cargo.lock

@@ -7370,11 +7370,7 @@ dependencies = [
  "frame-system",
  "pallet-balances",
  "pallet-membership",
- "pallet-timestamp",
- "parity-scale-codec",
- "serde",
  "sp-arithmetic",
- "sp-runtime",
  "sp-std",
 ]
 

+ 11 - 5
runtime-modules/staking-handler/Cargo.toml

@@ -5,14 +5,20 @@ authors = ['Joystream contributors']
 edition = '2018'
 
 [dependencies]
-serde = { version = "1.0.101", optional = true, features = ["derive"] }
-codec = { package = 'parity-scale-codec', version = '1.3.4', default-features = false, features = ['derive'] }
 sp-std = { package = 'sp-std', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 frame-support = { package = 'frame-support', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 frame-system = { package = 'frame-system', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
-sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
-pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
-balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+pallet-balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 membership = { package = 'pallet-membership', default-features = false, path = '../membership'}
 
+[features]
+default = ['std']
+std = [
+    'sp-std/std',
+    'frame-support/std',
+    'frame-system/std',
+    'sp-arithmetic/std',
+    'pallet-balances/std',
+    'membership/std',
+]

+ 107 - 4
runtime-modules/staking-handler/src/lib.rs

@@ -1,15 +1,18 @@
-use frame_support::dispatch::DispatchResult;
+use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::traits::{Currency, Get, LockIdentifier, LockableCurrency, WithdrawReasons};
+use sp_arithmetic::traits::Zero;
+use sp_std::marker::PhantomData;
 
-// Type alias for member id.
+/// Type alias for member id.
 pub type MemberId<T> = <T as membership::Trait>::MemberId;
 
 /// Balance alias for `balances` module.
-pub type BalanceOf<T> = <T as balances::Trait>::Balance;
+pub type BalanceOf<T> = <T as pallet_balances::Trait>::Balance;
 
 /// Defines abstract staking handler to manage user stakes for different activities
 /// like adding a proposal. Implementation should use built-in LockableCurrency
 /// and LockIdentifier to lock balance consistently with pallet_staking.
-pub trait StakingHandler<T: frame_system::Trait + membership::Trait + balances::Trait> {
+pub trait StakingHandler<T: frame_system::Trait + membership::Trait + pallet_balances::Trait> {
     /// Locks the specified balance on the account using specific lock identifier.
     fn lock(account_id: &T::AccountId, amount: BalanceOf<T>);
 
@@ -39,3 +42,103 @@ pub trait StakingHandler<T: frame_system::Trait + membership::Trait + balances::
     /// Returns the current stake on the account.
     fn current_stake(account_id: &T::AccountId) -> BalanceOf<T>;
 }
+
+/// Implementation of the StakingHandler.
+pub struct StakingManager<
+    T: frame_system::Trait + membership::Trait + pallet_balances::Trait,
+    LockId: Get<LockIdentifier>,
+> {
+    trait_marker: PhantomData<T>,
+    lock_id_marker: PhantomData<LockId>,
+}
+
+impl<
+        T: frame_system::Trait + membership::Trait + pallet_balances::Trait,
+        LockId: Get<LockIdentifier>,
+    > StakingHandler<T> for StakingManager<T, LockId>
+{
+    fn lock(account_id: &T::AccountId, amount: BalanceOf<T>) {
+        <pallet_balances::Module<T>>::set_lock(
+            LockId::get(),
+            &account_id,
+            amount,
+            WithdrawReasons::all(),
+        )
+    }
+
+    fn unlock(account_id: &T::AccountId) {
+        T::Currency::remove_lock(LockId::get(), &account_id);
+    }
+
+    fn slash(account_id: &T::AccountId, amount: Option<BalanceOf<T>>) -> BalanceOf<T> {
+        let locks = <pallet_balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        let mut actually_slashed_balance = Default::default();
+        if let Some(existing_lock) = existing_lock {
+            Self::unlock(&account_id);
+
+            let mut slashable_amount = existing_lock.amount;
+            if let Some(amount) = amount {
+                if existing_lock.amount > amount {
+                    let new_amount = existing_lock.amount - amount;
+                    Self::lock(&account_id, new_amount);
+
+                    slashable_amount = amount;
+                }
+            }
+
+            let _ = <pallet_balances::Module<T>>::slash(&account_id, slashable_amount);
+
+            actually_slashed_balance = slashable_amount
+        }
+
+        actually_slashed_balance
+    }
+
+    fn set_stake(account_id: &T::AccountId, new_stake: BalanceOf<T>) -> DispatchResult {
+        let current_stake = Self::current_stake(account_id);
+
+        //Unlock previous stake if its not zero.
+        if current_stake > Zero::zero() {
+            Self::unlock(account_id);
+        }
+
+        if !Self::is_enough_balance_for_stake(account_id, new_stake) {
+            //Restore previous stake if its not zero.
+            if current_stake > Zero::zero() {
+                Self::lock(account_id, current_stake);
+            }
+            return Err(DispatchError::Other("Not enough balance for a new stake."));
+        }
+
+        Self::lock(account_id, new_stake);
+
+        Ok(())
+    }
+
+    fn is_member_staking_account(_member_id: &MemberId<T>, _account_id: &T::AccountId) -> bool {
+        true
+    }
+
+    fn is_account_free_of_conflicting_stakes(account_id: &T::AccountId) -> bool {
+        let locks = <pallet_balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        existing_lock.is_none()
+    }
+
+    fn is_enough_balance_for_stake(account_id: &T::AccountId, amount: BalanceOf<T>) -> bool {
+        <pallet_balances::Module<T>>::usable_balance(account_id) >= amount
+    }
+
+    fn current_stake(account_id: &T::AccountId) -> BalanceOf<T> {
+        let locks = <pallet_balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        existing_lock.map_or(Zero::zero(), |lock| lock.amount)
+    }
+}