abstract_cw_multi_test/
staking.rs

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