pallet_delegated_staking/
types.rs1use super::*;
21use frame_support::traits::DefensiveSaturating;
22
23#[derive(Encode, Decode)]
25pub(crate) enum AccountType {
26	ProxyDelegator,
30}
31
32#[derive(Default, Encode, Clone, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
34#[scale_info(skip_type_params(T))]
35pub struct Delegation<T: Config> {
36	pub agent: T::AccountId,
38	pub amount: BalanceOf<T>,
40}
41
42impl<T: Config> Delegation<T> {
43	pub(crate) fn get(delegator: &T::AccountId) -> Option<Self> {
45		<Delegators<T>>::get(delegator)
46	}
47
48	pub(crate) fn new(agent: &T::AccountId, amount: BalanceOf<T>) -> Self {
50		Delegation { agent: agent.clone(), amount }
51	}
52
53	pub(crate) fn can_delegate(delegator: &T::AccountId, agent: &T::AccountId) -> bool {
58		Delegation::<T>::get(delegator)
59			.map(|delegation| delegation.agent == *agent)
60			.unwrap_or(
61				!<Agents<T>>::contains_key(delegator),
63			)
64	}
65
66	pub(crate) fn update(self, key: &T::AccountId) {
71		if <Delegators<T>>::contains_key(key) {
72			if self.amount == Zero::zero() {
74				<Delegators<T>>::remove(key);
75				let _ = frame_system::Pallet::<T>::dec_providers(key).defensive();
77				return
78			}
79		} else {
80			frame_system::Pallet::<T>::inc_providers(key);
82		}
83
84		<Delegators<T>>::insert(key, self);
85	}
86}
87
88#[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
94#[scale_info(skip_type_params(T))]
95pub struct AgentLedger<T: Config> {
96	pub payee: T::AccountId,
98	#[codec(compact)]
100	pub total_delegated: BalanceOf<T>,
101	#[codec(compact)]
107	pub unclaimed_withdrawals: BalanceOf<T>,
108	#[codec(compact)]
110	pub pending_slash: BalanceOf<T>,
111}
112
113impl<T: Config> AgentLedger<T> {
114	pub(crate) fn new(reward_destination: &T::AccountId) -> Self {
116		AgentLedger {
117			payee: reward_destination.clone(),
118			total_delegated: Zero::zero(),
119			unclaimed_withdrawals: Zero::zero(),
120			pending_slash: Zero::zero(),
121		}
122	}
123
124	pub(crate) fn get(key: &T::AccountId) -> Option<Self> {
126		<Agents<T>>::get(key)
127	}
128
129	pub(crate) fn update(self, key: &T::AccountId) {
133		<Agents<T>>::insert(key, self)
134	}
135
136	pub(crate) fn remove(key: &T::AccountId) {
138		debug_assert!(<Agents<T>>::contains_key(key), "Agent should exist in storage");
139		<Agents<T>>::remove(key);
140	}
141
142	pub(crate) fn effective_balance(&self) -> BalanceOf<T> {
146		defensive_assert!(
147			self.total_delegated >= self.pending_slash,
148			"slash cannot be higher than actual balance of delegator"
149		);
150
151		self.total_delegated.saturating_sub(self.pending_slash)
153	}
154
155	pub(crate) fn stakeable_balance(&self) -> BalanceOf<T> {
157		self.effective_balance().saturating_sub(self.unclaimed_withdrawals)
158	}
159}
160
161#[derive(Clone)]
163pub struct AgentLedgerOuter<T: Config> {
164	pub key: T::AccountId,
166	pub ledger: AgentLedger<T>,
168}
169
170impl<T: Config> AgentLedgerOuter<T> {
171	pub(crate) fn get(agent: &T::AccountId) -> Result<AgentLedgerOuter<T>, DispatchError> {
173		let ledger = AgentLedger::<T>::get(agent).ok_or(Error::<T>::NotAgent)?;
174		Ok(AgentLedgerOuter { key: agent.clone(), ledger })
175	}
176
177	pub(crate) fn remove_unclaimed_withdraw(
182		self,
183		amount: BalanceOf<T>,
184	) -> Result<Self, DispatchError> {
185		let new_total_delegated = self
186			.ledger
187			.total_delegated
188			.checked_sub(&amount)
189			.defensive_ok_or(ArithmeticError::Overflow)?;
190		let new_unclaimed_withdrawals = self
191			.ledger
192			.unclaimed_withdrawals
193			.checked_sub(&amount)
194			.defensive_ok_or(ArithmeticError::Overflow)?;
195
196		Ok(AgentLedgerOuter {
197			ledger: AgentLedger {
198				total_delegated: new_total_delegated,
199				unclaimed_withdrawals: new_unclaimed_withdrawals,
200				..self.ledger
201			},
202			..self
203		})
204	}
205
206	pub(crate) fn add_unclaimed_withdraw(
208		self,
209		amount: BalanceOf<T>,
210	) -> Result<Self, DispatchError> {
211		let new_unclaimed_withdrawals = self
212			.ledger
213			.unclaimed_withdrawals
214			.checked_add(&amount)
215			.defensive_ok_or(ArithmeticError::Overflow)?;
216
217		Ok(AgentLedgerOuter {
218			ledger: AgentLedger { unclaimed_withdrawals: new_unclaimed_withdrawals, ..self.ledger },
219			..self
220		})
221	}
222
223	pub(crate) fn available_to_bond(&self) -> BalanceOf<T> {
228		let bonded_stake = self.bonded_stake();
229		let stakeable = self.ledger.stakeable_balance();
230
231		defensive_assert!(
232			stakeable >= bonded_stake,
233			"cannot be bonded with more than total amount delegated to agent"
234		);
235
236		stakeable.saturating_sub(bonded_stake)
237	}
238
239	pub(crate) fn remove_slash(self, amount: BalanceOf<T>) -> Self {
241		let pending_slash = self.ledger.pending_slash.defensive_saturating_sub(amount);
242		let total_delegated = self.ledger.total_delegated.defensive_saturating_sub(amount);
243
244		AgentLedgerOuter {
245			ledger: AgentLedger { pending_slash, total_delegated, ..self.ledger },
246			..self
247		}
248	}
249
250	pub(crate) fn bonded_stake(&self) -> BalanceOf<T> {
252		T::CoreStaking::total_stake(&self.key).unwrap_or(Zero::zero())
253	}
254
255	pub(crate) fn is_bonded(&self) -> bool {
257		T::CoreStaking::stake(&self.key).is_ok()
258	}
259
260	pub(crate) fn reward_account(&self) -> &T::AccountId {
262		&self.ledger.payee
263	}
264
265	pub(crate) fn save(self) {
267		let key = self.key;
268		self.ledger.update(&key)
269	}
270
271	pub(crate) fn update(self) {
273		let key = self.key;
274		self.ledger.update(&key);
275	}
276
277	pub(crate) fn reload(self) -> Result<AgentLedgerOuter<T>, DispatchError> {
279		Self::get(&self.key)
280	}
281
282	#[cfg(test)]
287	pub(crate) fn total_unbonded(&self) -> BalanceOf<T> {
288		let bonded_stake = self.bonded_stake();
289
290		let net_balance = self.ledger.effective_balance();
291
292		assert!(net_balance >= bonded_stake, "cannot be bonded with more than the agent balance");
293
294		net_balance.saturating_sub(bonded_stake)
295	}
296}