Skip to content

Commit

Permalink
replaced historical epoch vector with just a rewards counter
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Jul 19, 2024
1 parent b8e7f6e commit a6a4f86
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 47 deletions.
2 changes: 1 addition & 1 deletion contracts/distribution/dao-rewards-distributor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
20 changes: 8 additions & 12 deletions contracts/distribution/dao-rewards-distributor/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -397,15 +395,13 @@ fn query_pending_rewards(deps: Deps, env: Env, addr: String) -> StdResult<Pendin

// we iterate over every registered denom and calculate the pending rewards for the user
for (denom, reward_state) in reward_states {
// first we go over the historic epochs and sum rewards earned puvp
let historic_rewards_earned_puvp = reward_state.get_historic_rewards_earned_puvp_sum();

// then we get the active epoch earned puvp value
// first we get the active epoch earned puvp value
let active_total_earned_puvp =
get_active_total_earned_puvp(deps, &env.block, &reward_state)?;

// then we add that to the historical rewards earned puvp
let total_earned_puvp =
active_total_earned_puvp.checked_add(historic_rewards_earned_puvp)?;
active_total_earned_puvp.checked_add(reward_state.historical_earned_puvp)?;

let earned_rewards = get_accrued_rewards_since_last_user_action(
deps,
Expand Down
3 changes: 3 additions & 0 deletions contracts/distribution/dao-rewards-distributor/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ pub enum ContractError {

#[error("Denom already registered")]
DenomAlreadyRegistered {},

#[error("Denom not registered")]
DenomNotRegistered {},
}
11 changes: 5 additions & 6 deletions contracts/distribution/dao-rewards-distributor/src/rewards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,18 @@ pub fn update_rewards(deps: &mut DepsMut, env: &Env, addr: &Addr, denom: String)
.unwrap_or_default();
let mut denom_reward_state = DENOM_REWARD_STATES.load(deps.storage, denom.clone())?;

// first we go over the historic epochs and sum the historic rewards earned
let total_historic_puvp = denom_reward_state.get_historic_rewards_earned_puvp_sum();

// we update the active epoch earned puvp value up to the current block
// first update the active epoch earned puvp value up to the current block
denom_reward_state.active_epoch.total_earned_puvp =
get_active_total_earned_puvp(deps.as_ref(), &env.block, &denom_reward_state)?;
denom_reward_state.bump_last_update(&env.block);

// the total applicable puvp is the sum of all historic puvp and the active epoch puvp
// then calculate the total applicable puvp, which is the sum of historical
// rewards earned puvp and the active epoch total earned puvp we just
// updated above based on the current block
let total_applicable_puvp = denom_reward_state
.active_epoch
.total_earned_puvp
.checked_add(total_historic_puvp)?;
.checked_add(denom_reward_state.historical_earned_puvp)?;

let earned_rewards = get_accrued_rewards_since_last_user_action(
deps.as_ref(),
Expand Down
63 changes: 35 additions & 28 deletions contracts/distribution/dao-rewards-distributor/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{ensure, Addr, BlockInfo, StdError, StdResult, Timestamp, Uint128, Uint256};
use cosmwasm_std::{
ensure, Addr, BlockInfo, Deps, StdError, StdResult, Timestamp, Uint128, Uint256,
};
use cw20::{Denom, Expiration};
use cw_storage_plus::Map;
use cw_utils::Duration;
use std::{cmp::min, collections::HashMap};

use crate::{helpers::get_start_end_diff, msg::RewardEmissionRate, ContractError};
use crate::{
helpers::get_start_end_diff, msg::RewardEmissionRate, rewards::get_active_total_earned_puvp,
ContractError,
};

/// map user address to their unique reward state
pub const USER_REWARD_STATES: Map<Addr, UserRewardState> = Map::new("u_r_s");
Expand Down Expand Up @@ -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<Epoch>,
/// 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(&current_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
Expand Down

0 comments on commit a6a4f86

Please sign in to comment.