-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathremove_stake.rs
114 lines (101 loc) · 4.37 KB
/
remove_stake.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use super::*;
impl<T: Config> Pallet<T> {
/// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey.
///
/// # Args:
/// * 'origin': (<T as frame_system::Config>RuntimeOrigin):
/// - The signature of the caller's coldkey.
///
/// * 'hotkey' (T::AccountId):
/// - The associated hotkey account.
///
/// * 'stake_to_be_added' (u64):
/// - The amount of stake to be added to the hotkey staking account.
///
/// # Event:
/// * StakeRemoved;
/// - On the successfully removing stake from the hotkey account.
///
/// # Raises:
/// * 'NotRegistered':
/// - Thrown if the account we are attempting to unstake from is non existent.
///
/// * 'NonAssociatedColdKey':
/// - Thrown if the coldkey does not own the hotkey we are unstaking from.
///
/// * 'NotEnoughStakeToWithdraw':
/// - Thrown if there is not enough stake on the hotkey to withdwraw this amount.
///
/// * 'TxRateLimitExceeded':
/// - Thrown if key has hit transaction rate limit
///
pub fn do_remove_stake(
origin: T::RuntimeOrigin,
hotkey: T::AccountId,
stake_to_be_removed: u64,
) -> dispatch::DispatchResult {
// We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
let coldkey = ensure_signed(origin)?;
log::debug!(
"do_remove_stake( origin:{:?} hotkey:{:?}, stake_to_be_removed:{:?} )",
coldkey,
hotkey,
stake_to_be_removed
);
// Ensure that the hotkey account exists this is only possible through registration.
ensure!(
Self::hotkey_account_exists(&hotkey),
Error::<T>::HotKeyAccountNotExists
);
// Ensure that the hotkey allows delegation or that the hotkey is owned by the calling coldkey.
ensure!(
Self::hotkey_is_delegate(&hotkey) || Self::coldkey_owns_hotkey(&coldkey, &hotkey),
Error::<T>::HotKeyNotDelegateAndSignerNotOwnHotKey
);
// Ensure that the stake amount to be removed is above zero.
ensure!(stake_to_be_removed > 0, Error::<T>::StakeToWithdrawIsZero);
// Ensure that the hotkey has enough stake to withdraw.
ensure!(
Self::has_enough_stake(&coldkey, &hotkey, stake_to_be_removed),
Error::<T>::NotEnoughStakeToWithdraw
);
// Ensure we don't exceed stake rate limit
let unstakes_this_interval =
Self::get_stakes_this_interval_for_coldkey_hotkey(&coldkey, &hotkey);
ensure!(
unstakes_this_interval < Self::get_target_stakes_per_interval(),
Error::<T>::UnstakeRateLimitExceeded
);
// We remove the balance from the hotkey.
Self::decrease_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, stake_to_be_removed);
// Track this removal in the stake delta.
StakeDeltaSinceLastEmissionDrain::<T>::mutate(&hotkey, &coldkey, |stake_delta| {
*stake_delta = stake_delta.saturating_sub_unsigned(stake_to_be_removed as u128);
});
// We add the balance to the coldkey. If the above fails we will not credit this coldkey.
Self::add_balance_to_coldkey_account(&coldkey, stake_to_be_removed);
// If the stake is below the minimum, we clear the nomination from storage.
// This only applies to nominator stakes.
// If the coldkey does not own the hotkey, it's a nominator stake.
let new_stake = Self::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey);
Self::clear_small_nomination_if_required(&hotkey, &coldkey, new_stake);
// Set last block for rate limiting
let block: u64 = Self::get_current_block_as_u64();
Self::set_last_tx_block(&coldkey, block);
// Emit the unstaking event.
Self::set_stakes_this_interval_for_coldkey_hotkey(
&coldkey,
&hotkey,
unstakes_this_interval.saturating_add(1),
block,
);
log::debug!(
"StakeRemoved( hotkey:{:?}, stake_to_be_removed:{:?} )",
hotkey,
stake_to_be_removed
);
Self::deposit_event(Event::StakeRemoved(hotkey, stake_to_be_removed));
// Done and ok.
Ok(())
}
}