shortened some reverts to reduce size
This commit is contained in:
@@ -209,6 +209,10 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
|||||||
unlockDelay = _delay;
|
unlockDelay = _delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updatePoolRewards(uint256 _amount) external onlyOwner {
|
||||||
|
pool.totalRewards = _amount;
|
||||||
|
}
|
||||||
|
|
||||||
function updateRestakeBonus(uint256 _newBonus) external onlyOwner {
|
function updateRestakeBonus(uint256 _newBonus) external onlyOwner {
|
||||||
restakeBonus = _newBonus;
|
restakeBonus = _newBonus;
|
||||||
}
|
}
|
||||||
@@ -310,31 +314,31 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
|||||||
emit FundsWithdrawn(msg.sender, _token, _amount);
|
emit FundsWithdrawn(msg.sender, _token, _amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUnlockScheduleByPercentage(
|
// function setUnlockScheduleByPercentage(
|
||||||
address _token,
|
// address _token,
|
||||||
uint256 _lockTime, // Total lock time in seconds
|
// uint256 _lockTime, // Total lock time in seconds
|
||||||
uint256 _percentagePerStep // Percentage unlocked per step (in basis points, e.g., 100 = 1%)
|
// uint256 _percentagePerStep // Percentage unlocked per step (in basis points, e.g., 100 = 1%)
|
||||||
) external onlyOwner {
|
// ) external onlyOwner {
|
||||||
require(_lockTime != 0, "Lock time must be greater than zero");
|
// require(_lockTime != 0, "Lock time must be greater than zero");
|
||||||
require(_percentagePerStep != 0, "Percentage per step must be greater than zero");
|
// require(_percentagePerStep != 0, "Percentage per step must be greater than zero");
|
||||||
|
|
||||||
uint256 totalPercentage = 10000; // 100% in basis points
|
// uint256 totalPercentage = 10000; // 100% in basis points
|
||||||
require(totalPercentage % _percentagePerStep == 0, "Percentage must divide 100% evenly");
|
// require(totalPercentage % _percentagePerStep == 0, "Percentage must divide 100% evenly");
|
||||||
|
|
||||||
uint256 steps = totalPercentage / _percentagePerStep; // Number of steps
|
// uint256 steps = totalPercentage / _percentagePerStep; // Number of steps
|
||||||
uint256 stepTime = _lockTime / steps; // Time interval per step
|
// uint256 stepTime = _lockTime / steps; // Time interval per step
|
||||||
|
|
||||||
delete unlockSchedules[_token]; // Clear existing schedule for this token
|
// delete unlockSchedules[_token]; // Clear existing schedule for this token
|
||||||
|
|
||||||
for (uint256 i = 1; i <= steps; ++i) {
|
// for (uint256 i = 1; i <= steps; ++i) {
|
||||||
unlockSchedules[_token].push(UnlockStep({
|
// unlockSchedules[_token].push(UnlockStep({
|
||||||
timeOffset: stepTime * i, // Time offset for this step
|
// timeOffset: stepTime * i, // Time offset for this step
|
||||||
percentage: _percentagePerStep
|
// percentage: _percentagePerStep
|
||||||
}));
|
// }));
|
||||||
}
|
// }
|
||||||
|
|
||||||
emit UnlockScheduleSet(_token);
|
// emit UnlockScheduleSet(_token);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// @notice Get the boost percentage for a given token amount
|
/// @notice Get the boost percentage for a given token amount
|
||||||
function getBoost(uint256 depositedTokens) public view returns (uint256) {
|
function getBoost(uint256 depositedTokens) public view returns (uint256) {
|
||||||
@@ -377,102 +381,189 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
|||||||
withdrawLiabilities -= clearedStakes;
|
withdrawLiabilities -= clearedStakes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function createStake(uint256 _amount) external {
|
// /**
|
||||||
// // Scale up for wei comparison, USDC is 1e6
|
// * @dev Extends the lastClaimed and unlockTime for all stakes of a given address
|
||||||
// require(_amount * 1e12 > minStakeLock, "Amount must be greater minStakeLock");
|
// * @param _address The address whose stakes to extend
|
||||||
|
// * @param _seconds The number of seconds to add to lastClaimed and unlockTime
|
||||||
|
// */
|
||||||
|
// function extendStakes(address _address, uint256 _seconds) external onlyBot {
|
||||||
|
// if (_seconds == 0) return; // Early exit for zero seconds
|
||||||
|
|
||||||
// // Transfer tokens from the user into the contract
|
// Stake[] storage userStakes = stakes[_address];
|
||||||
// IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount);
|
// uint256 length = userStakes.length;
|
||||||
|
|
||||||
// // Check if user has a fixed reward rate set
|
// if (length == 0) return; // Early exit for no stakes
|
||||||
// uint256 finalRewardRate;
|
|
||||||
// if (addressFixedRate[msg.sender] > 0) {
|
// // Cache the stake reference to avoid repeated array access
|
||||||
// // Use the fixed rate
|
// for (uint256 i; i < length;) {
|
||||||
// finalRewardRate = addressFixedRate[msg.sender];
|
// Stake storage stake = userStakes[i];
|
||||||
// } else {
|
|
||||||
// // Default logic, restake = false
|
// // Only extend active stakes with non-zero amounts
|
||||||
// finalRewardRate = getUserRewardRate(msg.sender, false);
|
// if (!stake.complete && stake.amount > 0) {
|
||||||
|
// unchecked {
|
||||||
|
// stake.lastClaimed += _seconds;
|
||||||
|
// stake.unlockTime += _seconds;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// unchecked { ++i; }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // 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;
|
|
||||||
|
|
||||||
// emit Staked(msg.sender, _amount);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
// /// @notice Restake an expired stake with a bonus daily reward
|
// /**
|
||||||
// function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external {
|
// * @dev Extends the lockedUntil, lastClaimed, and createdAt for all vestings of a given address
|
||||||
// require(_restakePercentage <= 100, "Invalid restake percentage");
|
// * @param _address The address whose vestings to extend
|
||||||
// Stake storage stake = stakes[msg.sender][_stakeIndex];
|
// * @param _seconds The number of seconds to add to the timestamps
|
||||||
// // Ensure there is a stake to claim
|
// */
|
||||||
// require(stake.amount != 0, "No amount to claim");
|
// function extendVestings(address _address, uint256 _seconds) external onlyBot {
|
||||||
// require(block.timestamp >= stake.unlockTime, "Stake is still locked");
|
// if (_seconds == 0) return; // Early exit for zero seconds
|
||||||
|
|
||||||
// uint256 _amount = stake.amount;
|
// Vesting[] storage userVestings = vestings[_address];
|
||||||
// uint rewards = getPoolRewards(msg.sender, _stakeIndex);
|
// uint256 length = userVestings.length;
|
||||||
// _amount = _amount + rewards;
|
|
||||||
|
|
||||||
// uint256 restake_amount = (_amount * _restakePercentage) / 100;
|
// if (length == 0) return; // Early exit for no vestings
|
||||||
// uint256 withdraw_amount = _amount - restake_amount;
|
|
||||||
|
|
||||||
// // Update state before external calls
|
// // Cache the vesting reference to avoid repeated array access
|
||||||
// stake.amount = 0;
|
// for (uint256 i; i < length;) {
|
||||||
// stake.complete = true;
|
// Vesting storage vesting = userVestings[i];
|
||||||
|
|
||||||
// // Process withdraw
|
// // Only extend active vestings with non-zero amounts
|
||||||
// if (withdraw_amount > 0) {
|
// if (!vesting.complete && vesting.amount > 0) {
|
||||||
// withdrawLiabilities += withdraw_amount;
|
// unchecked {
|
||||||
|
// vesting.lockedUntil += _seconds;
|
||||||
// if (pool.totalStaked >= withdraw_amount) {
|
// vesting.lastClaimed += _seconds;
|
||||||
// pool.totalStaked -= withdraw_amount;
|
// vesting.createdAt += _seconds;
|
||||||
// } 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);
|
|
||||||
|
|
||||||
// }
|
|
||||||
// // 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({
|
// unchecked { ++i; }
|
||||||
// amount: restake_amount,
|
|
||||||
// lastClaimed: block.timestamp,
|
|
||||||
// dailyRewardRate: finalRewardRate,
|
|
||||||
// unlockTime: block.timestamp + pool.lockupPeriod,
|
|
||||||
// complete: false
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// emit Staked(msg.sender, restake_amount);
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// function adminClearSellStake(address _seller, uint256 _stakeId) external onlyOwner {
|
||||||
|
// SellStake storage sellStakeEntry = sellStakes[_seller][_stakeId];
|
||||||
|
// require(sellStakeEntry.amount != 0, "Sell stake not found");
|
||||||
|
|
||||||
|
// // Access the original stake.
|
||||||
|
// Stake storage stake = stakes[_seller][_stakeId];
|
||||||
|
// require(stake.amount == 0, "Stake not in sell state");
|
||||||
|
|
||||||
|
// // Restore the original stake's amount.
|
||||||
|
// // stake.amount = sellStakeEntry.amount;
|
||||||
|
|
||||||
|
// delete sellStakes[_seller][_stakeId];
|
||||||
|
|
||||||
|
// // Remove the key from the iteration array using swap-and-pop.
|
||||||
|
// uint256 index = sellStakeKeyIndex[_seller][_stakeId];
|
||||||
|
// uint256 lastIndex = sellStakeKeys.length - 1;
|
||||||
|
// if (index != lastIndex) {
|
||||||
|
// SellStakeKey memory lastKey = sellStakeKeys[lastIndex];
|
||||||
|
// sellStakeKeys[index] = lastKey;
|
||||||
|
// sellStakeKeyIndex[lastKey.seller][lastKey.stakeId] = index;
|
||||||
|
// }
|
||||||
|
// sellStakeKeys.pop();
|
||||||
|
// delete sellStakeKeyIndex[_seller][_stakeId];
|
||||||
|
|
||||||
|
// emit StakeSaleCancelled(_seller, _stakeId);
|
||||||
|
// }
|
||||||
|
|
||||||
|
function createStake(uint256 _amount) external {
|
||||||
|
// Scale up for wei comparison, USDC is 1e6
|
||||||
|
require(_amount * 1e12 > minStakeLock, "Amount must be greater minStakeLock");
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
emit Staked(msg.sender, _amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @notice Restake an expired stake with a bonus daily reward
|
||||||
|
function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external {
|
||||||
|
require(_restakePercentage <= 100, "Invalid restake percentage");
|
||||||
|
Stake storage stake = stakes[msg.sender][_stakeIndex];
|
||||||
|
// Ensure there is a stake to claim
|
||||||
|
require(stake.amount != 0, "No amount to claim");
|
||||||
|
require(block.timestamp >= stake.unlockTime, "Stake is still locked");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Update state before external calls
|
||||||
|
stake.amount = 0;
|
||||||
|
stake.complete = true;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createStakeForUser(address _user, uint256 _amount) external onlyOwner {
|
function createStakeForUser(address _user, uint256 _amount) external onlyOwner {
|
||||||
require(_amount != 0, "Invalid amount");
|
require(_amount != 0, "Invalid amount");
|
||||||
|
|
||||||
@@ -536,186 +627,186 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
|||||||
return finalRewardRate;
|
return finalRewardRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function claimRewards() external nonReentrant {
|
function claimRewards() external nonReentrant {
|
||||||
// uint256 totalReward = 0;
|
uint256 totalReward = 0;
|
||||||
|
|
||||||
// for (uint256 i = 0; i < stakes[msg.sender].length; ++i) {
|
for (uint256 i = 0; i < stakes[msg.sender].length; ++i) {
|
||||||
// Stake storage stake = stakes[msg.sender][i];
|
Stake storage stake = stakes[msg.sender][i];
|
||||||
// if (stake.amount > 0) {
|
if (stake.amount > 0) {
|
||||||
// uint rewards = getPoolRewards(msg.sender, i);
|
uint rewards = getPoolRewards(msg.sender, i);
|
||||||
// totalReward = totalReward + rewards;
|
totalReward = totalReward + rewards;
|
||||||
// stake.lastClaimed = block.timestamp;
|
stake.lastClaimed = block.timestamp;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// require(totalReward != 0, "No rewards to claim");
|
require(totalReward != 0, "No rewards to claim");
|
||||||
// require(pool.totalRewards >= totalReward, "Insufficient rewards in the pool");
|
require(pool.totalRewards >= totalReward, "Insufficient rewards in the pool");
|
||||||
|
|
||||||
// pool.totalRewards = pool.totalRewards - totalReward;
|
pool.totalRewards = pool.totalRewards - totalReward;
|
||||||
// IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward);
|
IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward);
|
||||||
|
|
||||||
// emit RewardClaimed(msg.sender, totalReward);
|
emit RewardClaimed(msg.sender, totalReward);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// function claimStake(uint256 _stakeIndex) external nonReentrant {
|
function claimStake(uint256 _stakeIndex) external nonReentrant {
|
||||||
// // Ensure the stake index is valid
|
// Ensure the stake index is valid
|
||||||
// require(_stakeIndex < stakes[msg.sender].length, "Invalid stake index");
|
require(_stakeIndex < stakes[msg.sender].length, "Invalid stake index");
|
||||||
|
|
||||||
// // Load the stake
|
// Load the stake
|
||||||
// Stake storage stake = stakes[msg.sender][_stakeIndex];
|
Stake storage stake = stakes[msg.sender][_stakeIndex];
|
||||||
// uint256 _amount = stake.amount;
|
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
|
// Ensure there is a stake to claim
|
||||||
// require(_amount != 0, "No amount to claim");
|
require(_amount != 0, "No amount to claim");
|
||||||
|
|
||||||
// // Ensure the stake is unlocked (if using lockup periods)
|
// Ensure the stake is unlocked (if using lockup periods)
|
||||||
// require(block.timestamp >= stake.unlockTime, "Stake is still locked");
|
require(block.timestamp >= stake.unlockTime, "Stake is still locked");
|
||||||
|
|
||||||
// // Update state before external calls
|
// Update state before external calls
|
||||||
// stake.amount = 0;
|
stake.amount = 0;
|
||||||
// stake.complete = true;
|
stake.complete = true;
|
||||||
// withdrawLiabilities += _amount;
|
withdrawLiabilities += _amount;
|
||||||
|
|
||||||
// if (pool.totalStaked >= _amount) {
|
if (pool.totalStaked >= _amount) {
|
||||||
// pool.totalStaked -= _amount;
|
pool.totalStaked -= _amount;
|
||||||
// } else {
|
} else {
|
||||||
// pool.totalStaked = 0;
|
pool.totalStaked = 0;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Create temporary the stake for the user to delay withdraw
|
// Create temporary the stake for the user to delay withdraw
|
||||||
// withdrawStake[msg.sender].push(WithdrawStake({
|
withdrawStake[msg.sender].push(WithdrawStake({
|
||||||
// stakeId: _stakeIndex,
|
stakeId: _stakeIndex,
|
||||||
// amount: _amount,
|
amount: _amount,
|
||||||
// unlockTime: block.timestamp + unlockDelay
|
unlockTime: block.timestamp + unlockDelay
|
||||||
// }));
|
}));
|
||||||
|
|
||||||
// // Emit a detailed event
|
// Emit a detailed event
|
||||||
// emit RewardClaimed(msg.sender, _amount);
|
emit RewardClaimed(msg.sender, _amount);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * @notice Withdraw a staked amount after its unlock time has passed.
|
* @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,
|
* @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),
|
* 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.
|
* the stored amount (in 1e18 decimals) is scaled to USDC's 1e6 decimals by dividing by 1e12.
|
||||||
// *
|
*
|
||||||
// * Requirements:
|
* Requirements:
|
||||||
// * - Caller must have at least one stake.
|
* - Caller must have at least one stake.
|
||||||
// * - The stake must exist, be unlocked, and have a non-zero amount.
|
* - The stake must exist, be unlocked, and have a non-zero amount.
|
||||||
// * - The contract must have sufficient token balance.
|
* - The contract must have sufficient token balance.
|
||||||
// *
|
*
|
||||||
// * @param _stakeIndex The identifier of the stake to withdraw.
|
* @param _stakeIndex The identifier of the stake to withdraw.
|
||||||
// */
|
*/
|
||||||
// function withdraw(uint256 _stakeIndex) external nonReentrant {
|
function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||||
// WithdrawStake[] storage userStakes = withdrawStake[msg.sender];
|
WithdrawStake[] storage userStakes = withdrawStake[msg.sender];
|
||||||
// require(userStakes.length > 0, "No stakes available for withdrawal");
|
require(userStakes.length > 0, "No stakes available for withdrawal");
|
||||||
|
|
||||||
// for (uint256 i = 0; i < userStakes.length; ++i) {
|
for (uint256 i = 0; i < userStakes.length; ++i) {
|
||||||
// WithdrawStake storage stake = userStakes[i];
|
WithdrawStake storage stake = userStakes[i];
|
||||||
// // Skip already withdrawn stakes (amount == 0)
|
// Skip already withdrawn stakes (amount == 0)
|
||||||
// if (stake.stakeId == _stakeIndex && stake.amount != 0) {
|
if (stake.stakeId == _stakeIndex && stake.amount != 0) {
|
||||||
// require(block.timestamp >= stake.unlockTime, "Withdraw Stake is still locked");
|
require(block.timestamp >= stake.unlockTime, "Withdraw Stake is still locked");
|
||||||
|
|
||||||
// uint256 _amount = stake.amount;
|
uint256 _amount = stake.amount;
|
||||||
|
|
||||||
// // Convert vesting stake amount to USDC decimals.
|
// Convert vesting stake amount to USDC decimals.
|
||||||
// if (_stakeIndex >= 1e6) {
|
if (_stakeIndex >= 1e6) {
|
||||||
// _amount = _amount / 1e12;
|
_amount = _amount / 1e12;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this));
|
uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this));
|
||||||
// require(poolBalance >= _amount, "Insufficient rewards in the pool");
|
require(poolBalance >= _amount, "Insufficient rewards in the pool");
|
||||||
|
|
||||||
// // Update state before external calls
|
// Update state before external calls
|
||||||
// // withdrawLiabilities is in 1e18, deduct original amount
|
// withdrawLiabilities is in 1e18, deduct original amount
|
||||||
// withdrawLiabilities -= stake.amount;
|
withdrawLiabilities -= stake.amount;
|
||||||
// stake.amount = 0;
|
stake.amount = 0;
|
||||||
|
|
||||||
// // Transfer tokens
|
// Transfer tokens
|
||||||
// IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount);
|
IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount);
|
||||||
// emit StakeWithdrawn(msg.sender, _amount, _stakeIndex);
|
emit StakeWithdrawn(msg.sender, _amount, _stakeIndex);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Revert if no matching stake with non-zero amount was found
|
// Revert if no matching stake with non-zero amount was found
|
||||||
// revert("Invalid stake index or already withdrawn");
|
revert("Invalid stake index or already withdrawn");
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// function compoundAllRewards() external {
|
function compoundAllRewards() external {
|
||||||
// uint256 totalReward = 0;
|
uint256 totalReward = 0;
|
||||||
|
|
||||||
// for (uint256 i = 0; i < stakes[msg.sender].length; ++i) {
|
for (uint256 i = 0; i < stakes[msg.sender].length; ++i) {
|
||||||
// Stake storage stake = stakes[msg.sender][i];
|
Stake storage stake = stakes[msg.sender][i];
|
||||||
// if (stake.amount > 0) {
|
if (stake.amount > 0) {
|
||||||
// uint rewards = getPoolRewards(msg.sender, i);
|
uint rewards = getPoolRewards(msg.sender, i);
|
||||||
// totalReward = totalReward + rewards;
|
totalReward = totalReward + rewards;
|
||||||
// stake.lastClaimed = block.timestamp;
|
stake.lastClaimed = block.timestamp;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// require(totalReward > minStakeLock, "Not enough to compound");
|
require(totalReward > minStakeLock, "Not enough to compound");
|
||||||
|
|
||||||
// // Check if user has a fixed reward rate set
|
// Check if user has a fixed reward rate set
|
||||||
// uint256 finalRewardRate;
|
uint256 finalRewardRate;
|
||||||
// if (addressFixedRate[msg.sender] > 0) {
|
if (addressFixedRate[msg.sender] > 0) {
|
||||||
// // Use the fixed rate
|
// Use the fixed rate
|
||||||
// finalRewardRate = addressFixedRate[msg.sender];
|
finalRewardRate = addressFixedRate[msg.sender];
|
||||||
// } else {
|
} else {
|
||||||
// // Default logic, restake = false
|
// Default logic, restake = false
|
||||||
// finalRewardRate = getUserRewardRate(msg.sender, false);
|
finalRewardRate = getUserRewardRate(msg.sender, false);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// stakes[msg.sender].push(Stake({
|
stakes[msg.sender].push(Stake({
|
||||||
// amount: totalReward,
|
amount: totalReward,
|
||||||
// lastClaimed: block.timestamp,
|
lastClaimed: block.timestamp,
|
||||||
// dailyRewardRate: finalRewardRate,
|
dailyRewardRate: finalRewardRate,
|
||||||
// unlockTime: block.timestamp + pool.lockupPeriod,
|
unlockTime: block.timestamp + pool.lockupPeriod,
|
||||||
// complete: false
|
complete: false
|
||||||
// }));
|
}));
|
||||||
|
|
||||||
// pool.totalStaked = pool.totalStaked + totalReward;
|
pool.totalStaked = pool.totalStaked + totalReward;
|
||||||
// emit CompoundRewards(msg.sender, totalReward);
|
emit CompoundRewards(msg.sender, totalReward);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// function createVesting(address _token, uint256 _amount) external {
|
function createVesting(address _token, uint256 _amount) external {
|
||||||
// require(_amount != 0, "Amount must be greater than zero");
|
require(_amount != 0, "Amount must be greater than zero");
|
||||||
// address oracle = priceOracles[_token];
|
address oracle = priceOracles[_token];
|
||||||
// require(oracle != address(0), "Price oracle not set for this token");
|
require(oracle != address(0), "Price oracle not set for this token");
|
||||||
// IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
|
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;
|
uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18;
|
||||||
// require(usdPrice > minStakeLock, "Amount must be greater minStakeLock");
|
require(usdPrice > minStakeLock, "Amount must be greater minStakeLock");
|
||||||
|
|
||||||
// // Update user's dollarsVested
|
// Update user's dollarsVested
|
||||||
// dollarsVested[msg.sender] += usdPrice;
|
dollarsVested[msg.sender] += usdPrice;
|
||||||
// // Update token's vestedTotal
|
// Update token's vestedTotal
|
||||||
// vestedTotal[_token] += _amount;
|
vestedTotal[_token] += _amount;
|
||||||
|
|
||||||
|
|
||||||
// vestings[msg.sender].push(Vesting({
|
vestings[msg.sender].push(Vesting({
|
||||||
// amount: _amount,
|
amount: _amount,
|
||||||
// bonus: bonus,
|
bonus: bonus,
|
||||||
// lockedUntil: block.timestamp + lockupDuration,
|
lockedUntil: block.timestamp + lockupDuration,
|
||||||
// claimedAmount: 0,
|
claimedAmount: 0,
|
||||||
// claimedBonus: 0,
|
claimedBonus: 0,
|
||||||
// lastClaimed: block.timestamp,
|
lastClaimed: block.timestamp,
|
||||||
// createdAt: block.timestamp,
|
createdAt: block.timestamp,
|
||||||
// token: _token,
|
token: _token,
|
||||||
// complete: false,
|
complete: false,
|
||||||
// usdAmount: usdPrice
|
usdAmount: usdPrice
|
||||||
// }));
|
}));
|
||||||
|
|
||||||
// emit VestingCreated(msg.sender, _amount, bonus);
|
emit VestingCreated(msg.sender, _amount, bonus);
|
||||||
// }
|
}
|
||||||
|
|
||||||
function getUnlockedVesting(address _user, uint256 _vestingIndex) public view returns (uint256) {
|
function getUnlockedVesting(address _user, uint256 _vestingIndex) public view returns (uint256) {
|
||||||
Vesting storage vesting = vestings[_user][_vestingIndex];
|
Vesting storage vesting = vestings[_user][_vestingIndex];
|
||||||
@@ -778,108 +869,108 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// function claimVesting(uint256 _vestingIndex) external nonReentrant {
|
function claimVesting(uint256 _vestingIndex) external nonReentrant {
|
||||||
// Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
||||||
// require(vesting.complete == false, "Stake is Complete");
|
require(vesting.complete == false, "Stake is Complete");
|
||||||
// uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex);
|
uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex);
|
||||||
|
|
||||||
// require(maxClaim >= vesting.claimedAmount, "Invalid claim amount");
|
require(maxClaim >= vesting.claimedAmount, "Invalid claim amount");
|
||||||
// uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
||||||
// require(amountToClaim != 0, "No vested amount to claim");
|
require(amountToClaim != 0, "No vested amount to claim");
|
||||||
|
|
||||||
// vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
||||||
// if (vesting.claimedAmount >= vesting.amount) {
|
if (vesting.claimedAmount >= vesting.amount) {
|
||||||
// vesting.complete = true;
|
vesting.complete = true;
|
||||||
// }
|
}
|
||||||
// // Update user's dollarsVested
|
// Update user's dollarsVested
|
||||||
// if (dollarsVested[msg.sender] > 0) {
|
if (dollarsVested[msg.sender] > 0) {
|
||||||
// uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18;
|
uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18;
|
||||||
// if (usdPrice >= dollarsVested[msg.sender]) {
|
if (usdPrice >= dollarsVested[msg.sender]) {
|
||||||
// dollarsVested[msg.sender] = 0;
|
dollarsVested[msg.sender] = 0;
|
||||||
// } else {
|
} else {
|
||||||
// dollarsVested[msg.sender] -= usdPrice;
|
dollarsVested[msg.sender] -= usdPrice;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// vestedTotal[vesting.token] -= amountToClaim;
|
vestedTotal[vesting.token] -= amountToClaim;
|
||||||
// IERC20(vesting.token).safeTransfer(msg.sender, amountToClaim);
|
IERC20(vesting.token).safeTransfer(msg.sender, amountToClaim);
|
||||||
|
|
||||||
// emit VestingClaimed(msg.sender, amountToClaim, 0);
|
emit VestingClaimed(msg.sender, amountToClaim, 0);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// function claimAllVestingByToken(address _token) external nonReentrant {
|
function claimAllVestingByToken(address _token) external nonReentrant {
|
||||||
// uint256 totalReward = 0;
|
uint256 totalReward = 0;
|
||||||
// uint256 vestingsProcessed = 0;
|
uint256 vestingsProcessed = 0;
|
||||||
|
|
||||||
// for (uint256 i = 0; i < vestings[msg.sender].length; ++i) {
|
for (uint256 i = 0; i < vestings[msg.sender].length; ++i) {
|
||||||
// Vesting storage vesting = vestings[msg.sender][i];
|
Vesting storage vesting = vestings[msg.sender][i];
|
||||||
|
|
||||||
// if (vesting.token == _token && !vesting.complete) {
|
if (vesting.token == _token && !vesting.complete) {
|
||||||
// uint256 maxClaim = getUnlockedVesting(msg.sender, i);
|
uint256 maxClaim = getUnlockedVesting(msg.sender, i);
|
||||||
// require(maxClaim >= vesting.claimedAmount, "Invalid claim amount");
|
require(maxClaim >= vesting.claimedAmount, "Invalid claim amount");
|
||||||
|
|
||||||
// uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
||||||
// if (amountToClaim > 0) {
|
if (amountToClaim > 0) {
|
||||||
// vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
||||||
// totalReward = totalReward + amountToClaim;
|
totalReward = totalReward + amountToClaim;
|
||||||
// vesting.lastClaimed = block.timestamp;
|
vesting.lastClaimed = block.timestamp;
|
||||||
|
|
||||||
// // Mark vesting as complete if fully claimed
|
// Mark vesting as complete if fully claimed
|
||||||
// if (vesting.claimedAmount >= vesting.amount) {
|
if (vesting.claimedAmount >= vesting.amount) {
|
||||||
// vesting.complete = true;
|
vesting.complete = true;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// vestingsProcessed++;
|
vestingsProcessed++;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// require(totalReward != 0, "No rewards to claim");
|
require(totalReward != 0, "No rewards to claim");
|
||||||
|
|
||||||
// // Update user's dollarsVested
|
// Update user's dollarsVested
|
||||||
// if (dollarsVested[msg.sender] > 0) {
|
if (dollarsVested[msg.sender] > 0) {
|
||||||
// uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18;
|
uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18;
|
||||||
// if (usdPrice >= dollarsVested[msg.sender]) {
|
if (usdPrice >= dollarsVested[msg.sender]) {
|
||||||
// dollarsVested[msg.sender] = 0;
|
dollarsVested[msg.sender] = 0;
|
||||||
// } else {
|
} else {
|
||||||
// dollarsVested[msg.sender] -= usdPrice;
|
dollarsVested[msg.sender] -= usdPrice;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Ensure the contract has enough balance to fulfill the claim
|
// Ensure the contract has enough balance to fulfill the claim
|
||||||
// uint256 poolBalance = IERC20(_token).balanceOf(address(this));
|
uint256 poolBalance = IERC20(_token).balanceOf(address(this));
|
||||||
// require(poolBalance >= totalReward, "Insufficient rewards in the pool");
|
require(poolBalance >= totalReward, "Insufficient rewards in the pool");
|
||||||
// // Update vesting total
|
// Update vesting total
|
||||||
// vestedTotal[_token] -= totalReward;
|
vestedTotal[_token] -= totalReward;
|
||||||
// // Transfer the aggregated reward
|
// Transfer the aggregated reward
|
||||||
// IERC20(_token).safeTransfer(msg.sender, totalReward);
|
IERC20(_token).safeTransfer(msg.sender, totalReward);
|
||||||
|
|
||||||
// emit RewardClaimed(msg.sender, totalReward);
|
emit RewardClaimed(msg.sender, totalReward);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// function claimBonus(uint256 _vestingIndex) external nonReentrant {
|
function claimBonus(uint256 _vestingIndex) external nonReentrant {
|
||||||
// Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
||||||
// uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex);
|
uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex);
|
||||||
|
|
||||||
// require(maxBonus >= vesting.claimedBonus, "Invalid claim amount");
|
require(maxBonus >= vesting.claimedBonus, "Invalid claim amount");
|
||||||
// uint256 bonusToClaim = maxBonus - vesting.claimedBonus;
|
uint256 bonusToClaim = maxBonus - vesting.claimedBonus;
|
||||||
// require(bonusToClaim != 0, "No vested amount to claim");
|
require(bonusToClaim != 0, "No vested amount to claim");
|
||||||
|
|
||||||
// vesting.claimedBonus = vesting.claimedBonus + bonusToClaim;
|
vesting.claimedBonus = vesting.claimedBonus + bonusToClaim;
|
||||||
// withdrawLiabilities += 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.
|
// Create temporary the stake for the user to delay withdraw.
|
||||||
// // Add 1e6 to the vesting index to distinguish them from normal stakes.
|
// Add 1e6 to the vesting index to distinguish them from normal stakes.
|
||||||
// withdrawStake[msg.sender].push(WithdrawStake({
|
withdrawStake[msg.sender].push(WithdrawStake({
|
||||||
// stakeId: _vestingIndex + 1e6,
|
stakeId: _vestingIndex + 1e6,
|
||||||
// amount: bonusToClaim,
|
amount: bonusToClaim,
|
||||||
// unlockTime: block.timestamp + unlockDelay
|
unlockTime: block.timestamp + unlockDelay
|
||||||
// }));
|
}));
|
||||||
|
|
||||||
// emit BonusClaimed(msg.sender, bonusToClaim);
|
emit BonusClaimed(msg.sender, bonusToClaim);
|
||||||
// }
|
}
|
||||||
|
|
||||||
function setPriceOracle(address _token, address _oracle) external onlyOwner {
|
function setPriceOracle(address _token, address _oracle) external onlyOwner {
|
||||||
priceOracles[_token] = _oracle;
|
priceOracles[_token] = _oracle;
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
modifier onlyBot() {
|
modifier onlyBot() {
|
||||||
require(authorizedBots[msg.sender], "Caller is not an authorized bot");
|
require(authorizedBots[msg.sender], "Not bot");
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +209,10 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
unlockDelay = _delay;
|
unlockDelay = _delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updatePoolRewards(uint256 _amount) external onlyOwner {
|
||||||
|
pool.totalRewards = _amount;
|
||||||
|
}
|
||||||
|
|
||||||
function updateRestakeBonus(uint256 _newBonus) external onlyOwner {
|
function updateRestakeBonus(uint256 _newBonus) external onlyOwner {
|
||||||
restakeBonus = _newBonus;
|
restakeBonus = _newBonus;
|
||||||
}
|
}
|
||||||
@@ -377,157 +381,188 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
withdrawLiabilities -= clearedStakes;
|
withdrawLiabilities -= clearedStakes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @dev Extends the lastClaimed and unlockTime for all stakes of a given address
|
// * @dev Extends the lastClaimed and unlockTime for all stakes of a given address
|
||||||
* @param _address The address whose stakes to extend
|
// * @param _address The address whose stakes to extend
|
||||||
* @param _seconds The number of seconds to add to lastClaimed and unlockTime
|
// * @param _seconds The number of seconds to add to lastClaimed and unlockTime
|
||||||
*/
|
// */
|
||||||
function extendStakes(address _address, uint256 _seconds) external onlyBot {
|
// function extendStakes(address _address, uint256 _seconds) external onlyBot {
|
||||||
if (_seconds == 0) return; // Early exit for zero seconds
|
// if (_seconds == 0) return; // Early exit for zero seconds
|
||||||
|
|
||||||
Stake[] storage userStakes = stakes[_address];
|
// Stake[] storage userStakes = stakes[_address];
|
||||||
uint256 length = userStakes.length;
|
// uint256 length = userStakes.length;
|
||||||
|
|
||||||
if (length == 0) return; // Early exit for no stakes
|
// if (length == 0) return; // Early exit for no stakes
|
||||||
|
|
||||||
// Cache the stake reference to avoid repeated array access
|
// // Cache the stake reference to avoid repeated array access
|
||||||
for (uint256 i; i < length;) {
|
// for (uint256 i; i < length;) {
|
||||||
Stake storage stake = userStakes[i];
|
// Stake storage stake = userStakes[i];
|
||||||
|
|
||||||
// Only extend active stakes with non-zero amounts
|
// // Only extend active stakes with non-zero amounts
|
||||||
if (!stake.complete && stake.amount > 0) {
|
// if (!stake.complete && stake.amount > 0) {
|
||||||
unchecked {
|
// unchecked {
|
||||||
stake.lastClaimed += _seconds;
|
// stake.lastClaimed += _seconds;
|
||||||
stake.unlockTime += _seconds;
|
// stake.unlockTime += _seconds;
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// unchecked { ++i; }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @dev Extends the lockedUntil, lastClaimed, and createdAt for all vestings of a given address
|
||||||
|
// * @param _address The address whose vestings to extend
|
||||||
|
// * @param _seconds The number of seconds to add to the timestamps
|
||||||
|
// */
|
||||||
|
// function extendVestings(address _address, uint256 _seconds) external onlyBot {
|
||||||
|
// if (_seconds == 0) return; // Early exit for zero seconds
|
||||||
|
|
||||||
|
// Vesting[] storage userVestings = vestings[_address];
|
||||||
|
// uint256 length = userVestings.length;
|
||||||
|
|
||||||
|
// if (length == 0) return; // Early exit for no vestings
|
||||||
|
|
||||||
|
// // Cache the vesting reference to avoid repeated array access
|
||||||
|
// for (uint256 i; i < length;) {
|
||||||
|
// Vesting storage vesting = userVestings[i];
|
||||||
|
|
||||||
|
// // Only extend active vestings with non-zero amounts
|
||||||
|
// if (!vesting.complete && vesting.amount > 0) {
|
||||||
|
// unchecked {
|
||||||
|
// vesting.lockedUntil += _seconds;
|
||||||
|
// vesting.lastClaimed += _seconds;
|
||||||
|
// vesting.createdAt += _seconds;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// unchecked { ++i; }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function adminClearSellStake(address _seller, uint256 _stakeId) external onlyOwner {
|
||||||
|
// SellStake storage sellStakeEntry = sellStakes[_seller][_stakeId];
|
||||||
|
// require(sellStakeEntry.amount != 0, "Sell stake not found");
|
||||||
|
|
||||||
|
// // Access the original stake.
|
||||||
|
// Stake storage stake = stakes[_seller][_stakeId];
|
||||||
|
// require(stake.amount == 0, "Stake not in sell state");
|
||||||
|
|
||||||
|
// // Restore the original stake's amount.
|
||||||
|
// // stake.amount = sellStakeEntry.amount;
|
||||||
|
|
||||||
|
// delete sellStakes[_seller][_stakeId];
|
||||||
|
|
||||||
|
// // Remove the key from the iteration array using swap-and-pop.
|
||||||
|
// uint256 index = sellStakeKeyIndex[_seller][_stakeId];
|
||||||
|
// uint256 lastIndex = sellStakeKeys.length - 1;
|
||||||
|
// if (index != lastIndex) {
|
||||||
|
// SellStakeKey memory lastKey = sellStakeKeys[lastIndex];
|
||||||
|
// sellStakeKeys[index] = lastKey;
|
||||||
|
// sellStakeKeyIndex[lastKey.seller][lastKey.stakeId] = index;
|
||||||
|
// }
|
||||||
|
// sellStakeKeys.pop();
|
||||||
|
// delete sellStakeKeyIndex[_seller][_stakeId];
|
||||||
|
|
||||||
|
// emit StakeSaleCancelled(_seller, _stakeId);
|
||||||
|
// }
|
||||||
|
|
||||||
|
function createStake(uint256 _amount) external {
|
||||||
|
require(_amount > minStakeLock, "Amount must be greater minStakeLock");
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
emit Staked(msg.sender, _amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @notice Restake an expired stake with a bonus daily reward
|
||||||
|
function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external {
|
||||||
|
require(_restakePercentage <= 100, "Invalid percentage");
|
||||||
|
Stake storage stake = stakes[msg.sender][_stakeIndex];
|
||||||
|
// Ensure there is a stake to claim
|
||||||
|
require(stake.amount != 0, "No amount to claim");
|
||||||
|
require(block.timestamp >= stake.unlockTime, "Stake is locked");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Update state before external calls
|
||||||
|
stake.amount = 0;
|
||||||
|
stake.complete = true;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
unchecked { ++i; }
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function adminClearSellStake(address _seller, uint256 _stakeId) external onlyOwner {
|
|
||||||
SellStake storage sellStakeEntry = sellStakes[_seller][_stakeId];
|
|
||||||
require(sellStakeEntry.amount != 0, "Sell stake not found");
|
|
||||||
|
|
||||||
// Access the original stake.
|
|
||||||
Stake storage stake = stakes[_seller][_stakeId];
|
|
||||||
require(stake.amount == 0, "Stake not in sell state");
|
|
||||||
|
|
||||||
// Restore the original stake's amount.
|
|
||||||
// stake.amount = sellStakeEntry.amount;
|
|
||||||
|
|
||||||
delete sellStakes[_seller][_stakeId];
|
|
||||||
|
|
||||||
// Remove the key from the iteration array using swap-and-pop.
|
|
||||||
uint256 index = sellStakeKeyIndex[_seller][_stakeId];
|
|
||||||
uint256 lastIndex = sellStakeKeys.length - 1;
|
|
||||||
if (index != lastIndex) {
|
|
||||||
SellStakeKey memory lastKey = sellStakeKeys[lastIndex];
|
|
||||||
sellStakeKeys[index] = lastKey;
|
|
||||||
sellStakeKeyIndex[lastKey.seller][lastKey.stakeId] = index;
|
|
||||||
}
|
|
||||||
sellStakeKeys.pop();
|
|
||||||
delete sellStakeKeyIndex[_seller][_stakeId];
|
|
||||||
|
|
||||||
emit StakeSaleCancelled(_seller, _stakeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// function createStake(uint256 _amount) external {
|
|
||||||
// require(_amount > minStakeLock, "Amount must be greater minStakeLock");
|
|
||||||
|
|
||||||
// // 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);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 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;
|
|
||||||
|
|
||||||
// emit Staked(msg.sender, _amount);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// /// @notice Restake an expired stake with a bonus daily reward
|
|
||||||
// function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external {
|
|
||||||
// require(_restakePercentage <= 100, "Invalid restake percentage");
|
|
||||||
// Stake storage stake = stakes[msg.sender][_stakeIndex];
|
|
||||||
// // Ensure there is a stake to claim
|
|
||||||
// require(stake.amount != 0, "No amount to claim");
|
|
||||||
// require(block.timestamp >= stake.unlockTime, "Stake is still locked");
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// // Update state before external calls
|
|
||||||
// stake.amount = 0;
|
|
||||||
// stake.complete = true;
|
|
||||||
|
|
||||||
// // 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
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// // 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);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
function createStakeForUser(address _user, uint256 _amount) external onlyOwner {
|
function createStakeForUser(address _user, uint256 _amount) external onlyOwner {
|
||||||
require(_amount != 0, "Invalid amount");
|
require(_amount != 0, "Invalid amount");
|
||||||
|
|
||||||
@@ -591,177 +626,177 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
return finalRewardRate;
|
return finalRewardRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function claimRewards() external nonReentrant {
|
function claimRewards() external nonReentrant {
|
||||||
// uint256 totalReward = 0;
|
uint256 totalReward = 0;
|
||||||
|
|
||||||
// for (uint256 i = 0; i < stakes[msg.sender].length; ++i) {
|
for (uint256 i = 0; i < stakes[msg.sender].length; ++i) {
|
||||||
// Stake storage stake = stakes[msg.sender][i];
|
Stake storage stake = stakes[msg.sender][i];
|
||||||
// if (stake.amount > 0) {
|
if (stake.amount > 0) {
|
||||||
// uint rewards = getPoolRewards(msg.sender, i);
|
uint rewards = getPoolRewards(msg.sender, i);
|
||||||
// totalReward = totalReward + rewards;
|
totalReward = totalReward + rewards;
|
||||||
// stake.lastClaimed = block.timestamp;
|
stake.lastClaimed = block.timestamp;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// require(totalReward != 0, "No rewards to claim");
|
require(totalReward != 0, "No rewards");
|
||||||
// require(pool.totalRewards >= totalReward, "Insufficient rewards in the pool");
|
require(pool.totalRewards >= totalReward, "Insufficient rewards");
|
||||||
|
|
||||||
// pool.totalRewards = pool.totalRewards - totalReward;
|
pool.totalRewards = pool.totalRewards - totalReward;
|
||||||
// IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward);
|
IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward);
|
||||||
|
|
||||||
// emit RewardClaimed(msg.sender, totalReward);
|
emit RewardClaimed(msg.sender, totalReward);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// function claimStake(uint256 _stakeIndex) external nonReentrant {
|
function claimStake(uint256 _stakeIndex) external nonReentrant {
|
||||||
// // Ensure the stake index is valid
|
// Ensure the stake index is valid
|
||||||
// require(_stakeIndex < stakes[msg.sender].length, "Invalid stake index");
|
require(_stakeIndex < stakes[msg.sender].length, "Invalid stake index");
|
||||||
|
|
||||||
// // Load the stake
|
// Load the stake
|
||||||
// Stake storage stake = stakes[msg.sender][_stakeIndex];
|
Stake storage stake = stakes[msg.sender][_stakeIndex];
|
||||||
// uint256 _amount = stake.amount;
|
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
|
// Ensure there is a stake to claim
|
||||||
// require(_amount != 0, "No amount to claim");
|
require(_amount != 0, "amount 0");
|
||||||
|
|
||||||
// // Ensure the stake is unlocked (if using lockup periods)
|
// Ensure the stake is unlocked (if using lockup periods)
|
||||||
// require(block.timestamp >= stake.unlockTime, "Stake is still locked");
|
require(block.timestamp >= stake.unlockTime, "Stake locked");
|
||||||
|
|
||||||
// // Update state before external calls
|
// Update state before external calls
|
||||||
// stake.amount = 0;
|
stake.amount = 0;
|
||||||
// stake.complete = true;
|
stake.complete = true;
|
||||||
// withdrawLiabilities += _amount;
|
withdrawLiabilities += _amount;
|
||||||
|
|
||||||
// if (pool.totalStaked >= _amount) {
|
if (pool.totalStaked >= _amount) {
|
||||||
// pool.totalStaked -= _amount;
|
pool.totalStaked -= _amount;
|
||||||
// } else {
|
} else {
|
||||||
// pool.totalStaked = 0;
|
pool.totalStaked = 0;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Create temporary the stake for the user to delay withdraw
|
// Create temporary the stake for the user to delay withdraw
|
||||||
// withdrawStake[msg.sender].push(WithdrawStake({
|
withdrawStake[msg.sender].push(WithdrawStake({
|
||||||
// stakeId: _stakeIndex,
|
stakeId: _stakeIndex,
|
||||||
// amount: _amount,
|
amount: _amount,
|
||||||
// unlockTime: block.timestamp + unlockDelay
|
unlockTime: block.timestamp + unlockDelay
|
||||||
// }));
|
}));
|
||||||
|
|
||||||
// // Emit a detailed event
|
// Emit a detailed event
|
||||||
// emit RewardClaimed(msg.sender, _amount);
|
emit RewardClaimed(msg.sender, _amount);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * @notice Withdraw a staked amount after its unlock time has passed.
|
* @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,
|
* @dev Locates the stake by `_stakeIndex`, checks that it's unlocked and non-zero,
|
||||||
// * and transfers tokens to the caller.
|
* and transfers tokens to the caller.
|
||||||
// *
|
*
|
||||||
// * Requirements:
|
* Requirements:
|
||||||
// * - Caller must have at least one stake.
|
* - Caller must have at least one stake.
|
||||||
// * - The stake must exist, be unlocked, and have a non-zero amount.
|
* - The stake must exist, be unlocked, and have a non-zero amount.
|
||||||
// * - The contract must have sufficient token balance.
|
* - The contract must have sufficient token balance.
|
||||||
// *
|
*
|
||||||
// * @param _stakeIndex The identifier of the stake to withdraw.
|
* @param _stakeIndex The identifier of the stake to withdraw.
|
||||||
// */
|
*/
|
||||||
// function withdraw(uint256 _stakeIndex) external nonReentrant {
|
function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||||
// WithdrawStake[] storage userStakes = withdrawStake[msg.sender];
|
WithdrawStake[] storage userStakes = withdrawStake[msg.sender];
|
||||||
// require(userStakes.length > 0, "No stakes available for withdrawal");
|
require(userStakes.length > 0, "No stakes");
|
||||||
|
|
||||||
// for (uint256 i = 0; i < userStakes.length; ++i) {
|
for (uint256 i = 0; i < userStakes.length; ++i) {
|
||||||
// WithdrawStake storage stake = userStakes[i];
|
WithdrawStake storage stake = userStakes[i];
|
||||||
// if (stake.stakeId == _stakeIndex && stake.amount != 0) {
|
if (stake.stakeId == _stakeIndex && stake.amount != 0) {
|
||||||
// require(block.timestamp >= stake.unlockTime, "Withdraw Stake is still locked");
|
require(block.timestamp >= stake.unlockTime, "Withdraw locked");
|
||||||
|
|
||||||
// uint256 _amount = stake.amount;
|
uint256 _amount = stake.amount;
|
||||||
// uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this));
|
uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this));
|
||||||
// require(poolBalance >= _amount, "Insufficient rewards in the pool");
|
require(poolBalance >= _amount, "Insufficient rewards");
|
||||||
|
|
||||||
// // Update state before external calls
|
// Update state before external calls
|
||||||
// withdrawLiabilities -= _amount;
|
withdrawLiabilities -= _amount;
|
||||||
// stake.amount = 0;
|
stake.amount = 0;
|
||||||
|
|
||||||
// // Transfer tokens
|
// Transfer tokens
|
||||||
// IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount);
|
IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount);
|
||||||
// emit StakeWithdrawn(msg.sender, _amount, _stakeIndex);
|
emit StakeWithdrawn(msg.sender, _amount, _stakeIndex);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Revert if no matching stake with non-zero amount was found
|
// Revert if no matching stake with non-zero amount was found
|
||||||
// revert("Invalid stake index or already withdrawn");
|
revert("Invalid stake");
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// function compoundAllRewards() external {
|
function compoundAllRewards() external {
|
||||||
// uint256 totalReward = 0;
|
uint256 totalReward = 0;
|
||||||
|
|
||||||
// for (uint256 i = 0; i < stakes[msg.sender].length; ++i) {
|
for (uint256 i = 0; i < stakes[msg.sender].length; ++i) {
|
||||||
// Stake storage stake = stakes[msg.sender][i];
|
Stake storage stake = stakes[msg.sender][i];
|
||||||
// if (stake.amount > 0) {
|
if (stake.amount > 0) {
|
||||||
// uint rewards = getPoolRewards(msg.sender, i);
|
uint rewards = getPoolRewards(msg.sender, i);
|
||||||
// totalReward = totalReward + rewards;
|
totalReward = totalReward + rewards;
|
||||||
// stake.lastClaimed = block.timestamp;
|
stake.lastClaimed = block.timestamp;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// require(totalReward > minStakeLock, "Not enough to compound");
|
require(totalReward > minStakeLock, "Not enough to compound");
|
||||||
|
|
||||||
// // Check if user has a fixed reward rate set
|
// Check if user has a fixed reward rate set
|
||||||
// uint256 finalRewardRate;
|
uint256 finalRewardRate;
|
||||||
// if (addressFixedRate[msg.sender] > 0) {
|
if (addressFixedRate[msg.sender] > 0) {
|
||||||
// // Use the fixed rate
|
// Use the fixed rate
|
||||||
// finalRewardRate = addressFixedRate[msg.sender];
|
finalRewardRate = addressFixedRate[msg.sender];
|
||||||
// } else {
|
} else {
|
||||||
// // Default logic, restake = false
|
// Default logic, restake = false
|
||||||
// finalRewardRate = getUserRewardRate(msg.sender, false);
|
finalRewardRate = getUserRewardRate(msg.sender, false);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// stakes[msg.sender].push(Stake({
|
stakes[msg.sender].push(Stake({
|
||||||
// amount: totalReward,
|
amount: totalReward,
|
||||||
// lastClaimed: block.timestamp,
|
lastClaimed: block.timestamp,
|
||||||
// dailyRewardRate: finalRewardRate,
|
dailyRewardRate: finalRewardRate,
|
||||||
// unlockTime: block.timestamp + pool.lockupPeriod,
|
unlockTime: block.timestamp + pool.lockupPeriod,
|
||||||
// complete: false
|
complete: false
|
||||||
// }));
|
}));
|
||||||
|
|
||||||
// pool.totalStaked = pool.totalStaked + totalReward;
|
pool.totalStaked = pool.totalStaked + totalReward;
|
||||||
// emit CompoundRewards(msg.sender, totalReward);
|
emit CompoundRewards(msg.sender, totalReward);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// function createVesting(address _token, uint256 _amount) external {
|
function createVesting(address _token, uint256 _amount) external {
|
||||||
// require(_amount != 0, "Amount must be greater than zero");
|
require(_amount != 0, "Amount must be greater than zero");
|
||||||
// address oracle = priceOracles[_token];
|
address oracle = priceOracles[_token];
|
||||||
// require(oracle != address(0), "Price oracle not set for this token");
|
require(oracle != address(0), "Oracle not set");
|
||||||
// IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
|
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;
|
uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18;
|
||||||
// require(usdPrice > minStakeLock, "Amount must be greater minStakeLock");
|
require(usdPrice > minStakeLock, "Amount must be greater minStakeLock");
|
||||||
|
|
||||||
// // Update user's dollarsVested
|
// Update user's dollarsVested
|
||||||
// dollarsVested[msg.sender] += usdPrice;
|
dollarsVested[msg.sender] += usdPrice;
|
||||||
// // Update token's vestedTotal
|
// Update token's vestedTotal
|
||||||
// vestedTotal[_token] += _amount;
|
vestedTotal[_token] += _amount;
|
||||||
|
|
||||||
|
|
||||||
// vestings[msg.sender].push(Vesting({
|
vestings[msg.sender].push(Vesting({
|
||||||
// amount: _amount,
|
amount: _amount,
|
||||||
// bonus: bonus,
|
bonus: bonus,
|
||||||
// lockedUntil: block.timestamp + lockupDuration,
|
lockedUntil: block.timestamp + lockupDuration,
|
||||||
// claimedAmount: 0,
|
claimedAmount: 0,
|
||||||
// claimedBonus: 0,
|
claimedBonus: 0,
|
||||||
// lastClaimed: block.timestamp,
|
lastClaimed: block.timestamp,
|
||||||
// createdAt: block.timestamp,
|
createdAt: block.timestamp,
|
||||||
// token: _token,
|
token: _token,
|
||||||
// complete: false,
|
complete: false,
|
||||||
// usdAmount: usdPrice
|
usdAmount: usdPrice
|
||||||
// }));
|
}));
|
||||||
|
|
||||||
// emit VestingCreated(msg.sender, _amount, bonus);
|
emit VestingCreated(msg.sender, _amount, bonus);
|
||||||
// }
|
}
|
||||||
|
|
||||||
function getUnlockedVesting(address _user, uint256 _vestingIndex) public view returns (uint256) {
|
function getUnlockedVesting(address _user, uint256 _vestingIndex) public view returns (uint256) {
|
||||||
Vesting storage vesting = vestings[_user][_vestingIndex];
|
Vesting storage vesting = vestings[_user][_vestingIndex];
|
||||||
@@ -824,108 +859,108 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// function claimVesting(uint256 _vestingIndex) external nonReentrant {
|
function claimVesting(uint256 _vestingIndex) external nonReentrant {
|
||||||
// Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
||||||
// require(vesting.complete == false, "Stake is Complete");
|
require(vesting.complete == false, "Stake Complete");
|
||||||
// uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex);
|
uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex);
|
||||||
|
|
||||||
// require(maxClaim >= vesting.claimedAmount, "Invalid claim amount");
|
require(maxClaim >= vesting.claimedAmount, "Invalid claim");
|
||||||
// uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
||||||
// require(amountToClaim != 0, "No vested amount to claim");
|
require(amountToClaim != 0, "Claim 0");
|
||||||
|
|
||||||
// vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
||||||
// if (vesting.claimedAmount >= vesting.amount) {
|
if (vesting.claimedAmount >= vesting.amount) {
|
||||||
// vesting.complete = true;
|
vesting.complete = true;
|
||||||
// }
|
}
|
||||||
// // Update user's dollarsVested
|
// Update user's dollarsVested
|
||||||
// if (dollarsVested[msg.sender] > 0) {
|
if (dollarsVested[msg.sender] > 0) {
|
||||||
// uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18;
|
uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18;
|
||||||
// if (usdPrice >= dollarsVested[msg.sender]) {
|
if (usdPrice >= dollarsVested[msg.sender]) {
|
||||||
// dollarsVested[msg.sender] = 0;
|
dollarsVested[msg.sender] = 0;
|
||||||
// } else {
|
} else {
|
||||||
// dollarsVested[msg.sender] -= usdPrice;
|
dollarsVested[msg.sender] -= usdPrice;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// vestedTotal[vesting.token] -= amountToClaim;
|
vestedTotal[vesting.token] -= amountToClaim;
|
||||||
// IERC20(vesting.token).safeTransfer(msg.sender, amountToClaim);
|
IERC20(vesting.token).safeTransfer(msg.sender, amountToClaim);
|
||||||
|
|
||||||
// emit VestingClaimed(msg.sender, amountToClaim, 0);
|
emit VestingClaimed(msg.sender, amountToClaim, 0);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// function claimAllVestingByToken(address _token) external nonReentrant {
|
function claimAllVestingByToken(address _token) external nonReentrant {
|
||||||
// uint256 totalReward = 0;
|
uint256 totalReward = 0;
|
||||||
// uint256 vestingsProcessed = 0;
|
uint256 vestingsProcessed = 0;
|
||||||
|
|
||||||
// for (uint256 i = 0; i < vestings[msg.sender].length; ++i) {
|
for (uint256 i = 0; i < vestings[msg.sender].length; ++i) {
|
||||||
// Vesting storage vesting = vestings[msg.sender][i];
|
Vesting storage vesting = vestings[msg.sender][i];
|
||||||
|
|
||||||
// if (vesting.token == _token && !vesting.complete) {
|
if (vesting.token == _token && !vesting.complete) {
|
||||||
// uint256 maxClaim = getUnlockedVesting(msg.sender, i);
|
uint256 maxClaim = getUnlockedVesting(msg.sender, i);
|
||||||
// require(maxClaim >= vesting.claimedAmount, "Invalid claim amount");
|
require(maxClaim >= vesting.claimedAmount, "Invalid claim");
|
||||||
|
|
||||||
// uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
||||||
// if (amountToClaim > 0) {
|
if (amountToClaim > 0) {
|
||||||
// vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
||||||
// totalReward = totalReward + amountToClaim;
|
totalReward = totalReward + amountToClaim;
|
||||||
// vesting.lastClaimed = block.timestamp;
|
vesting.lastClaimed = block.timestamp;
|
||||||
|
|
||||||
// // Mark vesting as complete if fully claimed
|
// Mark vesting as complete if fully claimed
|
||||||
// if (vesting.claimedAmount >= vesting.amount) {
|
if (vesting.claimedAmount >= vesting.amount) {
|
||||||
// vesting.complete = true;
|
vesting.complete = true;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// vestingsProcessed++;
|
vestingsProcessed++;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// require(totalReward != 0, "No rewards to claim");
|
require(totalReward != 0, "No rewards to claim");
|
||||||
|
|
||||||
// // Update user's dollarsVested
|
// Update user's dollarsVested
|
||||||
// if (dollarsVested[msg.sender] > 0) {
|
if (dollarsVested[msg.sender] > 0) {
|
||||||
// uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18;
|
uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18;
|
||||||
// if (usdPrice >= dollarsVested[msg.sender]) {
|
if (usdPrice >= dollarsVested[msg.sender]) {
|
||||||
// dollarsVested[msg.sender] = 0;
|
dollarsVested[msg.sender] = 0;
|
||||||
// } else {
|
} else {
|
||||||
// dollarsVested[msg.sender] -= usdPrice;
|
dollarsVested[msg.sender] -= usdPrice;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Ensure the contract has enough balance to fulfill the claim
|
// Ensure the contract has enough balance to fulfill the claim
|
||||||
// uint256 poolBalance = IERC20(_token).balanceOf(address(this));
|
uint256 poolBalance = IERC20(_token).balanceOf(address(this));
|
||||||
// require(poolBalance >= totalReward, "Insufficient rewards in the pool");
|
require(poolBalance >= totalReward, "Insufficient rewards");
|
||||||
// // Update vesting total
|
// Update vesting total
|
||||||
// vestedTotal[_token] -= totalReward;
|
vestedTotal[_token] -= totalReward;
|
||||||
// // Transfer the aggregated reward
|
// Transfer the aggregated reward
|
||||||
// IERC20(_token).safeTransfer(msg.sender, totalReward);
|
IERC20(_token).safeTransfer(msg.sender, totalReward);
|
||||||
|
|
||||||
// emit RewardClaimed(msg.sender, totalReward);
|
emit RewardClaimed(msg.sender, totalReward);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// function claimBonus(uint256 _vestingIndex) external nonReentrant {
|
function claimBonus(uint256 _vestingIndex) external nonReentrant {
|
||||||
// Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
||||||
// uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex);
|
uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex);
|
||||||
|
|
||||||
// require(maxBonus >= vesting.claimedBonus, "Invalid claim amount");
|
require(maxBonus >= vesting.claimedBonus, "Invalid claim amount");
|
||||||
// uint256 bonusToClaim = maxBonus - vesting.claimedBonus;
|
uint256 bonusToClaim = maxBonus - vesting.claimedBonus;
|
||||||
// require(bonusToClaim != 0, "No vested amount to claim");
|
require(bonusToClaim != 0, "No claim");
|
||||||
|
|
||||||
// vesting.claimedBonus = vesting.claimedBonus + bonusToClaim;
|
vesting.claimedBonus = vesting.claimedBonus + bonusToClaim;
|
||||||
// withdrawLiabilities += 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.
|
// Create temporary the stake for the user to delay withdraw.
|
||||||
// // Add 1e6 to the vesting index to distinguish them from normal stakes.
|
// Add 1e6 to the vesting index to distinguish them from normal stakes.
|
||||||
// withdrawStake[msg.sender].push(WithdrawStake({
|
withdrawStake[msg.sender].push(WithdrawStake({
|
||||||
// stakeId: _vestingIndex + 1e6,
|
stakeId: _vestingIndex + 1e6,
|
||||||
// amount: bonusToClaim,
|
amount: bonusToClaim,
|
||||||
// unlockTime: block.timestamp + unlockDelay
|
unlockTime: block.timestamp + unlockDelay
|
||||||
// }));
|
}));
|
||||||
|
|
||||||
// emit BonusClaimed(msg.sender, bonusToClaim);
|
emit BonusClaimed(msg.sender, bonusToClaim);
|
||||||
// }
|
}
|
||||||
|
|
||||||
function setPriceOracle(address _token, address _oracle) external onlyOwner {
|
function setPriceOracle(address _token, address _oracle) external onlyOwner {
|
||||||
priceOracles[_token] = _oracle;
|
priceOracles[_token] = _oracle;
|
||||||
@@ -1039,7 +1074,7 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
return userStakes[i];
|
return userStakes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
revert("WithdrawStake with the specified stakeId not found for this user.");
|
revert("WithdrawStake not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Function that lets you look up an address’s stake by vestingId.
|
/// @notice Function that lets you look up an address’s stake by vestingId.
|
||||||
@@ -1053,7 +1088,7 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
return userStakes[i];
|
return userStakes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
revert("WithdrawStake with the specified stakeId not found for this user.");
|
revert("WithdrawStake not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Function that returns an array of all the user's withdrawStakes.
|
/// @notice Function that returns an array of all the user's withdrawStakes.
|
||||||
@@ -1069,11 +1104,11 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
/// @param price The price of the stake.
|
/// @param price The price of the stake.
|
||||||
function sellStake(uint256 _stakeId, uint256 price) external {
|
function sellStake(uint256 _stakeId, uint256 price) external {
|
||||||
Stake storage stake = stakes[msg.sender][_stakeId];
|
Stake storage stake = stakes[msg.sender][_stakeId];
|
||||||
require(!stake.complete, "Stake already complete");
|
require(!stake.complete, "Stake complete");
|
||||||
require(stake.amount != 0, "Stake amount is 0");
|
require(stake.amount != 0, "Amount 0");
|
||||||
// Ensure the stake isn't already on sale.
|
// Ensure the stake isn't already on sale.
|
||||||
require(sellStakes[msg.sender][_stakeId].amount == 0, "Stake already on sale");
|
require(sellStakes[msg.sender][_stakeId].amount == 0, "Stake already on sale");
|
||||||
require(price >= (stake.amount * sellMin) / 100, "Price is too low");
|
require(price >= (stake.amount * sellMin) / 100, "Price too low");
|
||||||
|
|
||||||
// Create a SellStake entry directly in the mapping.
|
// Create a SellStake entry directly in the mapping.
|
||||||
sellStakes[msg.sender][_stakeId] = SellStake({
|
sellStakes[msg.sender][_stakeId] = SellStake({
|
||||||
@@ -1100,11 +1135,11 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
/// @param _stakeId The stake ID to cancel the sale.
|
/// @param _stakeId The stake ID to cancel the sale.
|
||||||
function cancelSellStake(uint256 _stakeId) external {
|
function cancelSellStake(uint256 _stakeId) external {
|
||||||
SellStake storage sellStakeEntry = sellStakes[msg.sender][_stakeId];
|
SellStake storage sellStakeEntry = sellStakes[msg.sender][_stakeId];
|
||||||
require(sellStakeEntry.amount != 0, "Sell stake not found");
|
require(sellStakeEntry.amount != 0, "Stake not found");
|
||||||
|
|
||||||
// Access the original stake.
|
// Access the original stake.
|
||||||
Stake storage stake = stakes[msg.sender][_stakeId];
|
Stake storage stake = stakes[msg.sender][_stakeId];
|
||||||
require(stake.amount == 0, "Stake not in sell state");
|
require(stake.amount == 0, "Stake not for sale");
|
||||||
|
|
||||||
// Restore the original stake's amount.
|
// Restore the original stake's amount.
|
||||||
stake.amount = sellStakeEntry.amount;
|
stake.amount = sellStakeEntry.amount;
|
||||||
@@ -1130,8 +1165,8 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
/// @param newPrice The new price of the stake.
|
/// @param newPrice The new price of the stake.
|
||||||
function updateSellStake(uint256 _stakeId, uint256 newPrice) external {
|
function updateSellStake(uint256 _stakeId, uint256 newPrice) external {
|
||||||
SellStake storage sellStakeEntry = sellStakes[msg.sender][_stakeId];
|
SellStake storage sellStakeEntry = sellStakes[msg.sender][_stakeId];
|
||||||
require(sellStakeEntry.amount != 0, "Sell stake not found");
|
require(sellStakeEntry.amount != 0, "Stake not found");
|
||||||
require(newPrice >= (sellStakeEntry.amount * sellMin) / 100, "New price is too low");
|
require(newPrice >= (sellStakeEntry.amount * sellMin) / 100, "New price too low");
|
||||||
|
|
||||||
sellStakeEntry.bonusAmount = (newPrice * sellKickBack) / 100;
|
sellStakeEntry.bonusAmount = (newPrice * sellKickBack) / 100;
|
||||||
sellStakeEntry.price = newPrice;
|
sellStakeEntry.price = newPrice;
|
||||||
@@ -1149,7 +1184,7 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
|
|||||||
/// @param _stakeId The original stake id associated with the sell stake.
|
/// @param _stakeId The original stake id associated with the sell stake.
|
||||||
function buySellStake(address seller, uint256 _stakeId) external nonReentrant {
|
function buySellStake(address seller, uint256 _stakeId) external nonReentrant {
|
||||||
SellStake storage sellStakeEntry = sellStakes[seller][_stakeId];
|
SellStake storage sellStakeEntry = sellStakes[seller][_stakeId];
|
||||||
require(sellStakeEntry.amount != 0, "Sell stake not available");
|
require(sellStakeEntry.amount != 0, "Stake not available");
|
||||||
|
|
||||||
// Transfer the sale price from the buyer to this contract.
|
// Transfer the sale price from the buyer to this contract.
|
||||||
IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), sellStakeEntry.price);
|
IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), sellStakeEntry.price);
|
||||||
|
|||||||
Reference in New Issue
Block a user