From a6a4f8633e02ed125f704f7a12de89a94e512d8a Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Fri, 19 Jul 2024 15:38:42 -0400 Subject: [PATCH] replaced historical epoch vector with just a rewards counter --- .../dao-rewards-distributor/README.md | 2 +- .../dao-rewards-distributor/src/contract.rs | 20 +++--- .../dao-rewards-distributor/src/error.rs | 3 + .../dao-rewards-distributor/src/rewards.rs | 11 ++-- .../dao-rewards-distributor/src/state.rs | 63 ++++++++++--------- 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/contracts/distribution/dao-rewards-distributor/README.md b/contracts/distribution/dao-rewards-distributor/README.md index 0210ab615..68d636673 100644 --- a/contracts/distribution/dao-rewards-distributor/README.md +++ b/contracts/distribution/dao-rewards-distributor/README.md @@ -78,7 +78,7 @@ Updating the denom reward emission rate archives the active reward epoch and sta First, the currently active epoch is evaluated. We find the amount of tokens that were earned to this point per unit of voting power and save that in the current epoch as its total earned rewards per unit of voting power. We then bump the last update with that of the current block, and transition into the new epoch. -Active reward epoch is moved into the `historic_epochs`. This is a list of previously active reward emission schedules, along with their finalized amounts. +The final (partial) amount of rewards distributed during the active reward epoch are added to `historical_earned_puvp` to ensure they can still be claimed. This historical value contains all rewards distributed during past epochs. ### Shutting down denom distribution diff --git a/contracts/distribution/dao-rewards-distributor/src/contract.rs b/contracts/distribution/dao-rewards-distributor/src/contract.rs index c8b7a0e48..cbf1345ab 100644 --- a/contracts/distribution/dao-rewards-distributor/src/contract.rs +++ b/contracts/distribution/dao-rewards-distributor/src/contract.rs @@ -81,14 +81,12 @@ fn execute_update_reward_rate( // only the owner can update the reward rate cw_ownable::assert_owner(deps.storage, &info.sender)?; - let mut reward_state = DENOM_REWARD_STATES.load(deps.storage, denom.clone())?; - reward_state.active_epoch.total_earned_puvp = - get_active_total_earned_puvp(deps.as_ref(), &env.block, &reward_state)?; - reward_state.bump_last_update(&env.block); + let mut reward_state = DENOM_REWARD_STATES + .load(deps.storage, denom.clone()) + .map_err(|_| ContractError::DenomNotRegistered {})?; // transition the epoch to the new emission rate and save - reward_state.transition_epoch(new_emission_rate, &env.block)?; - + reward_state.transition_epoch(deps.as_ref(), new_emission_rate, &env.block)?; DENOM_REWARD_STATES.save(deps.storage, denom.clone(), &reward_state)?; Ok(Response::new().add_attribute("action", "update_reward_rate")) @@ -136,7 +134,7 @@ fn execute_register_reward_denom( hook_caller: hook_caller.clone(), funded_amount: Uint128::zero(), withdraw_destination, - historic_epochs: vec![], + historical_earned_puvp: Uint256::zero(), }; let str_denom = reward_state.to_str_denom(); @@ -397,15 +395,13 @@ fn query_pending_rewards(deps: Deps, env: Env, addr: String) -> StdResult = Map::new("u_r_s"); @@ -78,52 +83,54 @@ pub struct DenomRewardState { pub funded_amount: Uint128, /// optional destination address for reward clawbacks pub withdraw_destination: Addr, - /// historic denom distribution epochs - pub historic_epochs: Vec, + /// historical rewards earned per unit voting power from past epochs due to + /// changes in the emission rate. each time emission rate is changed, this + /// value is increased by the `active_epoch`'s rewards earned puvp. + pub historical_earned_puvp: Uint256, } impl DenomRewardState { - /// Sum all historical total_earned_puvp values. - pub fn get_historic_rewards_earned_puvp_sum(&self) -> Uint256 { - self.historic_epochs - .iter() - .fold(Uint256::zero(), |acc, epoch| acc + epoch.total_earned_puvp) - } - /// Finish current epoch early and start a new one with a new emission rate. pub fn transition_epoch( &mut self, + deps: Deps, new_emission_rate: RewardEmissionRate, current_block: &BlockInfo, ) -> StdResult<()> { + // if the new emission rate is the same as the active one, do nothing + if self.active_epoch.emission_rate == new_emission_rate { + return Ok(()); + } + let current_block_expiration = match self.active_epoch.emission_rate.duration { Duration::Height(_) => Expiration::AtHeight(current_block.height), Duration::Time(_) => Expiration::AtTime(current_block.time), }; - // 1. finish current epoch by changing the end to now - let mut curr_epoch = self.active_epoch.clone(); - curr_epoch.ends_at = current_block_expiration; - curr_epoch.finish_block = Some(current_block.to_owned()); + // 1. finish current epoch by updating rewards and setting end to now + self.active_epoch.total_earned_puvp = + get_active_total_earned_puvp(deps, current_block, &self)?; + self.active_epoch.ends_at = current_block_expiration; + self.active_epoch.finish_block = Some(current_block.to_owned()); + self.bump_last_update(¤t_block); - // TODO: remove println - println!("transition_epoch: {:?}", curr_epoch); - // 2. push current epoch to historic configs - self.historic_epochs.push(curr_epoch.clone()); + // 2. add current epoch rewards earned to historical rewards + // TODO: what to do on overflow? + self.historical_earned_puvp = self + .historical_earned_puvp + .checked_add(self.active_epoch.total_earned_puvp)?; - // 3. deduct the distributed rewards amount from total funded amount, - // as those rewards are no longer available for distribution - let curr_epoch_earned_rewards = match curr_epoch.emission_rate.amount.is_zero() { + // 3. deduct the distributed rewards amount from total funded amount, as + // those rewards are no longer distributed in the new epoch + let active_epoch_earned_rewards = match self.active_epoch.emission_rate.amount.is_zero() { true => Uint128::zero(), - false => curr_epoch.get_total_rewards()?, + false => self.active_epoch.get_total_rewards()?, }; - self.funded_amount = self.funded_amount.checked_sub(curr_epoch_earned_rewards)?; + self.funded_amount = self + .funded_amount + .checked_sub(active_epoch_earned_rewards)?; // 4. start new epoch - // TODO: remove println - println!("fund amount: {:?}", self.funded_amount); - // TODO: remove println - println!("new_emission_rate: {:?}", new_emission_rate); // we get the duration of the funded period and add it to the current // block height. if the sum overflows, we return u64::MAX, as it