cw_multi_test/
staking.rs

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