Skip to content

Commit

Permalink
test: add tests for reaching MP limit
Browse files Browse the repository at this point in the history
Closes #4
  • Loading branch information
0x-r4bbit committed Sep 25, 2024
1 parent 7d26854 commit f4cc291
Show file tree
Hide file tree
Showing 2 changed files with 334 additions and 3 deletions.
10 changes: 7 additions & 3 deletions src/RewardsStreamerMP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ contract RewardsStreamerMP is ReentrancyGuard {
}

_updateGlobalState();
updateUserMP(msg.sender);
_updateUserMP(msg.sender);

UserInfo storage user = users[msg.sender];
if (user.lockUntil != 0 && user.lockUntil > block.timestamp) {
Expand Down Expand Up @@ -110,7 +110,7 @@ contract RewardsStreamerMP is ReentrancyGuard {
}

_updateGlobalState();
updateUserMP(msg.sender);
_updateUserMP(msg.sender);

uint256 userRewards = calculateUserRewards(msg.sender);
if (userRewards > 0) {
Expand Down Expand Up @@ -192,7 +192,7 @@ contract RewardsStreamerMP is ReentrancyGuard {
}
}

function updateUserMP(address userAddress) internal {
function _updateUserMP(address userAddress) internal {
UserInfo storage user = users[userAddress];

if (user.userPotentialMP == 0 || user.stakedBalance == 0) {
Expand All @@ -217,6 +217,10 @@ contract RewardsStreamerMP is ReentrancyGuard {
user.lastMPUpdateTime = block.timestamp;
}

function updateUserMP(address userAddress) external {
_updateUserMP(userAddress);
}

function calculateUserRewards(address userAddress) public view returns (uint256) {
UserInfo storage user = users[userAddress];
uint256 userWeight = user.stakedBalance + user.userMP;
Expand Down
327 changes: 327 additions & 0 deletions test/RewardsStreamerMP.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ contract RewardsStreamerMPTest is Test {
* (lockupTime * streamer.MAX_MULTIPLIER() * streamer.SCALE_FACTOR() / streamer.MAX_LOCKING_PERIOD())
/ streamer.SCALE_FACTOR();
}

function _calculateTimeToMPLimit(uint256 amount) public view returns (uint256) {
uint256 maxMP = amount * streamer.MAX_MULTIPLIER();
uint256 mpPerYear = (amount * streamer.MP_RATE_PER_YEAR()) / streamer.SCALE_FACTOR();
uint256 timeInSeconds = (maxMP * 365 days) / mpPerYear;
return timeInSeconds;
}
}

contract IntegrationTest is RewardsStreamerMPTest {
Expand Down Expand Up @@ -577,6 +584,172 @@ contract StakeTest is RewardsStreamerMPTest {
);
}

function test_StakeOneAccountMPIncreasesPotentialMPDecreases() public {
uint256 stakeAmount = 15e18;
uint256 potentialMP = stakeAmount * streamer.MAX_MULTIPLIER();
uint256 totalMP = stakeAmount;

_stake(alice, stakeAmount, 0);

checkStreamer(
CheckStreamerParams({
totalStaked: stakeAmount,
totalMP: stakeAmount,
potentialMP: potentialMP,
stakingBalance: stakeAmount,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);

uint256 currentTime = vm.getBlockTimestamp();
vm.warp(currentTime + (365 days));

streamer.updateGlobalState();
streamer.updateUserMP(alice);

uint256 expectedMPIncrease = stakeAmount; // 1 year passed, 1 MP accrued per token staked
totalMP = totalMP + expectedMPIncrease;
potentialMP = potentialMP - expectedMPIncrease; // we expect a decrease in potential MP as some MP have already
// been minted

checkStreamer(
CheckStreamerParams({
totalStaked: stakeAmount,
totalMP: totalMP,
potentialMP: potentialMP,
stakingBalance: stakeAmount,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);

checkUser(
CheckUserParams({
user: alice,
rewardBalance: 0,
stakedBalance: stakeAmount,
rewardIndex: 0,
userMP: totalMP, // userMP == totalMP because only one user is staking
userPotentialMP: potentialMP
})
);

currentTime = vm.getBlockTimestamp();
vm.warp(currentTime + (365 days / 2));

streamer.updateGlobalState();
streamer.updateUserMP(alice);

expectedMPIncrease = stakeAmount / 2; // 1/2 year passed, 1/2 MP accrued per token staked
totalMP = totalMP + expectedMPIncrease;
potentialMP = potentialMP - expectedMPIncrease;

checkStreamer(
CheckStreamerParams({
totalStaked: stakeAmount,
totalMP: totalMP,
potentialMP: potentialMP,
stakingBalance: stakeAmount,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);

checkUser(
CheckUserParams({
user: alice,
rewardBalance: 0,
stakedBalance: stakeAmount,
rewardIndex: 0,
userMP: totalMP, // userMP == totalMP because only one user is staking
userPotentialMP: potentialMP
})
);
}

function test_StakeOneAccountReachingMPLimit() public {
uint256 stakeAmount = 15e18;
uint256 potentialMP = stakeAmount * streamer.MAX_MULTIPLIER();
uint256 totalMP = stakeAmount;

_stake(alice, stakeAmount, 0);

checkStreamer(
CheckStreamerParams({
totalStaked: stakeAmount,
totalMP: stakeAmount,
potentialMP: potentialMP,
stakingBalance: stakeAmount,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);

checkUser(
CheckUserParams({
user: alice,
rewardBalance: 0,
stakedBalance: stakeAmount,
rewardIndex: 0,
userMP: totalMP, // userMP == totalMP because only one user is staking
userPotentialMP: potentialMP
})
);

uint256 currentTime = vm.getBlockTimestamp();
uint256 timeToMaxMP = _calculateTimeToMPLimit(stakeAmount);
vm.warp(currentTime + timeToMaxMP);

streamer.updateGlobalState();
streamer.updateUserMP(alice);

checkStreamer(
CheckStreamerParams({
totalStaked: stakeAmount,
totalMP: potentialMP + stakeAmount,
potentialMP: 0,
stakingBalance: stakeAmount,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);

checkUser(
CheckUserParams({
user: alice,
rewardBalance: 0,
stakedBalance: stakeAmount,
rewardIndex: 0,
userMP: potentialMP + stakeAmount, // userMP == totalMP because only one user is staking
userPotentialMP: 0
})
);

// move forward in time to check we're not producing more MP
vm.warp(currentTime + 1);

streamer.updateGlobalState();
streamer.updateUserMP(alice);

checkStreamer(
CheckStreamerParams({
totalStaked: stakeAmount,
totalMP: potentialMP + stakeAmount,
potentialMP: 0,
stakingBalance: stakeAmount,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);
}

function test_StakeMultipleAccounts() public {
// Alice stakes 10 tokens
_stake(alice, 10e18, 0);
Expand Down Expand Up @@ -736,6 +909,160 @@ contract StakeTest is RewardsStreamerMPTest {
})
);
}

function test_StakeMultipleAccountsMPIncreasesPotentialMPDecreases() public {
uint256 aliceStakeAmount = 15e18;
uint256 aliceMP = aliceStakeAmount;
uint256 alicePotentialMP = aliceStakeAmount * streamer.MAX_MULTIPLIER();

uint256 bobStakeAmount = 5e18;
uint256 bobMP = bobStakeAmount;
uint256 bobPotentialMP = bobStakeAmount * streamer.MAX_MULTIPLIER();

uint256 totalMP = aliceStakeAmount + bobStakeAmount;
uint256 totalStaked = aliceStakeAmount + bobStakeAmount;
uint256 potentialMP = alicePotentialMP + bobPotentialMP;

_stake(alice, aliceStakeAmount, 0);
_stake(bob, bobStakeAmount, 0);

checkStreamer(
CheckStreamerParams({
totalStaked: totalStaked,
totalMP: totalMP,
potentialMP: potentialMP,
stakingBalance: totalStaked,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);

checkUser(
CheckUserParams({
user: alice,
rewardBalance: 0,
stakedBalance: aliceStakeAmount,
rewardIndex: 0,
userMP: aliceMP,
userPotentialMP: alicePotentialMP
})
);
checkUser(
CheckUserParams({
user: bob,
rewardBalance: 0,
stakedBalance: bobStakeAmount,
rewardIndex: 0,
userMP: bobMP,
userPotentialMP: bobPotentialMP
})
);

uint256 currentTime = vm.getBlockTimestamp();
vm.warp(currentTime + (365 days));

streamer.updateGlobalState();
streamer.updateUserMP(alice);
streamer.updateUserMP(bob);

uint256 aliceExpectedMPIncrease = aliceStakeAmount; // 1 year passed, 1 MP accrued per token staked
uint256 bobExpectedMPIncrease = bobStakeAmount; // 1 year passed, 1 MP accrued per token staked
uint256 totalExpectedMPIncrease = aliceExpectedMPIncrease + bobExpectedMPIncrease;

aliceMP = aliceMP + aliceExpectedMPIncrease;
bobMP = bobMP + bobExpectedMPIncrease;
totalMP = totalMP + totalExpectedMPIncrease;

alicePotentialMP = alicePotentialMP - aliceExpectedMPIncrease;
bobPotentialMP = bobPotentialMP - bobExpectedMPIncrease;
potentialMP = potentialMP - totalExpectedMPIncrease;

checkStreamer(
CheckStreamerParams({
totalStaked: totalStaked,
totalMP: totalMP,
potentialMP: potentialMP,
stakingBalance: totalStaked,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);

checkUser(
CheckUserParams({
user: alice,
rewardBalance: 0,
stakedBalance: aliceStakeAmount,
rewardIndex: 0,
userMP: aliceMP,
userPotentialMP: alicePotentialMP
})
);
checkUser(
CheckUserParams({
user: bob,
rewardBalance: 0,
stakedBalance: bobStakeAmount,
rewardIndex: 0,
userMP: bobMP,
userPotentialMP: bobPotentialMP
})
);

currentTime = vm.getBlockTimestamp();
vm.warp(currentTime + (365 days / 2));

streamer.updateGlobalState();
streamer.updateUserMP(alice);
streamer.updateUserMP(bob);

aliceExpectedMPIncrease = aliceStakeAmount / 2;
bobExpectedMPIncrease = bobStakeAmount / 2;
totalExpectedMPIncrease = aliceExpectedMPIncrease + bobExpectedMPIncrease;

aliceMP = aliceMP + aliceExpectedMPIncrease;
bobMP = bobMP + bobExpectedMPIncrease;
totalMP = totalMP + totalExpectedMPIncrease;

alicePotentialMP = alicePotentialMP - aliceExpectedMPIncrease;
bobPotentialMP = bobPotentialMP - bobExpectedMPIncrease;
potentialMP = potentialMP - totalExpectedMPIncrease;

checkStreamer(
CheckStreamerParams({
totalStaked: totalStaked,
totalMP: totalMP,
potentialMP: potentialMP,
stakingBalance: totalStaked,
rewardBalance: 0,
rewardIndex: 0,
accountedRewards: 0
})
);

checkUser(
CheckUserParams({
user: alice,
rewardBalance: 0,
stakedBalance: aliceStakeAmount,
rewardIndex: 0,
userMP: aliceMP,
userPotentialMP: alicePotentialMP
})
);
checkUser(
CheckUserParams({
user: bob,
rewardBalance: 0,
stakedBalance: bobStakeAmount,
rewardIndex: 0,
userMP: bobMP,
userPotentialMP: bobPotentialMP
})
);
}
}

contract UnstakeTest is StakeTest {
Expand Down

0 comments on commit f4cc291

Please sign in to comment.