Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

👷 KSX - Remove escrow on inflationary rewards and remove staking cooldown #252

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

Flocqst
Copy link
Contributor

@Flocqst Flocqst commented Jul 5, 2024

Remove escrow on inflationary rewards + Remove staking cooldown

@Flocqst Flocqst marked this pull request as ready for review July 16, 2024 16:53
@Flocqst Flocqst mentioned this pull request Jul 17, 2024
contracts/StakingRewardsV2.sol Outdated Show resolved Hide resolved
contracts/StakingRewardsV2.sol Outdated Show resolved Hide resolved
contracts/StakingRewardsV2.sol Outdated Show resolved Hide resolved
}
}

function _getRewardCompounding(address _account)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs natspec. i am confused what this is supposed to do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is called when compounding, basically it is doing the same as _getReward but without transfering because the rewards are staked right after this (can be staked immediatly after calling this (see _compound()).

Added natspec to specify this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, is there a difference to this vs. the code in _getReward other than transferring? I see duplicate code. I was thinking that this reward calculating logic would be shared between the two and getReward only has the distinction of transferring to the user.

ie.

getReward() {
    (kwenta, usdc) = _calculateReward()
    transfer kwenta
    transfer USDC
}

compound() {
    (kwenta, usdc) = _calculateReward()
    stake kwenta
    transfer USDC
}

_calculateReward() {
...
}

TLDR; we should be practicing DRY here to minimize room for error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored with a _processReward so that there is no duplicate logic

@Flocqst
Copy link
Contributor Author

Flocqst commented Aug 27, 2024

I've merged the 'Staking Cooldown Removal' feature into this branch and also pulled the USDC rewards from main branch. This PR should be the one that goes live with the KSX deployment.

Copy link
Contributor

@JaredBorders JaredBorders left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything LGTM! Nice work

@@ -19,7 +19,7 @@ import {IEscrowMigrator} from "./interfaces/IEscrowMigrator.sol";
/// @title KWENTA Reward Escrow V2
/// @author Originally inspired by SYNTHETIX RewardEscrow
/// @author Kwenta's RewardEscrow V1 by JaredBorders ([email protected]), JChiaramonte7 ([email protected])
/// @author RewardEscrowV2 by tommyrharper ([email protected])
/// @author RewardEscrowV2 by tommyrharper ([email protected]), Flocqst ([email protected])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would break each author up on separate lines

@Flocqst Flocqst changed the title 👷 Remove escrow on inflationary rewards 👷 KSX - Remove escrow on inflationary rewards and remove staking cooldown Sep 3, 2024
Copy link

Copy link

contracts/RewardEscrowV2.sol Show resolved Hide resolved
contracts/StakingRewardsV2.sol Outdated Show resolved Hide resolved
}
}

function _getRewardCompounding(address _account)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, is there a difference to this vs. the code in _getReward other than transferring? I see duplicate code. I was thinking that this reward calculating logic would be shared between the two and getReward only has the distinction of transferring to the user.

ie.

getReward() {
    (kwenta, usdc) = _calculateReward()
    transfer kwenta
    transfer USDC
}

compound() {
    (kwenta, usdc) = _calculateReward()
    stake kwenta
    transfer USDC
}

_calculateReward() {
...
}

TLDR; we should be practicing DRY here to minimize room for error.

whenNotPaused
updateReward(_account)
returns (uint256 reward)
returns (uint256 kwentaReward)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't seem you're using kwentaReward outside of _processReward, but for consistency sake you should either return both kwenta and USDC reward as a tuple or return neither.

Copy link
Contributor

@cmontecoding cmontecoding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initial review of main contracts
looks pretty straight forward so far

@@ -81,9 +75,6 @@ contract StakingRewardsV2 is
/// @notice summation of rewardRate divided by total staked tokens
uint256 public rewardPerTokenStored;

/// @inheritdoc IStakingRewardsV2
uint256 public cooldownPeriod;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we redeploying staking v2 or upgrading? because im pretty sure if we upgrade this removal will brick everything

@@ -81,9 +75,6 @@ contract StakingRewardsV2 is
/// @notice summation of rewardRate divided by total staked tokens
uint256 public rewardPerTokenStored;

/// @inheritdoc IStakingRewardsV2
uint256 public cooldownPeriod;

/// @notice represents the rewardPerToken
/// value the last time the staker calculated earned() rewards
mapping(address => uint256) public userRewardPerTokenPaid;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it wont let me comment a couple lines below for some reason but mapping(address => uint256) public userLastStakeTime; should be removed because we remove the use of it everywhere in the code

// update state (first)
rewards[_account] = 0;

// emit reward claimed event and index account
emit RewardPaid(_account, reward);
emit RewardPaid(_account, kwentaReward);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the other event is called RewardPaidUSDC

this should be called RewardPaidKwenta to match

{
// Process Kwenta reward
kwentaReward = rewards[_account];
if (kwentaReward > 0) {
// update state (first)
rewards[_account] = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if transferKwenta is set to false meaning they want to compound their rewards then doesnt this line ruin that?

their rewards are set to 0 but they dont get transferred their kwenta, so next time this is called again (im assuming after they waited for it to compound in this contract), then their rewards will be 0 or close to 0 and therefore they lost their kwenta entirely?

if im understanding this correctly then this rewards[_account] = 0; line shouldnt apply if transferKwenta == false

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh upon further look, kwentaReward is extrapolating this value? and it hopefully gets relogged when calling _stake in _compound?

@@ -397,8 +386,8 @@ contract StakingRewardsV2 is
/// @dev internal helper to compound for a given account
/// @param _account the account to compound for
function _compound(address _account) internal {
_getReward(_account);
_stakeEscrow(_account, unstakedEscrowedBalanceOf(_account));
uint256 reward = _processReward(_account, _account, false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will reward be 0 here?

Copy link
Contributor

@cmontecoding cmontecoding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just reviewed all the tests. aside: i cant find where we explicitly test these new _processReward changes.

important: we need to test the upgrade from a current fork --> new deployment (much like how cc-vesting does it). this should be done before we upgrade to ensure everything will be good, especially storage slots.
this may be doable in stakingV2.upgrade.t.sol. if not then we might have to add a new file. this may be difficult because i think everthing (testing and upgrading) is baked together and deeply webbed

Get Reward On Behalf
//////////////////////////////////////////////////////////////*/

function test_getRewardOnBehalf() public {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we remove this test and the accompanying fuzz test?

//////////////////////////////////////////////////////////////*/

function test_Get_Reward_And_Stake_On_Behalf() public {
function test_Get_Reward_On_Behalf() public {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its good that we are testing getReward() by itself now (im assuming we didnt before) but why are we just replacing the "on behalf" test? we no longer test getting the reward AND staking anymore

we should have both this test & the test_Get_Reward_And_Stake. not either or

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this reminds me: where do we test getReward (at least the new changes)? cant find it

@@ -354,7 +336,7 @@ contract StakingV2CheckpointingTests is DefaultStakingV2Setup {
assertEq(value, previousTotal + amountToStake);

// move beyond cold period
vm.warp(block.timestamp + stakingRewardsV2.cooldownPeriod());
vm.warp(block.timestamp + 2 weeks);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come we mostly remove the cooldown period in this test file but then sometimes we add back this warp forward 2 weeks?

rewardsUsdc = usdc.balanceOf(user1);
assertEq(rewards, expectedRewards);
assertApproxEqAbs(rewardsUsdc, expectedUsdcRewards, 10);
assertApproxEqAbs(rewardsUsdc, expectedUsdcRewards, 50);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we change this from 10 to 50? does that make the assert less accurate?

i just tested this locally with 10 and it still passes

assertEq(2 ether + 1 weeks, stakingRewardsV2.balanceOf(user1));
assertEq(1 ether + 1 weeks, stakingRewardsV2.escrowedBalanceOf(user1));
assertEq(1 ether, stakingRewardsV2.escrowedBalanceOf(user1));
assertEq(0, rewardEscrowV2.unstakedEscrowedBalanceOf(user1));
Copy link
Contributor

@cmontecoding cmontecoding Oct 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test suite needs to also test that all the accessible storage slots are not bricked

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants