mirror of https://github.com/logos-co/staking.git
WIP
This commit is contained in:
parent
4a04b46e14
commit
2b33c994fa
|
@ -2,6 +2,7 @@
|
|||
|
||||
pragma solidity ^0.8.18;
|
||||
|
||||
import { console } from "forge-std/console.sol";
|
||||
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
|
||||
|
@ -43,6 +44,8 @@ contract StakeManager is Ownable {
|
|||
uint256 public constant MAX_LOCKUP_PERIOD = 4 * YEAR; // 4 years
|
||||
uint256 public constant MP_APY = 1;
|
||||
uint256 public constant MAX_BOOST = 4;
|
||||
uint256 public constant DEPOSIT_COOLDOWN_PERIOD = 2 weeks;
|
||||
uint256 public constant WITHDRAW_COOLDOWN_PERIOD = 2 weeks;
|
||||
|
||||
mapping(address index => Account value) public accounts;
|
||||
mapping(uint256 index => Epoch value) public epochs;
|
||||
|
@ -108,12 +111,22 @@ contract StakeManager is Ownable {
|
|||
*/
|
||||
modifier finalizeEpoch() {
|
||||
if (block.timestamp >= epochEnd() && address(migration) == address(0)) {
|
||||
console.log("Processing epoch...");
|
||||
console.log("--- currentEpoch: ", currentEpoch);
|
||||
|
||||
uint256 _epochReward = epochReward();
|
||||
console.log("--- epochReward: ", _epochReward);
|
||||
//finalize current epoch
|
||||
epochs[currentEpoch].epochReward = epochReward();
|
||||
epochs[currentEpoch].epochReward = _epochReward;
|
||||
epochs[currentEpoch].totalSupply = totalSupply();
|
||||
pendingReward += epochs[currentEpoch].epochReward;
|
||||
|
||||
console.log("--- totalSupply: ", totalSupply());
|
||||
console.log("--- pendingReward: ", pendingReward);
|
||||
//create new epoch
|
||||
currentEpoch++;
|
||||
console.log("Done. New epoch started: ", currentEpoch);
|
||||
console.log("\n");
|
||||
epochs[currentEpoch].startTime = block.timestamp;
|
||||
}
|
||||
_;
|
||||
|
@ -133,6 +146,7 @@ contract StakeManager is Ownable {
|
|||
* @dev Reverts when resulting locked time is not in range of [MIN_LOCKUP_PERIOD, MAX_LOCKUP_PERIOD]
|
||||
*/
|
||||
function stake(uint256 _amount, uint256 _timeToIncrease) external onlyVault noPendingMigration finalizeEpoch {
|
||||
console.log("--- Staking: ", _amount);
|
||||
Account storage account = accounts[msg.sender];
|
||||
|
||||
if (account.lockUntil == 0) {
|
||||
|
@ -248,6 +262,7 @@ contract StakeManager is Ownable {
|
|||
onlyAccountInitialized(_vault)
|
||||
finalizeEpoch
|
||||
{
|
||||
console.log("Processing account: ", _vault);
|
||||
_processAccount(accounts[_vault], _limitEpoch);
|
||||
}
|
||||
|
||||
|
@ -367,14 +382,30 @@ contract StakeManager is Ownable {
|
|||
uint256 userEpoch = account.epoch;
|
||||
uint256 mpDifference = account.totalMP;
|
||||
for (Epoch storage iEpoch = epochs[userEpoch]; userEpoch < _limitEpoch; userEpoch++) {
|
||||
console.log("--- processing account epoch: ", userEpoch);
|
||||
uint256 userSupply = account.balance + account.totalMP;
|
||||
console.log("--- userSupply in epoch (before): ", userSupply);
|
||||
console.log("------ account.balance: ", account.balance);
|
||||
console.log("------ account.totalMP: ", account.totalMP);
|
||||
console.log("--- epoch totalSupply (before): ", iEpoch.totalSupply);
|
||||
console.log("------ Minting multiplier points for epoch...");
|
||||
//mint multiplier points to that epoch
|
||||
_mintMP(account, iEpoch.startTime + EPOCH_SIZE, iEpoch);
|
||||
uint256 userSupply = account.balance + account.totalMP;
|
||||
userSupply = account.balance + account.totalMP;
|
||||
console.log("--- userSupply in epoch (after): ", userSupply);
|
||||
console.log("------ account.balance: ", account.balance);
|
||||
console.log("------ account.totalMP: ", account.totalMP);
|
||||
console.log("--- epoch totalSupply (after): ", iEpoch.totalSupply);
|
||||
uint256 userEpochReward = Math.mulDiv(userSupply, iEpoch.epochReward, iEpoch.totalSupply);
|
||||
console.log("--- userEpochReward: ", userEpochReward);
|
||||
|
||||
userReward += userEpochReward;
|
||||
iEpoch.epochReward -= userEpochReward;
|
||||
console.log("--- removing epoch userSupply from epoch totalSupply: ", userSupply);
|
||||
iEpoch.totalSupply -= userSupply;
|
||||
console.log("--- New epoch epochReward: ", iEpoch.epochReward);
|
||||
console.log("--- New epoch totalSupply: ", iEpoch.totalSupply);
|
||||
console.log("\n");
|
||||
}
|
||||
account.epoch = userEpoch;
|
||||
if (userReward > 0) {
|
||||
|
@ -411,6 +442,8 @@ contract StakeManager is Ownable {
|
|||
//bonus for increased lock time
|
||||
mpToMint += _getMPToMint(account.balance + amount, increasedLockTime);
|
||||
}
|
||||
|
||||
console.log("--- Minting MP: ", mpToMint);
|
||||
//update storage
|
||||
totalSupplyMP += mpToMint;
|
||||
account.bonusMP += mpToMint;
|
||||
|
@ -432,6 +465,8 @@ contract StakeManager is Ownable {
|
|||
account.totalMP
|
||||
);
|
||||
|
||||
console.log("--------- increasedMP: ", increasedMP);
|
||||
|
||||
//update storage
|
||||
account.lastMint = processTime;
|
||||
account.totalMP += increasedMP;
|
||||
|
@ -501,4 +536,12 @@ contract StakeManager is Ownable {
|
|||
function epochEnd() public view returns (uint256 _epochEnd) {
|
||||
return epochs[currentEpoch].startTime + EPOCH_SIZE;
|
||||
}
|
||||
|
||||
function getEpoch(uint256 _epoch) public view returns (Epoch memory) {
|
||||
return epochs[_epoch];
|
||||
}
|
||||
|
||||
function getAccount(address _account) public view returns (Account memory) {
|
||||
return accounts[_account];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,15 +14,55 @@ import { StakeManager } from "./StakeManager.sol";
|
|||
contract StakeVault is Ownable {
|
||||
error StakeVault__MigrationNotAvailable();
|
||||
|
||||
error StakeVault__StakingFailed();
|
||||
error StakeVault__InDepositCooldown();
|
||||
|
||||
error StakeVault__UnstakingFailed();
|
||||
error StakeVault__InWithdrawCooldown();
|
||||
|
||||
error StakeVault__DepositFailed();
|
||||
|
||||
error StakeVault__WithdrawFailed();
|
||||
|
||||
error StakeVault__InsufficientFunds();
|
||||
|
||||
error StakeVault__InvalidLockTime();
|
||||
|
||||
event Deposited(uint256 amount);
|
||||
|
||||
event Withdrawn(uint256 amount);
|
||||
|
||||
event Staked(uint256 _amount, uint256 time);
|
||||
|
||||
StakeManager private stakeManager;
|
||||
|
||||
ERC20 public immutable STAKED_TOKEN;
|
||||
|
||||
event Staked(address from, address to, uint256 _amount, uint256 time);
|
||||
uint256 public balance;
|
||||
|
||||
uint256 public depositCooldownUntil;
|
||||
|
||||
uint256 public withdrawCooldownUntil;
|
||||
|
||||
modifier whenNotInDepositCooldown() {
|
||||
if (block.timestamp <= depositCooldownUntil) {
|
||||
revert StakeVault__InDepositCooldown();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
modifier whenNotInWithdrawCooldown() {
|
||||
if (block.timestamp <= withdrawCooldownUntil) {
|
||||
revert StakeVault__InWithdrawCooldown();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlySufficientBalance(uint256 _amount) {
|
||||
uint256 availableFunds = _unstakedBalance();
|
||||
if (_amount > availableFunds) {
|
||||
revert StakeVault__InsufficientFunds();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address _owner, ERC20 _stakedToken, StakeManager _stakeManager) {
|
||||
_transferOwnership(_owner);
|
||||
|
@ -30,26 +70,55 @@ contract StakeVault is Ownable {
|
|||
stakeManager = _stakeManager;
|
||||
}
|
||||
|
||||
function stake(uint256 _amount, uint256 _time) external onlyOwner {
|
||||
bool success = STAKED_TOKEN.transferFrom(msg.sender, address(this), _amount);
|
||||
if (!success) {
|
||||
revert StakeVault__StakingFailed();
|
||||
}
|
||||
stakeManager.stake(_amount, _time);
|
||||
function deposit(uint256 _amount) external onlyOwner whenNotInDepositCooldown {
|
||||
depositCooldownUntil = block.timestamp + stakeManager.DEPOSIT_COOLDOWN_PERIOD();
|
||||
_deposit(msg.sender, _amount);
|
||||
}
|
||||
|
||||
emit Staked(msg.sender, address(this), _amount, _time);
|
||||
function withdraw(uint256 _amount) public onlyOwner whenNotInWithdrawCooldown onlySufficientBalance(_amount) {
|
||||
balance -= _amount;
|
||||
bool success = STAKED_TOKEN.transfer(msg.sender, _amount);
|
||||
if (!success) {
|
||||
revert StakeVault__WithdrawFailed();
|
||||
}
|
||||
emit Withdrawn(_amount);
|
||||
}
|
||||
|
||||
function stake(
|
||||
uint256 _amount,
|
||||
uint256 _time
|
||||
)
|
||||
public
|
||||
onlyOwner
|
||||
whenNotInDepositCooldown
|
||||
onlySufficientBalance(_amount)
|
||||
{
|
||||
_stake(_amount, _time);
|
||||
}
|
||||
|
||||
function depositAndStake(uint256 _amount, uint256 _time) external onlyOwner whenNotInDepositCooldown {
|
||||
uint256 stakedBalance = _stakedBalance();
|
||||
if (stakedBalance == 0 && _time == 0) {
|
||||
// we expect `depositAndStake` to be called either with a lock time,
|
||||
// or when there's already funds staked (because it's possible to top up stake without locking)
|
||||
revert StakeVault__InvalidLockTime();
|
||||
}
|
||||
_deposit(msg.sender, _amount);
|
||||
_stake(_amount, _time);
|
||||
}
|
||||
|
||||
function lock(uint256 _time) external onlyOwner {
|
||||
stakeManager.lock(_time);
|
||||
}
|
||||
|
||||
function unstake(uint256 _amount) external onlyOwner {
|
||||
function unstake(uint256 _amount) external onlyOwner whenNotInWithdrawCooldown {
|
||||
withdrawCooldownUntil = block.timestamp + stakeManager.WITHDRAW_COOLDOWN_PERIOD();
|
||||
stakeManager.unstake(_amount);
|
||||
bool success = STAKED_TOKEN.transfer(msg.sender, _amount);
|
||||
if (!success) {
|
||||
revert StakeVault__UnstakingFailed();
|
||||
}
|
||||
}
|
||||
|
||||
function unstakeAndWithdraw(uint256 _amount) external onlyOwner {
|
||||
stakeManager.unstake(_amount);
|
||||
withdraw(_amount);
|
||||
}
|
||||
|
||||
function leave() external onlyOwner {
|
||||
|
@ -69,4 +138,28 @@ contract StakeVault is Ownable {
|
|||
function stakedToken() external view returns (ERC20) {
|
||||
return STAKED_TOKEN;
|
||||
}
|
||||
|
||||
function _deposit(address _from, uint256 _amount) internal {
|
||||
balance += _amount;
|
||||
bool success = STAKED_TOKEN.transferFrom(_from, address(this), _amount);
|
||||
if (!success) {
|
||||
revert StakeVault__DepositFailed();
|
||||
}
|
||||
emit Deposited(_amount);
|
||||
}
|
||||
|
||||
function _stake(uint256 _amount, uint256 _time) internal {
|
||||
stakeManager.stake(_amount, _time);
|
||||
emit Staked(_amount, _time);
|
||||
}
|
||||
|
||||
function _unstakedBalance() internal view returns (uint256) {
|
||||
(, uint256 stakedBalance,,,,,) = stakeManager.accounts(address(this));
|
||||
return balance - stakedBalance;
|
||||
}
|
||||
|
||||
function _stakedBalance() internal view returns (uint256) {
|
||||
(, uint256 stakedBalance,,,,,) = stakeManager.accounts(address(this));
|
||||
return stakedBalance;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,14 @@ contract StakeManagerTest is Test {
|
|||
userVault = _createTestVault(owner);
|
||||
vm.startPrank(owner);
|
||||
ERC20(stakeToken).approve(address(userVault), mintAmount);
|
||||
userVault.stake(amount, lockTime);
|
||||
|
||||
if (lockTime > 0) {
|
||||
userVault.depositAndStake(amount, lockTime);
|
||||
} else {
|
||||
userVault.deposit(amount);
|
||||
vm.warp(userVault.depositCooldownUntil() + 1);
|
||||
userVault.stake(amount, lockTime);
|
||||
}
|
||||
vm.stopPrank();
|
||||
}
|
||||
}
|
||||
|
@ -97,11 +104,11 @@ contract StakeTest is StakeManagerTest {
|
|||
|
||||
uint256 lockTime = stakeManager.MIN_LOCKUP_PERIOD() - 1;
|
||||
vm.expectRevert(StakeManager.StakeManager__InvalidLockTime.selector);
|
||||
userVault.stake(100, lockTime);
|
||||
userVault.depositAndStake(100, lockTime);
|
||||
|
||||
lockTime = stakeManager.MAX_LOCKUP_PERIOD() + 1;
|
||||
vm.expectRevert(StakeManager.StakeManager__InvalidLockTime.selector);
|
||||
userVault.stake(100, lockTime);
|
||||
userVault.depositAndStake(100, lockTime);
|
||||
}
|
||||
|
||||
function test_StakeWithoutLockUpTimeMintsMultiplierPoints() public {
|
||||
|
@ -129,7 +136,7 @@ contract StakeTest is StakeManagerTest {
|
|||
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, lockToIncrease, mintAmount);
|
||||
|
||||
vm.prank(testUser);
|
||||
userVault.stake(stakeAmount2, 0);
|
||||
userVault.depositAndStake(stakeAmount2, 0);
|
||||
|
||||
(, uint256 balance,, uint256 totalMP,,,) = stakeManager.accounts(address(userVault));
|
||||
assertEq(balance, stakeAmount + stakeAmount2, "account balance");
|
||||
|
@ -138,7 +145,7 @@ contract StakeTest is StakeManagerTest {
|
|||
vm.warp(stakeManager.epochEnd());
|
||||
|
||||
vm.prank(testUser);
|
||||
userVault.stake(stakeAmount3, 0);
|
||||
userVault.depositAndStake(stakeAmount3, 0);
|
||||
|
||||
(, balance,, totalMP,,,) = stakeManager.accounts(address(userVault));
|
||||
assertEq(balance, stakeAmount + stakeAmount2 + stakeAmount3, "account balance 2");
|
||||
|
@ -154,9 +161,9 @@ contract StakeTest is StakeManagerTest {
|
|||
_createStakingAccount(testUser2, stakeAmount, stakeManager.MIN_LOCKUP_PERIOD(), mintAmount);
|
||||
|
||||
vm.prank(testUser);
|
||||
userVault.stake(stakeAmount2, 0);
|
||||
userVault.depositAndStake(stakeAmount2, 0);
|
||||
vm.prank(testUser2);
|
||||
userVault2.stake(stakeAmount2, 0);
|
||||
userVault2.depositAndStake(stakeAmount2, 0);
|
||||
|
||||
(, uint256 balance,, uint256 totalMP,,,) = stakeManager.accounts(address(userVault));
|
||||
assertEq(balance, stakeAmount + stakeAmount2, "account balance");
|
||||
|
@ -168,9 +175,9 @@ contract StakeTest is StakeManagerTest {
|
|||
vm.warp(stakeManager.epochEnd());
|
||||
|
||||
vm.prank(testUser);
|
||||
userVault.stake(stakeAmount2, 0);
|
||||
userVault.depositAndStake(stakeAmount2, 0);
|
||||
vm.prank(testUser2);
|
||||
userVault2.stake(stakeAmount2, 0);
|
||||
userVault2.depositAndStake(stakeAmount2, 0);
|
||||
|
||||
(, balance,, totalMP,,,) = stakeManager.accounts(address(userVault));
|
||||
assertEq(balance, stakeAmount + stakeAmount2 + stakeAmount2, "account balance 2");
|
||||
|
@ -187,9 +194,9 @@ contract StakeTest is StakeManagerTest {
|
|||
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, 0, mintAmount);
|
||||
StakeVault userVault2 = _createStakingAccount(testUser2, stakeAmount, lockToIncrease, mintAmount);
|
||||
vm.prank(testUser);
|
||||
userVault.stake(0, lockToIncrease);
|
||||
userVault.depositAndStake(0, lockToIncrease);
|
||||
vm.prank(testUser2);
|
||||
userVault2.stake(0, lockToIncrease);
|
||||
userVault2.depositAndStake(0, lockToIncrease);
|
||||
|
||||
(, uint256 balance,, uint256 totalMP,,,) = stakeManager.accounts(address(userVault));
|
||||
assertEq(balance, stakeAmount, "account balance");
|
||||
|
@ -201,9 +208,9 @@ contract StakeTest is StakeManagerTest {
|
|||
vm.warp(stakeManager.epochEnd());
|
||||
|
||||
vm.prank(testUser);
|
||||
userVault.stake(0, lockToIncrease);
|
||||
userVault.depositAndStake(0, lockToIncrease);
|
||||
vm.prank(testUser2);
|
||||
userVault2.stake(0, lockToIncrease);
|
||||
userVault2.depositAndStake(0, lockToIncrease);
|
||||
|
||||
(, balance,, totalMP,,,) = stakeManager.accounts(address(userVault));
|
||||
assertEq(balance, stakeAmount, "account balance 2");
|
||||
|
@ -222,9 +229,9 @@ contract StakeTest is StakeManagerTest {
|
|||
StakeVault userVault2 = _createStakingAccount(testUser2, stakeAmount, lockToIncrease, mintAmount);
|
||||
|
||||
vm.prank(testUser);
|
||||
userVault.stake(stakeAmount2, lockToIncrease);
|
||||
userVault.depositAndStake(stakeAmount2, lockToIncrease);
|
||||
vm.prank(testUser2);
|
||||
userVault2.stake(stakeAmount2, lockToIncrease);
|
||||
userVault2.depositAndStake(stakeAmount2, lockToIncrease);
|
||||
|
||||
(, uint256 balance,, uint256 totalMP,,,) = stakeManager.accounts(address(userVault));
|
||||
assertEq(balance, stakeAmount + stakeAmount2, "account balance");
|
||||
|
@ -236,9 +243,9 @@ contract StakeTest is StakeManagerTest {
|
|||
vm.warp(stakeManager.epochEnd());
|
||||
|
||||
vm.prank(testUser);
|
||||
userVault.stake(stakeAmount2, lockToIncrease);
|
||||
userVault.depositAndStake(stakeAmount2, lockToIncrease);
|
||||
vm.prank(testUser2);
|
||||
userVault2.stake(stakeAmount2, lockToIncrease);
|
||||
userVault2.depositAndStake(stakeAmount2, lockToIncrease);
|
||||
|
||||
(, balance,, totalMP,,,) = stakeManager.accounts(address(userVault));
|
||||
assertEq(balance, stakeAmount + stakeAmount2 + stakeAmount2, "account balance 2");
|
||||
|
@ -518,57 +525,259 @@ contract ExecuteAccountTest is StakeManagerTest {
|
|||
stakeManager.executeAccount(address(userVault), currentEpoch + 1);
|
||||
}
|
||||
|
||||
function test_ExecuteAccountBug() public {
|
||||
uint256 stakeAmount = 10_000_000;
|
||||
deal(stakeToken, testUser, stakeAmount);
|
||||
|
||||
// initial assumptions
|
||||
assertEq(stakeManager.currentEpoch(), 0);
|
||||
assertEq(stakeManager.pendingReward(), 0);
|
||||
assertEq(stakeManager.totalSupplyMP(), 0);
|
||||
assertEq(stakeManager.totalSupplyBalance(), 0);
|
||||
StakeManager.Epoch memory currentEpoch = stakeManager.getEpoch(0);
|
||||
assertEq(currentEpoch.startTime, block.timestamp);
|
||||
assertEq(currentEpoch.epochReward, 0);
|
||||
assertEq(currentEpoch.totalSupply, 0);
|
||||
|
||||
userVaults.push(_createStakingAccount(testUser, stakeAmount, 0));
|
||||
|
||||
assertEq(stakeManager.currentEpoch(), 1);
|
||||
assertEq(stakeManager.pendingReward(), 0);
|
||||
assertEq(stakeManager.totalSupplyMP(), stakeAmount);
|
||||
assertEq(stakeManager.totalSupplyBalance(), stakeAmount);
|
||||
|
||||
// epoch `1` hasn't been processed yet, so no expected rewards
|
||||
currentEpoch = stakeManager.getEpoch(1);
|
||||
assertEq(currentEpoch.epochReward, 0);
|
||||
assertEq(currentEpoch.totalSupply, 0);
|
||||
|
||||
// however, account should have balance and MPs
|
||||
StakeManager.Account memory account = stakeManager.getAccount(address(userVaults[0]));
|
||||
assertEq(account.balance, stakeAmount);
|
||||
assertEq(account.bonusMP, stakeAmount);
|
||||
assertEq(account.totalMP, stakeAmount);
|
||||
assertEq(account.epoch, 1);
|
||||
|
||||
// -------- ADD REVENUE AND ADVANCE EPOCHS --------
|
||||
|
||||
// emulate revenue increase
|
||||
console.log("--- Adding revenue: ", 10 ether);
|
||||
deal(stakeToken, address(stakeManager), 10 ether);
|
||||
|
||||
// ensure current `epoch` has is complete
|
||||
vm.warp(stakeManager.epochEnd());
|
||||
// calculate account rewards and pending rewwards
|
||||
stakeManager.executeEpoch();
|
||||
|
||||
assertEq(stakeManager.currentEpoch(), 2);
|
||||
|
||||
// emulate revenue increase
|
||||
console.log("--- Adding revenue: ", 10 ether);
|
||||
deal(stakeToken, address(stakeManager), 20 ether);
|
||||
|
||||
// ensure current `epoch` has is complete
|
||||
vm.warp(stakeManager.epochEnd());
|
||||
// calculate account rewards and pending rewwards
|
||||
stakeManager.executeEpoch();
|
||||
|
||||
// account epoch is still at 1
|
||||
account = stakeManager.getAccount(address(userVaults[0]));
|
||||
assertEq(account.balance, stakeAmount);
|
||||
assertEq(account.bonusMP, stakeAmount);
|
||||
assertEq(account.totalMP, stakeAmount);
|
||||
assertEq(account.epoch, 1);
|
||||
|
||||
stakeManager.executeAccount(address(userVaults[0]), 2);
|
||||
|
||||
stakeManager.executeAccount(address(userVaults[0]), 3);
|
||||
}
|
||||
|
||||
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());
|
||||
// console.log("------- CREATING ACCOUNT 1");
|
||||
// userVaults.push(_createStakingAccount(testUser, stakeAmount, 0));
|
||||
// (,,, , ,, uint256 epoch) = stakeManager.accounts(address(userVaults[0]));
|
||||
// stakeManager.executeEpoch();
|
||||
// console.log("# NOW", block.timestamp);
|
||||
// vm.warp(stakeManager.epochEnd());
|
||||
// console.log("# EPOCH END", block.timestamp);
|
||||
// console.log("# START EPOCH", stakeManager.currentEpoch());
|
||||
// console.log("# USER 1 EPOCH", epoch);
|
||||
// console.log("# PND_REWARDS", stakeManager.pendingReward());
|
||||
// vm.warp(stakeManager.epochEnd());
|
||||
// stakeManager.executeEpoch();
|
||||
// console.log("------- CREATING ACCOUNT 2");
|
||||
// userVaults.push(_createStakingAccount(testUser2, stakeAmount, 0));
|
||||
// (,,, , ,, epoch) = stakeManager.accounts(address(userVaults[1]));
|
||||
// console.log("# NOW", block.timestamp);
|
||||
// console.log("# START EPOCH", stakeManager.currentEpoch());
|
||||
// console.log("# USER 2 EPOCH", epoch);
|
||||
// console.log("# PND_REWARDS", stakeManager.pendingReward());
|
||||
// userVaults.push(_createStakingAccount(makeAddr("testUser3"), stakeAmount, 0));
|
||||
|
||||
console.log("######### NOW", block.timestamp);
|
||||
console.log("# START EPOCH", stakeManager.currentEpoch());
|
||||
console.log("# PND_REWARDS", stakeManager.pendingReward());
|
||||
// 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());
|
||||
// initial assumptions
|
||||
assertEq(stakeManager.currentEpoch(), 0);
|
||||
assertEq(stakeManager.pendingReward(), 0);
|
||||
assertEq(stakeManager.totalSupplyMP(), 0);
|
||||
assertEq(stakeManager.totalSupplyBalance(), 0);
|
||||
StakeManager.Epoch memory currentEpoch = stakeManager.getEpoch(0);
|
||||
assertEq(currentEpoch.startTime, block.timestamp);
|
||||
assertEq(currentEpoch.epochReward, 0);
|
||||
assertEq(currentEpoch.totalSupply, 0);
|
||||
|
||||
for (uint256 j = 0; j < userVaults.length; j++) {
|
||||
(address rewardAddress,,, uint256 totalMPBefore, 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("---### totalMP :", totalMPBefore);
|
||||
console.log("---#### lastMint :", lastMintBefore);
|
||||
console.log("---## user_epoch :", epochBefore);
|
||||
console.log("---##### rewards :", rewardsBefore);
|
||||
console.log("--=====AFTER======");
|
||||
stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1);
|
||||
(,,, uint256 totalMP, uint256 lastMint,, uint256 epoch) = stakeManager.accounts(address(userVaults[j]));
|
||||
uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress);
|
||||
console.log("---### deltaTime :", lastMint - lastMintBefore);
|
||||
console.log("---### totalMP :", totalMP);
|
||||
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(totalMP, totalMPBefore, "must increase MPs");
|
||||
assertGt(rewards, rewardsBefore, "must increase rewards");
|
||||
lastMintBefore = lastMint;
|
||||
epochBefore = epoch;
|
||||
totalMPBefore = totalMP;
|
||||
}
|
||||
}
|
||||
// Create stake vaults and deposit + stake `stakeAmount`
|
||||
// Keep in mind that this advances `block.timestamp` to get past the
|
||||
// `depositCooldownUntil` time
|
||||
userVaults.push(_createStakingAccount(testUser, stakeAmount, 0));
|
||||
|
||||
assertEq(stakeManager.currentEpoch(), 1);
|
||||
assertEq(stakeManager.pendingReward(), 0);
|
||||
assertEq(stakeManager.totalSupplyMP(), stakeAmount);
|
||||
assertEq(stakeManager.totalSupplyBalance(), stakeAmount);
|
||||
|
||||
// epoch `1` hasn't been processed yet, so no expected rewards
|
||||
currentEpoch = stakeManager.getEpoch(1);
|
||||
assertEq(currentEpoch.epochReward, 0);
|
||||
assertEq(currentEpoch.totalSupply, 0);
|
||||
|
||||
// however, account should have balance and MPs
|
||||
StakeManager.Account memory account = stakeManager.getAccount(address(userVaults[0]));
|
||||
assertEq(account.balance, stakeAmount);
|
||||
assertEq(account.bonusMP, stakeAmount);
|
||||
assertEq(account.totalMP, stakeAmount);
|
||||
assertEq(account.epoch, 1);
|
||||
|
||||
// emulate revenue increase
|
||||
console.log("--- Adding revenue: ", 100 ether);
|
||||
deal(stakeToken, address(stakeManager), 100 ether);
|
||||
|
||||
// ensure current `epoch` has is complete
|
||||
vm.warp(stakeManager.epochEnd());
|
||||
// calculate account rewards and pending rewwards
|
||||
stakeManager.executeEpoch();
|
||||
|
||||
assertEq(stakeManager.currentEpoch(), 2);
|
||||
// previous epoch rewards should be added to `pendingReward`
|
||||
currentEpoch = stakeManager.getEpoch(1);
|
||||
assertEq(currentEpoch.epochReward, 100 ether, "epoch reward");
|
||||
assertEq(stakeManager.pendingReward(), 100 ether, "pending rewards");
|
||||
assertEq(stakeManager.totalSupplyMP(), stakeAmount);
|
||||
assertEq(stakeManager.totalSupplyBalance(), stakeAmount);
|
||||
assertEq(currentEpoch.totalSupply, account.balance + account.totalMP);
|
||||
|
||||
// account epoch is still at 1
|
||||
account = stakeManager.getAccount(address(userVaults[0]));
|
||||
assertEq(account.balance, stakeAmount);
|
||||
assertEq(account.bonusMP, stakeAmount);
|
||||
assertEq(account.totalMP, stakeAmount);
|
||||
assertEq(account.epoch, 1);
|
||||
|
||||
stakeManager.executeAccount(address(userVaults[0]), 2);
|
||||
|
||||
assertEq(stakeManager.pendingReward(), 0);
|
||||
account = stakeManager.getAccount(address(userVaults[0]));
|
||||
assertEq(account.balance, stakeAmount);
|
||||
assertEq(account.bonusMP, stakeAmount);
|
||||
assertGt(account.totalMP, stakeAmount);
|
||||
assertEq(ERC20(stakeToken).balanceOf(userVaults[0].owner()), 100 ether);
|
||||
assertEq(account.epoch, 2);
|
||||
|
||||
// second staker comes in
|
||||
userVaults.push(_createStakingAccount(testUser2, stakeAmount, 0));
|
||||
StakeManager.Account memory secondAccount = stakeManager.getAccount(address(userVaults[1]));
|
||||
|
||||
assertEq(stakeManager.currentEpoch(), 3);
|
||||
assertEq(stakeManager.pendingReward(), 0);
|
||||
assertEq(secondAccount.epoch, 3);
|
||||
assertEq(secondAccount.balance, stakeAmount);
|
||||
assertEq(secondAccount.bonusMP, stakeAmount);
|
||||
assertEq(secondAccount.totalMP, stakeAmount);
|
||||
// assertEq(stakeManager.totalSupplyMP(), stakeAmount);
|
||||
assertEq(stakeManager.totalSupplyBalance(), stakeAmount * 2);
|
||||
|
||||
// emulate revenue increase
|
||||
deal(stakeToken, address(stakeManager), 100 ether);
|
||||
vm.warp(stakeManager.epochEnd());
|
||||
// calculate account rewards and pending rewwards
|
||||
// stakeManager.executeEpoch();
|
||||
// assertEq(stakeManager.pendingReward(), 100 ether);
|
||||
stakeManager.executeAccount(address(userVaults[1]), 4);
|
||||
secondAccount = stakeManager.getAccount(address(userVaults[1]));
|
||||
assertEq(secondAccount.epoch, 4);
|
||||
assertEq(secondAccount.balance, stakeAmount);
|
||||
assertEq(secondAccount.bonusMP, stakeAmount);
|
||||
assertGt(secondAccount.totalMP, stakeAmount);
|
||||
assertEq(stakeManager.pendingReward(), 50 ether);
|
||||
|
||||
account = stakeManager.getAccount(address(userVaults[0]));
|
||||
assertEq(account.epoch, 2);
|
||||
stakeManager.executeAccount(address(userVaults[0]), 4);
|
||||
// assertEq(stakeManager.pendingReward(), 50 ether);
|
||||
// stakeManager.executeAccount(address(userVaults[0]), 4);
|
||||
assertEq(stakeManager.pendingReward(), 0);
|
||||
|
||||
// ensure current `epoch` has is complete
|
||||
|
||||
// userVaults.push(_createStakingAccount(makeAddr("testUser3"), stakeAmount, 0));
|
||||
|
||||
// for (uint256 i = 0; i < 3; i++) {
|
||||
|
||||
// for (uint256 i = 0; i < 1; i++) {
|
||||
// // emulate revenue increase
|
||||
// deal(stakeToken, address(stakeManager), 100 ether);
|
||||
// // ensure current `epoch` has is complete
|
||||
// vm.warp(stakeManager.epochEnd());
|
||||
// // calculate account rewards and pending rewwards
|
||||
// stakeManager.executeEpoch();
|
||||
//
|
||||
// // uint256 currentEpoch = stakeManager.currentEpoch();
|
||||
// // (uint256 startTime, uint256 epochReward, uint256 totalSupply) = stakeManager.epochs(currentEpoch);
|
||||
// //
|
||||
// // console.log("######### NOW", block.timestamp);
|
||||
// // console.log("##### NEW EPOCH", stakeManager.currentEpoch());
|
||||
// // console.log("# PND_REWARDS", stakeManager.pendingReward());
|
||||
//
|
||||
// for (uint256 j = 0; j < userVaults.length; j++) {
|
||||
// // (address rewardAddress,,, uint256 totalMPBefore, 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("---### totalMP :", totalMPBefore);
|
||||
// // console.log("---#### lastMint :", lastMintBefore);
|
||||
// // console.log("---## user_epoch :", epochBefore);
|
||||
// // console.log("---##### rewards :", rewardsBefore);
|
||||
// // console.log("--=====AFTER======");
|
||||
// // stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1);
|
||||
// // (,,, uint256 totalMP, uint256 lastMint,, uint256 epoch) =
|
||||
// // stakeManager.accounts(address(userVaults[j]));
|
||||
// // uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress);
|
||||
// // console.log("---### deltaTime :", lastMint - lastMintBefore);
|
||||
// // console.log("---### totalMP :", totalMP);
|
||||
// // 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(totalMP, totalMPBefore, "must increase MPs");
|
||||
// // assertGt(rewards, rewardsBefore, "must increase rewards");
|
||||
// // lastMintBefore = lastMint;
|
||||
// // epochBefore = epoch;
|
||||
// // totalMPBefore = totalMP;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
function test_ShouldNotMintMoreThanCap() public {
|
||||
|
|
|
@ -20,10 +20,14 @@ contract StakeVaultTest is Test {
|
|||
|
||||
StakeVault internal stakeVault;
|
||||
|
||||
StakeVault internal stakeVault2;
|
||||
|
||||
address internal deployer;
|
||||
|
||||
address internal testUser = makeAddr("testUser");
|
||||
|
||||
address internal testUser2 = makeAddr("testUser2");
|
||||
|
||||
address internal stakeToken;
|
||||
|
||||
function setUp() public virtual {
|
||||
|
@ -33,6 +37,12 @@ contract StakeVaultTest is Test {
|
|||
|
||||
vm.prank(testUser);
|
||||
stakeVault = vaultFactory.createVault();
|
||||
|
||||
vm.prank(testUser2);
|
||||
stakeVault2 = vaultFactory.createVault();
|
||||
|
||||
vm.prank(deployer);
|
||||
stakeManager.setVault(address(stakeVault).codehash);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +56,211 @@ contract StakedTokenTest is StakeVaultTest {
|
|||
}
|
||||
}
|
||||
|
||||
contract DepositTest is StakeVaultTest {
|
||||
event Deposited(uint256 amount);
|
||||
|
||||
function setUp() public override {
|
||||
StakeVaultTest.setUp();
|
||||
}
|
||||
|
||||
function test_RevertWhen_DepositAndInDepositCooldown() public {
|
||||
deal(stakeToken, testUser, 1000);
|
||||
vm.startPrank(testUser);
|
||||
ERC20(stakeToken).approve(address(stakeVault), 100);
|
||||
stakeVault.deposit(100);
|
||||
vm.expectRevert(StakeVault.StakeVault__InDepositCooldown.selector);
|
||||
stakeVault.deposit(100);
|
||||
}
|
||||
|
||||
function test_Deposit() public {
|
||||
uint256 userFunds = 1000;
|
||||
uint256 depositAmount = 100;
|
||||
|
||||
deal(stakeToken, testUser, userFunds);
|
||||
deal(stakeToken, testUser2, userFunds);
|
||||
|
||||
// first user
|
||||
vm.startPrank(testUser);
|
||||
ERC20(stakeToken).approve(address(stakeVault), depositAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Deposited(depositAmount);
|
||||
stakeVault.deposit(depositAmount);
|
||||
|
||||
assertEq(ERC20(stakeToken).balanceOf(address(stakeVault)), depositAmount);
|
||||
assertEq(stakeVault.balance(), depositAmount);
|
||||
assertEq(stakeVault.depositCooldownUntil(), block.timestamp + stakeManager.DEPOSIT_COOLDOWN_PERIOD());
|
||||
// ensure funds haven't reached stake manager yet
|
||||
assertEq(stakeManager.totalSupply(), 0);
|
||||
}
|
||||
|
||||
function test_DepositAfterCooldown() public {
|
||||
uint256 userFunds = 1000;
|
||||
uint256 depositAmount = 100;
|
||||
deal(stakeToken, testUser, userFunds);
|
||||
|
||||
vm.startPrank(testUser);
|
||||
ERC20(stakeToken).approve(address(stakeVault), depositAmount);
|
||||
|
||||
// make first deposit
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Deposited(depositAmount);
|
||||
stakeVault.deposit(depositAmount);
|
||||
|
||||
assertEq(ERC20(stakeToken).balanceOf(address(stakeVault)), depositAmount);
|
||||
assertEq(stakeVault.balance(), depositAmount);
|
||||
assertEq(stakeVault.depositCooldownUntil(), block.timestamp + stakeManager.DEPOSIT_COOLDOWN_PERIOD());
|
||||
assertEq(stakeManager.totalSupply(), 0);
|
||||
|
||||
// wait for deposit cooldown to elapse
|
||||
vm.warp(stakeVault.depositCooldownUntil() + 1);
|
||||
|
||||
ERC20(stakeToken).approve(address(stakeVault), depositAmount);
|
||||
|
||||
// make second deposit after first deposit has cooled down
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Deposited(depositAmount);
|
||||
stakeVault.deposit(depositAmount);
|
||||
|
||||
assertEq(ERC20(stakeToken).balanceOf(address(stakeVault)), depositAmount * 2);
|
||||
assertEq(stakeVault.balance(), depositAmount * 2);
|
||||
assertEq(stakeVault.depositCooldownUntil(), block.timestamp + stakeManager.DEPOSIT_COOLDOWN_PERIOD());
|
||||
assertEq(stakeManager.totalSupply(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
contract WithdrawTest is StakeVaultTest {
|
||||
event Withdrawn(uint256 amount);
|
||||
|
||||
uint256 internal stakeAmount = 100;
|
||||
uint256 internal userFunds = 1000;
|
||||
|
||||
function setUp() public override {
|
||||
StakeVaultTest.setUp();
|
||||
|
||||
deal(stakeToken, testUser, userFunds);
|
||||
|
||||
vm.startPrank(testUser);
|
||||
ERC20(stakeToken).approve(address(stakeVault), stakeAmount);
|
||||
stakeVault.deposit(stakeAmount);
|
||||
}
|
||||
|
||||
function test_RevertWhen_InWithdrawCooldown() public {
|
||||
// ensure deposit cooldown has passed
|
||||
vm.warp(stakeVault.depositCooldownUntil() + 1);
|
||||
|
||||
// stake funds so we can unstake after that (and initialize withdraw cooldown)
|
||||
stakeVault.stake(stakeAmount, 0);
|
||||
stakeVault.unstake(stakeAmount);
|
||||
|
||||
assertEq(stakeVault.withdrawCooldownUntil(), block.timestamp + stakeManager.WITHDRAW_COOLDOWN_PERIOD());
|
||||
|
||||
vm.expectRevert(StakeVault.StakeVault__InWithdrawCooldown.selector);
|
||||
stakeVault.withdraw(stakeAmount);
|
||||
}
|
||||
|
||||
function test_RevertWhen_WithdrawInsufficientFunds() public {
|
||||
vm.startPrank(testUser);
|
||||
vm.expectRevert(StakeVault.StakeVault__InsufficientFunds.selector);
|
||||
stakeVault.withdraw(stakeAmount + 1);
|
||||
}
|
||||
|
||||
function test_Withdraw() public {
|
||||
vm.startPrank(testUser);
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Withdrawn(stakeAmount);
|
||||
stakeVault.withdraw(stakeAmount);
|
||||
|
||||
assertEq(stakeVault.balance(), 0);
|
||||
assertEq(ERC20(stakeToken).balanceOf(address(stakeVault)), 0);
|
||||
assertEq(ERC20(stakeToken).balanceOf(testUser), userFunds);
|
||||
}
|
||||
|
||||
function test_WithdrawLessAmountThanAvailable() public {
|
||||
uint256 remainingAmount = 50;
|
||||
vm.startPrank(testUser);
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Withdrawn(stakeAmount - remainingAmount);
|
||||
stakeVault.withdraw(stakeAmount - remainingAmount);
|
||||
|
||||
assertEq(stakeVault.balance(), remainingAmount);
|
||||
assertEq(ERC20(stakeToken).balanceOf(address(stakeVault)), remainingAmount);
|
||||
assertEq(ERC20(stakeToken).balanceOf(testUser), userFunds - remainingAmount);
|
||||
|
||||
// try to withdraw the remaining amount
|
||||
emit Withdrawn(remainingAmount);
|
||||
stakeVault.withdraw(remainingAmount);
|
||||
|
||||
assertEq(stakeVault.balance(), 0);
|
||||
assertEq(ERC20(stakeToken).balanceOf(address(stakeVault)), 0);
|
||||
assertEq(ERC20(stakeToken).balanceOf(testUser), userFunds);
|
||||
}
|
||||
}
|
||||
|
||||
contract StakeTest is StakeVaultTest {
|
||||
event Staked(uint256 amount, uint256 time);
|
||||
|
||||
uint256 internal userFunds = 1000;
|
||||
uint256 internal stakeAmount = 100;
|
||||
|
||||
function setUp() public override {
|
||||
StakeVaultTest.setUp();
|
||||
deal(stakeToken, testUser, userFunds);
|
||||
}
|
||||
|
||||
function test_RevertWhen_StakeAndInDepositCooldown() public {
|
||||
vm.startPrank(testUser);
|
||||
ERC20(stakeToken).approve(address(stakeVault), stakeAmount);
|
||||
stakeVault.deposit(stakeAmount);
|
||||
|
||||
vm.expectRevert(StakeVault.StakeVault__InDepositCooldown.selector);
|
||||
stakeVault.stake(stakeAmount, 0);
|
||||
}
|
||||
|
||||
function test_RevertWhen_StakeAndInsufficientFunds() public {
|
||||
vm.startPrank(testUser);
|
||||
vm.expectRevert(StakeVault.StakeVault__InsufficientFunds.selector);
|
||||
stakeVault.stake(stakeAmount + 1, 0);
|
||||
|
||||
// do another one, this time with deposited funds (but too little)
|
||||
vm.startPrank(testUser);
|
||||
ERC20(stakeToken).approve(address(stakeVault), stakeAmount);
|
||||
stakeVault.deposit(stakeAmount);
|
||||
|
||||
// make sure deposit cooldown has passed
|
||||
vm.warp(stakeVault.depositCooldownUntil() + 1);
|
||||
|
||||
vm.expectRevert(StakeVault.StakeVault__InsufficientFunds.selector);
|
||||
stakeVault.stake(stakeAmount + 1, 0);
|
||||
}
|
||||
|
||||
function test_Stake() public {
|
||||
vm.startPrank(testUser);
|
||||
ERC20(stakeToken).approve(address(stakeVault), stakeAmount);
|
||||
stakeVault.deposit(stakeAmount);
|
||||
assertEq(stakeManager.totalSupply(), 0);
|
||||
|
||||
// make sure deposit cooldown has passed
|
||||
vm.warp(stakeVault.depositCooldownUntil() + 1);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Staked(stakeAmount, 0);
|
||||
stakeVault.stake(stakeAmount, 0);
|
||||
|
||||
assertEq(stakeVault.balance(), stakeAmount);
|
||||
assertEq(ERC20(stakeToken).balanceOf(address(stakeVault)), stakeAmount);
|
||||
assertEq(ERC20(stakeToken).balanceOf(testUser), userFunds - stakeAmount);
|
||||
|
||||
(, uint256 stakeBalance, uint256 initialMP, uint256 currentMP,,,) = stakeManager.accounts(address(stakeVault));
|
||||
|
||||
assertEq(stakeBalance, stakeAmount);
|
||||
assertEq(currentMP, stakeAmount);
|
||||
assertEq(initialMP, stakeAmount);
|
||||
assertEq(stakeManager.totalSupply(), stakeAmount + initialMP);
|
||||
}
|
||||
}
|
||||
|
||||
contract StakeWithBrokenTokenTest is StakeVaultTest {
|
||||
function setUp() public override {
|
||||
DeployBroken deployment = new DeployBroken();
|
||||
(vaultFactory, stakeManager, stakeToken) = deployment.run();
|
||||
|
@ -61,7 +275,44 @@ contract StakeTest is StakeVaultTest {
|
|||
|
||||
vm.startPrank(address(testUser));
|
||||
ERC20(stakeToken).approve(address(stakeVault), 100);
|
||||
vm.expectRevert(StakeVault.StakeVault__StakingFailed.selector);
|
||||
stakeVault.stake(100, 0);
|
||||
vm.expectRevert(StakeVault.StakeVault__DepositFailed.selector);
|
||||
stakeVault.deposit(100);
|
||||
}
|
||||
}
|
||||
|
||||
contract UnstakeTest is StakeVaultTest {
|
||||
uint256 internal userFunds = 1000;
|
||||
uint256 internal stakeAmount = 100;
|
||||
|
||||
function setUp() public override {
|
||||
StakeVaultTest.setUp();
|
||||
deal(stakeToken, testUser, userFunds);
|
||||
|
||||
vm.startPrank(testUser);
|
||||
ERC20(stakeToken).approve(address(stakeVault), stakeAmount);
|
||||
stakeVault.deposit(stakeAmount);
|
||||
|
||||
// ensure deposit cooldown has passed
|
||||
vm.warp(stakeVault.depositCooldownUntil() + 1);
|
||||
}
|
||||
|
||||
function test_RevertWhen_SenderIsNotOwner() public {
|
||||
vm.stopPrank();
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert(bytes("Ownable: caller is not the owner"));
|
||||
stakeVault.unstake(stakeAmount);
|
||||
}
|
||||
|
||||
function test_RevertWhen_UnstakeAndInWithdrawCooldown() public {
|
||||
uint256 unstakeAmount = stakeAmount / 2;
|
||||
|
||||
// stake funds so we can unstake after that (and initialize withdraw cooldown)
|
||||
stakeVault.stake(stakeAmount, 0);
|
||||
stakeVault.unstake(unstakeAmount);
|
||||
|
||||
assertEq(stakeVault.withdrawCooldownUntil(), block.timestamp + stakeManager.WITHDRAW_COOLDOWN_PERIOD());
|
||||
|
||||
vm.expectRevert(StakeVault.StakeVault__InWithdrawCooldown.selector);
|
||||
stakeVault.unstake(unstakeAmount);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue