Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(RewardStreamerMP): rename user vars to account #62

Merged
merged 1 commit into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions .gas-report
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@
| Deployment Cost | Deployment Size | | | | |
| 1115122 | 5026 | | | | |
| Function Name | min | avg | median | max | # calls |
| MAX_LOCKING_PERIOD | 228 | 228 | 228 | 228 | 22 |
| MAX_LOCKING_PERIOD | 273 | 273 | 273 | 273 | 22 |
| MAX_MULTIPLIER | 252 | 252 | 252 | 252 | 28 |
| MIN_LOCKING_PERIOD | 229 | 229 | 229 | 229 | 11 |
| MIN_LOCKING_PERIOD | 273 | 273 | 273 | 273 | 11 |
| MP_RATE_PER_YEAR | 231 | 231 | 231 | 231 | 3 |
| SCALE_FACTOR | 251 | 251 | 251 | 251 | 39 |
| accountedRewards | 373 | 931 | 373 | 2373 | 68 |
| getUserInfo | 1576 | 1576 | 1576 | 1576 | 65 |
| rewardIndex | 373 | 402 | 373 | 2373 | 68 |
| stake | 168040 | 217000 | 228839 | 249323 | 46 |
| totalMP | 330 | 330 | 330 | 330 | 71 |
| totalMaxMP | 329 | 329 | 329 | 329 | 71 |
| totalStaked | 373 | 373 | 373 | 373 | 71 |
| unstake | 75511 | 103924 | 91588 | 134250 | 13 |
| updateGlobalState | 30008 | 55589 | 47387 | 80335 | 25 |
| updateUserMP | 34631 | 36869 | 37133 | 37133 | 19 |
| SCALE_FACTOR | 229 | 229 | 229 | 229 | 39 |
| accountedRewards | 351 | 909 | 351 | 2351 | 68 |
| getAccount | 1574 | 1574 | 1574 | 1574 | 65 |
| rewardIndex | 351 | 380 | 351 | 2351 | 68 |
| stake | 168062 | 217022 | 228861 | 249345 | 46 |
| totalMP | 374 | 374 | 374 | 374 | 71 |
| totalMaxMP | 351 | 351 | 351 | 351 | 71 |
| totalStaked | 330 | 330 | 330 | 330 | 71 |
| unstake | 75493 | 103902 | 91566 | 134228 | 13 |
| updateAccountMP | 34610 | 36848 | 37112 | 37112 | 19 |
| updateGlobalState | 29986 | 55567 | 47365 | 80313 | 25 |


| src/XPNFTToken.sol:XPNFTToken contract | | | | | |
Expand Down
64 changes: 32 additions & 32 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
IntegrationTest:testStake() (gas: 1376278)
IntegrationTest:testStake() (gas: 1376068)
NFTMetadataGeneratorSVGTest:testGenerateMetadata() (gas: 92874)
NFTMetadataGeneratorSVGTest:testSetImageStrings() (gas: 60081)
NFTMetadataGeneratorSVGTest:testSetImageStringsRevert() (gas: 35818)
NFTMetadataGeneratorURLTest:testGenerateMetadata() (gas: 109345)
NFTMetadataGeneratorURLTest:testSetBaseURL() (gas: 50653)
NFTMetadataGeneratorURLTest:testSetBaseURLRevert() (gas: 35993)
RewardsStreamerTest:testStake() (gas: 869874)
StakeTest:test_StakeMultipleAccounts() (gas: 439306)
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 586550)
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 744051)
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 448548)
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 469950)
StakeTest:test_StakeOneAccount() (gas: 268069)
StakeTest:test_StakeOneAccountAndRewards() (gas: 415355)
StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 473161)
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 468272)
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 283222)
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 283254)
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 283321)
UnstakeTest:test_StakeMultipleAccounts() (gas: 439328)
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 586572)
UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 744073)
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 448592)
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 469972)
UnstakeTest:test_StakeOneAccount() (gas: 268092)
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 415333)
UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 473205)
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 468229)
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 283267)
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 283254)
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 283320)
UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 472749)
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 616899)
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 938271)
UnstakeTest:test_UnstakeOneAccount() (gas: 446601)
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 467894)
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 557494)
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 490861)
StakeTest:test_StakeMultipleAccounts() (gas: 439303)
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 586526)
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 743870)
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 448640)
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 470042)
StakeTest:test_StakeOneAccount() (gas: 268046)
StakeTest:test_StakeOneAccountAndRewards() (gas: 415311)
StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 473030)
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 468097)
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 283269)
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 283300)
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 283411)
UnstakeTest:test_StakeMultipleAccounts() (gas: 439325)
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 586548)
UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 743892)
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 448639)
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 470064)
UnstakeTest:test_StakeOneAccount() (gas: 268069)
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 415289)
UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 473074)
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 468099)
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 283314)
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 283300)
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 283389)
UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 472770)
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 616827)
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 938166)
UnstakeTest:test_UnstakeOneAccount() (gas: 446562)
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 467764)
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 557405)
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 490824)
XPNFTTokenTest:testApproveNotAllowed() (gas: 10507)
XPNFTTokenTest:testGetApproved() (gas: 10531)
XPNFTTokenTest:testIsApprovedForAll() (gas: 10705)
Expand Down
16 changes: 8 additions & 8 deletions certora/specs/RewardsStreamerMP.spec
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,41 @@ using ERC20A as staked;

methods {
function totalStaked() external returns (uint256) envfree;
function users(address) external returns (uint256, uint256, uint256, uint256, uint256, uint256) envfree;
function accounts(address) external returns (uint256, uint256, uint256, uint256, uint256, uint256) envfree;
function lastMPUpdatedTime() external returns (uint256) envfree;
function updateGlobalState() external;
function updateUserMP(address userAddress) external;
function updateAccountMP(address accountAddress) external;
}

ghost mathint sumOfBalances {
init_state axiom sumOfBalances == 0;
}

hook Sstore users[KEY address account].stakedBalance uint256 newValue (uint256 oldValue) {
hook Sstore accounts[KEY address account].stakedBalance uint256 newValue (uint256 oldValue) {
sumOfBalances = sumOfBalances - oldValue + newValue;
}

function getAccountMaxMP(address account) returns uint256 {
uint256 maxMP;
_, _, _, maxMP, _, _ = streamer.users(account);
_, _, _, maxMP, _, _ = streamer.accounts(account);
return maxMP;
}

function getAccountMP(address account) returns uint256 {
uint256 accountMP;
_, _, accountMP, _, _, _ = streamer.users(account);
_, _, accountMP, _, _, _ = streamer.accounts(account);
return accountMP;
}

function getAccountStakedBalance(address account) returns uint256 {
uint256 stakedBalance;
stakedBalance, _, _, _, _, _ = streamer.users(account);
stakedBalance, _, _, _, _, _ = streamer.accounts(account);
return stakedBalance;
}

function getAccountLockUntil(address account) returns uint256 {
uint256 lockUntil;
_, _, _, _, _, lockUntil = streamer.users(account);
_, _, _, _, _, lockUntil = streamer.accounts(account);
return lockUntil;
}

Expand All @@ -63,7 +63,7 @@ rule stakingMintsMultiplierPoints1To1Ratio {
require getAccountLockUntil(e.msg.sender) <= e.block.timestamp;

updateGlobalState(e);
updateUserMP(e, e.msg.sender);
updateAccountMP(e, e.msg.sender);
uint256 t = lastMPUpdatedTime();

multiplierPointsBefore = getAccountMP(e.msg.sender);
Expand Down
116 changes: 58 additions & 58 deletions src/RewardsStreamerMP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ contract RewardsStreamerMP is ReentrancyGuard {
uint256 public accountedRewards;
uint256 public lastMPUpdatedTime;

struct UserInfo {
struct Account {
uint256 stakedBalance;
uint256 userRewardIndex;
uint256 userMP;
uint256 accountRewardIndex;
uint256 accountMP;
uint256 maxMP;
uint256 lastMPUpdateTime;
uint256 lockUntil;
}

mapping(address account => UserInfo data) public users;
mapping(address account => Account data) public accounts;

constructor(address _stakingToken, address _rewardToken) {
STAKING_TOKEN = IERC20(_stakingToken);
Expand All @@ -57,24 +57,24 @@ contract RewardsStreamerMP is ReentrancyGuard {
}

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

UserInfo storage user = users[msg.sender];
if (user.lockUntil != 0 && user.lockUntil > block.timestamp) {
Account storage account = accounts[msg.sender];
if (account.lockUntil != 0 && account.lockUntil > block.timestamp) {
revert StakingManager__CannotRestakeWithLockedFunds();
}

uint256 userRewards = calculateUserRewards(msg.sender);
if (userRewards > 0) {
distributeRewards(msg.sender, userRewards);
uint256 accountRewards = calculateAccountRewards(msg.sender);
if (accountRewards > 0) {
distributeRewards(msg.sender, accountRewards);
}

bool success = STAKING_TOKEN.transferFrom(msg.sender, address(this), amount);
if (!success) {
revert StakingManager__TransferFailed();
}

user.stakedBalance += amount;
account.stakedBalance += amount;
totalStaked += amount;

uint256 initialMP = amount;
Expand All @@ -84,50 +84,50 @@ contract RewardsStreamerMP is ReentrancyGuard {
if (lockPeriod != 0) {
uint256 lockMultiplier = (lockPeriod * MAX_MULTIPLIER * SCALE_FACTOR) / MAX_LOCKING_PERIOD;
bonusMP = amount * lockMultiplier / SCALE_FACTOR;
user.lockUntil = block.timestamp + lockPeriod;
account.lockUntil = block.timestamp + lockPeriod;
} else {
user.lockUntil = 0;
account.lockUntil = 0;
}

uint256 userMaxMP = initialMP + bonusMP + potentialMP;
uint256 userMP = initialMP + bonusMP;
uint256 accountMaxMP = initialMP + bonusMP + potentialMP;
uint256 accountMP = initialMP + bonusMP;

user.userMP += userMP;
totalMP += userMP;
account.accountMP += accountMP;
totalMP += accountMP;

user.maxMP += userMaxMP;
totalMaxMP += userMaxMP;
account.maxMP += accountMaxMP;
totalMaxMP += accountMaxMP;

user.userRewardIndex = rewardIndex;
user.lastMPUpdateTime = block.timestamp;
account.accountRewardIndex = rewardIndex;
account.lastMPUpdateTime = block.timestamp;
}

function unstake(uint256 amount) external nonReentrant {
UserInfo storage user = users[msg.sender];
if (amount > user.stakedBalance) {
Account storage account = accounts[msg.sender];
if (amount > account.stakedBalance) {
revert StakingManager__InsufficientBalance();
}

if (block.timestamp < user.lockUntil) {
if (block.timestamp < account.lockUntil) {
revert StakingManager__TokensAreLocked();
}

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

uint256 userRewards = calculateUserRewards(msg.sender);
if (userRewards > 0) {
distributeRewards(msg.sender, userRewards);
uint256 accountRewards = calculateAccountRewards(msg.sender);
if (accountRewards > 0) {
distributeRewards(msg.sender, accountRewards);
}

uint256 previousStakedBalance = user.stakedBalance;
uint256 previousStakedBalance = account.stakedBalance;

uint256 mpToReduce = (user.userMP * amount * SCALE_FACTOR) / (previousStakedBalance * SCALE_FACTOR);
uint256 maxMPToReduce = (user.maxMP * amount * SCALE_FACTOR) / (previousStakedBalance * SCALE_FACTOR);
uint256 mpToReduce = (account.accountMP * amount * SCALE_FACTOR) / (previousStakedBalance * SCALE_FACTOR);
uint256 maxMPToReduce = (account.maxMP * amount * SCALE_FACTOR) / (previousStakedBalance * SCALE_FACTOR);

user.stakedBalance -= amount;
user.userMP -= mpToReduce;
user.maxMP -= maxMPToReduce;
account.stakedBalance -= amount;
account.accountMP -= mpToReduce;
account.maxMP -= maxMPToReduce;
totalMP -= mpToReduce;
totalMaxMP -= maxMPToReduce;
totalStaked -= amount;
Expand All @@ -137,7 +137,7 @@ contract RewardsStreamerMP is ReentrancyGuard {
revert StakingManager__TransferFailed();
}

user.userRewardIndex = rewardIndex;
account.accountRewardIndex = rewardIndex;
}

function _updateGlobalState() internal {
Expand Down Expand Up @@ -193,38 +193,38 @@ contract RewardsStreamerMP is ReentrancyGuard {
}
}

function _updateUserMP(address userAddress) internal {
UserInfo storage user = users[userAddress];
function _updateAccountMP(address accountAddress) internal {
Account storage account = accounts[accountAddress];

if (user.maxMP == 0 || user.stakedBalance == 0) {
user.lastMPUpdateTime = block.timestamp;
if (account.maxMP == 0 || account.stakedBalance == 0) {
account.lastMPUpdateTime = block.timestamp;
return;
}

uint256 timeDiff = block.timestamp - user.lastMPUpdateTime;
uint256 timeDiff = block.timestamp - account.lastMPUpdateTime;
if (timeDiff == 0) {
return;
}

uint256 accruedMP = (timeDiff * user.stakedBalance * MP_RATE_PER_YEAR) / (365 days * SCALE_FACTOR);
uint256 accruedMP = (timeDiff * account.stakedBalance * MP_RATE_PER_YEAR) / (365 days * SCALE_FACTOR);

if (user.userMP + accruedMP > user.maxMP) {
accruedMP = user.maxMP - user.userMP;
if (account.accountMP + accruedMP > account.maxMP) {
accruedMP = account.maxMP - account.accountMP;
}

user.userMP += accruedMP;
user.lastMPUpdateTime = block.timestamp;
account.accountMP += accruedMP;
account.lastMPUpdateTime = block.timestamp;
}

function updateUserMP(address userAddress) external {
_updateUserMP(userAddress);
function updateAccountMP(address accountAddress) external {
_updateAccountMP(accountAddress);
}

function calculateUserRewards(address userAddress) public view returns (uint256) {
UserInfo storage user = users[userAddress];
uint256 userWeight = user.stakedBalance + user.userMP;
uint256 deltaRewardIndex = rewardIndex - user.userRewardIndex;
return (userWeight * deltaRewardIndex) / SCALE_FACTOR;
function calculateAccountRewards(address accountAddress) public view returns (uint256) {
Account storage account = accounts[accountAddress];
uint256 accountWeight = account.stakedBalance + account.accountMP;
uint256 deltaRewardIndex = rewardIndex - account.accountRewardIndex;
return (accountWeight * deltaRewardIndex) / SCALE_FACTOR;
}

function distributeRewards(address to, uint256 amount) internal {
Expand All @@ -242,15 +242,15 @@ contract RewardsStreamerMP is ReentrancyGuard {
}
}

function getStakedBalance(address userAddress) external view returns (uint256) {
return users[userAddress].stakedBalance;
function getStakedBalance(address accountAddress) external view returns (uint256) {
return accounts[accountAddress].stakedBalance;
}

function getPendingRewards(address userAddress) external view returns (uint256) {
return calculateUserRewards(userAddress);
function getPendingRewards(address accountAddress) external view returns (uint256) {
return calculateAccountRewards(accountAddress);
}

function getUserInfo(address userAddress) external view returns (UserInfo memory) {
return users[userAddress];
function getAccount(address accountAddress) external view returns (Account memory) {
return accounts[accountAddress];
}
}
Loading
Loading