referrerpolicy=no-referrer-when-downgrade

pallet_delegated_staking/
impls.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Implementations of public traits, namely [`DelegationInterface`] and [`OnStakingUpdate`].
19
20use super::*;
21use sp_staking::{DelegationInterface, DelegationMigrator, OnStakingUpdate};
22
23impl<T: Config> DelegationInterface for Pallet<T> {
24	type Balance = BalanceOf<T>;
25	type AccountId = T::AccountId;
26
27	/// Effective balance of the `Agent` account.
28	fn agent_balance(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
29		AgentLedgerOuter::<T>::get(&agent.get())
30			.map(|a| a.ledger.effective_balance())
31			.ok()
32	}
33
34	fn agent_transferable_balance(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
35		AgentLedgerOuter::<T>::get(&agent.get())
36			.map(|a| a.ledger.unclaimed_withdrawals)
37			.ok()
38	}
39
40	fn delegator_balance(delegator: Delegator<Self::AccountId>) -> Option<Self::Balance> {
41		Delegation::<T>::get(&delegator.get()).map(|d| d.amount)
42	}
43
44	/// Delegate funds to an `Agent`.
45	fn register_agent(
46		agent: Agent<Self::AccountId>,
47		reward_account: &Self::AccountId,
48	) -> DispatchResult {
49		Pallet::<T>::register_agent(
50			RawOrigin::Signed(agent.clone().get()).into(),
51			reward_account.clone(),
52		)
53	}
54
55	/// Remove `Agent` registration.
56	fn remove_agent(agent: Agent<Self::AccountId>) -> DispatchResult {
57		Pallet::<T>::remove_agent(RawOrigin::Signed(agent.clone().get()).into())
58	}
59
60	/// Add more delegation to the `Agent` account.
61	fn delegate(
62		who: Delegator<Self::AccountId>,
63		agent: Agent<Self::AccountId>,
64		amount: Self::Balance,
65	) -> DispatchResult {
66		Pallet::<T>::delegate_to_agent(RawOrigin::Signed(who.get()).into(), agent.get(), amount)
67	}
68
69	/// Withdraw delegation of `delegator` to `Agent`.
70	///
71	/// If there are funds in `Agent` account that can be withdrawn, then those funds would be
72	/// unlocked/released in the delegator's account.
73	fn withdraw_delegation(
74		delegator: Delegator<Self::AccountId>,
75		agent: Agent<Self::AccountId>,
76		amount: Self::Balance,
77		num_slashing_spans: u32,
78	) -> DispatchResult {
79		Pallet::<T>::release_delegation(
80			RawOrigin::Signed(agent.get()).into(),
81			delegator.get(),
82			amount,
83			num_slashing_spans,
84		)
85	}
86
87	/// Returns pending slash of the `agent`.
88	fn pending_slash(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
89		AgentLedgerOuter::<T>::get(&agent.get()).map(|d| d.ledger.pending_slash).ok()
90	}
91
92	fn delegator_slash(
93		agent: Agent<Self::AccountId>,
94		delegator: Delegator<Self::AccountId>,
95		value: Self::Balance,
96		maybe_reporter: Option<Self::AccountId>,
97	) -> sp_runtime::DispatchResult {
98		Pallet::<T>::do_slash(agent, delegator, value, maybe_reporter)
99	}
100}
101
102impl<T: Config> DelegationMigrator for Pallet<T> {
103	type Balance = BalanceOf<T>;
104	type AccountId = T::AccountId;
105
106	fn migrate_nominator_to_agent(
107		agent: Agent<Self::AccountId>,
108		reward_account: &Self::AccountId,
109	) -> DispatchResult {
110		Pallet::<T>::migrate_to_agent(RawOrigin::Signed(agent.get()).into(), reward_account.clone())
111	}
112	fn migrate_delegation(
113		agent: Agent<Self::AccountId>,
114		delegator: Delegator<Self::AccountId>,
115		value: Self::Balance,
116	) -> DispatchResult {
117		Pallet::<T>::migrate_delegation(
118			RawOrigin::Signed(agent.get()).into(),
119			delegator.get(),
120			value,
121		)
122	}
123
124	/// Only used for testing.
125	#[cfg(feature = "runtime-benchmarks")]
126	fn force_kill_agent(agent: Agent<Self::AccountId>) {
127		<Agents<T>>::remove(agent.clone().get());
128		<Delegators<T>>::iter()
129			.filter(|(_, delegation)| delegation.agent == agent.clone().get())
130			.for_each(|(delegator, _)| {
131				let _ = T::Currency::release_all(
132					&HoldReason::StakingDelegation.into(),
133					&delegator,
134					Precision::BestEffort,
135				);
136				<Delegators<T>>::remove(&delegator);
137			});
138	}
139}
140
141impl<T: Config> OnStakingUpdate<T::AccountId, BalanceOf<T>> for Pallet<T> {
142	fn on_slash(
143		who: &T::AccountId,
144		_slashed_active: BalanceOf<T>,
145		_slashed_unlocking: &alloc::collections::btree_map::BTreeMap<EraIndex, BalanceOf<T>>,
146		slashed_total: BalanceOf<T>,
147	) {
148		<Agents<T>>::mutate(who, |maybe_register| match maybe_register {
149			// if existing agent, register the slashed amount as pending slash.
150			Some(register) => register.pending_slash.saturating_accrue(slashed_total),
151			None => {
152				// nothing to do
153			},
154		});
155	}
156
157	fn on_withdraw(stash: &T::AccountId, amount: BalanceOf<T>) {
158		// if there is a withdraw to the agent, then add it to the unclaimed withdrawals.
159		let _ = AgentLedgerOuter::<T>::get(stash)
160			// can't do anything if there is an overflow error. Just raise a defensive error.
161			.and_then(|agent| agent.add_unclaimed_withdraw(amount).defensive())
162			.map(|agent| agent.save());
163	}
164}