diff --git a/contracts/stake/src/contract.rs b/contracts/stake/src/contract.rs index cde982e..b0a3127 100644 --- a/contracts/stake/src/contract.rs +++ b/contracts/stake/src/contract.rs @@ -538,6 +538,7 @@ pub fn execute_mass_bond( .map(|((asset_info, mut distribution), old_reward_power)| { let new_reward_power = distribution.calc_rewards_power(deps.storage, &cfg, &sender)?; + dbg!("BONDING", old_reward_power, new_reward_power); update_rewards( deps.storage, &asset_info, diff --git a/contracts/stake/src/distribution.rs b/contracts/stake/src/distribution.rs index c177dd7..eeadea5 100644 --- a/contracts/stake/src/distribution.rs +++ b/contracts/stake/src/distribution.rs @@ -79,6 +79,7 @@ pub fn execute_distribute_rewards( let leftover: u128 = distribution.shares_leftover.into(); let points = (amount << SHARES_SHIFT) + leftover; + dbg!(points, total_rewards.u128(), points / total_rewards.u128()); let points_per_share = points / total_rewards.u128(); distribution.shares_leftover = (points % total_rewards.u128()) as u64; @@ -86,9 +87,11 @@ pub fn execute_distribute_rewards( // Full amount is added here to total withdrawable, as it should not be considered on its own // on future distributions - even if because of calculation offsets it is not fully // distributed, the error is handled by leftover. + // poi 1 distribution.shares_per_point += Uint128::new(points_per_share); distribution.distributed_total += Uint128::new(amount); distribution.withdrawable_total += Uint128::new(amount); + dbg!(distribution.clone()); DISTRIBUTION.save(deps.storage, &asset_info, &distribution)?; @@ -146,6 +149,7 @@ pub fn execute_withdraw_rewards( let mut adjustment = WITHDRAW_ADJUSTMENT .may_load(deps.storage, (&owner, &asset_info))? .unwrap_or_default(); + dbg!(adjustment.clone()); let reward = withdrawable_rewards(deps.as_ref(), &cfg, &owner, &distribution, &adjustment)?; @@ -290,8 +294,15 @@ pub fn apply_points_correction( diff: i128, ) -> StdResult<()> { WITHDRAW_ADJUSTMENT.update(storage, (addr, asset_info), |old| -> StdResult<_> { - let mut old = old.unwrap_or_default(); + let mut old = old.unwrap_or_default(); //eq to withdraw_adjustment in phoenix let shares_correction: i128 = old.shares_correction; + dbg!(old.clone()); + dbg!( + shares_correction, + shares_per_point, + diff, + shares_correction - shares_per_point as i128 * diff + ); old.shares_correction = shares_correction - shares_per_point as i128 * diff; Ok(old) })?; @@ -312,11 +323,12 @@ pub fn withdrawable_rewards( .calc_rewards_power(deps.storage, cfg, owner)? .u128(); + dbg!(ppw, points, adjustment.clone()); let correction = adjustment.shares_correction; let points = (ppw * points) as i128; + dbg!(ppw * points as u128); let points = points + correction; let amount = points as u128 >> SHARES_SHIFT; let amount = amount - adjustment.withdrawn_rewards.u128(); - Ok(amount.into()) } diff --git a/contracts/stake/src/multitest/distribution.rs b/contracts/stake/src/multitest/distribution.rs index e0a3408..7c8650a 100644 --- a/contracts/stake/src/multitest/distribution.rs +++ b/contracts/stake/src/multitest/distribution.rs @@ -2527,3 +2527,115 @@ fn withdraw_adjustment_handled_lazily() { // member should get rewards assert_eq!(suite.query_balance(member, "juno").unwrap(), 500); } + +#[test] +fn test_unbond_brakes_reward_distribution() { + let members = vec!["member0".to_owned(), "member1".to_owned()]; + let executor = "executor"; + + let unbonding_period = 10_000; + + let mut suite = SuiteBuilder::new() + .with_unbonding_periods(vec![unbonding_period]) + .with_min_bond(1000) + .with_initial_balances(vec![(&members[0], 1_000), (&members[1], 1_000)]) + .with_admin("admin") + .with_native_balances("juno", vec![(executor, 100_000)]) + .build(); + + suite + .create_distribution_flow( + "admin", + executor, + AssetInfo::Native("juno".to_string()), + vec![(unbonding_period, Decimal::one())], + ) + .unwrap(); + + // delegate + suite + .delegate(&members[0], 1_000u128, unbonding_period) + .unwrap(); + suite + .delegate(&members[1], 1_000u128, unbonding_period) + .unwrap(); + + suite.update_time(2_000); + + // distribute 20% of total supply + suite + .distribute_funds(executor, executor, Some(juno(20_000))) + .unwrap(); + + // withdraw the rewards + suite + .withdraw_funds(&members[0], members[0].as_str(), None) + .unwrap(); + suite + .withdraw_funds(&members[1], members[1].as_str(), None) + .unwrap(); + + assert_eq!(suite.query_balance(&members[0], "juno").unwrap(), 10_000); + assert_eq!(suite.query_balance(&members[1], "juno").unwrap(), 10_000); + + suite.update_time(5_000); + + // unbond member1 + suite.unbond(&members[0], 1000, unbonding_period).unwrap(); + + suite.update_time(10_000); + + // distribute the rest of the 100k + suite + .distribute_funds(executor, executor, Some(juno(80_000))) + .unwrap(); + + suite + .withdraw_funds(&members[1], members[1].as_str(), None) + .unwrap(); + + assert_eq!(suite.query_balance(&members[0], "juno").unwrap(), 10_000); + assert_eq!(suite.query_balance(&members[1], "juno").unwrap(), 90_000); +} + +#[test] +fn test_bond_withdraw_unbond() { + let user = "member"; + let executor = "executor"; + let unbonding_period = 10_000; + + let mut suite = SuiteBuilder::new() + .with_unbonding_periods(vec![unbonding_period]) + .with_min_bond(1000) + .with_initial_balances(vec![(user, 1_000)]) + .with_admin("admin") + .with_native_balances("juno", vec![(executor, 100_000)]) + .build(); + + // create distribution flow + suite + .create_distribution_flow( + "admin", + executor, + AssetInfo::Native("juno".to_string()), + vec![(unbonding_period, Decimal::one())], + ) + .unwrap(); + + // Bond + suite.delegate(user, 1_000, unbonding_period).unwrap(); + + // Distribute rewards + suite + .distribute_funds(executor, None, Some(juno(500))) + .unwrap(); + + // Withdraw rewards + suite.withdraw_funds(user, user, None).unwrap(); + + // Unbond + suite.unbond(user, 1_000, unbonding_period).unwrap(); + + // Assert balances + assert_eq!(suite.query_balance(user, "juno").unwrap(), 500); +} diff --git a/contracts/stake/src/utils.rs b/contracts/stake/src/utils.rs index 2547929..66e47a2 100644 --- a/contracts/stake/src/utils.rs +++ b/contracts/stake/src/utils.rs @@ -22,9 +22,16 @@ pub fn create_undelegate_msg( } pub fn calc_power(cfg: &Config, stake: Uint128, multiplier: Decimal) -> Uint128 { + dbg!("CALCULATING POWER"); if stake < cfg.min_bond { Uint128::zero() } else { + dbg!( + stake, + multiplier, + cfg.tokens_per_power, + stake * multiplier / cfg.tokens_per_power + ); stake * multiplier / cfg.tokens_per_power } }