From 3e691520775e74b20f0fcbe8ae01425deab3da38 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Mon, 30 Sep 2024 16:16:57 +0530 Subject: [PATCH 01/49] Add separate staking contracts --- contracts/PushStaking/PushStaking.sol | 418 +++++++++++++++++++ contracts/PushStaking/PushStakingAdmin.sol | 9 + contracts/PushStaking/PushStakingProxy.sol | 37 ++ contracts/PushStaking/PushStakingStorage.sol | 35 ++ 4 files changed, 499 insertions(+) create mode 100644 contracts/PushStaking/PushStaking.sol create mode 100644 contracts/PushStaking/PushStakingAdmin.sol create mode 100644 contracts/PushStaking/PushStakingProxy.sol create mode 100644 contracts/PushStaking/PushStakingStorage.sol diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol new file mode 100644 index 00000000..1c92201e --- /dev/null +++ b/contracts/PushStaking/PushStaking.sol @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: SEE LICENSE IN LICENSE +pragma solidity ^0.8.20; + +import "./PushStakingStorage.sol"; +import "../interfaces/IPUSH.sol"; +import { IPushCoreStaking } from "../interfaces/IPushCoreStaking.sol"; +import { Errors } from "../libraries/Errors.sol"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; + +contract PushFeePoolStaking is Initializable, PushStakingStorage { + using SafeERC20 for IERC20; + + event Staked(address indexed user, uint256 indexed amountStaked); + event Unstaked(address indexed user, uint256 indexed amountUnstaked); + event RewardsHarvested(address indexed user, uint256 indexed rewardAmount, uint256 fromEpoch, uint256 tillEpoch); + + function initialize( + address _pushChannelAdmin, + address _core, + address _pushToken + ) + public + initializer + { + pushChannelAdmin = _pushChannelAdmin; + governance = _pushChannelAdmin; + core = _core; + PUSH_TOKEN_ADDRESS = _pushToken; + } + + modifier onlyPushChannelAdmin() { + if (msg.sender != pushChannelAdmin) { + revert Errors.CallerNotAdmin(); + } + _; + } + + modifier onlyGovernance() { + if (msg.sender != governance) { + revert Errors.CallerNotGovernance(); + } + _; + } + + modifier isMigrated() { + if (migrated) { + revert Errors.PushStaking_MigrationCompleted(); + } + _; + } + + function setGovernanceAddress(address _governanceAddress) external onlyPushChannelAdmin { + governance = _governanceAddress; + } + + function initializeStake() external { + require( + genesisEpoch == 0, + "PushCoreV2::initializeStake: Already Initialized" + ); + genesisEpoch = block.number; + lastEpochInitialized = genesisEpoch; + + _stake(core, 1e18); + } + + /* + * Fetching shares for a wallet + * 1. Internal helper function + * 2. helps in getting the shares to be assigned for a wallet based on params passed in this function + */ + function getSharesAmount( + uint256 _totalShares, + StakingTypes.Percentage memory _percentage + ) + public + pure + returns (uint256 sharesToBeAllocated) + { + if (_percentage.percentageNumber / 10 ** _percentage.decimalPlaces >= 100) revert Errors.InvalidArg_MoreThanExpected( 99,_percentage.decimalPlaces); + sharesToBeAllocated = (_percentage.percentageNumber * _totalShares) + / ((100 * (10 ** _percentage.decimalPlaces)) - _percentage.percentageNumber); + } + + /* + * Adding Wallet Share to a Wallet + * 1. addWalletShare(address wallet, uint256 percentageOfShares) + * 2. Can be called by governance. + * 3. Uses the formulae to derive the percent of shares to be assigned to a specific wallet + * 4. Updates WALLET_TOTAL_SHARES + * 5. Updates WalletToShares mapping + * 6. Emits out an event. + * 7. If a wallet has already has a share, then it acts as a "increase share" function. And the percenatge passed + * should be greater than the already assigned percentge. + */ + function addWalletShare(address _walletAddress, StakingTypes.Percentage memory _percentage) public onlyGovernance{ + uint oldTotalShare = WALLET_TOTAL_SHARES; + uint currentWalletShare = WalletToShares[_walletAddress]; + uint newTotalShare; + + if( currentWalletShare != 0) { + newTotalShare = oldTotalShare - currentWalletShare; + }else{ + newTotalShare = oldTotalShare; + } + uint256 sharesToBeAllocated = getSharesAmount(newTotalShare, _percentage); + if (sharesToBeAllocated < currentWalletShare) revert Errors.InvalidArg_LessThanExpected(currentWalletShare, sharesToBeAllocated); + WALLET_TOTAL_SHARES = newTotalShare + sharesToBeAllocated; + WalletToShares[_walletAddress] = sharesToBeAllocated; + } + /* + * Removing Wallet Share from a Wallet + * 1. removes the shares from a wallet completely + * 2. Can be called by governance. + * 3. Updates WALLET_TOTAL_SHARES + * 4. Emits out an event. + */ + function removeWalletShare(address _walletAddress) public onlyGovernance { + WalletToShares[FOUNDATION] += WalletToShares[_walletAddress]; + WalletToShares[_walletAddress] = 0; + } + + function decreaseWalletShare(address _walletAddress, StakingTypes.Percentage memory _percentage) external onlyGovernance{ + removeWalletShare(_walletAddress); + addWalletShare( _walletAddress, _percentage); + + } + + /* + *Reward Calculation for a Given Wallet + * 1. calculateWalletRewards(address wallet) + * 2. public helper function + * 3. Helps in calculating rewards for a specific wallet based on + * a. Their Wallet Share + * b. Total Wallet Shares + * c. Total Rewards available in WALLET_TOTAL_SHARES + * 4. Once calculated rewards for a sepcific wallet can be updated in WalletToRewards mapping + * 5. Reward can be calculated for wallets similar they are calculated for Token holders in a specific epoch. + * Reward for a Given Wallet X = ( Wallet Share of X / WALLET_TOTAL_SHARES) * WALLET_FEE_POOL + */ + //TODO logic yet to be finalized + function calculateWalletRewards(address _wallet) public returns(uint) { + return ( WalletToShares[_wallet] / WALLET_TOTAL_SHARES) * IPushCoreStaking(core).WALLET_FEE_POOL(); + } + /** + * @notice Function to return User's Push Holder weight based on amount being staked & current block number + * + */ + function _returnPushTokenWeight( + address _account, + uint256 _amount, + uint256 _atBlock + ) + internal + view + returns (uint256) + { + return _amount * (_atBlock - IPUSH(PUSH_TOKEN_ADDRESS).holderWeight(_account)); + } + + /** + * @notice Returns the epoch ID based on the start and end block numbers passed as input + * + */ + function lastEpochRelative(uint256 _from, uint256 _to) public pure returns (uint256) { + if (_to < _from) { + revert Errors.InvalidArg_LessThanExpected(_from, _to); + } + return uint256((_to - _from) / epochDuration + 1); + } + + /** + * @notice Calculates and returns the claimable reward amount for a user at a given EPOCH ID. + * @dev Formulae for reward calculation: + * rewards = ( userStakedWeight at Epoch(n) * avalailable rewards at EPOCH(n) ) / totalStakedWeight at + * EPOCH(n) + * + */ + function calculateEpochRewards(address _user, uint256 _epochId) public view returns (uint256 rewards) { + rewards = (userFeesInfo[_user].epochToUserStakedWeight[_epochId] * epochRewards[_epochId]) + / epochToTotalStakedWeight[_epochId]; + } + + /** + * @notice Function to allow users to stake in the protocol + * @dev Records total Amount staked so far by a particular user + * Triggers weight adjustents functions + * @param _amount represents amount of tokens to be staked + * + */ + function stake(uint256 _amount) external { + _stake(msg.sender, _amount); + emit Staked(msg.sender, _amount); + } + + function _stake(address _staker, uint256 _amount) private { + uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); + uint256 blockNumberToConsider = genesisEpoch + (epochDuration * currentEpoch); + uint256 userWeight = _returnPushTokenWeight(_staker, _amount, blockNumberToConsider); + + IERC20(PUSH_TOKEN_ADDRESS).safeTransferFrom(msg.sender, core, _amount); + + userFeesInfo[_staker].stakedAmount = userFeesInfo[_staker].stakedAmount + _amount; + userFeesInfo[_staker].lastClaimedBlock = + userFeesInfo[_staker].lastClaimedBlock == 0 ? genesisEpoch : userFeesInfo[_staker].lastClaimedBlock; + totalStakedAmount += _amount; + // Adjust user and total rewards, piggyback method + _adjustUserAndTotalStake(_staker, userWeight, false); + } + + /** + * @notice Function to allow users to Unstake from the protocol + * @dev Allows stakers to claim rewards before unstaking their tokens + * Triggers weight adjustents functions + * Allows users to unstake all amount at once + * + */ + function unstake() external { + if (block.number <= userFeesInfo[msg.sender].lastStakedBlock + epochDuration) { + revert Errors.PushStaking_InvalidEpoch_LessThanExpected(); + } + if (userFeesInfo[msg.sender].stakedAmount == 0) { + revert Errors.UnauthorizedCaller(msg.sender); + } + harvestAll(); + uint256 stakedAmount = userFeesInfo[msg.sender].stakedAmount; + IPushCoreStaking(core).sendFunds(msg.sender, stakedAmount); + + // Adjust user and total rewards, piggyback method + _adjustUserAndTotalStake(msg.sender, userFeesInfo[msg.sender].stakedWeight, true); + + userFeesInfo[msg.sender].stakedAmount = 0; + userFeesInfo[msg.sender].stakedWeight = 0; + totalStakedAmount -= stakedAmount; + + emit Unstaked(msg.sender, stakedAmount); + } + + /** + * @notice Allows users to harvest/claim their earned rewards from the protocol + * @dev Computes nextFromEpoch and currentEpoch and uses them as startEPoch and endEpoch respectively. + * Rewards are claculated from start epoch till endEpoch(currentEpoch - 1). + * Once calculated, user's total claimed rewards and nextFromEpoch details is updated. + * + */ + function harvestAll() public { + uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); + + uint256 rewards = harvest(msg.sender, currentEpoch - 1); + IPushCoreStaking(core).sendFunds(msg.sender, rewards); + } + + /** + * @notice Allows paginated harvests for users between a particular number of epochs. + * @param _tillEpoch - the end epoch number till which rewards shall be counted. + * @dev _tillEpoch should never be equal to currentEpoch. + * Transfers rewards to caller and updates user's details. + * + */ + function harvestPaginated(uint256 _tillEpoch) external { + uint256 rewards = harvest(msg.sender, _tillEpoch); + IPushCoreStaking(core).sendFunds(msg.sender, rewards); + } + + /** + * @notice Allows Push Governance to harvest/claim the earned rewards for its stake in the protocol + * @param _tillEpoch - the end epoch number till which rewards shall be counted. + * @dev only accessible by Push Admin + * Unlike other harvest functions, this is designed to transfer rewards to Push Governance. + * + */ + function daoHarvestPaginated(uint256 _tillEpoch) external { + if (msg.sender != governance) { + revert Errors.CallerNotAdmin(); + } + uint256 rewards = harvest(core, _tillEpoch); + IPushCoreStaking(core).sendFunds(msg.sender, rewards); + } + + /** + * @notice Internal harvest function that is called for all types of harvest procedure. + * @param _user - The user address for which the rewards will be calculated. + * @param _tillEpoch - the end epoch number till which rewards shall be counted. + * @dev _tillEpoch should never be equal to currentEpoch. + * Transfers rewards to caller and updates user's details. + * + */ + function harvest(address _user, uint256 _tillEpoch) internal returns (uint256 rewards) { + IPUSH(PUSH_TOKEN_ADDRESS).resetHolderWeight(_user); + _adjustUserAndTotalStake(_user, 0, false); + + uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); + uint256 nextFromEpoch = lastEpochRelative(genesisEpoch, userFeesInfo[_user].lastClaimedBlock); + + if (currentEpoch <= _tillEpoch) { + revert Errors.PushStaking_InvalidEpoch_LessThanExpected(); + } + if (_tillEpoch < nextFromEpoch) { + revert Errors.InvalidArg_LessThanExpected(nextFromEpoch, _tillEpoch); + } + for (uint256 i = nextFromEpoch; i <= _tillEpoch; i++) { + uint256 claimableReward = calculateEpochRewards(_user, i); + rewards = rewards + claimableReward; + } + + usersRewardsClaimed[_user] = usersRewardsClaimed[_user] + rewards; + // set the lastClaimedBlock to blocknumer at the end of `_tillEpoch` + uint256 _epoch_to_block_number = genesisEpoch + _tillEpoch * epochDuration; + userFeesInfo[_user].lastClaimedBlock = _epoch_to_block_number; + + emit RewardsHarvested(_user, rewards, nextFromEpoch, _tillEpoch); + } + + /** + * @notice This functions helps in adjustment of user's as well as totalWeigts, both of which are imperative for + * reward calculation at a particular epoch. + * @dev Enables adjustments of user's stakedWeight, totalStakedWeight, epochToTotalStakedWeight as well as + * epochToTotalStakedWeight. + * triggers _setupEpochsReward() to adjust rewards for every epoch till the current epoch + * + * Includes 2 main cases of weight adjustments + * 1st Case: User stakes for the very first time: + * - Simply update userFeesInfo, totalStakedWeight and epochToTotalStakedWeight of currentEpoch + * + * 2nd Case: User is NOT staking for first time - 2 Subcases + * 2.1 Case: User stakes again but in Same Epoch + * - Increase user's stake and totalStakedWeight + * - Record the epochToUserStakedWeight for that epoch + * - Record the epochToTotalStakedWeight of that epoch + * + * 2.2 Case: - User stakes again but in different Epoch + * - Update the epochs between lastStakedEpoch & (currentEpoch - 1) with the old staked weight + * amounts + * - While updating epochs between lastStaked & current Epochs, if any epoch has zero value for + * totalStakedWeight, update it with current totalStakedWeight value of the protocol + * - For currentEpoch, initialize the epoch id with updated weight values for + * epochToUserStakedWeight & epochToTotalStakedWeight + */ + function _adjustUserAndTotalStake(address _user, uint256 _userWeight, bool isUnstake) internal { + uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); + _setupEpochsRewardAndWeights(_userWeight, currentEpoch, isUnstake); + uint256 userStakedWeight = userFeesInfo[_user].stakedWeight; + + // Initiating 1st Case: User stakes for first time + if (userStakedWeight == 0) { + userFeesInfo[_user].stakedWeight = _userWeight; + } else { + // Initiating 2.1 Case: User stakes again but in Same Epoch + uint256 lastStakedEpoch = lastEpochRelative(genesisEpoch, userFeesInfo[_user].lastStakedBlock); + if (currentEpoch == lastStakedEpoch) { + userFeesInfo[_user].stakedWeight = + isUnstake ? userStakedWeight - _userWeight : userStakedWeight + _userWeight; + } else { + // Initiating 2.2 Case: User stakes again but in Different Epoch + for (uint256 i = lastStakedEpoch; i <= currentEpoch; i++) { + if (i != currentEpoch) { + userFeesInfo[_user].epochToUserStakedWeight[i] = userStakedWeight; + } else { + userFeesInfo[_user].stakedWeight = + isUnstake ? userStakedWeight - _userWeight : userStakedWeight + _userWeight; + userFeesInfo[_user].epochToUserStakedWeight[i] = userFeesInfo[_user].stakedWeight; + } + } + } + } + + if (_userWeight != 0) { + userFeesInfo[_user].lastStakedBlock = block.number; + } + } + + /** + * @notice Internal function that allows setting up the rewards for specific EPOCH IDs + * @dev Initializes (sets reward) for every epoch ID that falls between the lastEpochInitialized and currentEpoch + * Reward amount for specific EPOCH Ids depends on newly available Protocol_Pool_Fees. + * - If no new fees was accumulated, rewards for particular epoch ids can be zero + * - Records the Pool_Fees value used as rewards. + * - Records the last epoch id whose rewards were set. + */ + function _setupEpochsRewardAndWeights(uint256 _userWeight, uint256 _currentEpoch, bool isUnstake) private { + uint256 _lastEpochInitiliazed = lastEpochRelative(genesisEpoch, lastEpochInitialized); + // Setting up Epoch Based Rewards + if (_currentEpoch > _lastEpochInitiliazed || _currentEpoch == 1) { + uint256 PROTOCOL_POOL_FEES = IPushCoreStaking(core).PROTOCOL_POOL_FEES(); + uint256 availableRewardsPerEpoch = (PROTOCOL_POOL_FEES - previouslySetEpochRewards); + uint256 _epochGap = _currentEpoch - _lastEpochInitiliazed; + + if (_epochGap > 1) { + epochRewards[_currentEpoch - 1] += availableRewardsPerEpoch; + } else { + epochRewards[_currentEpoch] += availableRewardsPerEpoch; + } + + lastEpochInitialized = block.number; + previouslySetEpochRewards = PROTOCOL_POOL_FEES; + } + // Setting up Epoch Based TotalWeight + if (lastTotalStakeEpochInitialized == 0 || lastTotalStakeEpochInitialized == _currentEpoch) { + epochToTotalStakedWeight[_currentEpoch] = isUnstake + ? epochToTotalStakedWeight[_currentEpoch] - _userWeight + : epochToTotalStakedWeight[_currentEpoch] + _userWeight; + } else { + for (uint256 i = lastTotalStakeEpochInitialized + 1; i <= _currentEpoch - 1; i++) { + if (epochToTotalStakedWeight[i] == 0) { + epochToTotalStakedWeight[i] = epochToTotalStakedWeight[lastTotalStakeEpochInitialized]; + } + } + + epochToTotalStakedWeight[_currentEpoch] = isUnstake + ? epochToTotalStakedWeight[lastTotalStakeEpochInitialized] - _userWeight + : epochToTotalStakedWeight[lastTotalStakeEpochInitialized] + _userWeight; + } + lastTotalStakeEpochInitialized = _currentEpoch; + } +} diff --git a/contracts/PushStaking/PushStakingAdmin.sol b/contracts/PushStaking/PushStakingAdmin.sol new file mode 100644 index 00000000..14d1dbbd --- /dev/null +++ b/contracts/PushStaking/PushStakingAdmin.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +contract PushStakingAdmin is ProxyAdmin { + constructor(address _pushChannelAdmin) ProxyAdmin() { } +} diff --git a/contracts/PushStaking/PushStakingProxy.sol b/contracts/PushStaking/PushStakingProxy.sol new file mode 100644 index 00000000..593d6b82 --- /dev/null +++ b/contracts/PushStaking/PushStakingProxy.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +contract PushStakingProxy is TransparentUpgradeableProxy { + constructor( + address _logic, + address _governance, + address _pushChannelAdmin, + address _core, + address _pushTokenAddress, + uint256 _genesisEpoch, + uint256 _lastEpochInitialized, + uint256 _lastTotalStakeEpochInitialized, + uint256 _totalStakedAmount, + uint256 _previouslySetEpochRewards + ) + payable + TransparentUpgradeableProxy( + _logic, + _governance, + abi.encodeWithSignature( + "initialize(address,address,address,uint256,uint256,uint256,uint256,uint256)", + _pushChannelAdmin, + _core, + _pushTokenAddress, + _genesisEpoch, + _lastEpochInitialized, + _lastTotalStakeEpochInitialized, + _totalStakedAmount, + _previouslySetEpochRewards + ) + ) + { } +} diff --git a/contracts/PushStaking/PushStakingStorage.sol b/contracts/PushStaking/PushStakingStorage.sol new file mode 100644 index 00000000..57348375 --- /dev/null +++ b/contracts/PushStaking/PushStakingStorage.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.8.20; + +import { StakingTypes } from "../libraries/DataTypes.sol"; + +contract PushStakingStorage { + /** + * Staking V2 state variables * + */ + mapping(address => uint256) public usersRewardsClaimed; + + uint256 public genesisEpoch; // Block number at which Stakig starts + uint256 lastEpochInitialized; // The last EPOCH ID initialized with the respective epoch rewards + uint256 lastTotalStakeEpochInitialized; // The last EPOCH ID initialized with the respective total staked weight + uint256 public totalStakedAmount; // Total token weight staked in Protocol at any given time + uint256 public previouslySetEpochRewards; // Amount of rewards set in last initialized epoch + uint256 public constant epochDuration = 21 * 7156; // 21 * number of blocks per day(7156) ~ 20 day approx + uint256 public WALLET_TOTAL_SHARES; //Total Sga + + address public pushChannelAdmin; + address public PUSH_TOKEN_ADDRESS; + address public governance; + address public core; + address public FOUNDATION; + + /// @notice Stores all the individual epoch rewards + mapping(uint256 => uint256) public epochRewards; + /// @notice Stores User's Fees Details + mapping(address => StakingTypes.UserFessInfo) public userFeesInfo; + /// @notice Stores the total staked weight at a specific epoch. + mapping(uint256 => uint256) public epochToTotalStakedWeight; + ///@notice Stores the shares acquired by a given wallet + mapping(address wallet => uint256 sharesAmount) public WalletToShares ; + mapping(address wallet => uint256 sharesAmount) public WalletToRewards ; + bool migrated; +} From 373fbc32ddbc1be61ad6080681f626d34d363afe Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Mon, 30 Sep 2024 16:17:31 +0530 Subject: [PATCH 02/49] separate interface for interactions --- contracts/interfaces/IPushCoreStaking.sol | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 contracts/interfaces/IPushCoreStaking.sol diff --git a/contracts/interfaces/IPushCoreStaking.sol b/contracts/interfaces/IPushCoreStaking.sol new file mode 100644 index 00000000..bdcb3670 --- /dev/null +++ b/contracts/interfaces/IPushCoreStaking.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.8.20; + +interface IPushCoreStaking { + function sendFunds(address _user, uint256 _amount) external; + + function PROTOCOL_POOL_FEES() external view returns (uint256); + function WALLET_FEE_POOL() external view returns (uint256); +} \ No newline at end of file From 4375c5ae91da19ee06797fdfa070df2a12c3500d Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Mon, 30 Sep 2024 16:17:56 +0530 Subject: [PATCH 03/49] minor updates for compatibility --- contracts/libraries/DataTypes.sol | 4 ++++ contracts/mocks/PushCoreMock.sol | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/contracts/libraries/DataTypes.sol b/contracts/libraries/DataTypes.sol index c0fa7f03..10b240c6 100644 --- a/contracts/libraries/DataTypes.sol +++ b/contracts/libraries/DataTypes.sol @@ -102,6 +102,10 @@ library StakingTypes { ///@notice Weight of staked amount of a user w.r.t total staked in a single epoch mapping(uint256 => uint256) epochToUserStakedWeight; } + struct Percentage { + uint256 percentageNumber; + uint256 decimalPlaces; + } } library CrossChainRequestTypes { diff --git a/contracts/mocks/PushCoreMock.sol b/contracts/mocks/PushCoreMock.sol index 0fb644e4..156a51fc 100644 --- a/contracts/mocks/PushCoreMock.sol +++ b/contracts/mocks/PushCoreMock.sol @@ -47,7 +47,7 @@ contract PushCoreMock is PushCoreV3 { // setup addresses pushChannelAdmin = _pushChannelAdmin; governance = _pushChannelAdmin; // Will be changed on-Chain governance Address later - daiAddress = _daiAddress; + // daiAddress = _daiAddress; aDaiAddress = _aDaiAddress; WETH_ADDRESS = _wethAddress; REFERRAL_CODE = _referralCode; @@ -60,8 +60,8 @@ contract PushCoreMock is PushCoreV3 { ADD_CHANNEL_MIN_FEES = 50 ether; // can never be below MIN_POOL_CONTRIBUTION ADJUST_FOR_FLOAT = 10 ** 7; - groupLastUpdate = block.number; - groupNormalizedWeight = ADJUST_FOR_FLOAT; // Always Starts with 1 * ADJUST FOR FLOAT + // groupLastUpdate = block.number; + // groupNormalizedWeight = ADJUST_FOR_FLOAT; // Always Starts with 1 * ADJUST FOR FLOAT // Create Channel success = true; From d6f5c6cdce77bb8cebde51017035437fc8cd0a4a Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Mon, 30 Sep 2024 16:18:26 +0530 Subject: [PATCH 04/49] reverting the changes done for OZ-V5 --- contracts/PushComm/EPNSCommAdmin.sol | 4 +--- contracts/PushCore/EPNSCoreAdmin.sol | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/contracts/PushComm/EPNSCommAdmin.sol b/contracts/PushComm/EPNSCommAdmin.sol index c304396a..78193dab 100644 --- a/contracts/PushComm/EPNSCommAdmin.sol +++ b/contracts/PushComm/EPNSCommAdmin.sol @@ -4,6 +4,4 @@ pragma solidity ^0.8.20; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -contract EPNSCommAdmin is ProxyAdmin { - constructor(address _pushChannelAdmin) public ProxyAdmin() { } -} +contract EPNSCommAdmin is ProxyAdmin {} diff --git a/contracts/PushCore/EPNSCoreAdmin.sol b/contracts/PushCore/EPNSCoreAdmin.sol index fa2faeb3..28b150ab 100644 --- a/contracts/PushCore/EPNSCoreAdmin.sol +++ b/contracts/PushCore/EPNSCoreAdmin.sol @@ -4,6 +4,4 @@ pragma solidity ^0.8.20; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -contract EPNSCoreAdmin is ProxyAdmin { - constructor(address _pushChannelAdmin) public ProxyAdmin() { } -} +contract EPNSCoreAdmin is ProxyAdmin {} From 8bd9f1014956d0ae124e40bfe9f3df7018d60c15 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Mon, 30 Sep 2024 16:22:27 +0530 Subject: [PATCH 05/49] changes in core/removal of staking --- contracts/PushCore/PushCoreStorageV1_5.sol | 8 +- contracts/PushCore/PushCoreV3.sol | 345 ++++----------------- 2 files changed, 57 insertions(+), 296 deletions(-) diff --git a/contracts/PushCore/PushCoreStorageV1_5.sol b/contracts/PushCore/PushCoreStorageV1_5.sol index 980a3d44..0aa10bd1 100644 --- a/contracts/PushCore/PushCoreStorageV1_5.sol +++ b/contracts/PushCore/PushCoreStorageV1_5.sol @@ -20,7 +20,7 @@ contract PushCoreStorageV1_5 { address public pushChannelAdmin; address public governance; - address public daiAddress; + address public STAKING_CONTRACT; //TODO Re-Using Dai's address slot address public aDaiAddress; address public WETH_ADDRESS; address public pushCommunicator; @@ -33,9 +33,9 @@ contract PushCoreStorageV1_5 { uint256 public channelsCount; /// @notice Helper Variables for FSRatio Calculation | GROUPS = CHANNELS -> NOT IN USE - uint256 public groupNormalizedWeight; - uint256 public groupHistoricalZ; - uint256 public groupLastUpdate; + uint256 public HOLDER_FEE_POOL;//TODO Re-Using groupNormalizedWeight slot + uint256 public WALLET_FEE_POOL; //TODO Re-Using groupHistoricalZ slot + uint256 public SPLIT_PERCENTAGE_FOR_HOLDER; //TODO Re-Using groupLastUpdate slot uint256 public groupFairShareCount; /// @notice Necessary variables for Keeping track of Funds and Fees diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index 1f48017e..57285197 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -172,7 +172,10 @@ contract PushCoreV3 is revert Errors.InvalidArg_LessThanExpected(requiredFees, _amount); } - PROTOCOL_POOL_FEES = PROTOCOL_POOL_FEES + _amount; + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _amount) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = _amount - holderFee; + channelUpdateCounter[_channel] = updateCounter; channelInfo[_channel].channelUpdateBlock = block.number; @@ -241,7 +244,10 @@ contract PushCoreV3 is uint256 poolFundAmount = _amountDeposited - poolFeeAmount; //store funds in pool_funds & pool_fees CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS + poolFundAmount; - PROTOCOL_POOL_FEES = PROTOCOL_POOL_FEES + poolFeeAmount; + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = poolFeeAmount - holderFee; + // Calculate channel weight uint256 _channelWeight = (poolFundAmount * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; // Next create the channel and mark user as channellized @@ -284,7 +290,10 @@ contract PushCoreV3 is ) private { - PROTOCOL_POOL_FEES = PROTOCOL_POOL_FEES + _amountDeposited; + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _amountDeposited) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = _amountDeposited - holderFee; + string memory notifSetting = string(abi.encodePacked(Strings.toString(_notifOptions), "+", _notifSettings)); emit ChannelNotifcationSettingsAdded(_channel, _notifOptions, notifSetting, _notifDescription); @@ -338,15 +347,18 @@ contract PushCoreV3 is } function _reactivateChannel(bytes32 _channelBytesID, uint256 _amount) internal { - if (_amount < ADD_CHANNEL_MIN_FEES) { - revert Errors.InvalidArg_LessThanExpected(ADD_CHANNEL_MIN_FEES, _amount); - } - CoreTypes.Channel storage channelData = channelInfo[_channelBytesID]; - uint256 poolFeeAmount = FEE_AMOUNT; - uint256 poolFundAmount = _amount - poolFeeAmount; - //store funds in pool_funds & pool_fees - CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS + poolFundAmount; - PROTOCOL_POOL_FEES = PROTOCOL_POOL_FEES + poolFeeAmount; + if (_amount < ADD_CHANNEL_MIN_FEES) { + revert Errors.InvalidArg_LessThanExpected(ADD_CHANNEL_MIN_FEES, _amount); + } + CoreTypes.Channel storage channelData = channelInfo[_channelBytesID]; + uint256 poolFeeAmount = FEE_AMOUNT; + uint256 poolFundAmount = _amount - poolFeeAmount; + //store funds in pool_funds & pool_fees + CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS + poolFundAmount; + + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = poolFeeAmount - holderFee; uint256 _newPoolContribution = channelData.poolContribution + poolFundAmount; uint256 _newChannelWeight = (_newPoolContribution * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; @@ -369,7 +381,10 @@ contract PushCoreV3 is // Decrease CHANNEL_POOL_FUNDS by currentPoolContribution uint256 currentPoolContribution = channelData.poolContribution - minPoolContribution; CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS - currentPoolContribution; - PROTOCOL_POOL_FEES = PROTOCOL_POOL_FEES + currentPoolContribution; + + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * currentPoolContribution) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = currentPoolContribution - holderFee; uint256 _newChannelWeight = (minPoolContribution * ADJUST_FOR_FLOAT) / minPoolContribution; @@ -471,295 +486,33 @@ contract PushCoreV3 is /** * Core-V3: Stake and Claim Functions */ - - /// @notice Allows caller to add pool_fees at any given epoch - function addPoolFees(uint256 _rewardAmount) external { - IERC20(PUSH_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), _rewardAmount); - PROTOCOL_POOL_FEES = PROTOCOL_POOL_FEES + _rewardAmount; - } - - /** - * @notice Function to return User's Push Holder weight based on amount being staked & current block number - */ - function _returnPushTokenWeight( - address _account, - uint256 _amount, - uint256 _atBlock - ) - internal - view - returns (uint256) - { - return _amount * (_atBlock - IPUSH(PUSH_TOKEN_ADDRESS).holderWeight(_account)); - } - - /** - * @notice Returns the epoch ID based on the start and end block numbers passed as input - */ - function lastEpochRelative(uint256 _from, uint256 _to) public view returns (uint256) { - if (_to < _from) { - revert Errors.InvalidArg_LessThanExpected(_from, _to); - } - - return uint256((_to - _from) / epochDuration + 1); - } - - /** - * @notice Calculates and returns the claimable reward amount for a user at a given EPOCH ID. - * @dev Formulae for reward calculation: - * rewards = ( userStakedWeight at Epoch(n) * avalailable rewards at EPOCH(n) ) / totalStakedWeight at - * EPOCH(n) - */ - function calculateEpochRewards(address _user, uint256 _epochId) public view returns (uint256 rewards) { - rewards = (userFeesInfo[_user].epochToUserStakedWeight[_epochId] * epochRewards[_epochId]) - / epochToTotalStakedWeight[_epochId]; - } - - /** - * @notice Function to initialize the staking procedure in Core contract - * @dev Requires caller to deposit/stake 1 PUSH token to ensure staking pool is never zero. - * - */ - function initializeStake() external { - if (genesisEpoch != 0) { - revert("Already Initialized"); - } - - genesisEpoch = block.number; - lastEpochInitialized = genesisEpoch; - - _stake(address(this), 1e18); - } - - /** - * @notice Function to allow users to stake in the protocol - * @dev Records total Amount staked so far by a particular user - * Triggers weight adjustents functions - * @param _amount represents amount of tokens to be staked - * - */ - function stake(uint256 _amount) external { - _stake(msg.sender, _amount); - emit Staked(msg.sender, _amount); - } - - function _stake(address _staker, uint256 _amount) private { - uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); - uint256 blockNumberToConsider = genesisEpoch + (epochDuration * currentEpoch); - uint256 userWeight = _returnPushTokenWeight(_staker, _amount, blockNumberToConsider); - - IERC20(PUSH_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), _amount); - - userFeesInfo[_staker].stakedAmount = userFeesInfo[_staker].stakedAmount + _amount; - userFeesInfo[_staker].lastClaimedBlock = - userFeesInfo[_staker].lastClaimedBlock == 0 ? genesisEpoch : userFeesInfo[_staker].lastClaimedBlock; - totalStakedAmount += _amount; - // Adjust user and total rewards, piggyback method - _adjustUserAndTotalStake(_staker, userWeight, false); + function updateStakingAddress(address _stakingAddress) external { + onlyPushChannelAdmin(); + STAKING_CONTRACT = _stakingAddress; } - /** - * @notice Function to allow users to Unstake from the protocol - * @dev Allows stakers to claim rewards before unstaking their tokens - * Triggers weight adjustents functions - * Allows users to unstake all amount at once - * - */ - function unstake() external { - if (block.number <= userFeesInfo[msg.sender].lastStakedBlock + epochDuration) { - revert Errors.PushStaking_InvalidEpoch_LessThanExpected(); - } - if (userFeesInfo[msg.sender].stakedAmount == 0) { + function sendFunds(address _user, uint256 _amount) external { + if (msg.sender != STAKING_CONTRACT) { revert Errors.UnauthorizedCaller(msg.sender); } - - harvestAll(); - uint256 stakedAmount = userFeesInfo[msg.sender].stakedAmount; - IERC20(PUSH_TOKEN_ADDRESS).safeTransfer(msg.sender, stakedAmount); - - // Adjust user and total rewards, piggyback method - _adjustUserAndTotalStake(msg.sender, userFeesInfo[msg.sender].stakedWeight, true); - - userFeesInfo[msg.sender].stakedAmount = 0; - userFeesInfo[msg.sender].stakedWeight = 0; - totalStakedAmount -= stakedAmount; - - emit Unstaked(msg.sender, stakedAmount); - } - - /** - * @notice Allows users to harvest/claim their earned rewards from the protocol - * @dev Computes nextFromEpoch and currentEpoch and uses them as startEPoch and endEpoch respectively. - * Rewards are claculated from start epoch till endEpoch(currentEpoch - 1). - * Once calculated, user's total claimed rewards and nextFromEpoch details is updated. - * - */ - function harvestAll() public { - uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); - - uint256 rewards = harvest(msg.sender, currentEpoch - 1); - IERC20(PUSH_TOKEN_ADDRESS).safeTransfer(msg.sender, rewards); + IERC20(PUSH_TOKEN_ADDRESS).transfer(_user, _amount); } /** - * @notice Allows paginated harvests for users between a particular number of epochs. - * @param _tillEpoch - the end epoch number till which rewards shall be counted. - * @dev _tillEpoch should never be equal to currentEpoch. - * Transfers rewards to caller and updates user's details. + * Allows caller to add pool_fees at any given epoch * */ - function harvestPaginated(uint256 _tillEpoch) external { - uint256 rewards = harvest(msg.sender, _tillEpoch); - IERC20(PUSH_TOKEN_ADDRESS).safeTransfer(msg.sender, rewards); + function addPoolFees(uint256 _rewardAmount) external { + IERC20(PUSH_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), _rewardAmount); + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _rewardAmount) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = _rewardAmount - holderFee; } - /** - * @notice Allows Push Governance to harvest/claim the earned rewards for its stake in the protocol - * @param _tillEpoch - the end epoch number till which rewards shall be counted. - * @dev only accessible by Push Admin - * Unlike other harvest functions, this is designed to transfer rewards to Push Governance. - * - */ - function daoHarvestPaginated(uint256 _tillEpoch) external { + function splitFeePool(uint256 holderSplit) external { onlyGovernance(); - uint256 rewards = harvest(address(this), _tillEpoch); - IERC20(PUSH_TOKEN_ADDRESS).safeTransfer(governance, rewards); - } - - /** - * @notice Internal harvest function that is called for all types of harvest procedure. - * @param _user - The user address for which the rewards will be calculated. - * @param _tillEpoch - the end epoch number till which rewards shall be counted. - * @dev _tillEpoch should never be equal to currentEpoch. - * Transfers rewards to caller and updates user's details. - * - */ - function harvest(address _user, uint256 _tillEpoch) internal returns (uint256 rewards) { - IPUSH(PUSH_TOKEN_ADDRESS).resetHolderWeight(_user); - _adjustUserAndTotalStake(_user, 0, false); - - uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); - uint256 nextFromEpoch = lastEpochRelative(genesisEpoch, userFeesInfo[_user].lastClaimedBlock); - - if (currentEpoch <= _tillEpoch) { - revert Errors.PushStaking_InvalidEpoch_LessThanExpected(); - } - if (_tillEpoch < nextFromEpoch) { - revert Errors.InvalidArg_LessThanExpected(nextFromEpoch, _tillEpoch); - } - for (uint256 i = nextFromEpoch; i <= _tillEpoch; i++) { - uint256 claimableReward = calculateEpochRewards(_user, i); - rewards = rewards + claimableReward; - } - - usersRewardsClaimed[_user] = usersRewardsClaimed[_user] + rewards; - // set the lastClaimedBlock to blocknumer at the end of `_tillEpoch` - uint256 _epoch_to_block_number = genesisEpoch + _tillEpoch * epochDuration; - userFeesInfo[_user].lastClaimedBlock = _epoch_to_block_number; - - emit RewardsHarvested(_user, rewards, nextFromEpoch, _tillEpoch); - } - - /** - * @notice This functions helps in adjustment of user's as well as totalWeigts, both of which are imperative for - * reward calculation at a particular epoch. - * @dev Enables adjustments of user's stakedWeight, totalStakedWeight, epochToTotalStakedWeight as well as - * epochToTotalStakedWeight. - * triggers _setupEpochsReward() to adjust rewards for every epoch till the current epoch - * - * Includes 2 main cases of weight adjustments - * 1st Case: User stakes for the very first time: - * - Simply update userFeesInfo, totalStakedWeight and epochToTotalStakedWeight of currentEpoch - * - * 2nd Case: User is NOT staking for first time - 2 Subcases - * 2.1 Case: User stakes again but in Same Epoch - * - Increase user's stake and totalStakedWeight - * - Record the epochToUserStakedWeight for that epoch - * - Record the epochToTotalStakedWeight of that epoch - * - * 2.2 Case: - User stakes again but in different Epoch - * - Update the epochs between lastStakedEpoch & (currentEpoch - 1) with the old staked weight - * amounts - * - While updating epochs between lastStaked & current Epochs, if any epoch has zero value for - * totalStakedWeight, update it with current totalStakedWeight value of the protocol - * - For currentEpoch, initialize the epoch id with updated weight values for - * epochToUserStakedWeight & epochToTotalStakedWeight - */ - function _adjustUserAndTotalStake(address _user, uint256 _userWeight, bool isUnstake) internal { - uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); - _setupEpochsRewardAndWeights(_userWeight, currentEpoch, isUnstake); - uint256 userStakedWeight = userFeesInfo[_user].stakedWeight; - - // Initiating 1st Case: User stakes for first time - if (userStakedWeight == 0) { - userFeesInfo[_user].stakedWeight = _userWeight; - } else { - // Initiating 2.1 Case: User stakes again but in Same Epoch - uint256 lastStakedEpoch = lastEpochRelative(genesisEpoch, userFeesInfo[_user].lastStakedBlock); - if (currentEpoch == lastStakedEpoch) { - userFeesInfo[_user].stakedWeight = - isUnstake ? userStakedWeight - _userWeight : userStakedWeight + _userWeight; - } else { - // Initiating 2.2 Case: User stakes again but in Different Epoch - for (uint256 i = lastStakedEpoch; i <= currentEpoch; i++) { - if (i != currentEpoch) { - userFeesInfo[_user].epochToUserStakedWeight[i] = userStakedWeight; - } else { - userFeesInfo[_user].stakedWeight = - isUnstake ? userStakedWeight - _userWeight : userStakedWeight + _userWeight; - userFeesInfo[_user].epochToUserStakedWeight[i] = userFeesInfo[_user].stakedWeight; - } - } - } - } - - if (_userWeight != 0) { - userFeesInfo[_user].lastStakedBlock = block.number; - } - } - - /** - * @notice Internal function that allows setting up the rewards for specific EPOCH IDs - * @dev Initializes (sets reward) for every epoch ID that falls between the lastEpochInitialized and currentEpoch - * Reward amount for specific EPOCH Ids depends on newly available Protocol_Pool_Fees. - * - If no new fees was accumulated, rewards for particular epoch ids can be zero - * - Records the Pool_Fees value used as rewards. - * - Records the last epoch id whose rewards were set. - */ - function _setupEpochsRewardAndWeights(uint256 _userWeight, uint256 _currentEpoch, bool isUnstake) private { - uint256 _lastEpochInitiliazed = lastEpochRelative(genesisEpoch, lastEpochInitialized); - - // Setting up Epoch Based Rewards - if (_currentEpoch > _lastEpochInitiliazed || _currentEpoch == 1) { - uint256 availableRewardsPerEpoch = (PROTOCOL_POOL_FEES - previouslySetEpochRewards); - uint256 _epochGap = _currentEpoch - _lastEpochInitiliazed; - - if (_epochGap > 1) { - epochRewards[_currentEpoch - 1] += availableRewardsPerEpoch; - } else { - epochRewards[_currentEpoch] += availableRewardsPerEpoch; - } - - lastEpochInitialized = block.number; - previouslySetEpochRewards = PROTOCOL_POOL_FEES; - } - // Setting up Epoch Based TotalWeight - if (lastTotalStakeEpochInitialized == 0 || lastTotalStakeEpochInitialized == _currentEpoch) { - epochToTotalStakedWeight[_currentEpoch] = isUnstake - ? epochToTotalStakedWeight[_currentEpoch] - _userWeight - : epochToTotalStakedWeight[_currentEpoch] + _userWeight; - } else { - for (uint256 i = lastTotalStakeEpochInitialized + 1; i <= _currentEpoch - 1; i++) { - if (epochToTotalStakedWeight[i] == 0) { - epochToTotalStakedWeight[i] = epochToTotalStakedWeight[lastTotalStakeEpochInitialized]; - } - } + SPLIT_PERCENTAGE_FOR_HOLDER = holderSplit; - epochToTotalStakedWeight[_currentEpoch] = isUnstake - ? epochToTotalStakedWeight[lastTotalStakeEpochInitialized] - _userWeight - : epochToTotalStakedWeight[lastTotalStakeEpochInitialized] + _userWeight; - } - lastTotalStakeEpochInitialized = _currentEpoch; } /// @inheritdoc IPushCoreV3 @@ -792,7 +545,10 @@ contract PushCoreV3 is uint256 requestReceiverAmount = amount - poolFeeAmount; celebUserFunds[requestReceiver] += requestReceiverAmount; - PROTOCOL_POOL_FEES = PROTOCOL_POOL_FEES + poolFeeAmount; + + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = poolFeeAmount - holderFee; emit IncentivizedChatReqReceived( requestSender, BaseHelper.addressToBytes32(requestReceiver), requestReceiverAmount, poolFeeAmount, block.timestamp @@ -900,7 +656,9 @@ contract PushCoreV3 is _handleArbitraryRequest(sender, feeId, feePercentage, BaseHelper.bytes32ToAddress(amountRecipient), amount); } else if (functionType == CrossChainRequestTypes.CrossChainFunction.AdminRequest_AddPoolFee) { // Admin Request - PROTOCOL_POOL_FEES += amount; + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * amount) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = amount - holderFee; } else { revert("Invalid Function Type"); } @@ -949,7 +707,10 @@ contract PushCoreV3 is uint256 feeAmount = BaseHelper.calcPercentage(amount, feePercentage); // Update states based on Fee Percentage calculation - PROTOCOL_POOL_FEES += feeAmount; + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * feeAmount) / 100; + HOLDER_FEE_POOL = holderFee; + WALLET_FEE_POOL = feeAmount - holderFee; + arbitraryReqFees[amountRecipient] += amount - feeAmount; // Emit an event for the arbitrary request From d9da740e187261e0860d48ef9895a738524c7ef4 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Mon, 30 Sep 2024 16:22:45 +0530 Subject: [PATCH 06/49] minor changes in test files --- test/BaseTest.t.sol | 12 ++++++------ test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol | 2 +- test/CCR/CCRutils/Helper.sol | 4 +++- .../2_StateVariables/StateVariables.f.sol | 14 +++++++------- .../PushStaking/fuzz_tests/BaseFuzzStaking.f.sol | 16 ++-------------- 5 files changed, 19 insertions(+), 29 deletions(-) diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index 43260fce..d9a5b78e 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -118,9 +118,9 @@ abstract contract BaseTest is Test, Constants, Events { // set governance as minter of ntt token // vm.prank(actor.admin); pushNttToken.setMinter(actor.governance); - epnsCoreProxyAdmin = new EPNSCoreAdmin(actor.admin); + epnsCoreProxyAdmin = new EPNSCoreAdmin(); - epnsCoreProxyAdmin = new EPNSCoreAdmin(actor.admin); + epnsCoreProxyAdmin = new EPNSCoreAdmin(); // Initialize coreMock proxy admin and coreProxy contract epnsCoreProxy = new EPNSCoreProxy( address(coreProxy), @@ -136,11 +136,9 @@ abstract contract BaseTest is Test, Constants, Events { ); coreProxy = PushCoreMock(address(epnsCoreProxy)); - changePrank(tokenDistributor); - pushToken.transfer(address(coreProxy), 1 ether); // Initialize comm proxy admin and commProxy contract - epnsCommProxyAdmin = new EPNSCommAdmin(actor.admin); + epnsCommProxyAdmin = new EPNSCommAdmin(); epnsCommProxy = new EPNSCommProxy(address(comm), address(epnsCommProxyAdmin), actor.admin, "FOUNDRY_TEST_NETWORK"); commProxy = PushCommV3(address(epnsCommProxy)); @@ -152,7 +150,7 @@ abstract contract BaseTest is Test, Constants, Events { vm.stopPrank(); // Initialize comm proxy admin and commProxy contract - epnsCommEthProxyAdmin = new EPNSCommAdmin(actor.admin); + epnsCommEthProxyAdmin = new EPNSCommAdmin(); epnsCommEthProxy = new EPNSCommProxy(address(commEth), address(epnsCommEthProxyAdmin), actor.admin, "FOUNDRY_TEST_NETWORK"); commEthProxy = PushCommETHV3(address(epnsCommEthProxy)); @@ -174,6 +172,8 @@ abstract contract BaseTest is Test, Constants, Events { approveTokens(actor.tony_channel_owner, address(coreProxy), 50_000 ether); approveTokens(actor.dan_push_holder, address(coreProxy), 50_000 ether); approveTokens(actor.tim_push_holder, address(coreProxy), 50_000 ether); + vm.prank(actor.admin); + // coreProxy.initializeStake(); vm.warp(DEC_27_2021); } diff --git a/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol b/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol index 8a1fb630..d281e793 100644 --- a/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol +++ b/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol @@ -121,7 +121,7 @@ contract ArbitraryRequesttsol is BaseCCRTest { function test_WhenDeliveryHashIsUsedAlready() external whenReceiveFunctionIsCalledInCore { // it should Revert - + test_WhenAllChecksPasses(); setUpDestChain(); changePrank(DestChain.WORMHOLE_RELAYER_DEST); diff --git a/test/CCR/CCRutils/Helper.sol b/test/CCR/CCRutils/Helper.sol index a092c4f9..ebcedc97 100644 --- a/test/CCR/CCRutils/Helper.sol +++ b/test/CCR/CCRutils/Helper.sol @@ -51,6 +51,7 @@ contract Helper is BasePushCommTest, CCRConfig { changePrank(_addr); pushToken.approve(address(coreProxy), type(uint256).max); + pushToken.setHolderDelegation(address(coreProxy), true); } } @@ -81,7 +82,8 @@ contract Helper is BasePushCommTest, CCRConfig { coreProxy.setWormholeRelayer(DestChain.WORMHOLE_RELAYER_DEST); coreProxy.setPushTokenAddress(address(pushToken)); coreProxy.setRegisteredSender(SourceChain.SourceChainId, toWormholeFormat(address(commProxy))); - + + getPushTokenOnfork(actor.admin, 1000e18, address(pushToken)); getPushTokenOnfork(actor.bob_channel_owner, 1000e18, address(pushToken)); getPushTokenOnfork(actor.charlie_channel_owner, 1000e18,address(pushToken)); changePrank(actor.bob_channel_owner); diff --git a/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol b/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol index 9e16a55c..a7dd89f9 100644 --- a/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol +++ b/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol @@ -14,8 +14,8 @@ contract StateVariables_test is BaseFuzzStaking { roll(_passEpoch * epochDuration); uint256 future = block.number; - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_LessThanExpected.selector, future, genesis)); - coreProxy.lastEpochRelative(future, genesis); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_LessThanExpected.selector, future, genesisEpoch)); + coreProxy.lastEpochRelative(future, genesisEpoch); } //Should calculate relative epoch numbers accurately @@ -25,7 +25,7 @@ contract StateVariables_test is BaseFuzzStaking { roll(_passEpoch * epochDuration); uint256 future = block.number; - assertEq(coreProxy.lastEpochRelative(genesis, future), _passEpoch); + assertEq(coreProxy.lastEpochRelative(genesisEpoch, future), _passEpoch); } // Should count staked EPOCH of user correctly @@ -39,8 +39,8 @@ contract StateVariables_test is BaseFuzzStaking { (uint256 stakedAmount, uint256 stakedWeight, uint256 lastStakedBlock, uint256 lastClaimedBlock) = coreProxy.userFeesInfo(actor.bob_channel_owner); - uint256 lastClaimedEpoch = coreProxy.lastEpochRelative(genesis, lastClaimedBlock); - uint256 lastStakedEpoch = coreProxy.lastEpochRelative(genesis, lastStakedBlock); + uint256 lastClaimedEpoch = coreProxy.lastEpochRelative(genesisEpoch, lastClaimedBlock); + uint256 lastStakedEpoch = coreProxy.lastEpochRelative(genesisEpoch, lastStakedBlock); assertEq(stakedAmount, _amount * 1e18); assertEq(lastClaimedEpoch, 1); assertEq(lastStakedEpoch, _passEpoch); @@ -56,14 +56,14 @@ contract StateVariables_test is BaseFuzzStaking { stake(actor.bob_channel_owner, _amount); (,, uint256 lastStakedBlock,) = coreProxy.userFeesInfo(actor.bob_channel_owner); - uint256 userLastStakedEpochId = coreProxy.lastEpochRelative(genesis, lastStakedBlock); + uint256 userLastStakedEpochId = coreProxy.lastEpochRelative(genesisEpoch, lastStakedBlock); roll((_passEpoch + 5) * epochDuration); uint256 harvestEpoch = getCurrentEpoch(); // Harvests Push Tokens after 15 blocks, at 16th EPOCH harvest(actor.bob_channel_owner); (,,, uint256 lastClaimedBlockAfter) = coreProxy.userFeesInfo(actor.bob_channel_owner); - uint256 userLastClaimedEpochId = coreProxy.lastEpochRelative(genesis, lastClaimedBlockAfter); + uint256 userLastClaimedEpochId = coreProxy.lastEpochRelative(genesisEpoch, lastClaimedBlockAfter); assertEq(userLastStakedEpochId, _passEpoch); assertEq(userLastClaimedEpochId, 5 + _passEpoch); } diff --git a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol index d881038d..47e540a4 100644 --- a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol +++ b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol @@ -4,22 +4,10 @@ pragma experimental ABIEncoderV2; import { BaseTest } from "../../BaseTest.t.sol"; contract BaseFuzzStaking is BaseTest { - uint256 genesis; function setUp() public virtual override { BaseTest.setUp(); - - approveTokens(actor.admin, address(coreProxy), 100_000 ether); - approveTokens(actor.admin, address(coreProxy), 100_000 ether); - approveTokens(actor.bob_channel_owner, address(coreProxy), 100_000 ether); - approveTokens(actor.alice_channel_owner, address(coreProxy), 100_000 ether); - approveTokens(actor.charlie_channel_owner, address(coreProxy), 100_000 ether); - approveTokens(actor.tony_channel_owner, address(coreProxy), 100_000 ether); - - //initialize stake to avoid divsion by zero errors - vm.prank(actor.admin); - coreProxy.initializeStake(); - genesis = coreProxy.genesisEpoch(); + genesisEpoch = coreProxy.genesisEpoch(); } //Helper Functions @@ -54,6 +42,6 @@ contract BaseFuzzStaking is BaseTest { } function getCurrentEpoch() public returns (uint256 currentEpoch) { - currentEpoch = coreProxy.lastEpochRelative(genesis, block.number); + currentEpoch = coreProxy.lastEpochRelative(genesisEpoch, block.number); } } From 0b7e9b11c694ac413ce7089d3c84cf1430b63269 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Tue, 1 Oct 2024 13:00:10 +0530 Subject: [PATCH 07/49] compilation successful --- contracts/PushStaking/PushStaking.sol | 2 +- contracts/PushStaking/PushStakingAdmin.sol | 2 +- contracts/PushStaking/PushStakingProxy.sol | 14 +--- test/BaseTest.t.sol | 25 +++++-- .../fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol | 10 +-- .../2_StateVariables/StateVariables.f.sol | 22 +++--- .../fuzz_tests/3_Unstaking/Unstaking.f.sol | 6 +- .../4_UserHarvest/UserHarvest.f.sol | 72 +++++++++---------- .../fuzz_tests/BaseFuzzStaking.f.sol | 14 ++-- 9 files changed, 84 insertions(+), 83 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index 1c92201e..f19455b3 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -10,7 +10,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -contract PushFeePoolStaking is Initializable, PushStakingStorage { +contract PushStaking is Initializable, PushStakingStorage { using SafeERC20 for IERC20; event Staked(address indexed user, uint256 indexed amountStaked); diff --git a/contracts/PushStaking/PushStakingAdmin.sol b/contracts/PushStaking/PushStakingAdmin.sol index 14d1dbbd..91ca7dc3 100644 --- a/contracts/PushStaking/PushStakingAdmin.sol +++ b/contracts/PushStaking/PushStakingAdmin.sol @@ -5,5 +5,5 @@ pragma solidity ^0.8.20; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; contract PushStakingAdmin is ProxyAdmin { - constructor(address _pushChannelAdmin) ProxyAdmin() { } + constructor() ProxyAdmin() { } } diff --git a/contracts/PushStaking/PushStakingProxy.sol b/contracts/PushStaking/PushStakingProxy.sol index 593d6b82..5534c3e1 100644 --- a/contracts/PushStaking/PushStakingProxy.sol +++ b/contracts/PushStaking/PushStakingProxy.sol @@ -10,12 +10,7 @@ contract PushStakingProxy is TransparentUpgradeableProxy { address _governance, address _pushChannelAdmin, address _core, - address _pushTokenAddress, - uint256 _genesisEpoch, - uint256 _lastEpochInitialized, - uint256 _lastTotalStakeEpochInitialized, - uint256 _totalStakedAmount, - uint256 _previouslySetEpochRewards + address _pushTokenAddress ) payable TransparentUpgradeableProxy( @@ -25,12 +20,7 @@ contract PushStakingProxy is TransparentUpgradeableProxy { "initialize(address,address,address,uint256,uint256,uint256,uint256,uint256)", _pushChannelAdmin, _core, - _pushTokenAddress, - _genesisEpoch, - _lastEpochInitialized, - _lastTotalStakeEpochInitialized, - _totalStakedAmount, - _previouslySetEpochRewards + _pushTokenAddress ) ) { } diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index d9a5b78e..5782568e 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -7,7 +7,7 @@ import "contracts/token/EPNS.sol"; import "contracts/token/Push.sol"; import "contracts/interfaces/uniswap/IUniswapV2Router.sol"; import { PushCoreMock } from "contracts/mocks/PushCoreMock.sol"; -import { EPNSCoreProxy} from "contracts/PushCore/EPNSCoreProxy.sol"; +import { EPNSCoreProxy } from "contracts/PushCore/EPNSCoreProxy.sol"; import { EPNSCoreAdmin } from "contracts/PushCore/EPNSCoreAdmin.sol"; import { PushCommETHV3 } from "contracts/PushComm/PushCommEthV3.sol"; import { PushCommV3 } from "contracts/PushComm/PushCommV3.sol"; @@ -16,7 +16,9 @@ import { EPNSCommAdmin } from "contracts/PushComm/EPNSCommAdmin.sol"; import { PushMigrationHelper } from "contracts/token/PushMigration.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - +import { PushStaking } from "contracts/PushStaking/PushStaking.sol"; +import { PushStakingProxy } from "contracts/PushStaking/PushStakingProxy.sol"; +import { PushStakingAdmin } from "contracts/PushStaking/PushStakingAdmin.sol"; import { Actors, ChannelCreators } from "./utils/Actors.sol"; import { Events } from "./utils/Events.sol"; import { Constants } from "./utils/Constants.sol"; @@ -27,7 +29,6 @@ abstract contract BaseTest is Test, Constants, Events { Push public pushNttToken; EPNS public pushToken; PushCoreMock public coreProxy; - PushCommV3 public comm; PushCommV3 public commProxy; PushCommETHV3 public commEth; PushCommETHV3 public commEthProxy; @@ -44,6 +45,9 @@ abstract contract BaseTest is Test, Constants, Events { TransparentUpgradeableProxy public pushNttProxy; ProxyAdmin public nttMigrationProxyAdmin; ProxyAdmin public nttProxyAdmin; + PushStaking public pushStaking; + PushStakingProxy public pushStakingProxy; + PushStakingAdmin public pushStakingProxyAdmin; /* *************** Main Actors in Test @@ -71,11 +75,12 @@ abstract contract BaseTest is Test, Constants, Events { pushToken = new EPNS(tokenDistributor); coreProxy = new PushCoreMock(); - comm = new PushCommV3(); + commProxy = new PushCommV3(); commEth = new PushCommETHV3(); pushMigrationHelper = new PushMigrationHelper(); uniV2Router = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); pushNtt = new Push(); + pushStaking = new PushStaking(); actor = Actors({ admin: createActor("admin"), @@ -140,9 +145,15 @@ abstract contract BaseTest is Test, Constants, Events { // Initialize comm proxy admin and commProxy contract epnsCommProxyAdmin = new EPNSCommAdmin(); epnsCommProxy = - new EPNSCommProxy(address(comm), address(epnsCommProxyAdmin), actor.admin, "FOUNDRY_TEST_NETWORK"); + new EPNSCommProxy(address(commProxy), address(epnsCommProxyAdmin), actor.admin, "FOUNDRY_TEST_NETWORK"); commProxy = PushCommV3(address(epnsCommProxy)); + //Setup PushStaking Contracts + pushStakingProxyAdmin = new PushStakingAdmin(); + pushStakingProxy = + new PushStakingProxy(address(pushStaking), actor.admin, address(coreProxy), actor.admin, address(pushToken)); + pushStaking = PushStaking(address(pushStakingProxy)); + // Set-up Core Address in Comm & Vice-Versa changePrank(actor.admin); commProxy.setPushCoreAddress(address(coreProxy)); @@ -173,7 +184,7 @@ abstract contract BaseTest is Test, Constants, Events { approveTokens(actor.dan_push_holder, address(coreProxy), 50_000 ether); approveTokens(actor.tim_push_holder, address(coreProxy), 50_000 ether); vm.prank(actor.admin); - // coreProxy.initializeStake(); + pushStaking.initializeStake(); vm.warp(DEC_27_2021); } @@ -193,7 +204,7 @@ abstract contract BaseTest is Test, Constants, Events { } function approveNttTokens(address from, address to, uint256 amount) internal { - changePrank(from); + changePrank(from); pushNttToken.approve(to, amount); pushNttToken.setHolderDelegation(to, true); vm.stopPrank(); diff --git a/test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol b/test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol index 76d9380b..cb90bb68 100644 --- a/test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol +++ b/test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol @@ -20,7 +20,7 @@ contract DaoHarvest_test is BaseFuzzStaking { roll(epochDuration * _passEpoch); daoHarvest(actor.admin, _passEpoch - 1); - uint256 rewards = coreProxy.usersRewardsClaimed(address(coreProxy)); + uint256 rewards = pushStaking.usersRewardsClaimed(address(coreProxy)); assertEq(rewards, _fee * 1e18); } @@ -33,7 +33,7 @@ contract DaoHarvest_test is BaseFuzzStaking { vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotGovernance.selector)); daoHarvest(actor.bob_channel_owner, _passEpoch - 1); daoHarvest(actor.admin, _passEpoch - 1); - uint256 rewardsBef = coreProxy.usersRewardsClaimed(address(coreProxy)); + uint256 rewardsBef = pushStaking.usersRewardsClaimed(address(coreProxy)); assertEq(rewardsBef, 0); } @@ -50,8 +50,8 @@ contract DaoHarvest_test is BaseFuzzStaking { roll(epochDuration * _passEpoch); harvest(actor.bob_channel_owner); daoHarvest(actor.admin, _passEpoch - 1); - uint256 rewardsAd = coreProxy.usersRewardsClaimed(address(coreProxy)); - uint256 rewardsBob = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewardsAd = pushStaking.usersRewardsClaimed(address(coreProxy)); + uint256 rewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); uint256 claimed = rewardsAd + rewardsBob; assertApproxEqAbs(_fee * 1e18, claimed, 1 ether); } @@ -65,7 +65,7 @@ contract DaoHarvest_test is BaseFuzzStaking { roll(epochDuration * _passEpoch); daoHarvest(actor.admin, _passEpoch - 1); - uint256 claimed = coreProxy.usersRewardsClaimed(address(coreProxy)); + uint256 claimed = pushStaking.usersRewardsClaimed(address(coreProxy)); assertEq(claimed, _fee * 1e18); } } diff --git a/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol b/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol index a7dd89f9..6f293222 100644 --- a/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol +++ b/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol @@ -15,7 +15,7 @@ contract StateVariables_test is BaseFuzzStaking { uint256 future = block.number; vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_LessThanExpected.selector, future, genesisEpoch)); - coreProxy.lastEpochRelative(future, genesisEpoch); + pushStaking.lastEpochRelative(future, genesisEpoch); } //Should calculate relative epoch numbers accurately @@ -25,7 +25,7 @@ contract StateVariables_test is BaseFuzzStaking { roll(_passEpoch * epochDuration); uint256 future = block.number; - assertEq(coreProxy.lastEpochRelative(genesisEpoch, future), _passEpoch); + assertEq(pushStaking.lastEpochRelative(genesisEpoch, future), _passEpoch); } // Should count staked EPOCH of user correctly @@ -37,10 +37,10 @@ contract StateVariables_test is BaseFuzzStaking { stake(actor.bob_channel_owner, _amount); (uint256 stakedAmount, uint256 stakedWeight, uint256 lastStakedBlock, uint256 lastClaimedBlock) = - coreProxy.userFeesInfo(actor.bob_channel_owner); + pushStaking.userFeesInfo(actor.bob_channel_owner); - uint256 lastClaimedEpoch = coreProxy.lastEpochRelative(genesisEpoch, lastClaimedBlock); - uint256 lastStakedEpoch = coreProxy.lastEpochRelative(genesisEpoch, lastStakedBlock); + uint256 lastClaimedEpoch = pushStaking.lastEpochRelative(genesisEpoch, lastClaimedBlock); + uint256 lastStakedEpoch = pushStaking.lastEpochRelative(genesisEpoch, lastStakedBlock); assertEq(stakedAmount, _amount * 1e18); assertEq(lastClaimedEpoch, 1); assertEq(lastStakedEpoch, _passEpoch); @@ -54,16 +54,16 @@ contract StateVariables_test is BaseFuzzStaking { uint256 stakeEpoch = getCurrentEpoch(); // Stakes Push Tokens after 5 blocks, at 6th EPOCH stake(actor.bob_channel_owner, _amount); - (,, uint256 lastStakedBlock,) = coreProxy.userFeesInfo(actor.bob_channel_owner); + (,, uint256 lastStakedBlock,) = pushStaking.userFeesInfo(actor.bob_channel_owner); - uint256 userLastStakedEpochId = coreProxy.lastEpochRelative(genesisEpoch, lastStakedBlock); + uint256 userLastStakedEpochId = pushStaking.lastEpochRelative(genesisEpoch, lastStakedBlock); roll((_passEpoch + 5) * epochDuration); uint256 harvestEpoch = getCurrentEpoch(); // Harvests Push Tokens after 15 blocks, at 16th EPOCH harvest(actor.bob_channel_owner); - (,,, uint256 lastClaimedBlockAfter) = coreProxy.userFeesInfo(actor.bob_channel_owner); - uint256 userLastClaimedEpochId = coreProxy.lastEpochRelative(genesisEpoch, lastClaimedBlockAfter); + (,,, uint256 lastClaimedBlockAfter) = pushStaking.userFeesInfo(actor.bob_channel_owner); + uint256 userLastClaimedEpochId = pushStaking.lastEpochRelative(genesisEpoch, lastClaimedBlockAfter); assertEq(userLastStakedEpochId, _passEpoch); assertEq(userLastClaimedEpochId, 5 + _passEpoch); } @@ -81,10 +81,10 @@ contract StateVariables_test is BaseFuzzStaking { stake(actor.bob_channel_owner, _amount); roll(epochDuration * (_passEpoch + 2)); - (,, uint256 blocks,) = coreProxy.userFeesInfo(actor.bob_channel_owner); + (,, uint256 blocks,) = pushStaking.userFeesInfo(actor.bob_channel_owner); unstake(actor.bob_channel_owner); (uint256 stakedAmount, uint256 stakedWeight, uint256 lastStakedBlock, uint256 lastClaimedBlock) = - coreProxy.userFeesInfo(actor.bob_channel_owner); + pushStaking.userFeesInfo(actor.bob_channel_owner); assertEq(stakedAmount, 0); assertEq(stakedWeight, 0); diff --git a/test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol b/test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol index da8d68a4..5e67ac21 100644 --- a/test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol +++ b/test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol @@ -22,7 +22,7 @@ contract Unstaking_test is BaseFuzzStaking { roll(epochDuration * _passEpoch); unstake(actor.bob_channel_owner); - assertEq(coreProxy.usersRewardsClaimed(actor.bob_channel_owner) > 0, true); + assertEq(pushStaking.usersRewardsClaimed(actor.bob_channel_owner) > 0, true); } //Users cannot claim rewards after unstaking @@ -55,7 +55,7 @@ contract Unstaking_test is BaseFuzzStaking { stake(actor.bob_channel_owner, _amount); roll(epochDuration * _passEpoch); unstake(actor.bob_channel_owner); - uint256 rewards = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); uint256 expectedAmount = rewards + balanceBefore; assertEq(expectedAmount, pushToken.balanceOf(actor.bob_channel_owner)); } @@ -76,7 +76,7 @@ contract Unstaking_test is BaseFuzzStaking { unstake(actor.bob_channel_owner); roll(epochDuration * _passEpoch); unstake(actor.bob_channel_owner); - uint256 rewards = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); uint256 expectedAmount = rewards + balanceBefore; assertEq(expectedAmount, pushToken.balanceOf(actor.bob_channel_owner)); } diff --git a/test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol b/test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol index bce887d7..b4c569e0 100644 --- a/test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol +++ b/test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol @@ -22,8 +22,8 @@ contract UserHarvest_test is BaseFuzzStaking { roll(epochDuration * _passEpoch); harvest(actor.bob_channel_owner); daoHarvest(actor.admin, _passEpoch - 1); - uint256 adminClaimed = coreProxy.usersRewardsClaimed(address(coreProxy)); - uint256 claimed = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); + uint256 adminClaimed = pushStaking.usersRewardsClaimed(address(coreProxy)); + uint256 claimed = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); assertApproxEqAbs(claimed, _fee * 1e18, (adminClaimed) * 1e18); } @@ -40,8 +40,8 @@ contract UserHarvest_test is BaseFuzzStaking { roll(epochDuration * (_passEpoch + 1)); harvest(actor.bob_channel_owner); daoHarvest(actor.admin, _passEpoch); - uint256 adminClaimed = coreProxy.usersRewardsClaimed(address(coreProxy)); - uint256 claimed = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); + uint256 adminClaimed = pushStaking.usersRewardsClaimed(address(coreProxy)); + uint256 claimed = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); assertApproxEqAbs(claimed, _fee * 1e18, adminClaimed + 1e18); } @@ -56,7 +56,7 @@ contract UserHarvest_test is BaseFuzzStaking { stake(actor.bob_channel_owner, _amount); harvest(actor.bob_channel_owner); - assertEq(coreProxy.usersRewardsClaimed(actor.bob_channel_owner), 0); + assertEq(pushStaking.usersRewardsClaimed(actor.bob_channel_owner), 0); } // bob stakes at epoch 2 and claims at epoch 9 using harvestAll()", @@ -73,9 +73,9 @@ contract UserHarvest_test is BaseFuzzStaking { daoHarvest(actor.admin, _passEpoch + 8); assertApproxEqAbs( - coreProxy.usersRewardsClaimed(actor.bob_channel_owner), + pushStaking.usersRewardsClaimed(actor.bob_channel_owner), _fee * 1e18, - (coreProxy.usersRewardsClaimed(address(coreProxy)) + 5) * 1e18 + (pushStaking.usersRewardsClaimed(address(coreProxy)) + 5) * 1e18 ); } @@ -95,8 +95,8 @@ contract UserHarvest_test is BaseFuzzStaking { roll(epochDuration * _passEpoch); harvest(actor.bob_channel_owner); harvest(actor.alice_channel_owner); - uint256 bobClaimed = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); - uint256 aliceClaimed = coreProxy.usersRewardsClaimed(actor.alice_channel_owner); + uint256 bobClaimed = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 aliceClaimed = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); assertEq(bobClaimed, aliceClaimed); } @@ -128,8 +128,8 @@ contract UserHarvest_test is BaseFuzzStaking { harvest(actor.alice_channel_owner); assertEq( - coreProxy.usersRewardsClaimed(actor.bob_channel_owner), - coreProxy.usersRewardsClaimed(actor.alice_channel_owner) + pushStaking.usersRewardsClaimed(actor.bob_channel_owner), + pushStaking.usersRewardsClaimed(actor.alice_channel_owner) ); } @@ -152,10 +152,10 @@ contract UserHarvest_test is BaseFuzzStaking { harvest(actor.alice_channel_owner); harvest(actor.charlie_channel_owner); harvest(actor.tony_channel_owner); - uint256 bobClaimed = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); - uint256 aliceClaimed = coreProxy.usersRewardsClaimed(actor.alice_channel_owner); - uint256 charlieclaimed = coreProxy.usersRewardsClaimed(actor.charlie_channel_owner); - uint256 tonyclaimed = coreProxy.usersRewardsClaimed(actor.tony_channel_owner); + uint256 bobClaimed = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 aliceClaimed = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + uint256 charlieclaimed = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); + uint256 tonyclaimed = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); assertTrue(charlieclaimed == tonyclaimed && bobClaimed == aliceClaimed && bobClaimed == charlieclaimed); } @@ -181,10 +181,10 @@ contract UserHarvest_test is BaseFuzzStaking { harvest(actor.bob_channel_owner); harvest(actor.alice_channel_owner); harvest(actor.charlie_channel_owner); - uint256 bobClaimed = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); - uint256 aliceClaimed = coreProxy.usersRewardsClaimed(actor.alice_channel_owner); - uint256 charlieclaimed = coreProxy.usersRewardsClaimed(actor.charlie_channel_owner); - uint256 tonyclaimed = coreProxy.usersRewardsClaimed(actor.tony_channel_owner); + uint256 bobClaimed = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 aliceClaimed = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + uint256 charlieclaimed = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); + uint256 tonyclaimed = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); assertTrue(tonyclaimed > charlieclaimed && charlieclaimed > aliceClaimed && aliceClaimed > bobClaimed); } @@ -216,10 +216,10 @@ contract UserHarvest_test is BaseFuzzStaking { roll(epochDuration * (_passEpoch + 12)); harvest(actor.charlie_channel_owner); - uint256 bobClaimed = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); - uint256 aliceClaimed = coreProxy.usersRewardsClaimed(actor.alice_channel_owner); - uint256 charlieclaimed = coreProxy.usersRewardsClaimed(actor.charlie_channel_owner); - uint256 tonyclaimed = coreProxy.usersRewardsClaimed(actor.tony_channel_owner); + uint256 bobClaimed = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 aliceClaimed = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + uint256 charlieclaimed = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); + uint256 tonyclaimed = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); assertEq(charlieclaimed, tonyclaimed, "charlie and tony"); assertEq(bobClaimed, aliceClaimed, "bob and alice"); @@ -237,8 +237,8 @@ contract UserHarvest_test is BaseFuzzStaking { roll(epochDuration * _passEpoch); harvestPaginated(actor.bob_channel_owner, _passEpoch - 1); daoHarvest(actor.admin, _passEpoch - 1); - uint256 rewardsAd = coreProxy.usersRewardsClaimed(address(coreProxy)); - uint256 rewardsBob = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewardsAd = pushStaking.usersRewardsClaimed(address(coreProxy)); + uint256 rewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); assertApproxEqAbs(_fee * 1e18, rewardsBob, rewardsAd * 1e18); } @@ -267,8 +267,8 @@ contract UserHarvest_test is BaseFuzzStaking { stake(actor.bob_channel_owner, _amount); roll(epochDuration * _passEpoch); harvestPaginated(actor.bob_channel_owner, _passEpoch - 1); - (,,, uint256 _lastClaimedBlock) = coreProxy.userFeesInfo(actor.bob_channel_owner); - uint256 _nextFromEpoch = coreProxy.lastEpochRelative(genesisEpoch, _lastClaimedBlock); + (,,, uint256 _lastClaimedBlock) = pushStaking.userFeesInfo(actor.bob_channel_owner); + uint256 _nextFromEpoch = pushStaking.lastEpochRelative(genesisEpoch, _lastClaimedBlock); vm.expectRevert( abi.encodeWithSelector(Errors.InvalidArg_LessThanExpected.selector, _nextFromEpoch, _passEpoch - 1) ); @@ -293,8 +293,8 @@ contract UserHarvest_test is BaseFuzzStaking { harvest(actor.bob_channel_owner); daoHarvest(actor.admin, _passEpoch - 1); - uint256 rewardsB = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); - uint256 rewardsA = coreProxy.usersRewardsClaimed(address(coreProxy)); + uint256 rewardsB = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewardsA = pushStaking.usersRewardsClaimed(address(coreProxy)); uint256 expected = _fee * 3e18 - rewardsA; assertApproxEqAbs(rewardsB, expected, _fee * 1e18); } @@ -319,8 +319,8 @@ contract UserHarvest_test is BaseFuzzStaking { harvestPaginated(actor.bob_channel_owner, _passEpoch + 3); daoHarvest(actor.admin, _passEpoch + 3); - uint256 rewardsB = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); - uint256 rewardsA = coreProxy.usersRewardsClaimed(address(coreProxy)); + uint256 rewardsB = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewardsA = pushStaking.usersRewardsClaimed(address(coreProxy)); uint256 expected = _fee * 3e18 - rewardsA; assertApproxEqAbs(rewardsB, expected, 5 ether); } @@ -348,9 +348,9 @@ contract UserHarvest_test is BaseFuzzStaking { harvestPaginated(actor.bob_channel_owner, _passEpoch + 2); harvestPaginated(actor.bob_channel_owner, _passEpoch + 3); daoHarvest(actor.admin, _passEpoch + 3); - uint256 rewardsB = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); - uint256 rewardsA = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); - uint256 rewardsAd = coreProxy.usersRewardsClaimed(address(coreProxy)); + uint256 rewardsB = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewardsA = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewardsAd = pushStaking.usersRewardsClaimed(address(coreProxy)); uint256 expected = (_fee * 3e18 - rewardsAd) / 2; assertApproxEqAbs(rewardsB, expected, 5 ether); assertApproxEqAbs(rewardsA, expected, 5 ether); @@ -370,10 +370,10 @@ contract UserHarvest_test is BaseFuzzStaking { roll(epochDuration * _passEpoch); harvest(actor.bob_channel_owner); - uint256 rewardsBef = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewardsBef = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); roll(epochDuration * _passEpoch + 2); harvest(actor.bob_channel_owner); - uint256 rewardsAf = coreProxy.usersRewardsClaimed(actor.bob_channel_owner); + uint256 rewardsAf = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); assertEq(rewardsAf, rewardsBef); } } diff --git a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol index 47e540a4..da9ffa1c 100644 --- a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol +++ b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol @@ -7,23 +7,23 @@ contract BaseFuzzStaking is BaseTest { function setUp() public virtual override { BaseTest.setUp(); - genesisEpoch = coreProxy.genesisEpoch(); + genesisEpoch = pushStaking.genesisEpoch(); } //Helper Functions function stake(address signer, uint256 amount) internal { changePrank(signer); - coreProxy.stake(amount * 1e18); + pushStaking.stake(amount * 1e18); } function harvest(address signer) internal { changePrank(signer); - coreProxy.harvestAll(); + pushStaking.harvestAll(); } function harvestPaginated(address signer, uint256 _till) internal { changePrank(signer); - coreProxy.harvestPaginated(_till); + pushStaking.harvestPaginated(_till); } function addPool(uint256 amount) internal { @@ -33,15 +33,15 @@ contract BaseFuzzStaking is BaseTest { function unstake(address signer) internal { changePrank(signer); - coreProxy.unstake(); + pushStaking.unstake(); } function daoHarvest(address signer, uint256 _epoch) internal { changePrank(signer); - coreProxy.daoHarvestPaginated(_epoch); + pushStaking.daoHarvestPaginated(_epoch); } function getCurrentEpoch() public returns (uint256 currentEpoch) { - currentEpoch = coreProxy.lastEpochRelative(genesisEpoch, block.number); + currentEpoch = pushStaking.lastEpochRelative(genesisEpoch, block.number); } } From 4bd70df210acfc4be164209c5ea72aef79db2343 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Tue, 1 Oct 2024 16:26:26 +0530 Subject: [PATCH 08/49] fix errors --- contracts/PushStaking/PushStakingProxy.sol | 2 +- test/BaseTest.t.sol | 5 ++--- test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol | 11 +++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/contracts/PushStaking/PushStakingProxy.sol b/contracts/PushStaking/PushStakingProxy.sol index 5534c3e1..098dac46 100644 --- a/contracts/PushStaking/PushStakingProxy.sol +++ b/contracts/PushStaking/PushStakingProxy.sol @@ -17,7 +17,7 @@ contract PushStakingProxy is TransparentUpgradeableProxy { _logic, _governance, abi.encodeWithSignature( - "initialize(address,address,address,uint256,uint256,uint256,uint256,uint256)", + "initialize(address,address,address)", _pushChannelAdmin, _core, _pushTokenAddress diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index 5782568e..36ddd99f 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -151,7 +151,7 @@ abstract contract BaseTest is Test, Constants, Events { //Setup PushStaking Contracts pushStakingProxyAdmin = new PushStakingAdmin(); pushStakingProxy = - new PushStakingProxy(address(pushStaking), actor.admin, address(coreProxy), actor.admin, address(pushToken)); + new PushStakingProxy(address(pushStaking), address(pushStakingProxyAdmin), address(coreProxy), actor.admin, address(pushToken)); pushStaking = PushStaking(address(pushStakingProxy)); // Set-up Core Address in Comm & Vice-Versa @@ -172,6 +172,7 @@ abstract contract BaseTest is Test, Constants, Events { commEthProxy.setPushTokenAddress(address(pushToken)); coreProxy.setPushCommunicatorAddress(address(commEthProxy)); commProxy.setCoreFeeConfig(ADD_CHANNEL_MIN_FEES, FEE_AMOUNT, MIN_POOL_CONTRIBUTION); + coreProxy.updateStakingAddress(address(pushStaking)); vm.stopPrank(); // Approve tokens of actors now to core contract proxy address @@ -183,8 +184,6 @@ abstract contract BaseTest is Test, Constants, Events { approveTokens(actor.tony_channel_owner, address(coreProxy), 50_000 ether); approveTokens(actor.dan_push_holder, address(coreProxy), 50_000 ether); approveTokens(actor.tim_push_holder, address(coreProxy), 50_000 ether); - vm.prank(actor.admin); - pushStaking.initializeStake(); vm.warp(DEC_27_2021); } diff --git a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol index da9ffa1c..72c961c1 100644 --- a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol +++ b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol @@ -7,6 +7,17 @@ contract BaseFuzzStaking is BaseTest { function setUp() public virtual override { BaseTest.setUp(); + + approveTokens(actor.admin, address(pushStaking), 50_000 ether); + approveTokens(actor.governance, address(pushStaking), 50_000 ether); + approveTokens(actor.bob_channel_owner, address(pushStaking), 50_000 ether); + approveTokens(actor.alice_channel_owner, address(pushStaking), 50_000 ether); + approveTokens(actor.charlie_channel_owner, address(pushStaking), 50_000 ether); + approveTokens(actor.tony_channel_owner, address(pushStaking), 50_000 ether); + approveTokens(actor.dan_push_holder, address(pushStaking), 50_000 ether); + approveTokens(actor.tim_push_holder, address(pushStaking), 50_000 ether); + + pushStaking.initializeStake(); genesisEpoch = pushStaking.genesisEpoch(); } From b2c61c401edb882feed92276a3e2eb4546f681fd Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 4 Oct 2024 16:25:01 +0530 Subject: [PATCH 09/49] Changes in core --- contracts/PushCore/PushCoreStorageV1_5.sol | 2 +- contracts/PushCore/PushCoreStorageV2.sol | 2 +- contracts/PushCore/PushCoreV3.sol | 2 +- contracts/interfaces/IPushCoreStaking.sol | 2 +- contracts/libraries/DataTypes.sol | 12 +++++++++++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/contracts/PushCore/PushCoreStorageV1_5.sol b/contracts/PushCore/PushCoreStorageV1_5.sol index 0aa10bd1..e199c87a 100644 --- a/contracts/PushCore/PushCoreStorageV1_5.sol +++ b/contracts/PushCore/PushCoreStorageV1_5.sol @@ -40,7 +40,7 @@ contract PushCoreStorageV1_5 { /// @notice Necessary variables for Keeping track of Funds and Fees uint256 public CHANNEL_POOL_FUNDS; - uint256 public PROTOCOL_POOL_FEES; + uint256 public PROTOCOL_POOL_FEES; //unused storage uint256 public ADD_CHANNEL_MIN_FEES; uint256 public FEE_AMOUNT; uint256 public MIN_POOL_CONTRIBUTION; diff --git a/contracts/PushCore/PushCoreStorageV2.sol b/contracts/PushCore/PushCoreStorageV2.sol index 77e7d77a..1ca718e5 100644 --- a/contracts/PushCore/PushCoreStorageV2.sol +++ b/contracts/PushCore/PushCoreStorageV2.sol @@ -27,7 +27,7 @@ contract PushCoreStorageV2 { /// @notice Stores all the individual epoch rewards mapping(uint256 => uint256) public epochRewards; /// @notice Stores User's Fees Details - mapping(address => StakingTypes.UserFessInfo) public userFeesInfo; + mapping(address => StakingTypes.UserFeesInfo) public userFeesInfo; /// @notice Stores the total staked weight at a specific epoch. mapping(uint256 => uint256) public epochToTotalStakedWeight; diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index 57285197..0bc80b9c 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -209,7 +209,7 @@ contract PushCoreV3 is * about the Channel being created * @dev -Initializes the Channel Struct * -Subscribes the Channel's Owner to Imperative Push Channels as well as their Own Channels - * - Updates the CHANNEL_POOL_FUNDS and PROTOCOL_POOL_FEES in the contract. + * - Updates the CHANNEL_POOL_FUNDS and POOL_FEES in the contract. * * @param _channel address of the channel being Created * @param _channelType The type of the Channel diff --git a/contracts/interfaces/IPushCoreStaking.sol b/contracts/interfaces/IPushCoreStaking.sol index bdcb3670..49ae2b9e 100644 --- a/contracts/interfaces/IPushCoreStaking.sol +++ b/contracts/interfaces/IPushCoreStaking.sol @@ -3,6 +3,6 @@ pragma solidity ^0.8.20; interface IPushCoreStaking { function sendFunds(address _user, uint256 _amount) external; - function PROTOCOL_POOL_FEES() external view returns (uint256); + function HOLDER_FEE_POOL() external view returns (uint256); function WALLET_FEE_POOL() external view returns (uint256); } \ No newline at end of file diff --git a/contracts/libraries/DataTypes.sol b/contracts/libraries/DataTypes.sol index 10b240c6..4b981798 100644 --- a/contracts/libraries/DataTypes.sol +++ b/contracts/libraries/DataTypes.sol @@ -90,7 +90,7 @@ library CommTypes { library StakingTypes { /// @dev: Stores all user's staking details - struct UserFessInfo { + struct UserFeesInfo { ///@notice Total amount staked by a user at any given time uint256 stakedAmount; ///@notice weight of PUSH tokens staked by user @@ -106,6 +106,16 @@ library StakingTypes { uint256 percentageNumber; uint256 decimalPlaces; } + struct WalletShareInfo { + ///@notice Total amount staked by a user at any given time + uint256 walletShare; + ///@notice The last block when user staked + uint256 lastStakedBlock; + ///@notice The last block when user claimed rewards + uint256 lastClaimedBlock; + ///@notice Weight of staked amount of a user w.r.t total staked in a single epoch + mapping(uint256 => uint256) epochToWalletShares; + } } library CrossChainRequestTypes { From 701e848c8917e1752845a7f6c5a80ea8de48564a Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 4 Oct 2024 16:25:14 +0530 Subject: [PATCH 10/49] changes in staking --- contracts/PushStaking/PushStaking.sol | 211 ++++++++++++++----- contracts/PushStaking/PushStakingStorage.sol | 17 +- 2 files changed, 168 insertions(+), 60 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index f19455b3..c57684d4 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -16,19 +16,18 @@ contract PushStaking is Initializable, PushStakingStorage { event Staked(address indexed user, uint256 indexed amountStaked); event Unstaked(address indexed user, uint256 indexed amountUnstaked); event RewardsHarvested(address indexed user, uint256 indexed rewardAmount, uint256 fromEpoch, uint256 tillEpoch); + event NewSharesIssued(address indexed Wallet, uint256 indexed Shares); + event SharesRemoved(address indexed Wallet, uint256 indexed Shares); + event SharesDecreased(address indexed Wallet, uint256 indexed oldShares, uint256 newShares); - function initialize( - address _pushChannelAdmin, - address _core, - address _pushToken - ) - public - initializer - { + function initialize(address _pushChannelAdmin, address _core, address _pushToken) public initializer { pushChannelAdmin = _pushChannelAdmin; governance = _pushChannelAdmin; core = _core; PUSH_TOKEN_ADDRESS = _pushToken; + WALLET_TOTAL_SHARES = 100_000 * 1e18; + FOUNDATION = _pushChannelAdmin; + walletShareInfo[FOUNDATION].walletShare = WALLET_TOTAL_SHARES; } modifier onlyPushChannelAdmin() { @@ -57,76 +56,85 @@ contract PushStaking is Initializable, PushStakingStorage { } function initializeStake() external { - require( - genesisEpoch == 0, - "PushCoreV2::initializeStake: Already Initialized" - ); + require(genesisEpoch == 0, "PushCoreV2::initializeStake: Already Initialized"); genesisEpoch = block.number; lastEpochInitialized = genesisEpoch; _stake(core, 1e18); } - /* + /* * Fetching shares for a wallet * 1. Internal helper function * 2. helps in getting the shares to be assigned for a wallet based on params passed in this function - */ + */ function getSharesAmount( uint256 _totalShares, StakingTypes.Percentage memory _percentage ) public - pure returns (uint256 sharesToBeAllocated) { - if (_percentage.percentageNumber / 10 ** _percentage.decimalPlaces >= 100) revert Errors.InvalidArg_MoreThanExpected( 99,_percentage.decimalPlaces); - sharesToBeAllocated = (_percentage.percentageNumber * _totalShares) + if (_percentage.percentageNumber / 10 ** _percentage.decimalPlaces >= 100) { + revert Errors.InvalidArg_MoreThanExpected(99, _percentage.decimalPlaces); + } + sharesToBeAllocated = (_percentage.percentageNumber * _totalShares) / ((100 * (10 ** _percentage.decimalPlaces)) - _percentage.percentageNumber); } - /* + /* * Adding Wallet Share to a Wallet * 1. addWalletShare(address wallet, uint256 percentageOfShares) * 2. Can be called by governance. * 3. Uses the formulae to derive the percent of shares to be assigned to a specific wallet * 4. Updates WALLET_TOTAL_SHARES - * 5. Updates WalletToShares mapping + * 5. Updates walletShareInfo mapping * 6. Emits out an event. - * 7. If a wallet has already has a share, then it acts as a "increase share" function. And the percenatge passed + * 7. If a wallet has already has a share, then it acts as a "increase share" function. And the percenatge passed * should be greater than the already assigned percentge. - */ - function addWalletShare(address _walletAddress, StakingTypes.Percentage memory _percentage) public onlyGovernance{ - uint oldTotalShare = WALLET_TOTAL_SHARES; - uint currentWalletShare = WalletToShares[_walletAddress]; - uint newTotalShare; - - if( currentWalletShare != 0) { - newTotalShare = oldTotalShare - currentWalletShare; - }else{ - newTotalShare = oldTotalShare; + */ + function addWalletShare(address _walletAddress, StakingTypes.Percentage memory _percentage) public onlyGovernance { + uint256 TotalShare = WALLET_TOTAL_SHARES; + uint256 currentWalletShare = walletShareInfo[_walletAddress].walletShare; + if (currentWalletShare != 0) { + TotalShare -= currentWalletShare; + } + uint256 sharesToBeAllocated = getSharesAmount(TotalShare, _percentage); + if (sharesToBeAllocated < currentWalletShare) { + revert Errors.InvalidArg_LessThanExpected(currentWalletShare, sharesToBeAllocated); } - uint256 sharesToBeAllocated = getSharesAmount(newTotalShare, _percentage); - if (sharesToBeAllocated < currentWalletShare) revert Errors.InvalidArg_LessThanExpected(currentWalletShare, sharesToBeAllocated); - WALLET_TOTAL_SHARES = newTotalShare + sharesToBeAllocated; - WalletToShares[_walletAddress] = sharesToBeAllocated; + _adjustWalletAndTotalStake(_walletAddress, sharesToBeAllocated, false); + WALLET_TOTAL_SHARES = TotalShare + sharesToBeAllocated; + emit NewSharesIssued(_walletAddress, sharesToBeAllocated); } - /* + /* * Removing Wallet Share from a Wallet * 1. removes the shares from a wallet completely * 2. Can be called by governance. * 3. Updates WALLET_TOTAL_SHARES * 4. Emits out an event. - */ + */ + function removeWalletShare(address _walletAddress) public onlyGovernance { - WalletToShares[FOUNDATION] += WalletToShares[_walletAddress]; - WalletToShares[_walletAddress] = 0; + uint256 sharesToBeRemoved = walletShareInfo[_walletAddress].walletShare; + _adjustWalletAndTotalStake(_walletAddress, sharesToBeRemoved, true); + + walletShareInfo[FOUNDATION].walletShare += sharesToBeRemoved; + + emit SharesRemoved(_walletAddress, sharesToBeRemoved); } - function decreaseWalletShare(address _walletAddress, StakingTypes.Percentage memory _percentage) external onlyGovernance{ + function decreaseWalletShare( + address _walletAddress, + StakingTypes.Percentage memory _percentage + ) + external + onlyGovernance + { + uint256 sharesToBeRemoved = walletShareInfo[_walletAddress].walletShare; removeWalletShare(_walletAddress); - addWalletShare( _walletAddress, _percentage); - + addWalletShare(_walletAddress, _percentage); + emit SharesDecreased(_walletAddress, sharesToBeRemoved, walletShareInfo[_walletAddress].walletShare); } /* @@ -141,14 +149,36 @@ contract PushStaking is Initializable, PushStakingStorage { * 5. Reward can be calculated for wallets similar they are calculated for Token holders in a specific epoch. * Reward for a Given Wallet X = ( Wallet Share of X / WALLET_TOTAL_SHARES) * WALLET_FEE_POOL */ - //TODO logic yet to be finalized - function calculateWalletRewards(address _wallet) public returns(uint) { - return ( WalletToShares[_wallet] / WALLET_TOTAL_SHARES) * IPushCoreStaking(core).WALLET_FEE_POOL(); - } + //TODO logic yet to be finalized + function calculateWalletRewards(address _wallet, uint256 _epochId) public returns (uint256) { + return (walletShareInfo[_wallet].walletShare * epochRewardsForWallets[_epochId]) / epochToTotalShares[_epochId]; + } + + function claimShareRewards() external returns (uint256 rewards) { + _adjustUserAndTotalStake(msg.sender, 0, false); + + uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); + uint256 nextFromEpoch = lastEpochRelative(genesisEpoch, walletShareInfo[msg.sender].lastClaimedBlock); + + uint256 _tillEpoch = currentEpoch - 1; + + for (uint256 i = nextFromEpoch; i <= _tillEpoch; i++) { + uint256 claimableReward = calculateEpochRewards(msg.sender, i); + rewards = rewards + claimableReward; + } + + usersRewardsClaimed[msg.sender] = usersRewardsClaimed[msg.sender] + rewards; + // set the lastClaimedBlock to blocknumer at the end of `_tillEpoch` + uint256 _epoch_to_block_number = genesisEpoch + _tillEpoch * epochDuration; + userFeesInfo[msg.sender].lastClaimedBlock = _epoch_to_block_number; + + emit RewardsHarvested(msg.sender, rewards, nextFromEpoch, _tillEpoch); + } /** * @notice Function to return User's Push Holder weight based on amount being staked & current block number * */ + function _returnPushTokenWeight( address _account, uint256 _amount, @@ -180,7 +210,7 @@ contract PushStaking is Initializable, PushStakingStorage { * */ function calculateEpochRewards(address _user, uint256 _epochId) public view returns (uint256 rewards) { - rewards = (userFeesInfo[_user].epochToUserStakedWeight[_epochId] * epochRewards[_epochId]) + rewards = (userFeesInfo[_user].epochToUserStakedWeight[_epochId] * epochRewardsForStakers[_epochId]) / epochToTotalStakedWeight[_epochId]; } @@ -200,7 +230,6 @@ contract PushStaking is Initializable, PushStakingStorage { uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); uint256 blockNumberToConsider = genesisEpoch + (epochDuration * currentEpoch); uint256 userWeight = _returnPushTokenWeight(_staker, _amount, blockNumberToConsider); - IERC20(PUSH_TOKEN_ADDRESS).safeTransferFrom(msg.sender, core, _amount); userFeesInfo[_staker].stakedAmount = userFeesInfo[_staker].stakedAmount + _amount; @@ -286,7 +315,6 @@ contract PushStaking is Initializable, PushStakingStorage { * @param _tillEpoch - the end epoch number till which rewards shall be counted. * @dev _tillEpoch should never be equal to currentEpoch. * Transfers rewards to caller and updates user's details. - * */ function harvest(address _user, uint256 _tillEpoch) internal returns (uint256 rewards) { IPUSH(PUSH_TOKEN_ADDRESS).resetHolderWeight(_user); @@ -384,18 +412,19 @@ contract PushStaking is Initializable, PushStakingStorage { uint256 _lastEpochInitiliazed = lastEpochRelative(genesisEpoch, lastEpochInitialized); // Setting up Epoch Based Rewards if (_currentEpoch > _lastEpochInitiliazed || _currentEpoch == 1) { - uint256 PROTOCOL_POOL_FEES = IPushCoreStaking(core).PROTOCOL_POOL_FEES(); - uint256 availableRewardsPerEpoch = (PROTOCOL_POOL_FEES - previouslySetEpochRewards); + uint256 HOLDER_FEE_POOL = IPushCoreStaking(core).HOLDER_FEE_POOL(); + + uint256 availableRewardsPerEpoch = (HOLDER_FEE_POOL - previouslySetEpochRewards); uint256 _epochGap = _currentEpoch - _lastEpochInitiliazed; if (_epochGap > 1) { - epochRewards[_currentEpoch - 1] += availableRewardsPerEpoch; + epochRewardsForStakers[_currentEpoch - 1] += availableRewardsPerEpoch; } else { - epochRewards[_currentEpoch] += availableRewardsPerEpoch; + epochRewardsForStakers[_currentEpoch] += availableRewardsPerEpoch; } lastEpochInitialized = block.number; - previouslySetEpochRewards = PROTOCOL_POOL_FEES; + previouslySetEpochRewards = HOLDER_FEE_POOL; } // Setting up Epoch Based TotalWeight if (lastTotalStakeEpochInitialized == 0 || lastTotalStakeEpochInitialized == _currentEpoch) { @@ -415,4 +444,80 @@ contract PushStaking is Initializable, PushStakingStorage { } lastTotalStakeEpochInitialized = _currentEpoch; } + + function _adjustWalletAndTotalStake(address _wallet, uint256 _shares, bool isUnstake) internal { + uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); + _setupEpochsRewardAndWeights(_shares, currentEpoch, isUnstake); + + uint256 _walletPrevShares = walletShareInfo[_wallet].walletShare; + + // Initiating 1st Case: User stakes for first time + if (_walletPrevShares == 0) { + walletShareInfo[_wallet].walletShare = _shares; + } else { + // Initiating 2.1 Case: User stakes again but in Same Epoch + uint256 lastStakedEpoch = lastEpochRelative(genesisEpoch, walletShareInfo[_wallet].lastStakedBlock); + if (currentEpoch == lastStakedEpoch) { + walletShareInfo[_wallet].walletShare = isUnstake ? _walletPrevShares - _shares : _shares; + } else { + // Initiating 2.2 Case: User stakes again but in Different Epoch + for (uint256 i = lastStakedEpoch; i <= currentEpoch; i++) { + if (i != currentEpoch) { + walletShareInfo[_wallet].epochToWalletShares[i] = _walletPrevShares; + } else { + walletShareInfo[_wallet].walletShare = + isUnstake ? _walletPrevShares - _shares : _walletPrevShares + _shares; + walletShareInfo[_wallet].epochToWalletShares[i] = walletShareInfo[_wallet].walletShare; + } + } + } + } + + if (_shares != 0) { + walletShareInfo[_wallet].lastStakedBlock = block.number; + } + } + + /** + * @notice Internal function that allows setting up the rewards for specific EPOCH IDs + * @dev Initializes (sets reward) for every epoch ID that falls between the lastEpochInitialized and currentEpoch + * Reward amount for specific EPOCH Ids depends on newly available Protocol_Pool_Fees. + * - If no new fees was accumulated, rewards for particular epoch ids can be zero + * - Records the Pool_Fees value used as rewards. + * - Records the last epoch id whose rewards were set. + */ + function _setupEpochsRewardAndWeightsForWallets(uint256 _wallet, uint256 _currentEpoch, bool isUnstake) private { + uint256 _lastEpochInitiliazed = lastEpochRelative(genesisEpoch, lastEpochInitialized); + // Setting up Epoch Based Rewards + if (_currentEpoch > _lastEpochInitiliazed || _currentEpoch == 1) { + uint256 WALLET_FEE_POOL = IPushCoreStaking(core).WALLET_FEE_POOL(); + uint256 availableRewardsPerEpoch = (WALLET_FEE_POOL - previouslySetEpochRewards); + uint256 _epochGap = _currentEpoch - _lastEpochInitiliazed; + + if (_epochGap > 1) { + epochRewardsForWallets[_currentEpoch - 1] += availableRewardsPerEpoch; + } else { + epochRewardsForWallets[_currentEpoch] += availableRewardsPerEpoch; + } + + lastEpochInitialized = block.number; + previouslySetEpochRewards = WALLET_FEE_POOL; + } + // Setting up Epoch Based TotalWeight + if (lastTotalStakeEpochInitialized == 0 || lastTotalStakeEpochInitialized == _currentEpoch) { + epochToTotalShares[_currentEpoch] = + isUnstake ? epochToTotalShares[_currentEpoch] - _wallet : epochToTotalShares[_currentEpoch] + _wallet; + } else { + for (uint256 i = lastTotalStakeEpochInitialized + 1; i <= _currentEpoch - 1; i++) { + if (epochToTotalShares[i] == 0) { + epochToTotalShares[i] = epochToTotalShares[lastTotalStakeEpochInitialized]; + } + } + + epochToTotalShares[_currentEpoch] = isUnstake + ? epochToTotalShares[lastTotalStakeEpochInitialized] - _wallet + : epochToTotalShares[lastTotalStakeEpochInitialized] + _wallet; + } + lastTotalStakeEpochInitialized = _currentEpoch; + } } diff --git a/contracts/PushStaking/PushStakingStorage.sol b/contracts/PushStaking/PushStakingStorage.sol index 57348375..91adfb8a 100644 --- a/contracts/PushStaking/PushStakingStorage.sol +++ b/contracts/PushStaking/PushStakingStorage.sol @@ -14,7 +14,7 @@ contract PushStakingStorage { uint256 public totalStakedAmount; // Total token weight staked in Protocol at any given time uint256 public previouslySetEpochRewards; // Amount of rewards set in last initialized epoch uint256 public constant epochDuration = 21 * 7156; // 21 * number of blocks per day(7156) ~ 20 day approx - uint256 public WALLET_TOTAL_SHARES; //Total Sga + uint256 public WALLET_TOTAL_SHARES; //Total Shares address public pushChannelAdmin; address public PUSH_TOKEN_ADDRESS; @@ -22,14 +22,17 @@ contract PushStakingStorage { address public core; address public FOUNDATION; - /// @notice Stores all the individual epoch rewards - mapping(uint256 => uint256) public epochRewards; + /// @notice Stores all the individual epoch rewards for stakers + mapping(uint256 => uint256) public epochRewardsForStakers; + /// @notice Stores all the individual epoch rewards for Wallet share holders + mapping(uint256 => uint256) public epochRewardsForWallets; /// @notice Stores User's Fees Details - mapping(address => StakingTypes.UserFessInfo) public userFeesInfo; + mapping(address => StakingTypes.UserFeesInfo) public userFeesInfo; + ///@notice stores Wallet share details for a given address + mapping(address => StakingTypes.WalletShareInfo) public walletShareInfo; /// @notice Stores the total staked weight at a specific epoch. mapping(uint256 => uint256) public epochToTotalStakedWeight; - ///@notice Stores the shares acquired by a given wallet - mapping(address wallet => uint256 sharesAmount) public WalletToShares ; - mapping(address wallet => uint256 sharesAmount) public WalletToRewards ; + ///@notice stores the total shares in a specific epoch + mapping(uint256 => uint256) public epochToTotalShares; bool migrated; } From 9ee87cb42a0b198a1aeced5c9c9d3ff19f7c5c1c Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 4 Oct 2024 16:25:25 +0530 Subject: [PATCH 11/49] test addition --- test/BaseTest.t.sol | 2 +- .../fuzz_tests/BaseFuzzStaking.f.sol | 1 + .../unit_tests/WalletShare/WalletShare.t.sol | 261 ++++++++++++++++++ .../unit_tests/WalletShare/WalletShare.tree | 17 ++ 4 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol create mode 100644 test/PushStaking/unit_tests/WalletShare/WalletShare.tree diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index 36ddd99f..1ff62a1b 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -151,7 +151,7 @@ abstract contract BaseTest is Test, Constants, Events { //Setup PushStaking Contracts pushStakingProxyAdmin = new PushStakingAdmin(); pushStakingProxy = - new PushStakingProxy(address(pushStaking), address(pushStakingProxyAdmin), address(coreProxy), actor.admin, address(pushToken)); + new PushStakingProxy(address(pushStaking), address(pushStakingProxyAdmin), actor.admin, address(coreProxy), address(pushToken)); pushStaking = PushStaking(address(pushStakingProxy)); // Set-up Core Address in Comm & Vice-Versa diff --git a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol index 72c961c1..3cac2319 100644 --- a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol +++ b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol @@ -17,6 +17,7 @@ contract BaseFuzzStaking is BaseTest { approveTokens(actor.dan_push_holder, address(pushStaking), 50_000 ether); approveTokens(actor.tim_push_holder, address(pushStaking), 50_000 ether); + changePrank(actor.admin); pushStaking.initializeStake(); genesisEpoch = pushStaking.genesisEpoch(); } diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol new file mode 100644 index 00000000..1ca6de30 --- /dev/null +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + + +import { BaseFuzzStaking } from "../../fuzz_tests/BaseFuzzStaking.f.sol"; +import { StakingTypes } from "../../../../contracts/libraries/DataTypes.sol"; +import {console2} from "forge-std/console2.sol"; + +contract WalletShareTest is BaseFuzzStaking{ + + + /// @dev A function invoked before each test case is run. + function setUp() public virtual override { + BaseFuzzStaking.setUp(); + + } + + function test_FoundationGetsInitialShares() public { + uint256 initialSharesAmount = 100_000 * 1e18; + (uint256 foundationWalletShares,,) = pushStaking.walletShareInfo(actor.admin); + uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + assertEq(initialSharesAmount, foundationWalletShares); + assertEq(foundationWalletShares, actualTotalShares); + } + + function test_WalletGets_20PercentAllocation() public { + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + uint256 expectedAllocationShares = 25_000 * 1e18; + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + + assertEq(bobWalletSharesBefore, 0); + assertEq(bobWalletSharesAfter, expectedAllocationShares); + assertEq(actualTotalShares, 125_000 * 1e18); + console2.log(bobWalletSharesAfter * 100, actualTotalShares); + + uint percentage = (bobWalletSharesAfter * 100)/actualTotalShares; + assertEq(percentage, percentAllocation.percentageNumber); + } + + + function test_WalletGets_50PercentAllocation() public { + // bob wallet gets allocated 20% shares i.e. 25k + test_WalletGets_20PercentAllocation(); + + (uint256 aliceWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.alice_channel_owner, percentAllocation); + uint256 expectedAllocationShares = 125_000 * 1e18; + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); + uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + + assertEq(aliceWalletSharesBefore, 0); + assertEq(bobWalletSharesAfter, 25_000 * 1e18); + assertEq(aliceWalletSharesAfter, expectedAllocationShares); + assertEq(foundationWalletSharesAfter, 100_000 * 1e18); + assertEq(actualTotalShares, 250_000 * 1e18); + uint percentage = (aliceWalletSharesAfter * 100)/actualTotalShares; + assertEq(percentage, percentAllocation.percentageNumber); + } + + // removes wallet allocation and assign shares to the foundation + function test_RemovalWalletM2() public { + // actor.bob_channel_owner has 20% allocation (25k shares), actor.alice_channel_owner has 50% (125k) & foundation (100k) + test_WalletGets_50PercentAllocation(); + + uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); + + changePrank(actor.admin); + pushStaking.removeWalletShare(actor.bob_channel_owner); + + uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); + + assertEq(bobWalletSharesAfter, 0,"bob wallet share"); + assertEq(aliceWalletSharesAfter, aliceWalletSharesBefore,"akice wallet share"); + assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + bobWalletSharesBefore,"foundation wallet share"); + assertEq(totalSharesAfter, totalSharesBefore,"total wallet share"); + } + // testing add wallet after removal with method m2 (assign shares to foundation) + function test_AddWallet_AfterRemoval_M2() public { + test_RemovalWalletM2(); + (uint256 charlieWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation); + uint256 expectedAllocationShares = 250_000 * 1e18; + (uint256 charlieWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + + assertEq(charlieWalletSharesBefore, 0); + assertEq(charlieWalletSharesAfter, expectedAllocationShares); + assertEq(totalSharesAfter, 500_000 * 1e18); + } + + // assign wallet 0.001% shares + function test_WalletGets_NegligiblePercentAllocation() public { + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 3 }); + + uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(),percentAllocation); + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + + assertEq(bobWalletSharesBefore, 0); + assertEq(bobWalletSharesAfter, expectedAllocationShares); + assertEq(actualTotalShares, 100_000 * 1e18 + expectedAllocationShares); + } + + // assign wallet 0.0001% shares + function test_WalletGets_NegligiblePercentAllocation2() public { + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 4 }); + + uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(),percentAllocation); + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + console2.log(expectedAllocationShares,bobWalletSharesAfter,actualTotalShares); + assertEq(bobWalletSharesBefore, 0); + assertEq(bobWalletSharesAfter, expectedAllocationShares); + console2.log(bobWalletSharesBefore,bobWalletSharesAfter); + assertEq(actualTotalShares, 100_000 * 1e18 + expectedAllocationShares); + } + + function test_IncreaseWalletShare() public { + // assigns actor.bob_channel_owner 20% allocation + test_WalletGets_20PercentAllocation(); + + // let's increase actor.bob_channel_owner allocation to 50% + uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); + + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + uint256 expectedAllocationShares = 100_000* 1e18; + uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); + + assertEq(bobWalletSharesBefore, 25_000* 1e18,"bob wallet share"); + assertEq(totalSharesBefore, 125_000* 1e18,"total wallet share"); + assertEq(foundationWalletSharesBefore, 100_000* 1e18,"foundation wallet share"); + assertEq(bobWalletSharesAfter, expectedAllocationShares,"bob wallet share after"); + assertEq(totalSharesAfter, 200_000* 1e18,"total wallet share after"); + assertEq(foundationWalletSharesAfter, 100_000* 1e18,"foundation wallet share after"); + } + + function test_RevertWhen_DecreaseWalletShare_UsingAdd() public { + // assigns actor.bob_channel_owner 20% allocation + test_WalletGets_20PercentAllocation(); + + // let's increase actor.bob_channel_owner allocation to 50% + uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + + changePrank(actor.admin); + vm.expectRevert(); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + + assertEq(bobWalletSharesBefore, bobWalletSharesAfter); + assertEq(actualTotalShares, totalSharesBefore); + + uint percentage = (bobWalletSharesAfter * 100)/actualTotalShares; + assertEq(percentage, 20); + } + + function test_DecreaseWalletShare() public { + // assigns actor.bob_channel_owner 20% allocation + test_WalletGets_20PercentAllocation(); + + // let's decrease actor.bob_channel_owner allocation to 10% + uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); + + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + + uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(),percentAllocation); + changePrank(actor.admin); + pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation); + uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); + + assertEq(bobWalletSharesBefore, 25_000 * 1e18); + assertEq(totalSharesBefore, 125_000 * 1e18); + assertEq(foundationWalletSharesBefore, 100_000 * 1e18); + assertEq(bobWalletSharesAfter, expectedAllocationShares); + assertEq(totalSharesAfter, 125_000 * 1e18 + expectedAllocationShares); + assertEq(foundationWalletSharesAfter, 125_000 * 1e18 ); + } + + // FUZZ TESTS + function testFuzz_AddShares(address _walletAddress, StakingTypes.Percentage memory _percentage) public { + _percentage.percentageNumber = bound(_percentage.percentageNumber,0,100); + _percentage.decimalPlaces = bound(_percentage.decimalPlaces,0,10); + // percentage must be less than 100 + vm.assume(_percentage.percentageNumber / 10 ** _percentage.decimalPlaces < 100); + changePrank(actor.admin); + pushStaking.addWalletShare(_walletAddress, _percentage); + } + + function testFuzz_RemoveShares(address _walletAddress, StakingTypes.Percentage memory _percentage) public { + _percentage.percentageNumber = bound(_percentage.percentageNumber,0,100); + vm.assume(_percentage.decimalPlaces < 10); + // percentage must be less than 100 + vm.assume(_percentage.percentageNumber / 10 ** _percentage.decimalPlaces < 100); + testFuzz_AddShares(_walletAddress, _percentage); + + changePrank(actor.admin); + pushStaking.removeWalletShare(_walletAddress); + (uint256 foundationWalletShares,,) = pushStaking.walletShareInfo(actor.admin); + + assertEq(pushStaking.WALLET_TOTAL_SHARES(), foundationWalletShares); + } + + function test_MaxDecimalAmount () public { + // fixed at most 10 decimal places + // percentage = 10.1111111111 + StakingTypes.Percentage memory _percentage = StakingTypes.Percentage({ + percentageNumber: 101111111111, + decimalPlaces: 10 + }); + + for (uint256 i=1; i<50; i++) { + uint256 shares = pushStaking.getSharesAmount({ + _totalShares: 10 ** i, + _percentage: _percentage + }); + console2.log("totalShares = ", i); + console2.log(shares/1e18); + console2.log(""); + } + } +} \ No newline at end of file diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.tree b/test/PushStaking/unit_tests/WalletShare/WalletShare.tree new file mode 100644 index 00000000..e73c15f9 --- /dev/null +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.tree @@ -0,0 +1,17 @@ +#when inititalize +## it should assign foundation a constant value +#when governance adds shares to a wallet +##when governance adds to a single wallet +### it should update the state Variables correctly +##when governance adds to another wallet +### it should update variables, without disturbing the previous allotment +#when governance removes wallet +##it should allot the shares to foundation +#when governance adds a very small percentage +## it should add negligible percentage too +# when governance increase shares +## it should increase the shares +# when governance decreases shares +## it should decrease and allot those to the foundation + + From 6c52596b6785fbb360267c6459ca27352544bec5 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 4 Oct 2024 17:21:43 +0530 Subject: [PATCH 12/49] additional fixes for failing tests --- contracts/PushCore/PushCoreV3.sol | 1 + contracts/PushStaking/PushStaking.sol | 5 +---- contracts/interfaces/IPUSH.sol | 2 +- test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol | 6 ++++++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index 0bc80b9c..7b7b18a6 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -489,6 +489,7 @@ contract PushCoreV3 is function updateStakingAddress(address _stakingAddress) external { onlyPushChannelAdmin(); STAKING_CONTRACT = _stakingAddress; + IPUSH(PUSH_TOKEN_ADDRESS).setHolderDelegation(_stakingAddress,true); } function sendFunds(address _user, uint256 _amount) external { diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index c57684d4..cc971244 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -301,10 +301,7 @@ contract PushStaking is Initializable, PushStakingStorage { * Unlike other harvest functions, this is designed to transfer rewards to Push Governance. * */ - function daoHarvestPaginated(uint256 _tillEpoch) external { - if (msg.sender != governance) { - revert Errors.CallerNotAdmin(); - } + function daoHarvestPaginated(uint256 _tillEpoch) external onlyGovernance{ uint256 rewards = harvest(core, _tillEpoch); IPushCoreStaking(core).sendFunds(msg.sender, rewards); } diff --git a/contracts/interfaces/IPUSH.sol b/contracts/interfaces/IPUSH.sol index c223b8bb..58ae7005 100644 --- a/contracts/interfaces/IPUSH.sol +++ b/contracts/interfaces/IPUSH.sol @@ -6,7 +6,7 @@ interface IPUSH { function resetHolderWeight(address holder) external; function holderWeight(address) external view returns (uint256); function returnHolderUnits(address account, uint256 atBlock) external view returns (uint256); - + function setHolderDelegation(address delegate, bool value) external ; // ----------- Additional Functions for NTT Support ------------- // // NOTE: the `mint` method is not present in the standard ERC20 interface. diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol index 1ca6de30..47739d62 100644 --- a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -42,6 +42,12 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(percentage, percentAllocation.percentageNumber); } + function test_whenWallet_TriesTo_ClaimRewards()external { + test_WalletGets_20PercentAllocation(); + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + } + function test_WalletGets_50PercentAllocation() public { // bob wallet gets allocated 20% shares i.e. 25k From cb79c8012dcdcc2666292cd6867fc15277b6f071 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Mon, 7 Oct 2024 02:44:01 +0530 Subject: [PATCH 13/49] fixes --- contracts/PushStaking/PushStaking.sol | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index cc971244..5538f323 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -9,7 +9,7 @@ import { Errors } from "../libraries/Errors.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; - +import { console } from "lib/forge-std/src/console.sol"; contract PushStaking is Initializable, PushStakingStorage { using SafeERC20 for IERC20; @@ -103,6 +103,8 @@ contract PushStaking is Initializable, PushStakingStorage { if (sharesToBeAllocated < currentWalletShare) { revert Errors.InvalidArg_LessThanExpected(currentWalletShare, sharesToBeAllocated); } + walletShareInfo[_walletAddress].lastClaimedBlock = + walletShareInfo[_walletAddress].lastClaimedBlock == 0 ? genesisEpoch : walletShareInfo[_walletAddress].lastClaimedBlock; _adjustWalletAndTotalStake(_walletAddress, sharesToBeAllocated, false); WALLET_TOTAL_SHARES = TotalShare + sharesToBeAllocated; emit NewSharesIssued(_walletAddress, sharesToBeAllocated); @@ -155,7 +157,7 @@ contract PushStaking is Initializable, PushStakingStorage { } function claimShareRewards() external returns (uint256 rewards) { - _adjustUserAndTotalStake(msg.sender, 0, false); + _adjustWalletAndTotalStake(msg.sender, 0, false); uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); uint256 nextFromEpoch = lastEpochRelative(genesisEpoch, walletShareInfo[msg.sender].lastClaimedBlock); @@ -163,7 +165,7 @@ contract PushStaking is Initializable, PushStakingStorage { uint256 _tillEpoch = currentEpoch - 1; for (uint256 i = nextFromEpoch; i <= _tillEpoch; i++) { - uint256 claimableReward = calculateEpochRewards(msg.sender, i); + uint256 claimableReward = calculateWalletRewards(msg.sender, i); rewards = rewards + claimableReward; } @@ -171,6 +173,7 @@ contract PushStaking is Initializable, PushStakingStorage { // set the lastClaimedBlock to blocknumer at the end of `_tillEpoch` uint256 _epoch_to_block_number = genesisEpoch + _tillEpoch * epochDuration; userFeesInfo[msg.sender].lastClaimedBlock = _epoch_to_block_number; + IPushCoreStaking(core).sendFunds(msg.sender, rewards); emit RewardsHarvested(msg.sender, rewards, nextFromEpoch, _tillEpoch); } @@ -444,7 +447,7 @@ contract PushStaking is Initializable, PushStakingStorage { function _adjustWalletAndTotalStake(address _wallet, uint256 _shares, bool isUnstake) internal { uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); - _setupEpochsRewardAndWeights(_shares, currentEpoch, isUnstake); + _setupEpochsRewardAndWeightsForWallets(_shares, currentEpoch, isUnstake); uint256 _walletPrevShares = walletShareInfo[_wallet].walletShare; From 9d783fcb46ccf842015f6398f8d26909d7fadca0 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Mon, 7 Oct 2024 15:47:39 +0530 Subject: [PATCH 14/49] updates for claim --- contracts/PushStaking/PushStaking.sol | 1 - test/BaseTest.t.sol | 1 + .../unit_tests/WalletShare/WalletShare.t.sol | 33 ++++++++++--------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index 5538f323..98a03d07 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -9,7 +9,6 @@ import { Errors } from "../libraries/Errors.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import { console } from "lib/forge-std/src/console.sol"; contract PushStaking is Initializable, PushStakingStorage { using SafeERC20 for IERC20; diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index 1ff62a1b..1688240e 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -173,6 +173,7 @@ abstract contract BaseTest is Test, Constants, Events { coreProxy.setPushCommunicatorAddress(address(commEthProxy)); commProxy.setCoreFeeConfig(ADD_CHANNEL_MIN_FEES, FEE_AMOUNT, MIN_POOL_CONTRIBUTION); coreProxy.updateStakingAddress(address(pushStaking)); + coreProxy.splitFeePool(50); vm.stopPrank(); // Approve tokens of actors now to core contract proxy address diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol index 47739d62..98ae03c7 100644 --- a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -24,27 +24,28 @@ contract WalletShareTest is BaseFuzzStaking{ } function test_WalletGets_20PercentAllocation() public { - (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); uint256 expectedAllocationShares = 25_000 * 1e18; - (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); assertEq(bobWalletSharesBefore, 0); assertEq(bobWalletSharesAfter, expectedAllocationShares); assertEq(actualTotalShares, 125_000 * 1e18); - console2.log(bobWalletSharesAfter * 100, actualTotalShares); uint percentage = (bobWalletSharesAfter * 100)/actualTotalShares; assertEq(percentage, percentAllocation.percentageNumber); } function test_whenWallet_TriesTo_ClaimRewards()external { + addPool(1000); test_WalletGets_20PercentAllocation(); changePrank(actor.bob_channel_owner); + roll(epochDuration * 2); pushStaking.claimShareRewards(); } @@ -59,7 +60,7 @@ contract WalletShareTest is BaseFuzzStaking{ changePrank(actor.admin); pushStaking.addWalletShare(actor.alice_channel_owner, percentAllocation); uint256 expectedAllocationShares = 125_000 * 1e18; - (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 aliceWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); @@ -79,7 +80,7 @@ contract WalletShareTest is BaseFuzzStaking{ test_WalletGets_50PercentAllocation(); uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 aliceWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); @@ -87,7 +88,7 @@ contract WalletShareTest is BaseFuzzStaking{ pushStaking.removeWalletShare(actor.bob_channel_owner); uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 aliceWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); @@ -116,13 +117,13 @@ contract WalletShareTest is BaseFuzzStaking{ // assign wallet 0.001% shares function test_WalletGets_NegligiblePercentAllocation() public { - (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 3 }); uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(),percentAllocation); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); - (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); assertEq(bobWalletSharesBefore, 0); @@ -132,13 +133,13 @@ contract WalletShareTest is BaseFuzzStaking{ // assign wallet 0.0001% shares function test_WalletGets_NegligiblePercentAllocation2() public { - (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 4 }); uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(),percentAllocation); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); - (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); console2.log(expectedAllocationShares,bobWalletSharesAfter,actualTotalShares); assertEq(bobWalletSharesBefore, 0); @@ -153,7 +154,7 @@ contract WalletShareTest is BaseFuzzStaking{ // let's increase actor.bob_channel_owner allocation to 50% uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); @@ -162,7 +163,7 @@ contract WalletShareTest is BaseFuzzStaking{ pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); uint256 expectedAllocationShares = 100_000* 1e18; uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); assertEq(bobWalletSharesBefore, 25_000* 1e18,"bob wallet share"); @@ -179,14 +180,14 @@ contract WalletShareTest is BaseFuzzStaking{ // let's increase actor.bob_channel_owner allocation to 50% uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); changePrank(actor.admin); vm.expectRevert(); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); - (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); assertEq(bobWalletSharesBefore, bobWalletSharesAfter); @@ -202,7 +203,7 @@ contract WalletShareTest is BaseFuzzStaking{ // let's decrease actor.bob_channel_owner allocation to 10% uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); @@ -211,7 +212,7 @@ contract WalletShareTest is BaseFuzzStaking{ changePrank(actor.admin); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation); uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); assertEq(bobWalletSharesBefore, 25_000 * 1e18); From c188eedbe4c3058e55b95ec784b8a94eb169498b Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Tue, 8 Oct 2024 02:51:36 +0530 Subject: [PATCH 15/49] updates --- contracts/PushStaking/PushStaking.sol | 4 ++-- test/BaseTest.t.sol | 7 +------ test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol | 2 +- test/utils/Constants.sol | 7 +++++++ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index 98a03d07..d687e478 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -151,7 +151,7 @@ contract PushStaking is Initializable, PushStakingStorage { * Reward for a Given Wallet X = ( Wallet Share of X / WALLET_TOTAL_SHARES) * WALLET_FEE_POOL */ //TODO logic yet to be finalized - function calculateWalletRewards(address _wallet, uint256 _epochId) public returns (uint256) { + function calculateWalletRewards(address _wallet, uint256 _epochId) public view returns (uint256) { return (walletShareInfo[_wallet].walletShare * epochRewardsForWallets[_epochId]) / epochToTotalShares[_epochId]; } @@ -171,7 +171,7 @@ contract PushStaking is Initializable, PushStakingStorage { usersRewardsClaimed[msg.sender] = usersRewardsClaimed[msg.sender] + rewards; // set the lastClaimedBlock to blocknumer at the end of `_tillEpoch` uint256 _epoch_to_block_number = genesisEpoch + _tillEpoch * epochDuration; - userFeesInfo[msg.sender].lastClaimedBlock = _epoch_to_block_number; + walletShareInfo[msg.sender].lastClaimedBlock = _epoch_to_block_number; IPushCoreStaking(core).sendFunds(msg.sender, rewards); emit RewardsHarvested(msg.sender, rewards, nextFromEpoch, _tillEpoch); diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index 1688240e..a7a4fa63 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -59,11 +59,6 @@ abstract contract BaseTest is Test, Constants, Events { /* *************** State Variables *************** */ - uint256 ADD_CHANNEL_MIN_FEES = 50 ether; - uint256 ADD_CHANNEL_MAX_POOL_CONTRIBUTION = 250 ether; - uint256 FEE_AMOUNT = 10 ether; - uint256 MIN_POOL_CONTRIBUTION = 1 ether; - uint256 ADJUST_FOR_FLOAT = 10 ** 7; mapping(address => uint256) privateKeys; /* *************** @@ -173,7 +168,7 @@ abstract contract BaseTest is Test, Constants, Events { coreProxy.setPushCommunicatorAddress(address(commEthProxy)); commProxy.setCoreFeeConfig(ADD_CHANNEL_MIN_FEES, FEE_AMOUNT, MIN_POOL_CONTRIBUTION); coreProxy.updateStakingAddress(address(pushStaking)); - coreProxy.splitFeePool(50); + coreProxy.splitFeePool(HOLDER_SPLIT); vm.stopPrank(); // Approve tokens of actors now to core contract proxy address diff --git a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol index 3cac2319..b374cb49 100644 --- a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol +++ b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol @@ -53,7 +53,7 @@ contract BaseFuzzStaking is BaseTest { pushStaking.daoHarvestPaginated(_epoch); } - function getCurrentEpoch() public returns (uint256 currentEpoch) { + function getCurrentEpoch() public view returns (uint256 currentEpoch) { currentEpoch = pushStaking.lastEpochRelative(genesisEpoch, block.number); } } diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index bac6c5ea..6d53adae 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -20,6 +20,13 @@ abstract contract Constants { uint256 public totalStakedAmount = 0 ether; uint256 public previouslySetEpochRewards = 0 ether; + uint256 ADD_CHANNEL_MIN_FEES = 50 ether; + uint256 ADD_CHANNEL_MAX_POOL_CONTRIBUTION = 250 ether; + uint256 FEE_AMOUNT = 10 ether; + uint256 MIN_POOL_CONTRIBUTION = 1 ether; + uint256 ADJUST_FOR_FLOAT = 10 ** 7; + uint256 HOLDER_SPLIT = 50; + //Comm Constants used for meta transaction string public constant name = "Push COMM V1"; bytes32 public constant NAME_HASH = keccak256(bytes(name)); From 5936ac19915acc3a3413c0ffb57cda82d8a0e87a Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Tue, 8 Oct 2024 15:51:10 +0530 Subject: [PATCH 16/49] fix claim --- contracts/PushStaking/PushStaking.sol | 11 ++-- .../unit_tests/WalletShare/WalletShare.t.sol | 54 +++++++++++++++++-- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index d687e478..e6e34f33 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -27,6 +27,7 @@ contract PushStaking is Initializable, PushStakingStorage { WALLET_TOTAL_SHARES = 100_000 * 1e18; FOUNDATION = _pushChannelAdmin; walletShareInfo[FOUNDATION].walletShare = WALLET_TOTAL_SHARES; + epochToTotalShares[1] = 100_000 * 1e18; } modifier onlyPushChannelAdmin() { @@ -152,7 +153,7 @@ contract PushStaking is Initializable, PushStakingStorage { */ //TODO logic yet to be finalized function calculateWalletRewards(address _wallet, uint256 _epochId) public view returns (uint256) { - return (walletShareInfo[_wallet].walletShare * epochRewardsForWallets[_epochId]) / epochToTotalShares[_epochId]; + return (walletShareInfo[_wallet].epochToWalletShares[_epochId] * epochRewardsForWallets[_epochId]) / epochToTotalShares[_epochId]; } function claimShareRewards() external returns (uint256 rewards) { @@ -485,7 +486,7 @@ contract PushStaking is Initializable, PushStakingStorage { * - Records the Pool_Fees value used as rewards. * - Records the last epoch id whose rewards were set. */ - function _setupEpochsRewardAndWeightsForWallets(uint256 _wallet, uint256 _currentEpoch, bool isUnstake) private { + function _setupEpochsRewardAndWeightsForWallets(uint256 _shares, uint256 _currentEpoch, bool isUnstake) private { uint256 _lastEpochInitiliazed = lastEpochRelative(genesisEpoch, lastEpochInitialized); // Setting up Epoch Based Rewards if (_currentEpoch > _lastEpochInitiliazed || _currentEpoch == 1) { @@ -505,7 +506,7 @@ contract PushStaking is Initializable, PushStakingStorage { // Setting up Epoch Based TotalWeight if (lastTotalStakeEpochInitialized == 0 || lastTotalStakeEpochInitialized == _currentEpoch) { epochToTotalShares[_currentEpoch] = - isUnstake ? epochToTotalShares[_currentEpoch] - _wallet : epochToTotalShares[_currentEpoch] + _wallet; + isUnstake ? epochToTotalShares[_currentEpoch] - _shares : epochToTotalShares[_currentEpoch] + _shares; } else { for (uint256 i = lastTotalStakeEpochInitialized + 1; i <= _currentEpoch - 1; i++) { if (epochToTotalShares[i] == 0) { @@ -514,8 +515,8 @@ contract PushStaking is Initializable, PushStakingStorage { } epochToTotalShares[_currentEpoch] = isUnstake - ? epochToTotalShares[lastTotalStakeEpochInitialized] - _wallet - : epochToTotalShares[lastTotalStakeEpochInitialized] + _wallet; + ? epochToTotalShares[lastTotalStakeEpochInitialized] - _shares + : epochToTotalShares[lastTotalStakeEpochInitialized] + _shares; } lastTotalStakeEpochInitialized = _currentEpoch; } diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol index 98ae03c7..a1d21187 100644 --- a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -41,12 +41,62 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(percentage, percentAllocation.percentageNumber); } - function test_whenWallet_TriesTo_ClaimRewards()external { + function test_whenWallet_ClaimRewards_for20Percent()external { addPool(1000); test_WalletGets_20PercentAllocation(); changePrank(actor.bob_channel_owner); roll(epochDuration * 2); + uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); pushStaking.claimShareRewards(); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + assertEq(bobWalletSharesBefore,bobWalletSharesAfter,"Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter,"StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + + uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint expectedRewards = coreProxy.WALLET_FEE_POOL(); + assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner),"ClaimedBlock"); + assertEq(expectedRewards,claimedRewards); + } + + function test_whenWallets_ClaimRewards_for_20_50_Percent()external { + addPool(1000); + test_WalletGets_50PercentAllocation(); + roll(epochDuration * 2); + uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 balanceAliceBefore = pushToken.balanceOf(actor.alice_channel_owner); + (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.alice_channel_owner); + + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + changePrank(actor.alice_channel_owner); + pushStaking.claimShareRewards(); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter , uint256 aliceClaimedBlockAfter) = pushStaking.walletShareInfo(actor.alice_channel_owner); + + assertEq(bobWalletSharesBefore,bobWalletSharesAfter,"Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter,"StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + + uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + + uint expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10)/100; + console2.log(expectedRewardsBob,claimedRewardsBob); + assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner),"balanceBob"); + assertEq(expectedRewardsBob, claimedRewardsBob,"bobClaimed"); + + assertEq(aliceWalletSharesBefore,aliceWalletSharesAfter,"Shares"); + assertEq(aliceStakedBlockBefore,aliceStakedBlockAfter,"StakedBlock"); + assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + + uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + uint expectedRewardsAlice = coreProxy.WALLET_FEE_POOL()* 50/100; + assertEq(balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner),"balanceAlice"); + assertEq(expectedRewardsAlice,claimedRewardsAlice,"Alice Claimed"); } @@ -141,10 +191,8 @@ contract WalletShareTest is BaseFuzzStaking{ pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); - console2.log(expectedAllocationShares,bobWalletSharesAfter,actualTotalShares); assertEq(bobWalletSharesBefore, 0); assertEq(bobWalletSharesAfter, expectedAllocationShares); - console2.log(bobWalletSharesBefore,bobWalletSharesAfter); assertEq(actualTotalShares, 100_000 * 1e18 + expectedAllocationShares); } From e6d1cb90ff9d1579084a68aaea766095aa6ed2b5 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 9 Oct 2024 01:12:16 +0530 Subject: [PATCH 17/49] fix miss --- contracts/PushCore/PushCoreV3.sol | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index 7b7b18a6..6dd464a3 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -173,8 +173,8 @@ contract PushCoreV3 is } uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _amount) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = _amount - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += _amount - holderFee; channelUpdateCounter[_channel] = updateCounter; @@ -245,8 +245,8 @@ contract PushCoreV3 is //store funds in pool_funds & pool_fees CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS + poolFundAmount; uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = poolFeeAmount - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += poolFeeAmount - holderFee; // Calculate channel weight uint256 _channelWeight = (poolFundAmount * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; @@ -291,8 +291,8 @@ contract PushCoreV3 is private { uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _amountDeposited) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = _amountDeposited - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += _amountDeposited - holderFee; string memory notifSetting = string(abi.encodePacked(Strings.toString(_notifOptions), "+", _notifSettings)); @@ -357,8 +357,8 @@ contract PushCoreV3 is CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS + poolFundAmount; uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = poolFeeAmount - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += poolFeeAmount - holderFee; uint256 _newPoolContribution = channelData.poolContribution + poolFundAmount; uint256 _newChannelWeight = (_newPoolContribution * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; @@ -383,8 +383,8 @@ contract PushCoreV3 is CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS - currentPoolContribution; uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * currentPoolContribution) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = currentPoolContribution - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += currentPoolContribution - holderFee; uint256 _newChannelWeight = (minPoolContribution * ADJUST_FOR_FLOAT) / minPoolContribution; @@ -506,8 +506,8 @@ contract PushCoreV3 is function addPoolFees(uint256 _rewardAmount) external { IERC20(PUSH_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), _rewardAmount); uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _rewardAmount) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = _rewardAmount - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += _rewardAmount - holderFee; } function splitFeePool(uint256 holderSplit) external { @@ -548,8 +548,8 @@ contract PushCoreV3 is celebUserFunds[requestReceiver] += requestReceiverAmount; uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = poolFeeAmount - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += poolFeeAmount - holderFee; emit IncentivizedChatReqReceived( requestSender, BaseHelper.addressToBytes32(requestReceiver), requestReceiverAmount, poolFeeAmount, block.timestamp @@ -658,8 +658,8 @@ contract PushCoreV3 is } else if (functionType == CrossChainRequestTypes.CrossChainFunction.AdminRequest_AddPoolFee) { // Admin Request uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * amount) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = amount - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += amount - holderFee; } else { revert("Invalid Function Type"); } @@ -709,8 +709,8 @@ contract PushCoreV3 is // Update states based on Fee Percentage calculation uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * feeAmount) / 100; - HOLDER_FEE_POOL = holderFee; - WALLET_FEE_POOL = feeAmount - holderFee; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += feeAmount - holderFee; arbitraryReqFees[amountRecipient] += amount - feeAmount; From 25715ca16f2a07f203d4247332476c2e7a755754 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 9 Oct 2024 02:06:45 +0530 Subject: [PATCH 18/49] fix failing CCR tests --- test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol | 6 ++++-- test/CCR/CCRutils/Helper.sol | 6 ++++-- .../CreateChannelCCR/CreateChannelCCR.t.sol | 5 +++-- .../CreateChannelSettingsCCR.t.sol | 8 +++++--- .../CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol | 7 ++++--- .../UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol | 6 ++++-- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol b/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol index d281e793..505403f7 100644 --- a/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol +++ b/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol @@ -139,7 +139,8 @@ contract ArbitraryRequesttsol is BaseCCRTest { test_WhenAllChecksPasses(); setUpDestChain(); - uint256 PROTOCOL_POOL_FEES = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); uint256 arbitraryFees = coreProxy.arbitraryReqFees(actor.charlie_channel_owner); changePrank(DestChain.WORMHOLE_RELAYER_DEST); @@ -153,7 +154,8 @@ contract ArbitraryRequesttsol is BaseCCRTest { uint256 feeAmount = BaseHelper.calcPercentage(amount, percentage); // Update states based on Fee Percentage calculation - assertEq(coreProxy.PROTOCOL_POOL_FEES(), PROTOCOL_POOL_FEES + feeAmount); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + (feeAmount * HOLDER_SPLIT) /100); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + (feeAmount * HOLDER_SPLIT) /100); assertEq(coreProxy.arbitraryReqFees(actor.charlie_channel_owner), arbitraryFees + amount - feeAmount); } diff --git a/test/CCR/CCRutils/Helper.sol b/test/CCR/CCRutils/Helper.sol index ebcedc97..4c7dcde3 100644 --- a/test/CCR/CCRutils/Helper.sol +++ b/test/CCR/CCRutils/Helper.sol @@ -94,13 +94,15 @@ contract Helper is BasePushCommTest, CCRConfig { function getPoolFundsAndFees(uint256 _amountDeposited) internal view - returns (uint256 CHANNEL_POOL_FUNDS, uint256 PROTOCOL_POOL_FEES) + returns (uint256 CHANNEL_POOL_FUNDS, uint256 HOLDER_FEE_POOL,uint256 WALLET_FEE_POOL ) { uint256 poolFeeAmount = coreProxy.FEE_AMOUNT(); uint256 poolFundAmount = _amountDeposited - poolFeeAmount; //store funds in pool_funds & pool_fees CHANNEL_POOL_FUNDS = coreProxy.CHANNEL_POOL_FUNDS() + poolFundAmount; - PROTOCOL_POOL_FEES = coreProxy.PROTOCOL_POOL_FEES() + poolFeeAmount; + uint holderFees = (poolFeeAmount* HOLDER_SPLIT) /100; + HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL() + holderFees ; + WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL() + poolFeeAmount - holderFees; } function getSpecificPayload( diff --git a/test/CCR/SpecificRequest/CreateChannelCCR/CreateChannelCCR.t.sol b/test/CCR/SpecificRequest/CreateChannelCCR/CreateChannelCCR.t.sol index 505ba584..d190ca37 100644 --- a/test/CCR/SpecificRequest/CreateChannelCCR/CreateChannelCCR.t.sol +++ b/test/CCR/SpecificRequest/CreateChannelCCR/CreateChannelCCR.t.sol @@ -123,7 +123,7 @@ contract CreateChannelCCR is BaseCCRTest { function test_whenReceiveChecksPass() public whenReceiveFunctionIsCalledInCore { // it should emit event and create Channel - (uint256 poolFunds, uint256 poolFees) = getPoolFundsAndFees(amount); + (uint256 poolFunds, uint256 HOLDER_FEE_POOL, uint256 WALLET_FEE_POOL) = getPoolFundsAndFees(amount); vm.expectEmit(true, true, false, true); emit ChannelCreated( @@ -134,7 +134,8 @@ contract CreateChannelCCR is BaseCCRTest { receiveWormholeMessage(requestPayload); assertEq(coreProxy.CHANNEL_POOL_FUNDS(), poolFunds); - assertEq(coreProxy.PROTOCOL_POOL_FEES(), poolFees); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL, "Holder pool"); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL,"Wallet Pool"); ( CoreTypes.ChannelType channelType, diff --git a/test/CCR/SpecificRequest/CreateChannelSettingsCCR/CreateChannelSettingsCCR.t.sol b/test/CCR/SpecificRequest/CreateChannelSettingsCCR/CreateChannelSettingsCCR.t.sol index 5cd3de4e..c7154d8c 100644 --- a/test/CCR/SpecificRequest/CreateChannelSettingsCCR/CreateChannelSettingsCCR.t.sol +++ b/test/CCR/SpecificRequest/CreateChannelSettingsCCR/CreateChannelSettingsCCR.t.sol @@ -113,7 +113,8 @@ contract CreateChannelSettingsCCR is BaseCCRTest { function test_whenReceiveChecksPass() public whenReceiveFunctionIsCalledInCore { - uint256 PROTOCOL_POOL_FEES = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); changePrank(DestChain.WORMHOLE_RELAYER_DEST); string memory notifSettingRes = string(abi.encodePacked(Strings.toString(notifOptions), "+", notifSettings)); @@ -125,8 +126,9 @@ contract CreateChannelSettingsCCR is BaseCCRTest { requestPayload, additionalVaas, sourceAddress, SourceChain.SourceChainId, deliveryHash ); // Update states based on Fee Percentage calculation - assertEq(coreProxy.PROTOCOL_POOL_FEES(), PROTOCOL_POOL_FEES + amount); - } + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + (amount * HOLDER_SPLIT) /100); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + (amount * HOLDER_SPLIT) /100); +} function test_whenTokensAreTransferred() external { vm.recordLogs(); diff --git a/test/CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol b/test/CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol index 12640712..d89858f9 100644 --- a/test/CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol +++ b/test/CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol @@ -122,7 +122,8 @@ contract CreateChatCCR is BaseCCRTest { uint256 poolFeeAmount = coreProxy.FEE_AMOUNT(); uint256 userFundsPre = coreProxy.celebUserFunds(actor.charlie_channel_owner); - uint256 PROTOCOL_POOL_FEES = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); vm.expectEmit(false, false, false, true); emit IncentivizedChatReqReceived( @@ -132,9 +133,9 @@ contract CreateChatCCR is BaseCCRTest { receiveWormholeMessage(requestPayload); assertEq(coreProxy.celebUserFunds(actor.charlie_channel_owner), userFundsPre + amount - poolFeeAmount); - assertEq(coreProxy.PROTOCOL_POOL_FEES(), PROTOCOL_POOL_FEES + poolFeeAmount); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + (poolFeeAmount * HOLDER_SPLIT) /100); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + (poolFeeAmount * HOLDER_SPLIT) /100); } - function test_whenTokensAreTransferred() public { vm.recordLogs(); test_whenReceiveChecksPass(); diff --git a/test/CCR/SpecificRequest/UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol b/test/CCR/SpecificRequest/UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol index fddd7edf..a73bb564 100644 --- a/test/CCR/SpecificRequest/UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol +++ b/test/CCR/SpecificRequest/UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol @@ -97,7 +97,8 @@ contract UpdateChannelCCR is BaseCCRTest { function test_whenReceiveChecksPass() public whenReceiveFunctionIsCalledInCore { // it should emit event and create Channel - uint256 PROTOCOL_POOL_FEES = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); uint256 oldCounter = coreProxy.channelUpdateCounter(toWormholeFormat(actor.bob_channel_owner)); vm.expectEmit(true, true, false, true); @@ -116,7 +117,8 @@ contract UpdateChannelCCR is BaseCCRTest { uint256 channelUpdateBlock, , ) = coreProxy.channelInfo(toWormholeFormat(actor.bob_channel_owner)); - assertEq(coreProxy.PROTOCOL_POOL_FEES(), PROTOCOL_POOL_FEES + amount); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + (amount * HOLDER_SPLIT) /100); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + (amount * HOLDER_SPLIT) /100); assertEq(coreProxy.channelUpdateCounter(toWormholeFormat(actor.bob_channel_owner)), oldCounter + 1); assertEq(channelUpdateBlock, block.number); } From 1e3f695b40eb03eb0eb3cdd757652d53531a2b7b Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 9 Oct 2024 02:27:22 +0530 Subject: [PATCH 19/49] tests working --- contracts/PushStaking/PushStaking.sol | 22 ++++---- contracts/PushStaking/PushStakingStorage.sol | 3 ++ .../unit_tests/WalletShare/WalletShare.t.sol | 53 +++++++++++++++++-- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index e6e34f33..7d350769 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -9,6 +9,7 @@ import { Errors } from "../libraries/Errors.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; + contract PushStaking is Initializable, PushStakingStorage { using SafeERC20 for IERC20; @@ -28,6 +29,7 @@ contract PushStaking is Initializable, PushStakingStorage { FOUNDATION = _pushChannelAdmin; walletShareInfo[FOUNDATION].walletShare = WALLET_TOTAL_SHARES; epochToTotalShares[1] = 100_000 * 1e18; + walletLastEpochInitialized = block.number; } modifier onlyPushChannelAdmin() { @@ -487,11 +489,11 @@ contract PushStaking is Initializable, PushStakingStorage { * - Records the last epoch id whose rewards were set. */ function _setupEpochsRewardAndWeightsForWallets(uint256 _shares, uint256 _currentEpoch, bool isUnstake) private { - uint256 _lastEpochInitiliazed = lastEpochRelative(genesisEpoch, lastEpochInitialized); + uint256 _lastEpochInitiliazed = lastEpochRelative(genesisEpoch, walletLastEpochInitialized); // Setting up Epoch Based Rewards if (_currentEpoch > _lastEpochInitiliazed || _currentEpoch == 1) { uint256 WALLET_FEE_POOL = IPushCoreStaking(core).WALLET_FEE_POOL(); - uint256 availableRewardsPerEpoch = (WALLET_FEE_POOL - previouslySetEpochRewards); + uint256 availableRewardsPerEpoch = (WALLET_FEE_POOL - walletPreviouslySetEpochRewards); uint256 _epochGap = _currentEpoch - _lastEpochInitiliazed; if (_epochGap > 1) { @@ -500,24 +502,24 @@ contract PushStaking is Initializable, PushStakingStorage { epochRewardsForWallets[_currentEpoch] += availableRewardsPerEpoch; } - lastEpochInitialized = block.number; - previouslySetEpochRewards = WALLET_FEE_POOL; + walletLastEpochInitialized = block.number; + walletPreviouslySetEpochRewards = WALLET_FEE_POOL; } // Setting up Epoch Based TotalWeight - if (lastTotalStakeEpochInitialized == 0 || lastTotalStakeEpochInitialized == _currentEpoch) { + if (walletLastTotalStakeEpochInitialized == 0 || walletLastTotalStakeEpochInitialized == _currentEpoch) { epochToTotalShares[_currentEpoch] = isUnstake ? epochToTotalShares[_currentEpoch] - _shares : epochToTotalShares[_currentEpoch] + _shares; } else { - for (uint256 i = lastTotalStakeEpochInitialized + 1; i <= _currentEpoch - 1; i++) { + for (uint256 i = walletLastTotalStakeEpochInitialized + 1; i <= _currentEpoch - 1; i++) { if (epochToTotalShares[i] == 0) { - epochToTotalShares[i] = epochToTotalShares[lastTotalStakeEpochInitialized]; + epochToTotalShares[i] = epochToTotalShares[walletLastTotalStakeEpochInitialized]; } } epochToTotalShares[_currentEpoch] = isUnstake - ? epochToTotalShares[lastTotalStakeEpochInitialized] - _shares - : epochToTotalShares[lastTotalStakeEpochInitialized] + _shares; + ? epochToTotalShares[walletLastTotalStakeEpochInitialized] - _shares + : epochToTotalShares[walletLastTotalStakeEpochInitialized] + _shares; } - lastTotalStakeEpochInitialized = _currentEpoch; + walletLastTotalStakeEpochInitialized = _currentEpoch; } } diff --git a/contracts/PushStaking/PushStakingStorage.sol b/contracts/PushStaking/PushStakingStorage.sol index 91adfb8a..7cbe3184 100644 --- a/contracts/PushStaking/PushStakingStorage.sol +++ b/contracts/PushStaking/PushStakingStorage.sol @@ -11,8 +11,11 @@ contract PushStakingStorage { uint256 public genesisEpoch; // Block number at which Stakig starts uint256 lastEpochInitialized; // The last EPOCH ID initialized with the respective epoch rewards uint256 lastTotalStakeEpochInitialized; // The last EPOCH ID initialized with the respective total staked weight + uint256 walletLastEpochInitialized; // todo new variable + uint256 walletLastTotalStakeEpochInitialized;//todo new variable uint256 public totalStakedAmount; // Total token weight staked in Protocol at any given time uint256 public previouslySetEpochRewards; // Amount of rewards set in last initialized epoch + uint256 public walletPreviouslySetEpochRewards; //todo new variable uint256 public constant epochDuration = 21 * 7156; // 21 * number of blocks per day(7156) ~ 20 day approx uint256 public WALLET_TOTAL_SHARES; //Total Shares diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol index a1d21187..b83ee800 100644 --- a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -56,8 +56,8 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - uint expectedRewards = coreProxy.WALLET_FEE_POOL(); - assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner),"ClaimedBlock"); + uint expectedRewards = (coreProxy.WALLET_FEE_POOL() * 20) / 100; + assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner),"Balance"); assertEq(expectedRewards,claimedRewards); } @@ -85,7 +85,6 @@ contract WalletShareTest is BaseFuzzStaking{ uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); uint expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10)/100; - console2.log(expectedRewardsBob,claimedRewardsBob); assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner),"balanceBob"); assertEq(expectedRewardsBob, claimedRewardsBob,"bobClaimed"); @@ -99,6 +98,54 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(expectedRewardsAlice,claimedRewardsAlice,"Alice Claimed"); } + function test_whenWalletsAndUsers_ClaimRewards()external { + addPool(1000); + test_WalletGets_50PercentAllocation(); + stake(actor.charlie_channel_owner, 200); + stake(actor.tony_channel_owner, 1000); + roll(epochDuration * 2); + uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 balanceAliceBefore = pushToken.balanceOf(actor.alice_channel_owner); + (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.alice_channel_owner); + + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + changePrank(actor.alice_channel_owner); + pushStaking.claimShareRewards(); + + harvest(actor.charlie_channel_owner); + harvest(actor.tony_channel_owner); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter , uint256 aliceClaimedBlockAfter) = pushStaking.walletShareInfo(actor.alice_channel_owner); + + assertEq(bobWalletSharesBefore,bobWalletSharesAfter,"Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter,"StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + + uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + + uint expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10)/100; + assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner),"balanceBob"); + assertEq(expectedRewardsBob, claimedRewardsBob,"bobClaimed"); + + assertEq(aliceWalletSharesBefore,aliceWalletSharesAfter,"Shares"); + assertEq(aliceStakedBlockBefore,aliceStakedBlockAfter,"StakedBlock"); + assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + + uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + + uint expectedRewardsAlice = coreProxy.WALLET_FEE_POOL()* 50/100; + assertEq(balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner),"balanceAlice"); + assertEq(expectedRewardsAlice,claimedRewardsAlice,"Alice Claimed"); + + uint256 claimedRewardsCharlie = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); + uint256 claimedRewardsTony = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); + assertGt(claimedRewardsTony, claimedRewardsCharlie ); + } + + function test_WalletGets_50PercentAllocation() public { // bob wallet gets allocated 20% shares i.e. 25k From 24f72175b5832c5649ee5af96ba6b88c17bf00c0 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Tue, 15 Oct 2024 01:46:01 +0530 Subject: [PATCH 20/49] Foundation can claim --- contracts/PushStaking/PushStaking.sol | 16 ++++++++++----- .../fuzz_tests/BaseFuzzStaking.f.sol | 2 +- .../unit_tests/WalletShare/WalletShare.t.sol | 20 +++++++++++++++++++ test/utils/Constants.sol | 1 + 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index 7d350769..ebe7acfe 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -25,11 +25,7 @@ contract PushStaking is Initializable, PushStakingStorage { governance = _pushChannelAdmin; core = _core; PUSH_TOKEN_ADDRESS = _pushToken; - WALLET_TOTAL_SHARES = 100_000 * 1e18; FOUNDATION = _pushChannelAdmin; - walletShareInfo[FOUNDATION].walletShare = WALLET_TOTAL_SHARES; - epochToTotalShares[1] = 100_000 * 1e18; - walletLastEpochInitialized = block.number; } modifier onlyPushChannelAdmin() { @@ -57,12 +53,22 @@ contract PushStaking is Initializable, PushStakingStorage { governance = _governanceAddress; } - function initializeStake() external { + function initializeStake(uint256 _walletTotalShares) external { require(genesisEpoch == 0, "PushCoreV2::initializeStake: Already Initialized"); genesisEpoch = block.number; lastEpochInitialized = genesisEpoch; _stake(core, 1e18); + + WALLET_TOTAL_SHARES = _walletTotalShares; + walletLastEpochInitialized = genesisEpoch; + uint256 sharesToBeAllocated = _walletTotalShares; + + walletShareInfo[FOUNDATION].lastClaimedBlock = genesisEpoch; + + _adjustWalletAndTotalStake(FOUNDATION, sharesToBeAllocated, false); + emit NewSharesIssued(FOUNDATION, sharesToBeAllocated); + } /* diff --git a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol index b374cb49..dbaab8e1 100644 --- a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol +++ b/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol @@ -18,7 +18,7 @@ contract BaseFuzzStaking is BaseTest { approveTokens(actor.tim_push_holder, address(pushStaking), 50_000 ether); changePrank(actor.admin); - pushStaking.initializeStake(); + pushStaking.initializeStake(WALLET_TOTAL_SHARES); genesisEpoch = pushStaking.genesisEpoch(); } diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol index b83ee800..28ab92d0 100644 --- a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -23,6 +23,26 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(foundationWalletShares, actualTotalShares); } + function test_whenFoundation_ClaimRewards()external { + addPool(1000); + test_WalletGets_20PercentAllocation(); + roll(epochDuration * 2); + uint256 balanceAdminBefore = pushToken.balanceOf(actor.admin); + (uint256 adminWalletSharesBefore, uint256 adminStakedBlockBefore ,) = pushStaking.walletShareInfo(actor.admin); + changePrank(actor.admin); + pushStaking.claimShareRewards(); + (uint256 adminWalletSharesAfter, uint256 adminStakedBlockAfter , uint256 adminClaimedBlockAfter) = pushStaking.walletShareInfo(actor.admin); + + assertEq(adminWalletSharesBefore,adminWalletSharesAfter,"Shares"); + assertEq(adminStakedBlockBefore, adminStakedBlockAfter,"StakedBlock"); + assertEq(adminClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + + uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.admin); + uint expectedRewards = (coreProxy.WALLET_FEE_POOL()* 80) / 100 ; + assertEq(balanceAdminBefore + expectedRewards, pushToken.balanceOf(actor.admin),"Balance"); + assertEq(expectedRewards,claimedRewards); + } + function test_WalletGets_20PercentAllocation() public { (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index 6d53adae..cc8512e4 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -26,6 +26,7 @@ abstract contract Constants { uint256 MIN_POOL_CONTRIBUTION = 1 ether; uint256 ADJUST_FOR_FLOAT = 10 ** 7; uint256 HOLDER_SPLIT = 50; + uint256 WALLET_TOTAL_SHARES = 100_000 * 1e18; //Comm Constants used for meta transaction string public constant name = "Push COMM V1"; From 4ea9724d614ba6fe6e5ccf3c8ca884272018dac8 Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Tue, 15 Oct 2024 15:14:04 +0530 Subject: [PATCH 21/49] refactor: modified the tests structure for separate staking modules --- ...uzzStaking.f.sol => BasePushStaking.t.sol} | 30 +--------- .../BasePushTokenStaking.t.sol | 37 ++++++++++++ .../fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol | 6 +- .../fuzz_tests/1_DaoHarvest/DaoHarvest.tree | 0 .../2_StateVariables/StateVariables.f.sol | 6 +- .../2_StateVariables/StateVariables.tree | 0 .../fuzz_tests/3_Unstaking/Unstaking.f.sol | 6 +- .../fuzz_tests/3_Unstaking/Unstaking.tree | 0 .../4_UserHarvest/UserHarvest.f.sol | 6 +- .../fuzz_tests/4_UserHarvest/UserHarvest.tree | 0 .../BaseWalletSharesStaking.t.sol | 11 ++++ .../unit_tests/WalletShare/WalletShare.t.sol | 59 ++----------------- .../unit_tests/WalletShare/WalletShare.tree | 0 13 files changed, 66 insertions(+), 95 deletions(-) rename test/PushStaking/{fuzz_tests/BaseFuzzStaking.f.sol => BasePushStaking.t.sol} (61%) create mode 100644 test/PushStaking/PushTokenStaking/BasePushTokenStaking.t.sol rename test/PushStaking/{ => PushTokenStaking}/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol (94%) rename test/PushStaking/{ => PushTokenStaking}/fuzz_tests/1_DaoHarvest/DaoHarvest.tree (100%) rename test/PushStaking/{ => PushTokenStaking}/fuzz_tests/2_StateVariables/StateVariables.f.sol (95%) rename test/PushStaking/{ => PushTokenStaking}/fuzz_tests/2_StateVariables/StateVariables.tree (100%) rename test/PushStaking/{ => PushTokenStaking}/fuzz_tests/3_Unstaking/Unstaking.f.sol (95%) rename test/PushStaking/{ => PushTokenStaking}/fuzz_tests/3_Unstaking/Unstaking.tree (100%) rename test/PushStaking/{ => PushTokenStaking}/fuzz_tests/4_UserHarvest/UserHarvest.f.sol (99%) rename test/PushStaking/{ => PushTokenStaking}/fuzz_tests/4_UserHarvest/UserHarvest.tree (100%) create mode 100644 test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol rename test/PushStaking/{ => WalletSharesStaking}/unit_tests/WalletShare/WalletShare.t.sol (85%) rename test/PushStaking/{ => WalletSharesStaking}/unit_tests/WalletShare/WalletShare.tree (100%) diff --git a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol b/test/PushStaking/BasePushStaking.t.sol similarity index 61% rename from test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol rename to test/PushStaking/BasePushStaking.t.sol index b374cb49..6ab95f7e 100644 --- a/test/PushStaking/fuzz_tests/BaseFuzzStaking.f.sol +++ b/test/PushStaking/BasePushStaking.t.sol @@ -1,9 +1,9 @@ pragma solidity ^0.8.20; pragma experimental ABIEncoderV2; -import { BaseTest } from "../../BaseTest.t.sol"; +import { BaseTest } from "../BaseTest.t.sol"; -contract BaseFuzzStaking is BaseTest { +contract BasePushStaking is BaseTest { function setUp() public virtual override { BaseTest.setUp(); @@ -22,37 +22,11 @@ contract BaseFuzzStaking is BaseTest { genesisEpoch = pushStaking.genesisEpoch(); } - //Helper Functions - function stake(address signer, uint256 amount) internal { - changePrank(signer); - pushStaking.stake(amount * 1e18); - } - - function harvest(address signer) internal { - changePrank(signer); - pushStaking.harvestAll(); - } - - function harvestPaginated(address signer, uint256 _till) internal { - changePrank(signer); - pushStaking.harvestPaginated(_till); - } - function addPool(uint256 amount) internal { changePrank(actor.admin); coreProxy.addPoolFees(amount * 1e18); } - function unstake(address signer) internal { - changePrank(signer); - pushStaking.unstake(); - } - - function daoHarvest(address signer, uint256 _epoch) internal { - changePrank(signer); - pushStaking.daoHarvestPaginated(_epoch); - } - function getCurrentEpoch() public view returns (uint256 currentEpoch) { currentEpoch = pushStaking.lastEpochRelative(genesisEpoch, block.number); } diff --git a/test/PushStaking/PushTokenStaking/BasePushTokenStaking.t.sol b/test/PushStaking/PushTokenStaking/BasePushTokenStaking.t.sol new file mode 100644 index 00000000..e88e1406 --- /dev/null +++ b/test/PushStaking/PushTokenStaking/BasePushTokenStaking.t.sol @@ -0,0 +1,37 @@ +pragma solidity ^0.8.20; +pragma experimental ABIEncoderV2; + +import { BasePushStaking } from "../BasePushStaking.t.sol"; + +contract BasePushTokenStaking is BasePushStaking { + + function setUp() public virtual override { + BasePushStaking.setUp(); + } + + //Helper Functions + function stake(address signer, uint256 amount) internal { + changePrank(signer); + pushStaking.stake(amount * 1e18); + } + + function harvest(address signer) internal { + changePrank(signer); + pushStaking.harvestAll(); + } + + function harvestPaginated(address signer, uint256 _till) internal { + changePrank(signer); + pushStaking.harvestPaginated(_till); + } + + function unstake(address signer) internal { + changePrank(signer); + pushStaking.unstake(); + } + + function daoHarvest(address signer, uint256 _epoch) internal { + changePrank(signer); + pushStaking.daoHarvestPaginated(_epoch); + } +} diff --git a/test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol b/test/PushStaking/PushTokenStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol similarity index 94% rename from test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol rename to test/PushStaking/PushTokenStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol index cb90bb68..d2193603 100644 --- a/test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol +++ b/test/PushStaking/PushTokenStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.f.sol @@ -1,12 +1,12 @@ pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; -import { BaseFuzzStaking } from "../BaseFuzzStaking.f.sol"; +import { BasePushTokenStaking } from "../../BasePushTokenStaking.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; -contract DaoHarvest_test is BaseFuzzStaking { +contract DaoHarvest_test is BasePushTokenStaking { function setUp() public virtual override { - BaseFuzzStaking.setUp(); + BasePushTokenStaking.setUp(); } // allows admin to harvest, diff --git a/test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.tree b/test/PushStaking/PushTokenStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.tree similarity index 100% rename from test/PushStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.tree rename to test/PushStaking/PushTokenStaking/fuzz_tests/1_DaoHarvest/DaoHarvest.tree diff --git a/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol b/test/PushStaking/PushTokenStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol similarity index 95% rename from test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol rename to test/PushStaking/PushTokenStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol index 6f293222..d6bad213 100644 --- a/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol +++ b/test/PushStaking/PushTokenStaking/fuzz_tests/2_StateVariables/StateVariables.f.sol @@ -1,12 +1,12 @@ pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; -import { BaseFuzzStaking } from "../BaseFuzzStaking.f.sol"; +import { BasePushTokenStaking } from "../../BasePushTokenStaking.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; -contract StateVariables_test is BaseFuzzStaking { +contract StateVariables_test is BasePushTokenStaking { function setUp() public virtual override { - BaseFuzzStaking.setUp(); + BasePushTokenStaking.setUp(); } function test_BlockOverflow(uint256 _passEpoch) public { diff --git a/test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.tree b/test/PushStaking/PushTokenStaking/fuzz_tests/2_StateVariables/StateVariables.tree similarity index 100% rename from test/PushStaking/fuzz_tests/2_StateVariables/StateVariables.tree rename to test/PushStaking/PushTokenStaking/fuzz_tests/2_StateVariables/StateVariables.tree diff --git a/test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol b/test/PushStaking/PushTokenStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol similarity index 95% rename from test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol rename to test/PushStaking/PushTokenStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol index 5e67ac21..ae387b67 100644 --- a/test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol +++ b/test/PushStaking/PushTokenStaking/fuzz_tests/3_Unstaking/Unstaking.f.sol @@ -1,12 +1,12 @@ pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; -import { BaseFuzzStaking } from "../BaseFuzzStaking.f.sol"; +import { BasePushTokenStaking } from "../../BasePushTokenStaking.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; -contract Unstaking_test is BaseFuzzStaking { +contract Unstaking_test is BasePushTokenStaking { function setUp() public virtual override { - BaseFuzzStaking.setUp(); + BasePushTokenStaking.setUp(); } // Unstaking allows users to Claim their pending rewards diff --git a/test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.tree b/test/PushStaking/PushTokenStaking/fuzz_tests/3_Unstaking/Unstaking.tree similarity index 100% rename from test/PushStaking/fuzz_tests/3_Unstaking/Unstaking.tree rename to test/PushStaking/PushTokenStaking/fuzz_tests/3_Unstaking/Unstaking.tree diff --git a/test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol b/test/PushStaking/PushTokenStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol similarity index 99% rename from test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol rename to test/PushStaking/PushTokenStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol index b4c569e0..ed94e488 100644 --- a/test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol +++ b/test/PushStaking/PushTokenStaking/fuzz_tests/4_UserHarvest/UserHarvest.f.sol @@ -1,12 +1,12 @@ pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; -import { BaseFuzzStaking } from "../BaseFuzzStaking.f.sol"; +import { BasePushTokenStaking } from "../../BasePushTokenStaking.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; -contract UserHarvest_test is BaseFuzzStaking { +contract UserHarvest_test is BasePushTokenStaking { function setUp() public virtual override { - BaseFuzzStaking.setUp(); + BasePushTokenStaking.setUp(); } // actor.bob_channel_owner Stakes at EPOCH 1 and Harvests alone- Should get all rewards diff --git a/test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.tree b/test/PushStaking/PushTokenStaking/fuzz_tests/4_UserHarvest/UserHarvest.tree similarity index 100% rename from test/PushStaking/fuzz_tests/4_UserHarvest/UserHarvest.tree rename to test/PushStaking/PushTokenStaking/fuzz_tests/4_UserHarvest/UserHarvest.tree diff --git a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol new file mode 100644 index 00000000..56f74437 --- /dev/null +++ b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.8.20; +pragma experimental ABIEncoderV2; + +import { BasePushStaking } from "../BasePushStaking.t.sol"; + +contract BaseWalletSharesStaking is BasePushStaking { + + function setUp() public virtual override { + BasePushStaking.setUp(); + } +} diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol similarity index 85% rename from test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol rename to test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol index b83ee800..eac9199f 100644 --- a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -2,17 +2,15 @@ pragma solidity ^0.8.20; -import { BaseFuzzStaking } from "../../fuzz_tests/BaseFuzzStaking.f.sol"; -import { StakingTypes } from "../../../../contracts/libraries/DataTypes.sol"; +import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; +import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; import {console2} from "forge-std/console2.sol"; -contract WalletShareTest is BaseFuzzStaking{ - +contract WalletShareTest is BaseWalletSharesStaking { /// @dev A function invoked before each test case is run. function setUp() public virtual override { - BaseFuzzStaking.setUp(); - + BaseWalletSharesStaking.setUp(); } function test_FoundationGetsInitialShares() public { @@ -98,55 +96,6 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(expectedRewardsAlice,claimedRewardsAlice,"Alice Claimed"); } - function test_whenWalletsAndUsers_ClaimRewards()external { - addPool(1000); - test_WalletGets_50PercentAllocation(); - stake(actor.charlie_channel_owner, 200); - stake(actor.tony_channel_owner, 1000); - roll(epochDuration * 2); - uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.bob_channel_owner); - uint256 balanceAliceBefore = pushToken.balanceOf(actor.alice_channel_owner); - (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.alice_channel_owner); - - changePrank(actor.bob_channel_owner); - pushStaking.claimShareRewards(); - changePrank(actor.alice_channel_owner); - pushStaking.claimShareRewards(); - - harvest(actor.charlie_channel_owner); - harvest(actor.tony_channel_owner); - - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); - (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter , uint256 aliceClaimedBlockAfter) = pushStaking.walletShareInfo(actor.alice_channel_owner); - - assertEq(bobWalletSharesBefore,bobWalletSharesAfter,"Shares"); - assertEq(bobStakedBlockBefore, bobStakedBlockAfter,"StakedBlock"); - assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); - - uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - - uint expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10)/100; - assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner),"balanceBob"); - assertEq(expectedRewardsBob, claimedRewardsBob,"bobClaimed"); - - assertEq(aliceWalletSharesBefore,aliceWalletSharesAfter,"Shares"); - assertEq(aliceStakedBlockBefore,aliceStakedBlockAfter,"StakedBlock"); - assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); - - uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); - - uint expectedRewardsAlice = coreProxy.WALLET_FEE_POOL()* 50/100; - assertEq(balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner),"balanceAlice"); - assertEq(expectedRewardsAlice,claimedRewardsAlice,"Alice Claimed"); - - uint256 claimedRewardsCharlie = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); - uint256 claimedRewardsTony = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); - assertGt(claimedRewardsTony, claimedRewardsCharlie ); - } - - - function test_WalletGets_50PercentAllocation() public { // bob wallet gets allocated 20% shares i.e. 25k test_WalletGets_20PercentAllocation(); diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.tree b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.tree similarity index 100% rename from test/PushStaking/unit_tests/WalletShare/WalletShare.tree rename to test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.tree From 3a47493aedb091a92c8be1e918d95c6710276157 Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Tue, 15 Oct 2024 17:15:43 +0530 Subject: [PATCH 22/49] refactor: added share invariants --- .../BaseWalletSharesStaking.t.sol | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol index 56f74437..fcb745fa 100644 --- a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol +++ b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol @@ -8,4 +8,39 @@ contract BaseWalletSharesStaking is BasePushStaking { function setUp() public virtual override { BasePushStaking.setUp(); } + + modifier validateShareInvariants () { + uint256 walletSharesBeforeExecution = pushStaking.WALLET_TOTAL_SHARES(); + _; + _validateWalletSharesSum(); + _validateEpochShares(); + _verifyTotalSharesConsistency(walletSharesBeforeExecution); + } + + function _validateWalletSharesSum() internal { + uint256 walletTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 foundationWalletShares,,) = pushStaking.walletShareInfo(actor.admin); + (uint256 bobWalletShares,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletShares,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 charlieWalletShares,,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 tonyWalletShares,,) = pushStaking.walletShareInfo(actor.tony_channel_owner); + + uint256 totalSharesSum = foundationWalletShares + bobWalletShares + aliceWalletShares + charlieWalletShares + tonyWalletShares; + assertEq(walletTotalShares, totalSharesSum); + } + + function _validateEpochShares() internal { + uint256 walletTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + for (uint256 i=genesisEpoch; i<=getCurrentEpoch(); ) { + assertLe(pushStaking.epochToTotalShares(i), walletTotalShares); + unchecked { + i++; + } + } + } + + function _verifyTotalSharesConsistency(uint256 _walletSharesBeforeExecution) internal { + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + assertEq(_walletSharesBeforeExecution, walletTotalSharesAfter); + } } From ef3988d9e3139ea23b00d83eda4629ac5b90c37a Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 16 Oct 2024 16:10:11 +0530 Subject: [PATCH 23/49] Fix epochToTotal Update issue --- contracts/PushStaking/PushStaking.sol | 52 +-- .../unit_tests/WalletShare/WalletShare.t.sol | 375 ++++++++++++------ 2 files changed, 275 insertions(+), 152 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index ebe7acfe..c858b993 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -64,11 +64,10 @@ contract PushStaking is Initializable, PushStakingStorage { walletLastEpochInitialized = genesisEpoch; uint256 sharesToBeAllocated = _walletTotalShares; - walletShareInfo[FOUNDATION].lastClaimedBlock = genesisEpoch; + walletShareInfo[FOUNDATION].lastClaimedBlock = genesisEpoch; - _adjustWalletAndTotalStake(FOUNDATION, sharesToBeAllocated, false); + _adjustWalletAndTotalStake(FOUNDATION, sharesToBeAllocated, 0); emit NewSharesIssued(FOUNDATION, sharesToBeAllocated); - } /* @@ -111,9 +110,10 @@ contract PushStaking is Initializable, PushStakingStorage { if (sharesToBeAllocated < currentWalletShare) { revert Errors.InvalidArg_LessThanExpected(currentWalletShare, sharesToBeAllocated); } - walletShareInfo[_walletAddress].lastClaimedBlock = - walletShareInfo[_walletAddress].lastClaimedBlock == 0 ? genesisEpoch : walletShareInfo[_walletAddress].lastClaimedBlock; - _adjustWalletAndTotalStake(_walletAddress, sharesToBeAllocated, false); + walletShareInfo[_walletAddress].lastClaimedBlock = walletShareInfo[_walletAddress].lastClaimedBlock == 0 + ? genesisEpoch + : walletShareInfo[_walletAddress].lastClaimedBlock; + _adjustWalletAndTotalStake(_walletAddress, sharesToBeAllocated, currentWalletShare); WALLET_TOTAL_SHARES = TotalShare + sharesToBeAllocated; emit NewSharesIssued(_walletAddress, sharesToBeAllocated); } @@ -127,7 +127,7 @@ contract PushStaking is Initializable, PushStakingStorage { function removeWalletShare(address _walletAddress) public onlyGovernance { uint256 sharesToBeRemoved = walletShareInfo[_walletAddress].walletShare; - _adjustWalletAndTotalStake(_walletAddress, sharesToBeRemoved, true); + _adjustWalletAndTotalStake(_walletAddress, 0, sharesToBeRemoved); walletShareInfo[FOUNDATION].walletShare += sharesToBeRemoved; @@ -161,11 +161,12 @@ contract PushStaking is Initializable, PushStakingStorage { */ //TODO logic yet to be finalized function calculateWalletRewards(address _wallet, uint256 _epochId) public view returns (uint256) { - return (walletShareInfo[_wallet].epochToWalletShares[_epochId] * epochRewardsForWallets[_epochId]) / epochToTotalShares[_epochId]; + return (walletShareInfo[_wallet].epochToWalletShares[_epochId] * epochRewardsForWallets[_epochId]) + / epochToTotalShares[_epochId]; } function claimShareRewards() external returns (uint256 rewards) { - _adjustWalletAndTotalStake(msg.sender, 0, false); + _adjustWalletAndTotalStake(msg.sender, 0, 0); uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); uint256 nextFromEpoch = lastEpochRelative(genesisEpoch, walletShareInfo[msg.sender].lastClaimedBlock); @@ -312,7 +313,7 @@ contract PushStaking is Initializable, PushStakingStorage { * Unlike other harvest functions, this is designed to transfer rewards to Push Governance. * */ - function daoHarvestPaginated(uint256 _tillEpoch) external onlyGovernance{ + function daoHarvestPaginated(uint256 _tillEpoch) external onlyGovernance { uint256 rewards = harvest(core, _tillEpoch); IPushCoreStaking(core).sendFunds(msg.sender, rewards); } @@ -453,35 +454,35 @@ contract PushStaking is Initializable, PushStakingStorage { lastTotalStakeEpochInitialized = _currentEpoch; } - function _adjustWalletAndTotalStake(address _wallet, uint256 _shares, bool isUnstake) internal { + function _adjustWalletAndTotalStake(address _wallet, uint256 _sharesToAdd, uint256 _sharesToRemove) internal { uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); - _setupEpochsRewardAndWeightsForWallets(_shares, currentEpoch, isUnstake); + _setupEpochsRewardAndWeightsForWallets(_sharesToAdd, currentEpoch, _sharesToRemove); uint256 _walletPrevShares = walletShareInfo[_wallet].walletShare; // Initiating 1st Case: User stakes for first time if (_walletPrevShares == 0) { - walletShareInfo[_wallet].walletShare = _shares; + walletShareInfo[_wallet].walletShare = _sharesToAdd; } else { // Initiating 2.1 Case: User stakes again but in Same Epoch uint256 lastStakedEpoch = lastEpochRelative(genesisEpoch, walletShareInfo[_wallet].lastStakedBlock); if (currentEpoch == lastStakedEpoch) { - walletShareInfo[_wallet].walletShare = isUnstake ? _walletPrevShares - _shares : _shares; + walletShareInfo[_wallet].walletShare = _walletPrevShares + _sharesToAdd - _sharesToRemove; } else { // Initiating 2.2 Case: User stakes again but in Different Epoch for (uint256 i = lastStakedEpoch; i <= currentEpoch; i++) { if (i != currentEpoch) { walletShareInfo[_wallet].epochToWalletShares[i] = _walletPrevShares; } else { - walletShareInfo[_wallet].walletShare = - isUnstake ? _walletPrevShares - _shares : _walletPrevShares + _shares; + walletShareInfo[_wallet].walletShare = _walletPrevShares + _sharesToAdd - _sharesToRemove; + walletShareInfo[_wallet].epochToWalletShares[i] = walletShareInfo[_wallet].walletShare; } } } } - if (_shares != 0) { + if (_sharesToAdd != 0) { walletShareInfo[_wallet].lastStakedBlock = block.number; } } @@ -494,7 +495,13 @@ contract PushStaking is Initializable, PushStakingStorage { * - Records the Pool_Fees value used as rewards. * - Records the last epoch id whose rewards were set. */ - function _setupEpochsRewardAndWeightsForWallets(uint256 _shares, uint256 _currentEpoch, bool isUnstake) private { + function _setupEpochsRewardAndWeightsForWallets( + uint256 _sharesToAdd, + uint256 _currentEpoch, + uint256 _sharesToRemove + ) + private + { uint256 _lastEpochInitiliazed = lastEpochRelative(genesisEpoch, walletLastEpochInitialized); // Setting up Epoch Based Rewards if (_currentEpoch > _lastEpochInitiliazed || _currentEpoch == 1) { @@ -513,18 +520,15 @@ contract PushStaking is Initializable, PushStakingStorage { } // Setting up Epoch Based TotalWeight if (walletLastTotalStakeEpochInitialized == 0 || walletLastTotalStakeEpochInitialized == _currentEpoch) { - epochToTotalShares[_currentEpoch] = - isUnstake ? epochToTotalShares[_currentEpoch] - _shares : epochToTotalShares[_currentEpoch] + _shares; + epochToTotalShares[_currentEpoch] = epochToTotalShares[_currentEpoch] + _sharesToAdd - _sharesToRemove; } else { for (uint256 i = walletLastTotalStakeEpochInitialized + 1; i <= _currentEpoch - 1; i++) { if (epochToTotalShares[i] == 0) { epochToTotalShares[i] = epochToTotalShares[walletLastTotalStakeEpochInitialized]; } } - - epochToTotalShares[_currentEpoch] = isUnstake - ? epochToTotalShares[walletLastTotalStakeEpochInitialized] - _shares - : epochToTotalShares[walletLastTotalStakeEpochInitialized] + _shares; + epochToTotalShares[_currentEpoch] = epochToTotalShares[_currentEpoch] + + epochToTotalShares[walletLastTotalStakeEpochInitialized] + _sharesToAdd - _sharesToRemove; } walletLastTotalStakeEpochInitialized = _currentEpoch; } diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol index 28ab92d0..1941181d 100644 --- a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -1,18 +1,14 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; - import { BaseFuzzStaking } from "../../fuzz_tests/BaseFuzzStaking.f.sol"; import { StakingTypes } from "../../../../contracts/libraries/DataTypes.sol"; -import {console2} from "forge-std/console2.sol"; - -contract WalletShareTest is BaseFuzzStaking{ - +import { console2 } from "forge-std/console2.sol"; +contract WalletShareTest is BaseFuzzStaking { /// @dev A function invoked before each test case is run. function setUp() public virtual override { BaseFuzzStaking.setUp(); - } function test_FoundationGetsInitialShares() public { @@ -23,161 +19,179 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(foundationWalletShares, actualTotalShares); } - function test_whenFoundation_ClaimRewards()external { + function test_whenFoundation_ClaimRewards() external { addPool(1000); test_WalletGets_20PercentAllocation(); roll(epochDuration * 2); uint256 balanceAdminBefore = pushToken.balanceOf(actor.admin); - (uint256 adminWalletSharesBefore, uint256 adminStakedBlockBefore ,) = pushStaking.walletShareInfo(actor.admin); + (uint256 adminWalletSharesBefore, uint256 adminStakedBlockBefore,) = pushStaking.walletShareInfo(actor.admin); changePrank(actor.admin); pushStaking.claimShareRewards(); - (uint256 adminWalletSharesAfter, uint256 adminStakedBlockAfter , uint256 adminClaimedBlockAfter) = pushStaking.walletShareInfo(actor.admin); + (uint256 adminWalletSharesAfter, uint256 adminStakedBlockAfter, uint256 adminClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.admin); - assertEq(adminWalletSharesBefore,adminWalletSharesAfter,"Shares"); - assertEq(adminStakedBlockBefore, adminStakedBlockAfter,"StakedBlock"); - assertEq(adminClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + assertEq(adminWalletSharesBefore, adminWalletSharesAfter, "Shares"); + assertEq(adminStakedBlockBefore, adminStakedBlockAfter, "StakedBlock"); + assertEq(adminClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.admin); - uint expectedRewards = (coreProxy.WALLET_FEE_POOL()* 80) / 100 ; - assertEq(balanceAdminBefore + expectedRewards, pushToken.balanceOf(actor.admin),"Balance"); - assertEq(expectedRewards,claimedRewards); + uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 80) / 100; + assertEq(balanceAdminBefore + expectedRewards, pushToken.balanceOf(actor.admin), "Balance"); + assertEq(expectedRewards, claimedRewards); } function test_WalletGets_20PercentAllocation() public { - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); uint256 expectedAllocationShares = 25_000 * 1e18; - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); assertEq(bobWalletSharesBefore, 0); assertEq(bobWalletSharesAfter, expectedAllocationShares); assertEq(actualTotalShares, 125_000 * 1e18); - uint percentage = (bobWalletSharesAfter * 100)/actualTotalShares; + uint256 percentage = (bobWalletSharesAfter * 100) / actualTotalShares; assertEq(percentage, percentAllocation.percentageNumber); } - function test_whenWallet_ClaimRewards_for20Percent()external { + function test_whenWallet_ClaimRewards_for20Percent() external { addPool(1000); test_WalletGets_20PercentAllocation(); changePrank(actor.bob_channel_owner); roll(epochDuration * 2); uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); pushStaking.claimShareRewards(); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); - assertEq(bobWalletSharesBefore,bobWalletSharesAfter,"Shares"); - assertEq(bobStakedBlockBefore, bobStakedBlockAfter,"StakedBlock"); - assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - uint expectedRewards = (coreProxy.WALLET_FEE_POOL() * 20) / 100; - assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner),"Balance"); - assertEq(expectedRewards,claimedRewards); + uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 20) / 100; + assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); + assertEq(expectedRewards, claimedRewards); } - function test_whenWallets_ClaimRewards_for_20_50_Percent()external { + function test_whenWallets_ClaimRewards_for_20_50_Percent() external { addPool(1000); test_WalletGets_50PercentAllocation(); roll(epochDuration * 2); uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,) = + pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 balanceAliceBefore = pushToken.balanceOf(actor.alice_channel_owner); - (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore,) = + pushStaking.walletShareInfo(actor.alice_channel_owner); changePrank(actor.bob_channel_owner); pushStaking.claimShareRewards(); changePrank(actor.alice_channel_owner); pushStaking.claimShareRewards(); - - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); - (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter , uint256 aliceClaimedBlockAfter) = pushStaking.walletShareInfo(actor.alice_channel_owner); - assertEq(bobWalletSharesBefore,bobWalletSharesAfter,"Shares"); - assertEq(bobStakedBlockBefore, bobStakedBlockAfter,"StakedBlock"); - assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter, uint256 aliceClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.alice_channel_owner); + + assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - uint expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10)/100; - assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner),"balanceBob"); - assertEq(expectedRewardsBob, claimedRewardsBob,"bobClaimed"); + uint256 expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10) / 100; + assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner), "balanceBob"); + assertEq(expectedRewardsBob, claimedRewardsBob, "bobClaimed"); - assertEq(aliceWalletSharesBefore,aliceWalletSharesAfter,"Shares"); - assertEq(aliceStakedBlockBefore,aliceStakedBlockAfter,"StakedBlock"); - assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + assertEq(aliceWalletSharesBefore, aliceWalletSharesAfter, "Shares"); + assertEq(aliceStakedBlockBefore, aliceStakedBlockAfter, "StakedBlock"); + assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); - uint expectedRewardsAlice = coreProxy.WALLET_FEE_POOL()* 50/100; - assertEq(balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner),"balanceAlice"); - assertEq(expectedRewardsAlice,claimedRewardsAlice,"Alice Claimed"); + uint256 expectedRewardsAlice = coreProxy.WALLET_FEE_POOL() * 50 / 100; + assertEq( + balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner), "balanceAlice" + ); + assertEq(expectedRewardsAlice, claimedRewardsAlice, "Alice Claimed"); } - function test_whenWalletsAndUsers_ClaimRewards()external { + function test_whenWalletsAndUsers_ClaimRewards() external { addPool(1000); test_WalletGets_50PercentAllocation(); stake(actor.charlie_channel_owner, 200); stake(actor.tony_channel_owner, 1000); roll(epochDuration * 2); uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,) = + pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 balanceAliceBefore = pushToken.balanceOf(actor.alice_channel_owner); - (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore , ) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore,) = + pushStaking.walletShareInfo(actor.alice_channel_owner); changePrank(actor.bob_channel_owner); pushStaking.claimShareRewards(); changePrank(actor.alice_channel_owner); pushStaking.claimShareRewards(); - + harvest(actor.charlie_channel_owner); harvest(actor.tony_channel_owner); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); - (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter , uint256 aliceClaimedBlockAfter) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter, uint256 aliceClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.alice_channel_owner); - assertEq(bobWalletSharesBefore,bobWalletSharesAfter,"Shares"); - assertEq(bobStakedBlockBefore, bobStakedBlockAfter,"StakedBlock"); - assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - uint expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10)/100; - assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner),"balanceBob"); - assertEq(expectedRewardsBob, claimedRewardsBob,"bobClaimed"); + uint256 expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10) / 100; + assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner), "balanceBob"); + assertEq(expectedRewardsBob, claimedRewardsBob, "bobClaimed"); - assertEq(aliceWalletSharesBefore,aliceWalletSharesAfter,"Shares"); - assertEq(aliceStakedBlockBefore,aliceStakedBlockAfter,"StakedBlock"); - assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration,"ClaimedBlock"); + assertEq(aliceWalletSharesBefore, aliceWalletSharesAfter, "Shares"); + assertEq(aliceStakedBlockBefore, aliceStakedBlockAfter, "StakedBlock"); + assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); - - uint expectedRewardsAlice = coreProxy.WALLET_FEE_POOL()* 50/100; - assertEq(balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner),"balanceAlice"); - assertEq(expectedRewardsAlice,claimedRewardsAlice,"Alice Claimed"); - + + uint256 expectedRewardsAlice = coreProxy.WALLET_FEE_POOL() * 50 / 100; + assertEq( + balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner), "balanceAlice" + ); + assertEq(expectedRewardsAlice, claimedRewardsAlice, "Alice Claimed"); + uint256 claimedRewardsCharlie = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); uint256 claimedRewardsTony = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); - assertGt(claimedRewardsTony, claimedRewardsCharlie ); + assertGt(claimedRewardsTony, claimedRewardsCharlie); } - - function test_WalletGets_50PercentAllocation() public { // bob wallet gets allocated 20% shares i.e. 25k test_WalletGets_20PercentAllocation(); (uint256 aliceWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.alice_channel_owner, percentAllocation); uint256 expectedAllocationShares = 125_000 * 1e18; - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 aliceWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); @@ -187,17 +201,19 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(aliceWalletSharesAfter, expectedAllocationShares); assertEq(foundationWalletSharesAfter, 100_000 * 1e18); assertEq(actualTotalShares, 250_000 * 1e18); - uint percentage = (aliceWalletSharesAfter * 100)/actualTotalShares; + uint256 percentage = (aliceWalletSharesAfter * 100) / actualTotalShares; assertEq(percentage, percentAllocation.percentageNumber); } // removes wallet allocation and assign shares to the foundation function test_RemovalWalletM2() public { - // actor.bob_channel_owner has 20% allocation (25k shares), actor.alice_channel_owner has 50% (125k) & foundation (100k) + // actor.bob_channel_owner has 20% allocation (25k shares), actor.alice_channel_owner has 50% (125k) & + // foundation (100k) test_WalletGets_50PercentAllocation(); uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 aliceWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); @@ -205,21 +221,26 @@ contract WalletShareTest is BaseFuzzStaking{ pushStaking.removeWalletShare(actor.bob_channel_owner); uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 aliceWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); - assertEq(bobWalletSharesAfter, 0,"bob wallet share"); - assertEq(aliceWalletSharesAfter, aliceWalletSharesBefore,"akice wallet share"); - assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + bobWalletSharesBefore,"foundation wallet share"); - assertEq(totalSharesAfter, totalSharesBefore,"total wallet share"); + assertEq(bobWalletSharesAfter, 0, "bob wallet share"); + assertEq(aliceWalletSharesAfter, aliceWalletSharesBefore, "akice wallet share"); + assertEq( + foundationWalletSharesAfter, foundationWalletSharesBefore + bobWalletSharesBefore, "foundation wallet share" + ); + assertEq(totalSharesAfter, totalSharesBefore, "total wallet share"); } // testing add wallet after removal with method m2 (assign shares to foundation) + function test_AddWallet_AfterRemoval_M2() public { test_RemovalWalletM2(); (uint256 charlieWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation); @@ -234,13 +255,17 @@ contract WalletShareTest is BaseFuzzStaking{ // assign wallet 0.001% shares function test_WalletGets_NegligiblePercentAllocation() public { - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 3 }); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 3 }); - uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(),percentAllocation); + uint256 expectedAllocationShares = + pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); assertEq(bobWalletSharesBefore, 0); @@ -250,13 +275,17 @@ contract WalletShareTest is BaseFuzzStaking{ // assign wallet 0.0001% shares function test_WalletGets_NegligiblePercentAllocation2() public { - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 4 }); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 4 }); - uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(),percentAllocation); + uint256 expectedAllocationShares = + pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); assertEq(bobWalletSharesBefore, 0); assertEq(bobWalletSharesAfter, expectedAllocationShares); @@ -269,24 +298,27 @@ contract WalletShareTest is BaseFuzzStaking{ // let's increase actor.bob_channel_owner allocation to 50% uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); - uint256 expectedAllocationShares = 100_000* 1e18; + uint256 expectedAllocationShares = 100_000 * 1e18; uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); - assertEq(bobWalletSharesBefore, 25_000* 1e18,"bob wallet share"); - assertEq(totalSharesBefore, 125_000* 1e18,"total wallet share"); - assertEq(foundationWalletSharesBefore, 100_000* 1e18,"foundation wallet share"); - assertEq(bobWalletSharesAfter, expectedAllocationShares,"bob wallet share after"); - assertEq(totalSharesAfter, 200_000* 1e18,"total wallet share after"); - assertEq(foundationWalletSharesAfter, 100_000* 1e18,"foundation wallet share after"); + assertEq(bobWalletSharesBefore, 25_000 * 1e18, "bob wallet share"); + assertEq(totalSharesBefore, 125_000 * 1e18, "total wallet share"); + assertEq(foundationWalletSharesBefore, 100_000 * 1e18, "foundation wallet share"); + assertEq(bobWalletSharesAfter, expectedAllocationShares, "bob wallet share after"); + assertEq(totalSharesAfter, 200_000 * 1e18, "total wallet share after"); + assertEq(foundationWalletSharesAfter, 100_000 * 1e18, "foundation wallet share after"); } function test_RevertWhen_DecreaseWalletShare_UsingAdd() public { @@ -295,20 +327,23 @@ contract WalletShareTest is BaseFuzzStaking{ // let's increase actor.bob_channel_owner allocation to 50% uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); changePrank(actor.admin); vm.expectRevert(); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); assertEq(bobWalletSharesBefore, bobWalletSharesAfter); assertEq(actualTotalShares, totalSharesBefore); - uint percentage = (bobWalletSharesAfter * 100)/actualTotalShares; + uint256 percentage = (bobWalletSharesAfter * 100) / actualTotalShares; assertEq(percentage, 20); } @@ -318,16 +353,20 @@ contract WalletShareTest is BaseFuzzStaking{ // let's decrease actor.bob_channel_owner allocation to 10% uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); - uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(),percentAllocation); + uint256 expectedAllocationShares = + pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation); changePrank(actor.admin); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation); uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); assertEq(bobWalletSharesBefore, 25_000 * 1e18); @@ -335,13 +374,13 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(foundationWalletSharesBefore, 100_000 * 1e18); assertEq(bobWalletSharesAfter, expectedAllocationShares); assertEq(totalSharesAfter, 125_000 * 1e18 + expectedAllocationShares); - assertEq(foundationWalletSharesAfter, 125_000 * 1e18 ); + assertEq(foundationWalletSharesAfter, 125_000 * 1e18); } // FUZZ TESTS function testFuzz_AddShares(address _walletAddress, StakingTypes.Percentage memory _percentage) public { - _percentage.percentageNumber = bound(_percentage.percentageNumber,0,100); - _percentage.decimalPlaces = bound(_percentage.decimalPlaces,0,10); + _percentage.percentageNumber = bound(_percentage.percentageNumber, 0, 100); + _percentage.decimalPlaces = bound(_percentage.decimalPlaces, 0, 10); // percentage must be less than 100 vm.assume(_percentage.percentageNumber / 10 ** _percentage.decimalPlaces < 100); changePrank(actor.admin); @@ -349,7 +388,7 @@ contract WalletShareTest is BaseFuzzStaking{ } function testFuzz_RemoveShares(address _walletAddress, StakingTypes.Percentage memory _percentage) public { - _percentage.percentageNumber = bound(_percentage.percentageNumber,0,100); + _percentage.percentageNumber = bound(_percentage.percentageNumber, 0, 100); vm.assume(_percentage.decimalPlaces < 10); // percentage must be less than 100 vm.assume(_percentage.percentageNumber / 10 ** _percentage.decimalPlaces < 100); @@ -362,22 +401,102 @@ contract WalletShareTest is BaseFuzzStaking{ assertEq(pushStaking.WALLET_TOTAL_SHARES(), foundationWalletShares); } - function test_MaxDecimalAmount () public { - // fixed at most 10 decimal places - // percentage = 10.1111111111 - StakingTypes.Percentage memory _percentage = StakingTypes.Percentage({ - percentageNumber: 101111111111, - decimalPlaces: 10 - }); - - for (uint256 i=1; i<50; i++) { - uint256 shares = pushStaking.getSharesAmount({ - _totalShares: 10 ** i, - _percentage: _percentage - }); - console2.log("totalShares = ", i); - console2.log(shares/1e18); - console2.log(""); - } + function test_whenWallet_SharesIncrease_InSameEpoch() public { + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + uint256 expectedAllocationShares = 25_000 * 1e18; + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(1); + + assertEq(bobWalletSharesBefore, 0); + assertEq(bobWalletSharesAfter, expectedAllocationShares); + assertEq(actualTotalShares, 125_000 * 1e18); + assertEq(epochToTotalSharesAfter, actualTotalShares); + + uint256 percentage = (bobWalletSharesAfter * 100) / actualTotalShares; + assertEq(percentage, percentAllocation.percentageNumber); + + StakingTypes.Percentage memory percentAllocation2 = + StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); + + uint256 expectedAllocationShares2 = 100_000 * 1e18; + (uint256 bobWalletSharesAfter2, uint256 bobStakedBlockAfter2, uint256 bobClaimedBlockAfter2) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 actualTotalShares2 = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter2 = pushStaking.epochToTotalShares(1); + + assertEq(bobWalletSharesAfter2, expectedAllocationShares2); + assertEq(actualTotalShares2, 200_000 * 1e18); + assertEq(epochToTotalSharesAfter2, actualTotalShares2); } -} \ No newline at end of file + + function test_whenWallet_SharesIncrease_InDifferentEpoch() public { + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + uint256 expectedAllocationShares = 25_000 * 1e18; + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 actualTotalShares = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(1); + + assertEq(bobWalletSharesBefore, 0); + assertEq(bobWalletSharesAfter, expectedAllocationShares); + assertEq(actualTotalShares, 125_000 * 1e18); + assertEq(epochToTotalSharesAfter, actualTotalShares); + + uint256 percentage = (bobWalletSharesAfter * 100) / actualTotalShares; + assertEq(percentage, percentAllocation.percentageNumber); + + roll(epochDuration + 1); + + StakingTypes.Percentage memory percentAllocation2 = + StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); + + uint256 expectedAllocationShares2 = 100_000 * 1e18; + (uint256 bobWalletSharesAfter2, uint256 bobStakedBlockAfter2, uint256 bobClaimedBlockAfter2) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 actualTotalShares2 = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter2 = pushStaking.epochToTotalShares(2); + + assertEq(bobWalletSharesAfter2, expectedAllocationShares2); + assertEq(actualTotalShares2, 200_000 * 1e18); + assertEq(epochToTotalSharesAfter2, actualTotalShares2); + } + + // function test_MaxDecimalAmount () public { + // // fixed at most 10 decimal places + // // percentage = 10.1111111111 + // StakingTypes.Percentage memory _percentage = StakingTypes.Percentage({ + // percentageNumber: 101111111111, + // decimalPlaces: 10 + // }); + + // for (uint256 i=1; i<50; i++) { + // uint256 shares = pushStaking.getSharesAmount({ + // _totalShares: 10 ** i, + // _percentage: _percentage + // }); + // console2.log("totalShares = ", i); + // console2.log(shares/1e18); + // console2.log(""); + // } + // } +} From db66d05a0d41584f5454760e51517f1b0500c05c Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 16 Oct 2024 18:38:10 +0530 Subject: [PATCH 24/49] walletShare being 0 test pass --- .../unit_tests/WalletShare/WalletShare.t.sol | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol index 1941181d..e4d4eb3e 100644 --- a/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -481,6 +481,25 @@ contract WalletShareTest is BaseFuzzStaking { assertEq(epochToTotalSharesAfter2, actualTotalShares2); } + // POC + function test_whenWallet_ClaimRewards_InSameEpoch() external { + addPool(1000); + test_WalletGets_20PercentAllocation(); + changePrank(actor.bob_channel_owner); + roll(epochDuration + 1); + addPool(1000); + StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + assertEq(bobWalletSharesBefore, bobWalletSharesAfter); + } + // function test_MaxDecimalAmount () public { // // fixed at most 10 decimal places // // percentage = 10.1111111111 From 1cc73fcf845868de2bcd164857892ddbcfb33f0d Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Thu, 17 Oct 2024 12:50:50 +0530 Subject: [PATCH 25/49] test: added invariants for unit tests --- .../BaseWalletSharesStaking.t.sol | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol index fcb745fa..28596b96 100644 --- a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol +++ b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol @@ -1,34 +1,60 @@ pragma solidity ^0.8.20; pragma experimental ABIEncoderV2; -import { BasePushStaking } from "../BasePushStaking.t.sol"; +import {BasePushStaking} from "../BasePushStaking.t.sol"; +import {StakingTypes} from "../../../../contracts/libraries/DataTypes.sol"; contract BaseWalletSharesStaking is BasePushStaking { - function setUp() public virtual override { BasePushStaking.setUp(); } - modifier validateShareInvariants () { + /** + * @notice Modifier that validates share invariants before and after the execution of the wrapped function. + * @dev Ensures that the total wallet shares remain consistent and checks the sum of individual wallet shares. + */ + modifier validateShareInvariants() { uint256 walletSharesBeforeExecution = pushStaking.WALLET_TOTAL_SHARES(); _; _validateWalletSharesSum(); _validateEpochShares(); - _verifyTotalSharesConsistency(walletSharesBeforeExecution); } + // VALIDATION FUNCTIONS + + /** + * @notice Validates that the total wallet shares are equal to the sum of individual wallet shares. + * @dev Ensures that the sum of shares for the foundation and other actors is consistent with the total wallet shares. + */ function _validateWalletSharesSum() internal { uint256 walletTotalShares = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 foundationWalletShares,,) = pushStaking.walletShareInfo(actor.admin); - (uint256 bobWalletShares,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); - (uint256 aliceWalletShares,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); - (uint256 charlieWalletShares,,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); - (uint256 tonyWalletShares,,) = pushStaking.walletShareInfo(actor.tony_channel_owner); + (uint256 foundationWalletShares, , ) = pushStaking.walletShareInfo( + actor.admin + ); + (uint256 bobWalletShares, , ) = pushStaking.walletShareInfo( + actor.bob_channel_owner + ); + (uint256 aliceWalletShares, , ) = pushStaking.walletShareInfo( + actor.alice_channel_owner + ); + (uint256 charlieWalletShares, , ) = pushStaking.walletShareInfo( + actor.charlie_channel_owner + ); + (uint256 tonyWalletShares, , ) = pushStaking.walletShareInfo( + actor.tony_channel_owner + ); - uint256 totalSharesSum = foundationWalletShares + bobWalletShares + aliceWalletShares + charlieWalletShares + tonyWalletShares; + uint256 totalSharesSum = foundationWalletShares + + bobWalletShares + + aliceWalletShares + + charlieWalletShares + + tonyWalletShares; assertEq(walletTotalShares, totalSharesSum); } + /** + * @notice Verifies that epochToTotalShares in any epoch remain less than equal to total + */ function _validateEpochShares() internal { uint256 walletTotalShares = pushStaking.WALLET_TOTAL_SHARES(); for (uint256 i=genesisEpoch; i<=getCurrentEpoch(); ) { @@ -38,9 +64,4 @@ contract BaseWalletSharesStaking is BasePushStaking { } } } - - function _verifyTotalSharesConsistency(uint256 _walletSharesBeforeExecution) internal { - uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); - assertEq(_walletSharesBeforeExecution, walletTotalSharesAfter); - } } From 5e692b1d6607a95336380f4aeb2091705a2c4a71 Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Thu, 17 Oct 2024 12:51:07 +0530 Subject: [PATCH 26/49] test: added test cases for addWalletShares --- .../AddWalletShare/AddWalletShare.t.sol | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol new file mode 100644 index 00000000..13f92792 --- /dev/null +++ b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; +import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import {console2} from "forge-std/console2.sol"; +import { Errors } from "contracts/libraries/Errors.sol"; + +contract AddWalletShareTest is BaseWalletSharesStaking { + + function setUp() public virtual override { + BaseWalletSharesStaking.setUp(); + } + + function test_Revertwhen_Caller_NotGovernance() public validateShareInvariants { + changePrank(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotGovernance.selector)); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + } + + function test_Revertwhen_InvalidPercentage() public validateShareInvariants { + changePrank(actor.admin); + StakingTypes.Percentage memory percentAllocationZero = StakingTypes.Percentage({ percentageNumber: 0, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationZero); + + StakingTypes.Percentage memory percentAllocationHundred = StakingTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationHundred); + } + + function test_Revertwhen_WalletAddress_Zero() public validateShareInvariants { + changePrank(actor.admin); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, address(0))); + pushStaking.addWalletShare(address(0), percentAllocation); + } + + function test_Revertwhen_Increased() public validateShareInvariants { + changePrank(actor.admin); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, address(0))); + pushStaking.addWalletShare(address(0), percentAllocation); + } + + function test_Revertwhen_NewSharesEqual_ToOldShares() public validateShareInvariants { + changePrank(actor.admin); + StakingTypes.Percentage memory percentAllocation1 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation1); + + // revert when new allocation is equal to already allocated shares + StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); + + // revert when new allocation is less than already allocated shares + StakingTypes.Percentage memory percentAllocation3 = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation3); + } + + function test_AddWalletShare() public validateShareInvariants { + changePrank(actor.admin); + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesBefore, , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 expectedSharesOfBob = 25_000 * 1e18; // wallet total shares is 100k initially + emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); + + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + assertEq(walletTotalSharesAfter, walletTotalSharesBefore + expectedSharesOfBob); + assertEq(epochToTotalSharesAfter, epochToTotalSharesBefore + expectedSharesOfBob); + + assertEq(bobWalletSharesBefore, 0); + assertEq(bobWalletSharesAfter, expectedSharesOfBob); + assertEq(bobStakedBlockAfter, block.number); + assertEq(bobClaimedBlockAfter, pushStaking.genesisEpoch()); + assertEq(bobClaimedBlockBefore, bobClaimedBlockAfter); + } + + function test_IncreaseAllocation_InSameEpoch() public validateShareInvariants { + test_AddWalletShare(); + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 expectedSharesOfBob = 100_000 * 1e18; // wallet total shares is 125k now, already allocated shares of bob is 25k + emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); + + StakingTypes.Percentage memory newPercentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, newPercentAllocation); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + assertEq(walletTotalSharesAfter, 200_000 * 1e18); + assertEq(epochToTotalSharesAfter, 200_000 * 1e18); + + assertEq(bobWalletSharesBefore, 25_000 * 1e18); + assertEq(bobWalletSharesAfter, expectedSharesOfBob); + assertEq(bobStakedBlockAfter, block.number); + assertEq(bobClaimedBlockAfter, pushStaking.genesisEpoch()); + + // INVARIANT: wallet total shares should never be reduced after a function call + assertLe(walletTotalSharesBefore, walletTotalSharesAfter); + // INVARIANT: epochToTotalShares should never be reduced after a function call + assertLe(epochToTotalSharesBefore, epochToTotalSharesAfter); + // INVARIANT: epochToTotalShares in any epoch should not exceed total wallet shares + assertLe(epochToTotalSharesAfter, walletTotalSharesAfter); + } + + function test_IncreaseAllocation_InDifferentEpoch() public validateShareInvariants { + test_AddWalletShare(); + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + // uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + roll(epochDuration + 1); + + uint256 expectedSharesOfBob = 100_000 * 1e18; // wallet total shares is 125k now, already allocated shares of bob is 25k + emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); + + StakingTypes.Percentage memory newPercentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, newPercentAllocation); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + assertEq(walletTotalSharesAfter, 200_000 * 1e18); + assertEq(epochToTotalSharesAfter, walletTotalSharesAfter); + + assertEq(bobWalletSharesBefore, 25_000 * 1e18); + assertEq(bobWalletSharesAfter, expectedSharesOfBob); + assertEq(bobStakedBlockAfter, block.number); + assertEq(bobClaimedBlockAfter, pushStaking.genesisEpoch()); + + // INVARIANT: wallet total shares should never be reduced after a function call + assertLe(walletTotalSharesBefore, walletTotalSharesAfter); + // INVARIANT: epochToTotalShares in any epoch should not exceed total wallet shares + assertLe(epochToTotalSharesAfter, walletTotalSharesAfter); + } +} \ No newline at end of file From 46c36772ca8308ca838d7e41d22990af61f15a8c Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Thu, 17 Oct 2024 12:51:24 +0530 Subject: [PATCH 27/49] test: added test cases for removeWalletShares --- .../RemoveWalletShare/RemoveWalletShare.t.sol | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol new file mode 100644 index 00000000..f80baf03 --- /dev/null +++ b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; +import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import {console2} from "forge-std/console2.sol"; +import { Errors } from "contracts/libraries/Errors.sol"; + +contract AddWalletShareTest is BaseWalletSharesStaking { + + function setUp() public virtual override { + BaseWalletSharesStaking.setUp(); + } + + function test_Revertwhen_Caller_NotGovernance() public validateShareInvariants { + changePrank(actor.bob_channel_owner); + vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotGovernance.selector)); + pushStaking.removeWalletShare(actor.bob_channel_owner); + } + + function test_Revertwhen_WalletAddress_Zero_OrFoundation() public validateShareInvariants { + changePrank(actor.admin); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, address(0))); + pushStaking.removeWalletShare(address(0)); + + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, actor.admin)); + pushStaking.removeWalletShare(actor.admin); + } + + function test_RemoveWalletShare_SameEpoch() public validateShareInvariants { + addPool(1000); + changePrank(actor.admin); + // Add wallet shares of bob + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesBefore, , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesBefore, , uint256 foundationClaimedBlockBefore) = pushStaking.walletShareInfo(actor.admin); + + emit SharesRemoved(actor.bob_channel_owner, bobWalletSharesBefore); + // Remove wallet shares of foundation + pushStaking.removeWalletShare(actor.bob_channel_owner); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesAfter, , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesAfter, uint256 foundationStakedBlockAfter, uint256 foundationClaimedBlockAfter) = pushStaking.walletShareInfo(actor.admin); + + assertEq(walletTotalSharesBefore, walletTotalSharesAfter); + assertEq(epochToTotalSharesBefore, epochToTotalSharesAfter); + assertEq(bobWalletSharesAfter, 0); + assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + bobWalletSharesBefore); + assertEq(foundationStakedBlockAfter, block.number); + assertEq(foundationClaimedBlockBefore, foundationClaimedBlockAfter); + assertEq(bobClaimedBlockAfter, bobClaimedBlockBefore); + } + + function test_RemoveWalletShare_SameEpoch_Rewards() public validateShareInvariants { + test_RemoveWalletShare_SameEpoch(); + + uint256 bobRewards = pushStaking.calculateWalletRewards(actor.bob_channel_owner, getCurrentEpoch()); + assertEq(bobRewards, 0); + } + + function test_RemoveWalletShare_DifferentEpoch() public validateShareInvariants { + addPool(1000); // doubt + changePrank(actor.admin); + // Add wallet shares of bob + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + roll(epochDuration * 2); + addPool(1000); + + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + (uint256 bobWalletSharesBefore, , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesBefore, , uint256 foundationClaimedBlockBefore) = pushStaking.walletShareInfo(actor.admin); + + emit SharesRemoved(actor.bob_channel_owner, bobWalletSharesBefore); + // Remove wallet shares of foundation + pushStaking.removeWalletShare(actor.bob_channel_owner); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesAfter, , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesAfter, uint256 foundationStakedBlockAfter, uint256 foundationClaimedBlockAfter) = pushStaking.walletShareInfo(actor.admin); + + assertEq(walletTotalSharesBefore, walletTotalSharesAfter); + assertEq(epochToTotalSharesAfter, walletTotalSharesAfter); + assertEq(bobWalletSharesAfter, 0); + assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + bobWalletSharesBefore); + assertEq(foundationStakedBlockAfter, block.number); + assertEq(foundationClaimedBlockBefore, foundationClaimedBlockAfter); + assertEq(bobClaimedBlockAfter, bobClaimedBlockBefore); + } + + function test_RemoveWalletShare_DifferentEpoch_Rewards() public validateShareInvariants { + test_RemoveWalletShare_DifferentEpoch(); + + uint256 bobRewards = pushStaking.calculateWalletRewards(actor.bob_channel_owner, 1); + assertGt(bobRewards, 0); + } +} \ No newline at end of file From 93272fb33b5c8ed4ed29f94a2c00f5be51f5fe42 Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Thu, 17 Oct 2024 12:51:47 +0530 Subject: [PATCH 28/49] test: added wallet staking events --- test/utils/Events.sol | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 7f7ca2a6..0cdb3c56 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -66,4 +66,13 @@ abstract contract PushTokenEvents { event NewMinter(address indexed newMinter); } -abstract contract Events is CoreEvents, CommEvents, ProxyEvents, PushTokenEvents, MigrationEvents { } +abstract contract WalletStakingEvents { + event Staked(address indexed user, uint256 indexed amountStaked); + event Unstaked(address indexed user, uint256 indexed amountUnstaked); + event RewardsHarvested(address indexed user, uint256 indexed rewardAmount, uint256 fromEpoch, uint256 tillEpoch); + event NewSharesIssued(address indexed Wallet, uint256 indexed Shares); + event SharesRemoved(address indexed Wallet, uint256 indexed Shares); + event SharesDecreased(address indexed Wallet, uint256 indexed oldShares, uint256 newShares); +} + +abstract contract Events is CoreEvents, CommEvents, ProxyEvents, PushTokenEvents, MigrationEvents, WalletStakingEvents { } From afb5b13e58cf457ccd469ef55734c50844b9c025 Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Thu, 17 Oct 2024 13:07:56 +0530 Subject: [PATCH 29/49] test: created test files for decrease and rewards claims --- .../unit_tests/ClaimRewards/ClaimRewards.t.sol | 15 +++++++++++++++ .../DecreaseWalletShare/DecreaseWalletShare.t.sol | 15 +++++++++++++++ .../RemoveWalletShare/RemoveWalletShare.t.sol | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol create mode 100644 test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol new file mode 100644 index 00000000..e39e7a26 --- /dev/null +++ b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; +import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import {console2} from "forge-std/console2.sol"; +import { Errors } from "contracts/libraries/Errors.sol"; + +contract ClaimRewardsTest is BaseWalletSharesStaking { + + function setUp() public virtual override { + BaseWalletSharesStaking.setUp(); + } + +} \ No newline at end of file diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol new file mode 100644 index 00000000..560c3e53 --- /dev/null +++ b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; +import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import {console2} from "forge-std/console2.sol"; +import { Errors } from "contracts/libraries/Errors.sol"; + +contract DecreaseWalletShareTest is BaseWalletSharesStaking { + + function setUp() public virtual override { + BaseWalletSharesStaking.setUp(); + } + +} \ No newline at end of file diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol index f80baf03..852e1ac6 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol @@ -6,7 +6,7 @@ import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; import {console2} from "forge-std/console2.sol"; import { Errors } from "contracts/libraries/Errors.sol"; -contract AddWalletShareTest is BaseWalletSharesStaking { +contract RemoveWalletShareTest is BaseWalletSharesStaking { function setUp() public virtual override { BaseWalletSharesStaking.setUp(); From cc2cefd173a811308657fe2646ceea6483544d9b Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Thu, 17 Oct 2024 13:09:49 +0530 Subject: [PATCH 30/49] test: commenting token staking and wallet staking test --- .../unit_tests/WalletShare/WalletShare.t.sol | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol index 0af1e637..2a74955b 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -127,58 +127,58 @@ contract WalletShareTest is BaseWalletSharesStaking { assertEq(expectedRewardsAlice, claimedRewardsAlice, "Alice Claimed"); } - function test_whenWalletsAndUsers_ClaimRewards() external { - addPool(1000); - test_WalletGets_50PercentAllocation(); - stake(actor.charlie_channel_owner, 200); - stake(actor.tony_channel_owner, 1000); - roll(epochDuration * 2); - uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,) = - pushStaking.walletShareInfo(actor.bob_channel_owner); - uint256 balanceAliceBefore = pushToken.balanceOf(actor.alice_channel_owner); - (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore,) = - pushStaking.walletShareInfo(actor.alice_channel_owner); - - changePrank(actor.bob_channel_owner); - pushStaking.claimShareRewards(); - changePrank(actor.alice_channel_owner); - pushStaking.claimShareRewards(); - - harvest(actor.charlie_channel_owner); - harvest(actor.tony_channel_owner); - - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = - pushStaking.walletShareInfo(actor.bob_channel_owner); - (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter, uint256 aliceClaimedBlockAfter) = - pushStaking.walletShareInfo(actor.alice_channel_owner); - - assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); - assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); - assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - - uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - - uint256 expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10) / 100; - assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner), "balanceBob"); - assertEq(expectedRewardsBob, claimedRewardsBob, "bobClaimed"); - - assertEq(aliceWalletSharesBefore, aliceWalletSharesAfter, "Shares"); - assertEq(aliceStakedBlockBefore, aliceStakedBlockAfter, "StakedBlock"); - assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - - uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); - - uint256 expectedRewardsAlice = coreProxy.WALLET_FEE_POOL() * 50 / 100; - assertEq( - balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner), "balanceAlice" - ); - assertEq(expectedRewardsAlice, claimedRewardsAlice, "Alice Claimed"); - - uint256 claimedRewardsCharlie = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); - uint256 claimedRewardsTony = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); - assertGt(claimedRewardsTony, claimedRewardsCharlie); - } + // function test_whenWalletsAndUsers_ClaimRewards() external { + // addPool(1000); + // test_WalletGets_50PercentAllocation(); + // stake(actor.charlie_channel_owner, 200); + // stake(actor.tony_channel_owner, 1000); + // roll(epochDuration * 2); + // uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + // (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,) = + // pushStaking.walletShareInfo(actor.bob_channel_owner); + // uint256 balanceAliceBefore = pushToken.balanceOf(actor.alice_channel_owner); + // (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore,) = + // pushStaking.walletShareInfo(actor.alice_channel_owner); + + // changePrank(actor.bob_channel_owner); + // pushStaking.claimShareRewards(); + // changePrank(actor.alice_channel_owner); + // pushStaking.claimShareRewards(); + + // harvest(actor.charlie_channel_owner); + // harvest(actor.tony_channel_owner); + + // (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + // pushStaking.walletShareInfo(actor.bob_channel_owner); + // (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter, uint256 aliceClaimedBlockAfter) = + // pushStaking.walletShareInfo(actor.alice_channel_owner); + + // assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); + // assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); + // assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + // uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + + // uint256 expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10) / 100; + // assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner), "balanceBob"); + // assertEq(expectedRewardsBob, claimedRewardsBob, "bobClaimed"); + + // assertEq(aliceWalletSharesBefore, aliceWalletSharesAfter, "Shares"); + // assertEq(aliceStakedBlockBefore, aliceStakedBlockAfter, "StakedBlock"); + // assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + // uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + + // uint256 expectedRewardsAlice = coreProxy.WALLET_FEE_POOL() * 50 / 100; + // assertEq( + // balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner), "balanceAlice" + // ); + // assertEq(expectedRewardsAlice, claimedRewardsAlice, "Alice Claimed"); + + // uint256 claimedRewardsCharlie = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); + // uint256 claimedRewardsTony = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); + // assertGt(claimedRewardsTony, claimedRewardsCharlie); + // } function test_WalletGets_50PercentAllocation() public { // bob wallet gets allocated 20% shares i.e. 25k From eaeb479f9686efb84cd1ce8a0a525fbd78cb833c Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Thu, 17 Oct 2024 15:24:02 +0530 Subject: [PATCH 31/49] medium issues and test fixes --- contracts/PushStaking/PushStaking.sol | 30 +++++++++++++++---- .../AddWalletShare/AddWalletShare.t.sol | 11 ++++--- .../unit_tests/WalletShare/WalletShare.t.sol | 27 +++++++++++++++-- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index c858b993..70ddf5d1 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -53,6 +53,21 @@ contract PushStaking is Initializable, PushStakingStorage { governance = _governanceAddress; } + function setPushChannelAdmin(address _newChannelAdmin) external onlyPushChannelAdmin{ + pushChannelAdmin = _newChannelAdmin; + } + + function setFoundationAddress(address _foundation) external onlyGovernance{ + uint256 _tillEpoch = lastEpochRelative(genesisEpoch, block.number) - 1; + uint256 _epoch_to_block_number = genesisEpoch + _tillEpoch * epochDuration; + + address oldFoundation = FOUNDATION; + FOUNDATION = _foundation; + walletShareInfo[_foundation].lastClaimedBlock = _epoch_to_block_number; + + removeWalletShare(oldFoundation); + } + function initializeStake(uint256 _walletTotalShares) external { require(genesisEpoch == 0, "PushCoreV2::initializeStake: Already Initialized"); genesisEpoch = block.number; @@ -82,8 +97,8 @@ contract PushStaking is Initializable, PushStakingStorage { public returns (uint256 sharesToBeAllocated) { - if (_percentage.percentageNumber / 10 ** _percentage.decimalPlaces >= 100) { - revert Errors.InvalidArg_MoreThanExpected(99, _percentage.decimalPlaces); + if (_percentage.percentageNumber / 10 ** _percentage.decimalPlaces >= 100 || _percentage.percentageNumber == 0) { + revert Errors.InvalidArg_MoreThanExpected(99, _percentage.percentageNumber); } sharesToBeAllocated = (_percentage.percentageNumber * _totalShares) / ((100 * (10 ** _percentage.decimalPlaces)) - _percentage.percentageNumber); @@ -101,13 +116,16 @@ contract PushStaking is Initializable, PushStakingStorage { * should be greater than the already assigned percentge. */ function addWalletShare(address _walletAddress, StakingTypes.Percentage memory _percentage) public onlyGovernance { + if(_walletAddress == address(0)){ + revert Errors.InvalidArgument_WrongAddress(_walletAddress); + } uint256 TotalShare = WALLET_TOTAL_SHARES; uint256 currentWalletShare = walletShareInfo[_walletAddress].walletShare; if (currentWalletShare != 0) { TotalShare -= currentWalletShare; } uint256 sharesToBeAllocated = getSharesAmount(TotalShare, _percentage); - if (sharesToBeAllocated < currentWalletShare) { + if (sharesToBeAllocated <= currentWalletShare) { revert Errors.InvalidArg_LessThanExpected(currentWalletShare, sharesToBeAllocated); } walletShareInfo[_walletAddress].lastClaimedBlock = walletShareInfo[_walletAddress].lastClaimedBlock == 0 @@ -126,10 +144,12 @@ contract PushStaking is Initializable, PushStakingStorage { */ function removeWalletShare(address _walletAddress) public onlyGovernance { + if(_walletAddress == address(0) || _walletAddress == FOUNDATION) { + revert Errors.InvalidArgument_WrongAddress(_walletAddress); + } uint256 sharesToBeRemoved = walletShareInfo[_walletAddress].walletShare; _adjustWalletAndTotalStake(_walletAddress, 0, sharesToBeRemoved); - - walletShareInfo[FOUNDATION].walletShare += sharesToBeRemoved; + _adjustWalletAndTotalStake(FOUNDATION, sharesToBeRemoved, 0); emit SharesRemoved(_walletAddress, sharesToBeRemoved); } diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol index 13f92792..2edfbb9b 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol @@ -26,7 +26,7 @@ contract AddWalletShareTest is BaseWalletSharesStaking { pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationZero); StakingTypes.Percentage memory percentAllocationHundred = StakingTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 100)); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationHundred); } @@ -48,15 +48,19 @@ contract AddWalletShareTest is BaseWalletSharesStaking { changePrank(actor.admin); StakingTypes.Percentage memory percentAllocation1 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation1); + (uint256 bobWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + // revert when new allocation is equal to already allocated shares StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + uint256 sharesToBeAllocated2 = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES() - bobWalletSharesBefore, percentAllocation2); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_LessThanExpected.selector, bobWalletSharesBefore, sharesToBeAllocated2)); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); // revert when new allocation is less than already allocated shares StakingTypes.Percentage memory percentAllocation3 = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + uint256 sharesToBeAllocated3 = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES() - bobWalletSharesBefore, percentAllocation3); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_LessThanExpected.selector, bobWalletSharesBefore, sharesToBeAllocated3)); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation3); } @@ -83,7 +87,6 @@ contract AddWalletShareTest is BaseWalletSharesStaking { assertEq(bobWalletSharesAfter, expectedSharesOfBob); assertEq(bobStakedBlockAfter, block.number); assertEq(bobClaimedBlockAfter, pushStaking.genesisEpoch()); - assertEq(bobClaimedBlockBefore, bobClaimedBlockAfter); } function test_IncreaseAllocation_InSameEpoch() public validateShareInvariants { diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol index 2a74955b..d938f0de 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -380,8 +380,9 @@ contract WalletShareTest is BaseWalletSharesStaking { // FUZZ TESTS function testFuzz_AddShares(address _walletAddress, StakingTypes.Percentage memory _percentage) public { - _percentage.percentageNumber = bound(_percentage.percentageNumber, 0, 100); - _percentage.decimalPlaces = bound(_percentage.decimalPlaces, 0, 10); + _percentage.percentageNumber = bound(_percentage.percentageNumber, 1, 100); + _percentage.decimalPlaces = bound(_percentage.decimalPlaces, 1, 10); + vm.assume(_walletAddress != actor.admin && _walletAddress != address(0)); // percentage must be less than 100 vm.assume(_percentage.percentageNumber / 10 ** _percentage.decimalPlaces < 100); changePrank(actor.admin); @@ -500,6 +501,28 @@ contract WalletShareTest is BaseWalletSharesStaking { (uint256 bobWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); assertEq(bobWalletSharesBefore, bobWalletSharesAfter); } + + function test_WhenFoundationIsChanged() external { + (uint256 foundationWalletShares,uint256 foundationStakedBlock, uint256 foundationClaimedBlock) = pushStaking.walletShareInfo(actor.admin); + assertEq(foundationWalletShares, 100_000 ether); + assertEq(foundationStakedBlock, genesisEpoch); + assertEq(foundationClaimedBlock, genesisEpoch); + roll(epochDuration + 1); + changePrank(actor.admin); + pushStaking.setFoundationAddress(actor.bob_channel_owner); + + (uint256 newfoundationWalletShares,uint256 newfoundationStakedBlock, uint256 newfoundationClaimedBlock) = pushStaking.walletShareInfo(actor.bob_channel_owner); + assertEq(newfoundationWalletShares, 100_000 ether); + assertEq(newfoundationStakedBlock, block.number); + uint256 _tillEpoch = pushStaking.lastEpochRelative(genesisEpoch, block.number) - 1; + assertEq(newfoundationClaimedBlock, genesisEpoch + _tillEpoch * epochDuration); + + (uint256 oldfoundationWalletShares,uint256 oldfoundationStakedBlock, uint256 oldfoundationClaimedBlock) = pushStaking.walletShareInfo(actor.admin); + + assertEq(oldfoundationWalletShares, 0); + assertEq(oldfoundationStakedBlock, genesisEpoch); + assertEq(oldfoundationClaimedBlock, genesisEpoch); + } // function test_MaxDecimalAmount () public { // // fixed at most 10 decimal places From 0fdeba7c786cea14a1754e4da079ebb5fbb5c4c1 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 18 Oct 2024 01:57:21 +0530 Subject: [PATCH 32/49] add claim test and minor updates --- .../BaseWalletSharesStaking.t.sol | 1 - .../AddWalletShare/AddWalletShare.t.sol | 3 + .../ClaimRewards/ClaimRewards.t.sol | 162 ++++++++++++++++++ 3 files changed, 165 insertions(+), 1 deletion(-) diff --git a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol index 28596b96..ba290c83 100644 --- a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol +++ b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.20; pragma experimental ABIEncoderV2; import {BasePushStaking} from "../BasePushStaking.t.sol"; -import {StakingTypes} from "../../../../contracts/libraries/DataTypes.sol"; contract BaseWalletSharesStaking is BasePushStaking { function setUp() public virtual override { diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol index 2edfbb9b..97b43424 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol @@ -71,6 +71,7 @@ contract AddWalletShareTest is BaseWalletSharesStaking { (uint256 bobWalletSharesBefore, , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 expectedSharesOfBob = 25_000 * 1e18; // wallet total shares is 100k initially + vm.expectEmit(true, true, false, false); emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); @@ -96,6 +97,7 @@ contract AddWalletShareTest is BaseWalletSharesStaking { (uint256 bobWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 expectedSharesOfBob = 100_000 * 1e18; // wallet total shares is 125k now, already allocated shares of bob is 25k + vm.expectEmit(true, true, false, false); emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); StakingTypes.Percentage memory newPercentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); @@ -130,6 +132,7 @@ contract AddWalletShareTest is BaseWalletSharesStaking { roll(epochDuration + 1); uint256 expectedSharesOfBob = 100_000 * 1e18; // wallet total shares is 125k now, already allocated shares of bob is 25k + vm.expectEmit(true, true, false, false); emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); StakingTypes.Percentage memory newPercentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol index e39e7a26..13f86b1f 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol @@ -12,4 +12,166 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { BaseWalletSharesStaking.setUp(); } + function test_whenUser_claimsIn_stakedEpoch()external validateShareInvariants{ + // gets zero rewards for that epoch + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + addPool(1000); + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,uint256 bobLastClaimedBlock) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + //Claims in the same epoch as shares issued + uint256 expectedRewards = 0; + vm.expectEmit(true, true, false, true); + emit RewardsHarvested(actor.bob_channel_owner, expectedRewards, pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), getCurrentEpoch() - 1); + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); + assertEq(expectedRewards, claimedRewards); + } + + function test_WhenUserClaims_in_DifferentEpoch() public validateShareInvariants{ + //SHould succesully Claim the reward + + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + addPool(1000); + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,uint256 bobLastClaimedBlock) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + //claims in the second epoch + roll(epochDuration + 1 ); + uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 20) / 100; + vm.expectEmit(true, true, false, true); + emit RewardsHarvested(actor.bob_channel_owner, expectedRewards, pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), getCurrentEpoch() - 1); + changePrank(actor.bob_channel_owner); + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); + assertEq(expectedRewards, claimedRewards); + + + } + + function test_whenUser_claimsIn_sameClaimedEpoch()external validateShareInvariants{ + test_WhenUserClaims_in_DifferentEpoch(); + + uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + uint256 claimedRewardsBefore = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,uint256 bobLastClaimedBlock) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + // claims again in the second epoch + vm.expectEmit(true, true, false, true); + emit RewardsHarvested(actor.bob_channel_owner, 0, pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), getCurrentEpoch() - 1); + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + + (uint256 bobWalletSharesAfter2, uint256 bobStakedBlockAfter2, uint256 bobClaimedBlockAfter2) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + //No changes in balance and claimed rewards + assertEq(bobWalletSharesBefore, bobWalletSharesAfter2, "Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter2, "StakedBlock"); + assertEq(bobClaimedBlockAfter2, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + assertEq(balanceBobBefore , pushToken.balanceOf(actor.bob_channel_owner), "Balance"); + assertEq(claimedRewardsBefore, claimedRewards); + } + + function test_whenUser_claimsFor_multipleEpochs()external validateShareInvariants{ + //shares issues in epoch one, reward added in subsequent epoch, wallet claims in 4th epoch + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + addPool(1000); + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + roll(epochDuration + 1); + addPool(2000); + + roll(epochDuration * 2 + 1); + addPool(3000); + + roll(epochDuration * 3 + 1); + addPool(4000); + + roll(epochDuration * 4 + 1); + + uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,uint256 bobLastClaimedBlock) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 20) / 100; + + vm.expectEmit(true, true, false, true); + emit RewardsHarvested(actor.bob_channel_owner, expectedRewards, pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), getCurrentEpoch() - 1); + + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter2) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + //No changes in balance and claimed rewards + assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); + assertEq(bobClaimedBlockAfter2, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + + assertEq(balanceBobBefore + expectedRewards , pushToken.balanceOf(actor.bob_channel_owner), "Balance"); + assertEq(expectedRewards, claimedRewards); + } + + function test_whenFoundation_ClaimRewards() external validateShareInvariants{ + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + addPool(1000); + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + roll(epochDuration * 2); + uint256 balanceAdminBefore = pushToken.balanceOf(actor.admin); + (uint256 adminWalletSharesBefore, uint256 adminStakedBlockBefore,uint256 adminLastClaimedBlock) = pushStaking.walletShareInfo(actor.admin); + + uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 80) / 100; + vm.expectEmit(true, true, false, true); + emit RewardsHarvested(actor.admin, expectedRewards, pushStaking.lastEpochRelative(genesisEpoch, adminLastClaimedBlock), getCurrentEpoch() - 1); + changePrank(actor.admin); + pushStaking.claimShareRewards(); + (uint256 adminWalletSharesAfter, uint256 adminStakedBlockAfter, uint256 adminClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.admin); + + assertEq(adminWalletSharesBefore, adminWalletSharesAfter, "Shares"); + assertEq(adminStakedBlockBefore, adminStakedBlockAfter, "StakedBlock"); + assertEq(adminClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.admin); + assertEq(balanceAdminBefore + expectedRewards, pushToken.balanceOf(actor.admin), "Balance"); + assertEq(expectedRewards, claimedRewards); + } + } \ No newline at end of file From 73e42d1d342c73b761968c1ca493e0b26d008e0a Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 18 Oct 2024 03:01:29 +0530 Subject: [PATCH 33/49] fmt and add a test --- .../ClaimRewards/ClaimRewards.t.sol | 200 +++++++++++++++--- 1 file changed, 165 insertions(+), 35 deletions(-) diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol index 13f86b1f..96e497d2 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol @@ -3,35 +3,45 @@ pragma solidity ^0.8.20; import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; -import {console2} from "forge-std/console2.sol"; +import { console2 } from "forge-std/console2.sol"; import { Errors } from "contracts/libraries/Errors.sol"; contract ClaimRewardsTest is BaseWalletSharesStaking { - function setUp() public virtual override { BaseWalletSharesStaking.setUp(); } - function test_whenUser_claimsIn_stakedEpoch()external validateShareInvariants{ + function test_whenUser_claimsIn_stakedEpoch() external validateShareInvariants { + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); // gets zero rewards for that epoch - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); addPool(1000); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,uint256 bobLastClaimedBlock) = + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobLastClaimedBlock) = pushStaking.walletShareInfo(actor.bob_channel_owner); - + //Claims in the same epoch as shares issued uint256 expectedRewards = 0; vm.expectEmit(true, true, false, true); - emit RewardsHarvested(actor.bob_channel_owner, expectedRewards, pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), getCurrentEpoch() - 1); + emit RewardsHarvested( + actor.bob_channel_owner, + expectedRewards, + pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), + getCurrentEpoch() - 1 + ); changePrank(actor.bob_channel_owner); pushStaking.claimShareRewards(); + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + + assertEq(epochToTotalSharesAfter, walletTotalSharesAfter, "eq epoch to total"); (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = - pushStaking.walletShareInfo(actor.bob_channel_owner); + pushStaking.walletShareInfo(actor.bob_channel_owner); assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); @@ -40,31 +50,45 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(expectedRewards, claimedRewards); + + assertLe(walletTotalSharesBefore, walletTotalSharesAfter, "Wallet Total Shares"); + assertLe(epochToTotalSharesAfter, walletTotalSharesAfter, "LE Epoch to total"); } - function test_WhenUserClaims_in_DifferentEpoch() public validateShareInvariants{ + function test_WhenUserClaims_in_DifferentEpoch() public validateShareInvariants { + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); //SHould succesully Claim the reward - - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); addPool(1000); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,uint256 bobLastClaimedBlock) = + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobLastClaimedBlock) = pushStaking.walletShareInfo(actor.bob_channel_owner); - + //claims in the second epoch - roll(epochDuration + 1 ); + roll(epochDuration + 1); uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 20) / 100; vm.expectEmit(true, true, false, true); - emit RewardsHarvested(actor.bob_channel_owner, expectedRewards, pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), getCurrentEpoch() - 1); - changePrank(actor.bob_channel_owner); + emit RewardsHarvested( + actor.bob_channel_owner, + expectedRewards, + pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), + getCurrentEpoch() - 1 + ); changePrank(actor.bob_channel_owner); pushStaking.claimShareRewards(); + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + + assertEq(epochToTotalSharesAfter, walletTotalSharesAfter, "eq epoch to total"); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = - pushStaking.walletShareInfo(actor.bob_channel_owner); + pushStaking.walletShareInfo(actor.bob_channel_owner); assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); @@ -74,25 +98,31 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(expectedRewards, claimedRewards); - + assertLe(walletTotalSharesBefore, walletTotalSharesAfter, "Wallet Total Shares"); + assertLe(epochToTotalSharesAfter, walletTotalSharesAfter, "LE Epoch to total"); } - function test_whenUser_claimsIn_sameClaimedEpoch()external validateShareInvariants{ + function test_whenUser_claimsIn_sameClaimedEpoch() external validateShareInvariants { test_WhenUserClaims_in_DifferentEpoch(); uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); uint256 claimedRewardsBefore = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,uint256 bobLastClaimedBlock) = + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobLastClaimedBlock) = pushStaking.walletShareInfo(actor.bob_channel_owner); // claims again in the second epoch vm.expectEmit(true, true, false, true); - emit RewardsHarvested(actor.bob_channel_owner, 0, pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), getCurrentEpoch() - 1); + emit RewardsHarvested( + actor.bob_channel_owner, + 0, + pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), + getCurrentEpoch() - 1 + ); changePrank(actor.bob_channel_owner); pushStaking.claimShareRewards(); (uint256 bobWalletSharesAfter2, uint256 bobStakedBlockAfter2, uint256 bobClaimedBlockAfter2) = - pushStaking.walletShareInfo(actor.bob_channel_owner); + pushStaking.walletShareInfo(actor.bob_channel_owner); //No changes in balance and claimed rewards assertEq(bobWalletSharesBefore, bobWalletSharesAfter2, "Shares"); @@ -100,13 +130,15 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(bobClaimedBlockAfter2, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - assertEq(balanceBobBefore , pushToken.balanceOf(actor.bob_channel_owner), "Balance"); + assertEq(balanceBobBefore, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(claimedRewardsBefore, claimedRewards); } - function test_whenUser_claimsFor_multipleEpochs()external validateShareInvariants{ + function test_whenUser_claimsFor_multipleEpochs() external validateShareInvariants { + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); //shares issues in epoch one, reward added in subsequent epoch, wallet claims in 4th epoch - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); addPool(1000); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -123,19 +155,29 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { roll(epochDuration * 4 + 1); uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,uint256 bobLastClaimedBlock) = + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobLastClaimedBlock) = pushStaking.walletShareInfo(actor.bob_channel_owner); uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 20) / 100; vm.expectEmit(true, true, false, true); - emit RewardsHarvested(actor.bob_channel_owner, expectedRewards, pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), getCurrentEpoch() - 1); + emit RewardsHarvested( + actor.bob_channel_owner, + expectedRewards, + pushStaking.lastEpochRelative(genesisEpoch, bobLastClaimedBlock), + getCurrentEpoch() - 1 + ); changePrank(actor.bob_channel_owner); pushStaking.claimShareRewards(); - + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + + assertEq(epochToTotalSharesAfter, walletTotalSharesAfter, "eq epoch to total"); + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter2) = - pushStaking.walletShareInfo(actor.bob_channel_owner); + pushStaking.walletShareInfo(actor.bob_channel_owner); //No changes in balance and claimed rewards assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); @@ -144,27 +186,44 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); - assertEq(balanceBobBefore + expectedRewards , pushToken.balanceOf(actor.bob_channel_owner), "Balance"); + assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(expectedRewards, claimedRewards); + + assertLe(walletTotalSharesBefore, walletTotalSharesAfter, "Wallet Total Shares"); + assertLe(epochToTotalSharesAfter, walletTotalSharesAfter, "LE Epoch to total"); } - function test_whenFoundation_ClaimRewards() external validateShareInvariants{ - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + function test_whenFoundation_ClaimRewards() external validateShareInvariants { + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); addPool(1000); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); roll(epochDuration * 2); uint256 balanceAdminBefore = pushToken.balanceOf(actor.admin); - (uint256 adminWalletSharesBefore, uint256 adminStakedBlockBefore,uint256 adminLastClaimedBlock) = pushStaking.walletShareInfo(actor.admin); + (uint256 adminWalletSharesBefore, uint256 adminStakedBlockBefore, uint256 adminLastClaimedBlock) = + pushStaking.walletShareInfo(actor.admin); uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 80) / 100; vm.expectEmit(true, true, false, true); - emit RewardsHarvested(actor.admin, expectedRewards, pushStaking.lastEpochRelative(genesisEpoch, adminLastClaimedBlock), getCurrentEpoch() - 1); + emit RewardsHarvested( + actor.admin, + expectedRewards, + pushStaking.lastEpochRelative(genesisEpoch, adminLastClaimedBlock), + getCurrentEpoch() - 1 + ); changePrank(actor.admin); pushStaking.claimShareRewards(); (uint256 adminWalletSharesAfter, uint256 adminStakedBlockAfter, uint256 adminClaimedBlockAfter) = pushStaking.walletShareInfo(actor.admin); + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + + assertEq(epochToTotalSharesAfter, walletTotalSharesAfter, "eq epoch to total"); + assertEq(adminWalletSharesBefore, adminWalletSharesAfter, "Shares"); assertEq(adminStakedBlockBefore, adminStakedBlockAfter, "StakedBlock"); assertEq(adminClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); @@ -172,6 +231,77 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.admin); assertEq(balanceAdminBefore + expectedRewards, pushToken.balanceOf(actor.admin), "Balance"); assertEq(expectedRewards, claimedRewards); + + assertLe(walletTotalSharesBefore, walletTotalSharesAfter, "Wallet Total Shares"); + assertLe(epochToTotalSharesAfter, walletTotalSharesAfter, "LE Epoch to total"); } -} \ No newline at end of file + function test_whenWalletsAndUsers_ClaimRewards() external { + addPool(1000); + StakingTypes.Percentage memory percentAllocation = + StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + StakingTypes.Percentage memory percentAllocation2 = + StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.alice_channel_owner, percentAllocation2); + + changePrank(actor.charlie_channel_owner); + pushStaking.stake(200 ether); + changePrank(actor.tony_channel_owner); + pushStaking.stake(1000 ether); + + roll(epochDuration * 2); + uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); + (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore,) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 balanceAliceBefore = pushToken.balanceOf(actor.alice_channel_owner); + (uint256 aliceWalletSharesBefore, uint256 aliceStakedBlockBefore,) = + pushStaking.walletShareInfo(actor.alice_channel_owner); + + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + changePrank(actor.alice_channel_owner); + pushStaking.claimShareRewards(); + + changePrank(actor.charlie_channel_owner); + pushStaking.harvestAll(); + changePrank(actor.tony_channel_owner); + pushStaking.harvestAll(); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesAfter, uint256 aliceStakedBlockAfter, uint256 aliceClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.alice_channel_owner); + + assertEq(bobWalletSharesBefore, bobWalletSharesAfter, "Shares"); + assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); + assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + + uint256 expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10) / 100; + assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner), "balanceBob"); + assertEq(expectedRewardsBob, claimedRewardsBob, "bobClaimed"); + + assertEq(aliceWalletSharesBefore, aliceWalletSharesAfter, "Shares"); + assertEq(aliceStakedBlockBefore, aliceStakedBlockAfter, "StakedBlock"); + assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); + + uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + + uint256 expectedRewardsAlice = coreProxy.WALLET_FEE_POOL() * 50 / 100; + assertEq( + balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner), "balanceAlice" + ); + assertEq(expectedRewardsAlice, claimedRewardsAlice, "Alice Claimed"); + + uint256 claimedRewardsCharlie = pushStaking.usersRewardsClaimed(actor.charlie_channel_owner); + uint256 claimedRewardsTony = pushStaking.usersRewardsClaimed(actor.tony_channel_owner); + assertGt(claimedRewardsTony, claimedRewardsCharlie); + } +} From befbca4f28187e0c3e357e7c87bc03a92731f64b Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Fri, 18 Oct 2024 13:28:35 +0530 Subject: [PATCH 34/49] tests: Added decreaseWalletShares test cases --- .../AddWalletShare/AddWalletShare.t.sol | 2 +- .../DecreaseWalletShare.t.sol | 112 +++++++++++++++++- .../RemoveWalletShare/RemoveWalletShare.t.sol | 4 +- 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol index 13f92792..fce381e2 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol @@ -44,7 +44,7 @@ contract AddWalletShareTest is BaseWalletSharesStaking { pushStaking.addWalletShare(address(0), percentAllocation); } - function test_Revertwhen_NewSharesEqual_ToOldShares() public validateShareInvariants { + function test_Revertwhen_NewShares_LE_ToOldShares() public validateShareInvariants { changePrank(actor.admin); StakingTypes.Percentage memory percentAllocation1 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation1); diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol index 560c3e53..0b1b2c7d 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol @@ -12,4 +12,114 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { BaseWalletSharesStaking.setUp(); } -} \ No newline at end of file + function test_Revertwhen_Caller_NotGovernance() public validateShareInvariants { + changePrank(actor.bob_channel_owner); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotGovernance.selector)); + pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation); + } + + function test_Revertwhen_WalletAddress_Zero_OrFoundation() public validateShareInvariants { + changePrank(actor.admin); + StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, address(0))); + pushStaking.decreaseWalletShare(address(0), percentAllocation); + + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, actor.admin)); + pushStaking.decreaseWalletShare(actor.admin, percentAllocation); + } + + function test_Revertwhen_InvalidPercentage() public validateShareInvariants { + changePrank(actor.admin); + StakingTypes.Percentage memory percentAllocationZero = StakingTypes.Percentage({ percentageNumber: 0, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocationZero); + + StakingTypes.Percentage memory percentAllocationHundred = StakingTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocationHundred); + } + + function test_Revertwhen_Percentage_GE_Allocated() public validateShareInvariants { + changePrank(actor.admin); + StakingTypes.Percentage memory percentAllocation1 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation1); + + // revert when new allocation is equal to already allocated shares + StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation2); + + // revert when new allocation is greater than already allocated shares + StakingTypes.Percentage memory percentAllocation3 = StakingTypes.Percentage({ percentageNumber: 30, decimalPlaces: 0 }); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation3); + } + + function test_DecreaseWalletShare_SameEpoch() public validateShareInvariants { + addPool(1000); + changePrank(actor.admin); + // Add wallet shares of bob + StakingTypes.Percentage memory percentAllocationFifty = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationFifty); + pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocationFifty); + + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 charlieWalletSharesBefore, , uint256 charlieClaimedBlockBefore) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); + + // Decrease wallet shares of charlie from 50 to 40% + StakingTypes.Percentage memory newPercentAllocationCharlie = StakingTypes.Percentage({ percentageNumber: 40, decimalPlaces: 0 }); + uint256 expectedCharlieShares = (newPercentAllocationCharlie.percentageNumber * charlieWalletSharesBefore) / percentAllocationFifty.percentageNumber; + emit SharesDecreased(actor.charlie_channel_owner, charlieWalletSharesBefore, expectedCharlieShares); + pushStaking.decreaseWalletShare(actor.charlie_channel_owner, newPercentAllocationCharlie); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 charlieWalletSharesAfter, , uint256 charlieClaimedBlockAfter) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 foundationWalletSharesAfter, uint256 foundationStakedBlockAfter, ) = pushStaking.walletShareInfo(actor.admin); + + assertEq(charlieWalletSharesAfter, expectedCharlieShares); + assertEq(walletTotalSharesBefore, walletTotalSharesAfter); + assertEq(epochToTotalSharesBefore, epochToTotalSharesAfter); + assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + (charlieWalletSharesBefore - charlieWalletSharesAfter)); + assertEq(foundationStakedBlockAfter, block.number); + assertEq(charlieClaimedBlockAfter, charlieClaimedBlockBefore); + } + + function test_DecreaseWalletShare_DifferentEpoch() public validateShareInvariants { + addPool(1000); + changePrank(actor.admin); + // Add wallet shares of bob + StakingTypes.Percentage memory percentAllocationFifty = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationFifty); + pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocationFifty); + + roll(epochDuration * 2); + addPool(1000); + + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 charlieWalletSharesBefore, , uint256 charlieClaimedBlockBefore) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); + + // Decrease wallet shares of charlie from 50 to 40% + StakingTypes.Percentage memory newPercentAllocationCharlie = StakingTypes.Percentage({ percentageNumber: 40, decimalPlaces: 0 }); + uint256 expectedCharlieShares = (newPercentAllocationCharlie.percentageNumber * charlieWalletSharesBefore) / percentAllocationFifty.percentageNumber; + emit SharesDecreased(actor.charlie_channel_owner, charlieWalletSharesBefore, expectedCharlieShares); + pushStaking.decreaseWalletShare(actor.charlie_channel_owner, newPercentAllocationCharlie); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 charlieWalletSharesAfter, , uint256 charlieClaimedBlockAfter) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 foundationWalletSharesAfter, uint256 foundationStakedBlockAfter, ) = pushStaking.walletShareInfo(actor.admin); + + assertEq(charlieWalletSharesAfter, expectedCharlieShares); + assertEq(walletTotalSharesBefore, walletTotalSharesAfter); + assertEq(epochToTotalSharesBefore, epochToTotalSharesAfter); + assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + (charlieWalletSharesBefore - charlieWalletSharesAfter)); + assertEq(foundationStakedBlockAfter, block.number); + assertEq(charlieClaimedBlockAfter, charlieClaimedBlockBefore); + } +} diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol index 852e1ac6..53409c9a 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol @@ -40,7 +40,7 @@ contract RemoveWalletShareTest is BaseWalletSharesStaking { (uint256 foundationWalletSharesBefore, , uint256 foundationClaimedBlockBefore) = pushStaking.walletShareInfo(actor.admin); emit SharesRemoved(actor.bob_channel_owner, bobWalletSharesBefore); - // Remove wallet shares of foundation + // Remove wallet shares of bob pushStaking.removeWalletShare(actor.bob_channel_owner); uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); @@ -79,7 +79,7 @@ contract RemoveWalletShareTest is BaseWalletSharesStaking { (uint256 foundationWalletSharesBefore, , uint256 foundationClaimedBlockBefore) = pushStaking.walletShareInfo(actor.admin); emit SharesRemoved(actor.bob_channel_owner, bobWalletSharesBefore); - // Remove wallet shares of foundation + // Remove wallet shares of bob pushStaking.removeWalletShare(actor.bob_channel_owner); uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); From e6f1aaa272f64f0b2fe6192f452761ffde212e90 Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Fri, 18 Oct 2024 14:04:32 +0530 Subject: [PATCH 35/49] test: fixed decrease shares test cases --- .../DecreaseWalletShare/DecreaseWalletShare.t.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol index 0b1b2c7d..39f53cf5 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol @@ -36,7 +36,7 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocationZero); StakingTypes.Percentage memory percentAllocationHundred = StakingTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 100)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocationHundred); } @@ -47,12 +47,12 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { // revert when new allocation is equal to already allocated shares StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 20)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation2); // revert when new allocation is greater than already allocated shares StakingTypes.Percentage memory percentAllocation3 = StakingTypes.Percentage({ percentageNumber: 30, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 30)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation3); } From fd2b17c35af3647d268b33a251c866d4cf06dc44 Mon Sep 17 00:00:00 2001 From: Nilesh Gupta Date: Fri, 18 Oct 2024 15:53:31 +0530 Subject: [PATCH 36/49] fix: fixed low/informationals in wallet staking --- contracts/PushStaking/PushStaking.sol | 14 +++------ contracts/PushStaking/PushStakingStorage.sol | 1 - .../unit_tests/WalletShare/WalletShare.t.sol | 29 +++++++++++++++++++ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index 70ddf5d1..0f67b6f2 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -42,13 +42,6 @@ contract PushStaking is Initializable, PushStakingStorage { _; } - modifier isMigrated() { - if (migrated) { - revert Errors.PushStaking_MigrationCompleted(); - } - _; - } - function setGovernanceAddress(address _governanceAddress) external onlyPushChannelAdmin { governance = _governanceAddress; } @@ -56,7 +49,7 @@ contract PushStaking is Initializable, PushStakingStorage { function setPushChannelAdmin(address _newChannelAdmin) external onlyPushChannelAdmin{ pushChannelAdmin = _newChannelAdmin; } - + function setFoundationAddress(address _foundation) external onlyGovernance{ uint256 _tillEpoch = lastEpochRelative(genesisEpoch, block.number) - 1; uint256 _epoch_to_block_number = genesisEpoch + _tillEpoch * epochDuration; @@ -95,6 +88,7 @@ contract PushStaking is Initializable, PushStakingStorage { StakingTypes.Percentage memory _percentage ) public + pure returns (uint256 sharesToBeAllocated) { if (_percentage.percentageNumber / 10 ** _percentage.decimalPlaces >= 100 || _percentage.percentageNumber == 0) { @@ -476,7 +470,7 @@ contract PushStaking is Initializable, PushStakingStorage { function _adjustWalletAndTotalStake(address _wallet, uint256 _sharesToAdd, uint256 _sharesToRemove) internal { uint256 currentEpoch = lastEpochRelative(genesisEpoch, block.number); - _setupEpochsRewardAndWeightsForWallets(_sharesToAdd, currentEpoch, _sharesToRemove); + _setupEpochsRewardAndSharesForWallets(_sharesToAdd, currentEpoch, _sharesToRemove); uint256 _walletPrevShares = walletShareInfo[_wallet].walletShare; @@ -515,7 +509,7 @@ contract PushStaking is Initializable, PushStakingStorage { * - Records the Pool_Fees value used as rewards. * - Records the last epoch id whose rewards were set. */ - function _setupEpochsRewardAndWeightsForWallets( + function _setupEpochsRewardAndSharesForWallets( uint256 _sharesToAdd, uint256 _currentEpoch, uint256 _sharesToRemove diff --git a/contracts/PushStaking/PushStakingStorage.sol b/contracts/PushStaking/PushStakingStorage.sol index 7cbe3184..5c5b678e 100644 --- a/contracts/PushStaking/PushStakingStorage.sol +++ b/contracts/PushStaking/PushStakingStorage.sol @@ -37,5 +37,4 @@ contract PushStakingStorage { mapping(uint256 => uint256) public epochToTotalStakedWeight; ///@notice stores the total shares in a specific epoch mapping(uint256 => uint256) public epochToTotalShares; - bool migrated; } diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol index d938f0de..bf6e6c14 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -502,14 +502,37 @@ contract WalletShareTest is BaseWalletSharesStaking { assertEq(bobWalletSharesBefore, bobWalletSharesAfter); } + function test_foundation() external { + addPool(1000); + StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation2); + roll(epochDuration + 1); + addPool(1000); + pushStaking.setFoundationAddress(actor.bob_channel_owner); + // StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + // pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation2); + roll(epochDuration * 3); + changePrank(actor.admin); + pushStaking.claimShareRewards(); + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + changePrank(actor.charlie_channel_owner); + pushStaking.claimShareRewards(); + } + function test_WhenFoundationIsChanged() external { + addPool(1000); + // pushStaking.claimShareRewards(); (uint256 foundationWalletShares,uint256 foundationStakedBlock, uint256 foundationClaimedBlock) = pushStaking.walletShareInfo(actor.admin); assertEq(foundationWalletShares, 100_000 ether); assertEq(foundationStakedBlock, genesisEpoch); assertEq(foundationClaimedBlock, genesisEpoch); roll(epochDuration + 1); changePrank(actor.admin); + StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); pushStaking.setFoundationAddress(actor.bob_channel_owner); + addPool(1000); (uint256 newfoundationWalletShares,uint256 newfoundationStakedBlock, uint256 newfoundationClaimedBlock) = pushStaking.walletShareInfo(actor.bob_channel_owner); assertEq(newfoundationWalletShares, 100_000 ether); @@ -519,6 +542,12 @@ contract WalletShareTest is BaseWalletSharesStaking { (uint256 oldfoundationWalletShares,uint256 oldfoundationStakedBlock, uint256 oldfoundationClaimedBlock) = pushStaking.walletShareInfo(actor.admin); + roll(epochDuration * 2); + + pushStaking.claimShareRewards(); + changePrank(actor.bob_channel_owner); + pushStaking.claimShareRewards(); + assertEq(oldfoundationWalletShares, 0); assertEq(oldfoundationStakedBlock, genesisEpoch); assertEq(oldfoundationClaimedBlock, genesisEpoch); From 1d1b4fa99ebca27f4673d6cb06add00dcd7b50ac Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 18 Oct 2024 16:25:19 +0530 Subject: [PATCH 37/49] add int func for fees distribute --- contracts/PushCore/PushCoreV3.sol | 53 ++++++++++++------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index 6dd464a3..ae4eb458 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -172,9 +172,7 @@ contract PushCoreV3 is revert Errors.InvalidArg_LessThanExpected(requiredFees, _amount); } - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _amount) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += _amount - holderFee; + distributeFees(_amount); channelUpdateCounter[_channel] = updateCounter; @@ -244,9 +242,7 @@ contract PushCoreV3 is uint256 poolFundAmount = _amountDeposited - poolFeeAmount; //store funds in pool_funds & pool_fees CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS + poolFundAmount; - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += poolFeeAmount - holderFee; + distributeFees(poolFeeAmount); // Calculate channel weight uint256 _channelWeight = (poolFundAmount * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; @@ -290,9 +286,7 @@ contract PushCoreV3 is ) private { - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _amountDeposited) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += _amountDeposited - holderFee; + distributeFees(_amountDeposited); string memory notifSetting = string(abi.encodePacked(Strings.toString(_notifOptions), "+", _notifSettings)); @@ -356,17 +350,15 @@ contract PushCoreV3 is //store funds in pool_funds & pool_fees CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS + poolFundAmount; - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += poolFeeAmount - holderFee; + distributeFees(poolFeeAmount); - uint256 _newPoolContribution = channelData.poolContribution + poolFundAmount; - uint256 _newChannelWeight = (_newPoolContribution * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; + uint256 _newPoolContribution = channelData.poolContribution + poolFundAmount; + uint256 _newChannelWeight = (_newPoolContribution * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; - channelData.channelState = 1; - channelData.poolContribution = _newPoolContribution; - channelData.channelWeight = _newChannelWeight; - emit ChannelStateUpdate(_channelBytesID, 0, _amount); + channelData.channelState = 1; + channelData.poolContribution = _newPoolContribution; + channelData.channelWeight = _newChannelWeight; + emit ChannelStateUpdate(_channelBytesID, 0, _amount); } /// @inheritdoc IPushCoreV3 @@ -382,9 +374,7 @@ contract PushCoreV3 is uint256 currentPoolContribution = channelData.poolContribution - minPoolContribution; CHANNEL_POOL_FUNDS = CHANNEL_POOL_FUNDS - currentPoolContribution; - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * currentPoolContribution) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += currentPoolContribution - holderFee; + distributeFees(currentPoolContribution); uint256 _newChannelWeight = (minPoolContribution * ADJUST_FOR_FLOAT) / minPoolContribution; @@ -505,15 +495,18 @@ contract PushCoreV3 is */ function addPoolFees(uint256 _rewardAmount) external { IERC20(PUSH_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), _rewardAmount); - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _rewardAmount) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += _rewardAmount - holderFee; + distributeFees(_rewardAmount); } function splitFeePool(uint256 holderSplit) external { onlyGovernance(); SPLIT_PERCENTAGE_FOR_HOLDER = holderSplit; + } + function distributeFees(uint256 _fees) internal{ + uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _fees) / 100; + HOLDER_FEE_POOL += holderFee; + WALLET_FEE_POOL += _fees - holderFee; } /// @inheritdoc IPushCoreV3 @@ -547,9 +540,7 @@ contract PushCoreV3 is celebUserFunds[requestReceiver] += requestReceiverAmount; - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * poolFeeAmount) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += poolFeeAmount - holderFee; + distributeFees(poolFeeAmount); emit IncentivizedChatReqReceived( requestSender, BaseHelper.addressToBytes32(requestReceiver), requestReceiverAmount, poolFeeAmount, block.timestamp @@ -657,9 +648,7 @@ contract PushCoreV3 is _handleArbitraryRequest(sender, feeId, feePercentage, BaseHelper.bytes32ToAddress(amountRecipient), amount); } else if (functionType == CrossChainRequestTypes.CrossChainFunction.AdminRequest_AddPoolFee) { // Admin Request - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * amount) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += amount - holderFee; + distributeFees(amount); } else { revert("Invalid Function Type"); } @@ -708,9 +697,7 @@ contract PushCoreV3 is uint256 feeAmount = BaseHelper.calcPercentage(amount, feePercentage); // Update states based on Fee Percentage calculation - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * feeAmount) / 100; - HOLDER_FEE_POOL += holderFee; - WALLET_FEE_POOL += feeAmount - holderFee; + distributeFees(feeAmount); arbitraryReqFees[amountRecipient] += amount - feeAmount; From e133c7f37d6609f939935ce35364b12cfdd997ed Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Thu, 24 Oct 2024 14:46:47 +0530 Subject: [PATCH 38/49] Decimal Percenatage for Splitting --- contracts/PushCore/PushCoreStorageV1_5.sol | 2 +- contracts/PushCore/PushCoreStorageV2.sol | 3 +- contracts/PushCore/PushCoreV3.sol | 4 +- contracts/PushStaking/PushStaking.sol | 6 +- contracts/PushStaking/PushStakingStorage.sol | 2 +- contracts/libraries/DataTypes.sol | 5 +- .../ArbitraryRequest/ArbitraryRequest.t.sol | 4 +- test/CCR/CCRutils/Helper.sol | 3 +- .../CreateChannelSettingsCCR.t.sol | 4 +- .../CreateChatCCR/CreateChatCCR.t.sol | 4 +- .../UpdateChannelMetaCCR.t.sol | 4 +- .../AddWalletShare/AddWalletShare.t.sol | 24 +++---- .../ClaimRewards/ClaimRewards.t.sol | 26 ++++---- .../DecreaseWalletShare.t.sol | 24 +++---- .../RemoveWalletShare/RemoveWalletShare.t.sol | 6 +- .../unit_tests/WalletShare/WalletShare.t.sol | 64 +++++++++---------- test/utils/Constants.sol | 4 +- 17 files changed, 94 insertions(+), 95 deletions(-) diff --git a/contracts/PushCore/PushCoreStorageV1_5.sol b/contracts/PushCore/PushCoreStorageV1_5.sol index e199c87a..a49ca051 100644 --- a/contracts/PushCore/PushCoreStorageV1_5.sol +++ b/contracts/PushCore/PushCoreStorageV1_5.sol @@ -35,7 +35,7 @@ contract PushCoreStorageV1_5 { /// @notice Helper Variables for FSRatio Calculation | GROUPS = CHANNELS -> NOT IN USE uint256 public HOLDER_FEE_POOL;//TODO Re-Using groupNormalizedWeight slot uint256 public WALLET_FEE_POOL; //TODO Re-Using groupHistoricalZ slot - uint256 public SPLIT_PERCENTAGE_FOR_HOLDER; //TODO Re-Using groupLastUpdate slot + uint256 public groupLastUpdate; uint256 public groupFairShareCount; /// @notice Necessary variables for Keeping track of Funds and Fees diff --git a/contracts/PushCore/PushCoreStorageV2.sol b/contracts/PushCore/PushCoreStorageV2.sol index 1ca718e5..27e84828 100644 --- a/contracts/PushCore/PushCoreStorageV2.sol +++ b/contracts/PushCore/PushCoreStorageV2.sol @@ -1,6 +1,6 @@ pragma solidity ^0.8.20; -import { CoreTypes, StakingTypes } from "../libraries/DataTypes.sol"; +import { CoreTypes, StakingTypes, GenericTypes } from "../libraries/DataTypes.sol"; contract PushCoreStorageV2 { /* *** V2 State variables *** */ @@ -47,4 +47,5 @@ contract PushCoreStorageV2 { mapping(bytes32 => CoreTypes.Channel) public channelInfo; mapping(bytes32 => uint256) public channelUpdateCounter; + GenericTypes.Percentage public SPLIT_PERCENTAGE_FOR_HOLDER; } diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index ae4eb458..1c08ec9c 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -498,13 +498,13 @@ contract PushCoreV3 is distributeFees(_rewardAmount); } - function splitFeePool(uint256 holderSplit) external { + function splitFeePool(GenericTypes.Percentage memory holderSplit) external { onlyGovernance(); SPLIT_PERCENTAGE_FOR_HOLDER = holderSplit; } function distributeFees(uint256 _fees) internal{ - uint holderFee = (SPLIT_PERCENTAGE_FOR_HOLDER * _fees) / 100; + uint holderFee = BaseHelper.calcPercentage(_fees, SPLIT_PERCENTAGE_FOR_HOLDER); HOLDER_FEE_POOL += holderFee; WALLET_FEE_POOL += _fees - holderFee; } diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index 0f67b6f2..9a50af85 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -85,7 +85,7 @@ contract PushStaking is Initializable, PushStakingStorage { */ function getSharesAmount( uint256 _totalShares, - StakingTypes.Percentage memory _percentage + GenericTypes.Percentage memory _percentage ) public pure @@ -109,7 +109,7 @@ contract PushStaking is Initializable, PushStakingStorage { * 7. If a wallet has already has a share, then it acts as a "increase share" function. And the percenatge passed * should be greater than the already assigned percentge. */ - function addWalletShare(address _walletAddress, StakingTypes.Percentage memory _percentage) public onlyGovernance { + function addWalletShare(address _walletAddress, GenericTypes.Percentage memory _percentage) public onlyGovernance { if(_walletAddress == address(0)){ revert Errors.InvalidArgument_WrongAddress(_walletAddress); } @@ -150,7 +150,7 @@ contract PushStaking is Initializable, PushStakingStorage { function decreaseWalletShare( address _walletAddress, - StakingTypes.Percentage memory _percentage + GenericTypes.Percentage memory _percentage ) external onlyGovernance diff --git a/contracts/PushStaking/PushStakingStorage.sol b/contracts/PushStaking/PushStakingStorage.sol index 5c5b678e..b5ae1fe2 100644 --- a/contracts/PushStaking/PushStakingStorage.sol +++ b/contracts/PushStaking/PushStakingStorage.sol @@ -1,6 +1,6 @@ pragma solidity ^0.8.20; -import { StakingTypes } from "../libraries/DataTypes.sol"; +import { StakingTypes, GenericTypes } from "../libraries/DataTypes.sol"; contract PushStakingStorage { /** diff --git a/contracts/libraries/DataTypes.sol b/contracts/libraries/DataTypes.sol index 4b981798..ea680ad9 100644 --- a/contracts/libraries/DataTypes.sol +++ b/contracts/libraries/DataTypes.sol @@ -102,10 +102,7 @@ library StakingTypes { ///@notice Weight of staked amount of a user w.r.t total staked in a single epoch mapping(uint256 => uint256) epochToUserStakedWeight; } - struct Percentage { - uint256 percentageNumber; - uint256 decimalPlaces; - } + struct WalletShareInfo { ///@notice Total amount staked by a user at any given time uint256 walletShare; diff --git a/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol b/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol index 505403f7..5453510a 100644 --- a/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol +++ b/test/CCR/ArbitraryRequest/ArbitraryRequest.t.sol @@ -154,8 +154,8 @@ contract ArbitraryRequesttsol is BaseCCRTest { uint256 feeAmount = BaseHelper.calcPercentage(amount, percentage); // Update states based on Fee Percentage calculation - assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + (feeAmount * HOLDER_SPLIT) /100); - assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + (feeAmount * HOLDER_SPLIT) /100); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(feeAmount , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + feeAmount - BaseHelper.calcPercentage(feeAmount , HOLDER_SPLIT)); assertEq(coreProxy.arbitraryReqFees(actor.charlie_channel_owner), arbitraryFees + amount - feeAmount); } diff --git a/test/CCR/CCRutils/Helper.sol b/test/CCR/CCRutils/Helper.sol index 4c7dcde3..3abf2e2b 100644 --- a/test/CCR/CCRutils/Helper.sol +++ b/test/CCR/CCRutils/Helper.sol @@ -12,6 +12,7 @@ import { CCRConfig } from "./CCRConfig.sol"; import { IWormholeTransceiver } from "contracts/interfaces/wormhole/IWormholeTransceiver.sol"; import { Vm } from "forge-std/Vm.sol"; import { EPNS } from "contracts/token/EPNS.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract Helper is BasePushCommTest, CCRConfig { // Set Source and dest chains @@ -100,7 +101,7 @@ contract Helper is BasePushCommTest, CCRConfig { uint256 poolFundAmount = _amountDeposited - poolFeeAmount; //store funds in pool_funds & pool_fees CHANNEL_POOL_FUNDS = coreProxy.CHANNEL_POOL_FUNDS() + poolFundAmount; - uint holderFees = (poolFeeAmount* HOLDER_SPLIT) /100; + uint holderFees = BaseHelper.calcPercentage(poolFeeAmount , HOLDER_SPLIT); HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL() + holderFees ; WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL() + poolFeeAmount - holderFees; } diff --git a/test/CCR/SpecificRequest/CreateChannelSettingsCCR/CreateChannelSettingsCCR.t.sol b/test/CCR/SpecificRequest/CreateChannelSettingsCCR/CreateChannelSettingsCCR.t.sol index c7154d8c..14f59fba 100644 --- a/test/CCR/SpecificRequest/CreateChannelSettingsCCR/CreateChannelSettingsCCR.t.sol +++ b/test/CCR/SpecificRequest/CreateChannelSettingsCCR/CreateChannelSettingsCCR.t.sol @@ -126,8 +126,8 @@ contract CreateChannelSettingsCCR is BaseCCRTest { requestPayload, additionalVaas, sourceAddress, SourceChain.SourceChainId, deliveryHash ); // Update states based on Fee Percentage calculation - assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + (amount * HOLDER_SPLIT) /100); - assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + (amount * HOLDER_SPLIT) /100); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(amount , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + amount - BaseHelper.calcPercentage(amount , HOLDER_SPLIT)); } function test_whenTokensAreTransferred() external { diff --git a/test/CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol b/test/CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol index d89858f9..739fd144 100644 --- a/test/CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol +++ b/test/CCR/SpecificRequest/CreateChatCCR/CreateChatCCR.t.sol @@ -133,8 +133,8 @@ contract CreateChatCCR is BaseCCRTest { receiveWormholeMessage(requestPayload); assertEq(coreProxy.celebUserFunds(actor.charlie_channel_owner), userFundsPre + amount - poolFeeAmount); - assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + (poolFeeAmount * HOLDER_SPLIT) /100); - assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + (poolFeeAmount * HOLDER_SPLIT) /100); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(poolFeeAmount , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + poolFeeAmount - BaseHelper.calcPercentage(poolFeeAmount , HOLDER_SPLIT)); } function test_whenTokensAreTransferred() public { vm.recordLogs(); diff --git a/test/CCR/SpecificRequest/UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol b/test/CCR/SpecificRequest/UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol index a73bb564..ebbe7434 100644 --- a/test/CCR/SpecificRequest/UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol +++ b/test/CCR/SpecificRequest/UpdateChannelMetaCCR/UpdateChannelMetaCCR.t.sol @@ -117,8 +117,8 @@ contract UpdateChannelCCR is BaseCCRTest { uint256 channelUpdateBlock, , ) = coreProxy.channelInfo(toWormholeFormat(actor.bob_channel_owner)); - assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + (amount * HOLDER_SPLIT) /100); - assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + (amount * HOLDER_SPLIT) /100); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(amount , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + amount - BaseHelper.calcPercentage(amount , HOLDER_SPLIT)); assertEq(coreProxy.channelUpdateCounter(toWormholeFormat(actor.bob_channel_owner)), oldCounter + 1); assertEq(channelUpdateBlock, block.number); } diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol index 9c21974e..f1a8f1fe 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/AddWalletShare/AddWalletShare.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; -import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import { GenericTypes } from "contracts/libraries/DataTypes.sol"; import {console2} from "forge-std/console2.sol"; import { Errors } from "contracts/libraries/Errors.sol"; @@ -14,51 +14,51 @@ contract AddWalletShareTest is BaseWalletSharesStaking { function test_Revertwhen_Caller_NotGovernance() public validateShareInvariants { changePrank(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotGovernance.selector)); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); } function test_Revertwhen_InvalidPercentage() public validateShareInvariants { changePrank(actor.admin); - StakingTypes.Percentage memory percentAllocationZero = StakingTypes.Percentage({ percentageNumber: 0, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocationZero = GenericTypes.Percentage({ percentageNumber: 0, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationZero); - StakingTypes.Percentage memory percentAllocationHundred = StakingTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocationHundred = GenericTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 100)); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationHundred); } function test_Revertwhen_WalletAddress_Zero() public validateShareInvariants { changePrank(actor.admin); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, address(0))); pushStaking.addWalletShare(address(0), percentAllocation); } function test_Revertwhen_Increased() public validateShareInvariants { changePrank(actor.admin); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, address(0))); pushStaking.addWalletShare(address(0), percentAllocation); } function test_Revertwhen_NewShares_LE_ToOldShares() public validateShareInvariants { changePrank(actor.admin); - StakingTypes.Percentage memory percentAllocation1 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation1 = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation1); (uint256 bobWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); // revert when new allocation is equal to already allocated shares - StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); uint256 sharesToBeAllocated2 = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES() - bobWalletSharesBefore, percentAllocation2); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_LessThanExpected.selector, bobWalletSharesBefore, sharesToBeAllocated2)); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); // revert when new allocation is less than already allocated shares - StakingTypes.Percentage memory percentAllocation3 = StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation3 = GenericTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); uint256 sharesToBeAllocated3 = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES() - bobWalletSharesBefore, percentAllocation3); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_LessThanExpected.selector, bobWalletSharesBefore, sharesToBeAllocated3)); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation3); @@ -74,7 +74,7 @@ contract AddWalletShareTest is BaseWalletSharesStaking { vm.expectEmit(true, true, false, false); emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); @@ -100,7 +100,7 @@ contract AddWalletShareTest is BaseWalletSharesStaking { vm.expectEmit(true, true, false, false); emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); - StakingTypes.Percentage memory newPercentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory newPercentAllocation = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, newPercentAllocation); (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); @@ -135,7 +135,7 @@ contract AddWalletShareTest is BaseWalletSharesStaking { vm.expectEmit(true, true, false, false); emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); - StakingTypes.Percentage memory newPercentAllocation = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory newPercentAllocation = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, newPercentAllocation); (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter , uint256 bobClaimedBlockAfter) = pushStaking.walletShareInfo(actor.bob_channel_owner); diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol index 96e497d2..b3c58c33 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; -import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import { GenericTypes } from "../../../../../contracts/libraries/DataTypes.sol"; import { console2 } from "forge-std/console2.sol"; import { Errors } from "contracts/libraries/Errors.sol"; @@ -14,8 +14,8 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { function test_whenUser_claimsIn_stakedEpoch() external validateShareInvariants { uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); // gets zero rewards for that epoch - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); addPool(1000); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -59,8 +59,8 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); //SHould succesully Claim the reward - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); addPool(1000); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -137,8 +137,8 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { function test_whenUser_claimsFor_multipleEpochs() external validateShareInvariants { uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); //shares issues in epoch one, reward added in subsequent epoch, wallet claims in 4th epoch - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); addPool(1000); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -196,8 +196,8 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { function test_whenFoundation_ClaimRewards() external validateShareInvariants { uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); addPool(1000); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -238,14 +238,14 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { function test_whenWalletsAndUsers_ClaimRewards() external { addPool(1000); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); - StakingTypes.Percentage memory percentAllocation2 = - StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation2 = + GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.alice_channel_owner, percentAllocation2); diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol index 39f53cf5..199785f2 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; -import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import { GenericTypes } from "../../../../../contracts/libraries/DataTypes.sol"; import {console2} from "forge-std/console2.sol"; import { Errors } from "contracts/libraries/Errors.sol"; @@ -14,14 +14,14 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { function test_Revertwhen_Caller_NotGovernance() public validateShareInvariants { changePrank(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotGovernance.selector)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation); } function test_Revertwhen_WalletAddress_Zero_OrFoundation() public validateShareInvariants { changePrank(actor.admin); - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArgument_WrongAddress.selector, address(0))); pushStaking.decreaseWalletShare(address(0), percentAllocation); @@ -31,27 +31,27 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { function test_Revertwhen_InvalidPercentage() public validateShareInvariants { changePrank(actor.admin); - StakingTypes.Percentage memory percentAllocationZero = StakingTypes.Percentage({ percentageNumber: 0, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocationZero = GenericTypes.Percentage({ percentageNumber: 0, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocationZero); - StakingTypes.Percentage memory percentAllocationHundred = StakingTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocationHundred = GenericTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 100)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocationHundred); } function test_Revertwhen_Percentage_GE_Allocated() public validateShareInvariants { changePrank(actor.admin); - StakingTypes.Percentage memory percentAllocation1 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation1 = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation1); // revert when new allocation is equal to already allocated shares - StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 20)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation2); // revert when new allocation is greater than already allocated shares - StakingTypes.Percentage memory percentAllocation3 = StakingTypes.Percentage({ percentageNumber: 30, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation3 = GenericTypes.Percentage({ percentageNumber: 30, decimalPlaces: 0 }); vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 30)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation3); } @@ -60,7 +60,7 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { addPool(1000); changePrank(actor.admin); // Add wallet shares of bob - StakingTypes.Percentage memory percentAllocationFifty = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocationFifty = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationFifty); pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocationFifty); @@ -70,7 +70,7 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); // Decrease wallet shares of charlie from 50 to 40% - StakingTypes.Percentage memory newPercentAllocationCharlie = StakingTypes.Percentage({ percentageNumber: 40, decimalPlaces: 0 }); + GenericTypes.Percentage memory newPercentAllocationCharlie = GenericTypes.Percentage({ percentageNumber: 40, decimalPlaces: 0 }); uint256 expectedCharlieShares = (newPercentAllocationCharlie.percentageNumber * charlieWalletSharesBefore) / percentAllocationFifty.percentageNumber; emit SharesDecreased(actor.charlie_channel_owner, charlieWalletSharesBefore, expectedCharlieShares); pushStaking.decreaseWalletShare(actor.charlie_channel_owner, newPercentAllocationCharlie); @@ -92,7 +92,7 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { addPool(1000); changePrank(actor.admin); // Add wallet shares of bob - StakingTypes.Percentage memory percentAllocationFifty = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocationFifty = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationFifty); pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocationFifty); @@ -105,7 +105,7 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); // Decrease wallet shares of charlie from 50 to 40% - StakingTypes.Percentage memory newPercentAllocationCharlie = StakingTypes.Percentage({ percentageNumber: 40, decimalPlaces: 0 }); + GenericTypes.Percentage memory newPercentAllocationCharlie = GenericTypes.Percentage({ percentageNumber: 40, decimalPlaces: 0 }); uint256 expectedCharlieShares = (newPercentAllocationCharlie.percentageNumber * charlieWalletSharesBefore) / percentAllocationFifty.percentageNumber; emit SharesDecreased(actor.charlie_channel_owner, charlieWalletSharesBefore, expectedCharlieShares); pushStaking.decreaseWalletShare(actor.charlie_channel_owner, newPercentAllocationCharlie); diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol index 53409c9a..b9161845 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; -import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import { GenericTypes } from "../../../../../contracts/libraries/DataTypes.sol"; import {console2} from "forge-std/console2.sol"; import { Errors } from "contracts/libraries/Errors.sol"; @@ -31,7 +31,7 @@ contract RemoveWalletShareTest is BaseWalletSharesStaking { addPool(1000); changePrank(actor.admin); // Add wallet shares of bob - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); @@ -68,7 +68,7 @@ contract RemoveWalletShareTest is BaseWalletSharesStaking { addPool(1000); // doubt changePrank(actor.admin); // Add wallet shares of bob - StakingTypes.Percentage memory percentAllocation = StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); roll(epochDuration * 2); diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol index bf6e6c14..7eccf114 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; -import { StakingTypes } from "../../../../../contracts/libraries/DataTypes.sol"; +import { GenericTypes } from "../../../../../contracts/libraries/DataTypes.sol"; import {console2} from "forge-std/console2.sol"; contract WalletShareTest is BaseWalletSharesStaking { @@ -44,8 +44,8 @@ contract WalletShareTest is BaseWalletSharesStaking { function test_WalletGets_20PercentAllocation() public { (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -185,8 +185,8 @@ contract WalletShareTest is BaseWalletSharesStaking { test_WalletGets_20PercentAllocation(); (uint256 aliceWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.alice_channel_owner, percentAllocation); @@ -240,8 +240,8 @@ contract WalletShareTest is BaseWalletSharesStaking { test_RemovalWalletM2(); (uint256 charlieWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation); @@ -258,8 +258,8 @@ contract WalletShareTest is BaseWalletSharesStaking { function test_WalletGets_NegligiblePercentAllocation() public { (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 3 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 1, decimalPlaces: 3 }); uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation); @@ -278,8 +278,8 @@ contract WalletShareTest is BaseWalletSharesStaking { function test_WalletGets_NegligiblePercentAllocation2() public { (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 1, decimalPlaces: 4 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 1, decimalPlaces: 4 }); uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation); @@ -303,8 +303,8 @@ contract WalletShareTest is BaseWalletSharesStaking { pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -331,8 +331,8 @@ contract WalletShareTest is BaseWalletSharesStaking { (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); changePrank(actor.admin); vm.expectRevert(); @@ -358,8 +358,8 @@ contract WalletShareTest is BaseWalletSharesStaking { pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); uint256 expectedAllocationShares = pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation); @@ -379,7 +379,7 @@ contract WalletShareTest is BaseWalletSharesStaking { } // FUZZ TESTS - function testFuzz_AddShares(address _walletAddress, StakingTypes.Percentage memory _percentage) public { + function testFuzz_AddShares(address _walletAddress, GenericTypes.Percentage memory _percentage) public { _percentage.percentageNumber = bound(_percentage.percentageNumber, 1, 100); _percentage.decimalPlaces = bound(_percentage.decimalPlaces, 1, 10); vm.assume(_walletAddress != actor.admin && _walletAddress != address(0)); @@ -389,7 +389,7 @@ contract WalletShareTest is BaseWalletSharesStaking { pushStaking.addWalletShare(_walletAddress, _percentage); } - function testFuzz_RemoveShares(address _walletAddress, StakingTypes.Percentage memory _percentage) public { + function testFuzz_RemoveShares(address _walletAddress, GenericTypes.Percentage memory _percentage) public { _percentage.percentageNumber = bound(_percentage.percentageNumber, 0, 100); vm.assume(_percentage.decimalPlaces < 10); // percentage must be less than 100 @@ -406,8 +406,8 @@ contract WalletShareTest is BaseWalletSharesStaking { function test_whenWallet_SharesIncrease_InSameEpoch() public { (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -425,8 +425,8 @@ contract WalletShareTest is BaseWalletSharesStaking { uint256 percentage = (bobWalletSharesAfter * 100) / actualTotalShares; assertEq(percentage, percentAllocation.percentageNumber); - StakingTypes.Percentage memory percentAllocation2 = - StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation2 = + GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); @@ -445,8 +445,8 @@ contract WalletShareTest is BaseWalletSharesStaking { function test_whenWallet_SharesIncrease_InDifferentEpoch() public { (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); - StakingTypes.Percentage memory percentAllocation = - StakingTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation = + GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); @@ -466,8 +466,8 @@ contract WalletShareTest is BaseWalletSharesStaking { roll(epochDuration + 1); - StakingTypes.Percentage memory percentAllocation2 = - StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation2 = + GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); @@ -490,7 +490,7 @@ contract WalletShareTest is BaseWalletSharesStaking { changePrank(actor.bob_channel_owner); roll(epochDuration + 1); addPool(1000); - StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); changePrank(actor.admin); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); @@ -504,12 +504,12 @@ contract WalletShareTest is BaseWalletSharesStaking { function test_foundation() external { addPool(1000); - StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation2); roll(epochDuration + 1); addPool(1000); pushStaking.setFoundationAddress(actor.bob_channel_owner); - // StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + // GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); // pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation2); roll(epochDuration * 3); changePrank(actor.admin); @@ -529,7 +529,7 @@ contract WalletShareTest is BaseWalletSharesStaking { assertEq(foundationClaimedBlock, genesisEpoch); roll(epochDuration + 1); changePrank(actor.admin); - StakingTypes.Percentage memory percentAllocation2 = StakingTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); pushStaking.setFoundationAddress(actor.bob_channel_owner); addPool(1000); @@ -556,7 +556,7 @@ contract WalletShareTest is BaseWalletSharesStaking { // function test_MaxDecimalAmount () public { // // fixed at most 10 decimal places // // percentage = 10.1111111111 - // StakingTypes.Percentage memory _percentage = StakingTypes.Percentage({ + // GenericTypes.Percentage memory _percentage = GenericTypes.Percentage({ // percentageNumber: 101111111111, // decimalPlaces: 10 // }); diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index cc8512e4..d8a8b549 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.20; - +import { GenericTypes } from "contracts/libraries/DataTypes.sol"; abstract contract Constants { // General Constant Values of All Contracts uint256 internal constant DEC_27_2021 = 1_640_605_391; @@ -25,7 +25,7 @@ abstract contract Constants { uint256 FEE_AMOUNT = 10 ether; uint256 MIN_POOL_CONTRIBUTION = 1 ether; uint256 ADJUST_FOR_FLOAT = 10 ** 7; - uint256 HOLDER_SPLIT = 50; + GenericTypes.Percentage HOLDER_SPLIT = GenericTypes.Percentage({ percentageNumber: 55, decimalPlaces: 1 }); uint256 WALLET_TOTAL_SHARES = 100_000 * 1e18; //Comm Constants used for meta transaction From 9556398c99ee540cd33b0d5c1ff47ad75c541a82 Mon Sep 17 00:00:00 2001 From: Zaryab Date: Tue, 29 Oct 2024 22:49:00 +0400 Subject: [PATCH 39/49] added getTotalFeePool() --- contracts/PushCore/PushCoreV3.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index 1c08ec9c..6a9aa77b 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -509,6 +509,10 @@ contract PushCoreV3 is WALLET_FEE_POOL += _fees - holderFee; } + function getTotalFeePool() external view returns (uint256) { + return HOLDER_FEE_POOL + WALLET_FEE_POOL; + } + /// @inheritdoc IPushCoreV3 function createIncentivizedChatRequest(address requestReceiver, uint256 amount) external { if (amount < FEE_AMOUNT) { From aff8290cfc680eaf37a06cb626c80a82cac72757 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 30 Oct 2024 00:55:55 +0530 Subject: [PATCH 40/49] Remove instances of PROTOCOL_POOL_FEES --- test/BaseTest.t.sol | 14 ++++++++++++++ test/CCR/CCRutils/Helper.sol | 14 +------------- .../ChannelStateMigration.t.sol | 14 +++++++++++++- .../ChannelUpdateCounterMigration.t.sol | 12 +++++++++++- .../createChannelWithPUSH.t.sol | 18 +++++++++++------- .../blockChannel/blockChannel.t.sol | 9 +++++---- .../deactivateChannel/deactivateChannel.t.sol | 9 +++++---- .../reactivateChannel/reactivateChannel.t.sol | 8 +++++--- .../reactivateChannel/reactivateChannel.tree | 12 ++++++------ .../ChannelUpdation/updateChannelMeta.t.sol | 8 +++++--- .../createIncentivizedChat.t.sol | 6 ++++-- .../HandleArbitraryReq.t.sol | 6 ++++-- .../TimeBoundChannel/timeBoundChannel.t.sol | 8 ++++---- 13 files changed, 88 insertions(+), 50 deletions(-) diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index a7a4fa63..f259f774 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -226,4 +226,18 @@ abstract contract BaseTest is Test, Constants, Events { function toWormholeFormat(address addr) internal pure returns (bytes32) { return bytes32(uint256(uint160(addr))); } + + function getPoolFundsAndFees(uint256 _amountDeposited) + internal + view + returns (uint256 CHANNEL_POOL_FUNDS, uint256 HOLDER_FEE_POOL,uint256 WALLET_FEE_POOL ) + { + uint256 poolFeeAmount = coreProxy.FEE_AMOUNT(); + uint256 poolFundAmount = _amountDeposited - poolFeeAmount; + //store funds in pool_funds & pool_fees + CHANNEL_POOL_FUNDS = coreProxy.CHANNEL_POOL_FUNDS() + poolFundAmount; + uint holderFees = BaseHelper.calcPercentage(poolFeeAmount , HOLDER_SPLIT); + HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL() + holderFees ; + WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL() + poolFeeAmount - holderFees; + } } diff --git a/test/CCR/CCRutils/Helper.sol b/test/CCR/CCRutils/Helper.sol index 3abf2e2b..5ac4030b 100644 --- a/test/CCR/CCRutils/Helper.sol +++ b/test/CCR/CCRutils/Helper.sol @@ -92,19 +92,7 @@ contract Helper is BasePushCommTest, CCRConfig { changePrank(actor.admin); } - function getPoolFundsAndFees(uint256 _amountDeposited) - internal - view - returns (uint256 CHANNEL_POOL_FUNDS, uint256 HOLDER_FEE_POOL,uint256 WALLET_FEE_POOL ) - { - uint256 poolFeeAmount = coreProxy.FEE_AMOUNT(); - uint256 poolFundAmount = _amountDeposited - poolFeeAmount; - //store funds in pool_funds & pool_fees - CHANNEL_POOL_FUNDS = coreProxy.CHANNEL_POOL_FUNDS() + poolFundAmount; - uint holderFees = BaseHelper.calcPercentage(poolFeeAmount , HOLDER_SPLIT); - HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL() + holderFees ; - WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL() + poolFeeAmount - holderFees; - } + function getSpecificPayload( CrossChainRequestTypes.CrossChainFunction typeOfReq, diff --git a/test/PushCore/unit_tests/AddressToBytesMigration/ChannelStateMigration.t.sol b/test/PushCore/unit_tests/AddressToBytesMigration/ChannelStateMigration.t.sol index ec8dc348..be21544f 100644 --- a/test/PushCore/unit_tests/AddressToBytesMigration/ChannelStateMigration.t.sol +++ b/test/PushCore/unit_tests/AddressToBytesMigration/ChannelStateMigration.t.sol @@ -7,6 +7,7 @@ import { PushCoreMock } from "contracts/mocks/PushCoreMock.sol"; import { console } from "forge-std/console.sol"; import { PushCoreV3 } from "contracts/PushCore/PushCoreV3.sol"; import { EPNSCoreProxy, ITransparentUpgradeableProxy } from "contracts/PushCore/EPNSCoreProxy.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract StateMigration_Test is BasePushCoreTest { PushCoreMock public coreV2; @@ -30,6 +31,12 @@ contract StateMigration_Test is BasePushCoreTest { 0 ); coreV2 = PushCoreMock(address(epnsCoreProxyV2)); + + changePrank(actor.admin); + coreV2.setPushCommunicatorAddress(address(commEthProxy)); + coreV2.updateStakingAddress(address(pushStaking)); + coreV2.splitFeePool(HOLDER_SPLIT); + changePrank(tokenDistributor); pushToken.transfer(address(coreV2), 1 ether); @@ -44,6 +51,9 @@ contract StateMigration_Test is BasePushCoreTest { } function test_ProtocolPoolFees_IsCorrect_ForMultipleChannelsCreation() public { + uint256 HOLDER_FEE_POOL = coreV2.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreV2.WALLET_FEE_POOL(); + changePrank(actor.bob_channel_owner); coreV2.createChannelWithPUSH( CoreTypes.ChannelType.InterestBearingOpen, _testChannelIdentity, ADD_CHANNEL_MIN_FEES, 0 @@ -56,7 +66,9 @@ contract StateMigration_Test is BasePushCoreTest { uint256 expectedProtocolPoolFees = FEE_AMOUNT * 2; uint256 expectedChannelPoolFunds = (ADD_CHANNEL_MIN_FEES + (ADD_CHANNEL_MIN_FEES * 2)) - expectedProtocolPoolFees; - assertEq(expectedProtocolPoolFees, coreV2.PROTOCOL_POOL_FEES()); + + assertEq(coreV2.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(expectedProtocolPoolFees , HOLDER_SPLIT)); + assertEq(coreV2.WALLET_FEE_POOL(), WALLET_FEE_POOL + expectedProtocolPoolFees - BaseHelper.calcPercentage(expectedProtocolPoolFees , HOLDER_SPLIT)); assertEq(expectedChannelPoolFunds, coreV2.CHANNEL_POOL_FUNDS()); } diff --git a/test/PushCore/unit_tests/AddressToBytesMigration/ChannelUpdateCounterMigration.t.sol b/test/PushCore/unit_tests/AddressToBytesMigration/ChannelUpdateCounterMigration.t.sol index abecdad4..adc2359a 100644 --- a/test/PushCore/unit_tests/AddressToBytesMigration/ChannelUpdateCounterMigration.t.sol +++ b/test/PushCore/unit_tests/AddressToBytesMigration/ChannelUpdateCounterMigration.t.sol @@ -6,6 +6,7 @@ import { EPNSCoreProxy, ITransparentUpgradeableProxy } from "contracts/PushCore/ import { PushCoreMock } from "contracts/mocks/PushCoreMock.sol"; import { PushCoreV3 } from "contracts/PushCore/PushCoreV3.sol"; import { EPNSCoreProxy, ITransparentUpgradeableProxy } from "contracts/PushCore/EPNSCoreProxy.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract UpdationMigration_Test is BasePushCoreTest { PushCoreMock public coreV2; @@ -29,6 +30,12 @@ contract UpdationMigration_Test is BasePushCoreTest { 0 ); coreV2 = PushCoreMock(address(epnsCoreProxyV2)); + + changePrank(actor.admin); + coreV2.setPushCommunicatorAddress(address(commEthProxy)); + coreV2.updateStakingAddress(address(pushStaking)); + coreV2.splitFeePool(HOLDER_SPLIT); + changePrank(tokenDistributor); pushToken.transfer(address(coreV2), 1 ether); @@ -43,6 +50,8 @@ contract UpdationMigration_Test is BasePushCoreTest { } function test_ProtocolPoolFees_IsCorrect_ForMultipleTimesUpdation() public { + uint256 HOLDER_FEE_POOL = coreV2.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreV2.WALLET_FEE_POOL(); changePrank(actor.bob_channel_owner); coreV2.createChannelWithPUSH( CoreTypes.ChannelType.InterestBearingOpen, _testChannelIdentity, ADD_CHANNEL_MIN_FEES, 0 @@ -54,7 +63,8 @@ contract UpdationMigration_Test is BasePushCoreTest { uint256 expectedProtocolPoolFees = FEE_AMOUNT + ADD_CHANNEL_MIN_FEES * 3; uint256 expectedChannelPoolFunds = ADD_CHANNEL_MIN_FEES - FEE_AMOUNT; - assertEq(expectedProtocolPoolFees, coreV2.PROTOCOL_POOL_FEES()); + assertEq(coreV2.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(expectedProtocolPoolFees , HOLDER_SPLIT)); + assertEq(coreV2.WALLET_FEE_POOL(), WALLET_FEE_POOL + expectedProtocolPoolFees - BaseHelper.calcPercentage(expectedProtocolPoolFees , HOLDER_SPLIT)); assertEq(expectedChannelPoolFunds, coreV2.CHANNEL_POOL_FUNDS()); } diff --git a/test/PushCore/unit_tests/ChannelCreationPush/createChannelWithPUSH.t.sol b/test/PushCore/unit_tests/ChannelCreationPush/createChannelWithPUSH.t.sol index d72806d6..04700191 100644 --- a/test/PushCore/unit_tests/ChannelCreationPush/createChannelWithPUSH.t.sol +++ b/test/PushCore/unit_tests/ChannelCreationPush/createChannelWithPUSH.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.20; import { BasePushCoreTest } from "../BasePushCoreTest.t.sol"; import { CoreTypes } from "contracts/libraries/DataTypes.sol"; import { Errors } from "contracts/libraries/Errors.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract CreateChannelWithPUSH_Test is BasePushCoreTest { function setUp() public virtual override { @@ -77,6 +78,7 @@ contract CreateChannelWithPUSH_Test is BasePushCoreTest { } function test_CreateChannel() public whenNotPaused { + (uint256 CHANNEL_POOL_FUNDS, uint256 HOLDER_FEE_POOL,uint256 WALLET_FEE_POOL) = getPoolFundsAndFees(ADD_CHANNEL_MIN_FEES); vm.startPrank(actor.bob_channel_owner); uint256 channelsCountBefore = coreProxy.channelsCount(); @@ -84,13 +86,11 @@ contract CreateChannelWithPUSH_Test is BasePushCoreTest { CoreTypes.ChannelType.InterestBearingOpen, _testChannelIdentity, ADD_CHANNEL_MIN_FEES, 0 ); - uint256 expectedPoolContribution = ADD_CHANNEL_MIN_FEES - FEE_AMOUNT; uint256 expectedBlockNumber = block.number; uint256 expectedChannelsCount = channelsCountBefore + 1; uint8 expectedChannelState = 1; - uint256 expectedChannelWeight = (expectedPoolContribution * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; + uint256 expectedChannelWeight = (CHANNEL_POOL_FUNDS * ADJUST_FOR_FLOAT) / MIN_POOL_CONTRIBUTION; uint256 expectedChannelExpiryTime = 0; - uint256 expectedProtocolPoolFees = FEE_AMOUNT; ( , @@ -106,20 +106,23 @@ contract CreateChannelWithPUSH_Test is BasePushCoreTest { uint256 actualExpiryTime ) = coreProxy.channelInfo(channelCreators.bob_channel_owner_Bytes32); - assertEq(expectedPoolContribution, coreProxy.CHANNEL_POOL_FUNDS()); + assertEq(CHANNEL_POOL_FUNDS, coreProxy.CHANNEL_POOL_FUNDS()); assertEq(expectedChannelsCount, coreProxy.channelsCount()); assertEq(expectedChannelState, actualChannelState); - assertEq(expectedPoolContribution, actualPoolContribution); + assertEq(CHANNEL_POOL_FUNDS, actualPoolContribution); assertEq(expectedBlockNumber, actualChannelStartBlock); assertEq(expectedBlockNumber, actualChannelUpdateBlock); assertEq(expectedChannelWeight, actualChannelWeight); assertEq(expectedChannelExpiryTime, actualExpiryTime); - assertEq(expectedProtocolPoolFees, coreProxy.PROTOCOL_POOL_FEES()); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL ); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL ); vm.stopPrank(); } function test_ProtocolPoolFeesCorrectForMultipleChannelsCreation() public whenNotPaused { + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); vm.prank(actor.bob_channel_owner); coreProxy.createChannelWithPUSH( CoreTypes.ChannelType.InterestBearingOpen, _testChannelIdentity, ADD_CHANNEL_MIN_FEES, 0 @@ -133,7 +136,8 @@ contract CreateChannelWithPUSH_Test is BasePushCoreTest { uint256 expectedProtocolPoolFees = FEE_AMOUNT * 2; uint256 expectedChannelPoolFunds = (ADD_CHANNEL_MIN_FEES + (ADD_CHANNEL_MIN_FEES * 2)) - expectedProtocolPoolFees; - assertEq(expectedProtocolPoolFees, coreProxy.PROTOCOL_POOL_FEES()); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(expectedProtocolPoolFees , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + expectedProtocolPoolFees - BaseHelper.calcPercentage(expectedProtocolPoolFees , HOLDER_SPLIT)); assertEq(expectedChannelPoolFunds, coreProxy.CHANNEL_POOL_FUNDS()); } diff --git a/test/PushCore/unit_tests/ChannelStateCycle/blockChannel/blockChannel.t.sol b/test/PushCore/unit_tests/ChannelStateCycle/blockChannel/blockChannel.t.sol index 65a8397d..ff214c71 100644 --- a/test/PushCore/unit_tests/ChannelStateCycle/blockChannel/blockChannel.t.sol +++ b/test/PushCore/unit_tests/ChannelStateCycle/blockChannel/blockChannel.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.20; import { BasePushCoreTest } from "../../BasePushCoreTest.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract BlockChannel_Test is BasePushCoreTest { bytes32 bobBytes; @@ -96,19 +97,19 @@ contract BlockChannel_Test is BasePushCoreTest { function test_FundsVariablesUpdation() public whenNotPaused whenCallerIsAdmin { uint256 poolContributionBeforeBlocked = _getChannelPoolContribution(actor.bob_channel_owner); - uint256 poolFeesBeforeBlocked = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); uint256 poolFundsBeforeBlocked = coreProxy.CHANNEL_POOL_FUNDS(); vm.prank(actor.admin); coreProxy.blockChannel(bobBytes); uint256 actualChannelFundsAfterBlocked = coreProxy.CHANNEL_POOL_FUNDS(); - uint256 actualPoolFeesAfterBlocked = coreProxy.PROTOCOL_POOL_FEES(); uint256 expectedPoolContributionAfterBlocked = poolContributionBeforeBlocked - MIN_POOL_CONTRIBUTION; uint256 expectedChannelFundsAfterBlocked = poolFundsBeforeBlocked - expectedPoolContributionAfterBlocked; - uint256 expectedPoolFeesAfterBlocked = poolFeesBeforeBlocked + expectedPoolContributionAfterBlocked; + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(expectedPoolContributionAfterBlocked , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + expectedPoolContributionAfterBlocked - BaseHelper.calcPercentage(expectedPoolContributionAfterBlocked , HOLDER_SPLIT)); assertEq(actualChannelFundsAfterBlocked, expectedChannelFundsAfterBlocked); - assertEq(actualPoolFeesAfterBlocked, expectedPoolFeesAfterBlocked); } } diff --git a/test/PushCore/unit_tests/ChannelStateCycle/deactivateChannel/deactivateChannel.t.sol b/test/PushCore/unit_tests/ChannelStateCycle/deactivateChannel/deactivateChannel.t.sol index 9287e552..d355aecd 100644 --- a/test/PushCore/unit_tests/ChannelStateCycle/deactivateChannel/deactivateChannel.t.sol +++ b/test/PushCore/unit_tests/ChannelStateCycle/deactivateChannel/deactivateChannel.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.20; import { BasePushCoreTest } from "../../BasePushCoreTest.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; import { CoreTypes } from "contracts/libraries/DataTypes.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract DeactivateChannel_Test is BasePushCoreTest { function setUp() public virtual override { @@ -91,24 +92,24 @@ contract DeactivateChannel_Test is BasePushCoreTest { function test_FundsVariablesUpdation() public whenNotPaused { vm.startPrank(actor.bob_channel_owner); - uint256 actualPoolFeesBeforeDeactivation = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); uint256 expectedRefundAmount = ADD_CHANNEL_MIN_FEES - FEE_AMOUNT - MIN_POOL_CONTRIBUTION; coreProxy.updateChannelState(0); uint256 actualChannelFundsAfterDeactivation = coreProxy.CHANNEL_POOL_FUNDS(); - uint256 actualPoolFeesAfterDeactivation = coreProxy.PROTOCOL_POOL_FEES(); uint256 actualChannelWeightAfterDeactivation = _getChannelWeight(actor.bob_channel_owner); uint256 actualChannelPoolContributionAfterDeactivation = _getChannelPoolContribution(actor.bob_channel_owner); uint256 expectedChannelFundsAfterDeactivation = ADD_CHANNEL_MIN_FEES - FEE_AMOUNT - expectedRefundAmount; - uint256 expectedPoolFeesAfterDeactivation = actualPoolFeesBeforeDeactivation; uint256 expectedChannelPoolContributionAfterDeactivation = MIN_POOL_CONTRIBUTION; uint256 expectedChannelWeightAfterDeactivation = (MIN_POOL_CONTRIBUTION * ADJUST_FOR_FLOAT) / (MIN_POOL_CONTRIBUTION); assertEq(actualChannelFundsAfterDeactivation, expectedChannelFundsAfterDeactivation); - assertEq(actualPoolFeesAfterDeactivation, expectedPoolFeesAfterDeactivation); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL); assertEq(actualChannelWeightAfterDeactivation, expectedChannelWeightAfterDeactivation); assertEq(actualChannelPoolContributionAfterDeactivation, expectedChannelPoolContributionAfterDeactivation); diff --git a/test/PushCore/unit_tests/ChannelStateCycle/reactivateChannel/reactivateChannel.t.sol b/test/PushCore/unit_tests/ChannelStateCycle/reactivateChannel/reactivateChannel.t.sol index bc475bbf..2be60390 100644 --- a/test/PushCore/unit_tests/ChannelStateCycle/reactivateChannel/reactivateChannel.t.sol +++ b/test/PushCore/unit_tests/ChannelStateCycle/reactivateChannel/reactivateChannel.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.20; import { BasePushCoreTest } from "../../BasePushCoreTest.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract ReactivateChannel_Test is BasePushCoreTest { function setUp() public virtual override { @@ -96,25 +97,26 @@ contract ReactivateChannel_Test is BasePushCoreTest { function test_FundsVariablesUpdation_PostReactivation() public whenNotPaused { approveTokens(actor.bob_channel_owner, address(coreProxy), ADD_CHANNEL_MIN_FEES); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); vm.startPrank(actor.bob_channel_owner); coreProxy.updateChannelState(0); coreProxy.updateChannelState(ADD_CHANNEL_MIN_FEES); uint256 actualChannelFundsAfterReactivation = coreProxy.CHANNEL_POOL_FUNDS(); - uint256 actualPoolFeesAfterReactivation = coreProxy.PROTOCOL_POOL_FEES(); uint256 actualChannelWeightAfterReactivation = _getChannelWeight(actor.bob_channel_owner); uint256 actualChannelPoolContributionAfterReactivation = _getChannelPoolContribution(actor.bob_channel_owner); uint256 expectedChannelFundsAfterReactivation = ADD_CHANNEL_MIN_FEES - FEE_AMOUNT + MIN_POOL_CONTRIBUTION; - uint256 expectedPoolFeesAfterReactivation = FEE_AMOUNT * 2; uint256 expectedChannelPoolContributionAfterReactivation = MIN_POOL_CONTRIBUTION + ADD_CHANNEL_MIN_FEES - FEE_AMOUNT; uint256 expectedChannelWeightAfterReactivation = (expectedChannelPoolContributionAfterReactivation * ADJUST_FOR_FLOAT) / (MIN_POOL_CONTRIBUTION); assertEq(actualChannelFundsAfterReactivation, expectedChannelFundsAfterReactivation); - assertEq(actualPoolFeesAfterReactivation, expectedPoolFeesAfterReactivation); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(FEE_AMOUNT , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + FEE_AMOUNT - BaseHelper.calcPercentage(FEE_AMOUNT , HOLDER_SPLIT)); assertEq(actualChannelWeightAfterReactivation, expectedChannelWeightAfterReactivation); assertEq(actualChannelPoolContributionAfterReactivation, expectedChannelPoolContributionAfterReactivation); diff --git a/test/PushCore/unit_tests/ChannelStateCycle/reactivateChannel/reactivateChannel.tree b/test/PushCore/unit_tests/ChannelStateCycle/reactivateChannel/reactivateChannel.tree index 71cbdf28..d0ce4635 100644 --- a/test/PushCore/unit_tests/ChannelStateCycle/reactivateChannel/reactivateChannel.tree +++ b/test/PushCore/unit_tests/ChannelStateCycle/reactivateChannel/reactivateChannel.tree @@ -6,12 +6,12 @@ updateChannelState.t.sol ├── when caller's chanel is INACTIVE or BLOCKED │ └── it REVERT - Core_InvalidChannel() └── when caller's channel is in DEACTIVATED STATE - └── Enter the REACTIVATION Phase + └── it Enter the REACTIVATION Phase ├── when token _amount is less than ADD_CHANNEL_MIN_FEES - │ └── REVERT - InvalidArg_LessThanExpected() + │ └── it REVERT - InvalidArg_LessThanExpected() └── when token _amount is accurate - ├── Transfer tokens from Caller to Core Contract - ├── Calculate and Update CHANNEL_POOL_FUNDS and PROTOCOL_POOL_FEES - ├── Update Channe's New Weight, Pool Contribution and Channe's State to 1 (ACTIVE STATE) - └── Emit ChannelStateUpdate(caller, 0, _amount) + ├── it Transfer tokens from Caller to Core Contract + ├──it Calculate and Update CHANNEL_POOL_FUNDS and PROTOCOL_POOL_FEES + ├──it Update Channe's New Weight, Pool Contribution and Channe's State to 1 (ACTIVE STATE) + └── it Emit ChannelStateUpdate(caller, 0, _amount) diff --git a/test/PushCore/unit_tests/ChannelUpdation/updateChannelMeta.t.sol b/test/PushCore/unit_tests/ChannelUpdation/updateChannelMeta.t.sol index 5fcc6d88..0392a31b 100644 --- a/test/PushCore/unit_tests/ChannelUpdation/updateChannelMeta.t.sol +++ b/test/PushCore/unit_tests/ChannelUpdation/updateChannelMeta.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.20; import { BasePushCoreTest } from "../BasePushCoreTest.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract UpdateChannelMeta_Test is BasePushCoreTest { function setUp() public virtual override { @@ -120,16 +121,17 @@ contract UpdateChannelMeta_Test is BasePushCoreTest { _createChannel(actor.bob_channel_owner); uint256 _amountBeingTransferred = ADD_CHANNEL_MIN_FEES; - uint256 poolFeesBeforeUpdate = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); uint256 channelPoolFundsBeforeUpdate = coreProxy.CHANNEL_POOL_FUNDS(); vm.prank(actor.bob_channel_owner); coreProxy.updateChannelMeta( _testChannelUpdatedIdentity, _amountBeingTransferred); - uint256 expectedProtocolPoolFees = poolFeesBeforeUpdate + _amountBeingTransferred; uint256 expectedChannelPoolFunds = channelPoolFundsBeforeUpdate; - assertEq(coreProxy.PROTOCOL_POOL_FEES(), expectedProtocolPoolFees); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(_amountBeingTransferred , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + _amountBeingTransferred - BaseHelper.calcPercentage(_amountBeingTransferred , HOLDER_SPLIT)); assertEq(coreProxy.CHANNEL_POOL_FUNDS(), expectedChannelPoolFunds); } diff --git a/test/PushCore/unit_tests/CreateIncentivizedChat/createIncentivizedChat.t.sol b/test/PushCore/unit_tests/CreateIncentivizedChat/createIncentivizedChat.t.sol index 76e16288..5d12788b 100644 --- a/test/PushCore/unit_tests/CreateIncentivizedChat/createIncentivizedChat.t.sol +++ b/test/PushCore/unit_tests/CreateIncentivizedChat/createIncentivizedChat.t.sol @@ -36,7 +36,8 @@ contract test_createIncentivizedChat is BasePushCoreTest { // it should update storage and emit event uint256 previousAmount = coreProxy.celebUserFunds(actor.charlie_channel_owner); - uint256 PROTOCOL_POOL_FEES = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); changePrank(actor.bob_channel_owner); @@ -50,7 +51,8 @@ contract test_createIncentivizedChat is BasePushCoreTest { assertEq(coreBalanceBefore + 100e18, pushToken.balanceOf(address(coreProxy))); assertEq(previousAmount + 100e18 - FEE_AMOUNT, coreProxy.celebUserFunds(actor.charlie_channel_owner)); - assertEq(PROTOCOL_POOL_FEES + FEE_AMOUNT, coreProxy.PROTOCOL_POOL_FEES()); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(FEE_AMOUNT , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + FEE_AMOUNT - BaseHelper.calcPercentage(FEE_AMOUNT , HOLDER_SPLIT)); } modifier whenCelebTriesToClaimTheTokens() { diff --git a/test/PushCore/unit_tests/HandleArbitraryRequest/HandleArbitraryReq.t.sol b/test/PushCore/unit_tests/HandleArbitraryRequest/HandleArbitraryReq.t.sol index e08fca1c..1a4bdeb2 100644 --- a/test/PushCore/unit_tests/HandleArbitraryRequest/HandleArbitraryReq.t.sol +++ b/test/PushCore/unit_tests/HandleArbitraryRequest/HandleArbitraryReq.t.sol @@ -25,7 +25,8 @@ contract HandleArbitraryReq is BasePushCoreTest { function test_WhenTheySendAmount_GreaterThanZero() public whenUserCreatesAnArbitraryRequest { // it should execute and update storage - uint256 PROTOCOL_POOL_FEES = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); uint256 arbitraryFees = coreProxy.arbitraryReqFees(actor.charlie_channel_owner); vm.expectEmit(true, true, false, true); @@ -35,7 +36,8 @@ contract HandleArbitraryReq is BasePushCoreTest { uint256 feeAmount = BaseHelper.calcPercentage(amount, feePercentage); // Update states based on Fee Percentage calculation - assertEq(coreProxy.PROTOCOL_POOL_FEES(), PROTOCOL_POOL_FEES + feeAmount); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL + BaseHelper.calcPercentage(feeAmount , HOLDER_SPLIT)); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL + feeAmount - BaseHelper.calcPercentage(feeAmount , HOLDER_SPLIT)); assertEq(coreProxy.arbitraryReqFees(actor.charlie_channel_owner), arbitraryFees + amount - feeAmount); } diff --git a/test/PushCore/unit_tests/TimeBoundChannel/timeBoundChannel.t.sol b/test/PushCore/unit_tests/TimeBoundChannel/timeBoundChannel.t.sol index 6221ce74..b4ab3957 100644 --- a/test/PushCore/unit_tests/TimeBoundChannel/timeBoundChannel.t.sol +++ b/test/PushCore/unit_tests/TimeBoundChannel/timeBoundChannel.t.sol @@ -109,22 +109,22 @@ contract TimeBoundChannel_Test is BasePushCoreTest { uint256 poolContributionBeforeDestroyed = _getChannelPoolContribution(actor.bob_channel_owner); uint256 channelsCountBeforeDestroyed = coreProxy.channelsCount(); uint256 channelPoolFundsBeforeDestroyed = coreProxy.CHANNEL_POOL_FUNDS(); - uint256 protocolPoolFeesBeforeDestroyed = coreProxy.PROTOCOL_POOL_FEES(); + uint256 HOLDER_FEE_POOL = coreProxy.HOLDER_FEE_POOL(); + uint256 WALLET_FEE_POOL = coreProxy.WALLET_FEE_POOL(); vm.prank(actor.bob_channel_owner); coreProxy.updateChannelState(0); uint256 actualChannelsCountAfterDestroyed = coreProxy.channelsCount(); uint256 actualChannelPoolFundsAfterDestroyed = coreProxy.CHANNEL_POOL_FUNDS(); - uint256 actualProtocolPoolFeesAfterDestroyed = coreProxy.PROTOCOL_POOL_FEES(); uint256 expectedChannelsCountAfterDestroyed = channelsCountBeforeDestroyed - 1; uint256 expectedChannelPoolFundsAfterDestroyed = channelPoolFundsBeforeDestroyed - poolContributionBeforeDestroyed; - uint256 expectedProtocolPoolFeesAfterDestroyed = protocolPoolFeesBeforeDestroyed; assertEq(expectedChannelsCountAfterDestroyed, actualChannelsCountAfterDestroyed); assertEq(expectedChannelPoolFundsAfterDestroyed, actualChannelPoolFundsAfterDestroyed); - assertEq(expectedProtocolPoolFeesAfterDestroyed, actualProtocolPoolFeesAfterDestroyed); + assertEq(coreProxy.HOLDER_FEE_POOL(), HOLDER_FEE_POOL); + assertEq(coreProxy.WALLET_FEE_POOL(), WALLET_FEE_POOL); } function test_ShouldRefundAfterDestroyedByOwner() public whenNotPaused { From 616720932dc83e91f50b2547a74cb6bf30b80468 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 30 Oct 2024 15:53:42 +0530 Subject: [PATCH 41/49] added test for split ppol fees --- .../CoreAdminActions/CoreAdminActions.t.sol | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/PushCore/unit_tests/CoreAdminActions/CoreAdminActions.t.sol b/test/PushCore/unit_tests/CoreAdminActions/CoreAdminActions.t.sol index b5efaf10..251c566f 100644 --- a/test/PushCore/unit_tests/CoreAdminActions/CoreAdminActions.t.sol +++ b/test/PushCore/unit_tests/CoreAdminActions/CoreAdminActions.t.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.0; import { BasePushCoreTest } from "../BasePushCoreTest.t.sol"; import { Errors } from "contracts/libraries/Errors.sol"; +import { GenericTypes } from "contracts/libraries/DataTypes.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract CoreAdminActions_Test is BasePushCoreTest { function setUp() public virtual override { @@ -147,4 +149,25 @@ contract CoreAdminActions_Test is BasePushCoreTest { coreProxy.setMinChannelCreationFees(minFeeRequired + 10); assertEq(coreProxy.ADD_CHANNEL_MIN_FEES(), minFeeRequired + 10); } + + function test_whenSplitsFeePool(GenericTypes.Percentage memory _percentage) external { + _percentage.percentageNumber = bound(_percentage.percentageNumber, 1, 100); + _percentage.decimalPlaces = bound(_percentage.decimalPlaces, 0, 4); + changePrank(actor.admin); + coreProxy.splitFeePool(_percentage); + (uint percentNumber, uint decimals) = coreProxy.SPLIT_PERCENTAGE_FOR_HOLDER(); + + assertEq(percentNumber, _percentage.percentageNumber); + assertEq(decimals, _percentage.decimalPlaces); + + uint FeesToAdd = 1000 ether; + + uint expectedHolderFees = coreProxy.HOLDER_FEE_POOL() + BaseHelper.calcPercentage(FeesToAdd, _percentage); + uint expectedWalletFees = coreProxy.WALLET_FEE_POOL() + FeesToAdd - expectedHolderFees; + + coreProxy.addPoolFees(FeesToAdd); + + assertEq(coreProxy.HOLDER_FEE_POOL(),expectedHolderFees ); + assertEq(coreProxy.WALLET_FEE_POOL(),expectedWalletFees ); + } } From 2cbf5cdb87eab83d02fed564f360753177828c7f Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 1 Nov 2024 11:10:50 +0530 Subject: [PATCH 42/49] mark unused staking variables --- contracts/PushCore/PushCoreStorageV2.sol | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/contracts/PushCore/PushCoreStorageV2.sol b/contracts/PushCore/PushCoreStorageV2.sol index 27e84828..c3d63d63 100644 --- a/contracts/PushCore/PushCoreStorageV2.sol +++ b/contracts/PushCore/PushCoreStorageV2.sol @@ -15,6 +15,9 @@ contract PushCoreStorageV2 { /** * Staking V2 state variables * */ + + //UNUSED STATE VARIABLES START HERE + mapping(address => uint256) public usersRewardsClaimed; uint256 public genesisEpoch; // Block number at which Stakig starts @@ -25,11 +28,13 @@ contract PushCoreStorageV2 { uint256 public constant epochDuration = 21 * 7156; // 21 * number of blocks per day(7156) ~ 20 day approx /// @notice Stores all the individual epoch rewards - mapping(uint256 => uint256) public epochRewards; + mapping(uint256 => uint256) public epochRewards; /// @notice Stores User's Fees Details - mapping(address => StakingTypes.UserFeesInfo) public userFeesInfo; + mapping(address => StakingTypes.UserFeesInfo) public userFeesInfo; /// @notice Stores the total staked weight at a specific epoch. - mapping(uint256 => uint256) public epochToTotalStakedWeight; + mapping(uint256 => uint256) public epochToTotalStakedWeight; + + //UNUSED STATE VARIABLES END HERE /** * Handling bridged information * From 84120ef205c7174b59b1dbb252ac9c342bcd02ab Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 1 Nov 2024 12:23:48 +0530 Subject: [PATCH 43/49] improved natspec and storage --- contracts/PushStaking/PushStaking.sol | 64 ++++++++----------- contracts/PushStaking/PushStakingStorage.sol | 31 +++++---- .../ClaimRewards/ClaimRewards.t.sol | 16 ++--- .../unit_tests/WalletShare/WalletShare.t.sol | 12 ++-- 4 files changed, 57 insertions(+), 66 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index 9a50af85..a8e216db 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -9,6 +9,7 @@ import { Errors } from "../libraries/Errors.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import { GenericTypes } from "../libraries/DataTypes.sol"; contract PushStaking is Initializable, PushStakingStorage { using SafeERC20 for IERC20; @@ -16,8 +17,8 @@ contract PushStaking is Initializable, PushStakingStorage { event Staked(address indexed user, uint256 indexed amountStaked); event Unstaked(address indexed user, uint256 indexed amountUnstaked); event RewardsHarvested(address indexed user, uint256 indexed rewardAmount, uint256 fromEpoch, uint256 tillEpoch); - event NewSharesIssued(address indexed Wallet, uint256 indexed Shares); - event SharesRemoved(address indexed Wallet, uint256 indexed Shares); + event NewSharesIssued(address indexed wallet, uint256 indexed shares); + event SharesRemoved(address indexed wallet, uint256 indexed shares); event SharesDecreased(address indexed Wallet, uint256 indexed oldShares, uint256 newShares); function initialize(address _pushChannelAdmin, address _core, address _pushToken) public initializer { @@ -78,11 +79,9 @@ contract PushStaking is Initializable, PushStakingStorage { emit NewSharesIssued(FOUNDATION, sharesToBeAllocated); } - /* - * Fetching shares for a wallet - * 1. Internal helper function - * 2. helps in getting the shares to be assigned for a wallet based on params passed in this function - */ + /** + * @notice Calcultes the share amount based on requested shares and total shares + */ function getSharesAmount( uint256 _totalShares, GenericTypes.Percentage memory _percentage @@ -97,18 +96,13 @@ contract PushStaking is Initializable, PushStakingStorage { sharesToBeAllocated = (_percentage.percentageNumber * _totalShares) / ((100 * (10 ** _percentage.decimalPlaces)) - _percentage.percentageNumber); } + /** + * @notice allows Governance to add/increase wallet shares. + * @notice If a wallet has already has a share, then it acts as a "increase share" function, given that the percenatge passed + * @notice should be greater than the already assigned percentge. + * Emits NewSharesIssued + */ - /* - * Adding Wallet Share to a Wallet - * 1. addWalletShare(address wallet, uint256 percentageOfShares) - * 2. Can be called by governance. - * 3. Uses the formulae to derive the percent of shares to be assigned to a specific wallet - * 4. Updates WALLET_TOTAL_SHARES - * 5. Updates walletShareInfo mapping - * 6. Emits out an event. - * 7. If a wallet has already has a share, then it acts as a "increase share" function. And the percenatge passed - * should be greater than the already assigned percentge. - */ function addWalletShare(address _walletAddress, GenericTypes.Percentage memory _percentage) public onlyGovernance { if(_walletAddress == address(0)){ revert Errors.InvalidArgument_WrongAddress(_walletAddress); @@ -129,13 +123,12 @@ contract PushStaking is Initializable, PushStakingStorage { WALLET_TOTAL_SHARES = TotalShare + sharesToBeAllocated; emit NewSharesIssued(_walletAddress, sharesToBeAllocated); } - /* - * Removing Wallet Share from a Wallet - * 1. removes the shares from a wallet completely - * 2. Can be called by governance. - * 3. Updates WALLET_TOTAL_SHARES - * 4. Emits out an event. - */ + + /** + * @notice allows Governance to remove wallet shares. + * @notice shares to be removed are given back to FOUNDATION + * Emits SharesRemoved + */ function removeWalletShare(address _walletAddress) public onlyGovernance { if(_walletAddress == address(0) || _walletAddress == FOUNDATION) { @@ -161,19 +154,12 @@ contract PushStaking is Initializable, PushStakingStorage { emit SharesDecreased(_walletAddress, sharesToBeRemoved, walletShareInfo[_walletAddress].walletShare); } - /* - *Reward Calculation for a Given Wallet - * 1. calculateWalletRewards(address wallet) - * 2. public helper function - * 3. Helps in calculating rewards for a specific wallet based on - * a. Their Wallet Share - * b. Total Wallet Shares - * c. Total Rewards available in WALLET_TOTAL_SHARES - * 4. Once calculated rewards for a sepcific wallet can be updated in WalletToRewards mapping - * 5. Reward can be calculated for wallets similar they are calculated for Token holders in a specific epoch. - * Reward for a Given Wallet X = ( Wallet Share of X / WALLET_TOTAL_SHARES) * WALLET_FEE_POOL - */ - //TODO logic yet to be finalized + /** + * @notice calculates rewards for share holders, for any given epoch. + * @notice The rewards are calcluated based on -Their Wallet Share in that epoch, Total Wallet Shares in that epoch, + * @notice Total Rewards available in that epoch + * @dev Reward for a Given Wallet X in epoch i = ( Wallet Share of X in epoch i * Rewards in epoch i) / WALLET_TOTAL_SHARES in epoch i + */ function calculateWalletRewards(address _wallet, uint256 _epochId) public view returns (uint256) { return (walletShareInfo[_wallet].epochToWalletShares[_epochId] * epochRewardsForWallets[_epochId]) / epochToTotalShares[_epochId]; @@ -192,7 +178,7 @@ contract PushStaking is Initializable, PushStakingStorage { rewards = rewards + claimableReward; } - usersRewardsClaimed[msg.sender] = usersRewardsClaimed[msg.sender] + rewards; + walletRewardsClaimed[msg.sender] = walletRewardsClaimed[msg.sender] + rewards; // set the lastClaimedBlock to blocknumer at the end of `_tillEpoch` uint256 _epoch_to_block_number = genesisEpoch + _tillEpoch * epochDuration; walletShareInfo[msg.sender].lastClaimedBlock = _epoch_to_block_number; diff --git a/contracts/PushStaking/PushStakingStorage.sol b/contracts/PushStaking/PushStakingStorage.sol index b5ae1fe2..b3188e9f 100644 --- a/contracts/PushStaking/PushStakingStorage.sol +++ b/contracts/PushStaking/PushStakingStorage.sol @@ -1,40 +1,45 @@ pragma solidity ^0.8.20; -import { StakingTypes, GenericTypes } from "../libraries/DataTypes.sol"; +import { StakingTypes } from "../libraries/DataTypes.sol"; contract PushStakingStorage { - /** - * Staking V2 state variables * - */ - mapping(address => uint256) public usersRewardsClaimed; - + //State variables for Stakers uint256 public genesisEpoch; // Block number at which Stakig starts uint256 lastEpochInitialized; // The last EPOCH ID initialized with the respective epoch rewards uint256 lastTotalStakeEpochInitialized; // The last EPOCH ID initialized with the respective total staked weight + uint256 public previouslySetEpochRewards; // Amount of rewards set in last initialized epoch + uint256 public totalStakedAmount; // Total token weight staked in Protocol at any given time + + // State variables for Share holders uint256 walletLastEpochInitialized; // todo new variable uint256 walletLastTotalStakeEpochInitialized;//todo new variable - uint256 public totalStakedAmount; // Total token weight staked in Protocol at any given time - uint256 public previouslySetEpochRewards; // Amount of rewards set in last initialized epoch uint256 public walletPreviouslySetEpochRewards; //todo new variable - uint256 public constant epochDuration = 21 * 7156; // 21 * number of blocks per day(7156) ~ 20 day approx uint256 public WALLET_TOTAL_SHARES; //Total Shares + uint256 public constant epochDuration = 21 * 7156; // 21 * number of blocks per day(7156) ~ 20 day approx address public pushChannelAdmin; address public PUSH_TOKEN_ADDRESS; address public governance; address public core; address public FOUNDATION; + //Mappings for Stakers + ///@notice stores total rewards claimed by a user + mapping(address => uint256) public usersRewardsClaimed; /// @notice Stores all the individual epoch rewards for stakers mapping(uint256 => uint256) public epochRewardsForStakers; - /// @notice Stores all the individual epoch rewards for Wallet share holders - mapping(uint256 => uint256) public epochRewardsForWallets; /// @notice Stores User's Fees Details mapping(address => StakingTypes.UserFeesInfo) public userFeesInfo; - ///@notice stores Wallet share details for a given address - mapping(address => StakingTypes.WalletShareInfo) public walletShareInfo; /// @notice Stores the total staked weight at a specific epoch. mapping(uint256 => uint256) public epochToTotalStakedWeight; + + //Mappings for Share Holders + ///@notice stores total reward claimed by a wallet + mapping(address => uint256) public walletRewardsClaimed; + /// @notice Stores all the individual epoch rewards for Wallet share holders + mapping(uint256 => uint256) public epochRewardsForWallets; + ///@notice stores Wallet share details for a given address + mapping(address => StakingTypes.WalletShareInfo) public walletShareInfo; ///@notice stores the total shares in a specific epoch mapping(uint256 => uint256) public epochToTotalShares; } diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol index b3c58c33..3e7f9428 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/ClaimRewards/ClaimRewards.t.sol @@ -47,7 +47,7 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 claimedRewards = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(expectedRewards, claimedRewards); @@ -94,7 +94,7 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 claimedRewards = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(expectedRewards, claimedRewards); @@ -106,7 +106,7 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { test_WhenUserClaims_in_DifferentEpoch(); uint256 balanceBobBefore = pushToken.balanceOf(actor.bob_channel_owner); - uint256 claimedRewardsBefore = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 claimedRewardsBefore = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobLastClaimedBlock) = pushStaking.walletShareInfo(actor.bob_channel_owner); @@ -129,7 +129,7 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(bobStakedBlockBefore, bobStakedBlockAfter2, "StakedBlock"); assertEq(bobClaimedBlockAfter2, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 claimedRewards = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); assertEq(balanceBobBefore, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(claimedRewardsBefore, claimedRewards); } @@ -184,7 +184,7 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); assertEq(bobClaimedBlockAfter2, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 claimedRewards = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(expectedRewards, claimedRewards); @@ -228,7 +228,7 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(adminStakedBlockBefore, adminStakedBlockAfter, "StakedBlock"); assertEq(adminClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.admin); + uint256 claimedRewards = pushStaking.walletRewardsClaimed(actor.admin); assertEq(balanceAdminBefore + expectedRewards, pushToken.balanceOf(actor.admin), "Balance"); assertEq(expectedRewards, claimedRewards); @@ -282,7 +282,7 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 claimedRewardsBob = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); uint256 expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10) / 100; assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner), "balanceBob"); @@ -292,7 +292,7 @@ contract ClaimRewardsTest is BaseWalletSharesStaking { assertEq(aliceStakedBlockBefore, aliceStakedBlockAfter, "StakedBlock"); assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + uint256 claimedRewardsAlice = pushStaking.walletRewardsClaimed(actor.alice_channel_owner); uint256 expectedRewardsAlice = coreProxy.WALLET_FEE_POOL() * 50 / 100; assertEq( diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol index 7eccf114..bd8d9e4c 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -35,7 +35,7 @@ contract WalletShareTest is BaseWalletSharesStaking { assertEq(adminStakedBlockBefore, adminStakedBlockAfter, "StakedBlock"); assertEq(adminClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.admin); + uint256 claimedRewards = pushStaking.walletRewardsClaimed(actor.admin); uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 80) / 100; assertEq(balanceAdminBefore + expectedRewards, pushToken.balanceOf(actor.admin), "Balance"); assertEq(expectedRewards, claimedRewards); @@ -78,7 +78,7 @@ contract WalletShareTest is BaseWalletSharesStaking { assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewards = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 claimedRewards = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); uint256 expectedRewards = (coreProxy.WALLET_FEE_POOL() * 20) / 100; assertEq(balanceBobBefore + expectedRewards, pushToken.balanceOf(actor.bob_channel_owner), "Balance"); assertEq(expectedRewards, claimedRewards); @@ -109,7 +109,7 @@ contract WalletShareTest is BaseWalletSharesStaking { assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + uint256 claimedRewardsBob = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); uint256 expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10) / 100; assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner), "balanceBob"); @@ -119,7 +119,7 @@ contract WalletShareTest is BaseWalletSharesStaking { assertEq(aliceStakedBlockBefore, aliceStakedBlockAfter, "StakedBlock"); assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + uint256 claimedRewardsAlice = pushStaking.walletRewardsClaimed(actor.alice_channel_owner); uint256 expectedRewardsAlice = coreProxy.WALLET_FEE_POOL() * 50 / 100; assertEq( balanceAliceBefore + expectedRewardsAlice, pushToken.balanceOf(actor.alice_channel_owner), "balanceAlice" @@ -157,7 +157,7 @@ contract WalletShareTest is BaseWalletSharesStaking { // assertEq(bobStakedBlockBefore, bobStakedBlockAfter, "StakedBlock"); // assertEq(bobClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - // uint256 claimedRewardsBob = pushStaking.usersRewardsClaimed(actor.bob_channel_owner); + // uint256 claimedRewardsBob = pushStaking.walletRewardsClaimed(actor.bob_channel_owner); // uint256 expectedRewardsBob = (coreProxy.WALLET_FEE_POOL() * 10) / 100; // assertEq(balanceBobBefore + expectedRewardsBob, pushToken.balanceOf(actor.bob_channel_owner), "balanceBob"); @@ -167,7 +167,7 @@ contract WalletShareTest is BaseWalletSharesStaking { // assertEq(aliceStakedBlockBefore, aliceStakedBlockAfter, "StakedBlock"); // assertEq(aliceClaimedBlockAfter, genesisEpoch + (getCurrentEpoch() - 1) * epochDuration, "ClaimedBlock"); - // uint256 claimedRewardsAlice = pushStaking.usersRewardsClaimed(actor.alice_channel_owner); + // uint256 claimedRewardsAlice = pushStaking.walletRewardsClaimed(actor.alice_channel_owner); // uint256 expectedRewardsAlice = coreProxy.WALLET_FEE_POOL() * 50 / 100; // assertEq( From fb7e16aed1b14f14e553a1250521976a95acba85 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Tue, 5 Nov 2024 12:07:24 +0530 Subject: [PATCH 44/49] fix decrement of shares --- contracts/PushStaking/PushStaking.sol | 46 +++++++--- .../BaseWalletSharesStaking.t.sol | 4 +- .../DecreaseWalletShare.t.sol | 83 ++++++++++++++++--- .../RemoveWalletShare/RemoveWalletShare.t.sol | 16 +++- .../unit_tests/WalletShare/WalletShare.t.sol | 65 +-------------- 5 files changed, 125 insertions(+), 89 deletions(-) diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index a8e216db..83d3eaa5 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -10,6 +10,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { GenericTypes } from "../libraries/DataTypes.sol"; +import { BaseHelper } from "../libraries/BaseHelper.sol"; contract PushStaking is Initializable, PushStakingStorage { using SafeERC20 for IERC20; @@ -62,6 +63,10 @@ contract PushStaking is Initializable, PushStakingStorage { removeWalletShare(oldFoundation); } + function getEpochToWalletShare(address wallet, uint epoch) public view returns(uint){ + return walletShareInfo[wallet].epochToWalletShares[epoch]; + } + function initializeStake(uint256 _walletTotalShares) external { require(genesisEpoch == 0, "PushCoreV2::initializeStake: Already Initialized"); genesisEpoch = block.number; @@ -134,6 +139,9 @@ contract PushStaking is Initializable, PushStakingStorage { if(_walletAddress == address(0) || _walletAddress == FOUNDATION) { revert Errors.InvalidArgument_WrongAddress(_walletAddress); } + if (block.number <= walletShareInfo[_walletAddress].lastStakedBlock + epochDuration) { + revert Errors.PushStaking_InvalidEpoch_LessThanExpected(); + } uint256 sharesToBeRemoved = walletShareInfo[_walletAddress].walletShare; _adjustWalletAndTotalStake(_walletAddress, 0, sharesToBeRemoved); _adjustWalletAndTotalStake(FOUNDATION, sharesToBeRemoved, 0); @@ -142,17 +150,33 @@ contract PushStaking is Initializable, PushStakingStorage { } function decreaseWalletShare( - address _walletAddress, - GenericTypes.Percentage memory _percentage - ) - external - onlyGovernance - { - uint256 sharesToBeRemoved = walletShareInfo[_walletAddress].walletShare; - removeWalletShare(_walletAddress); - addWalletShare(_walletAddress, _percentage); - emit SharesDecreased(_walletAddress, sharesToBeRemoved, walletShareInfo[_walletAddress].walletShare); - } + address _walletAddress, + GenericTypes.Percentage memory _percentage + ) + external + onlyGovernance + { + if(_walletAddress == address(0) || _walletAddress == FOUNDATION) { + revert Errors.InvalidArgument_WrongAddress(_walletAddress); + } + + uint currentEpoch = lastEpochRelative(genesisEpoch,block.number); + + uint256 currentShares = walletShareInfo[_walletAddress].walletShare; + uint256 sharesToBeAllocated = BaseHelper.calcPercentage(WALLET_TOTAL_SHARES, _percentage); + + if(sharesToBeAllocated >= currentShares){ + revert Errors.InvalidArg_MoreThanExpected(currentShares, sharesToBeAllocated); + } + uint256 sharesToBeRemoved = currentShares - sharesToBeAllocated; + walletShareInfo[_walletAddress].walletShare = sharesToBeAllocated; + walletShareInfo[_walletAddress].epochToWalletShares[currentEpoch] = sharesToBeAllocated; + + walletShareInfo[FOUNDATION].walletShare += sharesToBeRemoved; + walletShareInfo[FOUNDATION].epochToWalletShares[currentEpoch] += sharesToBeRemoved; + + emit SharesDecreased(_walletAddress, currentShares, sharesToBeAllocated); + } /** * @notice calculates rewards for share holders, for any given epoch. diff --git a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol index ba290c83..8b805274 100644 --- a/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol +++ b/test/PushStaking/WalletSharesStaking/BaseWalletSharesStaking.t.sol @@ -48,7 +48,7 @@ contract BaseWalletSharesStaking is BasePushStaking { aliceWalletShares + charlieWalletShares + tonyWalletShares; - assertEq(walletTotalShares, totalSharesSum); + assertEq(walletTotalShares, totalSharesSum,"wallet Share Sum"); } /** @@ -57,7 +57,7 @@ contract BaseWalletSharesStaking is BasePushStaking { function _validateEpochShares() internal { uint256 walletTotalShares = pushStaking.WALLET_TOTAL_SHARES(); for (uint256 i=genesisEpoch; i<=getCurrentEpoch(); ) { - assertLe(pushStaking.epochToTotalShares(i), walletTotalShares); + assertLe(pushStaking.epochToTotalShares(i), walletTotalShares, "Epoch Shares"); unchecked { i++; } diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol index 199785f2..fcebd0fc 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol @@ -5,6 +5,7 @@ import { BaseWalletSharesStaking } from "../../BaseWalletSharesStaking.t.sol"; import { GenericTypes } from "../../../../../contracts/libraries/DataTypes.sol"; import {console2} from "forge-std/console2.sol"; import { Errors } from "contracts/libraries/Errors.sol"; +import { BaseHelper } from "contracts/libraries/BaseHelper.sol"; contract DecreaseWalletShareTest is BaseWalletSharesStaking { @@ -32,27 +33,31 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { function test_Revertwhen_InvalidPercentage() public validateShareInvariants { changePrank(actor.admin); GenericTypes.Percentage memory percentAllocationZero = GenericTypes.Percentage({ percentageNumber: 0, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 0)); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 0, 0)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocationZero); GenericTypes.Percentage memory percentAllocationHundred = GenericTypes.Percentage({ percentageNumber: 100, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 100)); + uint256 calculatedShares = BaseHelper.calcPercentage(pushStaking.WALLET_TOTAL_SHARES(), percentAllocationHundred); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 0, calculatedShares)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocationHundred); } function test_Revertwhen_Percentage_GE_Allocated() public validateShareInvariants { changePrank(actor.admin); GenericTypes.Percentage memory percentAllocation1 = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); - pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation1); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation1); + (uint256 bobWalletShares,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); // revert when new allocation is equal to already allocated shares GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 20)); + uint256 calculatedShares = BaseHelper.calcPercentage(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation2); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, bobWalletShares, calculatedShares)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation2); // revert when new allocation is greater than already allocated shares GenericTypes.Percentage memory percentAllocation3 = GenericTypes.Percentage({ percentageNumber: 30, decimalPlaces: 0 }); - vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, 99, 30)); + uint256 calculatedShares2 = BaseHelper.calcPercentage(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation3); + vm.expectRevert(abi.encodeWithSelector(Errors.InvalidArg_MoreThanExpected.selector, bobWalletShares, calculatedShares2)); pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation3); } @@ -67,25 +72,29 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); (uint256 charlieWalletSharesBefore, , uint256 charlieClaimedBlockBefore) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 bobWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); // Decrease wallet shares of charlie from 50 to 40% GenericTypes.Percentage memory newPercentAllocationCharlie = GenericTypes.Percentage({ percentageNumber: 40, decimalPlaces: 0 }); - uint256 expectedCharlieShares = (newPercentAllocationCharlie.percentageNumber * charlieWalletSharesBefore) / percentAllocationFifty.percentageNumber; + uint256 expectedCharlieShares = (newPercentAllocationCharlie.percentageNumber * walletTotalSharesBefore ) / 100; + vm.expectEmit(true,true, false, true); emit SharesDecreased(actor.charlie_channel_owner, charlieWalletSharesBefore, expectedCharlieShares); pushStaking.decreaseWalletShare(actor.charlie_channel_owner, newPercentAllocationCharlie); uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); (uint256 charlieWalletSharesAfter, , uint256 charlieClaimedBlockAfter) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 bobWalletSharesAfter, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesAfter, uint256 foundationStakedBlockAfter, ) = pushStaking.walletShareInfo(actor.admin); assertEq(charlieWalletSharesAfter, expectedCharlieShares); + assertEq(bobWalletSharesBefore, bobWalletSharesAfter,"bob shares"); assertEq(walletTotalSharesBefore, walletTotalSharesAfter); assertEq(epochToTotalSharesBefore, epochToTotalSharesAfter); assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + (charlieWalletSharesBefore - charlieWalletSharesAfter)); - assertEq(foundationStakedBlockAfter, block.number); - assertEq(charlieClaimedBlockAfter, charlieClaimedBlockBefore); + assertEq(foundationStakedBlockAfter, block.number,"foundation staked block"); + assertEq(charlieClaimedBlockAfter, charlieClaimedBlockBefore,"charlie claimed block"); } function test_DecreaseWalletShare_DifferentEpoch() public validateShareInvariants { @@ -102,24 +111,72 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); (uint256 charlieWalletSharesBefore, , uint256 charlieClaimedBlockBefore) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 bobWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); // Decrease wallet shares of charlie from 50 to 40% GenericTypes.Percentage memory newPercentAllocationCharlie = GenericTypes.Percentage({ percentageNumber: 40, decimalPlaces: 0 }); - uint256 expectedCharlieShares = (newPercentAllocationCharlie.percentageNumber * charlieWalletSharesBefore) / percentAllocationFifty.percentageNumber; + uint256 expectedCharlieShares = (newPercentAllocationCharlie.percentageNumber * walletTotalSharesBefore) / 100; + vm.expectEmit(true,true, false, true); emit SharesDecreased(actor.charlie_channel_owner, charlieWalletSharesBefore, expectedCharlieShares); pushStaking.decreaseWalletShare(actor.charlie_channel_owner, newPercentAllocationCharlie); uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); (uint256 charlieWalletSharesAfter, , uint256 charlieClaimedBlockAfter) = pushStaking.walletShareInfo(actor.charlie_channel_owner); - (uint256 foundationWalletSharesAfter, uint256 foundationStakedBlockAfter, ) = pushStaking.walletShareInfo(actor.admin); - + (uint256 bobWalletSharesAfter, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 foundationWalletSharesAfter, , ) = pushStaking.walletShareInfo(actor.admin); + assertEq(charlieWalletSharesAfter, expectedCharlieShares); + assertEq(bobWalletSharesBefore, bobWalletSharesAfter,"bob shares"); + assertEq(expectedCharlieShares, pushStaking.getEpochToWalletShare(actor.charlie_channel_owner,2),"E2TW"); assertEq(walletTotalSharesBefore, walletTotalSharesAfter); assertEq(epochToTotalSharesBefore, epochToTotalSharesAfter); assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + (charlieWalletSharesBefore - charlieWalletSharesAfter)); - assertEq(foundationStakedBlockAfter, block.number); - assertEq(charlieClaimedBlockAfter, charlieClaimedBlockBefore); + assertEq(charlieClaimedBlockAfter, charlieClaimedBlockBefore,"charlie claimed block"); + } + + + function test_DecreaseWalletShare_3_Wallets() public validateShareInvariants { + addPool(1000); + changePrank(actor.admin); + // Add wallet shares of bob + GenericTypes.Percentage memory percentAllocation20 = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation25 = GenericTypes.Percentage({ percentageNumber: 25, decimalPlaces: 0 }); + GenericTypes.Percentage memory percentAllocation30 = GenericTypes.Percentage({ percentageNumber: 30, decimalPlaces: 0 }); + + pushStaking.addWalletShare(actor.alice_channel_owner, percentAllocation25); + pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation30); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation20); + + roll(epochDuration * 2); + addPool(1000); + + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 charlieWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 bobWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); + + // Decrease wallet shares of charlie from 50 to 40% + GenericTypes.Percentage memory newPercentAllocation = GenericTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); + uint256 expectedBobShares = (newPercentAllocation.percentageNumber * walletTotalSharesBefore) / 100; + vm.expectEmit(true,true, false, true); + emit SharesDecreased(actor.bob_channel_owner, bobWalletSharesBefore, expectedBobShares); + pushStaking.decreaseWalletShare(actor.bob_channel_owner, newPercentAllocation); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 charlieWalletSharesAfter, ,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); + (uint256 bobWalletSharesAfter, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + (uint256 aliceWalletSharesAfter, ,) = pushStaking.walletShareInfo(actor.alice_channel_owner); + (uint256 foundationWalletSharesAfter, , ) = pushStaking.walletShareInfo(actor.admin); + + assertEq(bobWalletSharesAfter, expectedBobShares); + assertEq(walletTotalSharesBefore, walletTotalSharesAfter); + assertEq(epochToTotalSharesBefore, epochToTotalSharesAfter); + assertEq(charlieWalletSharesBefore, charlieWalletSharesAfter); + assertEq(aliceWalletSharesBefore, aliceWalletSharesAfter); } } diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol index b9161845..2727067d 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/RemoveWalletShare/RemoveWalletShare.t.sol @@ -27,7 +27,17 @@ contract RemoveWalletShareTest is BaseWalletSharesStaking { pushStaking.removeWalletShare(actor.admin); } - function test_RemoveWalletShare_SameEpoch() public validateShareInvariants { + function test_Revertwhen_RemovesBefore_1Epoch() public validateShareInvariants { + changePrank(actor.admin); + // Add wallet shares of bob + GenericTypes.Percentage memory percentAllocation = GenericTypes.Percentage({ percentageNumber: 20, decimalPlaces: 0 }); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + vm.expectRevert(abi.encodeWithSelector(Errors.PushStaking_InvalidEpoch_LessThanExpected.selector)); + pushStaking.removeWalletShare(actor.bob_channel_owner); + } + + function test_RemoveWalletShare() public validateShareInvariants { addPool(1000); changePrank(actor.admin); // Add wallet shares of bob @@ -39,6 +49,8 @@ contract RemoveWalletShareTest is BaseWalletSharesStaking { (uint256 bobWalletSharesBefore, , uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore, , uint256 foundationClaimedBlockBefore) = pushStaking.walletShareInfo(actor.admin); + roll(epochDuration * 2); + emit SharesRemoved(actor.bob_channel_owner, bobWalletSharesBefore); // Remove wallet shares of bob pushStaking.removeWalletShare(actor.bob_channel_owner); @@ -58,7 +70,7 @@ contract RemoveWalletShareTest is BaseWalletSharesStaking { } function test_RemoveWalletShare_SameEpoch_Rewards() public validateShareInvariants { - test_RemoveWalletShare_SameEpoch(); + test_RemoveWalletShare(); uint256 bobRewards = pushStaking.calculateWalletRewards(actor.bob_channel_owner, getCurrentEpoch()); assertEq(bobRewards, 0); diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol index bd8d9e4c..a18188f3 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/WalletShare/WalletShare.t.sol @@ -217,6 +217,7 @@ contract WalletShareTest is BaseWalletSharesStaking { pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 aliceWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.alice_channel_owner); (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); + roll(epochDuration * 2); changePrank(actor.admin); pushStaking.removeWalletShare(actor.bob_channel_owner); @@ -228,7 +229,7 @@ contract WalletShareTest is BaseWalletSharesStaking { (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); assertEq(bobWalletSharesAfter, 0, "bob wallet share"); - assertEq(aliceWalletSharesAfter, aliceWalletSharesBefore, "akice wallet share"); + assertEq(aliceWalletSharesAfter, aliceWalletSharesBefore, "alice wallet share"); assertEq( foundationWalletSharesAfter, foundationWalletSharesBefore + bobWalletSharesBefore, "foundation wallet share" ); @@ -347,62 +348,6 @@ contract WalletShareTest is BaseWalletSharesStaking { uint256 percentage = (bobWalletSharesAfter * 100) / actualTotalShares; assertEq(percentage, 20); } - - function test_DecreaseWalletShare() public { - // assigns actor.bob_channel_owner 20% allocation - test_WalletGets_20PercentAllocation(); - - // let's decrease actor.bob_channel_owner allocation to 10% - uint256 totalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = - pushStaking.walletShareInfo(actor.bob_channel_owner); - (uint256 foundationWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.admin); - - GenericTypes.Percentage memory percentAllocation = - GenericTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); - - uint256 expectedAllocationShares = - pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES(), percentAllocation); - changePrank(actor.admin); - pushStaking.decreaseWalletShare(actor.bob_channel_owner, percentAllocation); - uint256 totalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); - (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = - pushStaking.walletShareInfo(actor.bob_channel_owner); - (uint256 foundationWalletSharesAfter,,) = pushStaking.walletShareInfo(actor.admin); - - assertEq(bobWalletSharesBefore, 25_000 * 1e18); - assertEq(totalSharesBefore, 125_000 * 1e18); - assertEq(foundationWalletSharesBefore, 100_000 * 1e18); - assertEq(bobWalletSharesAfter, expectedAllocationShares); - assertEq(totalSharesAfter, 125_000 * 1e18 + expectedAllocationShares); - assertEq(foundationWalletSharesAfter, 125_000 * 1e18); - } - - // FUZZ TESTS - function testFuzz_AddShares(address _walletAddress, GenericTypes.Percentage memory _percentage) public { - _percentage.percentageNumber = bound(_percentage.percentageNumber, 1, 100); - _percentage.decimalPlaces = bound(_percentage.decimalPlaces, 1, 10); - vm.assume(_walletAddress != actor.admin && _walletAddress != address(0)); - // percentage must be less than 100 - vm.assume(_percentage.percentageNumber / 10 ** _percentage.decimalPlaces < 100); - changePrank(actor.admin); - pushStaking.addWalletShare(_walletAddress, _percentage); - } - - function testFuzz_RemoveShares(address _walletAddress, GenericTypes.Percentage memory _percentage) public { - _percentage.percentageNumber = bound(_percentage.percentageNumber, 0, 100); - vm.assume(_percentage.decimalPlaces < 10); - // percentage must be less than 100 - vm.assume(_percentage.percentageNumber / 10 ** _percentage.decimalPlaces < 100); - testFuzz_AddShares(_walletAddress, _percentage); - - changePrank(actor.admin); - pushStaking.removeWalletShare(_walletAddress); - (uint256 foundationWalletShares,,) = pushStaking.walletShareInfo(actor.admin); - - assertEq(pushStaking.WALLET_TOTAL_SHARES(), foundationWalletShares); - } - function test_whenWallet_SharesIncrease_InSameEpoch() public { (uint256 bobWalletSharesBefore, uint256 bobStakedBlockBefore, uint256 bobClaimedBlockBefore) = pushStaking.walletShareInfo(actor.bob_channel_owner); @@ -506,7 +451,7 @@ contract WalletShareTest is BaseWalletSharesStaking { addPool(1000); GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation2); - roll(epochDuration + 1); + roll(epochDuration + 2); addPool(1000); pushStaking.setFoundationAddress(actor.bob_channel_owner); // GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); @@ -527,10 +472,8 @@ contract WalletShareTest is BaseWalletSharesStaking { assertEq(foundationWalletShares, 100_000 ether); assertEq(foundationStakedBlock, genesisEpoch); assertEq(foundationClaimedBlock, genesisEpoch); - roll(epochDuration + 1); changePrank(actor.admin); - GenericTypes.Percentage memory percentAllocation2 = GenericTypes.Percentage({ percentageNumber: 50, decimalPlaces: 0 }); - pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation2); + roll(epochDuration + 2); pushStaking.setFoundationAddress(actor.bob_channel_owner); addPool(1000); From c28cf09303d6ac361de27ad7691aff3046fd7e11 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 18 Dec 2024 12:12:56 +0530 Subject: [PATCH 45/49] fix: Minor Bug fixes wrt non-EVM audit --- contracts/PushComm/PushCommETHV3.sol | 23 +++++------- contracts/PushComm/PushCommEthStorageV2.sol | 2 +- contracts/PushComm/PushCommStorageV2.sol | 2 +- contracts/PushComm/PushCommV3.sol | 35 +++++++++---------- contracts/interfaces/IPushCommV3.sol | 12 +++---- .../SubscribeBySig/SubscribeBySig.t.sol | 3 +- 6 files changed, 35 insertions(+), 42 deletions(-) diff --git a/contracts/PushComm/PushCommETHV3.sol b/contracts/PushComm/PushCommETHV3.sol index faf0526d..7c3cf996 100644 --- a/contracts/PushComm/PushCommETHV3.sol +++ b/contracts/PushComm/PushCommETHV3.sol @@ -78,11 +78,11 @@ contract PushCommETHV3 is Initializable, PushCommEthStorageV2, IPushCommV3 { ***************************** */ function verifyChannelAlias(string memory _channelAddress) external { - emit ChannelAlias(chainName, chainID, msg.sender, _channelAddress); + emit ChannelAlias(chainName, block.chainid, msg.sender, _channelAddress); } function removeChannelAlias(string memory _channelAddress) external { - emit RemoveChannelAlias(chainName, chainID, msg.sender, _channelAddress); + emit RemoveChannelAlias(chainName, block.chainid, msg.sender, _channelAddress); } // function completeMigration() external onlyPushChannelAdmin { @@ -123,13 +123,12 @@ contract PushCommETHV3 is Initializable, PushCommEthStorageV2, IPushCommV3 { } /// @inheritdoc IPushCommV3 - function subscribe(address _channel) external returns (bool) { + function subscribe(address _channel) external { _subscribe(_channel, msg.sender); - return true; } /// @inheritdoc IPushCommV3 - function batchSubscribe(address[] calldata _channelList) external returns (bool) { + function batchSubscribe(address[] calldata _channelList) external { uint256 channelListLength = _channelList.length; for (uint256 i = 0; i < channelListLength;) { _subscribe(_channelList[i], msg.sender); @@ -137,7 +136,6 @@ contract PushCommETHV3 is Initializable, PushCommEthStorageV2, IPushCommV3 { i++; } } - return true; } /** @@ -213,9 +211,8 @@ contract PushCommETHV3 is Initializable, PushCommEthStorageV2, IPushCommV3 { } /// @inheritdoc IPushCommV3 - function subscribeViaCore(address _channel, address _user) external onlyPushCore returns (bool) { + function subscribeViaCore(address _channel, address _user) external onlyPushCore { _subscribe(_channel, _user); - return true; } /* ***************************** @@ -225,14 +222,13 @@ contract PushCommETHV3 is Initializable, PushCommEthStorageV2, IPushCommV3 { ***************************** */ /// @inheritdoc IPushCommV3 - function unsubscribe(address _channel) external returns (bool) { + function unsubscribe(address _channel) external { // Call actual unsubscribe _unsubscribe(_channel, msg.sender); - return true; } /// @inheritdoc IPushCommV3 - function batchUnsubscribe(address[] calldata _channelList) external returns (bool) { + function batchUnsubscribe(address[] calldata _channelList) external { uint256 channelListLength = _channelList.length; for (uint256 i = 0; i < channelListLength;) { _unsubscribe(_channelList[i], msg.sender); @@ -240,7 +236,6 @@ contract PushCommETHV3 is Initializable, PushCommEthStorageV2, IPushCommV3 { i++; } } - return true; } /** @@ -314,9 +309,8 @@ contract PushCommETHV3 is Initializable, PushCommEthStorageV2, IPushCommV3 { } /// @inheritdoc IPushCommV3 - function unSubscribeViaCore(address _channel, address _user) external onlyPushCore returns (bool) { + function unSubscribeViaCore(address _channel, address _user) external onlyPushCore { _unsubscribe(_channel, _user); - return true; } /** @@ -354,6 +348,7 @@ contract PushCommETHV3 is Initializable, PushCommEthStorageV2, IPushCommV3 { /// @inheritdoc IPushCommV3 function removeDelegate(address _delegate) external { delegatedNotificationSenders[msg.sender][_delegate] = false; + _unsubscribe(msg.sender, _delegate); emit RemoveDelegate(msg.sender, _delegate); } diff --git a/contracts/PushComm/PushCommEthStorageV2.sol b/contracts/PushComm/PushCommEthStorageV2.sol index f40dfbae..abea0d21 100644 --- a/contracts/PushComm/PushCommEthStorageV2.sol +++ b/contracts/PushComm/PushCommEthStorageV2.sol @@ -17,7 +17,7 @@ contract PushCommEthStorageV2 { */ address public governance; address public pushChannelAdmin; - uint256 public chainID; + uint256 public chainID; // Unused Variable uint256 public usersCount; bool public isMigrationComplete; address public PushCoreAddress; diff --git a/contracts/PushComm/PushCommStorageV2.sol b/contracts/PushComm/PushCommStorageV2.sol index b187b514..629603c3 100644 --- a/contracts/PushComm/PushCommStorageV2.sol +++ b/contracts/PushComm/PushCommStorageV2.sol @@ -22,7 +22,7 @@ contract PushCommStorageV2 { */ address public governance; address public pushChannelAdmin; - uint256 public chainID; + uint256 public chainID; //Unused Variable uint256 public usersCount; bool public isMigrationComplete; address public PushCoreAddress; diff --git a/contracts/PushComm/PushCommV3.sol b/contracts/PushComm/PushCommV3.sol index 236669db..058a8de5 100644 --- a/contracts/PushComm/PushCommV3.sol +++ b/contracts/PushComm/PushCommV3.sol @@ -84,7 +84,7 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp ***************************** */ function verifyChannelAlias(string memory _channelAddress) external { - emit ChannelAlias(chainName, chainID, msg.sender, _channelAddress); + emit ChannelAlias(chainName, block.chainid, msg.sender, _channelAddress); } @@ -130,13 +130,12 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp } /// @inheritdoc IPushCommV3 - function subscribe(address _channel) external returns (bool) { + function subscribe(address _channel) external { _subscribe(_channel, msg.sender); - return true; } /// @inheritdoc IPushCommV3 - function batchSubscribe(address[] calldata _channelList) external returns (bool) { + function batchSubscribe(address[] calldata _channelList) external { uint256 channelListLength = _channelList.length; for (uint256 i = 0; i < channelListLength;) { _subscribe(_channelList[i], msg.sender); @@ -144,7 +143,6 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp i++; } } - return true; } /** @@ -220,9 +218,8 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp } /// @inheritdoc IPushCommV3 - function subscribeViaCore(address _channel, address _user) external onlyPushCore returns (bool) { + function subscribeViaCore(address _channel, address _user) external onlyPushCore { _subscribe(_channel, _user); - return true; } /* ***************************** @@ -232,14 +229,13 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp ***************************** */ /// @inheritdoc IPushCommV3 - function unsubscribe(address _channel) external returns (bool) { + function unsubscribe(address _channel) external { // Call actual unsubscribe _unsubscribe(_channel, msg.sender); - return true; } /// @inheritdoc IPushCommV3 - function batchUnsubscribe(address[] calldata _channelList) external returns (bool) { + function batchUnsubscribe(address[] calldata _channelList) external { uint256 channelListLength = _channelList.length; for (uint256 i = 0; i < channelListLength;) { _unsubscribe(_channelList[i], msg.sender); @@ -247,7 +243,6 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp i++; } } - return true; } /** @@ -321,9 +316,8 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp } /// @inheritdoc IPushCommV3 - function unSubscribeViaCore(address _channel, address _user) external onlyPushCore returns (bool) { + function unSubscribeViaCore(address _channel, address _user) external onlyPushCore { _unsubscribe(_channel, _user); - return true; } /** @@ -353,15 +347,20 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp /// @inheritdoc IPushCommV3 function addDelegate(address _delegate) external { - delegatedNotificationSenders[msg.sender][_delegate] = true; - _subscribe(msg.sender, _delegate); - emit AddDelegate(msg.sender, _delegate); + if(delegatedNotificationSenders[msg.sender][_delegate] == false){ + delegatedNotificationSenders[msg.sender][_delegate] = true; + _subscribe(msg.sender, _delegate); + emit AddDelegate(msg.sender, _delegate); + } } /// @inheritdoc IPushCommV3 function removeDelegate(address _delegate) external { - delegatedNotificationSenders[msg.sender][_delegate] = false; - emit RemoveDelegate(msg.sender, _delegate); + if(delegatedNotificationSenders[msg.sender][_delegate] == false){ + delegatedNotificationSenders[msg.sender][_delegate] = false; + _unsubscribe(msg.sender, _delegate); + emit RemoveDelegate(msg.sender, _delegate); + } } /** diff --git a/contracts/interfaces/IPushCommV3.sol b/contracts/interfaces/IPushCommV3.sol index 4c34a9b9..5511c71f 100644 --- a/contracts/interfaces/IPushCommV3.sol +++ b/contracts/interfaces/IPushCommV3.sol @@ -67,11 +67,11 @@ interface IPushCommV3 { /// @dev Subscribes the caller of the function to a particular Channel /// - Takes into Consideration the "msg.sender" /// @param _channel address of the channel that the user is subscribing to - function subscribe(address _channel) external returns (bool); + function subscribe(address _channel) external; /// @notice Allows users to subscribe a List of Channels at once /// @param _channelList array of addresses of the channels that the user wishes to Subscribe - function batchSubscribe(address[] calldata _channelList) external returns (bool); + function batchSubscribe(address[] calldata _channelList) external; /// @notice Subscribe Function through Meta TX /// @dev Takes into Consideration the Sign of the User @@ -98,7 +98,7 @@ interface IPushCommV3 { /// @param _channel address of the channel that the user is subscribing to /// @param _user address of the Subscriber of a Channel - function subscribeViaCore(address _channel, address _user) external returns (bool); + function subscribeViaCore(address _channel, address _user) external; /// @notice Allows PushCore contract to call the Base UnSubscribe function whenever a User Destroys his/her /// TimeBound Channel. @@ -110,19 +110,19 @@ interface IPushCommV3 { /// @param _channel address of the channel being unsubscribed /// @param _user address of the UnSubscriber of a Channel - function unSubscribeViaCore(address _channel, address _user) external returns (bool); + function unSubscribeViaCore(address _channel, address _user) external; /// @notice External Unsubcribe Function that allows users to directly unsubscribe from a particular channel /// @dev UnSubscribes the caller of the function from the particular Channel. /// Takes into Consideration the "msg.sender" /// @param _channel address of the channel that the user is unsubscribing to - function unsubscribe(address _channel) external returns (bool); + function unsubscribe(address _channel) external; /// @notice Allows users to unsubscribe from a List of Channels at once /// @param _channelList array of addresses of the channels that the user wishes to Unsubscribe - function batchUnsubscribe(address[] calldata _channelList) external returns (bool); + function batchUnsubscribe(address[] calldata _channelList) external; /// @notice Unsubscribe Function through Meta TX /// @dev Takes into Consideration the Signer of the transactioner diff --git a/test/PushComm/unit_tests/SubscribeBySig/SubscribeBySig.t.sol b/test/PushComm/unit_tests/SubscribeBySig/SubscribeBySig.t.sol index 492be3ba..0d7bec7a 100644 --- a/test/PushComm/unit_tests/SubscribeBySig/SubscribeBySig.t.sol +++ b/test/PushComm/unit_tests/SubscribeBySig/SubscribeBySig.t.sol @@ -166,8 +166,7 @@ contract SubscribeBySig_Test is BasePushCommTest { function test_WhenUsersUnsubscribeWith712Sig() public { //Alice subscribes to bob's channel to check the unsubscribe function changePrank(actor.alice_channel_owner); - bool res = commProxy.subscribe(actor.bob_channel_owner); - assertEq(res, true); + commProxy.subscribe(actor.bob_channel_owner); bytes32 DOMAIN_SEPARATOR = getDomainSeparator(); SubscribeUnsubscribe memory _subscribeUnsubscribe = SubscribeUnsubscribe( From ce5012ec12b43e8286a7ef98f63d2c16b7779887 Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Wed, 18 Dec 2024 15:26:37 +0530 Subject: [PATCH 46/49] add security contact --- contracts/PushComm/PushCommETHV3.sol | 2 +- contracts/PushComm/PushCommV3.sol | 2 +- contracts/PushCore/PushCoreV3.sol | 2 +- contracts/PushStaking/PushStakingProxy.sol | 11 ++++++++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/contracts/PushComm/PushCommETHV3.sol b/contracts/PushComm/PushCommETHV3.sol index 7c3cf996..6faa2496 100644 --- a/contracts/PushComm/PushCommETHV3.sol +++ b/contracts/PushComm/PushCommETHV3.sol @@ -12,7 +12,7 @@ pragma solidity ^0.8.20; * @dev Some imperative functionalities that the Push Communicator Protocol allows * are Subscribing to a particular channel, Unsubscribing a channel, Sending * Notifications to a particular recipient or all subscribers of a Channel etc. - * + * @Custom:security-contact https://push.org/ */ import { PushCommEthStorageV2 } from "./PushCommEthStorageV2.sol"; import { Errors } from "../libraries/Errors.sol"; diff --git a/contracts/PushComm/PushCommV3.sol b/contracts/PushComm/PushCommV3.sol index 058a8de5..bd484eb6 100644 --- a/contracts/PushComm/PushCommV3.sol +++ b/contracts/PushComm/PushCommV3.sol @@ -12,7 +12,7 @@ pragma solidity ^0.8.20; * @dev Some imperative functionalities that the Push Communicator Protocol allows * are Subscribing to a particular channel, Unsubscribing a channel, Sending * Notifications to a particular recipient or all subscribers of a Channel etc. - * + * @Custom:security-contact https://push.org/ */ import { PushCommStorageV2 } from "./PushCommStorageV2.sol"; import { Errors } from "../libraries/Errors.sol"; diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index 6a9aa77b..f6569f23 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -9,7 +9,7 @@ pragma solidity ^0.8.20; * @dev This protocol will be specifically deployed on Ethereum Blockchain while the Communicator * protocols can be deployed on Multiple Chains. * The Push Core is more inclined towards the storing and handling the Channel related functionalties. - * + * @Custom:security-contact https://push.org/ */ import { PushCoreStorageV1_5 } from "./PushCoreStorageV1_5.sol"; import { PushCoreStorageV2 } from "./PushCoreStorageV2.sol"; diff --git a/contracts/PushStaking/PushStakingProxy.sol b/contracts/PushStaking/PushStakingProxy.sol index 098dac46..2ee80885 100644 --- a/contracts/PushStaking/PushStakingProxy.sol +++ b/contracts/PushStaking/PushStakingProxy.sol @@ -1,7 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; - +/** + * @title PushStakingProxy + * @author Push Protocol + * @notice Push Stakin will deal with the handling of staking initiatives by Push Protocol. + * + * @dev This protocol will be specifically deployed on Ethereum Blockchain and will be connected to Push Core + * contract in a way that the core contract handles all the funds and this contract handles the state + * of stakers. + * @Custom:security-contact https://push.org/ + */ import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; contract PushStakingProxy is TransparentUpgradeableProxy { From 33e4b261f7031c06c50886fc3ea205b8a19aac85 Mon Sep 17 00:00:00 2001 From: Zaryab Date: Thu, 19 Dec 2024 16:06:07 +0530 Subject: [PATCH 47/49] fix sec link --- contracts/PushComm/PushCommV3.sol | 2 +- contracts/PushCore/PushCoreV3.sol | 2 +- contracts/PushStaking/PushStakingProxy.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/PushComm/PushCommV3.sol b/contracts/PushComm/PushCommV3.sol index bd484eb6..03fe5c5a 100644 --- a/contracts/PushComm/PushCommV3.sol +++ b/contracts/PushComm/PushCommV3.sol @@ -12,7 +12,7 @@ pragma solidity ^0.8.20; * @dev Some imperative functionalities that the Push Communicator Protocol allows * are Subscribing to a particular channel, Unsubscribing a channel, Sending * Notifications to a particular recipient or all subscribers of a Channel etc. - * @Custom:security-contact https://push.org/ + * @Custom:security-contact https://immunefi.com/bug-bounty/pushprotocol/information/ */ import { PushCommStorageV2 } from "./PushCommStorageV2.sol"; import { Errors } from "../libraries/Errors.sol"; diff --git a/contracts/PushCore/PushCoreV3.sol b/contracts/PushCore/PushCoreV3.sol index f6569f23..8bb3f147 100644 --- a/contracts/PushCore/PushCoreV3.sol +++ b/contracts/PushCore/PushCoreV3.sol @@ -9,7 +9,7 @@ pragma solidity ^0.8.20; * @dev This protocol will be specifically deployed on Ethereum Blockchain while the Communicator * protocols can be deployed on Multiple Chains. * The Push Core is more inclined towards the storing and handling the Channel related functionalties. - * @Custom:security-contact https://push.org/ + * @Custom:security-contact https://immunefi.com/bug-bounty/pushprotocol/information/ */ import { PushCoreStorageV1_5 } from "./PushCoreStorageV1_5.sol"; import { PushCoreStorageV2 } from "./PushCoreStorageV2.sol"; diff --git a/contracts/PushStaking/PushStakingProxy.sol b/contracts/PushStaking/PushStakingProxy.sol index 2ee80885..830e8fec 100644 --- a/contracts/PushStaking/PushStakingProxy.sol +++ b/contracts/PushStaking/PushStakingProxy.sol @@ -9,7 +9,7 @@ pragma solidity ^0.8.20; * @dev This protocol will be specifically deployed on Ethereum Blockchain and will be connected to Push Core * contract in a way that the core contract handles all the funds and this contract handles the state * of stakers. - * @Custom:security-contact https://push.org/ + * @Custom:security-contact https://immunefi.com/bug-bounty/pushprotocol/information/ */ import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; From b7bf880079227a63096586e1b4d492aa51b4120c Mon Sep 17 00:00:00 2001 From: Md Zartaj Afser Date: Fri, 20 Dec 2024 12:35:47 +0530 Subject: [PATCH 48/49] fix delegatation and add test --- contracts/PushComm/PushCommV3.sol | 2 +- .../ChannelDelegation.t.sol | 81 +++++++++++++++++++ .../ChannelDelegation.tree | 11 +++ .../SendingNotifications/SendNotifs.t.sol | 12 --- 4 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 test/PushComm/unit_tests/ChannelDelegatation/ChannelDelegation.t.sol create mode 100644 test/PushComm/unit_tests/ChannelDelegatation/ChannelDelegation.tree diff --git a/contracts/PushComm/PushCommV3.sol b/contracts/PushComm/PushCommV3.sol index 03fe5c5a..82a6cad0 100644 --- a/contracts/PushComm/PushCommV3.sol +++ b/contracts/PushComm/PushCommV3.sol @@ -356,7 +356,7 @@ contract PushCommV3 is Initializable, PushCommStorageV2, IPushCommV3, PausableUp /// @inheritdoc IPushCommV3 function removeDelegate(address _delegate) external { - if(delegatedNotificationSenders[msg.sender][_delegate] == false){ + if(delegatedNotificationSenders[msg.sender][_delegate] == true){ delegatedNotificationSenders[msg.sender][_delegate] = false; _unsubscribe(msg.sender, _delegate); emit RemoveDelegate(msg.sender, _delegate); diff --git a/test/PushComm/unit_tests/ChannelDelegatation/ChannelDelegation.t.sol b/test/PushComm/unit_tests/ChannelDelegatation/ChannelDelegation.t.sol new file mode 100644 index 00000000..85b2a2e3 --- /dev/null +++ b/test/PushComm/unit_tests/ChannelDelegatation/ChannelDelegation.t.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; +import { BasePushCommTest } from "../BasePushCommTest.t.sol"; +import { Errors } from "contracts/libraries/Errors.sol"; + +contract ChannelDelegation_Test is BasePushCommTest { + function setUp() public override { + BasePushCommTest.setUp(); + } + + modifier whenChannelAddsDelegate(address caller) { + changePrank(caller); + commProxy.addDelegate(actor.dan_push_holder); + _; + } + + function test_WhenDelegateIsNotAdded() external whenChannelAddsDelegate(actor.bob_channel_owner) { + // it should add the delagate + bool isDanDelegate = commProxy.delegatedNotificationSenders(actor.bob_channel_owner, actor.dan_push_holder); + + assertEq(isDanDelegate, true); + + } + + function test_WhenDelegateIsAlreadyAdded() external whenChannelAddsDelegate(actor.bob_channel_owner) { + // it should not change anything + commProxy.addDelegate(actor.dan_push_holder); + bool isDanDelegate = commProxy.delegatedNotificationSenders(actor.bob_channel_owner, actor.dan_push_holder); + + assertEq(isDanDelegate, true); + } + + modifier whenChannelRemovesDelegate(address caller) { + changePrank(caller); + commProxy.removeDelegate(actor.dan_push_holder); + _; + } + + function test_WhenDelegateIsAdded() external whenChannelRemovesDelegate(actor.bob_channel_owner) { + // it should remove the delagate + bool isDanDelegate = commProxy.delegatedNotificationSenders(actor.bob_channel_owner, actor.dan_push_holder); + + assertEq(isDanDelegate, false); + } + + function test_WhenDelegateIsAlreadyRemoved() external whenChannelRemovesDelegate(actor.bob_channel_owner) { + // it should not change anything + commProxy.removeDelegate(actor.dan_push_holder); + + bool isDanDelegate = commProxy.delegatedNotificationSenders(actor.bob_channel_owner, actor.dan_push_holder); + + assertEq(isDanDelegate, false); + } + + function test_WhenAddingDelegate_ShouldBeSubscribedToChannel() external { + changePrank(actor.bob_channel_owner); + commProxy.addDelegate(actor.dan_push_holder); + bool isTonyDelegate = commProxy.delegatedNotificationSenders(actor.bob_channel_owner, actor.dan_push_holder); + + assertEq(isTonyDelegate, true); + + //Check the delegate becomes a subscriber. + bool isSub = commProxy.isUserSubscribed(actor.bob_channel_owner, actor.dan_push_holder); + assertEq(isSub, true); + } + + function test_WhenRemovingDelegate_Should_UnSubscribeChannel() external { + changePrank(actor.bob_channel_owner); + commProxy.addDelegate(actor.dan_push_holder); + + //Check the delegate becomes a subscriber. + bool isSub = commProxy.isUserSubscribed(actor.bob_channel_owner, actor.dan_push_holder); + assertEq(isSub, true); + + commProxy.removeDelegate(actor.dan_push_holder); + + bool isSubAfter = commProxy.isUserSubscribed(actor.bob_channel_owner, actor.dan_push_holder); + assertEq(isSubAfter, false); + + } +} \ No newline at end of file diff --git a/test/PushComm/unit_tests/ChannelDelegatation/ChannelDelegation.tree b/test/PushComm/unit_tests/ChannelDelegatation/ChannelDelegation.tree new file mode 100644 index 00000000..06262079 --- /dev/null +++ b/test/PushComm/unit_tests/ChannelDelegatation/ChannelDelegation.tree @@ -0,0 +1,11 @@ +ChannelDelegation.t.sol +├── when channel adds delegate +│ ├── when delegate Is not added +│ │ └── it should add the delagate +│ └── when delegate is already added +│ └── it should not change anything +└── when channel removes delegate + ├── when delegate Is added + │ └── it should remove the delagate + └── when delegate is already removed + └── it should not change anything \ No newline at end of file diff --git a/test/PushComm/unit_tests/SendingNotifications/SendNotifs.t.sol b/test/PushComm/unit_tests/SendingNotifications/SendNotifs.t.sol index cf4dc018..e94fd002 100644 --- a/test/PushComm/unit_tests/SendingNotifications/SendNotifs.t.sol +++ b/test/PushComm/unit_tests/SendingNotifications/SendNotifs.t.sol @@ -48,16 +48,4 @@ contract SendNotifs_Test is BasePushCommTest { bool res = commProxy.sendNotification(actor.bob_channel_owner, actor.alice_channel_owner, _testChannelIdentity); assertEq(res, true); } - - function test_WhenAddingDelegate_ShouldBeSubscribedToChannel() external { - changePrank(actor.bob_channel_owner); - commProxy.addDelegate(actor.dan_push_holder); - bool isTonyDelegate = commProxy.delegatedNotificationSenders(actor.bob_channel_owner, actor.dan_push_holder); - - assertEq(isTonyDelegate, true); - - //Check the delegate becomes a subscriber. - bool isSub = commProxy.isUserSubscribed(actor.bob_channel_owner, actor.dan_push_holder); - assertEq(isSub, true); - } } From b8d22047b1cc538444fe93ecc1fe6d765f0b4559 Mon Sep 17 00:00:00 2001 From: Zartaj0 Date: Fri, 10 Jan 2025 15:42:34 +0530 Subject: [PATCH 49/49] fix decrease shares --- contracts/PushStaking/PushStaking.sol | 8 +- .../fuzz_tests/AddWalletShare.f.sol | 166 ++++++++++++++++++ .../DecreaseWalletShare.t.sol | 14 +- 3 files changed, 176 insertions(+), 12 deletions(-) create mode 100644 test/PushStaking/WalletSharesStaking/fuzz_tests/AddWalletShare.f.sol diff --git a/contracts/PushStaking/PushStaking.sol b/contracts/PushStaking/PushStaking.sol index 83d3eaa5..77fbf291 100644 --- a/contracts/PushStaking/PushStaking.sol +++ b/contracts/PushStaking/PushStaking.sol @@ -169,12 +169,10 @@ contract PushStaking is Initializable, PushStakingStorage { revert Errors.InvalidArg_MoreThanExpected(currentShares, sharesToBeAllocated); } uint256 sharesToBeRemoved = currentShares - sharesToBeAllocated; - walletShareInfo[_walletAddress].walletShare = sharesToBeAllocated; - walletShareInfo[_walletAddress].epochToWalletShares[currentEpoch] = sharesToBeAllocated; - - walletShareInfo[FOUNDATION].walletShare += sharesToBeRemoved; - walletShareInfo[FOUNDATION].epochToWalletShares[currentEpoch] += sharesToBeRemoved; + _adjustWalletAndTotalStake(_walletAddress, 0, sharesToBeRemoved); + _adjustWalletAndTotalStake(FOUNDATION, sharesToBeRemoved, 0); + emit SharesDecreased(_walletAddress, currentShares, sharesToBeAllocated); } diff --git a/test/PushStaking/WalletSharesStaking/fuzz_tests/AddWalletShare.f.sol b/test/PushStaking/WalletSharesStaking/fuzz_tests/AddWalletShare.f.sol new file mode 100644 index 00000000..48d2320d --- /dev/null +++ b/test/PushStaking/WalletSharesStaking/fuzz_tests/AddWalletShare.f.sol @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import { BaseWalletSharesStaking } from "../BaseWalletSharesStaking.t.sol"; +import { GenericTypes } from "contracts/libraries/DataTypes.sol"; +import { console2 } from "forge-std/console2.sol"; +import { Errors } from "contracts/libraries/Errors.sol"; + +contract AddWalletShareTestFuzz is BaseWalletSharesStaking { + function setUp() public virtual override { + BaseWalletSharesStaking.setUp(); + } + + function testFuzz_Revertwhen_NewShares_LE_ToOldShares(GenericTypes.Percentage memory percentAllocation1) + public + validateShareInvariants + { + percentAllocation1.percentageNumber = bound(percentAllocation1.percentageNumber, 10, 99); + percentAllocation1.decimalPlaces = bound(percentAllocation1.decimalPlaces, 0, 10); + + changePrank(actor.admin); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation1); + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + + // revert when new allocation is equal to already allocated shares + uint256 sharesToBeAllocated2 = + pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES() - bobWalletSharesBefore, percentAllocation1); + vm.expectRevert( + abi.encodeWithSelector( + Errors.InvalidArg_LessThanExpected.selector, bobWalletSharesBefore, sharesToBeAllocated2 + ) + ); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation1); + + // revert when new allocation is less than already allocated shares + percentAllocation1.percentageNumber = percentAllocation1.percentageNumber - 5; + uint256 sharesToBeAllocated3 = + pushStaking.getSharesAmount(pushStaking.WALLET_TOTAL_SHARES() - bobWalletSharesBefore, percentAllocation1); + vm.expectRevert( + abi.encodeWithSelector( + Errors.InvalidArg_LessThanExpected.selector, bobWalletSharesBefore, sharesToBeAllocated3 + ) + ); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation1); + } + + function testFuzz_AddWalletShare(GenericTypes.Percentage memory percentAllocation) public validateShareInvariants { + percentAllocation.percentageNumber = bound(percentAllocation.percentageNumber, 5, 89); + percentAllocation.decimalPlaces = bound(percentAllocation.decimalPlaces, 0, 10); + changePrank(actor.admin); + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesBefore,, uint256 bobClaimedBlockBefore) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 expectedSharesOfBob = (percentAllocation.percentageNumber * walletTotalSharesBefore) + / ((100 * (10 ** percentAllocation.decimalPlaces)) - percentAllocation.percentageNumber); + vm.expectEmit(true, true, false, false); + emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); + pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + assertEq(walletTotalSharesAfter, walletTotalSharesBefore + expectedSharesOfBob); + assertEq(epochToTotalSharesAfter, epochToTotalSharesBefore + expectedSharesOfBob); + + assertEq(bobWalletSharesBefore, 0); + assertEq(bobWalletSharesAfter, expectedSharesOfBob); + assertEq(bobStakedBlockAfter, block.number); + assertEq(bobClaimedBlockAfter, pushStaking.genesisEpoch()); + } + + function testFuzz_IncreaseAllocation_InSameEpoch(GenericTypes.Percentage memory percentAllocation) + public + validateShareInvariants + { + percentAllocation.percentageNumber = bound(percentAllocation.percentageNumber, 5, 89); + percentAllocation.decimalPlaces = bound(percentAllocation.decimalPlaces, 0, 10); + + testFuzz_AddWalletShare(percentAllocation); + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 walletTotalSharesForCalc = walletTotalSharesBefore - bobWalletSharesBefore; + + GenericTypes.Percentage memory newPercentAllocation = GenericTypes.Percentage({ + percentageNumber: percentAllocation.percentageNumber + 10, + decimalPlaces: percentAllocation.decimalPlaces + }); + uint expectedSharesOfBob = (newPercentAllocation.percentageNumber * walletTotalSharesForCalc) + / ((100 * (10 ** newPercentAllocation.decimalPlaces)) - newPercentAllocation.percentageNumber);// bob is 25k + vm.expectEmit(true, true, false, false); + emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); + + pushStaking.addWalletShare(actor.bob_channel_owner, newPercentAllocation); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + assertEq(walletTotalSharesAfter, expectedSharesOfBob + walletTotalSharesForCalc); + assertEq(epochToTotalSharesAfter, expectedSharesOfBob + walletTotalSharesForCalc); + + assertEq(bobWalletSharesAfter, expectedSharesOfBob); + assertEq(bobStakedBlockAfter, block.number); + assertEq(bobClaimedBlockAfter, pushStaking.genesisEpoch()); + + // INVARIANT: wallet total shares should never be reduced after a function call + assertLe(walletTotalSharesBefore, walletTotalSharesAfter); + // INVARIANT: epochToTotalShares should never be reduced after a function call + assertLe(epochToTotalSharesBefore, epochToTotalSharesAfter); + // INVARIANT: epochToTotalShares in any epoch should not exceed total wallet shares + assertLe(epochToTotalSharesAfter, walletTotalSharesAfter); + } + + function testFuzz_IncreaseAllocation_InDifferentEpoch(GenericTypes.Percentage memory percentAllocation) + public + validateShareInvariants + { + percentAllocation.percentageNumber = bound(percentAllocation.percentageNumber, 5, 89); + percentAllocation.decimalPlaces = bound(percentAllocation.decimalPlaces, 0, 10); + + testFuzz_AddWalletShare(percentAllocation); + + uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); + + // uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); + (uint256 bobWalletSharesBefore,,) = pushStaking.walletShareInfo(actor.bob_channel_owner); + uint256 walletTotalSharesForCalc = walletTotalSharesBefore - bobWalletSharesBefore; + + roll(epochDuration + 1); + + GenericTypes.Percentage memory newPercentAllocation = GenericTypes.Percentage({ + percentageNumber: percentAllocation.percentageNumber + 10, + decimalPlaces: percentAllocation.decimalPlaces + }); + + uint expectedSharesOfBob = (newPercentAllocation.percentageNumber * walletTotalSharesForCalc) + / ((100 * (10 ** newPercentAllocation.decimalPlaces)) - newPercentAllocation.percentageNumber); + + vm.expectEmit(true, true, false, false); + emit NewSharesIssued(actor.bob_channel_owner, expectedSharesOfBob); + pushStaking.addWalletShare(actor.bob_channel_owner, newPercentAllocation); + + (uint256 bobWalletSharesAfter, uint256 bobStakedBlockAfter, uint256 bobClaimedBlockAfter) = + pushStaking.walletShareInfo(actor.bob_channel_owner); + + uint256 walletTotalSharesAfter = pushStaking.WALLET_TOTAL_SHARES(); + uint256 epochToTotalSharesAfter = pushStaking.epochToTotalShares(getCurrentEpoch()); + assertEq(walletTotalSharesAfter, expectedSharesOfBob + walletTotalSharesForCalc); + assertEq(epochToTotalSharesAfter, expectedSharesOfBob + walletTotalSharesForCalc); + + assertEq(bobWalletSharesAfter, expectedSharesOfBob); + assertEq(bobStakedBlockAfter, block.number); + assertEq(bobClaimedBlockAfter, pushStaking.genesisEpoch()); + + // INVARIANT: wallet total shares should never be reduced after a function call + assertLe(walletTotalSharesBefore, walletTotalSharesAfter); + // INVARIANT: epochToTotalShares in any epoch should not exceed total wallet shares + assertLe(epochToTotalSharesAfter, walletTotalSharesAfter); + } +} diff --git a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol index fcebd0fc..7388d8a0 100644 --- a/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol +++ b/test/PushStaking/WalletSharesStaking/unit_tests/DecreaseWalletShare/DecreaseWalletShare.t.sol @@ -105,11 +105,11 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocationFifty); pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocationFifty); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); roll(epochDuration * 2); addPool(1000); uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); (uint256 charlieWalletSharesBefore, , uint256 charlieClaimedBlockBefore) = pushStaking.walletShareInfo(actor.charlie_channel_owner); (uint256 bobWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); @@ -127,12 +127,12 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { (uint256 bobWalletSharesAfter, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 foundationWalletSharesAfter, , ) = pushStaking.walletShareInfo(actor.admin); - assertEq(charlieWalletSharesAfter, expectedCharlieShares); + assertEq(charlieWalletSharesAfter, expectedCharlieShares,"Charlie"); assertEq(bobWalletSharesBefore, bobWalletSharesAfter,"bob shares"); assertEq(expectedCharlieShares, pushStaking.getEpochToWalletShare(actor.charlie_channel_owner,2),"E2TW"); - assertEq(walletTotalSharesBefore, walletTotalSharesAfter); - assertEq(epochToTotalSharesBefore, epochToTotalSharesAfter); - assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + (charlieWalletSharesBefore - charlieWalletSharesAfter)); + assertEq(walletTotalSharesBefore, walletTotalSharesAfter,"Total"); + assertEq(epochToTotalSharesBefore, epochToTotalSharesAfter,"EtT"); + assertEq(foundationWalletSharesAfter, foundationWalletSharesBefore + (charlieWalletSharesBefore - charlieWalletSharesAfter),"Combine"); assertEq(charlieClaimedBlockAfter, charlieClaimedBlockBefore,"charlie claimed block"); } @@ -149,17 +149,17 @@ contract DecreaseWalletShareTest is BaseWalletSharesStaking { pushStaking.addWalletShare(actor.charlie_channel_owner, percentAllocation30); pushStaking.addWalletShare(actor.bob_channel_owner, percentAllocation20); + uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); roll(epochDuration * 2); addPool(1000); uint256 walletTotalSharesBefore = pushStaking.WALLET_TOTAL_SHARES(); - uint256 epochToTotalSharesBefore = pushStaking.epochToTotalShares(getCurrentEpoch()); (uint256 charlieWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.charlie_channel_owner); (uint256 bobWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.bob_channel_owner); (uint256 aliceWalletSharesBefore, ,) = pushStaking.walletShareInfo(actor.alice_channel_owner); (uint256 foundationWalletSharesBefore, , ) = pushStaking.walletShareInfo(actor.admin); - // Decrease wallet shares of charlie from 50 to 40% + // Decrease wallet shares of charlie from 20 to 10% GenericTypes.Percentage memory newPercentAllocation = GenericTypes.Percentage({ percentageNumber: 10, decimalPlaces: 0 }); uint256 expectedBobShares = (newPercentAllocation.percentageNumber * walletTotalSharesBefore) / 100; vm.expectEmit(true,true, false, true);