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}