From 7e5551506310cd4c4bc53f57e97f3bfb4afaa641 Mon Sep 17 00:00:00 2001 From: sascha Date: Mon, 4 Aug 2025 23:00:31 +0200 Subject: [PATCH] Commented out stuff to pause functions --- contracts/base_paca.sol | 727 ++++++++++++++++++------------------ contracts/bsc_paca.sol | 704 +++++++++++++++++------------------ contracts/sonic_paca.sol | 775 +++++++++++++++++++++------------------ 3 files changed, 1127 insertions(+), 1079 deletions(-) diff --git a/contracts/base_paca.sol b/contracts/base_paca.sol index cb349eb..92bff8f 100644 --- a/contracts/base_paca.sol +++ b/contracts/base_paca.sol @@ -553,101 +553,101 @@ contract PacaFinanceWithBoostAndScheduleBase is Initializable, ReentrancyGuardUp // emit StakeSaleCancelled(_seller, _stakeId); // } - function createStake(uint256 _amount) external { - // Scale up for wei comparison, USDC is 1e6 - if (_amount * 1e12 <= minStakeLock) revert AmountBelowMinimum(); + // function createStake(uint256 _amount) external { + // // Scale up for wei comparison, USDC is 1e6 + // if (_amount * 1e12 <= minStakeLock) revert AmountBelowMinimum(); - // Transfer tokens from the user into the contract - IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); + // // Transfer tokens from the user into the contract + // IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // Default logic, restake = false - finalRewardRate = getUserRewardRate(msg.sender, false); - } + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // Default logic, restake = false + // finalRewardRate = getUserRewardRate(msg.sender, false); + // } - // Create the stake - stakes[msg.sender].push(Stake({ - amount: _amount, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // // Create the stake + // stakes[msg.sender].push(Stake({ + // amount: _amount, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - // Update total staked - pool.totalStaked += _amount; + // // Update total staked + // pool.totalStaked += _amount; - emit Staked(msg.sender, _amount); - } + // emit Staked(msg.sender, _amount); + // } - /// @notice Restake an expired stake with a bonus daily reward - function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external { - if (_restakePercentage > 100) revert InvalidRestakePercentage(); - Stake storage stake = stakes[msg.sender][_stakeIndex]; - // Ensure there is a stake to claim - if (stake.amount == 0) revert NothingToClaim(); - if (block.timestamp < stake.unlockTime) revert StakeLocked(); + // /// @notice Restake an expired stake with a bonus daily reward + // function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external { + // if (_restakePercentage > 100) revert InvalidRestakePercentage(); + // Stake storage stake = stakes[msg.sender][_stakeIndex]; + // // Ensure there is a stake to claim + // if (stake.amount == 0) revert NothingToClaim(); + // if (block.timestamp < stake.unlockTime) revert StakeLocked(); - uint256 _amount = stake.amount; - uint rewards = getPoolRewards(msg.sender, _stakeIndex); - _amount = _amount + rewards; + // uint256 _amount = stake.amount; + // uint rewards = getPoolRewards(msg.sender, _stakeIndex); + // _amount = _amount + rewards; - uint256 restake_amount = (_amount * _restakePercentage) / 100; - uint256 withdraw_amount = _amount - restake_amount; + // uint256 restake_amount = (_amount * _restakePercentage) / 100; + // uint256 withdraw_amount = _amount - restake_amount; - // Update state before external calls - stake.amount = 0; - stake.complete = true; + // // Update state before external calls + // stake.amount = 0; + // stake.complete = true; - // Process withdraw - if (withdraw_amount > 0) { - withdrawLiabilities += withdraw_amount; + // // Process withdraw + // if (withdraw_amount > 0) { + // withdrawLiabilities += withdraw_amount; - if (pool.totalStaked >= withdraw_amount) { - pool.totalStaked -= withdraw_amount; - } else { - pool.totalStaked = 0; - } - // Create temporary the stake for the user to delay withdraw - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _stakeIndex, - amount: withdraw_amount, - unlockTime: block.timestamp + unlockDelay - })); + // if (pool.totalStaked >= withdraw_amount) { + // pool.totalStaked -= withdraw_amount; + // } else { + // pool.totalStaked = 0; + // } + // // Create temporary the stake for the user to delay withdraw + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _stakeIndex, + // amount: withdraw_amount, + // unlockTime: block.timestamp + unlockDelay + // })); - // Emit a detailed event - emit RewardClaimed(msg.sender, withdraw_amount); + // // Emit a detailed event + // emit RewardClaimed(msg.sender, withdraw_amount); - } - // Process restake - if (restake_amount > 0) { - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // restake = true - finalRewardRate = getUserRewardRate(msg.sender, true); - } + // } + // // Process restake + // if (restake_amount > 0) { + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // restake = true + // finalRewardRate = getUserRewardRate(msg.sender, true); + // } - stakes[msg.sender].push(Stake({ - amount: restake_amount, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // stakes[msg.sender].push(Stake({ + // amount: restake_amount, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - emit Staked(msg.sender, restake_amount); - } - } + // emit Staked(msg.sender, restake_amount); + // } + // } function createStakeForUser(address _user, uint256 _amount) external onlyOwner { if (_amount == 0) revert InvalidAmount(); @@ -712,222 +712,222 @@ contract PacaFinanceWithBoostAndScheduleBase is Initializable, ReentrancyGuardUp return finalRewardRate; } - function claimRewards() external nonReentrant { - uint256 totalReward = 0; + // function claimRewards() external nonReentrant { + // uint256 totalReward = 0; - for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { - Stake storage stake = stakes[msg.sender][i]; - if (stake.amount > 0) { - uint rewards = getPoolRewards(msg.sender, i); - totalReward = totalReward + rewards; - stake.lastClaimed = block.timestamp; - } - } + // for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { + // Stake storage stake = stakes[msg.sender][i]; + // if (stake.amount > 0) { + // uint rewards = getPoolRewards(msg.sender, i); + // totalReward = totalReward + rewards; + // stake.lastClaimed = block.timestamp; + // } + // } - if (totalReward == 0) revert NothingToClaim(); - if (pool.totalRewards < totalReward) revert InsufficientRewards(); + // if (totalReward == 0) revert NothingToClaim(); + // if (pool.totalRewards < totalReward) revert InsufficientRewards(); - pool.totalRewards = pool.totalRewards - totalReward; - IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward); + // pool.totalRewards = pool.totalRewards - totalReward; + // IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward); - emit RewardClaimed(msg.sender, totalReward); - } + // emit RewardClaimed(msg.sender, totalReward); + // } - function claimStake(uint256 _stakeIndex) external nonReentrant { - // Ensure the stake index is valid - if (_stakeIndex >= stakes[msg.sender].length) revert InvalidStakeIndex(); + // function claimStake(uint256 _stakeIndex) external nonReentrant { + // // Ensure the stake index is valid + // if (_stakeIndex >= stakes[msg.sender].length) revert InvalidStakeIndex(); - // Load the stake - Stake storage stake = stakes[msg.sender][_stakeIndex]; - uint256 _amount = stake.amount; + // // Load the stake + // Stake storage stake = stakes[msg.sender][_stakeIndex]; + // uint256 _amount = stake.amount; - uint rewards = getPoolRewards(msg.sender, _stakeIndex); + // uint rewards = getPoolRewards(msg.sender, _stakeIndex); - _amount = _amount + rewards; + // _amount = _amount + rewards; - // Ensure there is a stake to claim - if (_amount == 0) revert NothingToClaim(); + // // Ensure there is a stake to claim + // if (_amount == 0) revert NothingToClaim(); - // Ensure the stake is unlocked (if using lockup periods) - if (block.timestamp < stake.unlockTime) revert StakeLocked(); + // // Ensure the stake is unlocked (if using lockup periods) + // if (block.timestamp < stake.unlockTime) revert StakeLocked(); - // Update state before external calls - stake.amount = 0; - stake.complete = true; - withdrawLiabilities += _amount; + // // Update state before external calls + // stake.amount = 0; + // stake.complete = true; + // withdrawLiabilities += _amount; - if (pool.totalStaked >= _amount) { - pool.totalStaked -= _amount; - } else { - pool.totalStaked = 0; - } + // if (pool.totalStaked >= _amount) { + // pool.totalStaked -= _amount; + // } else { + // pool.totalStaked = 0; + // } - // Create temporary the stake for the user to delay withdraw - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _stakeIndex, - amount: _amount, - unlockTime: block.timestamp + unlockDelay - })); + // // Create temporary the stake for the user to delay withdraw + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _stakeIndex, + // amount: _amount, + // unlockTime: block.timestamp + unlockDelay + // })); - // Emit a detailed event - emit RewardClaimed(msg.sender, _amount); - } + // // Emit a detailed event + // emit RewardClaimed(msg.sender, _amount); + // } -/** - * @notice Withdraw a staked amount after its unlock time has passed. - * @dev Locates the stake by `_stakeIndex`, checks that it's unlocked and non-zero, - * and transfers tokens to the caller. For vesting stakes (where `_stakeIndex` >= 1e6), - * the stored amount (in 1e18 decimals) is scaled to USDC's 1e6 decimals by dividing by 1e12. - * - * Requirements: - * - Caller must have at least one stake. - * - The stake must exist, be unlocked, and have a non-zero amount. - * - The contract must have sufficient token balance. - * - * @param _stakeIndex The identifier of the stake to withdraw. - */ -function withdraw(uint256 _stakeIndex) external nonReentrant { - WithdrawStake[] storage userStakes = withdrawStake[msg.sender]; - if (userStakes.length == 0) revert NoStakesAvailable(); - - for (uint256 i = 0; i < userStakes.length; ++i) { - WithdrawStake storage stake = userStakes[i]; - // Skip already withdrawn stakes (amount == 0) - if (stake.stakeId == _stakeIndex && stake.amount != 0) { - if (block.timestamp < stake.unlockTime) revert StakeLocked(); - - uint256 _amount = stake.amount; - - // Convert vesting stake amount to USDC decimals. - if (_stakeIndex >= 1e6) { - _amount = _amount / 1e12; - } - - uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this)); - if (poolBalance < _amount) revert InsufficientRewards(); - - // Update state before external calls - // withdrawLiabilities is in 1e18, deduct original amount - withdrawLiabilities -= stake.amount; - stake.amount = 0; - - // Transfer tokens - IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount); - emit StakeWithdrawn(msg.sender, _amount, _stakeIndex); - return; - } - } - - // Revert if no matching stake with non-zero amount was found - revert StakeNotFound(); -} +// /** +// * @notice Withdraw a staked amount after its unlock time has passed. +// * @dev Locates the stake by `_stakeIndex`, checks that it's unlocked and non-zero, +// * and transfers tokens to the caller. For vesting stakes (where `_stakeIndex` >= 1e6), +// * the stored amount (in 1e18 decimals) is scaled to USDC's 1e6 decimals by dividing by 1e12. +// * +// * Requirements: +// * - Caller must have at least one stake. +// * - The stake must exist, be unlocked, and have a non-zero amount. +// * - The contract must have sufficient token balance. +// * +// * @param _stakeIndex The identifier of the stake to withdraw. +// */ +// function withdraw(uint256 _stakeIndex) external nonReentrant { +// WithdrawStake[] storage userStakes = withdrawStake[msg.sender]; +// if (userStakes.length == 0) revert NoStakesAvailable(); +// +// for (uint256 i = 0; i < userStakes.length; ++i) { +// WithdrawStake storage stake = userStakes[i]; +// // Skip already withdrawn stakes (amount == 0) +// if (stake.stakeId == _stakeIndex && stake.amount != 0) { +// if (block.timestamp < stake.unlockTime) revert StakeLocked(); +// +// uint256 _amount = stake.amount; +// +// // Convert vesting stake amount to USDC decimals. +// if (_stakeIndex >= 1e6) { +// _amount = _amount / 1e12; +// } +// +// uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this)); +// if (poolBalance < _amount) revert InsufficientRewards(); +// +// // Update state before external calls +// // withdrawLiabilities is in 1e18, deduct original amount +// withdrawLiabilities -= stake.amount; +// stake.amount = 0; +// +// // Transfer tokens +// IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount); +// emit StakeWithdrawn(msg.sender, _amount, _stakeIndex); +// return; +// } +// } +// +// // Revert if no matching stake with non-zero amount was found +// revert StakeNotFound(); +// } -/** - * @notice Withdraws vesting tokens after cooldown period - * @param _vestingId The vesting ID to withdraw - */ -function withdrawVestingToken(uint256 _vestingId) external nonReentrant { - WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender]; - if (userVestings.length == 0) revert NoStakesAvailable(); - - for (uint256 i = 0; i < userVestings.length; ++i) { - WithdrawVesting storage vestingWithdraw = userVestings[i]; - if (vestingWithdraw.vestingId == _vestingId && vestingWithdraw.amount != 0) { - if (block.timestamp < vestingWithdraw.unlockTime) revert StakeLocked(); - - uint256 _amount = vestingWithdraw.amount; - address _token = vestingWithdraw.token; - - // Check contract has sufficient balance - uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); - if (tokenBalance < _amount) revert InsufficientRewards(); - - // Update state before external calls - vestingWithdraw.amount = 0; - - // Decrement withdraw vesting liabilities for this token - withdrawVestingLiabilities[_token] -= _amount; - - // Transfer tokens - IERC20(_token).safeTransfer(msg.sender, _amount); - emit StakeWithdrawn(msg.sender, _amount, _vestingId); - return; - } - } - - revert StakeNotFound(); -} +// /** +// * @notice Withdraws vesting tokens after cooldown period +// * @param _vestingId The vesting ID to withdraw +// */ +// function withdrawVestingToken(uint256 _vestingId) external nonReentrant { +// WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender]; +// if (userVestings.length == 0) revert NoStakesAvailable(); +// +// for (uint256 i = 0; i < userVestings.length; ++i) { +// WithdrawVesting storage vestingWithdraw = userVestings[i]; +// if (vestingWithdraw.vestingId == _vestingId && vestingWithdraw.amount != 0) { +// if (block.timestamp < vestingWithdraw.unlockTime) revert StakeLocked(); +// +// uint256 _amount = vestingWithdraw.amount; +// address _token = vestingWithdraw.token; +// +// // Check contract has sufficient balance +// uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); +// if (tokenBalance < _amount) revert InsufficientRewards(); +// +// // Update state before external calls +// vestingWithdraw.amount = 0; +// +// // Decrement withdraw vesting liabilities for this token +// withdrawVestingLiabilities[_token] -= _amount; +// +// // Transfer tokens +// IERC20(_token).safeTransfer(msg.sender, _amount); +// emit StakeWithdrawn(msg.sender, _amount, _vestingId); +// return; +// } +// } +// +// revert StakeNotFound(); +// } - function compoundAllRewards() external { - uint256 totalReward = 0; + // function compoundAllRewards() external { + // uint256 totalReward = 0; - for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { - Stake storage stake = stakes[msg.sender][i]; - if (stake.amount > 0) { - uint rewards = getPoolRewards(msg.sender, i); - totalReward = totalReward + rewards; - stake.lastClaimed = block.timestamp; - } - } + // for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { + // Stake storage stake = stakes[msg.sender][i]; + // if (stake.amount > 0) { + // uint rewards = getPoolRewards(msg.sender, i); + // totalReward = totalReward + rewards; + // stake.lastClaimed = block.timestamp; + // } + // } - if (totalReward <= minStakeLock) revert NotEnoughToCompound(); - - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // Default logic, restake = false - finalRewardRate = getUserRewardRate(msg.sender, false); - } + // if (totalReward <= minStakeLock) revert NotEnoughToCompound(); + // + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // Default logic, restake = false + // finalRewardRate = getUserRewardRate(msg.sender, false); + // } - stakes[msg.sender].push(Stake({ - amount: totalReward, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // stakes[msg.sender].push(Stake({ + // amount: totalReward, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - pool.totalStaked = pool.totalStaked + totalReward; - emit CompoundRewards(msg.sender, totalReward); - } + // pool.totalStaked = pool.totalStaked + totalReward; + // emit CompoundRewards(msg.sender, totalReward); + // } - function createVesting(address _token, uint256 _amount) external { - if (_amount == 0) revert InvalidAmount(); - address oracle = priceOracles[_token]; - if (oracle == address(0)) revert PriceOracleNotSet(); - IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); + // function createVesting(address _token, uint256 _amount) external { + // if (_amount == 0) revert InvalidAmount(); + // address oracle = priceOracles[_token]; + // if (oracle == address(0)) revert PriceOracleNotSet(); + // IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); - uint256 bonus = (_amount * BONUS_PERCENTAGE) / 100; + // uint256 bonus = (_amount * BONUS_PERCENTAGE) / 100; - uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18; - if (usdPrice <= minStakeLock) revert AmountBelowMinimum(); + // uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18; + // if (usdPrice <= minStakeLock) revert AmountBelowMinimum(); - // Update user's dollarsVested - dollarsVested[msg.sender] += usdPrice; - // Update token's vestedTotal - vestedTotal[_token] += _amount; + // // Update user's dollarsVested + // dollarsVested[msg.sender] += usdPrice; + // // Update token's vestedTotal + // vestedTotal[_token] += _amount; - vestings[msg.sender].push(Vesting({ - amount: _amount, - bonus: bonus, - lockedUntil: block.timestamp + lockupDuration, - claimedAmount: 0, - claimedBonus: 0, - lastClaimed: block.timestamp, - createdAt: block.timestamp, - token: _token, - complete: false, - usdAmount: usdPrice - })); + // vestings[msg.sender].push(Vesting({ + // amount: _amount, + // bonus: bonus, + // lockedUntil: block.timestamp + lockupDuration, + // claimedAmount: 0, + // claimedBonus: 0, + // lastClaimed: block.timestamp, + // createdAt: block.timestamp, + // token: _token, + // complete: false, + // usdAmount: usdPrice + // })); - emit VestingCreated(msg.sender, _amount, bonus); - } + // emit VestingCreated(msg.sender, _amount, bonus); + // } function getUnlockedVesting(address _user, uint256 _vestingIndex) public view returns (uint256) { Vesting storage vesting = vestings[_user][_vestingIndex]; @@ -990,124 +990,124 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant { } - function claimVesting(uint256 _vestingIndex) external nonReentrant { - Vesting storage vesting = vestings[msg.sender][_vestingIndex]; - if (vesting.complete) revert StakeComplete(); - uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex); + // function claimVesting(uint256 _vestingIndex) external nonReentrant { + // Vesting storage vesting = vestings[msg.sender][_vestingIndex]; + // if (vesting.complete) revert StakeComplete(); + // uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex); - if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); - uint256 amountToClaim = maxClaim - vesting.claimedAmount; - if (amountToClaim == 0) revert NothingToClaim(); + // if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); + // uint256 amountToClaim = maxClaim - vesting.claimedAmount; + // if (amountToClaim == 0) revert NothingToClaim(); - vesting.claimedAmount = vesting.claimedAmount + amountToClaim; - if (vesting.claimedAmount >= vesting.amount) { - vesting.complete = true; - } - // Update user's dollarsVested - if (dollarsVested[msg.sender] > 0) { - uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18; - if (usdPrice >= dollarsVested[msg.sender]) { - dollarsVested[msg.sender] = 0; - } else { - dollarsVested[msg.sender] -= usdPrice; - } - } - vestedTotal[vesting.token] -= amountToClaim; - - // Add vesting claims to cooldown queue - withdrawVestingActual[msg.sender].push(WithdrawVesting({ - vestingId: withdrawVestingCounterActual++, - amount: amountToClaim, - unlockTime: block.timestamp + unlockDelay, - token: vesting.token - })); - - // Increment withdraw vesting liabilities for this token - withdrawVestingLiabilities[vesting.token] += amountToClaim; + // vesting.claimedAmount = vesting.claimedAmount + amountToClaim; + // if (vesting.claimedAmount >= vesting.amount) { + // vesting.complete = true; + // } + // // Update user's dollarsVested + // if (dollarsVested[msg.sender] > 0) { + // uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18; + // if (usdPrice >= dollarsVested[msg.sender]) { + // dollarsVested[msg.sender] = 0; + // } else { + // dollarsVested[msg.sender] -= usdPrice; + // } + // } + // vestedTotal[vesting.token] -= amountToClaim; + // + // // Add vesting claims to cooldown queue + // withdrawVestingActual[msg.sender].push(WithdrawVesting({ + // vestingId: withdrawVestingCounterActual++, + // amount: amountToClaim, + // unlockTime: block.timestamp + unlockDelay, + // token: vesting.token + // })); + // + // // Increment withdraw vesting liabilities for this token + // withdrawVestingLiabilities[vesting.token] += amountToClaim; - emit VestingClaimed(msg.sender, amountToClaim, 0); - } + // emit VestingClaimed(msg.sender, amountToClaim, 0); + // } - function claimAllVestingByToken(address _token) external nonReentrant { - uint256 totalReward = 0; - uint256 vestingsProcessed = 0; + // function claimAllVestingByToken(address _token) external nonReentrant { + // uint256 totalReward = 0; + // uint256 vestingsProcessed = 0; - for (uint256 i = 0; i < vestings[msg.sender].length; ++i) { - Vesting storage vesting = vestings[msg.sender][i]; + // for (uint256 i = 0; i < vestings[msg.sender].length; ++i) { + // Vesting storage vesting = vestings[msg.sender][i]; - if (vesting.token == _token && !vesting.complete) { - uint256 maxClaim = getUnlockedVesting(msg.sender, i); - if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); + // if (vesting.token == _token && !vesting.complete) { + // uint256 maxClaim = getUnlockedVesting(msg.sender, i); + // if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); - uint256 amountToClaim = maxClaim - vesting.claimedAmount; - if (amountToClaim > 0) { - vesting.claimedAmount = vesting.claimedAmount + amountToClaim; - totalReward = totalReward + amountToClaim; - vesting.lastClaimed = block.timestamp; + // uint256 amountToClaim = maxClaim - vesting.claimedAmount; + // if (amountToClaim > 0) { + // vesting.claimedAmount = vesting.claimedAmount + amountToClaim; + // totalReward = totalReward + amountToClaim; + // vesting.lastClaimed = block.timestamp; - // Mark vesting as complete if fully claimed - if (vesting.claimedAmount >= vesting.amount) { - vesting.complete = true; - } + // // Mark vesting as complete if fully claimed + // if (vesting.claimedAmount >= vesting.amount) { + // vesting.complete = true; + // } - vestingsProcessed++; - } - } - } + // vestingsProcessed++; + // } + // } + // } - if (totalReward == 0) revert NothingToClaim(); + // if (totalReward == 0) revert NothingToClaim(); - // Update user's dollarsVested - if (dollarsVested[msg.sender] > 0) { - uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18; - if (usdPrice >= dollarsVested[msg.sender]) { - dollarsVested[msg.sender] = 0; - } else { - dollarsVested[msg.sender] -= usdPrice; - } - } + // // Update user's dollarsVested + // if (dollarsVested[msg.sender] > 0) { + // uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18; + // if (usdPrice >= dollarsVested[msg.sender]) { + // dollarsVested[msg.sender] = 0; + // } else { + // dollarsVested[msg.sender] -= usdPrice; + // } + // } - // Update vesting total - vestedTotal[_token] -= totalReward; - - // Add vesting claims to cooldown queue - withdrawVestingActual[msg.sender].push(WithdrawVesting({ - vestingId: withdrawVestingCounterActual++, - amount: totalReward, - unlockTime: block.timestamp + unlockDelay, - token: _token - })); - - // Increment withdraw vesting liabilities for this token - withdrawVestingLiabilities[_token] += totalReward; + // // Update vesting total + // vestedTotal[_token] -= totalReward; + // + // // Add vesting claims to cooldown queue + // withdrawVestingActual[msg.sender].push(WithdrawVesting({ + // vestingId: withdrawVestingCounterActual++, + // amount: totalReward, + // unlockTime: block.timestamp + unlockDelay, + // token: _token + // })); + // + // // Increment withdraw vesting liabilities for this token + // withdrawVestingLiabilities[_token] += totalReward; - emit RewardClaimed(msg.sender, totalReward); - } + // emit RewardClaimed(msg.sender, totalReward); + // } - function claimBonus(uint256 _vestingIndex) external nonReentrant { - Vesting storage vesting = vestings[msg.sender][_vestingIndex]; - uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex); + // function claimBonus(uint256 _vestingIndex) external nonReentrant { + // Vesting storage vesting = vestings[msg.sender][_vestingIndex]; + // uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex); - if (maxBonus < vesting.claimedBonus) revert InvalidClaimAmount(); - uint256 bonusToClaim = maxBonus - vesting.claimedBonus; - if (bonusToClaim == 0) revert NothingToClaim(); + // if (maxBonus < vesting.claimedBonus) revert InvalidClaimAmount(); + // uint256 bonusToClaim = maxBonus - vesting.claimedBonus; + // if (bonusToClaim == 0) revert NothingToClaim(); - vesting.claimedBonus = vesting.claimedBonus + bonusToClaim; - withdrawLiabilities += bonusToClaim; + // vesting.claimedBonus = vesting.claimedBonus + bonusToClaim; + // withdrawLiabilities += bonusToClaim; - // IERC20(vesting.token).safeTransfer(msg.sender, bonusToClaim); + // // IERC20(vesting.token).safeTransfer(msg.sender, bonusToClaim); - // Create temporary the stake for the user to delay withdraw. - // Add 1e6 to the vesting index to distinguish them from normal stakes. - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _vestingIndex + 1e6, - amount: bonusToClaim, - unlockTime: block.timestamp + unlockDelay - })); + // // Create temporary the stake for the user to delay withdraw. + // // Add 1e6 to the vesting index to distinguish them from normal stakes. + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _vestingIndex + 1e6, + // amount: bonusToClaim, + // unlockTime: block.timestamp + unlockDelay + // })); - emit BonusClaimed(msg.sender, bonusToClaim); - } + // emit BonusClaimed(msg.sender, bonusToClaim); + // } function setPriceOracle(address _token, address _oracle) external onlyOwner { priceOracles[_token] = _oracle; @@ -1265,7 +1265,6 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant { } - /// @notice Function to put a stake for sale. /// Sets the original stake amount to 0 to prevent any alterations while for sale. /// @param _stakeId The stake to sell. diff --git a/contracts/bsc_paca.sol b/contracts/bsc_paca.sol index f7abaef..7d0973f 100644 --- a/contracts/bsc_paca.sol +++ b/contracts/bsc_paca.sol @@ -553,100 +553,100 @@ contract PacaFinanceWithBoostAndScheduleBsc is Initializable, ReentrancyGuardUpg // emit StakeSaleCancelled(_seller, _stakeId); // } - function createStake(uint256 _amount) external { - if (_amount <= minStakeLock) revert AmountBelowMinimum(); + // function createStake(uint256 _amount) external { + // if (_amount <= minStakeLock) revert AmountBelowMinimum(); - // Transfer tokens from the user into the contract - IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); + // // Transfer tokens from the user into the contract + // IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // Default logic, restake = false - finalRewardRate = getUserRewardRate(msg.sender, false); - } + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // Default logic, restake = false + // finalRewardRate = getUserRewardRate(msg.sender, false); + // } - // Create the stake - stakes[msg.sender].push(Stake({ - amount: _amount, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // // Create the stake + // stakes[msg.sender].push(Stake({ + // amount: _amount, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - // Update total staked - pool.totalStaked += _amount; + // // Update total staked + // pool.totalStaked += _amount; - emit Staked(msg.sender, _amount); - } + // emit Staked(msg.sender, _amount); + // } - /// @notice Restake an expired stake with a bonus daily reward - function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external { - if (_restakePercentage > 100) revert InvalidRestakePercentage(); - Stake storage stake = stakes[msg.sender][_stakeIndex]; - // Ensure there is a stake to claim - if (stake.amount == 0) revert NothingToClaim(); - if (block.timestamp < stake.unlockTime) revert StakeLocked(); + // /// @notice Restake an expired stake with a bonus daily reward + // function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external { + // if (_restakePercentage > 100) revert InvalidRestakePercentage(); + // Stake storage stake = stakes[msg.sender][_stakeIndex]; + // // Ensure there is a stake to claim + // if (stake.amount == 0) revert NothingToClaim(); + // if (block.timestamp < stake.unlockTime) revert StakeLocked(); - uint256 _amount = stake.amount; - uint rewards = getPoolRewards(msg.sender, _stakeIndex); - _amount = _amount + rewards; + // uint256 _amount = stake.amount; + // uint rewards = getPoolRewards(msg.sender, _stakeIndex); + // _amount = _amount + rewards; - uint256 restake_amount = (_amount * _restakePercentage) / 100; - uint256 withdraw_amount = _amount - restake_amount; + // uint256 restake_amount = (_amount * _restakePercentage) / 100; + // uint256 withdraw_amount = _amount - restake_amount; - // Update state before external calls - stake.amount = 0; - stake.complete = true; + // // Update state before external calls + // stake.amount = 0; + // stake.complete = true; - // Process withdraw - if (withdraw_amount > 0) { - withdrawLiabilities += withdraw_amount; + // // Process withdraw + // if (withdraw_amount > 0) { + // withdrawLiabilities += withdraw_amount; - if (pool.totalStaked >= withdraw_amount) { - pool.totalStaked -= withdraw_amount; - } else { - pool.totalStaked = 0; - } - // Create temporary the stake for the user to delay withdraw - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _stakeIndex, - amount: withdraw_amount, - unlockTime: block.timestamp + unlockDelay - })); + // if (pool.totalStaked >= withdraw_amount) { + // pool.totalStaked -= withdraw_amount; + // } else { + // pool.totalStaked = 0; + // } + // // Create temporary the stake for the user to delay withdraw + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _stakeIndex, + // amount: withdraw_amount, + // unlockTime: block.timestamp + unlockDelay + // })); - // Emit a detailed event - emit RewardClaimed(msg.sender, withdraw_amount); + // // Emit a detailed event + // emit RewardClaimed(msg.sender, withdraw_amount); - } - // Process restake - if (restake_amount > 0) { - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // restake = true - finalRewardRate = getUserRewardRate(msg.sender, true); - } + // } + // // Process restake + // if (restake_amount > 0) { + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // restake = true + // finalRewardRate = getUserRewardRate(msg.sender, true); + // } - stakes[msg.sender].push(Stake({ - amount: restake_amount, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // stakes[msg.sender].push(Stake({ + // amount: restake_amount, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - emit Staked(msg.sender, restake_amount); - } - } + // emit Staked(msg.sender, restake_amount); + // } + // } function createStakeForUser(address _user, uint256 _amount) external onlyOwner { if (_amount == 0) revert InvalidAmount(); @@ -711,213 +711,213 @@ contract PacaFinanceWithBoostAndScheduleBsc is Initializable, ReentrancyGuardUpg return finalRewardRate; } - function claimRewards() external nonReentrant { - uint256 totalReward = 0; + // function claimRewards() external nonReentrant { + // uint256 totalReward = 0; - for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { - Stake storage stake = stakes[msg.sender][i]; - if (stake.amount > 0) { - uint rewards = getPoolRewards(msg.sender, i); - totalReward = totalReward + rewards; - stake.lastClaimed = block.timestamp; - } - } + // for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { + // Stake storage stake = stakes[msg.sender][i]; + // if (stake.amount > 0) { + // uint rewards = getPoolRewards(msg.sender, i); + // totalReward = totalReward + rewards; + // stake.lastClaimed = block.timestamp; + // } + // } - if (totalReward == 0) revert NothingToClaim(); - if (pool.totalRewards < totalReward) revert InsufficientRewards(); + // if (totalReward == 0) revert NothingToClaim(); + // if (pool.totalRewards < totalReward) revert InsufficientRewards(); - pool.totalRewards = pool.totalRewards - totalReward; - IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward); + // pool.totalRewards = pool.totalRewards - totalReward; + // IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward); - emit RewardClaimed(msg.sender, totalReward); - } + // emit RewardClaimed(msg.sender, totalReward); + // } - function claimStake(uint256 _stakeIndex) external nonReentrant { - // Ensure the stake index is valid - if (_stakeIndex >= stakes[msg.sender].length) revert InvalidStakeIndex(); + // function claimStake(uint256 _stakeIndex) external nonReentrant { + // // Ensure the stake index is valid + // if (_stakeIndex >= stakes[msg.sender].length) revert InvalidStakeIndex(); - // Load the stake - Stake storage stake = stakes[msg.sender][_stakeIndex]; - uint256 _amount = stake.amount; + // // Load the stake + // Stake storage stake = stakes[msg.sender][_stakeIndex]; + // uint256 _amount = stake.amount; - uint rewards = getPoolRewards(msg.sender, _stakeIndex); + // uint rewards = getPoolRewards(msg.sender, _stakeIndex); - _amount = _amount + rewards; + // _amount = _amount + rewards; - // Ensure there is a stake to claim - if (_amount == 0) revert NothingToClaim(); + // // Ensure there is a stake to claim + // if (_amount == 0) revert NothingToClaim(); - // Ensure the stake is unlocked (if using lockup periods) - if (block.timestamp < stake.unlockTime) revert StakeLocked(); + // // Ensure the stake is unlocked (if using lockup periods) + // if (block.timestamp < stake.unlockTime) revert StakeLocked(); - // Update state before external calls - stake.amount = 0; - stake.complete = true; - withdrawLiabilities += _amount; + // // Update state before external calls + // stake.amount = 0; + // stake.complete = true; + // withdrawLiabilities += _amount; - if (pool.totalStaked >= _amount) { - pool.totalStaked -= _amount; - } else { - pool.totalStaked = 0; - } + // if (pool.totalStaked >= _amount) { + // pool.totalStaked -= _amount; + // } else { + // pool.totalStaked = 0; + // } - // Create temporary the stake for the user to delay withdraw - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _stakeIndex, - amount: _amount, - unlockTime: block.timestamp + unlockDelay - })); + // // Create temporary the stake for the user to delay withdraw + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _stakeIndex, + // amount: _amount, + // unlockTime: block.timestamp + unlockDelay + // })); - // Emit a detailed event - emit RewardClaimed(msg.sender, _amount); - } + // // Emit a detailed event + // emit RewardClaimed(msg.sender, _amount); + // } - /** - * @notice Withdraw a staked amount after its unlock time has passed. - * @dev Locates the stake by `_stakeIndex`, checks that it's unlocked and non-zero, - * and transfers tokens to the caller. - * - * Requirements: - * - Caller must have at least one stake. - * - The stake must exist, be unlocked, and have a non-zero amount. - * - The contract must have sufficient token balance. - * - * @param _stakeIndex The identifier of the stake to withdraw. - */ - function withdraw(uint256 _stakeIndex) external nonReentrant { - WithdrawStake[] storage userStakes = withdrawStake[msg.sender]; - if (userStakes.length == 0) revert NoStakesAvailable(); - - for (uint256 i = 0; i < userStakes.length; ++i) { - WithdrawStake storage stake = userStakes[i]; - if (stake.stakeId == _stakeIndex && stake.amount != 0) { - if (block.timestamp < stake.unlockTime) revert StakeLocked(); - - uint256 _amount = stake.amount; - uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this)); - if (poolBalance < _amount) revert InsufficientRewards(); - - // Update state before external calls - withdrawLiabilities -= _amount; - stake.amount = 0; - - // Transfer tokens - IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount); - emit StakeWithdrawn(msg.sender, _amount, _stakeIndex); - return; - } - } - - // Revert if no matching stake with non-zero amount was found - revert StakeNotFound(); - } + // /** + // * @notice Withdraw a staked amount after its unlock time has passed. + // * @dev Locates the stake by `_stakeIndex`, checks that it's unlocked and non-zero, + // * and transfers tokens to the caller. + // * + // * Requirements: + // * - Caller must have at least one stake. + // * - The stake must exist, be unlocked, and have a non-zero amount. + // * - The contract must have sufficient token balance. + // * + // * @param _stakeIndex The identifier of the stake to withdraw. + // */ + // function withdraw(uint256 _stakeIndex) external nonReentrant { + // WithdrawStake[] storage userStakes = withdrawStake[msg.sender]; + // if (userStakes.length == 0) revert NoStakesAvailable(); + // + // for (uint256 i = 0; i < userStakes.length; ++i) { + // WithdrawStake storage stake = userStakes[i]; + // if (stake.stakeId == _stakeIndex && stake.amount != 0) { + // if (block.timestamp < stake.unlockTime) revert StakeLocked(); + // + // uint256 _amount = stake.amount; + // uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this)); + // if (poolBalance < _amount) revert InsufficientRewards(); + // + // // Update state before external calls + // withdrawLiabilities -= _amount; + // stake.amount = 0; + // + // // Transfer tokens + // IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount); + // emit StakeWithdrawn(msg.sender, _amount, _stakeIndex); + // return; + // } + // } + // + // // Revert if no matching stake with non-zero amount was found + // revert StakeNotFound(); + // } -/** - * @notice Withdraws vesting tokens after cooldown period - * @param _vestingId The vesting ID to withdraw - */ -function withdrawVestingToken(uint256 _vestingId) external nonReentrant { - WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender]; - if (userVestings.length == 0) revert NoStakesAvailable(); - - for (uint256 i = 0; i < userVestings.length; ++i) { - WithdrawVesting storage vestingWithdraw = userVestings[i]; - if (vestingWithdraw.vestingId == _vestingId && vestingWithdraw.amount != 0) { - if (block.timestamp < vestingWithdraw.unlockTime) revert StakeLocked(); - - uint256 _amount = vestingWithdraw.amount; - address _token = vestingWithdraw.token; - - // Check contract has sufficient balance - uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); - if (tokenBalance < _amount) revert InsufficientRewards(); - - // Update state before external calls - vestingWithdraw.amount = 0; - - // Decrement withdraw vesting liabilities for this token - withdrawVestingLiabilities[_token] -= _amount; - - // Transfer tokens - IERC20(_token).safeTransfer(msg.sender, _amount); - emit StakeWithdrawn(msg.sender, _amount, _vestingId); - return; - } - } - - revert StakeNotFound(); -} +// /** +// * @notice Withdraws vesting tokens after cooldown period +// * @param _vestingId The vesting ID to withdraw +// */ +// function withdrawVestingToken(uint256 _vestingId) external nonReentrant { +// WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender]; +// if (userVestings.length == 0) revert NoStakesAvailable(); +// +// for (uint256 i = 0; i < userVestings.length; ++i) { +// WithdrawVesting storage vestingWithdraw = userVestings[i]; +// if (vestingWithdraw.vestingId == _vestingId && vestingWithdraw.amount != 0) { +// if (block.timestamp < vestingWithdraw.unlockTime) revert StakeLocked(); +// +// uint256 _amount = vestingWithdraw.amount; +// address _token = vestingWithdraw.token; +// +// // Check contract has sufficient balance +// uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); +// if (tokenBalance < _amount) revert InsufficientRewards(); +// +// // Update state before external calls +// vestingWithdraw.amount = 0; +// +// // Decrement withdraw vesting liabilities for this token +// withdrawVestingLiabilities[_token] -= _amount; +// +// // Transfer tokens +// IERC20(_token).safeTransfer(msg.sender, _amount); +// emit StakeWithdrawn(msg.sender, _amount, _vestingId); +// return; +// } +// } +// +// revert StakeNotFound(); +// } - function compoundAllRewards() external { - uint256 totalReward = 0; + // function compoundAllRewards() external { + // uint256 totalReward = 0; - for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { - Stake storage stake = stakes[msg.sender][i]; - if (stake.amount > 0) { - uint rewards = getPoolRewards(msg.sender, i); - totalReward = totalReward + rewards; - stake.lastClaimed = block.timestamp; - } - } + // for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { + // Stake storage stake = stakes[msg.sender][i]; + // if (stake.amount > 0) { + // uint rewards = getPoolRewards(msg.sender, i); + // totalReward = totalReward + rewards; + // stake.lastClaimed = block.timestamp; + // } + // } - if (totalReward <= minStakeLock) revert NotEnoughToCompound(); + // if (totalReward <= minStakeLock) revert NotEnoughToCompound(); - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // Default logic, restake = false - finalRewardRate = getUserRewardRate(msg.sender, false); - } + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // Default logic, restake = false + // finalRewardRate = getUserRewardRate(msg.sender, false); + // } - stakes[msg.sender].push(Stake({ - amount: totalReward, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // stakes[msg.sender].push(Stake({ + // amount: totalReward, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - pool.totalStaked = pool.totalStaked + totalReward; - emit CompoundRewards(msg.sender, totalReward); - } + // pool.totalStaked = pool.totalStaked + totalReward; + // emit CompoundRewards(msg.sender, totalReward); + // } - function createVesting(address _token, uint256 _amount) external { - if (_amount == 0) revert InvalidAmount(); - address oracle = priceOracles[_token]; - if (oracle == address(0)) revert PriceOracleNotSet(); - IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); + // function createVesting(address _token, uint256 _amount) external { + // if (_amount == 0) revert InvalidAmount(); + // address oracle = priceOracles[_token]; + // if (oracle == address(0)) revert PriceOracleNotSet(); + // IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); - uint256 bonus = (_amount * BONUS_PERCENTAGE) / 100; + // uint256 bonus = (_amount * BONUS_PERCENTAGE) / 100; - uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18; - if (usdPrice <= minStakeLock) revert AmountBelowMinimum(); + // uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18; + // if (usdPrice <= minStakeLock) revert AmountBelowMinimum(); - // Update user's dollarsVested - dollarsVested[msg.sender] += usdPrice; - // Update token's vestedTotal - vestedTotal[_token] += _amount; + // // Update user's dollarsVested + // dollarsVested[msg.sender] += usdPrice; + // // Update token's vestedTotal + // vestedTotal[_token] += _amount; - vestings[msg.sender].push(Vesting({ - amount: _amount, - bonus: bonus, - lockedUntil: block.timestamp + lockupDuration, - claimedAmount: 0, - claimedBonus: 0, - lastClaimed: block.timestamp, - createdAt: block.timestamp, - token: _token, - complete: false, - usdAmount: usdPrice - })); + // vestings[msg.sender].push(Vesting({ + // amount: _amount, + // bonus: bonus, + // lockedUntil: block.timestamp + lockupDuration, + // claimedAmount: 0, + // claimedBonus: 0, + // lastClaimed: block.timestamp, + // createdAt: block.timestamp, + // token: _token, + // complete: false, + // usdAmount: usdPrice + // })); - emit VestingCreated(msg.sender, _amount, bonus); - } + // emit VestingCreated(msg.sender, _amount, bonus); + // } function getUnlockedVesting(address _user, uint256 _vestingIndex) public view returns (uint256) { Vesting storage vesting = vestings[_user][_vestingIndex]; @@ -980,124 +980,124 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant { } - function claimVesting(uint256 _vestingIndex) external nonReentrant { - Vesting storage vesting = vestings[msg.sender][_vestingIndex]; - if (vesting.complete) revert StakeComplete(); - uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex); + // function claimVesting(uint256 _vestingIndex) external nonReentrant { + // Vesting storage vesting = vestings[msg.sender][_vestingIndex]; + // if (vesting.complete) revert StakeComplete(); + // uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex); - if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); - uint256 amountToClaim = maxClaim - vesting.claimedAmount; - if (amountToClaim == 0) revert NothingToClaim(); + // if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); + // uint256 amountToClaim = maxClaim - vesting.claimedAmount; + // if (amountToClaim == 0) revert NothingToClaim(); - vesting.claimedAmount = vesting.claimedAmount + amountToClaim; - if (vesting.claimedAmount >= vesting.amount) { - vesting.complete = true; - } - // Update user's dollarsVested - if (dollarsVested[msg.sender] > 0) { - uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18; - if (usdPrice >= dollarsVested[msg.sender]) { - dollarsVested[msg.sender] = 0; - } else { - dollarsVested[msg.sender] -= usdPrice; - } - } - vestedTotal[vesting.token] -= amountToClaim; - - // Add vesting claims to cooldown queue - withdrawVestingActual[msg.sender].push(WithdrawVesting({ - vestingId: withdrawVestingCounterActual++, - amount: amountToClaim, - unlockTime: block.timestamp + unlockDelay, - token: vesting.token - })); - - // Increment withdraw vesting liabilities for this token - withdrawVestingLiabilities[vesting.token] += amountToClaim; + // vesting.claimedAmount = vesting.claimedAmount + amountToClaim; + // if (vesting.claimedAmount >= vesting.amount) { + // vesting.complete = true; + // } + // // Update user's dollarsVested + // if (dollarsVested[msg.sender] > 0) { + // uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18; + // if (usdPrice >= dollarsVested[msg.sender]) { + // dollarsVested[msg.sender] = 0; + // } else { + // dollarsVested[msg.sender] -= usdPrice; + // } + // } + // vestedTotal[vesting.token] -= amountToClaim; + // + // // Add vesting claims to cooldown queue + // withdrawVestingActual[msg.sender].push(WithdrawVesting({ + // vestingId: withdrawVestingCounterActual++, + // amount: amountToClaim, + // unlockTime: block.timestamp + unlockDelay, + // token: vesting.token + // })); + // + // // Increment withdraw vesting liabilities for this token + // withdrawVestingLiabilities[vesting.token] += amountToClaim; - emit VestingClaimed(msg.sender, amountToClaim, 0); - } + // emit VestingClaimed(msg.sender, amountToClaim, 0); + // } - function claimAllVestingByToken(address _token) external nonReentrant { - uint256 totalReward = 0; - uint256 vestingsProcessed = 0; + // function claimAllVestingByToken(address _token) external nonReentrant { + // uint256 totalReward = 0; + // uint256 vestingsProcessed = 0; - for (uint256 i = 0; i < vestings[msg.sender].length; ++i) { - Vesting storage vesting = vestings[msg.sender][i]; + // for (uint256 i = 0; i < vestings[msg.sender].length; ++i) { + // Vesting storage vesting = vestings[msg.sender][i]; - if (vesting.token == _token && !vesting.complete) { - uint256 maxClaim = getUnlockedVesting(msg.sender, i); - if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); + // if (vesting.token == _token && !vesting.complete) { + // uint256 maxClaim = getUnlockedVesting(msg.sender, i); + // if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); - uint256 amountToClaim = maxClaim - vesting.claimedAmount; - if (amountToClaim > 0) { - vesting.claimedAmount = vesting.claimedAmount + amountToClaim; - totalReward = totalReward + amountToClaim; - vesting.lastClaimed = block.timestamp; + // uint256 amountToClaim = maxClaim - vesting.claimedAmount; + // if (amountToClaim > 0) { + // vesting.claimedAmount = vesting.claimedAmount + amountToClaim; + // totalReward = totalReward + amountToClaim; + // vesting.lastClaimed = block.timestamp; - // Mark vesting as complete if fully claimed - if (vesting.claimedAmount >= vesting.amount) { - vesting.complete = true; - } + // // Mark vesting as complete if fully claimed + // if (vesting.claimedAmount >= vesting.amount) { + // vesting.complete = true; + // } - vestingsProcessed++; - } - } - } + // vestingsProcessed++; + // } + // } + // } - if (totalReward == 0) revert NothingToClaim(); + // if (totalReward == 0) revert NothingToClaim(); - // Update user's dollarsVested - if (dollarsVested[msg.sender] > 0) { - uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18; - if (usdPrice >= dollarsVested[msg.sender]) { - dollarsVested[msg.sender] = 0; - } else { - dollarsVested[msg.sender] -= usdPrice; - } - } + // // Update user's dollarsVested + // if (dollarsVested[msg.sender] > 0) { + // uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18; + // if (usdPrice >= dollarsVested[msg.sender]) { + // dollarsVested[msg.sender] = 0; + // } else { + // dollarsVested[msg.sender] -= usdPrice; + // } + // } - // Update vesting total - vestedTotal[_token] -= totalReward; - - // Add vesting claims to cooldown queue - withdrawVestingActual[msg.sender].push(WithdrawVesting({ - vestingId: withdrawVestingCounterActual++, - amount: totalReward, - unlockTime: block.timestamp + unlockDelay, - token: _token - })); - - // Increment withdraw vesting liabilities for this token - withdrawVestingLiabilities[_token] += totalReward; + // // Update vesting total + // vestedTotal[_token] -= totalReward; + // + // // Add vesting claims to cooldown queue + // withdrawVestingActual[msg.sender].push(WithdrawVesting({ + // vestingId: withdrawVestingCounterActual++, + // amount: totalReward, + // unlockTime: block.timestamp + unlockDelay, + // token: _token + // })); + // + // // Increment withdraw vesting liabilities for this token + // withdrawVestingLiabilities[_token] += totalReward; - emit RewardClaimed(msg.sender, totalReward); - } + // emit RewardClaimed(msg.sender, totalReward); + // } - function claimBonus(uint256 _vestingIndex) external nonReentrant { - Vesting storage vesting = vestings[msg.sender][_vestingIndex]; - uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex); + // function claimBonus(uint256 _vestingIndex) external nonReentrant { + // Vesting storage vesting = vestings[msg.sender][_vestingIndex]; + // uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex); - if (maxBonus < vesting.claimedBonus) revert InvalidClaimAmount(); - uint256 bonusToClaim = maxBonus - vesting.claimedBonus; - if (bonusToClaim == 0) revert NothingToClaim(); + // if (maxBonus < vesting.claimedBonus) revert InvalidClaimAmount(); + // uint256 bonusToClaim = maxBonus - vesting.claimedBonus; + // if (bonusToClaim == 0) revert NothingToClaim(); - vesting.claimedBonus = vesting.claimedBonus + bonusToClaim; - withdrawLiabilities += bonusToClaim; + // vesting.claimedBonus = vesting.claimedBonus + bonusToClaim; + // withdrawLiabilities += bonusToClaim; - // IERC20(vesting.token).safeTransfer(msg.sender, bonusToClaim); + // // IERC20(vesting.token).safeTransfer(msg.sender, bonusToClaim); - // Create temporary the stake for the user to delay withdraw. - // Add 1e6 to the vesting index to distinguish them from normal stakes. - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _vestingIndex + 1e6, - amount: bonusToClaim, - unlockTime: block.timestamp + unlockDelay - })); + // // Create temporary the stake for the user to delay withdraw. + // // Add 1e6 to the vesting index to distinguish them from normal stakes. + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _vestingIndex + 1e6, + // amount: bonusToClaim, + // unlockTime: block.timestamp + unlockDelay + // })); - emit BonusClaimed(msg.sender, bonusToClaim); - } + // emit BonusClaimed(msg.sender, bonusToClaim); + // } function setPriceOracle(address _token, address _oracle) external onlyOwner { priceOracles[_token] = _oracle; diff --git a/contracts/sonic_paca.sol b/contracts/sonic_paca.sol index a663d35..1b29560 100644 --- a/contracts/sonic_paca.sol +++ b/contracts/sonic_paca.sol @@ -556,101 +556,101 @@ contract PacaFinanceWithBoostAndScheduleSonic is Initializable, ReentrancyGuardU // emit StakeSaleCancelled(_seller, _stakeId); // } - function createStake(uint256 _amount) external { - // Scale up for wei comparison, USDC is 1e6 - if (_amount * 1e12 <= minStakeLock) revert AmountBelowMinimum(); + // function createStake(uint256 _amount) external { + // // Scale up for wei comparison, USDC is 1e6 + // if (_amount * 1e12 <= minStakeLock) revert AmountBelowMinimum(); - // Transfer tokens from the user into the contract - IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); + // // Transfer tokens from the user into the contract + // IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // Default logic, restake = false - finalRewardRate = getUserRewardRate(msg.sender, false); - } + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // Default logic, restake = false + // finalRewardRate = getUserRewardRate(msg.sender, false); + // } - // Create the stake - stakes[msg.sender].push(Stake({ - amount: _amount, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // // Create the stake + // stakes[msg.sender].push(Stake({ + // amount: _amount, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - // Update total staked - pool.totalStaked += _amount; + // // Update total staked + // pool.totalStaked += _amount; - emit Staked(msg.sender, _amount); - } + // emit Staked(msg.sender, _amount); + // } - /// @notice Restake an expired stake with a bonus daily reward - function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external { - if (_restakePercentage > 100) revert InvalidRestakePercentage(); - Stake storage stake = stakes[msg.sender][_stakeIndex]; - // Ensure there is a stake to claim - if (stake.amount == 0) revert NothingToClaim(); - if (block.timestamp < stake.unlockTime) revert StakeLocked(); + // /// @notice Restake an expired stake with a bonus daily reward + // function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external { + // if (_restakePercentage > 100) revert InvalidRestakePercentage(); + // Stake storage stake = stakes[msg.sender][_stakeIndex]; + // // Ensure there is a stake to claim + // if (stake.amount == 0) revert NothingToClaim(); + // if (block.timestamp < stake.unlockTime) revert StakeLocked(); - uint256 _amount = stake.amount; - uint rewards = getPoolRewards(msg.sender, _stakeIndex); - _amount = _amount + rewards; + // uint256 _amount = stake.amount; + // uint rewards = getPoolRewards(msg.sender, _stakeIndex); + // _amount = _amount + rewards; - uint256 restake_amount = (_amount * _restakePercentage) / 100; - uint256 withdraw_amount = _amount - restake_amount; + // uint256 restake_amount = (_amount * _restakePercentage) / 100; + // uint256 withdraw_amount = _amount - restake_amount; - // Update state before external calls - stake.amount = 0; - stake.complete = true; + // // Update state before external calls + // stake.amount = 0; + // stake.complete = true; - // Process withdraw - if (withdraw_amount > 0) { - withdrawLiabilities += withdraw_amount; + // // Process withdraw + // if (withdraw_amount > 0) { + // withdrawLiabilities += withdraw_amount; - if (pool.totalStaked >= withdraw_amount) { - pool.totalStaked -= withdraw_amount; - } else { - pool.totalStaked = 0; - } - // Create temporary the stake for the user to delay withdraw - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _stakeIndex, - amount: withdraw_amount, - unlockTime: block.timestamp + unlockDelay - })); + // if (pool.totalStaked >= withdraw_amount) { + // pool.totalStaked -= withdraw_amount; + // } else { + // pool.totalStaked = 0; + // } + // // Create temporary the stake for the user to delay withdraw + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _stakeIndex, + // amount: withdraw_amount, + // unlockTime: block.timestamp + unlockDelay + // })); - // Emit a detailed event - emit RewardClaimed(msg.sender, withdraw_amount); + // // Emit a detailed event + // emit RewardClaimed(msg.sender, withdraw_amount); - } - // Process restake - if (restake_amount > 0) { - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // restake = true - finalRewardRate = getUserRewardRate(msg.sender, true); - } + // } + // // Process restake + // if (restake_amount > 0) { + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // restake = true + // finalRewardRate = getUserRewardRate(msg.sender, true); + // } - stakes[msg.sender].push(Stake({ - amount: restake_amount, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // stakes[msg.sender].push(Stake({ + // amount: restake_amount, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - emit Staked(msg.sender, restake_amount); - } - } + // emit Staked(msg.sender, restake_amount); + // } + // } function createStakeForUser(address _user, uint256 _amount) external onlyOwner { if (_amount == 0) revert InvalidAmount(); @@ -715,222 +715,222 @@ contract PacaFinanceWithBoostAndScheduleSonic is Initializable, ReentrancyGuardU return finalRewardRate; } - function claimRewards() external nonReentrant { - uint256 totalReward = 0; + // function claimRewards() external nonReentrant { + // uint256 totalReward = 0; - for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { - Stake storage stake = stakes[msg.sender][i]; - if (stake.amount > 0) { - uint rewards = getPoolRewards(msg.sender, i); - totalReward = totalReward + rewards; - stake.lastClaimed = block.timestamp; - } - } + // for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { + // Stake storage stake = stakes[msg.sender][i]; + // if (stake.amount > 0) { + // uint rewards = getPoolRewards(msg.sender, i); + // totalReward = totalReward + rewards; + // stake.lastClaimed = block.timestamp; + // } + // } - if (totalReward == 0) revert NothingToClaim(); - if (pool.totalRewards < totalReward) revert InsufficientRewards(); + // if (totalReward == 0) revert NothingToClaim(); + // if (pool.totalRewards < totalReward) revert InsufficientRewards(); - pool.totalRewards = pool.totalRewards - totalReward; - IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward); + // pool.totalRewards = pool.totalRewards - totalReward; + // IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward); - emit RewardClaimed(msg.sender, totalReward); - } + // emit RewardClaimed(msg.sender, totalReward); + // } - function claimStake(uint256 _stakeIndex) external nonReentrant { - // Ensure the stake index is valid - if (_stakeIndex >= stakes[msg.sender].length) revert InvalidStakeIndex(); + // function claimStake(uint256 _stakeIndex) external nonReentrant { + // // Ensure the stake index is valid + // if (_stakeIndex >= stakes[msg.sender].length) revert InvalidStakeIndex(); - // Load the stake - Stake storage stake = stakes[msg.sender][_stakeIndex]; - uint256 _amount = stake.amount; + // // Load the stake + // Stake storage stake = stakes[msg.sender][_stakeIndex]; + // uint256 _amount = stake.amount; - uint rewards = getPoolRewards(msg.sender, _stakeIndex); + // uint rewards = getPoolRewards(msg.sender, _stakeIndex); - _amount = _amount + rewards; + // _amount = _amount + rewards; - // Ensure there is a stake to claim - if (_amount == 0) revert NothingToClaim(); + // // Ensure there is a stake to claim + // if (_amount == 0) revert NothingToClaim(); - // Ensure the stake is unlocked (if using lockup periods) - if (block.timestamp < stake.unlockTime) revert StakeLocked(); + // // Ensure the stake is unlocked (if using lockup periods) + // if (block.timestamp < stake.unlockTime) revert StakeLocked(); - // Update state before external calls - stake.amount = 0; - stake.complete = true; - withdrawLiabilities += _amount; + // // Update state before external calls + // stake.amount = 0; + // stake.complete = true; + // withdrawLiabilities += _amount; - if (pool.totalStaked >= _amount) { - pool.totalStaked -= _amount; - } else { - pool.totalStaked = 0; - } + // if (pool.totalStaked >= _amount) { + // pool.totalStaked -= _amount; + // } else { + // pool.totalStaked = 0; + // } - // Create temporary the stake for the user to delay withdraw - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _stakeIndex, - amount: _amount, - unlockTime: block.timestamp + unlockDelay - })); + // // Create temporary the stake for the user to delay withdraw + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _stakeIndex, + // amount: _amount, + // unlockTime: block.timestamp + unlockDelay + // })); - // Emit a detailed event - emit RewardClaimed(msg.sender, _amount); - } + // // Emit a detailed event + // emit RewardClaimed(msg.sender, _amount); + // } -/** - * @notice Withdraw a staked amount after its unlock time has passed. - * @dev Locates the stake by `_stakeIndex`, checks that it's unlocked and non-zero, - * and transfers tokens to the caller. For vesting stakes (where `_stakeIndex` >= 1e6), - * the stored amount (in 1e18 decimals) is scaled to USDC's 1e6 decimals by dividing by 1e12. - * - * Requirements: - * - Caller must have at least one stake. - * - The stake must exist, be unlocked, and have a non-zero amount. - * - The contract must have sufficient token balance. - * - * @param _stakeIndex The identifier of the stake to withdraw. - */ -function withdraw(uint256 _stakeIndex) external nonReentrant { - WithdrawStake[] storage userStakes = withdrawStake[msg.sender]; - if (userStakes.length == 0) revert NoStakesAvailable(); - - for (uint256 i = 0; i < userStakes.length; ++i) { - WithdrawStake storage stake = userStakes[i]; - // Skip already withdrawn stakes (amount == 0) - if (stake.stakeId == _stakeIndex && stake.amount != 0) { - if (block.timestamp < stake.unlockTime) revert StakeLocked(); - - uint256 _amount = stake.amount; - - // Convert vesting stake amount to USDC decimals. - if (_stakeIndex >= 1e6) { - _amount = _amount / 1e12; - } - - uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this)); - if (poolBalance < _amount) revert InsufficientRewards(); - - // Update state before external calls - // withdrawLiabilities is in 1e18, deduct original amount - withdrawLiabilities -= stake.amount; - stake.amount = 0; - - // Transfer tokens - IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount); - emit StakeWithdrawn(msg.sender, _amount, _stakeIndex); - return; - } - } - - // Revert if no matching stake with non-zero amount was found - revert StakeNotFound(); -} +// /** +// * @notice Withdraw a staked amount after its unlock time has passed. +// * @dev Locates the stake by `_stakeIndex`, checks that it's unlocked and non-zero, +// * and transfers tokens to the caller. For vesting stakes (where `_stakeIndex` >= 1e6), +// * the stored amount (in 1e18 decimals) is scaled to USDC's 1e6 decimals by dividing by 1e12. +// * +// * Requirements: +// * - Caller must have at least one stake. +// * - The stake must exist, be unlocked, and have a non-zero amount. +// * - The contract must have sufficient token balance. +// * +// * @param _stakeIndex The identifier of the stake to withdraw. +// */ +// function withdraw(uint256 _stakeIndex) external nonReentrant { +// WithdrawStake[] storage userStakes = withdrawStake[msg.sender]; +// if (userStakes.length == 0) revert NoStakesAvailable(); +// +// for (uint256 i = 0; i < userStakes.length; ++i) { +// WithdrawStake storage stake = userStakes[i]; +// // Skip already withdrawn stakes (amount == 0) +// if (stake.stakeId == _stakeIndex && stake.amount != 0) { +// if (block.timestamp < stake.unlockTime) revert StakeLocked(); +// +// uint256 _amount = stake.amount; +// +// // Convert vesting stake amount to USDC decimals. +// if (_stakeIndex >= 1e6) { +// _amount = _amount / 1e12; +// } +// +// uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this)); +// if (poolBalance < _amount) revert InsufficientRewards(); +// +// // Update state before external calls +// // withdrawLiabilities is in 1e18, deduct original amount +// withdrawLiabilities -= stake.amount; +// stake.amount = 0; +// +// // Transfer tokens +// IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount); +// emit StakeWithdrawn(msg.sender, _amount, _stakeIndex); +// return; +// } +// } +// +// // Revert if no matching stake with non-zero amount was found +// revert StakeNotFound(); +// } -/** - * @notice Withdraws vesting tokens after cooldown period - * @param _vestingId The vesting ID to withdraw - */ -function withdrawVestingToken(uint256 _vestingId) external nonReentrant { - WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender]; - if (userVestings.length == 0) revert NoStakesAvailable(); - - for (uint256 i = 0; i < userVestings.length; ++i) { - WithdrawVesting storage vestingWithdraw = userVestings[i]; - if (vestingWithdraw.vestingId == _vestingId && vestingWithdraw.amount != 0) { - if (block.timestamp < vestingWithdraw.unlockTime) revert StakeLocked(); - - uint256 _amount = vestingWithdraw.amount; - address _token = vestingWithdraw.token; - - // Check contract has sufficient balance - uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); - if (tokenBalance < _amount) revert InsufficientRewards(); - - // Update state before external calls - vestingWithdraw.amount = 0; - - // Decrement withdraw vesting liabilities for this token - withdrawVestingLiabilities[_token] -= _amount; - - // Transfer tokens - IERC20(_token).safeTransfer(msg.sender, _amount); - emit StakeWithdrawn(msg.sender, _amount, _vestingId); - return; - } - } - - revert StakeNotFound(); -} +// /** +// * @notice Withdraws vesting tokens after cooldown period +// * @param _vestingId The vesting ID to withdraw +// */ +// function withdrawVestingToken(uint256 _vestingId) external nonReentrant { +// WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender]; +// if (userVestings.length == 0) revert NoStakesAvailable(); +// +// for (uint256 i = 0; i < userVestings.length; ++i) { +// WithdrawVesting storage vestingWithdraw = userVestings[i]; +// if (vestingWithdraw.vestingId == _vestingId && vestingWithdraw.amount != 0) { +// if (block.timestamp < vestingWithdraw.unlockTime) revert StakeLocked(); +// +// uint256 _amount = vestingWithdraw.amount; +// address _token = vestingWithdraw.token; +// +// // Check contract has sufficient balance +// uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); +// if (tokenBalance < _amount) revert InsufficientRewards(); +// +// // Update state before external calls +// vestingWithdraw.amount = 0; +// +// // Decrement withdraw vesting liabilities for this token +// withdrawVestingLiabilities[_token] -= _amount; +// +// // Transfer tokens +// IERC20(_token).safeTransfer(msg.sender, _amount); +// emit StakeWithdrawn(msg.sender, _amount, _vestingId); +// return; +// } +// } +// +// revert StakeNotFound(); +// } - function compoundAllRewards() external { - uint256 totalReward = 0; + // function compoundAllRewards() external { + // uint256 totalReward = 0; - for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { - Stake storage stake = stakes[msg.sender][i]; - if (stake.amount > 0) { - uint rewards = getPoolRewards(msg.sender, i); - totalReward = totalReward + rewards; - stake.lastClaimed = block.timestamp; - } - } + // for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { + // Stake storage stake = stakes[msg.sender][i]; + // if (stake.amount > 0) { + // uint rewards = getPoolRewards(msg.sender, i); + // totalReward = totalReward + rewards; + // stake.lastClaimed = block.timestamp; + // } + // } - if (totalReward <= minStakeLock) revert NotEnoughToCompound(); - - // Check if user has a fixed reward rate set - uint256 finalRewardRate; - if (addressFixedRate[msg.sender] > 0) { - // Use the fixed rate - finalRewardRate = addressFixedRate[msg.sender]; - } else { - // Default logic, restake = false - finalRewardRate = getUserRewardRate(msg.sender, false); - } + // if (totalReward <= minStakeLock) revert NotEnoughToCompound(); + // + // // Check if user has a fixed reward rate set + // uint256 finalRewardRate; + // if (addressFixedRate[msg.sender] > 0) { + // // Use the fixed rate + // finalRewardRate = addressFixedRate[msg.sender]; + // } else { + // // Default logic, restake = false + // finalRewardRate = getUserRewardRate(msg.sender, false); + // } - stakes[msg.sender].push(Stake({ - amount: totalReward, - lastClaimed: block.timestamp, - dailyRewardRate: finalRewardRate, - unlockTime: block.timestamp + pool.lockupPeriod, - complete: false - })); + // stakes[msg.sender].push(Stake({ + // amount: totalReward, + // lastClaimed: block.timestamp, + // dailyRewardRate: finalRewardRate, + // unlockTime: block.timestamp + pool.lockupPeriod, + // complete: false + // })); - pool.totalStaked = pool.totalStaked + totalReward; - emit CompoundRewards(msg.sender, totalReward); - } + // pool.totalStaked = pool.totalStaked + totalReward; + // emit CompoundRewards(msg.sender, totalReward); + // } - function createVesting(address _token, uint256 _amount) external { - if (_amount == 0) revert InvalidAmount(); - address oracle = priceOracles[_token]; - if (oracle == address(0)) revert PriceOracleNotSet(); - IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); + // function createVesting(address _token, uint256 _amount) external { + // if (_amount == 0) revert InvalidAmount(); + // address oracle = priceOracles[_token]; + // if (oracle == address(0)) revert PriceOracleNotSet(); + // IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); - uint256 bonus = (_amount * BONUS_PERCENTAGE) / 100; + // uint256 bonus = (_amount * BONUS_PERCENTAGE) / 100; - uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18; - if (usdPrice <= minStakeLock) revert AmountBelowMinimum(); + // uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18; + // if (usdPrice <= minStakeLock) revert AmountBelowMinimum(); - // Update user's dollarsVested - dollarsVested[msg.sender] += usdPrice; - // Update token's vestedTotal - vestedTotal[_token] += _amount; + // // Update user's dollarsVested + // dollarsVested[msg.sender] += usdPrice; + // // Update token's vestedTotal + // vestedTotal[_token] += _amount; - vestings[msg.sender].push(Vesting({ - amount: _amount, - bonus: bonus, - lockedUntil: block.timestamp + lockupDuration, - claimedAmount: 0, - claimedBonus: 0, - lastClaimed: block.timestamp, - createdAt: block.timestamp, - token: _token, - complete: false, - usdAmount: usdPrice - })); + // vestings[msg.sender].push(Vesting({ + // amount: _amount, + // bonus: bonus, + // lockedUntil: block.timestamp + lockupDuration, + // claimedAmount: 0, + // claimedBonus: 0, + // lastClaimed: block.timestamp, + // createdAt: block.timestamp, + // token: _token, + // complete: false, + // usdAmount: usdPrice + // })); - emit VestingCreated(msg.sender, _amount, bonus); - } + // emit VestingCreated(msg.sender, _amount, bonus); + // } function getUnlockedVesting(address _user, uint256 _vestingIndex) public view returns (uint256) { Vesting storage vesting = vestings[_user][_vestingIndex]; @@ -993,124 +993,124 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant { } - function claimVesting(uint256 _vestingIndex) external nonReentrant { - Vesting storage vesting = vestings[msg.sender][_vestingIndex]; - if (vesting.complete) revert StakeComplete(); - uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex); + // function claimVesting(uint256 _vestingIndex) external nonReentrant { + // Vesting storage vesting = vestings[msg.sender][_vestingIndex]; + // if (vesting.complete) revert StakeComplete(); + // uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex); - if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); - uint256 amountToClaim = maxClaim - vesting.claimedAmount; - if (amountToClaim == 0) revert NothingToClaim(); + // if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); + // uint256 amountToClaim = maxClaim - vesting.claimedAmount; + // if (amountToClaim == 0) revert NothingToClaim(); - vesting.claimedAmount = vesting.claimedAmount + amountToClaim; - if (vesting.claimedAmount >= vesting.amount) { - vesting.complete = true; - } - // Update user's dollarsVested - if (dollarsVested[msg.sender] > 0) { - uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18; - if (usdPrice >= dollarsVested[msg.sender]) { - dollarsVested[msg.sender] = 0; - } else { - dollarsVested[msg.sender] -= usdPrice; - } - } - vestedTotal[vesting.token] -= amountToClaim; - - // Add vesting claims to cooldown queue - withdrawVestingActual[msg.sender].push(WithdrawVesting({ - vestingId: withdrawVestingCounterActual++, - amount: amountToClaim, - unlockTime: block.timestamp + unlockDelay, - token: vesting.token - })); - - // Increment withdraw vesting liabilities for this token - withdrawVestingLiabilities[vesting.token] += amountToClaim; + // vesting.claimedAmount = vesting.claimedAmount + amountToClaim; + // if (vesting.claimedAmount >= vesting.amount) { + // vesting.complete = true; + // } + // // Update user's dollarsVested + // if (dollarsVested[msg.sender] > 0) { + // uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18; + // if (usdPrice >= dollarsVested[msg.sender]) { + // dollarsVested[msg.sender] = 0; + // } else { + // dollarsVested[msg.sender] -= usdPrice; + // } + // } + // vestedTotal[vesting.token] -= amountToClaim; + // + // // Add vesting claims to cooldown queue + // withdrawVestingActual[msg.sender].push(WithdrawVesting({ + // vestingId: withdrawVestingCounterActual++, + // amount: amountToClaim, + // unlockTime: block.timestamp + unlockDelay, + // token: vesting.token + // })); + // + // // Increment withdraw vesting liabilities for this token + // withdrawVestingLiabilities[vesting.token] += amountToClaim; - emit VestingClaimed(msg.sender, amountToClaim, 0); - } + // emit VestingClaimed(msg.sender, amountToClaim, 0); + // } - function claimAllVestingByToken(address _token) external nonReentrant { - uint256 totalReward = 0; - uint256 vestingsProcessed = 0; + // function claimAllVestingByToken(address _token) external nonReentrant { + // uint256 totalReward = 0; + // uint256 vestingsProcessed = 0; - for (uint256 i = 0; i < vestings[msg.sender].length; ++i) { - Vesting storage vesting = vestings[msg.sender][i]; + // for (uint256 i = 0; i < vestings[msg.sender].length; ++i) { + // Vesting storage vesting = vestings[msg.sender][i]; - if (vesting.token == _token && !vesting.complete) { - uint256 maxClaim = getUnlockedVesting(msg.sender, i); - if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); + // if (vesting.token == _token && !vesting.complete) { + // uint256 maxClaim = getUnlockedVesting(msg.sender, i); + // if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount(); - uint256 amountToClaim = maxClaim - vesting.claimedAmount; - if (amountToClaim > 0) { - vesting.claimedAmount = vesting.claimedAmount + amountToClaim; - totalReward = totalReward + amountToClaim; - vesting.lastClaimed = block.timestamp; + // uint256 amountToClaim = maxClaim - vesting.claimedAmount; + // if (amountToClaim > 0) { + // vesting.claimedAmount = vesting.claimedAmount + amountToClaim; + // totalReward = totalReward + amountToClaim; + // vesting.lastClaimed = block.timestamp; - // Mark vesting as complete if fully claimed - if (vesting.claimedAmount >= vesting.amount) { - vesting.complete = true; - } + // // Mark vesting as complete if fully claimed + // if (vesting.claimedAmount >= vesting.amount) { + // vesting.complete = true; + // } - vestingsProcessed++; - } - } - } + // vestingsProcessed++; + // } + // } + // } - if (totalReward == 0) revert NothingToClaim(); + // if (totalReward == 0) revert NothingToClaim(); - // Update user's dollarsVested - if (dollarsVested[msg.sender] > 0) { - uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18; - if (usdPrice >= dollarsVested[msg.sender]) { - dollarsVested[msg.sender] = 0; - } else { - dollarsVested[msg.sender] -= usdPrice; - } - } + // // Update user's dollarsVested + // if (dollarsVested[msg.sender] > 0) { + // uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18; + // if (usdPrice >= dollarsVested[msg.sender]) { + // dollarsVested[msg.sender] = 0; + // } else { + // dollarsVested[msg.sender] -= usdPrice; + // } + // } - // Update vesting total - vestedTotal[_token] -= totalReward; - - // Add vesting claims to cooldown queue - withdrawVestingActual[msg.sender].push(WithdrawVesting({ - vestingId: withdrawVestingCounterActual++, - amount: totalReward, - unlockTime: block.timestamp + unlockDelay, - token: _token - })); - - // Increment withdraw vesting liabilities for this token - withdrawVestingLiabilities[_token] += totalReward; + // // Update vesting total + // vestedTotal[_token] -= totalReward; + // + // // Add vesting claims to cooldown queue + // withdrawVestingActual[msg.sender].push(WithdrawVesting({ + // vestingId: withdrawVestingCounterActual++, + // amount: totalReward, + // unlockTime: block.timestamp + unlockDelay, + // token: _token + // })); + // + // // Increment withdraw vesting liabilities for this token + // withdrawVestingLiabilities[_token] += totalReward; - emit RewardClaimed(msg.sender, totalReward); - } + // emit RewardClaimed(msg.sender, totalReward); + // } - function claimBonus(uint256 _vestingIndex) external nonReentrant { - Vesting storage vesting = vestings[msg.sender][_vestingIndex]; - uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex); + // function claimBonus(uint256 _vestingIndex) external nonReentrant { + // Vesting storage vesting = vestings[msg.sender][_vestingIndex]; + // uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex); - if (maxBonus < vesting.claimedBonus) revert InvalidClaimAmount(); - uint256 bonusToClaim = maxBonus - vesting.claimedBonus; - if (bonusToClaim == 0) revert NothingToClaim(); + // if (maxBonus < vesting.claimedBonus) revert InvalidClaimAmount(); + // uint256 bonusToClaim = maxBonus - vesting.claimedBonus; + // if (bonusToClaim == 0) revert NothingToClaim(); - vesting.claimedBonus = vesting.claimedBonus + bonusToClaim; - withdrawLiabilities += bonusToClaim; + // vesting.claimedBonus = vesting.claimedBonus + bonusToClaim; + // withdrawLiabilities += bonusToClaim; - // IERC20(vesting.token).safeTransfer(msg.sender, bonusToClaim); + // // IERC20(vesting.token).safeTransfer(msg.sender, bonusToClaim); - // Create temporary the stake for the user to delay withdraw. - // Add 1e6 to the vesting index to distinguish them from normal stakes. - withdrawStake[msg.sender].push(WithdrawStake({ - stakeId: _vestingIndex + 1e6, - amount: bonusToClaim, - unlockTime: block.timestamp + unlockDelay - })); + // // Create temporary the stake for the user to delay withdraw. + // // Add 1e6 to the vesting index to distinguish them from normal stakes. + // withdrawStake[msg.sender].push(WithdrawStake({ + // stakeId: _vestingIndex + 1e6, + // amount: bonusToClaim, + // unlockTime: block.timestamp + unlockDelay + // })); - emit BonusClaimed(msg.sender, bonusToClaim); - } + // emit BonusClaimed(msg.sender, bonusToClaim); + // } function setPriceOracle(address _token, address _oracle) external onlyOwner { priceOracles[_token] = _oracle; @@ -1388,6 +1388,55 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant { emit StakeSold(seller, msg.sender, sellStakeEntry.price, _stakeId); } + /// @notice Admin function to clear all sellStakes for a specific address + /// @dev Only callable by contract owners. Restores original stakes and removes all sell listings. + /// @param _address The address whose sellStakes should be cleared + function clearAllSellStakes(address _address) external onlyOwner { + + // First, collect all stakeIds for this address from the sellStakeKeys array + uint256[] memory stakeIdsToRemove = new uint256[](sellStakeKeys.length); + uint256 stakeCount = 0; + + // Find all stakeIds belonging to the target address + for (uint256 i = 0; i < sellStakeKeys.length; i++) { + if (sellStakeKeys[i].seller == _address) { + stakeIdsToRemove[stakeCount] = sellStakeKeys[i].stakeId; + stakeCount++; + } + } + + // Process each stake found + for (uint256 i = 0; i < stakeCount; i++) { + uint256 stakeId = stakeIdsToRemove[i]; + SellStake storage sellStakeEntry = sellStakes[_address][stakeId]; + + // Skip if already cleared + if (sellStakeEntry.amount == 0) continue; + + // Restore the original stake + Stake storage originalStake = stakes[_address][stakeId]; + originalStake.amount = sellStakeEntry.amount; + + // Clear the sell stake entry + delete sellStakes[_address][stakeId]; + + // Remove from sellStakeKeys array using swap-and-pop + uint256 keyIndex = sellStakeKeyIndex[_address][stakeId]; + uint256 lastIndex = sellStakeKeys.length - 1; + + if (keyIndex != lastIndex) { + SellStakeKey memory lastKey = sellStakeKeys[lastIndex]; + sellStakeKeys[keyIndex] = lastKey; + sellStakeKeyIndex[lastKey.seller][lastKey.stakeId] = keyIndex; + } + + sellStakeKeys.pop(); + delete sellStakeKeyIndex[_address][stakeId]; + + emit StakeSaleCancelled(_address, stakeId); + } + } + /// @notice Returns all active sell stakes with their keys and pending rewards. /// @return sellers Array of seller addresses for each stake /// @return stakeIds Array of stake IDs corresponding to each seller