cw_multi_test/
staking.rs

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