This commit is contained in:
Ricardo Guilherme Schmidt 2024-09-28 20:01:34 -03:00
parent ba6902643c
commit 34fe48d919
No known key found for this signature in database
GPG Key ID: 54B4454CC123AD17
3 changed files with 59 additions and 42 deletions

View File

@ -174,11 +174,14 @@ contract StakeManager is TrustedCodehashAccess {
if (mpPerEpoch < MultiplierPoint.wrap(1)) { if (mpPerEpoch < MultiplierPoint.wrap(1)) {
revert StakeManager__StakeIsTooLow(); revert StakeManager__StakeIsTooLow();
} }
MultiplierPoint currentEpochExpiredMP = mpPerEpoch - MultiplierPointCalculator.getMPToMint(_amount, epochEnd() - block.timestamp); MultiplierPoint currentEpochExpiredMP =
MultiplierPoint maxMpToMint = MultiplierPointCalculator.getMPToMint(_amount, MAX_BOOST * YEAR) + currentEpochExpiredMP; mpPerEpoch - MultiplierPointCalculator.getMPToMint(_amount, epochEnd() - block.timestamp);
MultiplierPoint maxMpToMint =
MultiplierPointCalculator.getMPToMint(_amount, MAX_BOOST * YEAR) + currentEpochExpiredMP;
uint256 epochAmountToReachMpLimit = MultiplierPoint.unwrap(maxMpToMint / mpPerEpoch); uint256 epochAmountToReachMpLimit = MultiplierPoint.unwrap(maxMpToMint / mpPerEpoch);
uint256 mpLimitEpoch = currentEpoch + epochAmountToReachMpLimit; uint256 mpLimitEpoch = currentEpoch + epochAmountToReachMpLimit;
MultiplierPoint lastEpochAmountToMint = (mpPerEpoch * MultiplierPoint.wrap(epochAmountToReachMpLimit + 1)) - maxMpToMint; MultiplierPoint lastEpochAmountToMint =
(mpPerEpoch * MultiplierPoint.wrap(epochAmountToReachMpLimit + 1)) - maxMpToMint;
// account initialization // account initialization
account.lockUntil = block.timestamp + _secondsToLock; account.lockUntil = block.timestamp + _secondsToLock;
@ -216,7 +219,8 @@ contract StakeManager is TrustedCodehashAccess {
_processAccount(account, currentEpoch); _processAccount(account, currentEpoch);
MultiplierPoint reducedMP = MultiplierPointCalculator.getMPReduced(account.balance, _amount, account.totalMP); MultiplierPoint reducedMP = MultiplierPointCalculator.getMPReduced(account.balance, _amount, account.totalMP);
MultiplierPoint reducedInitialMP = MultiplierPointCalculator.getMPReduced(account.balance, _amount, account.bonusMP); MultiplierPoint reducedInitialMP =
MultiplierPointCalculator.getMPReduced(account.balance, _amount, account.bonusMP);
MultiplierPoint mpPerEpoch = MultiplierPointCalculator.getMPToMint(account.balance, EPOCH_SIZE); MultiplierPoint mpPerEpoch = MultiplierPointCalculator.getMPToMint(account.balance, EPOCH_SIZE);
expiredStakeStorage.decrementExpiredMP(account.mpLimitEpoch, mpPerEpoch); expiredStakeStorage.decrementExpiredMP(account.mpLimitEpoch, mpPerEpoch);
@ -505,8 +509,6 @@ contract StakeManager is TrustedCodehashAccess {
pendingMPToBeMinted = pendingMPToBeMinted - mpToMint; pendingMPToBeMinted = pendingMPToBeMinted - mpToMint;
} }
/* /*
* @notice Calculates multiplier points to mint for given balance and time * @notice Calculates multiplier points to mint for given balance and time
* @param _balance balance of account * @param _balance balance of account

View File

@ -53,7 +53,15 @@ library MultiplierPointCalculator {
return MultiplierPoint.wrap(Math.mulDiv(_balance, _deltaTime, YEAR) * MP_APY); return MultiplierPoint.wrap(Math.mulDiv(_balance, _deltaTime, YEAR) * MP_APY);
} }
function getMPReduced(uint256 _currentBalance, uint256 _decreasedBalance, MultiplierPoint _totalMP) public pure returns (MultiplierPoint) { function getMPReduced(
uint256 _currentBalance,
uint256 _decreasedBalance,
MultiplierPoint _totalMP
)
public
pure
returns (MultiplierPoint)
{
return MultiplierPoint.wrap(Math.mulDiv(_decreasedBalance, MultiplierPoint.unwrap(_totalMP), _currentBalance)); return MultiplierPoint.wrap(Math.mulDiv(_decreasedBalance, MultiplierPoint.unwrap(_totalMP), _currentBalance));
} }

View File

@ -13,7 +13,6 @@ import { StakeVault } from "../contracts/StakeVault.sol";
import { VaultFactory } from "../contracts/VaultFactory.sol"; import { VaultFactory } from "../contracts/VaultFactory.sol";
library console { library console {
function log(string memory s, MultiplierPoint p) internal view { function log(string memory s, MultiplierPoint p) internal view {
cons.log(s, MultiplierPoint.unwrap(p)); cons.log(s, MultiplierPoint.unwrap(p));
} }
@ -22,47 +21,46 @@ library console {
cons.log(s, p); cons.log(s, p);
} }
function log(string memory s) internal view{ function log(string memory s) internal view {
cons.log(s); cons.log(s);
} }
function log(uint256 p) internal view{ function log(uint256 p) internal view {
cons.log(p); cons.log(p);
} }
} }
contract MultiplierPointTest is Test { contract MultiplierPointTest is Test {
function assertEq(MultiplierPoint a, uint256 b) internal { function assertEq(MultiplierPoint a, uint256 b) internal {
assertEq(MultiplierPoint.unwrap(a), b); assertEq(MultiplierPoint.unwrap(a), b);
} }
function assertEq(MultiplierPoint a, MultiplierPoint b) internal { function assertEq(MultiplierPoint a, MultiplierPoint b) internal {
assertEq(MultiplierPoint.unwrap(a), MultiplierPoint.unwrap(b)); assertEq(MultiplierPoint.unwrap(a), MultiplierPoint.unwrap(b));
} }
function assertEq(uint256 a, MultiplierPoint b) internal { function assertEq(uint256 a, MultiplierPoint b) internal {
assertEq(a, MultiplierPoint.unwrap(b)); assertEq(a, MultiplierPoint.unwrap(b));
} }
function assertEq(MultiplierPoint a, uint256 b, string memory message) internal { function assertEq(MultiplierPoint a, uint256 b, string memory message) internal {
assertEq(MultiplierPoint.unwrap(a), b, message); assertEq(MultiplierPoint.unwrap(a), b, message);
} }
function assertEq(MultiplierPoint a, MultiplierPoint b, string memory message) internal { function assertEq(MultiplierPoint a, MultiplierPoint b, string memory message) internal {
assertEq(MultiplierPoint.unwrap(a), MultiplierPoint.unwrap(b), message); assertEq(MultiplierPoint.unwrap(a), MultiplierPoint.unwrap(b), message);
} }
function assertEq(uint256 a, MultiplierPoint b, string memory message) internal { function assertEq(uint256 a, MultiplierPoint b, string memory message) internal {
assertEq(a, MultiplierPoint.unwrap(b), message); assertEq(a, MultiplierPoint.unwrap(b), message);
} }
function assertGt(MultiplierPoint a, MultiplierPoint b) internal { function assertGt(MultiplierPoint a, MultiplierPoint b) internal {
assertGt(MultiplierPoint.unwrap(a), MultiplierPoint.unwrap(b)); assertGt(MultiplierPoint.unwrap(a), MultiplierPoint.unwrap(b));
} }
function assertGt(MultiplierPoint a, MultiplierPoint b, string memory message) internal { function assertGt(MultiplierPoint a, MultiplierPoint b, string memory message) internal {
assertGt(MultiplierPoint.unwrap(a),MultiplierPoint.unwrap(b), message); assertGt(MultiplierPoint.unwrap(a), MultiplierPoint.unwrap(b), message);
} }
} }
@ -93,8 +91,6 @@ contract StakeManagerTest is MultiplierPointTest {
assertEq(stakeManager.totalSupply(), 0); assertEq(stakeManager.totalSupply(), 0);
} }
function _createTestVault(address owner) internal returns (StakeVault vault) { function _createTestVault(address owner) internal returns (StakeVault vault) {
vm.prank(owner); vm.prank(owner);
vault = vaultFactory.createVault(); vault = vaultFactory.createVault();
@ -150,14 +146,16 @@ contract StakeTest is StakeManagerTest {
StakeVault userVault = _createStakingAccount(testUser, stakeAmount, 0, stakeAmount); StakeVault userVault = _createStakingAccount(testUser, stakeAmount, 0, stakeAmount);
(, uint256 balance, MultiplierPoint bonusMP, MultiplierPoint totalMP,,,,) = stakeManager.accounts(address(userVault)); (, uint256 balance, MultiplierPoint bonusMP, MultiplierPoint totalMP,,,,) =
stakeManager.accounts(address(userVault));
assertEq(balance, stakeAmount, "balance of user vault should be equal to stake amount after stake"); assertEq(balance, stakeAmount, "balance of user vault should be equal to stake amount after stake");
assertEq(bonusMP, stakeAmount, "bonusMP of user vault should be equal to stake amount after stake if no lock"); assertEq(bonusMP, stakeAmount, "bonusMP of user vault should be equal to stake amount after stake if no lock");
assertEq(totalMP, bonusMP, "totalMP of user vault should be equal to bonusMP after stake if no epochs passed"); assertEq(totalMP, bonusMP, "totalMP of user vault should be equal to bonusMP after stake if no epochs passed");
vm.prank(testUser); vm.prank(testUser);
userVault.lock(lockTime); userVault.lock(lockTime);
MultiplierPoint estimatedBonusMp = MultiplierPoint.wrap(stakeAmount) + stakeManager.calculateMPToMint(stakeAmount, lockTime); MultiplierPoint estimatedBonusMp =
MultiplierPoint.wrap(stakeAmount) + stakeManager.calculateMPToMint(stakeAmount, lockTime);
(, balance, bonusMP, totalMP,,,,) = stakeManager.accounts(address(userVault)); (, balance, bonusMP, totalMP,,,,) = stakeManager.accounts(address(userVault));
assertEq(balance, stakeAmount, "balance of user vault should be equal to stake amount after lock"); assertEq(balance, stakeAmount, "balance of user vault should be equal to stake amount after lock");
@ -357,7 +355,8 @@ contract LockTest is StakeManagerTest {
vm.startPrank(testUser); vm.startPrank(testUser);
userVault.lock(lockTime); userVault.lock(lockTime);
(, uint256 balance, MultiplierPoint bonusMP, MultiplierPoint totalMP,,,,) = stakeManager.accounts(address(userVault)); (, uint256 balance, MultiplierPoint bonusMP, MultiplierPoint totalMP,,,,) =
stakeManager.accounts(address(userVault));
console.log("balance", balance); console.log("balance", balance);
console.log("bonusMP", bonusMP); console.log("bonusMP", bonusMP);
@ -410,14 +409,16 @@ contract LockTest is StakeManagerTest {
uint256 stakeAmount = 100; uint256 stakeAmount = 100;
uint256 lockTime = stakeManager.MAX_LOCKUP_PERIOD(); uint256 lockTime = stakeManager.MAX_LOCKUP_PERIOD();
StakeVault userVault = _createStakingAccount(testUser, stakeAmount); StakeVault userVault = _createStakingAccount(testUser, stakeAmount);
(, uint256 balance, MultiplierPoint bonusMP, MultiplierPoint totalMP,,,,) = stakeManager.accounts(address(userVault)); (, uint256 balance, MultiplierPoint bonusMP, MultiplierPoint totalMP,,,,) =
stakeManager.accounts(address(userVault));
MultiplierPoint totalSupplyMPBefore = stakeManager.totalSupplyMP(); MultiplierPoint totalSupplyMPBefore = stakeManager.totalSupplyMP();
vm.startPrank(testUser); vm.startPrank(testUser);
userVault.lock(lockTime); userVault.lock(lockTime);
//solhint-disable-next-line max-line-length //solhint-disable-next-line max-line-length
(, uint256 newBalance, MultiplierPoint newBonusMP, MultiplierPoint newCurrentMP,,,,) = stakeManager.accounts(address(userVault)); (, uint256 newBalance, MultiplierPoint newBonusMP, MultiplierPoint newCurrentMP,,,,) =
stakeManager.accounts(address(userVault));
MultiplierPoint totalSupplyMPAfter = stakeManager.totalSupplyMP(); MultiplierPoint totalSupplyMPAfter = stakeManager.totalSupplyMP();
assertGt(totalSupplyMPAfter, totalSupplyMPBefore, "totalSupplyMP"); assertGt(totalSupplyMPAfter, totalSupplyMPBefore, "totalSupplyMP");
assertGt(newBonusMP, bonusMP, "bonusMP"); assertGt(newBonusMP, bonusMP, "bonusMP");
@ -571,7 +572,8 @@ contract ExecuteAccountTest is StakeManagerTest {
//expected MP is, the starting totalMP + the calculatedMPToMint of user balance for one EPOCH_SIZE multiplied by //expected MP is, the starting totalMP + the calculatedMPToMint of user balance for one EPOCH_SIZE multiplied by
// 2. // 2.
MultiplierPoint expectedMP = totalMP + (stakeManager.calculateMPToMint(stakeAmount, stakeManager.EPOCH_SIZE()) * MultiplierPoint.wrap(2)); MultiplierPoint expectedMP =
totalMP + (stakeManager.calculateMPToMint(stakeAmount, stakeManager.EPOCH_SIZE()) * MultiplierPoint.wrap(2));
stakeManager.executeAccount(address(userVaults[0]), stakeManager.currentEpoch() + 1); stakeManager.executeAccount(address(userVaults[0]), stakeManager.currentEpoch() + 1);
(,,, totalMP, lastMint,, epoch,) = stakeManager.accounts(address(userVaults[0])); (,,, totalMP, lastMint,, epoch,) = stakeManager.accounts(address(userVaults[0]));
@ -600,8 +602,8 @@ contract ExecuteAccountTest is StakeManagerTest {
for (uint256 j = 0; j < userVaults.length; j++) { for (uint256 j = 0; j < userVaults.length; j++) {
//solhint-disable-next-line max-line-length //solhint-disable-next-line max-line-length
(address rewardAddress,,, MultiplierPoint totalMPBefore, uint256 lastMintBefore,, uint256 epochBefore,) = (address rewardAddress,,, MultiplierPoint totalMPBefore, uint256 lastMintBefore,, uint256 epochBefore,)
stakeManager.accounts(address(userVaults[j])); = stakeManager.accounts(address(userVaults[j]));
uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress); uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress);
console.log("-Vault number", j); console.log("-Vault number", j);
console.log("--=====BEFORE====="); console.log("--=====BEFORE=====");
@ -612,7 +614,8 @@ contract ExecuteAccountTest is StakeManagerTest {
console.log("--=====AFTER======"); console.log("--=====AFTER======");
stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1); stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1);
//solhint-disable-next-line max-line-length //solhint-disable-next-line max-line-length
(,,, MultiplierPoint totalMP, uint256 lastMint,, uint256 epoch,) = stakeManager.accounts(address(userVaults[j])); (,,, MultiplierPoint totalMP, uint256 lastMint,, uint256 epoch,) =
stakeManager.accounts(address(userVaults[j]));
uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress); uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress);
console.log("---### deltaTime :", lastMint - lastMintBefore); console.log("---### deltaTime :", lastMint - lastMintBefore);
console.log("---### totalMP :", totalMP); console.log("---### totalMP :", totalMP);
@ -636,9 +639,10 @@ contract ExecuteAccountTest is StakeManagerTest {
function test_ShouldNotMintMoreThanCap() public { function test_ShouldNotMintMoreThanCap() public {
uint256 stakeAmount = 10_000_000_000; uint256 stakeAmount = 10_000_000_000;
uint256 epochsAmountToReachCap = MultiplierPoint.unwrap(stakeManager.calculateMPToMint( uint256 epochsAmountToReachCap = MultiplierPoint.unwrap(
stakeAmount, stakeManager.MAX_BOOST() * stakeManager.YEAR() stakeManager.calculateMPToMint(stakeAmount, stakeManager.MAX_BOOST() * stakeManager.YEAR())
) / stakeManager.calculateMPToMint(stakeAmount, stakeManager.EPOCH_SIZE())); / stakeManager.calculateMPToMint(stakeAmount, stakeManager.EPOCH_SIZE())
);
deal(stakeToken, testUser, stakeAmount); deal(stakeToken, testUser, stakeAmount);
@ -670,13 +674,14 @@ contract ExecuteAccountTest is StakeManagerTest {
vm.warp(stakeManager.epochEnd()); vm.warp(stakeManager.epochEnd());
stakeManager.executeEpoch(); stakeManager.executeEpoch();
for (uint256 j = 0; j < userVaults.length; j++) { for (uint256 j = 0; j < userVaults.length; j++) {
(address rewardAddress,,, MultiplierPoint totalMPBefore, uint256 lastMintBefore,, uint256 epochBefore,) = (address rewardAddress,,, MultiplierPoint totalMPBefore, uint256 lastMintBefore,, uint256 epochBefore,)
stakeManager.accounts(address(userVaults[j])); = stakeManager.accounts(address(userVaults[j]));
uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress); uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress);
stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1); stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1);
//solhint-disable-next-line max-line-length //solhint-disable-next-line max-line-length
(,,, MultiplierPoint totalMP, uint256 lastMint,, uint256 epoch,) = stakeManager.accounts(address(userVaults[j])); (,,, MultiplierPoint totalMP, uint256 lastMint,, uint256 epoch,) =
stakeManager.accounts(address(userVaults[j]));
uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress); uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress);
assertEq(epoch, epochBefore + 1, "must increase epoch"); assertEq(epoch, epochBefore + 1, "must increase epoch");
assertGt(totalMP, totalMPBefore, "must increase MPs"); assertGt(totalMP, totalMPBefore, "must increase MPs");
@ -692,13 +697,14 @@ contract ExecuteAccountTest is StakeManagerTest {
vm.warp(stakeManager.epochEnd()); vm.warp(stakeManager.epochEnd());
stakeManager.executeEpoch(); stakeManager.executeEpoch();
for (uint256 j = 0; j < userVaults.length; j++) { for (uint256 j = 0; j < userVaults.length; j++) {
(address rewardAddress,,, MultiplierPoint totalMPBefore, uint256 lastMintBefore,, uint256 epochBefore,) = (address rewardAddress,,, MultiplierPoint totalMPBefore, uint256 lastMintBefore,, uint256 epochBefore,)
stakeManager.accounts(address(userVaults[j])); = stakeManager.accounts(address(userVaults[j]));
uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress); uint256 rewardsBefore = ERC20(stakeToken).balanceOf(rewardAddress);
stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1); stakeManager.executeAccount(address(userVaults[j]), epochBefore + 1);
//solhint-disable-next-line max-line-length //solhint-disable-next-line max-line-length
(,,, MultiplierPoint totalMP, uint256 lastMint,, uint256 epoch,) = stakeManager.accounts(address(userVaults[j])); (,,, MultiplierPoint totalMP, uint256 lastMint,, uint256 epoch,) =
stakeManager.accounts(address(userVaults[j]));
uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress); uint256 rewards = ERC20(stakeToken).balanceOf(rewardAddress);
assertEq(lastMint, lastMintBefore + stakeManager.EPOCH_SIZE(), "must increaase lastMint"); assertEq(lastMint, lastMintBefore + stakeManager.EPOCH_SIZE(), "must increaase lastMint");
assertEq(epoch, epochBefore + 1, "must increase epoch"); assertEq(epoch, epochBefore + 1, "must increase epoch");
@ -779,9 +785,10 @@ contract UserFlowsTest is StakeManagerTest {
userVaults.push( userVaults.push(
_createStakingAccount(makeAddr(string(abi.encode(keccak256(abi.encode(accountNum))))), thisAccStake, 0) _createStakingAccount(makeAddr(string(abi.encode(keccak256(abi.encode(accountNum))))), thisAccStake, 0)
); );
uint256 thisAccReachCapIn = MultiplierPoint.unwrap(stakeManager.calculateMPToMint( uint256 thisAccReachCapIn = MultiplierPoint.unwrap(
thisAccStake, stakeManager.MAX_BOOST() * stakeManager.YEAR() stakeManager.calculateMPToMint(thisAccStake, stakeManager.MAX_BOOST() * stakeManager.YEAR())
) / stakeManager.calculateMPToMint(thisAccStake, stakeManager.EPOCH_SIZE())); / stakeManager.calculateMPToMint(thisAccStake, stakeManager.EPOCH_SIZE())
);
if (thisAccReachCapIn > epochsAmountToReachCap) { if (thisAccReachCapIn > epochsAmountToReachCap) {
epochsAmountToReachCap = thisAccReachCapIn; //uses the amount to reach cap from the account that takes epochsAmountToReachCap = thisAccReachCapIn; //uses the amount to reach cap from the account that takes
// longer to reach cap // longer to reach cap