2023-09-12 16:37:30 +00:00
|
|
|
// SPDX-License-Identifier: UNLICENSED
|
|
|
|
pragma solidity ^0.8.19;
|
|
|
|
|
2023-10-10 13:44:16 +00:00
|
|
|
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
|
|
|
2024-02-24 19:35:34 +00:00
|
|
|
import { Test, console } from "forge-std/Test.sol";
|
2023-09-12 16:37:30 +00:00
|
|
|
import { Deploy } from "../script/Deploy.s.sol";
|
2024-02-28 12:46:50 +00:00
|
|
|
import { DeployMigrationStakeManager } from "../script/DeployMigrationStakeManager.s.sol";
|
2023-09-12 16:37:30 +00:00
|
|
|
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
|
|
|
import { StakeManager } from "../contracts/StakeManager.sol";
|
2023-10-10 13:44:16 +00:00
|
|
|
import { StakeVault } from "../contracts/StakeVault.sol";
|
2023-11-07 08:49:22 +00:00
|
|
|
import { VaultFactory } from "../contracts/VaultFactory.sol";
|
2023-09-12 16:37:30 +00:00
|
|
|
|
|
|
|
contract StakeManagerTest is Test {
|
|
|
|
DeploymentConfig internal deploymentConfig;
|
|
|
|
StakeManager internal stakeManager;
|
2023-11-07 08:49:22 +00:00
|
|
|
VaultFactory internal vaultFactory;
|
2023-09-12 16:37:30 +00:00
|
|
|
|
2023-10-10 11:53:03 +00:00
|
|
|
address internal stakeToken;
|
|
|
|
address internal deployer;
|
2023-10-10 13:44:16 +00:00
|
|
|
address internal testUser = makeAddr("testUser");
|
2024-01-12 12:07:31 +00:00
|
|
|
address internal testUser2 = makeAddr("testUser2");
|
2023-10-10 11:53:03 +00:00
|
|
|
|
2023-09-12 16:37:30 +00:00
|
|
|
function setUp() public virtual {
|
|
|
|
Deploy deployment = new Deploy();
|
2023-11-07 08:49:22 +00:00
|
|
|
(vaultFactory, stakeManager, deploymentConfig) = deployment.run();
|
2023-10-10 11:53:03 +00:00
|
|
|
(deployer, stakeToken) = deploymentConfig.activeNetworkConfig();
|
2023-09-12 16:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function testDeployment() public {
|
|
|
|
assertEq(stakeManager.owner(), deployer);
|
2023-10-10 11:53:03 +00:00
|
|
|
assertEq(stakeManager.currentEpoch(), 0);
|
|
|
|
assertEq(stakeManager.pendingReward(), 0);
|
2024-02-18 21:37:15 +00:00
|
|
|
assertEq(stakeManager.totalSupplyMP(), 0);
|
|
|
|
assertEq(stakeManager.totalSupplyBalance(), 0);
|
2023-10-10 11:53:03 +00:00
|
|
|
assertEq(address(stakeManager.stakedToken()), stakeToken);
|
|
|
|
assertEq(address(stakeManager.oldManager()), address(0));
|
2023-09-12 16:37:30 +00:00
|
|
|
assertEq(stakeManager.totalSupply(), 0);
|
|
|
|
}
|
2023-10-10 13:44:16 +00:00
|
|
|
|
|
|
|
function _createTestVault(address owner) internal returns (StakeVault vault) {
|
|
|
|
vm.prank(owner);
|
2023-11-07 08:49:22 +00:00
|
|
|
vault = vaultFactory.createVault();
|
2023-10-10 13:44:16 +00:00
|
|
|
|
2024-01-12 12:07:31 +00:00
|
|
|
if (!stakeManager.isVault(address(vault).codehash)) {
|
|
|
|
vm.prank(deployer);
|
|
|
|
stakeManager.setVault(address(vault).codehash);
|
|
|
|
}
|
2023-10-10 13:44:16 +00:00
|
|
|
}
|
2024-02-28 03:03:35 +00:00
|
|
|
|
|
|
|
function _createStakingAccount(address owner, uint256 amount) internal returns (StakeVault userVault) {
|
|
|
|
return _createStakingAccount(owner, amount, 0, amount);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _createStakingAccount(
|
|
|
|
address owner,
|
|
|
|
uint256 amount,
|
|
|
|
uint256 lockTime
|
|
|
|
)
|
|
|
|
internal
|
|
|
|
returns (StakeVault userVault)
|
|
|
|
{
|
|
|
|
return _createStakingAccount(owner, amount, lockTime, amount);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _createStakingAccount(
|
|
|
|
address owner,
|
|
|
|
uint256 amount,
|
|
|
|
uint256 lockTime,
|
|
|
|
uint256 mintAmount
|
|
|
|
)
|
|
|
|
internal
|
|
|
|
returns (StakeVault userVault)
|
|
|
|
{
|
|
|
|
deal(stakeToken, owner, mintAmount);
|
|
|
|
userVault = _createTestVault(owner);
|
|
|
|
vm.startPrank(owner);
|
2024-03-01 22:19:45 +00:00
|
|
|
ERC20(stakeToken).approve(address(userVault), mintAmount);
|
2024-02-28 03:03:35 +00:00
|
|
|
userVault.stake(amount, lockTime);
|
|
|
|
vm.stopPrank();
|
|
|
|
}
|
2023-09-12 16:37:30 +00:00
|
|
|
}
|
2023-10-10 13:32:46 +00:00
|
|
|
|
|
|
|
contract StakeTest is StakeManagerTest {
|
|
|
|
function test_RevertWhen_SenderIsNotVault() public {
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__SenderIsNotVault.selector);
|
|
|
|
stakeManager.stake(100, 1);
|
|
|
|
}
|
2023-12-06 11:10:07 +00:00
|
|
|
|
|
|
|
function test_RevertWhen_InvalidLockupPeriod() public {
|
|
|
|
// ensure user has funds
|
|
|
|
deal(stakeToken, testUser, 1000);
|
|
|
|
StakeVault userVault = _createTestVault(testUser);
|
|
|
|
|
|
|
|
vm.startPrank(testUser);
|
|
|
|
ERC20(stakeToken).approve(address(userVault), 100);
|
|
|
|
|
|
|
|
uint256 lockTime = stakeManager.MIN_LOCKUP_PERIOD() - 1;
|
2024-03-04 15:27:40 +00:00
|
|
|
vm.expectRevert(StakeManager.StakeManager__InvalidLockTime.selector);
|
2023-12-06 11:10:07 +00:00
|
|
|
userVault.stake(100, lockTime);
|
|
|
|
|
|
|
|
lockTime = stakeManager.MAX_LOCKUP_PERIOD() + 1;
|
2024-03-04 15:27:40 +00:00
|
|
|
vm.expectRevert(StakeManager.StakeManager__InvalidLockTime.selector);
|
2023-12-06 11:10:07 +00:00
|
|
|
userVault.stake(100, lockTime);
|
|
|
|
}
|
2024-01-12 12:07:31 +00:00
|
|
|
|
|
|
|
function test_StakeWithoutLockUpTimeMintsMultiplierPoints() public {
|
2024-02-28 03:03:35 +00:00
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, 0, stakeAmount * 10);
|
2024-01-12 12:07:31 +00:00
|
|
|
|
2024-02-18 21:37:15 +00:00
|
|
|
(,, uint256 currentMP,,,,) = stakeManager.accounts(address(userVault));
|
2024-02-28 03:03:35 +00:00
|
|
|
assertEq(stakeManager.totalSupplyMP(), stakeAmount, "total multiplier point supply");
|
|
|
|
assertEq(currentMP, stakeAmount, "user multiplier points");
|
2024-01-12 12:07:31 +00:00
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
vm.prank(testUser);
|
|
|
|
userVault.unstake(stakeAmount);
|
2024-01-12 12:07:31 +00:00
|
|
|
|
2024-02-18 21:37:15 +00:00
|
|
|
(,,, currentMP,,,) = stakeManager.accounts(address(userVault));
|
2024-02-28 03:03:35 +00:00
|
|
|
assertEq(stakeManager.totalSupplyMP(), 0, "totalSupplyMP burned after unstaking");
|
|
|
|
assertEq(currentMP, 0, "userMP burned after unstaking");
|
2024-01-12 12:07:31 +00:00
|
|
|
}
|
2024-02-28 03:03:35 +00:00
|
|
|
|
2024-03-01 22:19:45 +00:00
|
|
|
function test_restakeJustStake() public {
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 stakeAmount2 = 50;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, 0, mintAmount);
|
|
|
|
StakeVault userVault2 =
|
|
|
|
_createStakingAccount(testUser2, stakeAmount, stakeManager.MIN_LOCKUP_PERIOD(), mintAmount);
|
|
|
|
|
|
|
|
vm.prank(testUser);
|
|
|
|
userVault.stake(stakeAmount2, 0);
|
|
|
|
vm.prank(testUser2);
|
|
|
|
userVault2.stake(stakeAmount2, 0);
|
|
|
|
|
|
|
|
(, uint256 balance,, uint256 currentMP,,,) = stakeManager.accounts(address(userVault));
|
|
|
|
assertEq(balance, stakeAmount + stakeAmount2, "account balance");
|
|
|
|
assertEq(currentMP, stakeAmount + stakeAmount2, "account MP");
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault2));
|
|
|
|
assertEq(balance, stakeAmount + stakeAmount2, "account 2 balance");
|
|
|
|
assertGt(currentMP, stakeAmount + stakeAmount2, "account 2 MP");
|
|
|
|
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
|
|
|
|
vm.prank(testUser);
|
|
|
|
userVault.stake(stakeAmount2, 0);
|
|
|
|
vm.prank(testUser2);
|
|
|
|
userVault2.stake(stakeAmount2, 0);
|
|
|
|
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault));
|
|
|
|
assertEq(balance, stakeAmount + stakeAmount2 + stakeAmount2, "account balance 2");
|
|
|
|
assertGt(currentMP, stakeAmount + stakeAmount2 + stakeAmount2, "account MP 2");
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault2));
|
|
|
|
assertEq(balance, stakeAmount + stakeAmount2 + stakeAmount2, "account 2 balance 2");
|
|
|
|
assertGt(currentMP, stakeAmount + stakeAmount2 + stakeAmount2, "account 2 MP 2");
|
|
|
|
}
|
|
|
|
|
|
|
|
function test_restakeJustLock() public {
|
|
|
|
uint256 lockToIncrease = stakeManager.MIN_LOCKUP_PERIOD();
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 stakeAmount2 = 50;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, 0, mintAmount);
|
|
|
|
StakeVault userVault2 = _createStakingAccount(testUser2, stakeAmount, lockToIncrease, mintAmount);
|
|
|
|
vm.prank(testUser);
|
|
|
|
userVault.stake(0, lockToIncrease);
|
|
|
|
vm.prank(testUser2);
|
|
|
|
userVault2.stake(0, lockToIncrease);
|
2024-02-28 03:03:35 +00:00
|
|
|
|
2024-03-01 22:19:45 +00:00
|
|
|
(, uint256 balance,, uint256 currentMP,,,) = stakeManager.accounts(address(userVault));
|
|
|
|
assertEq(balance, stakeAmount, "account balance");
|
|
|
|
assertGt(currentMP, stakeAmount, "account MP");
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault2));
|
|
|
|
assertEq(balance, stakeAmount, "account 2 balance");
|
|
|
|
assertGt(currentMP, stakeAmount, "account 2 MP");
|
2024-02-28 03:03:35 +00:00
|
|
|
|
2024-03-01 22:19:45 +00:00
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
|
|
|
|
vm.prank(testUser);
|
|
|
|
userVault.stake(0, lockToIncrease);
|
|
|
|
vm.prank(testUser2);
|
|
|
|
userVault2.stake(0, lockToIncrease);
|
|
|
|
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault));
|
|
|
|
assertEq(balance, stakeAmount, "account balance 2");
|
|
|
|
assertGt(currentMP, stakeAmount, "account MP 2");
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault2));
|
|
|
|
assertEq(balance, stakeAmount, "account 2 balance 2");
|
|
|
|
assertGt(currentMP, stakeAmount, "account 2 MP 2");
|
|
|
|
}
|
|
|
|
|
|
|
|
function test_restakeStakeAndLock() public {
|
|
|
|
uint256 lockToIncrease = stakeManager.MIN_LOCKUP_PERIOD();
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 stakeAmount2 = 50;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, 0, mintAmount);
|
|
|
|
StakeVault userVault2 = _createStakingAccount(testUser2, stakeAmount, lockToIncrease, mintAmount);
|
|
|
|
|
|
|
|
vm.prank(testUser);
|
|
|
|
userVault.stake(stakeAmount2, lockToIncrease);
|
|
|
|
vm.prank(testUser2);
|
|
|
|
userVault2.stake(stakeAmount2, lockToIncrease);
|
|
|
|
|
|
|
|
(, uint256 balance,, uint256 currentMP,,,) = stakeManager.accounts(address(userVault));
|
|
|
|
assertEq(balance, stakeAmount + stakeAmount2, "account balance");
|
|
|
|
assertGt(currentMP, stakeAmount + stakeAmount2, "account MP");
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault2));
|
|
|
|
assertEq(balance, stakeAmount + stakeAmount2, "account 2 balance");
|
|
|
|
assertGt(currentMP, stakeAmount + stakeAmount2, "account 2 MP");
|
|
|
|
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
|
|
|
|
vm.prank(testUser);
|
|
|
|
userVault.stake(stakeAmount2, lockToIncrease);
|
|
|
|
vm.prank(testUser2);
|
|
|
|
userVault2.stake(stakeAmount2, lockToIncrease);
|
|
|
|
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault));
|
|
|
|
assertEq(balance, stakeAmount + stakeAmount2 + stakeAmount2, "account balance 2");
|
|
|
|
assertGt(currentMP, stakeAmount + stakeAmount2 + stakeAmount2, "account MP 2");
|
|
|
|
(, balance,, currentMP,,,) = stakeManager.accounts(address(userVault2));
|
|
|
|
assertEq(balance, stakeAmount + stakeAmount2 + stakeAmount2, "account 2 balance 2");
|
|
|
|
assertGt(currentMP, stakeAmount + stakeAmount2 + stakeAmount2, "account 2 MP 2");
|
|
|
|
}
|
2023-10-10 13:32:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
contract UnstakeTest is StakeManagerTest {
|
|
|
|
function test_RevertWhen_SenderIsNotVault() public {
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__SenderIsNotVault.selector);
|
2024-02-18 21:37:15 +00:00
|
|
|
stakeManager.unstake(1);
|
2023-10-10 13:32:46 +00:00
|
|
|
}
|
2023-10-10 13:44:16 +00:00
|
|
|
|
|
|
|
function test_RevertWhen_FundsLocked() public {
|
2023-12-06 11:10:07 +00:00
|
|
|
uint256 lockTime = stakeManager.MIN_LOCKUP_PERIOD();
|
2024-02-28 03:03:35 +00:00
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockTime, mintAmount);
|
2023-10-10 13:44:16 +00:00
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
vm.prank(testUser);
|
2023-10-10 13:44:16 +00:00
|
|
|
vm.expectRevert(StakeManager.StakeManager__FundsLocked.selector);
|
2024-02-18 21:37:15 +00:00
|
|
|
userVault.unstake(1);
|
2024-02-28 03:03:35 +00:00
|
|
|
|
|
|
|
vm.prank(testUser);
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__FundsLocked.selector);
|
|
|
|
userVault.unstake(stakeAmount);
|
2023-10-10 13:44:16 +00:00
|
|
|
}
|
2024-01-11 13:54:39 +00:00
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
function test_UnstakeShouldReturnFund_NoLockUp() public {
|
|
|
|
uint256 lockTime = 0;
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockTime, mintAmount);
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(testUser), 900);
|
2024-01-11 13:54:39 +00:00
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
vm.prank(testUser);
|
|
|
|
userVault.unstake(100);
|
|
|
|
|
|
|
|
assertEq(stakeManager.totalSupplyBalance(), 0);
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(address(userVault)), 0);
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(testUser), 1000);
|
|
|
|
}
|
2024-01-11 13:54:39 +00:00
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
function test_UnstakeShouldReturnFund_WithLockUp() public {
|
|
|
|
uint256 lockTime = stakeManager.MIN_LOCKUP_PERIOD();
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockTime, mintAmount);
|
2024-01-11 13:54:39 +00:00
|
|
|
assertEq(ERC20(stakeToken).balanceOf(testUser), 900);
|
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
vm.warp(block.timestamp + lockTime + 1);
|
|
|
|
|
|
|
|
vm.prank(testUser);
|
2024-01-11 13:54:39 +00:00
|
|
|
userVault.unstake(100);
|
|
|
|
|
2024-02-18 21:37:15 +00:00
|
|
|
assertEq(stakeManager.totalSupplyBalance(), 0);
|
2024-01-11 13:54:39 +00:00
|
|
|
assertEq(ERC20(stakeToken).balanceOf(address(userVault)), 0);
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(testUser), 1000);
|
|
|
|
}
|
2024-02-24 19:35:34 +00:00
|
|
|
|
|
|
|
function test_UnstakeShouldBurnMultiplierPoints() public {
|
|
|
|
uint256 percentToBurn = 90;
|
2024-02-28 03:03:35 +00:00
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount);
|
2024-02-24 19:35:34 +00:00
|
|
|
|
|
|
|
vm.startPrank(testUser);
|
|
|
|
|
|
|
|
assertEq(stakeManager.totalSupplyMP(), stakeAmount);
|
|
|
|
for (uint256 i = 0; i < 53; i++) {
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
stakeManager.executeAccount(address(userVault), i + 1);
|
|
|
|
}
|
|
|
|
(, uint256 balanceBefore, uint256 initialMPBefore, uint256 currentMPBefore,,,) =
|
|
|
|
stakeManager.accounts(address(userVault));
|
|
|
|
uint256 totalSupplyMPBefore = stakeManager.totalSupplyMP();
|
|
|
|
uint256 unstakeAmount = stakeAmount * percentToBurn / 100;
|
|
|
|
console.log("unstake", unstakeAmount);
|
|
|
|
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(testUser), 0);
|
|
|
|
userVault.unstake(unstakeAmount);
|
|
|
|
(, uint256 balanceAfter, uint256 initialMPAfter, uint256 currentMPAfter,,,) =
|
|
|
|
stakeManager.accounts(address(userVault));
|
|
|
|
|
|
|
|
uint256 totalSupplyMPAfter = stakeManager.totalSupplyMP();
|
|
|
|
console.log("totalSupplyMPBefore", totalSupplyMPBefore);
|
|
|
|
console.log("totalSupplyMPAfter", totalSupplyMPAfter);
|
|
|
|
console.log("balanceBefore", balanceBefore);
|
|
|
|
console.log("balanceAfter", balanceAfter);
|
|
|
|
console.log("initialMPBefore", initialMPBefore);
|
|
|
|
console.log("initialMPAfter", initialMPAfter);
|
|
|
|
console.log("currentMPBefore", currentMPBefore);
|
|
|
|
console.log("currentMPAfter", currentMPAfter);
|
|
|
|
|
|
|
|
assertEq(balanceAfter, balanceBefore - (balanceBefore * percentToBurn / 100));
|
2024-02-28 03:03:35 +00:00
|
|
|
assertEq(initialMPAfter, initialMPBefore - (initialMPBefore * percentToBurn / 100));
|
|
|
|
assertEq(currentMPAfter, currentMPBefore - (currentMPBefore * percentToBurn / 100));
|
|
|
|
assertEq(totalSupplyMPAfter, totalSupplyMPBefore - (currentMPBefore * percentToBurn / 100));
|
2024-02-24 19:35:34 +00:00
|
|
|
assertEq(ERC20(stakeToken).balanceOf(testUser), unstakeAmount);
|
|
|
|
}
|
2024-03-04 15:11:23 +00:00
|
|
|
|
|
|
|
function test_RevertWhen_AmountMoreThanBalance() public {
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount);
|
|
|
|
vm.startPrank(testUser);
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__InsufficientFunds.selector);
|
|
|
|
userVault.unstake(stakeAmount + 1);
|
|
|
|
}
|
2023-10-10 13:32:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
contract LockTest is StakeManagerTest {
|
|
|
|
function test_RevertWhen_SenderIsNotVault() public {
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__SenderIsNotVault.selector);
|
|
|
|
stakeManager.lock(100);
|
|
|
|
}
|
2023-10-10 13:49:34 +00:00
|
|
|
|
2023-12-06 11:10:07 +00:00
|
|
|
function test_RevertWhen_InvalidLockupPeriod() public {
|
|
|
|
// ensure user has funds
|
|
|
|
deal(stakeToken, testUser, 1000);
|
|
|
|
StakeVault userVault = _createTestVault(testUser);
|
|
|
|
|
|
|
|
vm.startPrank(testUser);
|
|
|
|
// ensure user vault can spend user tokens
|
|
|
|
ERC20(stakeToken).approve(address(userVault), 100);
|
|
|
|
|
|
|
|
uint256 lockTime = stakeManager.MAX_LOCKUP_PERIOD() + 1;
|
2024-03-04 15:27:40 +00:00
|
|
|
vm.expectRevert(StakeManager.StakeManager__InvalidLockTime.selector);
|
2023-12-06 11:10:07 +00:00
|
|
|
userVault.stake(100, lockTime);
|
|
|
|
}
|
2023-10-10 13:32:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
contract LeaveTest is StakeManagerTest {
|
|
|
|
function test_RevertWhen_SenderIsNotVault() public {
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__SenderIsNotVault.selector);
|
2024-01-24 15:07:23 +00:00
|
|
|
stakeManager.migrateTo(false);
|
2023-10-10 13:32:46 +00:00
|
|
|
}
|
2023-10-10 13:49:34 +00:00
|
|
|
|
|
|
|
function test_RevertWhen_NoPendingMigration() public {
|
2024-02-28 03:03:35 +00:00
|
|
|
uint256 lockTime = 0;
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockTime, mintAmount);
|
2024-02-18 21:37:15 +00:00
|
|
|
vm.startPrank(testUser);
|
|
|
|
|
2023-10-10 13:49:34 +00:00
|
|
|
vm.expectRevert(StakeManager.StakeManager__NoPendingMigration.selector);
|
2024-01-24 15:07:23 +00:00
|
|
|
userVault.acceptMigration();
|
2024-02-18 21:37:15 +00:00
|
|
|
|
2024-01-24 15:07:23 +00:00
|
|
|
vm.expectRevert(StakeManager.StakeManager__NoPendingMigration.selector);
|
2023-10-10 13:49:34 +00:00
|
|
|
userVault.leave();
|
2024-02-18 21:37:15 +00:00
|
|
|
vm.stopPrank();
|
2023-10-10 13:49:34 +00:00
|
|
|
}
|
2023-10-10 13:32:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
contract MigrateTest is StakeManagerTest {
|
|
|
|
function test_RevertWhen_SenderIsNotVault() public {
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__SenderIsNotVault.selector);
|
2024-01-24 15:07:23 +00:00
|
|
|
stakeManager.migrateTo(true);
|
2023-10-10 13:32:46 +00:00
|
|
|
}
|
2023-10-10 13:49:34 +00:00
|
|
|
|
|
|
|
function test_RevertWhen_NoPendingMigration() public {
|
2024-02-28 03:03:35 +00:00
|
|
|
uint256 lockTime = 0;
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockTime, mintAmount);
|
2024-02-18 21:37:15 +00:00
|
|
|
vm.startPrank(testUser);
|
|
|
|
|
2023-10-10 13:49:34 +00:00
|
|
|
vm.expectRevert(StakeManager.StakeManager__NoPendingMigration.selector);
|
2024-01-24 15:07:23 +00:00
|
|
|
userVault.acceptMigration();
|
2024-02-18 21:37:15 +00:00
|
|
|
vm.stopPrank();
|
2023-10-10 13:49:34 +00:00
|
|
|
}
|
2024-02-28 03:03:35 +00:00
|
|
|
|
|
|
|
function increaseEpoch(uint256 epochNumber) internal { }
|
2023-10-10 13:49:34 +00:00
|
|
|
}
|
|
|
|
|
2024-03-01 09:56:19 +00:00
|
|
|
contract MigrationInitializeTest is StakeManagerTest {
|
|
|
|
function setUp() public override {
|
|
|
|
StakeManagerTest.setUp();
|
|
|
|
}
|
|
|
|
|
|
|
|
function test_RevertWhen_MigrationPending() public {
|
|
|
|
// first, create 2nd and 3rd generation stake manager
|
|
|
|
vm.startPrank(deployer);
|
|
|
|
StakeManager secondStakeManager = new StakeManager(stakeToken, address(stakeManager));
|
|
|
|
StakeManager thirdStakeManager = new StakeManager(stakeToken, address(secondStakeManager));
|
|
|
|
|
|
|
|
// first, ensure `secondStakeManager` is in migration mode itself
|
|
|
|
secondStakeManager.startMigration(thirdStakeManager);
|
|
|
|
vm.stopPrank();
|
|
|
|
|
|
|
|
uint256 currentEpoch = stakeManager.currentEpoch();
|
|
|
|
uint256 totalMP = stakeManager.totalSupplyMP();
|
|
|
|
uint256 totalBalance = stakeManager.totalSupplyBalance();
|
|
|
|
|
|
|
|
// `stakeManager` calling `migrationInitialize` while the new stake manager is
|
|
|
|
// in migration itself, should revert
|
|
|
|
vm.prank(address(stakeManager));
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__PendingMigration.selector);
|
|
|
|
secondStakeManager.migrationInitialize(currentEpoch, totalMP, totalBalance, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-10 13:49:34 +00:00
|
|
|
contract ExecuteAccountTest is StakeManagerTest {
|
2024-02-24 19:35:34 +00:00
|
|
|
StakeVault[] private userVaults;
|
|
|
|
|
2023-10-10 13:49:34 +00:00
|
|
|
function test_RevertWhen_InvalidLimitEpoch() public {
|
2023-12-06 11:10:07 +00:00
|
|
|
uint256 lockTime = stakeManager.MIN_LOCKUP_PERIOD();
|
2024-02-28 03:03:35 +00:00
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockTime, mintAmount);
|
|
|
|
vm.startPrank(testUser);
|
2023-10-10 13:49:34 +00:00
|
|
|
|
|
|
|
uint256 currentEpoch = stakeManager.currentEpoch();
|
|
|
|
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__InvalidLimitEpoch.selector);
|
|
|
|
stakeManager.executeAccount(address(userVault), currentEpoch + 1);
|
|
|
|
}
|
2024-02-24 19:35:34 +00:00
|
|
|
|
|
|
|
function test_ExecuteAccountMintMP() public {
|
|
|
|
uint256 stakeAmount = 10_000_000;
|
|
|
|
deal(stakeToken, testUser, stakeAmount);
|
|
|
|
|
|
|
|
userVaults.push(_createStakingAccount(makeAddr("testUser"), stakeAmount, 0));
|
|
|
|
userVaults.push(_createStakingAccount(makeAddr("testUser2"), stakeAmount, 0));
|
|
|
|
userVaults.push(_createStakingAccount(makeAddr("testUser3"), stakeAmount, 0));
|
|
|
|
|
|
|
|
console.log("######### NOW", block.timestamp);
|
|
|
|
console.log("# START EPOCH", stakeManager.currentEpoch());
|
|
|
|
console.log("# PND_REWARDS", stakeManager.pendingReward());
|
|
|
|
|
|
|
|
for (uint256 i = 0; i < 3; i++) {
|
|
|
|
deal(stakeToken, address(stakeManager), 100 ether);
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
console.log("######### NOW", block.timestamp);
|
|
|
|
stakeManager.executeEpoch();
|
|
|
|
console.log("##### NEW EPOCH", stakeManager.currentEpoch());
|
|
|
|
console.log("# PND_REWARDS", stakeManager.pendingReward());
|
|
|
|
|
|
|
|
for (uint256 j = 0; j < userVaults.length; j++) {
|
|
|
|
(address rewardAddress,,, uint256 currentMPBefore, uint256 lastMintBefore,, uint256 epochBefore) =
|
|
|
|
stakeManager.accounts(address(userVaults[j]));
|
|
|
|
uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress);
|
|
|
|
console.log("-Vault number", j);
|
|
|
|
console.log("--=====BEFORE=====");
|
|
|
|
console.log("---### currentMP :", currentMPBefore);
|
|
|
|
console.log("---#### lastMint :", lastMintBefore);
|
|
|
|
console.log("---## user_epoch :", epochBefore);
|
|
|
|
console.log("---##### rewards :", rewardsBefore);
|
|
|
|
console.log("--=====AFTER======");
|
|
|
|
stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1);
|
|
|
|
(,,, uint256 currentMP, uint256 lastMint,, uint256 epoch) =
|
|
|
|
stakeManager.accounts(address(userVaults[j]));
|
|
|
|
uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress);
|
|
|
|
console.log("---### deltaTime :", lastMint - lastMintBefore);
|
|
|
|
console.log("---### currentMP :", currentMP);
|
|
|
|
console.log("---#### lastMint :", lastMint);
|
|
|
|
console.log("---## user_epoch :", epoch);
|
|
|
|
console.log("---##### rewards :", rewards);
|
|
|
|
console.log("--=======#=======");
|
|
|
|
console.log("--# TOTAL_SUPPLY", stakeManager.totalSupply());
|
|
|
|
console.log("--# PND_REWARDS", stakeManager.pendingReward());
|
|
|
|
assertEq(lastMint, lastMintBefore + stakeManager.EPOCH_SIZE(), "must increaase lastMint");
|
|
|
|
assertEq(epoch, epochBefore + 1, "must increase epoch");
|
|
|
|
assertGt(currentMP, currentMPBefore, "must increase MPs");
|
|
|
|
assertGt(rewards, rewardsBefore, "must increase rewards");
|
|
|
|
lastMintBefore = lastMint;
|
|
|
|
epochBefore = epoch;
|
|
|
|
currentMPBefore = currentMP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-28 03:03:35 +00:00
|
|
|
|
2024-03-04 13:47:09 +00:00
|
|
|
function test_ShouldNotMintMoreThanCap() public {
|
|
|
|
uint256 stakeAmount = 10_000_000;
|
|
|
|
deal(stakeToken, testUser, stakeAmount);
|
|
|
|
|
|
|
|
userVaults.push(_createStakingAccount(makeAddr("testUser"), stakeAmount, 0));
|
|
|
|
userVaults.push(_createStakingAccount(makeAddr("testUser2"), stakeAmount, stakeManager.MAX_LOCKUP_PERIOD()));
|
|
|
|
userVaults.push(_createStakingAccount(makeAddr("testUser3"), stakeAmount, stakeManager.MIN_LOCKUP_PERIOD()));
|
|
|
|
|
|
|
|
for (uint256 i = 0; i < 209; i++) {
|
|
|
|
deal(stakeToken, address(stakeManager), 100 ether);
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
stakeManager.executeEpoch();
|
|
|
|
for (uint256 j = 0; j < userVaults.length; j++) {
|
|
|
|
(address rewardAddress,,, uint256 currentMPBefore, uint256 lastMintBefore,, uint256 epochBefore) =
|
|
|
|
stakeManager.accounts(address(userVaults[j]));
|
|
|
|
uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress);
|
|
|
|
|
|
|
|
stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1);
|
|
|
|
(,,, uint256 currentMP, uint256 lastMint,, uint256 epoch) =
|
|
|
|
stakeManager.accounts(address(userVaults[j]));
|
|
|
|
uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress);
|
|
|
|
assertEq(lastMint, lastMintBefore + stakeManager.EPOCH_SIZE(), "must increaase lastMint");
|
|
|
|
assertEq(epoch, epochBefore + 1, "must increase epoch");
|
|
|
|
assertGt(currentMP, currentMPBefore, "must increase MPs");
|
|
|
|
assertGt(rewards, rewardsBefore, "must increase rewards");
|
|
|
|
lastMintBefore = lastMint;
|
|
|
|
epochBefore = epoch;
|
|
|
|
currentMPBefore = currentMP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint256 i = 0; i < 100; i++) {
|
|
|
|
deal(stakeToken, address(stakeManager), 100 ether);
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
stakeManager.executeEpoch();
|
|
|
|
for (uint256 j = 0; j < userVaults.length; j++) {
|
|
|
|
(address rewardAddress,,, uint256 currentMPBefore, uint256 lastMintBefore,, uint256 epochBefore) =
|
|
|
|
stakeManager.accounts(address(userVaults[j]));
|
|
|
|
uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress);
|
|
|
|
|
|
|
|
stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1);
|
|
|
|
(,,, uint256 currentMP, uint256 lastMint,, uint256 epoch) =
|
|
|
|
stakeManager.accounts(address(userVaults[j]));
|
|
|
|
uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress);
|
|
|
|
assertEq(lastMint, lastMintBefore + stakeManager.EPOCH_SIZE(), "must increaase lastMint");
|
|
|
|
assertEq(epoch, epochBefore + 1, "must increase epoch");
|
|
|
|
assertEq(currentMP, currentMPBefore, "must NOT increase MPs");
|
|
|
|
assertGt(rewards, rewardsBefore, "must increase rewards");
|
|
|
|
lastMintBefore = lastMint;
|
|
|
|
epochBefore = epoch;
|
|
|
|
currentMPBefore = currentMP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-28 03:03:35 +00:00
|
|
|
|
|
|
|
function internal_logAccount(address vault) internal {
|
|
|
|
(
|
|
|
|
address rewardAddress,
|
|
|
|
uint256 balance,
|
|
|
|
uint256 initialMP,
|
|
|
|
uint256 currentMP,
|
|
|
|
uint256 lastMint,
|
|
|
|
uint256 lockUntil,
|
|
|
|
uint256 epoch
|
|
|
|
) = stakeManager.accounts(vault);
|
|
|
|
console.log("===============");
|
|
|
|
console.log("rewardAddress :", rewardAddress);
|
|
|
|
console.log("##### balance :", balance);
|
|
|
|
console.log("### initialMP :", initialMP);
|
|
|
|
console.log("### currentMP :", currentMP);
|
|
|
|
console.log("#### lastMint :", lastMint);
|
|
|
|
console.log("### lockUntil :", lockUntil);
|
|
|
|
console.log("####### epoch :", epoch);
|
|
|
|
console.log("===============");
|
|
|
|
}
|
|
|
|
|
|
|
|
function test_UpdateEpoch() public { }
|
|
|
|
function test_PayRewards() public { }
|
|
|
|
|
|
|
|
function test_MintMPLimit() public { }
|
2023-10-10 13:32:46 +00:00
|
|
|
}
|
2024-01-12 12:07:31 +00:00
|
|
|
|
|
|
|
contract UserFlowsTest is StakeManagerTest {
|
|
|
|
function test_StakedSupplyShouldIncreaseAndDecreaseAgain() public {
|
2024-02-28 03:03:35 +00:00
|
|
|
uint256 lockTime = 0;
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
2024-01-12 12:07:31 +00:00
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockTime, mintAmount);
|
|
|
|
StakeVault user2Vault = _createStakingAccount(testUser2, stakeAmount, lockTime, mintAmount);
|
2024-01-12 12:07:31 +00:00
|
|
|
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(address(userVault)), 100);
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(address(user2Vault)), 100);
|
2024-02-18 21:37:15 +00:00
|
|
|
assertEq(stakeManager.totalSupplyBalance(), 200);
|
2024-01-12 12:07:31 +00:00
|
|
|
|
|
|
|
vm.startPrank(testUser);
|
|
|
|
userVault.unstake(100);
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(address(userVault)), 0);
|
2024-02-18 21:37:15 +00:00
|
|
|
assertEq(stakeManager.totalSupplyBalance(), 100);
|
2024-01-12 12:07:31 +00:00
|
|
|
|
|
|
|
vm.startPrank(testUser2);
|
|
|
|
user2Vault.unstake(100);
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(address(user2Vault)), 0);
|
2024-02-18 21:37:15 +00:00
|
|
|
assertEq(stakeManager.totalSupplyBalance(), 0);
|
2024-01-12 12:07:31 +00:00
|
|
|
}
|
2024-01-12 12:36:13 +00:00
|
|
|
|
|
|
|
function test_StakeWithLockUpTimeLocksStake() public {
|
2024-02-28 03:03:35 +00:00
|
|
|
uint256 lockTime = stakeManager.MIN_LOCKUP_PERIOD();
|
|
|
|
uint256 stakeAmount = 100;
|
|
|
|
uint256 mintAmount = stakeAmount * 10;
|
|
|
|
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockTime, mintAmount);
|
2024-01-12 12:36:13 +00:00
|
|
|
vm.startPrank(testUser);
|
|
|
|
|
|
|
|
// unstaking should fail as lockup time isn't over yet
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__FundsLocked.selector);
|
|
|
|
userVault.unstake(100);
|
|
|
|
|
|
|
|
// fast forward 12 weeks
|
2024-02-28 03:03:35 +00:00
|
|
|
skip(lockTime + 1);
|
2024-01-12 12:36:13 +00:00
|
|
|
|
|
|
|
userVault.unstake(100);
|
|
|
|
assertEq(ERC20(stakeToken).balanceOf(address(userVault)), 0);
|
2024-02-18 21:37:15 +00:00
|
|
|
assertEq(stakeManager.totalSupplyBalance(), 0);
|
2024-01-12 12:36:13 +00:00
|
|
|
}
|
2024-01-12 12:07:31 +00:00
|
|
|
}
|
2024-02-28 12:46:50 +00:00
|
|
|
|
2024-03-04 14:50:41 +00:00
|
|
|
contract MigrationStakeManagerTest is StakeManagerTest {
|
2024-02-28 12:46:50 +00:00
|
|
|
StakeManager internal newStakeManager;
|
|
|
|
|
|
|
|
function setUp() public virtual override {
|
|
|
|
super.setUp();
|
|
|
|
DeployMigrationStakeManager deployment = new DeployMigrationStakeManager(address(stakeManager), stakeToken);
|
|
|
|
newStakeManager = deployment.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
function testNewDeployment() public {
|
|
|
|
assertEq(newStakeManager.owner(), deployer);
|
|
|
|
assertEq(newStakeManager.currentEpoch(), 0);
|
|
|
|
assertEq(newStakeManager.pendingReward(), 0);
|
|
|
|
assertEq(newStakeManager.totalSupplyMP(), 0);
|
|
|
|
assertEq(newStakeManager.totalSupplyBalance(), 0);
|
|
|
|
assertEq(address(newStakeManager.stakedToken()), stakeToken);
|
|
|
|
assertEq(address(newStakeManager.oldManager()), address(stakeManager));
|
|
|
|
assertEq(newStakeManager.totalSupply(), 0);
|
|
|
|
}
|
2024-02-28 03:03:35 +00:00
|
|
|
|
|
|
|
function test_ExecuteEpochShouldNotIncreaseEpochInMigration() public {
|
|
|
|
assertEq(stakeManager.currentEpoch(), 0);
|
|
|
|
assertEq(address(stakeManager.migration()), address(0));
|
|
|
|
vm.prank(deployer);
|
2024-03-04 14:53:44 +00:00
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
stakeManager.startMigration(newStakeManager);
|
|
|
|
assertEq(address(stakeManager.migration()), address(newStakeManager));
|
|
|
|
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
vm.expectRevert(StakeManager.StakeManager__PendingMigration.selector);
|
|
|
|
stakeManager.executeEpoch();
|
|
|
|
assertEq(stakeManager.currentEpoch(), 0);
|
|
|
|
}
|
2024-03-04 14:53:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
contract ExecuteEpochTest is MigrationStakeManagerTest {
|
|
|
|
//currentEpoch can only increase if time stakeManager.epochEnd().
|
|
|
|
function test_ExecuteEpochShouldNotIncreaseEpochBeforeEnd() public {
|
|
|
|
assertEq(stakeManager.currentEpoch(), 0);
|
2024-02-28 03:03:35 +00:00
|
|
|
|
2024-03-04 14:53:44 +00:00
|
|
|
vm.warp(stakeManager.epochEnd() - 1);
|
|
|
|
stakeManager.executeEpoch();
|
|
|
|
assertEq(stakeManager.currentEpoch(), 0);
|
|
|
|
}
|
2024-02-28 03:03:35 +00:00
|
|
|
//currentEpoch can only increase.
|
2024-03-04 14:53:44 +00:00
|
|
|
|
2024-02-28 03:03:35 +00:00
|
|
|
function test_ExecuteEpochShouldIncreaseEpoch() public {
|
|
|
|
assertEq(stakeManager.currentEpoch(), 0);
|
|
|
|
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
stakeManager.executeEpoch();
|
|
|
|
assertEq(stakeManager.currentEpoch(), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//invariant: stakeManager balanceOf stakeToken > pendingReward
|
|
|
|
function test_ExecuteEpochShouldIncreasePendingReward() public {
|
|
|
|
assertEq(stakeManager.pendingReward(), 0);
|
|
|
|
assertEq(stakeManager.epochReward(), 0);
|
|
|
|
deal(stakeToken, address(stakeManager), 1);
|
|
|
|
assertEq(stakeManager.pendingReward(), 0);
|
|
|
|
assertEq(stakeManager.epochReward(), 1);
|
|
|
|
vm.warp(stakeManager.epochEnd());
|
|
|
|
stakeManager.executeEpoch();
|
|
|
|
assertEq(stakeManager.pendingReward(), 1);
|
|
|
|
assertEq(stakeManager.epochReward(), 0);
|
|
|
|
}
|
|
|
|
}
|