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 {
683                    events,
684                    ..Default::default()
685                })
686            }
687            StakingMsg::Undelegate { validator, amount } => {
688                self.validate_denom(&staking_storage, &amount)?;
689
690                // see https://github.com/cosmos/cosmos-sdk/blob/3c5387048f75d7e78b40c5b8d2421fdb8f5d973a/x/staking/types/msg.go#L292-L297
691                if amount.amount.is_zero() {
692                    bail!("invalid shares amount");
693                }
694
695                // see https://github.com/cosmos/cosmos-sdk/blob/v0.46.1/x/staking/keeper/msg_server.go#L378-L383
696                let events = vec![Event::new("unbond")
697                    .add_attribute("validator", &validator)
698                    .add_attribute("amount", format!("{}{}", amount.amount, amount.denom))
699                    .add_attribute("completion_time", "2022-09-27T14:00:00+00:00")]; // TODO: actual date?
700                self.remove_stake(
701                    api,
702                    &mut staking_storage,
703                    block,
704                    &sender,
705                    &validator,
706                    amount.clone(),
707                )?;
708                // add tokens to unbonding queue
709                let staking_info = Self::get_staking_info(&staking_storage)?;
710                let mut unbonding_queue = UNBONDING_QUEUE
711                    .may_load(&staking_storage)?
712                    .unwrap_or_default();
713                unbonding_queue.push_back(Unbonding {
714                    delegator: sender.clone(),
715                    validator,
716                    amount: amount.amount,
717                    payout_at: block.time.plus_seconds(staking_info.unbonding_time),
718                });
719                UNBONDING_QUEUE.save(&mut staking_storage, &unbonding_queue)?;
720                Ok(AppResponse {
721                    events,
722                    ..Default::default()
723                })
724            }
725            StakingMsg::Redelegate {
726                src_validator,
727                dst_validator,
728                amount,
729            } => {
730                // see https://github.com/cosmos/cosmos-sdk/blob/v0.46.1/x/staking/keeper/msg_server.go#L316-L322
731                let events = vec![Event::new("redelegate")
732                    .add_attribute("source_validator", &src_validator)
733                    .add_attribute("destination_validator", &dst_validator)
734                    .add_attribute("amount", format!("{}{}", amount.amount, amount.denom))];
735
736                self.remove_stake(
737                    api,
738                    &mut staking_storage,
739                    block,
740                    &sender,
741                    &src_validator,
742                    amount.clone(),
743                )?;
744                self.add_stake(
745                    api,
746                    &mut staking_storage,
747                    block,
748                    &sender,
749                    &dst_validator,
750                    amount,
751                )?;
752
753                Ok(AppResponse {
754                    events,
755                    ..Default::default()
756                })
757            }
758            m => bail!("Unsupported staking message: {:?}", m),
759        }
760    }
761
762    fn query(
763        &self,
764        api: &dyn Api,
765        storage: &dyn Storage,
766        _querier: &dyn Querier,
767        block: &BlockInfo,
768        request: StakingQuery,
769    ) -> AnyResult<Binary> {
770        let staking_storage = prefixed_read(storage, NAMESPACE_STAKING);
771        match request {
772            StakingQuery::BondedDenom {} => Ok(to_json_binary(&BondedDenomResponse::new(
773                Self::get_staking_info(&staking_storage)?.bonded_denom,
774            ))?),
775            StakingQuery::AllDelegations { delegator } => {
776                let delegator = api.addr_validate(&delegator)?;
777                let validators = self.get_validators(&staking_storage)?;
778
779                let res: AnyResult<Vec<Delegation>> =
780                    validators
781                        .into_iter()
782                        .filter_map(|validator| {
783                            let delegator = delegator.clone();
784                            let amount = self
785                                .get_stake(&staking_storage, &delegator, &validator.address)
786                                .transpose()?;
787
788                            Some(amount.map(|amount| {
789                                Delegation::new(delegator, validator.address, amount)
790                            }))
791                        })
792                        .collect();
793
794                Ok(to_json_binary(&AllDelegationsResponse::new(res?))?)
795            }
796            StakingQuery::Delegation {
797                delegator,
798                validator,
799            } => {
800                let validator_obj = match self.get_validator(&staking_storage, &validator)? {
801                    Some(validator) => validator,
802                    None => bail!("non-existent validator {}", validator),
803                };
804                let delegator = api.addr_validate(&delegator)?;
805
806                let shares = STAKES
807                    .may_load(&staking_storage, (&delegator, &validator))?
808                    .unwrap_or_default();
809
810                let validator_info = VALIDATOR_INFO.load(&staking_storage, &validator)?;
811                let reward = Self::get_rewards_internal(
812                    &staking_storage,
813                    block,
814                    &shares,
815                    &validator_obj,
816                    &validator_info,
817                )?;
818                let staking_info = Self::get_staking_info(&staking_storage)?;
819
820                let amount = coin(
821                    Uint128::new(1).mul_floor(shares.stake).u128(),
822                    staking_info.bonded_denom,
823                );
824
825                let full_delegation_response = if amount.amount.is_zero() {
826                    // no delegation
827                    DelegationResponse::new(None)
828                } else {
829                    DelegationResponse::new(Some(FullDelegation::new(
830                        delegator,
831                        validator,
832                        amount.clone(),
833                        amount, // TODO: not implemented right now
834                        if reward.amount.is_zero() {
835                            vec![]
836                        } else {
837                            vec![reward]
838                        },
839                    )))
840                };
841
842                let res = to_json_binary(&full_delegation_response)?;
843                Ok(res)
844            }
845            StakingQuery::AllValidators {} => Ok(to_json_binary(&AllValidatorsResponse::new(
846                self.get_validators(&staking_storage)?,
847            ))?),
848            StakingQuery::Validator { address } => Ok(to_json_binary(&ValidatorResponse::new(
849                self.get_validator(&staking_storage, &address)?,
850            ))?),
851            q => bail!("Unsupported staking sudo message: {:?}", q),
852        }
853    }
854
855    fn sudo<ExecC: CustomMsg, QueryC: CustomQuery>(
856        &self,
857        api: &dyn Api,
858        storage: &mut dyn Storage,
859        _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
860        block: &BlockInfo,
861        msg: StakingSudo,
862    ) -> AnyResult<AppResponse> {
863        match msg {
864            StakingSudo::Slash {
865                validator,
866                percentage,
867            } => {
868                let mut staking_storage = prefixed(storage, NAMESPACE_STAKING);
869                self.validate_percentage(percentage)?;
870                self.slash(api, &mut staking_storage, block, &validator, percentage)?;
871                Ok(AppResponse::default())
872            }
873        }
874    }
875}
876
877/// A structure representing a default distribution keeper.
878///
879/// This module likely manages the distribution of rewards and fees within the blockchain network.
880/// It could handle tasks like distributing block rewards to validators and delegators,
881/// and managing community funding mechanisms.
882#[derive(Default)]
883pub struct DistributionKeeper {}
884
885impl DistributionKeeper {
886    /// Creates a new distribution keeper with default settings.
887    pub fn new() -> Self {
888        Self::default()
889    }
890
891    /// Removes all rewards from the given (delegator, validator) pair and returns the amount
892    pub fn remove_rewards(
893        &self,
894        api: &dyn Api,
895        storage: &mut dyn Storage,
896        block: &BlockInfo,
897        delegator: &Addr,
898        validator: &str,
899    ) -> AnyResult<Uint128> {
900        let mut staking_storage = prefixed(storage, NAMESPACE_STAKING);
901        // update the validator and staker rewards
902        StakeKeeper::update_rewards(api, &mut staking_storage, block, validator)?;
903
904        // load updated rewards for delegator
905        let mut shares = STAKES.load(&staking_storage, (delegator, validator))?;
906        let rewards = Uint128::new(1).mul_floor(shares.rewards); // convert to Uint128
907
908        // remove rewards from delegator
909        shares.rewards = Decimal::zero();
910        STAKES.save(&mut staking_storage, (delegator, validator), &shares)?;
911
912        Ok(rewards)
913    }
914
915    /// Returns the withdrawal address for specified delegator.
916    pub fn get_withdraw_address(storage: &dyn Storage, delegator: &Addr) -> AnyResult<Addr> {
917        Ok(match WITHDRAW_ADDRESS.may_load(storage, delegator)? {
918            Some(a) => a,
919            None => delegator.clone(),
920        })
921    }
922
923    /// Sets (changes) the [withdraw address] of the delegator.
924    ///
925    /// [withdraw address]: https://docs.cosmos.network/main/modules/distribution#msgsetwithdrawaddress
926    pub fn set_withdraw_address(
927        storage: &mut dyn Storage,
928        delegator: &Addr,
929        withdraw_addr: &Addr,
930    ) -> AnyResult<()> {
931        if delegator == withdraw_addr {
932            WITHDRAW_ADDRESS.remove(storage, delegator);
933            Ok(())
934        } else {
935            // technically we should require that this address is not
936            // the address of a module. TODO: how?
937            WITHDRAW_ADDRESS
938                .save(storage, delegator, withdraw_addr)
939                .map_err(|e| e.into())
940        }
941    }
942}
943
944impl Distribution for DistributionKeeper {}
945
946impl Module for DistributionKeeper {
947    type ExecT = DistributionMsg;
948    type QueryT = Empty;
949    type SudoT = Empty;
950
951    fn execute<ExecC: CustomMsg, QueryC: CustomQuery>(
952        &self,
953        api: &dyn Api,
954        storage: &mut dyn Storage,
955        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
956        block: &BlockInfo,
957        sender: Addr,
958        msg: DistributionMsg,
959    ) -> AnyResult<AppResponse> {
960        match msg {
961            DistributionMsg::WithdrawDelegatorReward { validator } => {
962                let rewards = self.remove_rewards(api, storage, block, &sender, &validator)?;
963                let staking_storage = prefixed_read(storage, NAMESPACE_STAKING);
964                let distribution_storage = prefixed_read(storage, NAMESPACE_DISTRIBUTION);
965                let staking_info = StakeKeeper::get_staking_info(&staking_storage)?;
966                let receiver = Self::get_withdraw_address(&distribution_storage, &sender)?;
967                // directly mint rewards to delegator
968                router.sudo(
969                    api,
970                    storage,
971                    block,
972                    BankSudo::Mint {
973                        to_address: receiver.into_string(),
974                        amount: vec![Coin {
975                            amount: rewards,
976                            denom: staking_info.bonded_denom.clone(),
977                        }],
978                    }
979                    .into(),
980                )?;
981
982                let events = vec![Event::new("withdraw_delegator_reward")
983                    .add_attribute("validator", &validator)
984                    .add_attribute("sender", &sender)
985                    .add_attribute(
986                        "amount",
987                        format!("{}{}", rewards, staking_info.bonded_denom),
988                    )];
989                Ok(AppResponse {
990                    events,
991                    ..Default::default()
992                })
993            }
994            DistributionMsg::SetWithdrawAddress { address } => {
995                let address = api.addr_validate(&address)?;
996                // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/keeper/msg_server.go#L38
997                let storage = &mut prefixed(storage, NAMESPACE_DISTRIBUTION);
998                Self::set_withdraw_address(storage, &sender, &address)?;
999                Ok(AppResponse {
1000                    // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/keeper/keeper.go#L74
1001                    events: vec![Event::new("set_withdraw_address")
1002                        .add_attribute("withdraw_address", address)],
1003                    ..Default::default()
1004                })
1005            }
1006            m => bail!("Unsupported distribution message: {:?}", m),
1007        }
1008    }
1009
1010    fn query(
1011        &self,
1012        _api: &dyn Api,
1013        _storage: &dyn Storage,
1014        _querier: &dyn Querier,
1015        _block: &BlockInfo,
1016        _request: Empty,
1017    ) -> AnyResult<Binary> {
1018        bail!("Something went wrong - Distribution doesn't have query messages")
1019    }
1020
1021    fn sudo<ExecC, QueryC>(
1022        &self,
1023        _api: &dyn Api,
1024        _storage: &mut dyn Storage,
1025        _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1026        _block: &BlockInfo,
1027        _msg: Empty,
1028    ) -> AnyResult<AppResponse> {
1029        bail!("Something went wrong - Distribution doesn't have sudo messages")
1030    }
1031}
1032
1033#[cfg(test)]
1034mod test {
1035    use super::*;
1036    use crate::{
1037        BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, IntoBech32, Router,
1038        StargateFailing, WasmKeeper,
1039    };
1040    use cosmwasm_std::{
1041        coins, from_json,
1042        testing::{mock_env, MockApi, MockStorage},
1043        BalanceResponse, BankQuery, QuerierWrapper,
1044    };
1045    use serde::de::DeserializeOwned;
1046
1047    /// Utility structure for combining validator properties,
1048    /// used mainly for validator initialization.
1049    struct ValidatorProperties {
1050        /// Validator's commission.
1051        commission: Decimal,
1052        /// Validator's maximum commission.
1053        max_commission: Decimal,
1054        /// The maximum daily increase of the validator's commission.
1055        max_change_rate: Decimal,
1056    }
1057
1058    /// Creates validator properties from values expressed as a percentage.
1059    fn vp(commission: u64, max_commission: u64, max_change_rate: u64) -> ValidatorProperties {
1060        ValidatorProperties {
1061            commission: Decimal::percent(commission),
1062            max_commission: Decimal::percent(max_commission),
1063            max_change_rate: Decimal::percent(max_change_rate),
1064        }
1065    }
1066
1067    /// Type alias for default build of [Router], to make its reference in typical test scenario.
1068    type BasicRouter<ExecC = Empty, QueryC = Empty> = Router<
1069        BankKeeper,
1070        FailingModule<ExecC, QueryC, Empty>,
1071        WasmKeeper<ExecC, QueryC>,
1072        StakeKeeper,
1073        DistributionKeeper,
1074        IbcFailingModule,
1075        GovFailingModule,
1076        StargateFailing,
1077    >;
1078
1079    /// Test environment that simplifies initialization of test cases.
1080    struct TestEnv {
1081        api: MockApi,
1082        storage: MockStorage,
1083        router: BasicRouter,
1084        block: BlockInfo,
1085        validator_addr_1: String,
1086        validator_addr_2: String,
1087        validator_addr_3: String,
1088        delegator_addr_1: Addr,
1089        delegator_addr_2: Addr,
1090        user_addr_1: Addr,
1091    }
1092
1093    impl TestEnv {
1094        /// Returns preconfigured test environment.
1095        fn new(validator1: ValidatorProperties, validator2: ValidatorProperties) -> Self {
1096            // Utility function for creating a validator's address,
1097            // which has a different prefix from a user's address.
1098            fn validator_address(value: &str) -> String {
1099                value.into_bech32_with_prefix("cosmwasmvaloper").to_string()
1100            }
1101
1102            // Utility function for creating a user's address,
1103            // which is in Bech32 format with the chain's prefix.
1104            fn user_address(api: &MockApi, value: &str) -> Addr {
1105                api.addr_make(value)
1106            }
1107
1108            let api = MockApi::default();
1109            let router = Router {
1110                wasm: WasmKeeper::new(),
1111                bank: BankKeeper::new(),
1112                custom: FailingModule::new(),
1113                staking: StakeKeeper::new(),
1114                distribution: DistributionKeeper::new(),
1115                ibc: IbcFailingModule::new(),
1116                gov: GovFailingModule::new(),
1117                stargate: StargateFailing,
1118            };
1119            let mut storage = MockStorage::new();
1120            let block = mock_env().block;
1121
1122            let validator_addr_1 = validator_address("validator1");
1123            let validator_addr_2 = validator_address("validator2");
1124            let validator_addr_3 = validator_address("validator3");
1125
1126            // configure basic staking parameters
1127            router
1128                .staking
1129                .setup(&mut storage, StakingInfo::default())
1130                .unwrap();
1131
1132            // create validator no. 1
1133            let valoper1 = Validator::new(
1134                validator_addr_1.to_string(),
1135                validator1.commission,
1136                validator1.max_commission,
1137                validator1.max_change_rate,
1138            );
1139            router
1140                .staking
1141                .add_validator(&api, &mut storage, &block, valoper1)
1142                .unwrap();
1143
1144            // create validator no. 2
1145            let valoper2 = Validator::new(
1146                validator_addr_2.to_string(),
1147                validator2.commission,
1148                validator2.max_commission,
1149                validator2.max_change_rate,
1150            );
1151            router
1152                .staking
1153                .add_validator(&api, &mut storage, &block, valoper2)
1154                .unwrap();
1155
1156            // return testing environment
1157            Self {
1158                api,
1159                storage,
1160                router,
1161                block,
1162                validator_addr_1,
1163                validator_addr_2,
1164                validator_addr_3,
1165                delegator_addr_1: user_address(&api, "delegator1"),
1166                delegator_addr_2: user_address(&api, "delegator2"),
1167                user_addr_1: user_address(&api, "user1"),
1168            }
1169        }
1170
1171        /// Returns an address of EXISTING validator no. 1.
1172        #[inline(always)]
1173        fn validator_addr_1(&self) -> String {
1174            self.validator_addr_1.clone()
1175        }
1176
1177        /// Returns an address of EXISTING validator no. 2.
1178        #[inline(always)]
1179        fn validator_addr_2(&self) -> String {
1180            self.validator_addr_2.clone()
1181        }
1182
1183        /// Returns an address of NON-EXISTING validator no. 3.
1184        #[inline(always)]
1185        fn validator_addr_3(&self) -> String {
1186            self.validator_addr_3.clone()
1187        }
1188
1189        /// Returns address of the delegator no. 1.
1190        #[inline(always)]
1191        fn delegator_addr_1(&self) -> Addr {
1192            self.delegator_addr_1.clone()
1193        }
1194
1195        /// Returns address of the delegator no. 2.
1196        #[inline(always)]
1197        fn delegator_addr_2(&self) -> Addr {
1198            self.delegator_addr_2.clone()
1199        }
1200
1201        /// Returns address of the user no. 1.
1202        #[inline(always)]
1203        fn user_addr_1(&self) -> Addr {
1204            self.user_addr_1.clone()
1205        }
1206    }
1207
1208    /// Executes staking message.
1209    fn execute_stake(env: &mut TestEnv, sender: Addr, msg: StakingMsg) -> AnyResult<AppResponse> {
1210        env.router.staking.execute(
1211            &env.api,
1212            &mut env.storage,
1213            &env.router,
1214            &env.block,
1215            sender,
1216            msg,
1217        )
1218    }
1219
1220    /// Executes staking query.
1221    fn query_stake<T: DeserializeOwned>(env: &TestEnv, msg: StakingQuery) -> AnyResult<T> {
1222        Ok(from_json(env.router.staking.query(
1223            &env.api,
1224            &env.storage,
1225            &env.router.querier(&env.api, &env.storage, &env.block),
1226            &env.block,
1227            msg,
1228        )?)?)
1229    }
1230
1231    /// Executes distribution message.
1232    fn execute_distr(
1233        env: &mut TestEnv,
1234        sender: Addr,
1235        msg: DistributionMsg,
1236    ) -> AnyResult<AppResponse> {
1237        env.router.distribution.execute(
1238            &env.api,
1239            &mut env.storage,
1240            &env.router,
1241            &env.block,
1242            sender,
1243            msg,
1244        )
1245    }
1246
1247    /// Executes bank query.
1248    fn query_bank<T: DeserializeOwned>(env: &TestEnv, msg: BankQuery) -> AnyResult<T> {
1249        Ok(from_json(env.router.bank.query(
1250            &env.api,
1251            &env.storage,
1252            &env.router.querier(&env.api, &env.storage, &env.block),
1253            &env.block,
1254            msg,
1255        )?)?)
1256    }
1257
1258    /// Initializes balance for specified address in staking denominator.
1259    fn init_balance(env: &mut TestEnv, address: &Addr, amount: u128) {
1260        init_balance_denom(env, address, amount, BONDED_DENOM);
1261    }
1262
1263    /// Initializes balance for specified address in any denominator.
1264    fn init_balance_denom(env: &mut TestEnv, address: &Addr, amount: u128, denom: &str) {
1265        env.router
1266            .bank
1267            .init_balance(&mut env.storage, address, coins(amount, denom))
1268            .unwrap();
1269    }
1270
1271    /// Utility function for checking multiple balances in staking denominator.
1272    fn assert_balances(env: &TestEnv, balances: impl IntoIterator<Item = (Addr, u128)>) {
1273        for (addr, amount) in balances {
1274            let balance: BalanceResponse = query_bank(
1275                env,
1276                BankQuery::Balance {
1277                    address: addr.to_string(),
1278                    denom: BONDED_DENOM.to_string(),
1279                },
1280            )
1281            .unwrap();
1282            assert_eq!(balance.amount.amount.u128(), amount);
1283        }
1284    }
1285
1286    #[test]
1287    fn add_get_validators() {
1288        let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1));
1289
1290        let validator_addr_3 = env.validator_addr_3();
1291
1292        // add a new validator (validator no. 3 does not exist yet)
1293        let validator = Validator::new(
1294            validator_addr_3.to_string(),
1295            Decimal::percent(1),
1296            Decimal::percent(10),
1297            Decimal::percent(1),
1298        );
1299        env.router
1300            .staking
1301            .add_validator(&env.api, &mut env.storage, &env.block, validator.clone())
1302            .unwrap();
1303
1304        // get the newly created validator
1305        let staking_storage = prefixed_read(&env.storage, NAMESPACE_STAKING);
1306        let val = env
1307            .router
1308            .staking
1309            .get_validator(&staking_storage, &validator_addr_3)
1310            .unwrap()
1311            .unwrap();
1312        assert_eq!(val, validator);
1313
1314        // try to create a validator with the same address as validator no. 3
1315        let validator_fake = Validator::new(
1316            validator_addr_3.to_string(),
1317            Decimal::percent(2),
1318            Decimal::percent(20),
1319            Decimal::percent(2),
1320        );
1321        env.router
1322            .staking
1323            .add_validator(&env.api, &mut env.storage, &env.block, validator_fake)
1324            .unwrap_err();
1325
1326        // validator no. 3 should still have the original values of its attributes
1327        let staking_storage = prefixed_read(&env.storage, NAMESPACE_STAKING);
1328        let val = env
1329            .router
1330            .staking
1331            .get_validator(&staking_storage, &validator_addr_3)
1332            .unwrap()
1333            .unwrap();
1334        assert_eq!(val, validator);
1335    }
1336
1337    #[test]
1338    fn validator_slashing() {
1339        let mut env = TestEnv::new(vp(10, 20, 1), vp(10, 20, 1));
1340
1341        let validator_addr_1 = env.validator_addr_1();
1342        let delegator_addr_1 = env.delegator_addr_1();
1343
1344        // stake (delegate) 100 tokens from delegator to validator
1345        let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING);
1346        env.router
1347            .staking
1348            .add_stake(
1349                &env.api,
1350                &mut staking_storage,
1351                &env.block,
1352                &delegator_addr_1,
1353                &validator_addr_1,
1354                coin(100, BONDED_DENOM),
1355            )
1356            .unwrap();
1357
1358        // slash 50% of the stake of the validator
1359        env.router
1360            .staking
1361            .sudo(
1362                &env.api,
1363                &mut env.storage,
1364                &env.router,
1365                &env.block,
1366                StakingSudo::Slash {
1367                    validator: validator_addr_1.to_string(),
1368                    percentage: Decimal::percent(50),
1369                },
1370            )
1371            .unwrap();
1372
1373        // check the remaining stake
1374        let staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING);
1375        let stake_left = env
1376            .router
1377            .staking
1378            .get_stake(&staking_storage, &delegator_addr_1, &validator_addr_1)
1379            .unwrap()
1380            .unwrap();
1381        assert_eq!(50, stake_left.amount.u128());
1382
1383        // slash all
1384        env.router
1385            .staking
1386            .sudo(
1387                &env.api,
1388                &mut env.storage,
1389                &env.router,
1390                &env.block,
1391                StakingSudo::Slash {
1392                    validator: validator_addr_1.to_string(),
1393                    percentage: Decimal::percent(100),
1394                },
1395            )
1396            .unwrap();
1397
1398        // check the current stake
1399        let staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING);
1400        let stake_left = env
1401            .router
1402            .staking
1403            .get_stake(&staking_storage, &delegator_addr_1, &validator_addr_1)
1404            .unwrap();
1405        assert_eq!(None, stake_left);
1406    }
1407
1408    #[test]
1409    fn rewards_work_for_single_delegator() {
1410        let mut env = TestEnv::new(vp(10, 20, 1), vp(10, 20, 1));
1411
1412        let validator_addr_1 = env.validator_addr_1();
1413        let delegator_addr_1 = env.delegator_addr_1();
1414
1415        let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING);
1416        // stake 200 tokens
1417        env.router
1418            .staking
1419            .add_stake(
1420                &env.api,
1421                &mut staking_storage,
1422                &env.block,
1423                &delegator_addr_1,
1424                &validator_addr_1,
1425                coin(200, BONDED_DENOM),
1426            )
1427            .unwrap();
1428
1429        // wait 1/2 year
1430        env.block.time = env.block.time.plus_seconds(YEAR / 2);
1431
1432        // should now have 200 * 10% / 2 - 10% commission = 9 tokens reward
1433        let rewards = env
1434            .router
1435            .staking
1436            .get_rewards(
1437                &env.storage,
1438                &env.block,
1439                &delegator_addr_1,
1440                &validator_addr_1,
1441            )
1442            .unwrap()
1443            .unwrap();
1444        assert_eq!(9, rewards.amount.u128());
1445
1446        // withdraw rewards
1447        env.router
1448            .distribution
1449            .execute(
1450                &env.api,
1451                &mut env.storage,
1452                &env.router,
1453                &env.block,
1454                delegator_addr_1.clone(),
1455                DistributionMsg::WithdrawDelegatorReward {
1456                    validator: validator_addr_1.to_string(),
1457                },
1458            )
1459            .unwrap();
1460
1461        // should have no rewards left
1462        let rewards = env
1463            .router
1464            .staking
1465            .get_rewards(
1466                &env.storage,
1467                &env.block,
1468                &delegator_addr_1,
1469                &validator_addr_1,
1470            )
1471            .unwrap()
1472            .unwrap();
1473        assert_eq!(0, rewards.amount.u128());
1474
1475        // wait another 1/2 year
1476        env.block.time = env.block.time.plus_seconds(YEAR / 2);
1477        // should now have 9 tokens again
1478        let rewards = env
1479            .router
1480            .staking
1481            .get_rewards(
1482                &env.storage,
1483                &env.block,
1484                &delegator_addr_1,
1485                &validator_addr_1,
1486            )
1487            .unwrap()
1488            .unwrap();
1489        assert_eq!(9, rewards.amount.u128());
1490    }
1491
1492    #[test]
1493    fn rewards_work_for_multiple_delegators() {
1494        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
1495
1496        let validator_addr_1 = env.validator_addr_1();
1497        let delegator_addr_1 = env.delegator_addr_1();
1498        let delegator_addr_2 = env.delegator_addr_2();
1499
1500        let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING);
1501
1502        // add 100 stake to delegator1 and 200 to delegator2
1503        env.router
1504            .staking
1505            .add_stake(
1506                &env.api,
1507                &mut staking_storage,
1508                &env.block,
1509                &delegator_addr_1,
1510                &validator_addr_1,
1511                coin(100, BONDED_DENOM),
1512            )
1513            .unwrap();
1514        env.router
1515            .staking
1516            .add_stake(
1517                &env.api,
1518                &mut staking_storage,
1519                &env.block,
1520                &delegator_addr_2,
1521                &validator_addr_1,
1522                coin(200, BONDED_DENOM),
1523            )
1524            .unwrap();
1525
1526        // wait 1 year
1527        env.block.time = env.block.time.plus_seconds(YEAR);
1528
1529        // delegator1 should now have 100 * 10% - 10% commission = 9 tokens
1530        let rewards = env
1531            .router
1532            .staking
1533            .get_rewards(
1534                &env.storage,
1535                &env.block,
1536                &delegator_addr_1,
1537                &validator_addr_1,
1538            )
1539            .unwrap()
1540            .unwrap();
1541        assert_eq!(rewards.amount.u128(), 9);
1542
1543        // delegator2 should now have 200 * 10% - 10% commission = 18 tokens
1544        let rewards = env
1545            .router
1546            .staking
1547            .get_rewards(
1548                &env.storage,
1549                &env.block,
1550                &delegator_addr_2,
1551                &validator_addr_1,
1552            )
1553            .unwrap()
1554            .unwrap();
1555        assert_eq!(rewards.amount.u128(), 18);
1556
1557        // delegator1 stakes 100 more
1558        let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING);
1559        env.router
1560            .staking
1561            .add_stake(
1562                &env.api,
1563                &mut staking_storage,
1564                &env.block,
1565                &delegator_addr_1,
1566                &validator_addr_1,
1567                coin(100, BONDED_DENOM),
1568            )
1569            .unwrap();
1570
1571        // wait another year
1572        env.block.time = env.block.time.plus_seconds(YEAR);
1573
1574        // delegator1 should now have 9 + 200 * 10% - 10% commission = 27 tokens
1575        let rewards = env
1576            .router
1577            .staking
1578            .get_rewards(
1579                &env.storage,
1580                &env.block,
1581                &delegator_addr_1,
1582                &validator_addr_1,
1583            )
1584            .unwrap()
1585            .unwrap();
1586        assert_eq!(rewards.amount.u128(), 27);
1587
1588        // delegator2 should now have 18 + 200 * 10% - 10% commission = 36 tokens
1589        let rewards = env
1590            .router
1591            .staking
1592            .get_rewards(
1593                &env.storage,
1594                &env.block,
1595                &delegator_addr_2,
1596                &validator_addr_1,
1597            )
1598            .unwrap()
1599            .unwrap();
1600        assert_eq!(rewards.amount.u128(), 36);
1601
1602        // delegator2 unstakes 100 (has 100 left after that)
1603        let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING);
1604        env.router
1605            .staking
1606            .remove_stake(
1607                &env.api,
1608                &mut staking_storage,
1609                &env.block,
1610                &delegator_addr_2,
1611                &validator_addr_1,
1612                coin(100, BONDED_DENOM),
1613            )
1614            .unwrap();
1615
1616        // and delegator1 withdraws rewards
1617        env.router
1618            .distribution
1619            .execute(
1620                &env.api,
1621                &mut env.storage,
1622                &env.router,
1623                &env.block,
1624                delegator_addr_1.clone(),
1625                DistributionMsg::WithdrawDelegatorReward {
1626                    validator: validator_addr_1.to_string(),
1627                },
1628            )
1629            .unwrap();
1630
1631        let balance: BalanceResponse = from_json(
1632            env.router
1633                .bank
1634                .query(
1635                    &env.api,
1636                    &env.storage,
1637                    &env.router.querier(&env.api, &env.storage, &env.block),
1638                    &env.block,
1639                    BankQuery::Balance {
1640                        address: delegator_addr_1.to_string(),
1641                        denom: BONDED_DENOM.to_string(),
1642                    },
1643                )
1644                .unwrap(),
1645        )
1646        .unwrap();
1647        assert_eq!(27, balance.amount.amount.u128());
1648
1649        let rewards = env
1650            .router
1651            .staking
1652            .get_rewards(
1653                &env.storage,
1654                &env.block,
1655                &delegator_addr_1,
1656                &validator_addr_1,
1657            )
1658            .unwrap()
1659            .unwrap();
1660        assert_eq!(0, rewards.amount.u128());
1661
1662        // wait another year
1663        env.block.time = env.block.time.plus_seconds(YEAR);
1664
1665        // delegator1 should now have 0 + 200 * 10% - 10% commission = 18 tokens
1666        let rewards = env
1667            .router
1668            .staking
1669            .get_rewards(
1670                &env.storage,
1671                &env.block,
1672                &delegator_addr_1,
1673                &validator_addr_1,
1674            )
1675            .unwrap()
1676            .unwrap();
1677        assert_eq!(18, rewards.amount.u128());
1678
1679        // delegator2 should now have 36 + 100 * 10% - 10% commission = 45 tokens
1680        let rewards = env
1681            .router
1682            .staking
1683            .get_rewards(
1684                &env.storage,
1685                &env.block,
1686                &delegator_addr_2,
1687                &validator_addr_1,
1688            )
1689            .unwrap()
1690            .unwrap();
1691        assert_eq!(45, rewards.amount.u128());
1692    }
1693
1694    #[test]
1695    fn execute() {
1696        let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1));
1697
1698        let validator_addr_1 = env.validator_addr_1();
1699        let validator_addr_2 = env.validator_addr_2();
1700        let delegator_addr_1 = env.delegator_addr_2();
1701        let reward_receiver_addr = env.user_addr_1();
1702
1703        // initialize balances
1704        init_balance(&mut env, &delegator_addr_1, 1000);
1705
1706        // delegate 100 tokens to validator 1
1707        execute_stake(
1708            &mut env,
1709            delegator_addr_1.clone(),
1710            StakingMsg::Delegate {
1711                validator: validator_addr_1.clone(),
1712                amount: coin(100, BONDED_DENOM),
1713            },
1714        )
1715        .unwrap();
1716
1717        // should now have 100 tokens less
1718        assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]);
1719
1720        // wait a year
1721        env.block.time = env.block.time.plus_seconds(YEAR);
1722
1723        // change the withdrawal address
1724        execute_distr(
1725            &mut env,
1726            delegator_addr_1.clone(),
1727            DistributionMsg::SetWithdrawAddress {
1728                address: reward_receiver_addr.to_string(),
1729            },
1730        )
1731        .unwrap();
1732
1733        // withdraw rewards
1734        execute_distr(
1735            &mut env,
1736            delegator_addr_1.clone(),
1737            DistributionMsg::WithdrawDelegatorReward {
1738                validator: validator_addr_1.clone(),
1739            },
1740        )
1741        .unwrap();
1742
1743        // withdrawal address received rewards
1744        assert_balances(
1745            &env,
1746            // one year, 10%apr, 10% commission, 100 tokens staked
1747            vec![(reward_receiver_addr, 100 / 10 * 9 / 10)],
1748        );
1749
1750        // redelegate to validator 2
1751        execute_stake(
1752            &mut env,
1753            delegator_addr_1.clone(),
1754            StakingMsg::Redelegate {
1755                src_validator: validator_addr_1,
1756                dst_validator: validator_addr_2.clone(),
1757                amount: coin(100, BONDED_DENOM),
1758            },
1759        )
1760        .unwrap();
1761
1762        // should have same amount as before (rewards receiver received rewards)
1763        assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]);
1764
1765        let delegations: AllDelegationsResponse = query_stake(
1766            &env,
1767            StakingQuery::AllDelegations {
1768                delegator: delegator_addr_1.to_string(),
1769            },
1770        )
1771        .unwrap();
1772        assert_eq!(
1773            delegations.delegations,
1774            [Delegation::new(
1775                delegator_addr_1.clone(),
1776                validator_addr_2.clone(),
1777                coin(100, BONDED_DENOM),
1778            )]
1779        );
1780
1781        // undelegate all tokens
1782        execute_stake(
1783            &mut env,
1784            delegator_addr_1.clone(),
1785            StakingMsg::Undelegate {
1786                validator: validator_addr_2,
1787                amount: coin(100, BONDED_DENOM),
1788            },
1789        )
1790        .unwrap();
1791
1792        // wait for unbonding period (60 seconds in default config)
1793        env.block.time = env.block.time.plus_seconds(60);
1794
1795        // need to manually cause queue to get processed
1796        env.router
1797            .staking
1798            .process_queue(&env.api, &mut env.storage, &env.router, &env.block)
1799            .unwrap();
1800
1801        // check bank balance
1802        assert_balances(&env, vec![(delegator_addr_1.clone(), 1000)]);
1803    }
1804
1805    #[test]
1806    fn can_set_withdraw_address() {
1807        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
1808
1809        let validator_addr_1 = env.validator_addr_1();
1810        let delegator_addr_1 = env.delegator_addr_1();
1811        let reward_receiver_addr = env.user_addr_1();
1812
1813        // initialize balances
1814        init_balance(&mut env, &delegator_addr_1, 100);
1815
1816        // stake (delegate) 100 tokens to the validator
1817        execute_stake(
1818            &mut env,
1819            delegator_addr_1.clone(),
1820            StakingMsg::Delegate {
1821                validator: validator_addr_1.clone(),
1822                amount: coin(100, BONDED_DENOM),
1823            },
1824        )
1825        .unwrap();
1826
1827        // change the receiver of rewards
1828        execute_distr(
1829            &mut env,
1830            delegator_addr_1.clone(),
1831            DistributionMsg::SetWithdrawAddress {
1832                address: reward_receiver_addr.to_string(),
1833            },
1834        )
1835        .unwrap();
1836
1837        // let one year pass
1838        env.block.time = env.block.time.plus_seconds(YEAR);
1839
1840        // Withdraw rewards to reward receiver.
1841        execute_distr(
1842            &mut env,
1843            delegator_addr_1.clone(),
1844            DistributionMsg::WithdrawDelegatorReward {
1845                validator: validator_addr_1.clone(),
1846            },
1847        )
1848        .unwrap();
1849
1850        // Change reward receiver back to delegator.
1851        execute_distr(
1852            &mut env,
1853            delegator_addr_1.clone(),
1854            DistributionMsg::SetWithdrawAddress {
1855                address: delegator_addr_1.to_string(),
1856            },
1857        )
1858        .unwrap();
1859
1860        // Another year passes.
1861        env.block.time = env.block.time.plus_seconds(YEAR);
1862
1863        // Withdraw rewards to delegator.
1864        execute_distr(
1865            &mut env,
1866            delegator_addr_1.clone(),
1867            DistributionMsg::WithdrawDelegatorReward {
1868                validator: validator_addr_1,
1869            },
1870        )
1871        .unwrap();
1872
1873        // one year, 10%apr, 10% commission, 100 tokens staked
1874        let rewards_yr = 100 / 10 * 9 / 10;
1875
1876        assert_balances(
1877            &env,
1878            vec![
1879                (reward_receiver_addr, rewards_yr),
1880                (delegator_addr_1, rewards_yr),
1881            ],
1882        );
1883    }
1884
1885    #[test]
1886    fn cannot_steal() {
1887        let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1));
1888
1889        let validator_addr_1 = env.validator_addr_1();
1890        let validator_addr_2 = env.validator_addr_2();
1891        let delegator_addr_1 = env.delegator_addr_1();
1892
1893        // initialize balances
1894        init_balance(&mut env, &delegator_addr_1, 100);
1895
1896        // delegate 100 tokens to validator 1
1897        execute_stake(
1898            &mut env,
1899            delegator_addr_1.clone(),
1900            StakingMsg::Delegate {
1901                validator: validator_addr_1.clone(),
1902                amount: coin(100, BONDED_DENOM),
1903            },
1904        )
1905        .unwrap();
1906
1907        // undelegate more tokens than we have
1908        let error_result = execute_stake(
1909            &mut env,
1910            delegator_addr_1.clone(),
1911            StakingMsg::Undelegate {
1912                validator: validator_addr_1.clone(),
1913                amount: coin(200, BONDED_DENOM),
1914            },
1915        )
1916        .unwrap_err();
1917        assert_eq!(error_result.to_string(), "invalid shares amount");
1918
1919        // redelegate more tokens than we have from validator 1 to validator 2
1920        let error_result = execute_stake(
1921            &mut env,
1922            delegator_addr_1.clone(),
1923            StakingMsg::Redelegate {
1924                src_validator: validator_addr_1,
1925                dst_validator: validator_addr_2.clone(),
1926                amount: coin(200, BONDED_DENOM),
1927            },
1928        )
1929        .unwrap_err();
1930        assert_eq!(error_result.to_string(), "invalid shares amount");
1931
1932        // undelegate from non-existing delegation
1933        let error_result = execute_stake(
1934            &mut env,
1935            delegator_addr_1.clone(),
1936            StakingMsg::Undelegate {
1937                validator: validator_addr_2,
1938                amount: coin(100, BONDED_DENOM),
1939            },
1940        )
1941        .unwrap_err();
1942        assert_eq!(
1943            error_result.to_string(),
1944            "no delegation for (address, validator) tuple"
1945        );
1946    }
1947
1948    #[test]
1949    fn denom_validation() {
1950        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
1951
1952        let validator_addr_1 = env.validator_addr_1();
1953        let delegator_addr_1 = env.delegator_addr_1();
1954
1955        // init balances
1956        init_balance_denom(&mut env, &delegator_addr_1, 100, "FAKE");
1957
1958        // try to delegate 100 to validator
1959        let error_result = execute_stake(
1960            &mut env,
1961            delegator_addr_1.clone(),
1962            StakingMsg::Delegate {
1963                validator: validator_addr_1,
1964                amount: coin(100, "FAKE"),
1965            },
1966        )
1967        .unwrap_err();
1968        assert_eq!(
1969            error_result.to_string(),
1970            "cannot delegate coins of denominator FAKE, only of TOKEN",
1971        );
1972    }
1973
1974    #[test]
1975    fn cannot_slash_nonexistent() {
1976        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
1977
1978        let validator_addr_3 = env.validator_addr_3();
1979        let delegator_addr_1 = env.delegator_addr_1();
1980
1981        // init balances
1982        init_balance_denom(&mut env, &delegator_addr_1, 100, "FAKE");
1983
1984        // try to delegate 100 to non existing validator
1985        let error_result = env
1986            .router
1987            .staking
1988            .sudo(
1989                &env.api,
1990                &mut env.storage,
1991                &env.router,
1992                &env.block,
1993                StakingSudo::Slash {
1994                    validator: validator_addr_3,
1995                    percentage: Decimal::percent(50),
1996                },
1997            )
1998            .unwrap_err();
1999        assert_eq!(error_result.to_string(), "validator does not exist");
2000    }
2001
2002    #[test]
2003    fn non_existent_validator() {
2004        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2005
2006        let validator_addr_3 = env.validator_addr_3();
2007        let delegator_addr_1 = env.delegator_addr_1();
2008
2009        // initialize balances
2010        init_balance(&mut env, &delegator_addr_1, 100);
2011
2012        // try to delegate
2013        let error_result = execute_stake(
2014            &mut env,
2015            delegator_addr_1.clone(),
2016            StakingMsg::Delegate {
2017                validator: validator_addr_3.clone(),
2018                amount: coin(100, BONDED_DENOM),
2019            },
2020        )
2021        .unwrap_err();
2022        assert_eq!(error_result.to_string(), "validator does not exist");
2023
2024        // try to undelegate
2025        let error_result = execute_stake(
2026            &mut env,
2027            delegator_addr_1.clone(),
2028            StakingMsg::Undelegate {
2029                validator: validator_addr_3,
2030                amount: coin(100, BONDED_DENOM),
2031            },
2032        )
2033        .unwrap_err();
2034        assert_eq!(error_result.to_string(), "validator does not exist");
2035    }
2036
2037    #[test]
2038    fn zero_staking_forbidden() {
2039        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2040
2041        let validator_addr_1 = env.validator_addr_1();
2042        let delegator_addr_1 = env.delegator_addr_1();
2043
2044        // delegate 0
2045        let error_result = execute_stake(
2046            &mut env,
2047            delegator_addr_1.clone(),
2048            StakingMsg::Delegate {
2049                validator: validator_addr_1.clone(),
2050                amount: coin(0, BONDED_DENOM),
2051            },
2052        )
2053        .unwrap_err();
2054        assert_eq!(error_result.to_string(), "invalid delegation amount");
2055
2056        // undelegate 0
2057        let error_result = execute_stake(
2058            &mut env,
2059            delegator_addr_1,
2060            StakingMsg::Undelegate {
2061                validator: validator_addr_1,
2062                amount: coin(0, BONDED_DENOM),
2063            },
2064        )
2065        .unwrap_err();
2066        assert_eq!(error_result.to_string(), "invalid shares amount");
2067    }
2068
2069    #[test]
2070    fn query_staking() {
2071        let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 1, 1));
2072
2073        let validator_addr_1 = env.validator_addr_1();
2074        let validator_addr_2 = env.validator_addr_2();
2075        let delegator_addr_1 = env.delegator_addr_1();
2076        let delegator_addr_2 = env.delegator_addr_2();
2077        let user_addr_1 = env.user_addr_1();
2078
2079        // initialize balances
2080        init_balance(&mut env, &delegator_addr_1, 260);
2081        init_balance(&mut env, &delegator_addr_2, 150);
2082
2083        // query validators
2084        let valoper1: ValidatorResponse = query_stake(
2085            &env,
2086            StakingQuery::Validator {
2087                address: validator_addr_1.to_string(),
2088            },
2089        )
2090        .unwrap();
2091        let valoper2: ValidatorResponse = query_stake(
2092            &env,
2093            StakingQuery::Validator {
2094                address: validator_addr_2.to_string(),
2095            },
2096        )
2097        .unwrap();
2098
2099        let validators: AllValidatorsResponse =
2100            query_stake(&env, StakingQuery::AllValidators {}).unwrap();
2101        assert_eq!(
2102            validators.validators,
2103            [valoper1.validator.unwrap(), valoper2.validator.unwrap()]
2104        );
2105
2106        // query non-existent validator
2107        let response = query_stake::<ValidatorResponse>(
2108            &env,
2109            StakingQuery::Validator {
2110                address: user_addr_1.to_string(),
2111            },
2112        )
2113        .unwrap();
2114        assert_eq!(response.validator, None);
2115
2116        // query bonded denom
2117        let response: BondedDenomResponse =
2118            query_stake(&env, StakingQuery::BondedDenom {}).unwrap();
2119        assert_eq!(response.denom, BONDED_DENOM);
2120
2121        // delegate some tokens with delegator1 and delegator2
2122        execute_stake(
2123            &mut env,
2124            delegator_addr_1.clone(),
2125            StakingMsg::Delegate {
2126                validator: validator_addr_1.to_string(),
2127                amount: coin(100, BONDED_DENOM),
2128            },
2129        )
2130        .unwrap();
2131        execute_stake(
2132            &mut env,
2133            delegator_addr_1.clone(),
2134            StakingMsg::Delegate {
2135                validator: validator_addr_2.to_string(),
2136                amount: coin(160, BONDED_DENOM),
2137            },
2138        )
2139        .unwrap();
2140        execute_stake(
2141            &mut env,
2142            delegator_addr_2.clone(),
2143            StakingMsg::Delegate {
2144                validator: validator_addr_1.to_string(),
2145                amount: coin(150, BONDED_DENOM),
2146            },
2147        )
2148        .unwrap();
2149        // unstake some again
2150        execute_stake(
2151            &mut env,
2152            delegator_addr_1.clone(),
2153            StakingMsg::Undelegate {
2154                validator: validator_addr_1.to_string(),
2155                amount: coin(50, BONDED_DENOM),
2156            },
2157        )
2158        .unwrap();
2159        execute_stake(
2160            &mut env,
2161            delegator_addr_2.clone(),
2162            StakingMsg::Undelegate {
2163                validator: validator_addr_1.to_string(),
2164                amount: coin(50, BONDED_DENOM),
2165            },
2166        )
2167        .unwrap();
2168
2169        // query all delegations
2170        let response1: AllDelegationsResponse = query_stake(
2171            &env,
2172            StakingQuery::AllDelegations {
2173                delegator: delegator_addr_1.to_string(),
2174            },
2175        )
2176        .unwrap();
2177        assert_eq!(
2178            response1.delegations,
2179            vec![
2180                Delegation::new(
2181                    delegator_addr_1.clone(),
2182                    validator_addr_1.to_string(),
2183                    coin(50, BONDED_DENOM),
2184                ),
2185                Delegation::new(
2186                    delegator_addr_1.clone(),
2187                    validator_addr_2,
2188                    coin(160, BONDED_DENOM),
2189                ),
2190            ]
2191        );
2192        let response2: DelegationResponse = query_stake(
2193            &env,
2194            StakingQuery::Delegation {
2195                delegator: delegator_addr_2.to_string(),
2196                validator: validator_addr_1.clone(),
2197            },
2198        )
2199        .unwrap();
2200        assert_eq!(
2201            response2.delegation.unwrap(),
2202            FullDelegation::new(
2203                delegator_addr_2.clone(),
2204                validator_addr_1,
2205                coin(100, BONDED_DENOM),
2206                coin(100, BONDED_DENOM),
2207                vec![],
2208            ),
2209        );
2210    }
2211
2212    #[test]
2213    fn delegation_queries_unbonding() {
2214        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2215
2216        let validator_addr_1 = env.validator_addr_1();
2217        let delegator_addr_1 = env.delegator_addr_1();
2218        let delegator_addr_2 = env.delegator_addr_2();
2219
2220        // initialize balances
2221        init_balance(&mut env, &delegator_addr_1, 100);
2222        init_balance(&mut env, &delegator_addr_2, 150);
2223
2224        // delegate some tokens with delegator1 and delegator2
2225        execute_stake(
2226            &mut env,
2227            delegator_addr_1.clone(),
2228            StakingMsg::Delegate {
2229                validator: validator_addr_1.to_string(),
2230                amount: coin(100, BONDED_DENOM),
2231            },
2232        )
2233        .unwrap();
2234        execute_stake(
2235            &mut env,
2236            delegator_addr_2.clone(),
2237            StakingMsg::Delegate {
2238                validator: validator_addr_1.to_string(),
2239                amount: coin(150, BONDED_DENOM),
2240            },
2241        )
2242        .unwrap();
2243        // unstake some of delegator1's stake
2244        execute_stake(
2245            &mut env,
2246            delegator_addr_1.clone(),
2247            StakingMsg::Undelegate {
2248                validator: validator_addr_1.to_string(),
2249                amount: coin(50, BONDED_DENOM),
2250            },
2251        )
2252        .unwrap();
2253        // unstake all of delegator2's stake
2254        execute_stake(
2255            &mut env,
2256            delegator_addr_2.clone(),
2257            StakingMsg::Undelegate {
2258                validator: validator_addr_1.to_string(),
2259                amount: coin(150, BONDED_DENOM),
2260            },
2261        )
2262        .unwrap();
2263
2264        // query all delegations
2265        let response1: AllDelegationsResponse = query_stake(
2266            &env,
2267            StakingQuery::AllDelegations {
2268                delegator: delegator_addr_1.to_string(),
2269            },
2270        )
2271        .unwrap();
2272        assert_eq!(
2273            response1.delegations,
2274            vec![Delegation::new(
2275                delegator_addr_1.clone(),
2276                validator_addr_1.to_string(),
2277                coin(50, BONDED_DENOM),
2278            )]
2279        );
2280        let response2: DelegationResponse = query_stake(
2281            &env,
2282            StakingQuery::Delegation {
2283                delegator: delegator_addr_2.to_string(),
2284                validator: validator_addr_1.to_string(),
2285            },
2286        )
2287        .unwrap();
2288        assert_eq!(response2.delegation, None);
2289
2290        // unstake rest of delegator1's stake in two steps
2291        execute_stake(
2292            &mut env,
2293            delegator_addr_1.clone(),
2294            StakingMsg::Undelegate {
2295                validator: validator_addr_1.to_string(),
2296                amount: coin(25, BONDED_DENOM),
2297            },
2298        )
2299        .unwrap();
2300        env.block.time = env.block.time.plus_seconds(10);
2301        execute_stake(
2302            &mut env,
2303            delegator_addr_1.clone(),
2304            StakingMsg::Undelegate {
2305                validator: validator_addr_1.to_string(),
2306                amount: coin(25, BONDED_DENOM),
2307            },
2308        )
2309        .unwrap();
2310
2311        // query all delegations again
2312        let response1: DelegationResponse = query_stake(
2313            &env,
2314            StakingQuery::Delegation {
2315                delegator: delegator_addr_1.to_string(),
2316                validator: validator_addr_1,
2317            },
2318        )
2319        .unwrap();
2320        let response2: AllDelegationsResponse = query_stake(
2321            &env,
2322            StakingQuery::AllDelegations {
2323                delegator: delegator_addr_1.to_string(),
2324            },
2325        )
2326        .unwrap();
2327        assert_eq!(
2328            response1.delegation, None,
2329            "delegator1 should have no delegations left"
2330        );
2331        assert_eq!(response2.delegations, vec![]);
2332    }
2333
2334    #[test]
2335    fn partial_unbonding_reduces_stake() {
2336        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2337
2338        let validator_addr_1 = env.validator_addr_1();
2339        let delegator_addr_1 = env.delegator_addr_1();
2340
2341        // initialize balances
2342        init_balance(&mut env, &delegator_addr_1, 100);
2343
2344        // delegate all tokens
2345        execute_stake(
2346            &mut env,
2347            delegator_addr_1.clone(),
2348            StakingMsg::Delegate {
2349                validator: validator_addr_1.to_string(),
2350                amount: coin(100, BONDED_DENOM),
2351            },
2352        )
2353        .unwrap();
2354        // unstake in multiple steps
2355        execute_stake(
2356            &mut env,
2357            delegator_addr_1.clone(),
2358            StakingMsg::Undelegate {
2359                validator: validator_addr_1.to_string(),
2360                amount: coin(50, BONDED_DENOM),
2361            },
2362        )
2363        .unwrap();
2364        env.block.time = env.block.time.plus_seconds(10);
2365        execute_stake(
2366            &mut env,
2367            delegator_addr_1.clone(),
2368            StakingMsg::Undelegate {
2369                validator: validator_addr_1.to_string(),
2370                amount: coin(30, BONDED_DENOM),
2371            },
2372        )
2373        .unwrap();
2374        env.block.time = env.block.time.plus_seconds(10);
2375        execute_stake(
2376            &mut env,
2377            delegator_addr_1.clone(),
2378            StakingMsg::Undelegate {
2379                validator: validator_addr_1.to_string(),
2380                amount: coin(20, BONDED_DENOM),
2381            },
2382        )
2383        .unwrap();
2384
2385        // wait for first unbonding to complete (but not the others) and process queue
2386        env.block.time = env.block.time.plus_seconds(40);
2387        env.router
2388            .staking
2389            .process_queue(&env.api, &mut env.storage, &env.router, &env.block)
2390            .unwrap();
2391
2392        // query delegations
2393        // we now have 0 stake, 50 unbonding and 50 completed unbonding
2394        let response1: DelegationResponse = query_stake(
2395            &env,
2396            StakingQuery::Delegation {
2397                delegator: delegator_addr_1.to_string(),
2398                validator: validator_addr_1.to_string(),
2399            },
2400        )
2401        .unwrap();
2402        let response2: AllDelegationsResponse = query_stake(
2403            &env,
2404            StakingQuery::AllDelegations {
2405                delegator: delegator_addr_1.to_string(),
2406            },
2407        )
2408        .unwrap();
2409        assert_eq!(response1.delegation, None);
2410        assert_eq!(response2.delegations, vec![]);
2411
2412        // wait for the rest to complete
2413        env.block.time = env.block.time.plus_seconds(20);
2414        env.router
2415            .staking
2416            .process_queue(&env.api, &mut env.storage, &env.router, &env.block)
2417            .unwrap();
2418
2419        // query delegations again
2420        let response1: DelegationResponse = query_stake(
2421            &env,
2422            StakingQuery::Delegation {
2423                delegator: delegator_addr_1.to_string(),
2424                validator: validator_addr_1,
2425            },
2426        )
2427        .unwrap();
2428        let response2: AllDelegationsResponse = query_stake(
2429            &env,
2430            StakingQuery::AllDelegations {
2431                delegator: delegator_addr_1.to_string(),
2432            },
2433        )
2434        .unwrap();
2435        assert_eq!(
2436            response1.delegation, None,
2437            "delegator should have nothing left"
2438        );
2439        assert!(response2.delegations.is_empty());
2440    }
2441
2442    #[test]
2443    fn delegations_slashed() {
2444        let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1));
2445
2446        let validator_addr_1 = env.validator_addr_1();
2447        let delegator_addr_1 = env.delegator_addr_1();
2448
2449        // initialize balances
2450        init_balance(&mut env, &delegator_addr_1, 333);
2451
2452        // stake (delegate) some tokens
2453        execute_stake(
2454            &mut env,
2455            delegator_addr_1.clone(),
2456            StakingMsg::Delegate {
2457                validator: validator_addr_1.to_string(),
2458                amount: coin(333, BONDED_DENOM),
2459            },
2460        )
2461        .unwrap();
2462
2463        // unstake (undelegate) some tokens
2464        execute_stake(
2465            &mut env,
2466            delegator_addr_1.clone(),
2467            StakingMsg::Undelegate {
2468                validator: validator_addr_1.to_string(),
2469                amount: coin(111, BONDED_DENOM),
2470            },
2471        )
2472        .unwrap();
2473
2474        // slash validator
2475        env.router
2476            .staking
2477            .sudo(
2478                &env.api,
2479                &mut env.storage,
2480                &env.router,
2481                &env.block,
2482                StakingSudo::Slash {
2483                    validator: validator_addr_1.to_string(),
2484                    percentage: Decimal::percent(50),
2485                },
2486            )
2487            .unwrap();
2488
2489        // query all delegations
2490        let response1: AllDelegationsResponse = query_stake(
2491            &env,
2492            StakingQuery::AllDelegations {
2493                delegator: delegator_addr_1.to_string(),
2494            },
2495        )
2496        .unwrap();
2497        assert_eq!(
2498            response1.delegations[0],
2499            Delegation::new(
2500                delegator_addr_1.clone(),
2501                validator_addr_1,
2502                coin(111, BONDED_DENOM),
2503            )
2504        );
2505
2506        // wait until unbonding is complete and check if amount was slashed
2507        env.block.time = env.block.time.plus_seconds(60);
2508        env.router
2509            .staking
2510            .process_queue(&env.api, &mut env.storage, &env.router, &env.block)
2511            .unwrap();
2512        let balance =
2513            QuerierWrapper::<Empty>::new(&env.router.querier(&env.api, &env.storage, &env.block))
2514                .query_balance(delegator_addr_1, BONDED_DENOM)
2515                .unwrap();
2516        assert_eq!(55, balance.amount.u128());
2517    }
2518
2519    #[test]
2520    fn rewards_initial_wait() {
2521        let mut env = TestEnv::new(vp(0, 100, 1), vp(0, 100, 1));
2522
2523        let validator_addr_1 = env.validator_addr_1();
2524        let delegator_addr_1 = env.delegator_addr_1();
2525
2526        // initialize balances
2527        init_balance(&mut env, &delegator_addr_1, 100);
2528
2529        // wait one year before staking
2530        env.block.time = env.block.time.plus_seconds(YEAR);
2531
2532        // stake (delegate) 100 tokens to validator
2533        execute_stake(
2534            &mut env,
2535            delegator_addr_1.clone(),
2536            StakingMsg::Delegate {
2537                validator: validator_addr_1.to_string(),
2538                amount: coin(100, BONDED_DENOM),
2539            },
2540        )
2541        .unwrap();
2542
2543        // wait another year
2544        env.block.time = env.block.time.plus_seconds(YEAR);
2545
2546        // query rewards
2547        let response: DelegationResponse = query_stake(
2548            &env,
2549            StakingQuery::Delegation {
2550                delegator: delegator_addr_1.to_string(),
2551                validator: validator_addr_1,
2552            },
2553        )
2554        .unwrap();
2555
2556        assert_eq!(
2557            response.delegation.unwrap().accumulated_rewards,
2558            vec![coin(10, BONDED_DENOM)] // 10% of 100
2559        );
2560    }
2561}