1use crate::app::CosmosRouter;
2use crate::error::{anyhow, bail, AnyResult};
3use crate::executor::AppResponse;
4use crate::prefixed_storage::typed_prefixed_storage::{
5 StoragePrefix, TypedPrefixedStorage, TypedPrefixedStorageMut,
6};
7use crate::{BankSudo, Module};
8use cosmwasm_std::{
9 coin, ensure, ensure_eq, to_json_binary, Addr, AllDelegationsResponse, AllValidatorsResponse,
10 Api, BankMsg, Binary, BlockInfo, BondedDenomResponse, Coin, CustomMsg, CustomQuery, Decimal,
11 Delegation, DelegationResponse, DelegatorWithdrawAddressResponse, DistributionMsg,
12 DistributionQuery, Empty, Event, FullDelegation, Order, Querier, StakingMsg, StakingQuery,
13 StdError, Storage, Timestamp, Uint128, Validator, ValidatorResponse,
14};
15#[cfg(feature = "cosmwasm_1_4")]
16use cosmwasm_std::{
17 DecCoin, Decimal256, DelegationRewardsResponse, DelegationTotalRewardsResponse,
18 DelegatorReward, DelegatorValidatorsResponse,
19};
20use cw_storage_plus::{Deque, Item, Map};
21use schemars::JsonSchema;
22use serde::{Deserialize, Serialize};
23use std::collections::{BTreeSet, VecDeque};
24
25const BONDED_DENOM: &str = "TOKEN";
27
28const YEAR: u64 = 60 * 60 * 24 * 365;
30
31#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
33pub struct StakingInfo {
34 pub bonded_denom: String,
36 pub unbonding_time: u64,
38 pub apr: Decimal,
40}
41
42impl Default for StakingInfo {
43 fn default() -> Self {
45 StakingInfo {
46 bonded_denom: BONDED_DENOM.to_string(),
47 unbonding_time: 60,
48 apr: Decimal::percent(10),
49 }
50 }
51}
52
53#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, JsonSchema)]
55struct Shares {
56 stake: Decimal,
57 rewards: Decimal,
58}
59
60impl Shares {
61 pub fn share_of_rewards(&self, validator_info: &ValidatorInfo, rewards: Decimal) -> Decimal {
63 if validator_info.stake.is_zero() {
64 return Decimal::zero();
65 }
66 rewards * self.stake / validator_info.stake
67 }
68}
69
70#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
72struct ValidatorInfo {
73 stakers: BTreeSet<Addr>,
76 stake: Uint128,
78 last_rewards_calculation: Timestamp,
80}
81
82impl ValidatorInfo {
83 pub fn new(block_time: Timestamp) -> Self {
84 Self {
85 stakers: BTreeSet::new(),
86 stake: Uint128::zero(),
87 last_rewards_calculation: block_time,
88 }
89 }
90}
91
92#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
93struct Unbonding {
94 pub delegator: Addr,
96 pub validator: String,
98 pub amount: Uint128,
100 pub payout_at: Timestamp,
102}
103
104const STAKING_INFO: Item<StakingInfo> = Item::new("staking_info");
105const STAKES: Map<(&Addr, &str), Shares> = Map::new("stakes");
107const VALIDATOR_MAP: Map<&str, Validator> = Map::new("validator_map");
108const VALIDATORS: Deque<Validator> = Deque::new("validators");
110const VALIDATOR_INFO: Map<&str, ValidatorInfo> = Map::new("validator_info");
112const UNBONDING_QUEUE: Item<VecDeque<Unbonding>> = Item::new("unbonding_queue");
114const WITHDRAW_ADDRESS: Map<&Addr, Addr> = Map::new("withdraw_address");
118
119#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)]
123pub enum StakingSudo {
124 Slash {
127 validator: String,
129 percentage: Decimal,
131 },
132}
133
134pub trait Staking: Module<ExecT = StakingMsg, QueryT = StakingQuery, SudoT = StakingSudo> {
139 fn process_queue<ExecC: CustomMsg, QueryC: CustomQuery>(
143 &self,
144 _api: &dyn Api,
145 _storage: &mut dyn Storage,
146 _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
147 _block: &BlockInfo,
148 ) -> AnyResult<AppResponse> {
149 Ok(AppResponse::default())
150 }
151}
152
153pub trait Distribution:
155 Module<ExecT = DistributionMsg, QueryT = DistributionQuery, SudoT = Empty>
156{
157}
158
159pub struct StakeKeeper {
161 module_addr: Addr,
163}
164
165impl Default for StakeKeeper {
166 fn default() -> Self {
168 StakeKeeper {
169 module_addr: Addr::unchecked("staking_module"),
171 }
172 }
173}
174
175impl StakeKeeper {
176 pub fn new() -> Self {
178 Self::default()
179 }
180
181 pub fn setup(&self, storage: &mut dyn Storage, staking_info: StakingInfo) -> AnyResult<()> {
183 STAKING_INFO.save(&mut StakingStorageMut::new(storage), &staking_info)?;
184 Ok(())
185 }
186
187 pub fn add_validator(
189 &self,
190 _api: &dyn Api,
191 storage: &mut dyn Storage,
192 block: &BlockInfo,
193 validator: Validator,
194 ) -> AnyResult<()> {
195 let mut storage = StakingStorageMut::new(storage);
196 if VALIDATOR_MAP
197 .may_load(&storage, &validator.address)?
198 .is_some()
199 {
200 bail!(
201 "Cannot add validator {}, since a validator with that address already exists",
202 validator.address
203 );
204 }
205 VALIDATOR_MAP.save(&mut storage, &validator.address, &validator)?;
206 VALIDATORS.push_back(&mut storage, &validator)?;
207 VALIDATOR_INFO.save(
208 &mut storage,
209 &validator.address,
210 &ValidatorInfo::new(block.time),
211 )?;
212 Ok(())
213 }
214
215 fn get_staking_info(storage: &StakingStorage) -> AnyResult<StakingInfo> {
216 Ok(STAKING_INFO.may_load(storage)?.unwrap_or_default())
217 }
218
219 pub fn get_rewards(
221 &self,
222 storage: &dyn Storage,
223 block: &BlockInfo,
224 delegator: &Addr,
225 validator: &str,
226 ) -> AnyResult<Option<Coin>> {
227 Self::get_rewards_internal(storage, block, delegator, validator)
228 }
229
230 fn get_rewards_internal(
231 storage: &dyn Storage,
232 block: &BlockInfo,
233 delegator: &Addr,
234 validator: &str,
235 ) -> AnyResult<Option<Coin>> {
236 let staking_storage = StakingStorage::new(storage);
237 let validator_obj = match Self::get_validator(&staking_storage, validator)? {
238 Some(validator) => validator,
239 None => bail!("validator {} not found", validator),
240 };
241 let shares = match STAKES.load(&staking_storage, (delegator, validator)) {
243 Ok(stakes) => stakes,
244 Err(_) => return Ok(None),
245 };
246 let validator_info = VALIDATOR_INFO.load(&staking_storage, validator)?;
247 Self::get_rewards_from_validator(
248 &staking_storage,
249 block,
250 &shares,
251 &validator_obj,
252 &validator_info,
253 )
254 .map(Some)
255 }
256
257 fn get_rewards_from_validator(
258 storage: &StakingStorage,
259 block: &BlockInfo,
260 shares: &Shares,
261 validator: &Validator,
262 validator_info: &ValidatorInfo,
263 ) -> AnyResult<Coin> {
264 let staking_info = Self::get_staking_info(storage)?;
265
266 let new_validator_rewards = Self::calculate_rewards(
268 block.time,
269 validator_info.last_rewards_calculation,
270 staking_info.apr,
271 validator.commission,
272 validator_info.stake,
273 );
274
275 let delegator_rewards =
277 shares.rewards + shares.share_of_rewards(validator_info, new_validator_rewards);
278
279 Ok(Coin {
280 denom: staking_info.bonded_denom,
281 amount: Uint128::new(1).mul_floor(delegator_rewards), })
283 }
284
285 fn calculate_rewards(
287 current_time: Timestamp,
288 since: Timestamp,
289 interest_rate: Decimal,
290 validator_commission: Decimal,
291 stake: Uint128,
292 ) -> Decimal {
293 let time_diff = current_time.minus_seconds(since.seconds()).seconds();
295
296 let reward = Decimal::from_ratio(stake, 1u128)
298 * interest_rate
299 * Decimal::from_ratio(time_diff, 1u128)
300 / Decimal::from_ratio(YEAR, 1u128);
301 let commission = reward * validator_commission;
302
303 reward - commission
304 }
305
306 fn update_rewards(
310 _api: &dyn Api,
311 storage: &mut StakingStorageMut,
312 block: &BlockInfo,
313 validator: &str,
314 ) -> AnyResult<()> {
315 let staking_info = Self::get_staking_info(&storage.borrow())?;
316
317 let mut validator_info = VALIDATOR_INFO
318 .may_load(storage, validator)?
319 .ok_or_else(|| anyhow!("validator does not exist"))?;
321
322 let validator_obj = VALIDATOR_MAP.load(storage, validator)?;
323
324 if validator_info.last_rewards_calculation >= block.time {
325 return Ok(());
326 }
327
328 let new_rewards = Self::calculate_rewards(
329 block.time,
330 validator_info.last_rewards_calculation,
331 staking_info.apr,
332 validator_obj.commission,
333 validator_info.stake,
334 );
335
336 validator_info.last_rewards_calculation = block.time;
338 VALIDATOR_INFO.save(storage, validator, &validator_info)?;
339
340 if !new_rewards.is_zero() {
342 for staker in validator_info.stakers.iter() {
344 STAKES.update(
345 storage,
346 (staker, &validator_obj.address),
347 |shares| -> AnyResult<_> {
348 let mut shares =
349 shares.expect("all stakers in validator_info should exist");
350 shares.rewards += shares.share_of_rewards(&validator_info, new_rewards);
351 Ok(shares)
352 },
353 )?;
354 }
355 }
356 Ok(())
357 }
358
359 fn get_validator(storage: &StakingStorage, address: &str) -> AnyResult<Option<Validator>> {
361 Ok(VALIDATOR_MAP.may_load(storage, address)?)
362 }
363
364 fn get_validators(&self, storage: &StakingStorage) -> AnyResult<Vec<Validator>> {
366 let res: Result<_, _> = VALIDATORS.iter(storage)?.collect();
367 Ok(res?)
368 }
369
370 fn get_stake(
371 &self,
372 storage: &StakingStorage,
373 account: &Addr,
374 validator: &str,
375 ) -> AnyResult<Option<Coin>> {
376 let shares = STAKES.may_load(storage, (account, validator))?;
377 let staking_info = Self::get_staking_info(storage)?;
378 Ok(shares.map(|shares| {
379 Coin {
380 denom: staking_info.bonded_denom,
381 amount: Uint128::new(1).mul_floor(shares.stake), }
383 }))
384 }
385
386 fn add_stake(
387 &self,
388 api: &dyn Api,
389 storage: &mut StakingStorageMut,
390 block: &BlockInfo,
391 to_address: &Addr,
392 validator: &str,
393 amount: Coin,
394 ) -> AnyResult<()> {
395 self.validate_denom(&storage.borrow(), &amount)?;
396 self.update_stake(
397 api,
398 storage,
399 block,
400 to_address,
401 validator,
402 amount.amount,
403 false,
404 )
405 }
406
407 fn remove_stake(
408 &self,
409 api: &dyn Api,
410 storage: &mut StakingStorageMut,
411 block: &BlockInfo,
412 from_address: &Addr,
413 validator: &str,
414 amount: Coin,
415 ) -> AnyResult<()> {
416 self.validate_denom(&storage.borrow(), &amount)?;
417 self.update_stake(
418 api,
419 storage,
420 block,
421 from_address,
422 validator,
423 amount.amount,
424 true,
425 )
426 }
427
428 fn update_stake(
429 &self,
430 api: &dyn Api,
431 storage: &mut StakingStorageMut,
432 block: &BlockInfo,
433 delegator: &Addr,
434 validator: &str,
435 amount: impl Into<Uint128>,
436 sub: bool,
437 ) -> AnyResult<()> {
438 let amount = amount.into();
439
440 Self::update_rewards(api, storage, block, validator)?;
442
443 let mut validator_info = VALIDATOR_INFO
445 .may_load(storage, validator)?
446 .unwrap_or_else(|| ValidatorInfo::new(block.time));
447 let shares = STAKES.may_load(storage, (delegator, validator))?;
448 let mut shares = if sub {
449 shares.ok_or_else(|| anyhow!("no delegation for (address, validator) tuple"))?
452 } else {
453 shares.unwrap_or_default()
454 };
455
456 let amount_dec = Decimal::from_ratio(amount, 1u128);
457 if sub {
458 if amount_dec > shares.stake {
460 bail!("invalid shares amount");
461 }
462 shares.stake -= amount_dec;
463 validator_info.stake = validator_info.stake.checked_sub(amount)?;
464 } else {
465 shares.stake += amount_dec;
466 validator_info.stake = validator_info.stake.checked_add(amount)?;
467 }
468
469 if shares.stake.is_zero() {
471 STAKES.remove(storage, (delegator, validator));
473 validator_info.stakers.remove(delegator);
474 } else {
475 STAKES.save(storage, (delegator, validator), &shares)?;
476 validator_info.stakers.insert(delegator.clone());
477 }
478 VALIDATOR_INFO.save(storage, validator, &validator_info)?;
480
481 Ok(())
482 }
483
484 fn slash(
485 &self,
486 api: &dyn Api,
487 storage: &mut StakingStorageMut,
488 block: &BlockInfo,
489 validator: &str,
490 percentage: Decimal,
491 ) -> AnyResult<()> {
492 Self::update_rewards(api, storage, block, validator)?;
494
495 let mut validator_info = VALIDATOR_INFO.may_load(storage, validator)?.unwrap();
497
498 let remaining_percentage = Decimal::one() - percentage;
499 validator_info.stake = validator_info.stake.mul_floor(remaining_percentage);
500
501 if validator_info.stake.is_zero() {
503 for delegator in validator_info.stakers.iter() {
505 STAKES.remove(storage, (delegator, validator));
506 }
507 validator_info.stakers.clear();
508 } else {
509 for delegator in validator_info.stakers.iter() {
511 STAKES.update(storage, (delegator, validator), |stake| -> AnyResult<_> {
512 let mut stake = stake.expect("all stakers in validator_info should exist");
513 stake.stake *= remaining_percentage;
514
515 Ok(stake)
516 })?;
517 }
518 }
519 let mut unbonding_queue = UNBONDING_QUEUE.may_load(storage)?.unwrap_or_default();
521 unbonding_queue
522 .iter_mut()
523 .filter(|ub| ub.validator == validator)
524 .for_each(|ub| {
525 ub.amount = ub.amount.mul_floor(remaining_percentage);
526 });
527 UNBONDING_QUEUE.save(storage, &unbonding_queue)?;
528
529 VALIDATOR_INFO.save(storage, validator, &validator_info)?;
530 Ok(())
531 }
532
533 fn validate_denom(&self, storage: &StakingStorage, amount: &Coin) -> AnyResult<()> {
535 let staking_info = Self::get_staking_info(storage)?;
536 ensure_eq!(
537 amount.denom,
538 staking_info.bonded_denom,
539 anyhow!(
540 "cannot delegate coins of denominator {}, only of {}",
541 amount.denom,
542 staking_info.bonded_denom
543 )
544 );
545 Ok(())
546 }
547
548 fn validate_percentage(&self, percentage: Decimal) -> AnyResult<()> {
550 ensure!(percentage <= Decimal::one(), anyhow!("expected percentage"));
551 Ok(())
552 }
553
554 fn process_queue<ExecC: CustomMsg, QueryC: CustomQuery>(
555 &self,
556 api: &dyn Api,
557 storage: &mut dyn Storage,
558 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
559 block: &BlockInfo,
560 ) -> AnyResult<AppResponse> {
561 let mut unbonding_queue = UNBONDING_QUEUE
562 .may_load(&StakingStorage::new(storage))?
563 .unwrap_or_default();
564 loop {
565 match unbonding_queue.front() {
566 Some(Unbonding { payout_at, .. }) if payout_at <= &block.time => {
568 let mut staking_storage_mut = StakingStorageMut::new(storage);
569
570 let Unbonding {
572 delegator,
573 validator,
574 amount,
575 ..
576 } = unbonding_queue.pop_front().unwrap();
577
578 let delegation = self
580 .get_stake(&staking_storage_mut.borrow(), &delegator, &validator)?
581 .map(|mut stake| {
582 stake.amount += unbonding_queue
584 .iter()
585 .filter(|u| u.delegator == delegator && u.validator == validator)
586 .map(|u| u.amount)
587 .sum::<Uint128>();
588 stake
589 });
590 match delegation {
591 Some(delegation) if delegation.amount.is_zero() => {
592 STAKES.remove(&mut staking_storage_mut, (&delegator, &validator));
593 }
594 None => {
595 STAKES.remove(&mut staking_storage_mut, (&delegator, &validator));
596 }
597 _ => {}
598 }
599
600 let staking_info = Self::get_staking_info(&staking_storage_mut.borrow())?;
601 if !amount.is_zero() {
602 router.execute(
603 api,
604 storage,
605 block,
606 self.module_addr.clone(),
607 BankMsg::Send {
608 to_address: delegator.into_string(),
609 amount: vec![coin(amount.u128(), &staking_info.bonded_denom)],
610 }
611 .into(),
612 )?;
613 }
614 }
615 _ => break,
616 }
617 }
618 UNBONDING_QUEUE.save(&mut StakingStorageMut::new(storage), &unbonding_queue)?;
619 Ok(AppResponse::default())
620 }
621}
622
623impl Staking for StakeKeeper {
624 fn process_queue<ExecC: CustomMsg, QueryC: CustomQuery>(
625 &self,
626 api: &dyn Api,
627 storage: &mut dyn Storage,
628 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
629 block: &BlockInfo,
630 ) -> AnyResult<AppResponse> {
631 self.process_queue(api, storage, router, block)
632 }
633}
634
635impl StoragePrefix for StakeKeeper {
636 const NAMESPACE: &'static [u8] = b"staking";
637}
638type StakingStorage<'a> = TypedPrefixedStorage<'a, StakeKeeper>;
639type StakingStorageMut<'a> = TypedPrefixedStorageMut<'a, StakeKeeper>;
640
641impl Module for StakeKeeper {
642 type ExecT = StakingMsg;
643 type QueryT = StakingQuery;
644 type SudoT = StakingSudo;
645
646 fn execute<ExecC: CustomMsg, QueryC: CustomQuery>(
647 &self,
648 api: &dyn Api,
649 storage: &mut dyn Storage,
650 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
651 block: &BlockInfo,
652 sender: Addr,
653 msg: StakingMsg,
654 ) -> AnyResult<AppResponse> {
655 let mut staking_storage_mut = StakingStorageMut::new(storage);
656 match msg {
657 StakingMsg::Delegate { validator, amount } => {
658 if amount.amount.is_zero() {
660 bail!("invalid delegation amount");
661 }
662
663 let events = vec![Event::new("delegate")
665 .add_attribute("validator", &validator)
666 .add_attribute("amount", format!("{}{}", amount.amount, amount.denom))
667 .add_attribute("new_shares", amount.amount.to_string())]; self.add_stake(
669 api,
670 &mut staking_storage_mut,
671 block,
672 &sender,
673 &validator,
674 amount.clone(),
675 )?;
676 router.execute(
678 api,
679 storage,
680 block,
681 sender,
682 BankMsg::Send {
683 to_address: self.module_addr.to_string(),
684 amount: vec![amount],
685 }
686 .into(),
687 )?;
688 Ok(AppResponse {
689 events,
690 ..Default::default()
691 })
692 }
693 StakingMsg::Undelegate { validator, amount } => {
694 self.validate_denom(&staking_storage_mut.borrow(), &amount)?;
695
696 if amount.amount.is_zero() {
698 bail!("invalid shares amount");
699 }
700
701 let events = vec![Event::new("unbond")
703 .add_attribute("validator", &validator)
704 .add_attribute("amount", format!("{}{}", amount.amount, amount.denom))
705 .add_attribute("completion_time", "2022-09-27T14:00:00+00:00")]; self.remove_stake(
707 api,
708 &mut staking_storage_mut,
709 block,
710 &sender,
711 &validator,
712 amount.clone(),
713 )?;
714 let staking_info = Self::get_staking_info(&staking_storage_mut.borrow())?;
716 let mut unbonding_queue = UNBONDING_QUEUE
717 .may_load(&staking_storage_mut)?
718 .unwrap_or_default();
719 unbonding_queue.push_back(Unbonding {
720 delegator: sender.clone(),
721 validator,
722 amount: amount.amount,
723 payout_at: block.time.plus_seconds(staking_info.unbonding_time),
724 });
725 UNBONDING_QUEUE.save(&mut staking_storage_mut, &unbonding_queue)?;
726 Ok(AppResponse {
727 events,
728 ..Default::default()
729 })
730 }
731 StakingMsg::Redelegate {
732 src_validator,
733 dst_validator,
734 amount,
735 } => {
736 let events = vec![Event::new("redelegate")
738 .add_attribute("source_validator", &src_validator)
739 .add_attribute("destination_validator", &dst_validator)
740 .add_attribute("amount", format!("{}{}", amount.amount, amount.denom))];
741
742 self.remove_stake(
743 api,
744 &mut staking_storage_mut,
745 block,
746 &sender,
747 &src_validator,
748 amount.clone(),
749 )?;
750 self.add_stake(
751 api,
752 &mut staking_storage_mut,
753 block,
754 &sender,
755 &dst_validator,
756 amount,
757 )?;
758
759 Ok(AppResponse {
760 events,
761 ..Default::default()
762 })
763 }
764 m => bail!("Unsupported staking message: {:?}", m),
765 }
766 }
767
768 fn query(
769 &self,
770 api: &dyn Api,
771 storage: &dyn Storage,
772 _querier: &dyn Querier,
773 block: &BlockInfo,
774 request: StakingQuery,
775 ) -> AnyResult<Binary> {
776 let staking_storage = StakingStorage::new(storage);
777 match request {
778 StakingQuery::BondedDenom {} => Ok(to_json_binary(&BondedDenomResponse::new(
779 Self::get_staking_info(&staking_storage)?.bonded_denom,
780 ))?),
781 StakingQuery::AllDelegations { delegator } => {
782 let delegator = api.addr_validate(&delegator)?;
783 let validators = self.get_validators(&staking_storage)?;
784
785 let res: AnyResult<Vec<Delegation>> =
786 validators
787 .into_iter()
788 .filter_map(|validator| {
789 let delegator = delegator.clone();
790 let amount = self
791 .get_stake(&staking_storage, &delegator, &validator.address)
792 .transpose()?;
793
794 Some(amount.map(|amount| {
795 Delegation::new(delegator, validator.address, amount)
796 }))
797 })
798 .collect();
799
800 Ok(to_json_binary(&AllDelegationsResponse::new(res?))?)
801 }
802 StakingQuery::Delegation {
803 delegator,
804 validator,
805 } => {
806 let validator_obj = match Self::get_validator(&staking_storage, &validator)? {
807 Some(validator) => validator,
808 None => bail!("non-existent validator {}", validator),
809 };
810 let delegator = api.addr_validate(&delegator)?;
811
812 let shares = STAKES
813 .may_load(&staking_storage, (&delegator, &validator))?
814 .unwrap_or_default();
815
816 let validator_info = VALIDATOR_INFO.load(&staking_storage, &validator)?;
817 let reward = Self::get_rewards_from_validator(
818 &staking_storage,
819 block,
820 &shares,
821 &validator_obj,
822 &validator_info,
823 )?;
824 let staking_info = Self::get_staking_info(&staking_storage)?;
825
826 let amount = coin(
827 Uint128::new(1).mul_floor(shares.stake).u128(),
828 staking_info.bonded_denom,
829 );
830
831 let full_delegation_response = if amount.amount.is_zero() {
832 DelegationResponse::new(None)
834 } else {
835 DelegationResponse::new(Some(FullDelegation::new(
836 delegator,
837 validator,
838 amount.clone(),
839 amount, if reward.amount.is_zero() {
841 vec![]
842 } else {
843 vec![reward]
844 },
845 )))
846 };
847
848 let res = to_json_binary(&full_delegation_response)?;
849 Ok(res)
850 }
851 StakingQuery::AllValidators {} => Ok(to_json_binary(&AllValidatorsResponse::new(
852 self.get_validators(&staking_storage)?,
853 ))?),
854 StakingQuery::Validator { address } => Ok(to_json_binary(&ValidatorResponse::new(
855 Self::get_validator(&staking_storage, &address)?,
856 ))?),
857 q => bail!("Unsupported staking sudo message: {:?}", q),
858 }
859 }
860
861 fn sudo<ExecC: CustomMsg, QueryC: CustomQuery>(
862 &self,
863 api: &dyn Api,
864 storage: &mut dyn Storage,
865 _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
866 block: &BlockInfo,
867 msg: StakingSudo,
868 ) -> AnyResult<AppResponse> {
869 match msg {
870 StakingSudo::Slash {
871 validator,
872 percentage,
873 } => {
874 let mut staking_storage = StakingStorageMut::new(storage);
875 self.validate_percentage(percentage)?;
876 self.slash(api, &mut staking_storage, block, &validator, percentage)?;
877 Ok(AppResponse::default())
878 }
879 }
880 }
881}
882
883#[derive(Default)]
889pub struct DistributionKeeper {}
890
891impl DistributionKeeper {
892 pub fn new() -> Self {
894 Self::default()
895 }
896
897 pub fn remove_rewards(
899 &self,
900 api: &dyn Api,
901 storage: &mut dyn Storage,
902 block: &BlockInfo,
903 delegator: &Addr,
904 validator: &str,
905 ) -> AnyResult<Uint128> {
906 let mut staking_storage_mut = StakingStorageMut::new(storage);
907 StakeKeeper::update_rewards(api, &mut staking_storage_mut, block, validator)?;
909
910 let mut shares = STAKES.load(&staking_storage_mut, (delegator, validator))?;
912 let rewards = Uint128::new(1).mul_floor(shares.rewards); shares.rewards = Decimal::zero();
916 STAKES.save(&mut staking_storage_mut, (delegator, validator), &shares)?;
917
918 Ok(rewards)
919 }
920
921 pub fn get_withdraw_address(storage: &dyn Storage, delegator_addr: &Addr) -> AnyResult<Addr> {
923 let storage = DistributionStorage::new(storage);
924 Ok(match WITHDRAW_ADDRESS.may_load(&storage, delegator_addr)? {
925 Some(withdraw_addr) => withdraw_addr,
926 None => delegator_addr.clone(),
927 })
928 }
929
930 pub fn set_withdraw_address(
934 storage: &mut dyn Storage,
935 delegator_addr: &Addr,
936 withdraw_addr: &Addr,
937 ) -> AnyResult<()> {
938 let mut storage = DistributionStorageMut::new(storage);
939 if delegator_addr == withdraw_addr {
940 WITHDRAW_ADDRESS.remove(&mut storage, delegator_addr);
941 Ok(())
942 } else {
943 WITHDRAW_ADDRESS
945 .save(&mut storage, delegator_addr, withdraw_addr)
946 .map_err(|e| e.into())
947 }
948 }
949
950 pub fn get_delegator_validators(
952 &self,
953 storage: &dyn Storage,
954 delegator_addr: &Addr,
955 ) -> AnyResult<Vec<String>> {
956 let storage = StakingStorage::new(storage);
957 Ok(STAKES
958 .prefix(delegator_addr)
959 .keys(&storage, None, None, Order::Ascending)
960 .collect::<Result<Vec<String>, StdError>>()?)
961 }
962
963 #[cfg(feature = "cosmwasm_1_4")]
965 pub fn get_rewards(
966 &self,
967 storage: &dyn Storage,
968 block: &BlockInfo,
969 delegator_address: &Addr,
970 validator_address: &str,
971 ) -> AnyResult<Option<DecCoin>> {
972 Ok(
973 if let Some(coin) = StakeKeeper::get_rewards_internal(
974 storage,
975 block,
976 delegator_address,
977 validator_address,
978 )? {
979 Some(DecCoin::new(
980 Decimal256::from_atomics(coin.amount, 0)?,
981 coin.denom,
982 ))
983 } else {
984 None
985 },
986 )
987 }
988}
989
990impl Distribution for DistributionKeeper {}
991
992impl StoragePrefix for DistributionKeeper {
993 const NAMESPACE: &'static [u8] = b"distribution";
994}
995type DistributionStorage<'a> = TypedPrefixedStorage<'a, DistributionKeeper>;
996type DistributionStorageMut<'a> = TypedPrefixedStorageMut<'a, DistributionKeeper>;
997
998impl Module for DistributionKeeper {
999 type ExecT = DistributionMsg;
1000 type QueryT = DistributionQuery;
1001 type SudoT = Empty;
1002
1003 fn execute<ExecC: CustomMsg, QueryC: CustomQuery>(
1004 &self,
1005 api: &dyn Api,
1006 storage: &mut dyn Storage,
1007 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1008 block: &BlockInfo,
1009 sender: Addr,
1010 msg: DistributionMsg,
1011 ) -> AnyResult<AppResponse> {
1012 match msg {
1013 DistributionMsg::WithdrawDelegatorReward { validator } => {
1014 let rewards = self.remove_rewards(api, storage, block, &sender, &validator)?;
1015 let staking_storage = StakingStorage::new(storage);
1016 let staking_info = StakeKeeper::get_staking_info(&staking_storage)?;
1017 let receiver = Self::get_withdraw_address(storage, &sender)?;
1018 router.sudo(
1020 api,
1021 storage,
1022 block,
1023 BankSudo::Mint {
1024 to_address: receiver.into_string(),
1025 amount: vec![Coin {
1026 amount: rewards,
1027 denom: staking_info.bonded_denom.clone(),
1028 }],
1029 }
1030 .into(),
1031 )?;
1032
1033 let events = vec![Event::new("withdraw_delegator_reward")
1034 .add_attribute("validator", &validator)
1035 .add_attribute("sender", &sender)
1036 .add_attribute(
1037 "amount",
1038 format!("{}{}", rewards, staking_info.bonded_denom),
1039 )];
1040 Ok(AppResponse {
1041 events,
1042 ..Default::default()
1043 })
1044 }
1045 DistributionMsg::SetWithdrawAddress { address } => {
1046 let address = api.addr_validate(&address)?;
1047 Self::set_withdraw_address(storage, &sender, &address)?;
1049 Ok(AppResponse {
1050 events: vec![Event::new("set_withdraw_address")
1052 .add_attribute("withdraw_address", address)],
1053 ..Default::default()
1054 })
1055 }
1056 other => bail!("Unsupported distribution message: {:?}", other),
1057 }
1058 }
1059
1060 fn query(
1061 &self,
1062 api: &dyn Api,
1063 storage: &dyn Storage,
1064 _querier: &dyn Querier,
1065 block: &BlockInfo,
1066 request: DistributionQuery,
1067 ) -> AnyResult<Binary> {
1068 match request {
1069 #[cfg(feature = "cosmwasm_1_4")]
1070 DistributionQuery::DelegatorValidators { delegator_address } => {
1071 let delegator_address = api.addr_validate(&delegator_address)?;
1072 let validators = self.get_delegator_validators(storage, &delegator_address)?;
1073 Ok(to_json_binary(&DelegatorValidatorsResponse::new(
1074 validators,
1075 ))?)
1076 }
1077 DistributionQuery::DelegatorWithdrawAddress { delegator_address } => {
1078 let delegator_address = api.addr_validate(&delegator_address)?;
1079 let withdraw_address = Self::get_withdraw_address(storage, &delegator_address)?;
1080 Ok(to_json_binary(&DelegatorWithdrawAddressResponse::new(
1081 withdraw_address,
1082 ))?)
1083 }
1084 #[cfg(feature = "cosmwasm_1_4")]
1085 DistributionQuery::DelegationRewards {
1086 delegator_address,
1087 validator_address,
1088 } => {
1089 let delegator_address = api.addr_validate(&delegator_address)?;
1090 let rewards = if let Some(dec_coin) =
1091 self.get_rewards(storage, block, &delegator_address, &validator_address)?
1092 {
1093 vec![dec_coin]
1094 } else {
1095 vec![]
1096 };
1097 Ok(to_json_binary(&DelegationRewardsResponse::new(rewards))?)
1098 }
1099 #[cfg(feature = "cosmwasm_1_4")]
1100 DistributionQuery::DelegationTotalRewards { delegator_address } => {
1101 let delegator_address = api.addr_validate(&delegator_address)?;
1102 let mut delegator_rewards = vec![];
1103 let mut total_rewards = std::collections::BTreeMap::new();
1104 for validator_address in
1105 self.get_delegator_validators(storage, &delegator_address)?
1106 {
1107 if let Some(dec_coin) =
1108 self.get_rewards(storage, block, &delegator_address, &validator_address)?
1109 {
1110 delegator_rewards.push(DelegatorReward::new(
1111 validator_address.clone(),
1112 vec![dec_coin.clone()],
1113 ));
1114 total_rewards
1115 .entry(dec_coin.denom)
1116 .and_modify(|value| *value += dec_coin.amount)
1117 .or_insert(dec_coin.amount);
1118 }
1119 }
1120 let total_rewards = total_rewards
1121 .iter()
1122 .map(|(denom, amount)| DecCoin::new(*amount, denom))
1123 .collect();
1124 Ok(to_json_binary(&DelegationTotalRewardsResponse::new(
1125 delegator_rewards,
1126 total_rewards,
1127 ))?)
1128 }
1129 other => {
1130 let _ = block; bail!("Unsupported distribution query: {:?}", other)
1132 }
1133 }
1134 }
1135
1136 fn sudo<ExecC, QueryC>(
1137 &self,
1138 _api: &dyn Api,
1139 _storage: &mut dyn Storage,
1140 _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1141 _block: &BlockInfo,
1142 _msg: Empty,
1143 ) -> AnyResult<AppResponse> {
1144 bail!("Something went wrong - distribution doesn't have sudo messages")
1145 }
1146}
1147
1148#[cfg(test)]
1149mod test {
1150 use super::*;
1151 use crate::{
1152 BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, IntoBech32, Router,
1153 StargateFailing, WasmKeeper,
1154 };
1155 use cosmwasm_std::{
1156 coins, from_json,
1157 testing::{mock_env, MockApi, MockStorage},
1158 BalanceResponse, BankQuery, QuerierWrapper,
1159 };
1160 use serde::de::DeserializeOwned;
1161
1162 struct ValidatorProperties {
1165 commission: Decimal,
1167 max_commission: Decimal,
1169 max_change_rate: Decimal,
1171 }
1172
1173 fn vp(commission: u64, max_commission: u64, max_change_rate: u64) -> ValidatorProperties {
1175 ValidatorProperties {
1176 commission: Decimal::percent(commission),
1177 max_commission: Decimal::percent(max_commission),
1178 max_change_rate: Decimal::percent(max_change_rate),
1179 }
1180 }
1181
1182 type BasicRouter<ExecC = Empty, QueryC = Empty> = Router<
1184 BankKeeper,
1185 FailingModule<ExecC, QueryC, Empty>,
1186 WasmKeeper<ExecC, QueryC>,
1187 StakeKeeper,
1188 DistributionKeeper,
1189 IbcFailingModule,
1190 GovFailingModule,
1191 StargateFailing,
1192 >;
1193
1194 struct TestEnv {
1196 api: MockApi,
1197 storage: MockStorage,
1198 router: BasicRouter,
1199 block: BlockInfo,
1200 validator_addr_1: String,
1201 validator_addr_2: String,
1202 validator_addr_3: String,
1203 delegator_addr_1: Addr,
1204 delegator_addr_2: Addr,
1205 user_addr_1: Addr,
1206 }
1207
1208 impl TestEnv {
1209 fn new(validator1: ValidatorProperties, validator2: ValidatorProperties) -> Self {
1211 fn validator_address(value: &str) -> String {
1214 value.into_bech32_with_prefix("cosmwasmvaloper").to_string()
1215 }
1216
1217 fn user_address(api: &MockApi, value: &str) -> Addr {
1220 api.addr_make(value)
1221 }
1222
1223 let api = MockApi::default();
1224 let router = Router {
1225 wasm: WasmKeeper::new(),
1226 bank: BankKeeper::new(),
1227 custom: FailingModule::new(),
1228 staking: StakeKeeper::new(),
1229 distribution: DistributionKeeper::new(),
1230 ibc: IbcFailingModule::new(),
1231 gov: GovFailingModule::new(),
1232 stargate: StargateFailing,
1233 };
1234 let mut storage = MockStorage::new();
1235 let block = mock_env().block;
1236
1237 let validator_addr_1 = validator_address("validator1");
1238 let validator_addr_2 = validator_address("validator2");
1239 let validator_addr_3 = validator_address("validator3");
1240
1241 router
1243 .staking
1244 .setup(&mut storage, StakingInfo::default())
1245 .unwrap();
1246
1247 let valoper1 = Validator::new(
1249 validator_addr_1.to_string(),
1250 validator1.commission,
1251 validator1.max_commission,
1252 validator1.max_change_rate,
1253 );
1254 router
1255 .staking
1256 .add_validator(&api, &mut storage, &block, valoper1)
1257 .unwrap();
1258
1259 let valoper2 = Validator::new(
1261 validator_addr_2.to_string(),
1262 validator2.commission,
1263 validator2.max_commission,
1264 validator2.max_change_rate,
1265 );
1266 router
1267 .staking
1268 .add_validator(&api, &mut storage, &block, valoper2)
1269 .unwrap();
1270
1271 Self {
1273 api,
1274 storage,
1275 router,
1276 block,
1277 validator_addr_1,
1278 validator_addr_2,
1279 validator_addr_3,
1280 delegator_addr_1: user_address(&api, "delegator1"),
1281 delegator_addr_2: user_address(&api, "delegator2"),
1282 user_addr_1: user_address(&api, "user1"),
1283 }
1284 }
1285
1286 #[inline(always)]
1288 fn validator_addr_1(&self) -> String {
1289 self.validator_addr_1.clone()
1290 }
1291
1292 #[inline(always)]
1294 fn validator_addr_2(&self) -> String {
1295 self.validator_addr_2.clone()
1296 }
1297
1298 #[inline(always)]
1300 fn validator_addr_3(&self) -> String {
1301 self.validator_addr_3.clone()
1302 }
1303
1304 #[inline(always)]
1306 fn delegator_addr_1(&self) -> Addr {
1307 self.delegator_addr_1.clone()
1308 }
1309
1310 #[inline(always)]
1312 fn delegator_addr_2(&self) -> Addr {
1313 self.delegator_addr_2.clone()
1314 }
1315
1316 #[inline(always)]
1318 fn user_addr_1(&self) -> Addr {
1319 self.user_addr_1.clone()
1320 }
1321 }
1322
1323 fn execute_stake(env: &mut TestEnv, sender: Addr, msg: StakingMsg) -> AnyResult<AppResponse> {
1325 env.router.staking.execute(
1326 &env.api,
1327 &mut env.storage,
1328 &env.router,
1329 &env.block,
1330 sender,
1331 msg,
1332 )
1333 }
1334
1335 fn query_stake<T: DeserializeOwned>(env: &TestEnv, msg: StakingQuery) -> AnyResult<T> {
1337 Ok(from_json(env.router.staking.query(
1338 &env.api,
1339 &env.storage,
1340 &env.router.querier(&env.api, &env.storage, &env.block),
1341 &env.block,
1342 msg,
1343 )?)?)
1344 }
1345
1346 fn execute_distr(
1348 env: &mut TestEnv,
1349 sender: Addr,
1350 msg: DistributionMsg,
1351 ) -> AnyResult<AppResponse> {
1352 env.router.distribution.execute(
1353 &env.api,
1354 &mut env.storage,
1355 &env.router,
1356 &env.block,
1357 sender,
1358 msg,
1359 )
1360 }
1361
1362 fn query_bank<T: DeserializeOwned>(env: &TestEnv, msg: BankQuery) -> AnyResult<T> {
1364 Ok(from_json(env.router.bank.query(
1365 &env.api,
1366 &env.storage,
1367 &env.router.querier(&env.api, &env.storage, &env.block),
1368 &env.block,
1369 msg,
1370 )?)?)
1371 }
1372
1373 fn init_balance(env: &mut TestEnv, address: &Addr, amount: u128) {
1375 init_balance_denom(env, address, amount, BONDED_DENOM);
1376 }
1377
1378 fn init_balance_denom(env: &mut TestEnv, address: &Addr, amount: u128, denom: &str) {
1380 env.router
1381 .bank
1382 .init_balance(&mut env.storage, address, coins(amount, denom))
1383 .unwrap();
1384 }
1385
1386 fn assert_balances(env: &TestEnv, balances: impl IntoIterator<Item = (Addr, u128)>) {
1388 for (addr, amount) in balances {
1389 let balance: BalanceResponse = query_bank(
1390 env,
1391 BankQuery::Balance {
1392 address: addr.to_string(),
1393 denom: BONDED_DENOM.to_string(),
1394 },
1395 )
1396 .unwrap();
1397 assert_eq!(balance.amount.amount.u128(), amount);
1398 }
1399 }
1400
1401 #[test]
1402 fn add_get_validators() {
1403 let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1));
1404
1405 let validator_addr_3 = env.validator_addr_3();
1406
1407 let validator = Validator::new(
1409 validator_addr_3.to_string(),
1410 Decimal::percent(1),
1411 Decimal::percent(10),
1412 Decimal::percent(1),
1413 );
1414 env.router
1415 .staking
1416 .add_validator(&env.api, &mut env.storage, &env.block, validator.clone())
1417 .unwrap();
1418
1419 let val = StakeKeeper::get_validator(&StakingStorage::new(&env.storage), &validator_addr_3)
1421 .unwrap()
1422 .unwrap();
1423 assert_eq!(val, validator);
1424
1425 let validator_fake = Validator::new(
1427 validator_addr_3.to_string(),
1428 Decimal::percent(2),
1429 Decimal::percent(20),
1430 Decimal::percent(2),
1431 );
1432 env.router
1433 .staking
1434 .add_validator(&env.api, &mut env.storage, &env.block, validator_fake)
1435 .unwrap_err();
1436
1437 let val = StakeKeeper::get_validator(&StakingStorage::new(&env.storage), &validator_addr_3)
1439 .unwrap()
1440 .unwrap();
1441 assert_eq!(val, validator);
1442 }
1443
1444 #[test]
1445 fn validator_slashing() {
1446 let mut env = TestEnv::new(vp(10, 20, 1), vp(10, 20, 1));
1447
1448 let validator_addr_1 = env.validator_addr_1();
1449 let delegator_addr_1 = env.delegator_addr_1();
1450
1451 let mut staking_storage_mut = StakingStorageMut::new(&mut env.storage);
1453 env.router
1454 .staking
1455 .add_stake(
1456 &env.api,
1457 &mut staking_storage_mut,
1458 &env.block,
1459 &delegator_addr_1,
1460 &validator_addr_1,
1461 coin(100, BONDED_DENOM),
1462 )
1463 .unwrap();
1464
1465 env.router
1467 .staking
1468 .sudo(
1469 &env.api,
1470 &mut env.storage,
1471 &env.router,
1472 &env.block,
1473 StakingSudo::Slash {
1474 validator: validator_addr_1.to_string(),
1475 percentage: Decimal::percent(50),
1476 },
1477 )
1478 .unwrap();
1479
1480 let stake_left = env
1482 .router
1483 .staking
1484 .get_stake(
1485 &StakingStorage::new(&env.storage),
1486 &delegator_addr_1,
1487 &validator_addr_1,
1488 )
1489 .unwrap()
1490 .unwrap();
1491 assert_eq!(50, stake_left.amount.u128());
1492
1493 env.router
1495 .staking
1496 .sudo(
1497 &env.api,
1498 &mut env.storage,
1499 &env.router,
1500 &env.block,
1501 StakingSudo::Slash {
1502 validator: validator_addr_1.to_string(),
1503 percentage: Decimal::percent(100),
1504 },
1505 )
1506 .unwrap();
1507
1508 let stake_left = env
1510 .router
1511 .staking
1512 .get_stake(
1513 &StakingStorage::new(&env.storage),
1514 &delegator_addr_1,
1515 &validator_addr_1,
1516 )
1517 .unwrap();
1518 assert_eq!(None, stake_left);
1519 }
1520
1521 #[test]
1522 fn rewards_work_for_single_delegator() {
1523 let mut env = TestEnv::new(vp(10, 20, 1), vp(10, 20, 1));
1524
1525 let validator_addr_1 = env.validator_addr_1();
1526 let delegator_addr_1 = env.delegator_addr_1();
1527
1528 let mut staking_storage_mut = StakingStorageMut::new(&mut env.storage);
1529 env.router
1531 .staking
1532 .add_stake(
1533 &env.api,
1534 &mut staking_storage_mut,
1535 &env.block,
1536 &delegator_addr_1,
1537 &validator_addr_1,
1538 coin(200, BONDED_DENOM),
1539 )
1540 .unwrap();
1541
1542 env.block.time = env.block.time.plus_seconds(YEAR / 2);
1544
1545 let rewards = env
1547 .router
1548 .staking
1549 .get_rewards(
1550 &env.storage,
1551 &env.block,
1552 &delegator_addr_1,
1553 &validator_addr_1,
1554 )
1555 .unwrap()
1556 .unwrap();
1557 assert_eq!(9, rewards.amount.u128());
1558
1559 env.router
1561 .distribution
1562 .execute(
1563 &env.api,
1564 &mut env.storage,
1565 &env.router,
1566 &env.block,
1567 delegator_addr_1.clone(),
1568 DistributionMsg::WithdrawDelegatorReward {
1569 validator: validator_addr_1.to_string(),
1570 },
1571 )
1572 .unwrap();
1573
1574 let rewards = env
1576 .router
1577 .staking
1578 .get_rewards(
1579 &env.storage,
1580 &env.block,
1581 &delegator_addr_1,
1582 &validator_addr_1,
1583 )
1584 .unwrap()
1585 .unwrap();
1586 assert_eq!(0, rewards.amount.u128());
1587
1588 env.block.time = env.block.time.plus_seconds(YEAR / 2);
1590 let rewards = env
1592 .router
1593 .staking
1594 .get_rewards(
1595 &env.storage,
1596 &env.block,
1597 &delegator_addr_1,
1598 &validator_addr_1,
1599 )
1600 .unwrap()
1601 .unwrap();
1602 assert_eq!(9, rewards.amount.u128());
1603 }
1604
1605 #[test]
1606 fn rewards_work_for_multiple_delegators() {
1607 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
1608
1609 let validator_addr_1 = env.validator_addr_1();
1610 let delegator_addr_1 = env.delegator_addr_1();
1611 let delegator_addr_2 = env.delegator_addr_2();
1612
1613 env.router
1615 .staking
1616 .add_stake(
1617 &env.api,
1618 &mut StakingStorageMut::new(&mut env.storage),
1619 &env.block,
1620 &delegator_addr_1,
1621 &validator_addr_1,
1622 coin(100, BONDED_DENOM),
1623 )
1624 .unwrap();
1625 env.router
1626 .staking
1627 .add_stake(
1628 &env.api,
1629 &mut StakingStorageMut::new(&mut env.storage),
1630 &env.block,
1631 &delegator_addr_2,
1632 &validator_addr_1,
1633 coin(200, BONDED_DENOM),
1634 )
1635 .unwrap();
1636
1637 env.block.time = env.block.time.plus_seconds(YEAR);
1639
1640 let rewards = env
1642 .router
1643 .staking
1644 .get_rewards(
1645 &env.storage,
1646 &env.block,
1647 &delegator_addr_1,
1648 &validator_addr_1,
1649 )
1650 .unwrap()
1651 .unwrap();
1652 assert_eq!(rewards.amount.u128(), 9);
1653
1654 let rewards = env
1656 .router
1657 .staking
1658 .get_rewards(
1659 &env.storage,
1660 &env.block,
1661 &delegator_addr_2,
1662 &validator_addr_1,
1663 )
1664 .unwrap()
1665 .unwrap();
1666 assert_eq!(rewards.amount.u128(), 18);
1667
1668 env.router
1670 .staking
1671 .add_stake(
1672 &env.api,
1673 &mut StakingStorageMut::new(&mut env.storage),
1674 &env.block,
1675 &delegator_addr_1,
1676 &validator_addr_1,
1677 coin(100, BONDED_DENOM),
1678 )
1679 .unwrap();
1680
1681 env.block.time = env.block.time.plus_seconds(YEAR);
1683
1684 let rewards = env
1686 .router
1687 .staking
1688 .get_rewards(
1689 &env.storage,
1690 &env.block,
1691 &delegator_addr_1,
1692 &validator_addr_1,
1693 )
1694 .unwrap()
1695 .unwrap();
1696 assert_eq!(rewards.amount.u128(), 27);
1697
1698 let rewards = env
1700 .router
1701 .staking
1702 .get_rewards(
1703 &env.storage,
1704 &env.block,
1705 &delegator_addr_2,
1706 &validator_addr_1,
1707 )
1708 .unwrap()
1709 .unwrap();
1710 assert_eq!(rewards.amount.u128(), 36);
1711
1712 env.router
1714 .staking
1715 .remove_stake(
1716 &env.api,
1717 &mut StakingStorageMut::new(&mut env.storage),
1718 &env.block,
1719 &delegator_addr_2,
1720 &validator_addr_1,
1721 coin(100, BONDED_DENOM),
1722 )
1723 .unwrap();
1724
1725 env.router
1727 .distribution
1728 .execute(
1729 &env.api,
1730 &mut env.storage,
1731 &env.router,
1732 &env.block,
1733 delegator_addr_1.clone(),
1734 DistributionMsg::WithdrawDelegatorReward {
1735 validator: validator_addr_1.to_string(),
1736 },
1737 )
1738 .unwrap();
1739
1740 let balance: BalanceResponse = from_json(
1741 env.router
1742 .bank
1743 .query(
1744 &env.api,
1745 &env.storage,
1746 &env.router.querier(&env.api, &env.storage, &env.block),
1747 &env.block,
1748 BankQuery::Balance {
1749 address: delegator_addr_1.to_string(),
1750 denom: BONDED_DENOM.to_string(),
1751 },
1752 )
1753 .unwrap(),
1754 )
1755 .unwrap();
1756 assert_eq!(27, balance.amount.amount.u128());
1757
1758 let rewards = env
1759 .router
1760 .staking
1761 .get_rewards(
1762 &env.storage,
1763 &env.block,
1764 &delegator_addr_1,
1765 &validator_addr_1,
1766 )
1767 .unwrap()
1768 .unwrap();
1769 assert_eq!(0, rewards.amount.u128());
1770
1771 env.block.time = env.block.time.plus_seconds(YEAR);
1773
1774 let rewards = env
1776 .router
1777 .staking
1778 .get_rewards(
1779 &env.storage,
1780 &env.block,
1781 &delegator_addr_1,
1782 &validator_addr_1,
1783 )
1784 .unwrap()
1785 .unwrap();
1786 assert_eq!(18, rewards.amount.u128());
1787
1788 let rewards = env
1790 .router
1791 .staking
1792 .get_rewards(
1793 &env.storage,
1794 &env.block,
1795 &delegator_addr_2,
1796 &validator_addr_1,
1797 )
1798 .unwrap()
1799 .unwrap();
1800 assert_eq!(45, rewards.amount.u128());
1801 }
1802
1803 #[test]
1804 fn execute() {
1805 let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1));
1806
1807 let validator_addr_1 = env.validator_addr_1();
1808 let validator_addr_2 = env.validator_addr_2();
1809 let delegator_addr_1 = env.delegator_addr_2();
1810 let reward_receiver_addr = env.user_addr_1();
1811
1812 init_balance(&mut env, &delegator_addr_1, 1000);
1814
1815 execute_stake(
1817 &mut env,
1818 delegator_addr_1.clone(),
1819 StakingMsg::Delegate {
1820 validator: validator_addr_1.clone(),
1821 amount: coin(100, BONDED_DENOM),
1822 },
1823 )
1824 .unwrap();
1825
1826 assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]);
1828
1829 env.block.time = env.block.time.plus_seconds(YEAR);
1831
1832 execute_distr(
1834 &mut env,
1835 delegator_addr_1.clone(),
1836 DistributionMsg::SetWithdrawAddress {
1837 address: reward_receiver_addr.to_string(),
1838 },
1839 )
1840 .unwrap();
1841
1842 execute_distr(
1844 &mut env,
1845 delegator_addr_1.clone(),
1846 DistributionMsg::WithdrawDelegatorReward {
1847 validator: validator_addr_1.clone(),
1848 },
1849 )
1850 .unwrap();
1851
1852 assert_balances(
1854 &env,
1855 vec![(reward_receiver_addr, 100 / 10 * 9 / 10)],
1857 );
1858
1859 execute_stake(
1861 &mut env,
1862 delegator_addr_1.clone(),
1863 StakingMsg::Redelegate {
1864 src_validator: validator_addr_1,
1865 dst_validator: validator_addr_2.clone(),
1866 amount: coin(100, BONDED_DENOM),
1867 },
1868 )
1869 .unwrap();
1870
1871 assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]);
1873
1874 let delegations: AllDelegationsResponse = query_stake(
1875 &env,
1876 StakingQuery::AllDelegations {
1877 delegator: delegator_addr_1.to_string(),
1878 },
1879 )
1880 .unwrap();
1881 assert_eq!(
1882 delegations.delegations,
1883 [Delegation::new(
1884 delegator_addr_1.clone(),
1885 validator_addr_2.clone(),
1886 coin(100, BONDED_DENOM),
1887 )]
1888 );
1889
1890 execute_stake(
1892 &mut env,
1893 delegator_addr_1.clone(),
1894 StakingMsg::Undelegate {
1895 validator: validator_addr_2,
1896 amount: coin(100, BONDED_DENOM),
1897 },
1898 )
1899 .unwrap();
1900
1901 env.block.time = env.block.time.plus_seconds(60);
1903
1904 env.router
1906 .staking
1907 .process_queue(&env.api, &mut env.storage, &env.router, &env.block)
1908 .unwrap();
1909
1910 assert_balances(&env, vec![(delegator_addr_1.clone(), 1000)]);
1912 }
1913
1914 #[test]
1915 fn can_set_withdraw_address() {
1916 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
1917
1918 let validator_addr_1 = env.validator_addr_1();
1919 let delegator_addr_1 = env.delegator_addr_1();
1920 let reward_receiver_addr = env.user_addr_1();
1921
1922 init_balance(&mut env, &delegator_addr_1, 100);
1924
1925 execute_stake(
1927 &mut env,
1928 delegator_addr_1.clone(),
1929 StakingMsg::Delegate {
1930 validator: validator_addr_1.clone(),
1931 amount: coin(100, BONDED_DENOM),
1932 },
1933 )
1934 .unwrap();
1935
1936 execute_distr(
1938 &mut env,
1939 delegator_addr_1.clone(),
1940 DistributionMsg::SetWithdrawAddress {
1941 address: reward_receiver_addr.to_string(),
1942 },
1943 )
1944 .unwrap();
1945
1946 env.block.time = env.block.time.plus_seconds(YEAR);
1948
1949 execute_distr(
1951 &mut env,
1952 delegator_addr_1.clone(),
1953 DistributionMsg::WithdrawDelegatorReward {
1954 validator: validator_addr_1.clone(),
1955 },
1956 )
1957 .unwrap();
1958
1959 execute_distr(
1961 &mut env,
1962 delegator_addr_1.clone(),
1963 DistributionMsg::SetWithdrawAddress {
1964 address: delegator_addr_1.to_string(),
1965 },
1966 )
1967 .unwrap();
1968
1969 env.block.time = env.block.time.plus_seconds(YEAR);
1971
1972 execute_distr(
1974 &mut env,
1975 delegator_addr_1.clone(),
1976 DistributionMsg::WithdrawDelegatorReward {
1977 validator: validator_addr_1,
1978 },
1979 )
1980 .unwrap();
1981
1982 let rewards_yr = 100 / 10 * 9 / 10;
1984
1985 assert_balances(
1986 &env,
1987 vec![
1988 (reward_receiver_addr, rewards_yr),
1989 (delegator_addr_1, rewards_yr),
1990 ],
1991 );
1992 }
1993
1994 #[test]
1995 fn cannot_steal() {
1996 let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1));
1997
1998 let validator_addr_1 = env.validator_addr_1();
1999 let validator_addr_2 = env.validator_addr_2();
2000 let delegator_addr_1 = env.delegator_addr_1();
2001
2002 init_balance(&mut env, &delegator_addr_1, 100);
2004
2005 execute_stake(
2007 &mut env,
2008 delegator_addr_1.clone(),
2009 StakingMsg::Delegate {
2010 validator: validator_addr_1.clone(),
2011 amount: coin(100, BONDED_DENOM),
2012 },
2013 )
2014 .unwrap();
2015
2016 let error_result = execute_stake(
2018 &mut env,
2019 delegator_addr_1.clone(),
2020 StakingMsg::Undelegate {
2021 validator: validator_addr_1.clone(),
2022 amount: coin(200, BONDED_DENOM),
2023 },
2024 )
2025 .unwrap_err();
2026 assert_eq!(error_result.to_string(), "invalid shares amount");
2027
2028 let error_result = execute_stake(
2030 &mut env,
2031 delegator_addr_1.clone(),
2032 StakingMsg::Redelegate {
2033 src_validator: validator_addr_1,
2034 dst_validator: validator_addr_2.clone(),
2035 amount: coin(200, BONDED_DENOM),
2036 },
2037 )
2038 .unwrap_err();
2039 assert_eq!(error_result.to_string(), "invalid shares amount");
2040
2041 let error_result = execute_stake(
2043 &mut env,
2044 delegator_addr_1.clone(),
2045 StakingMsg::Undelegate {
2046 validator: validator_addr_2,
2047 amount: coin(100, BONDED_DENOM),
2048 },
2049 )
2050 .unwrap_err();
2051 assert_eq!(
2052 error_result.to_string(),
2053 "no delegation for (address, validator) tuple"
2054 );
2055 }
2056
2057 #[test]
2058 fn denom_validation() {
2059 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2060
2061 let validator_addr_1 = env.validator_addr_1();
2062 let delegator_addr_1 = env.delegator_addr_1();
2063
2064 init_balance_denom(&mut env, &delegator_addr_1, 100, "FAKE");
2066
2067 let error_result = execute_stake(
2069 &mut env,
2070 delegator_addr_1.clone(),
2071 StakingMsg::Delegate {
2072 validator: validator_addr_1,
2073 amount: coin(100, "FAKE"),
2074 },
2075 )
2076 .unwrap_err();
2077 assert_eq!(
2078 error_result.to_string(),
2079 "cannot delegate coins of denominator FAKE, only of TOKEN",
2080 );
2081 }
2082
2083 #[test]
2084 fn cannot_slash_nonexistent() {
2085 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2086
2087 let validator_addr_3 = env.validator_addr_3();
2088 let delegator_addr_1 = env.delegator_addr_1();
2089
2090 init_balance_denom(&mut env, &delegator_addr_1, 100, "FAKE");
2092
2093 let error_result = env
2095 .router
2096 .staking
2097 .sudo(
2098 &env.api,
2099 &mut env.storage,
2100 &env.router,
2101 &env.block,
2102 StakingSudo::Slash {
2103 validator: validator_addr_3,
2104 percentage: Decimal::percent(50),
2105 },
2106 )
2107 .unwrap_err();
2108 assert_eq!(error_result.to_string(), "validator does not exist");
2109 }
2110
2111 #[test]
2112 fn non_existent_validator() {
2113 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2114
2115 let validator_addr_3 = env.validator_addr_3();
2116 let delegator_addr_1 = env.delegator_addr_1();
2117
2118 init_balance(&mut env, &delegator_addr_1, 100);
2120
2121 let error_result = execute_stake(
2123 &mut env,
2124 delegator_addr_1.clone(),
2125 StakingMsg::Delegate {
2126 validator: validator_addr_3.clone(),
2127 amount: coin(100, BONDED_DENOM),
2128 },
2129 )
2130 .unwrap_err();
2131 assert_eq!(error_result.to_string(), "validator does not exist");
2132
2133 let error_result = execute_stake(
2135 &mut env,
2136 delegator_addr_1.clone(),
2137 StakingMsg::Undelegate {
2138 validator: validator_addr_3,
2139 amount: coin(100, BONDED_DENOM),
2140 },
2141 )
2142 .unwrap_err();
2143 assert_eq!(error_result.to_string(), "validator does not exist");
2144 }
2145
2146 #[test]
2147 fn zero_staking_forbidden() {
2148 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2149
2150 let validator_addr_1 = env.validator_addr_1();
2151 let delegator_addr_1 = env.delegator_addr_1();
2152
2153 let error_result = execute_stake(
2155 &mut env,
2156 delegator_addr_1.clone(),
2157 StakingMsg::Delegate {
2158 validator: validator_addr_1.clone(),
2159 amount: coin(0, BONDED_DENOM),
2160 },
2161 )
2162 .unwrap_err();
2163 assert_eq!(error_result.to_string(), "invalid delegation amount");
2164
2165 let error_result = execute_stake(
2167 &mut env,
2168 delegator_addr_1,
2169 StakingMsg::Undelegate {
2170 validator: validator_addr_1,
2171 amount: coin(0, BONDED_DENOM),
2172 },
2173 )
2174 .unwrap_err();
2175 assert_eq!(error_result.to_string(), "invalid shares amount");
2176 }
2177
2178 #[test]
2179 fn query_staking() {
2180 let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 1, 1));
2181
2182 let validator_addr_1 = env.validator_addr_1();
2183 let validator_addr_2 = env.validator_addr_2();
2184 let delegator_addr_1 = env.delegator_addr_1();
2185 let delegator_addr_2 = env.delegator_addr_2();
2186 let user_addr_1 = env.user_addr_1();
2187
2188 init_balance(&mut env, &delegator_addr_1, 260);
2190 init_balance(&mut env, &delegator_addr_2, 150);
2191
2192 let valoper1: ValidatorResponse = query_stake(
2194 &env,
2195 StakingQuery::Validator {
2196 address: validator_addr_1.to_string(),
2197 },
2198 )
2199 .unwrap();
2200 let valoper2: ValidatorResponse = query_stake(
2201 &env,
2202 StakingQuery::Validator {
2203 address: validator_addr_2.to_string(),
2204 },
2205 )
2206 .unwrap();
2207
2208 let validators: AllValidatorsResponse =
2209 query_stake(&env, StakingQuery::AllValidators {}).unwrap();
2210 assert_eq!(
2211 validators.validators,
2212 [valoper1.validator.unwrap(), valoper2.validator.unwrap()]
2213 );
2214
2215 let response = query_stake::<ValidatorResponse>(
2217 &env,
2218 StakingQuery::Validator {
2219 address: user_addr_1.to_string(),
2220 },
2221 )
2222 .unwrap();
2223 assert_eq!(response.validator, None);
2224
2225 let response: BondedDenomResponse =
2227 query_stake(&env, StakingQuery::BondedDenom {}).unwrap();
2228 assert_eq!(response.denom, BONDED_DENOM);
2229
2230 execute_stake(
2232 &mut env,
2233 delegator_addr_1.clone(),
2234 StakingMsg::Delegate {
2235 validator: validator_addr_1.to_string(),
2236 amount: coin(100, BONDED_DENOM),
2237 },
2238 )
2239 .unwrap();
2240 execute_stake(
2241 &mut env,
2242 delegator_addr_1.clone(),
2243 StakingMsg::Delegate {
2244 validator: validator_addr_2.to_string(),
2245 amount: coin(160, BONDED_DENOM),
2246 },
2247 )
2248 .unwrap();
2249 execute_stake(
2250 &mut env,
2251 delegator_addr_2.clone(),
2252 StakingMsg::Delegate {
2253 validator: validator_addr_1.to_string(),
2254 amount: coin(150, BONDED_DENOM),
2255 },
2256 )
2257 .unwrap();
2258 execute_stake(
2260 &mut env,
2261 delegator_addr_1.clone(),
2262 StakingMsg::Undelegate {
2263 validator: validator_addr_1.to_string(),
2264 amount: coin(50, BONDED_DENOM),
2265 },
2266 )
2267 .unwrap();
2268 execute_stake(
2269 &mut env,
2270 delegator_addr_2.clone(),
2271 StakingMsg::Undelegate {
2272 validator: validator_addr_1.to_string(),
2273 amount: coin(50, BONDED_DENOM),
2274 },
2275 )
2276 .unwrap();
2277
2278 let response1: AllDelegationsResponse = query_stake(
2280 &env,
2281 StakingQuery::AllDelegations {
2282 delegator: delegator_addr_1.to_string(),
2283 },
2284 )
2285 .unwrap();
2286 assert_eq!(
2287 response1.delegations,
2288 vec![
2289 Delegation::new(
2290 delegator_addr_1.clone(),
2291 validator_addr_1.to_string(),
2292 coin(50, BONDED_DENOM),
2293 ),
2294 Delegation::new(
2295 delegator_addr_1.clone(),
2296 validator_addr_2,
2297 coin(160, BONDED_DENOM),
2298 ),
2299 ]
2300 );
2301 let response2: DelegationResponse = query_stake(
2302 &env,
2303 StakingQuery::Delegation {
2304 delegator: delegator_addr_2.to_string(),
2305 validator: validator_addr_1.clone(),
2306 },
2307 )
2308 .unwrap();
2309 assert_eq!(
2310 response2.delegation.unwrap(),
2311 FullDelegation::new(
2312 delegator_addr_2.clone(),
2313 validator_addr_1,
2314 coin(100, BONDED_DENOM),
2315 coin(100, BONDED_DENOM),
2316 vec![],
2317 ),
2318 );
2319 }
2320
2321 #[test]
2322 fn delegation_queries_unbonding() {
2323 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2324
2325 let validator_addr_1 = env.validator_addr_1();
2326 let delegator_addr_1 = env.delegator_addr_1();
2327 let delegator_addr_2 = env.delegator_addr_2();
2328
2329 init_balance(&mut env, &delegator_addr_1, 100);
2331 init_balance(&mut env, &delegator_addr_2, 150);
2332
2333 execute_stake(
2335 &mut env,
2336 delegator_addr_1.clone(),
2337 StakingMsg::Delegate {
2338 validator: validator_addr_1.to_string(),
2339 amount: coin(100, BONDED_DENOM),
2340 },
2341 )
2342 .unwrap();
2343 execute_stake(
2344 &mut env,
2345 delegator_addr_2.clone(),
2346 StakingMsg::Delegate {
2347 validator: validator_addr_1.to_string(),
2348 amount: coin(150, BONDED_DENOM),
2349 },
2350 )
2351 .unwrap();
2352 execute_stake(
2354 &mut env,
2355 delegator_addr_1.clone(),
2356 StakingMsg::Undelegate {
2357 validator: validator_addr_1.to_string(),
2358 amount: coin(50, BONDED_DENOM),
2359 },
2360 )
2361 .unwrap();
2362 execute_stake(
2364 &mut env,
2365 delegator_addr_2.clone(),
2366 StakingMsg::Undelegate {
2367 validator: validator_addr_1.to_string(),
2368 amount: coin(150, BONDED_DENOM),
2369 },
2370 )
2371 .unwrap();
2372
2373 let response1: AllDelegationsResponse = query_stake(
2375 &env,
2376 StakingQuery::AllDelegations {
2377 delegator: delegator_addr_1.to_string(),
2378 },
2379 )
2380 .unwrap();
2381 assert_eq!(
2382 response1.delegations,
2383 vec![Delegation::new(
2384 delegator_addr_1.clone(),
2385 validator_addr_1.to_string(),
2386 coin(50, BONDED_DENOM),
2387 )]
2388 );
2389 let response2: DelegationResponse = query_stake(
2390 &env,
2391 StakingQuery::Delegation {
2392 delegator: delegator_addr_2.to_string(),
2393 validator: validator_addr_1.to_string(),
2394 },
2395 )
2396 .unwrap();
2397 assert_eq!(response2.delegation, None);
2398
2399 execute_stake(
2401 &mut env,
2402 delegator_addr_1.clone(),
2403 StakingMsg::Undelegate {
2404 validator: validator_addr_1.to_string(),
2405 amount: coin(25, BONDED_DENOM),
2406 },
2407 )
2408 .unwrap();
2409 env.block.time = env.block.time.plus_seconds(10);
2410 execute_stake(
2411 &mut env,
2412 delegator_addr_1.clone(),
2413 StakingMsg::Undelegate {
2414 validator: validator_addr_1.to_string(),
2415 amount: coin(25, BONDED_DENOM),
2416 },
2417 )
2418 .unwrap();
2419
2420 let response1: DelegationResponse = query_stake(
2422 &env,
2423 StakingQuery::Delegation {
2424 delegator: delegator_addr_1.to_string(),
2425 validator: validator_addr_1,
2426 },
2427 )
2428 .unwrap();
2429 let response2: AllDelegationsResponse = query_stake(
2430 &env,
2431 StakingQuery::AllDelegations {
2432 delegator: delegator_addr_1.to_string(),
2433 },
2434 )
2435 .unwrap();
2436 assert_eq!(
2437 response1.delegation, None,
2438 "delegator1 should have no delegations left"
2439 );
2440 assert_eq!(response2.delegations, vec![]);
2441 }
2442
2443 #[test]
2444 fn partial_unbonding_reduces_stake() {
2445 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2446
2447 let validator_addr_1 = env.validator_addr_1();
2448 let delegator_addr_1 = env.delegator_addr_1();
2449
2450 init_balance(&mut env, &delegator_addr_1, 100);
2452
2453 execute_stake(
2455 &mut env,
2456 delegator_addr_1.clone(),
2457 StakingMsg::Delegate {
2458 validator: validator_addr_1.to_string(),
2459 amount: coin(100, BONDED_DENOM),
2460 },
2461 )
2462 .unwrap();
2463 execute_stake(
2465 &mut env,
2466 delegator_addr_1.clone(),
2467 StakingMsg::Undelegate {
2468 validator: validator_addr_1.to_string(),
2469 amount: coin(50, BONDED_DENOM),
2470 },
2471 )
2472 .unwrap();
2473 env.block.time = env.block.time.plus_seconds(10);
2474 execute_stake(
2475 &mut env,
2476 delegator_addr_1.clone(),
2477 StakingMsg::Undelegate {
2478 validator: validator_addr_1.to_string(),
2479 amount: coin(30, BONDED_DENOM),
2480 },
2481 )
2482 .unwrap();
2483 env.block.time = env.block.time.plus_seconds(10);
2484 execute_stake(
2485 &mut env,
2486 delegator_addr_1.clone(),
2487 StakingMsg::Undelegate {
2488 validator: validator_addr_1.to_string(),
2489 amount: coin(20, BONDED_DENOM),
2490 },
2491 )
2492 .unwrap();
2493
2494 env.block.time = env.block.time.plus_seconds(40);
2496 env.router
2497 .staking
2498 .process_queue(&env.api, &mut env.storage, &env.router, &env.block)
2499 .unwrap();
2500
2501 let response1: DelegationResponse = query_stake(
2504 &env,
2505 StakingQuery::Delegation {
2506 delegator: delegator_addr_1.to_string(),
2507 validator: validator_addr_1.to_string(),
2508 },
2509 )
2510 .unwrap();
2511 let response2: AllDelegationsResponse = query_stake(
2512 &env,
2513 StakingQuery::AllDelegations {
2514 delegator: delegator_addr_1.to_string(),
2515 },
2516 )
2517 .unwrap();
2518 assert_eq!(response1.delegation, None);
2519 assert_eq!(response2.delegations, vec![]);
2520
2521 env.block.time = env.block.time.plus_seconds(20);
2523 env.router
2524 .staking
2525 .process_queue(&env.api, &mut env.storage, &env.router, &env.block)
2526 .unwrap();
2527
2528 let response1: DelegationResponse = query_stake(
2530 &env,
2531 StakingQuery::Delegation {
2532 delegator: delegator_addr_1.to_string(),
2533 validator: validator_addr_1,
2534 },
2535 )
2536 .unwrap();
2537 let response2: AllDelegationsResponse = query_stake(
2538 &env,
2539 StakingQuery::AllDelegations {
2540 delegator: delegator_addr_1.to_string(),
2541 },
2542 )
2543 .unwrap();
2544 assert_eq!(
2545 response1.delegation, None,
2546 "delegator should have nothing left"
2547 );
2548 assert!(response2.delegations.is_empty());
2549 }
2550
2551 #[test]
2552 fn delegations_slashed() {
2553 let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2554
2555 let validator_addr_1 = env.validator_addr_1();
2556 let delegator_addr_1 = env.delegator_addr_1();
2557
2558 init_balance(&mut env, &delegator_addr_1, 333);
2560
2561 execute_stake(
2563 &mut env,
2564 delegator_addr_1.clone(),
2565 StakingMsg::Delegate {
2566 validator: validator_addr_1.to_string(),
2567 amount: coin(333, BONDED_DENOM),
2568 },
2569 )
2570 .unwrap();
2571
2572 execute_stake(
2574 &mut env,
2575 delegator_addr_1.clone(),
2576 StakingMsg::Undelegate {
2577 validator: validator_addr_1.to_string(),
2578 amount: coin(111, BONDED_DENOM),
2579 },
2580 )
2581 .unwrap();
2582
2583 env.router
2585 .staking
2586 .sudo(
2587 &env.api,
2588 &mut env.storage,
2589 &env.router,
2590 &env.block,
2591 StakingSudo::Slash {
2592 validator: validator_addr_1.to_string(),
2593 percentage: Decimal::percent(50),
2594 },
2595 )
2596 .unwrap();
2597
2598 let response1: AllDelegationsResponse = query_stake(
2600 &env,
2601 StakingQuery::AllDelegations {
2602 delegator: delegator_addr_1.to_string(),
2603 },
2604 )
2605 .unwrap();
2606 assert_eq!(
2607 response1.delegations[0],
2608 Delegation::new(
2609 delegator_addr_1.clone(),
2610 validator_addr_1,
2611 coin(111, BONDED_DENOM),
2612 )
2613 );
2614
2615 env.block.time = env.block.time.plus_seconds(60);
2617 env.router
2618 .staking
2619 .process_queue(&env.api, &mut env.storage, &env.router, &env.block)
2620 .unwrap();
2621 let balance =
2622 QuerierWrapper::<Empty>::new(&env.router.querier(&env.api, &env.storage, &env.block))
2623 .query_balance(delegator_addr_1, BONDED_DENOM)
2624 .unwrap();
2625 assert_eq!(55, balance.amount.u128());
2626 }
2627
2628 #[test]
2629 fn rewards_initial_wait() {
2630 let mut env = TestEnv::new(vp(0, 100, 1), vp(0, 100, 1));
2631
2632 let validator_addr_1 = env.validator_addr_1();
2633 let delegator_addr_1 = env.delegator_addr_1();
2634
2635 init_balance(&mut env, &delegator_addr_1, 100);
2637
2638 env.block.time = env.block.time.plus_seconds(YEAR);
2640
2641 execute_stake(
2643 &mut env,
2644 delegator_addr_1.clone(),
2645 StakingMsg::Delegate {
2646 validator: validator_addr_1.to_string(),
2647 amount: coin(100, BONDED_DENOM),
2648 },
2649 )
2650 .unwrap();
2651
2652 env.block.time = env.block.time.plus_seconds(YEAR);
2654
2655 let response: DelegationResponse = query_stake(
2657 &env,
2658 StakingQuery::Delegation {
2659 delegator: delegator_addr_1.to_string(),
2660 validator: validator_addr_1,
2661 },
2662 )
2663 .unwrap();
2664
2665 assert_eq!(
2666 response.delegation.unwrap().accumulated_rewards,
2667 vec![coin(10, BONDED_DENOM)] );
2669 }
2670}