Skip to content

Commit

Permalink
Merge branch 'DanielVF/xogn2' into shah/ogn-rewards-source
Browse files Browse the repository at this point in the history
  • Loading branch information
shahthepro committed Apr 26, 2024
2 parents db52be3 + 1864b68 commit 50a0021
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 18 deletions.
17 changes: 13 additions & 4 deletions contracts/ExponentialStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {RewardsSource} from "./RewardsSource.sol";
/// The balance received for staking (and thus the voting power and rewards
/// distribution) goes up exponentially by the end of the staked period.
contract ExponentialStaking is ERC20Votes {
uint256 public immutable epoch; // timestamp
uint256 public immutable epoch; // Start of staking program - timestamp
ERC20 public immutable asset; // Must not allow reentrancy
RewardsSource public immutable rewardsSource;
uint256 public immutable minStakeDuration; // in seconds
Expand Down Expand Up @@ -136,17 +136,18 @@ contract ExponentialStaking is ERC20Votes {

// Update or create lockup
if (lockupId != NEW_STAKE) {
require(newEnd > oldEnd, "Staking: New lockup must be longer");
require(newEnd >= oldEnd, "Staking: New lockup must not be shorter");
require(newPoints > oldPoints, "Staking: Must have increased amount or duration");
lockups[to][uint256(lockupId)] = lockup;
} else {
lockups[to].push(lockup);
uint256 numLockups = lockups[to].length;
require(numLockups < uint256(type(int256).max), "Staking: Too many lockups");
lockupId = int256(numLockups - 1);
// Delegate voting power to the receiver, if unregistered and first stake
if (numLockups == 1 && delegates(to) == address(0)) {
_delegate(to, to);
}
require(numLockups < uint256(type(int256).max), "Staking: Too many lockups");
lockupId = int256(numLockups - 1);
}
_mint(to, newPoints - oldPoints);
emit Stake(to, uint256(lockupId), newAmount, newEnd, newPoints);
Expand Down Expand Up @@ -267,4 +268,12 @@ contract ExponentialStaking is ERC20Votes {
(uint256 currentPoints,) = previewPoints(1e36, 0); // 1e36 saves a later multiplication
return amount * ((currentPoints / fullPoints)) / 1e18;
}

/// @notice Returns the total number of lockups the user has
/// created so far (including expired & unstaked ones)
/// @param user Address
/// @return asset Number of lockups the user has had
function lockupsCount(address user) external view returns (uint256) {
return lockups[user].length;
}
}
68 changes: 54 additions & 14 deletions tests/staking/ExponentialStaking.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ contract ExponentialStakingTest is Test {

uint256 beforeOgv = ogn.balanceOf(alice);
uint256 beforexOGN = ogn.balanceOf(address(staking));
assertEq(staking.lockupsCount(alice), 0);

staking.stake(10 ether, 10 days, alice, false, NEW_STAKE);

assertEq(staking.lockupsCount(alice), 1);
assertEq(ogn.balanceOf(alice), beforeOgv - 10 ether);
assertEq(ogn.balanceOf(address(staking)), beforexOGN + 10 ether);
assertEq(staking.balanceOf(alice), previewPoints);
Expand All @@ -77,6 +79,7 @@ contract ExponentialStakingTest is Test {
vm.warp(31 days);
staking.unstake(0);

assertEq(staking.lockupsCount(alice), 1);
assertEq(ogn.balanceOf(alice), beforeOgv);
assertEq(ogn.balanceOf(address(staking)), 0);
(lockupAmount, lockupEnd, lockupPoints) = staking.lockups(alice, 0);
Expand Down Expand Up @@ -158,6 +161,39 @@ contract ExponentialStakingTest is Test {
assertEq(staking.accRewardPerShare(), staking.rewardDebtPerShare(bob));
}

function testExtendOnOtherUser() public {
vm.prank(alice);
staking.stake(1 ether, 60 days, alice, false, NEW_STAKE);

vm.expectRevert("Staking: Self only");
vm.prank(bob);
staking.stake(1 ether, 60 days, alice, false, 0);

vm.expectRevert("Staking: Self only");
vm.prank(bob);
staking.stake(1 ether, 60 days, alice, true, NEW_STAKE);
}

function testExtendOnClosed() public {
vm.prank(alice);
staking.stake(1 ether, 60 days, alice, false, NEW_STAKE);
vm.prank(alice);
staking.unstake(0);

vm.expectRevert("Staking: Already closed stake");
vm.prank(alice);
staking.stake(1 ether, 80 days, alice, false, 0);
}

function testExtendNoChange() public {
vm.prank(alice);
staking.stake(1 ether, 60 days, alice, false, NEW_STAKE);

vm.expectRevert("Staking: Must have increased amount or duration");
vm.prank(alice);
staking.stake(0, 60 days, alice, false, 0);
}

function testDoubleExtend() public {
vm.warp(EPOCH + 600 days);

Expand Down Expand Up @@ -186,7 +222,7 @@ contract ExponentialStakingTest is Test {

vm.startPrank(bob);
staking.stake(100 ether, 11 days, bob, false, NEW_STAKE);
vm.expectRevert("Staking: New lockup must be longer");
vm.expectRevert("Staking: New lockup must not be shorter");
staking.stake(1 ether, 8 days, bob, false, 0);
}

Expand Down Expand Up @@ -300,13 +336,6 @@ contract ExponentialStakingTest is Test {
}

function testMultipleUnstake() public {
RewardsSource.Slope[] memory slopes = new RewardsSource.Slope[](1);
slopes[0].start = uint64(EPOCH);
slopes[0].ratePerDay = 2 ether;

vm.prank(team);
source.setInflation(slopes);

vm.startPrank(alice);
staking.stake(1 ether, 10 days, alice, false, NEW_STAKE);
vm.warp(EPOCH + 11 days);
Expand All @@ -315,22 +344,29 @@ contract ExponentialStakingTest is Test {
staking.unstake(0);
}

function testUnstakeNeverStaked() public {
vm.startPrank(alice);
vm.expectRevert();
staking.unstake(0);
}

function testEarlyUnstake() public {
vm.startPrank(alice);
vm.warp(EPOCH);
staking.stake(1 ether, 200 days, alice, false, NEW_STAKE);

// console.log("----");
// for(uint256 i = 0; i < 721; i++){
// console.log(i, staking.previewWithdraw(1e18, EPOCH + i * 1 days));
// }
// console.log("----");

vm.warp(EPOCH + 100 days);
uint256 before = ogn.balanceOf(alice);
uint256 beforeCollected = ogn.balanceOf(address(source));
uint256 expectedWithdraw = staking.previewWithdraw(1 ether, EPOCH + 200 days);

staking.unstake(0);

uint256 returnAmount = ogn.balanceOf(alice) - before;
assertEq(returnAmount, 911937178579591520);
assertEq(expectedWithdraw, returnAmount);
uint256 penaltyCollected = ogn.balanceOf(address(source)) - beforeCollected;
assertEq(penaltyCollected, 1 ether - 911937178579591520);
}

function testCollectRewardsOnExpand() public {
Expand Down Expand Up @@ -479,8 +515,12 @@ contract ExponentialStakingTest is Test {
ogn.mint(alice, amountA);
vm.prank(alice);
ogn.approve(address(staking), amountA);
assertEq(staking.balanceOf(alice), 0);
// preview check
(uint256 expectedPoints,) = staking.previewPoints(amountA, durationA);
vm.prank(alice);
staking.stake(amountA, durationA, alice, false, NEW_STAKE);
assertEq(staking.balanceOf(alice), expectedPoints);

vm.prank(bob);
ogn.mint(bob, amountB);
Expand Down

0 comments on commit 50a0021

Please sign in to comment.