diff --git a/Cargo.lock b/Cargo.lock index 416b5955..eb015e47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -532,9 +532,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] diff --git a/src/staking.rs b/src/staking.rs index 8dc750a4..79783ae0 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -50,12 +50,12 @@ struct Shares { } impl Shares { - /// Calculates the share of validator rewards that should be given to this staker. - pub fn share_of_rewards(&self, validator: &ValidatorInfo, rewards: Decimal) -> Decimal { - if validator.stake.is_zero() { + /// Calculates the share of validator's rewards that should be given to this staker. + pub fn share_of_rewards(&self, validator_info: &ValidatorInfo, rewards: Decimal) -> Decimal { + if validator_info.stake.is_zero() { return Decimal::zero(); } - rewards * self.stake / validator.stake + rewards * self.stake / validator_info.stake } } @@ -83,20 +83,24 @@ impl ValidatorInfo { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] struct Unbonding { + /// Staker (delegator) address. pub delegator: Addr, - pub validator: Addr, + /// Validator address. + pub validator: String, + /// Amount of stakes to be unbonded. pub amount: Uint128, + /// Timestamp at which unbonding will take place (simulates unbonding timeout). pub payout_at: Timestamp, } const STAKING_INFO: Item = Item::new("staking_info"); /// (staker_addr, validator_addr) -> shares -const STAKES: Map<(&Addr, &Addr), Shares> = Map::new("stakes"); -const VALIDATOR_MAP: Map<&Addr, Validator> = Map::new("validator_map"); +const STAKES: Map<(&Addr, &str), Shares> = Map::new("stakes"); +const VALIDATOR_MAP: Map<&str, Validator> = Map::new("validator_map"); /// Additional vec of validators, in case the `iterator` feature is disabled const VALIDATORS: Deque = Deque::new("validators"); /// Contains additional info for each validator -const VALIDATOR_INFO: Map<&Addr, ValidatorInfo> = Map::new("validator_info"); +const VALIDATOR_INFO: Map<&str, ValidatorInfo> = Map::new("validator_info"); /// The queue of unbonding operations. This is needed because unbonding has a waiting time. See [`StakeKeeper`] const UNBONDING_QUEUE: Item> = Item::new("unbonding_queue"); /// (addr) -> addr. Maps addresses to the address they have delegated @@ -174,27 +178,31 @@ impl StakeKeeper { Ok(()) } - /// Add a new validator available for staking + /// Add a new validator available for staking. pub fn add_validator( &self, - api: &dyn Api, + _api: &dyn Api, storage: &mut dyn Storage, block: &BlockInfo, validator: Validator, ) -> AnyResult<()> { let mut storage = prefixed(storage, NAMESPACE_STAKING); - - let val_addr = api.addr_validate(&validator.address)?; - if VALIDATOR_MAP.may_load(&storage, &val_addr)?.is_some() { + if VALIDATOR_MAP + .may_load(&storage, &validator.address)? + .is_some() + { bail!( "Cannot add validator {}, since a validator with that address already exists", - val_addr + validator.address ); } - - VALIDATOR_MAP.save(&mut storage, &val_addr, &validator)?; + VALIDATOR_MAP.save(&mut storage, &validator.address, &validator)?; VALIDATORS.push_back(&mut storage, &validator)?; - VALIDATOR_INFO.save(&mut storage, &val_addr, &ValidatorInfo::new(block.time))?; + VALIDATOR_INFO.save( + &mut storage, + &validator.address, + &ValidatorInfo::new(block.time), + )?; Ok(()) } @@ -202,16 +210,15 @@ impl StakeKeeper { Ok(STAKING_INFO.may_load(staking_storage)?.unwrap_or_default()) } - /// Returns the rewards of the given delegator at the given validator + /// Returns the rewards of the given delegator at the given validator. pub fn get_rewards( &self, storage: &dyn Storage, block: &BlockInfo, delegator: &Addr, - validator: &Addr, + validator: &str, ) -> AnyResult> { let staking_storage = prefixed_read(storage, NAMESPACE_STAKING); - let validator_obj = match self.get_validator(&staking_storage, validator)? { Some(validator) => validator, None => bail!("validator {} not found", validator), @@ -224,7 +231,6 @@ impl StakeKeeper { } }; let validator_info = VALIDATOR_INFO.load(&staking_storage, validator)?; - Self::get_rewards_internal( &staking_storage, block, @@ -288,10 +294,10 @@ impl StakeKeeper { /// It saves the validator info and stakers, so make sure not to overwrite that. /// Always call this to update rewards before changing anything that influences future rewards. fn update_rewards( - api: &dyn Api, + _api: &dyn Api, staking_storage: &mut dyn Storage, block: &BlockInfo, - validator: &Addr, + validator: &str, ) -> AnyResult<()> { let staking_info = Self::get_staking_info(staking_storage)?; @@ -320,12 +326,11 @@ impl StakeKeeper { // update delegators if !new_rewards.is_zero() { - let validator_addr = api.addr_validate(&validator_obj.address)?; // update all delegators for staker in validator_info.stakers.iter() { STAKES.update( staking_storage, - (staker, &validator_addr), + (staker, &validator_obj.address), |shares| -> AnyResult<_> { let mut shares = shares.expect("all stakers in validator_info should exist"); @@ -338,11 +343,11 @@ impl StakeKeeper { Ok(()) } - /// Returns the single validator with the given address (or `None` if there is no such validator) + /// Returns the single validator with the given address (or `None` if there is no such validator). fn get_validator( &self, staking_storage: &dyn Storage, - address: &Addr, + address: &str, ) -> AnyResult> { Ok(VALIDATOR_MAP.may_load(staking_storage, address)?) } @@ -357,7 +362,7 @@ impl StakeKeeper { &self, staking_storage: &dyn Storage, account: &Addr, - validator: &Addr, + validator: &str, ) -> AnyResult> { let shares = STAKES.may_load(staking_storage, (account, validator))?; let staking_info = Self::get_staking_info(staking_storage)?; @@ -376,7 +381,7 @@ impl StakeKeeper { staking_storage: &mut dyn Storage, block: &BlockInfo, to_address: &Addr, - validator: &Addr, + validator: &str, amount: Coin, ) -> AnyResult<()> { self.validate_denom(staking_storage, &amount)?; @@ -397,7 +402,7 @@ impl StakeKeeper { staking_storage: &mut dyn Storage, block: &BlockInfo, from_address: &Addr, - validator: &Addr, + validator: &str, amount: Coin, ) -> AnyResult<()> { self.validate_denom(staking_storage, &amount)?; @@ -418,7 +423,7 @@ impl StakeKeeper { staking_storage: &mut dyn Storage, block: &BlockInfo, delegator: &Addr, - validator: &Addr, + validator: &str, amount: impl Into, sub: bool, ) -> AnyResult<()> { @@ -473,7 +478,7 @@ impl StakeKeeper { api: &dyn Api, staking_storage: &mut dyn Storage, block: &BlockInfo, - validator: &Addr, + validator: &str, percentage: Decimal, ) -> AnyResult<()> { // calculate rewards before slashing @@ -644,8 +649,6 @@ impl Module for StakeKeeper { let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); match msg { StakingMsg::Delegate { validator, amount } => { - let validator = api.addr_validate(&validator)?; - // see https://github.com/cosmos/cosmos-sdk/blob/3c5387048f75d7e78b40c5b8d2421fdb8f5d973a/x/staking/types/msg.go#L202-L207 if amount.amount.is_zero() { bail!("invalid delegation amount"); @@ -679,7 +682,6 @@ impl Module for StakeKeeper { Ok(AppResponse { events, data: None }) } StakingMsg::Undelegate { validator, amount } => { - let validator = api.addr_validate(&validator)?; self.validate_denom(&staking_storage, &amount)?; // see https://github.com/cosmos/cosmos-sdk/blob/3c5387048f75d7e78b40c5b8d2421fdb8f5d973a/x/staking/types/msg.go#L292-L297 @@ -719,8 +721,6 @@ impl Module for StakeKeeper { dst_validator, amount, } => { - let src_validator = api.addr_validate(&src_validator)?; - let dst_validator = api.addr_validate(&dst_validator)?; // see https://github.com/cosmos/cosmos-sdk/blob/v0.46.1/x/staking/keeper/msg_server.go#L316-L322 let events = vec![Event::new("redelegate") .add_attribute("source_validator", &src_validator) @@ -773,11 +773,7 @@ impl Module for StakeKeeper { .filter_map(|validator| { let delegator = delegator.clone(); let amount = self - .get_stake( - &staking_storage, - &delegator, - &Addr::unchecked(&validator.address), - ) + .get_stake(&staking_storage, &delegator, &validator.address) .transpose()?; Some(amount.map(|amount| { @@ -792,18 +788,17 @@ impl Module for StakeKeeper { delegator, validator, } => { - let validator_addr = Addr::unchecked(&validator); - let validator_obj = match self.get_validator(&staking_storage, &validator_addr)? { + let validator_obj = match self.get_validator(&staking_storage, &validator)? { Some(validator) => validator, None => bail!("non-existent validator {}", validator), }; let delegator = api.addr_validate(&delegator)?; let shares = STAKES - .may_load(&staking_storage, (&delegator, &validator_addr))? + .may_load(&staking_storage, (&delegator, &validator))? .unwrap_or_default(); - let validator_info = VALIDATOR_INFO.load(&staking_storage, &validator_addr)?; + let validator_info = VALIDATOR_INFO.load(&staking_storage, &validator)?; let reward = Self::get_rewards_internal( &staking_storage, block, @@ -842,7 +837,7 @@ impl Module for StakeKeeper { self.get_validators(&staking_storage)?, ))?), StakingQuery::Validator { address } => Ok(to_json_binary(&ValidatorResponse::new( - self.get_validator(&staking_storage, &Addr::unchecked(address))?, + self.get_validator(&staking_storage, &address)?, ))?), q => bail!("Unsupported staking sudo message: {:?}", q), } @@ -862,7 +857,6 @@ impl Module for StakeKeeper { percentage, } => { let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); - let validator = api.addr_validate(&validator)?; self.validate_percentage(percentage)?; self.slash(api, &mut staking_storage, block, &validator, percentage)?; Ok(AppResponse::default()) @@ -892,7 +886,7 @@ impl DistributionKeeper { storage: &mut dyn Storage, block: &BlockInfo, delegator: &Addr, - validator: &Addr, + validator: &str, ) -> AnyResult { let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); // update the validator and staker rewards @@ -956,10 +950,7 @@ impl Module for DistributionKeeper { ) -> AnyResult { match msg { DistributionMsg::WithdrawDelegatorReward { validator } => { - let validator_addr = api.addr_validate(&validator)?; - - let rewards = self.remove_rewards(api, storage, block, &sender, &validator_addr)?; - + let rewards = self.remove_rewards(api, storage, block, &sender, &validator)?; let staking_storage = prefixed_read(storage, NAMESPACE_STAKING); let distribution_storage = prefixed_read(storage, NAMESPACE_DISTRIBUTION); let staking_info = StakeKeeper::get_staking_info(&staking_storage)?; @@ -1031,8 +1022,8 @@ impl Module for DistributionKeeper { mod test { use super::*; use crate::{ - BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, StargateFailing, - WasmKeeper, + BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, IntoBech32, Router, + StargateFailing, WasmKeeper, }; use cosmwasm_std::{ coins, from_json, @@ -1079,9 +1070,9 @@ mod test { storage: MockStorage, router: BasicRouter, block: BlockInfo, - validator_addr_1: Addr, - validator_addr_2: Addr, - validator_addr_3: Addr, + validator_addr_1: String, + validator_addr_2: String, + validator_addr_3: String, delegator_addr_1: Addr, delegator_addr_2: Addr, user_addr_1: Addr, @@ -1092,9 +1083,8 @@ mod test { fn new(validator1: ValidatorProperties, validator2: ValidatorProperties) -> Self { // Utility function for creating a validator's address, // which has a different prefix from a user's address. - fn valoper_address(api: &MockApi, value: &str) -> Addr { - //TODO: this will be different in next PR, as requested in: https://github.com/CosmWasm/cw-multi-test/issues/173 - api.addr_make(value) + fn validator_address(value: &str) -> String { + value.into_bech32_with_prefix("cosmwasmvaloper").to_string() } // Utility function for creating a user's address, @@ -1117,9 +1107,9 @@ mod test { let mut storage = MockStorage::new(); let block = mock_env().block; - let validator_addr_1 = valoper_address(&api, "validator1"); - let validator_addr_2 = valoper_address(&api, "validator2"); - let validator_addr_3 = valoper_address(&api, "validator3"); + let validator_addr_1 = validator_address("validator1"); + let validator_addr_2 = validator_address("validator2"); + let validator_addr_3 = validator_address("validator3"); // configure basic staking parameters router @@ -1168,19 +1158,19 @@ mod test { /// Returns an address of EXISTING validator no. 1. #[inline(always)] - fn validator_addr_1(&self) -> Addr { + fn validator_addr_1(&self) -> String { self.validator_addr_1.clone() } /// Returns an address of EXISTING validator no. 2. #[inline(always)] - fn validator_addr_2(&self) -> Addr { + fn validator_addr_2(&self) -> String { self.validator_addr_2.clone() } /// Returns an address of NON-EXISTING validator no. 3. #[inline(always)] - fn validator_addr_3(&self) -> Addr { + fn validator_addr_3(&self) -> String { self.validator_addr_3.clone() } @@ -1706,7 +1696,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -1733,7 +1723,7 @@ mod test { &mut env, delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), }, ) .unwrap(); @@ -1750,8 +1740,8 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Redelegate { - src_validator: validator_addr_1.to_string(), - dst_validator: validator_addr_2.to_string(), + src_validator: validator_addr_1, + dst_validator: validator_addr_2.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -1771,7 +1761,7 @@ mod test { delegations.delegations, [Delegation::new( delegator_addr_1.clone(), - validator_addr_2.to_string(), + validator_addr_2.clone(), coin(100, BONDED_DENOM), )] ); @@ -1781,7 +1771,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator_addr_2.to_string(), + validator: validator_addr_2, amount: coin(100, BONDED_DENOM), }, ) @@ -1816,7 +1806,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -1840,7 +1830,7 @@ mod test { &mut env, delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), }, ) .unwrap(); @@ -1863,7 +1853,7 @@ mod test { &mut env, delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), + validator: validator_addr_1, }, ) .unwrap(); @@ -1896,7 +1886,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -1907,7 +1897,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(200, BONDED_DENOM), }, ) @@ -1919,8 +1909,8 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Redelegate { - src_validator: validator_addr_1.to_string(), - dst_validator: validator_addr_2.to_string(), + src_validator: validator_addr_1, + dst_validator: validator_addr_2.clone(), amount: coin(200, BONDED_DENOM), }, ) @@ -1932,7 +1922,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator_addr_2.to_string(), + validator: validator_addr_2, amount: coin(100, BONDED_DENOM), }, ) @@ -1958,7 +1948,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1, amount: coin(100, "FAKE"), }, ) @@ -1989,7 +1979,7 @@ mod test { &env.router, &env.block, StakingSudo::Slash { - validator: validator_addr_3.to_string(), + validator: validator_addr_3, percentage: Decimal::percent(50), }, ) @@ -2012,7 +2002,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_3.to_string(), + validator: validator_addr_3.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -2024,7 +2014,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator_addr_3.to_string(), + validator: validator_addr_3, amount: coin(100, BONDED_DENOM), }, ) @@ -2044,7 +2034,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(0, BONDED_DENOM), }, ) @@ -2056,7 +2046,7 @@ mod test { &mut env, delegator_addr_1, StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1, amount: coin(0, BONDED_DENOM), }, ) @@ -2182,7 +2172,7 @@ mod test { ), Delegation::new( delegator_addr_1.clone(), - validator_addr_2.to_string(), + validator_addr_2, coin(160, BONDED_DENOM), ), ] @@ -2191,7 +2181,7 @@ mod test { &env, StakingQuery::Delegation { delegator: delegator_addr_2.to_string(), - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), }, ) .unwrap(); @@ -2199,7 +2189,7 @@ mod test { response2.delegation.unwrap(), FullDelegation::new( delegator_addr_2.clone(), - validator_addr_1.to_string(), + validator_addr_1, coin(100, BONDED_DENOM), coin(100, BONDED_DENOM), vec![], @@ -2311,7 +2301,7 @@ mod test { &env, StakingQuery::Delegation { delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), + validator: validator_addr_1, }, ) .unwrap(); @@ -2419,7 +2409,7 @@ mod test { &env, StakingQuery::Delegation { delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), + validator: validator_addr_1, }, ) .unwrap(); @@ -2496,7 +2486,7 @@ mod test { response1.delegations[0], Delegation::new( delegator_addr_1.clone(), - validator_addr_1.to_string(), + validator_addr_1, coin(111, BONDED_DENOM), ) ); @@ -2546,7 +2536,7 @@ mod test { &env, StakingQuery::Delegation { delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), + validator: validator_addr_1, }, ) .unwrap();