Error Refactor and Vesting Delay
This commit is contained in:
@@ -11,6 +11,29 @@ interface iPriceOracle {
|
||||
function getLatestPrice(address token) external view returns (uint256);
|
||||
}
|
||||
|
||||
// Custom errors for gas optimization
|
||||
error NotAuthorized();
|
||||
error AlreadyOwner();
|
||||
error NotOwner();
|
||||
error CannotRemoveSelf();
|
||||
error InvalidAddress();
|
||||
error InvalidAmount();
|
||||
error AmountBelowMinimum();
|
||||
error InvalidRestakePercentage();
|
||||
error StakeLocked();
|
||||
error StakeComplete();
|
||||
error NothingToClaim();
|
||||
error InvalidClaimAmount();
|
||||
error InsufficientRewards();
|
||||
error InvalidStakeIndex();
|
||||
error NoStakesAvailable();
|
||||
error StakeNotFound();
|
||||
error NotEnoughToCompound();
|
||||
error PriceOracleNotSet();
|
||||
error StakeAlreadyOnSale();
|
||||
error PriceTooLow();
|
||||
error StakeNotInSellState();
|
||||
|
||||
// File: paca.sol
|
||||
|
||||
contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUpgradeable {
|
||||
@@ -72,6 +95,13 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
uint256 unlockTime;
|
||||
}
|
||||
|
||||
struct WithdrawVesting {
|
||||
uint256 vestingId;
|
||||
uint256 amount;
|
||||
uint256 unlockTime;
|
||||
address token;
|
||||
}
|
||||
|
||||
struct SellStake {
|
||||
uint256 price;
|
||||
uint256 bonusAmount;
|
||||
@@ -106,6 +136,8 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
uint256 public unlockDelay;
|
||||
uint256 public withdrawLiabilities;
|
||||
mapping(address => WithdrawStake[]) public withdrawStake;
|
||||
mapping(address => WithdrawVesting[]) public withdrawVesting;
|
||||
uint256 private withdrawVestingCounter;
|
||||
uint256 public restakeBonus;
|
||||
mapping(address => uint256) public addressFixedRate;
|
||||
mapping(address => mapping(uint256 => SellStake)) public sellStakes;
|
||||
@@ -134,11 +166,11 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
|
||||
// Modifiers
|
||||
modifier onlyOwner() {
|
||||
require(owners[msg.sender], "Not authorized");
|
||||
if (!owners[msg.sender]) revert NotAuthorized();
|
||||
_;
|
||||
}
|
||||
modifier onlyBot() {
|
||||
require(authorizedBots[msg.sender], "Caller is not an authorized bot");
|
||||
if (!authorizedBots[msg.sender]) revert NotAuthorized();
|
||||
_;
|
||||
}
|
||||
|
||||
@@ -165,19 +197,20 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
|
||||
// Ownership Management
|
||||
function addOwner(address _newOwner) external onlyOwner {
|
||||
require(!owners[_newOwner], "Already an owner");
|
||||
if (owners[_newOwner]) revert AlreadyOwner();
|
||||
owners[_newOwner] = true;
|
||||
}
|
||||
|
||||
function removeOwner(address _owner) external onlyOwner {
|
||||
require(owners[_owner], "Not an owner");
|
||||
require(_owner != msg.sender, "Cannot remove yourself");
|
||||
if (!owners[_owner]) revert NotOwner();
|
||||
if (_owner == msg.sender) revert CannotRemoveSelf();
|
||||
owners[_owner] = false;
|
||||
}
|
||||
|
||||
|
||||
/// @notice Function to add a bot to the list (only callable by the contract owner)
|
||||
function addBot(address bot) external onlyOwner {
|
||||
require(bot != address(0), "Invalid address");
|
||||
if (bot == address(0)) revert InvalidAddress();
|
||||
authorizedBots[bot] = true;
|
||||
}
|
||||
|
||||
@@ -194,6 +227,7 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
emit PoolUpdated(_lockupPeriod, _dailyRewardRate);
|
||||
}
|
||||
|
||||
|
||||
function depositRewards(uint256 _amount) external onlyOwner {
|
||||
IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount);
|
||||
pool.totalRewards = pool.totalRewards + _amount;
|
||||
@@ -239,14 +273,14 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
/// @param _addr The address to give a fixed rate
|
||||
/// @param _rate The fixed rate expressed in 2 digits, ex: 40
|
||||
function addFixedRate(address _addr, uint _rate) external onlyOwner {
|
||||
require(_addr != address(0), "Invalid address");
|
||||
if (_addr == address(0)) revert InvalidAddress();
|
||||
addressFixedRate[_addr] = _rate;
|
||||
}
|
||||
|
||||
/// @notice Function to remove an address' fixed daily reward (only callable by the contract owner)
|
||||
/// @param _addr The address to 0 out
|
||||
function removeFixedRate(address _addr) external onlyOwner {
|
||||
require(_addr != address(0), "Invalid address");
|
||||
if (_addr == address(0)) revert InvalidAddress();
|
||||
addressFixedRate[_addr] = 0;
|
||||
}
|
||||
|
||||
@@ -381,6 +415,53 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
withdrawLiabilities -= clearedStakes;
|
||||
}
|
||||
|
||||
/// @notice Migrates all vestings from an old address to a new address
|
||||
/// @dev Only to be used by bots for account migrations
|
||||
/// @param oldAddress The address with existing vestings to migrate from
|
||||
/// @param newAddress The address to migrate vestings to
|
||||
function migrateVestings(address oldAddress, address newAddress) external onlyBot {
|
||||
if (oldAddress == address(0) || newAddress == address(0) || oldAddress == newAddress) revert InvalidAddress();
|
||||
|
||||
Vesting[] storage oldVestings = vestings[oldAddress];
|
||||
uint256 vestingCount = oldVestings.length;
|
||||
if (vestingCount == 0) revert NoStakesAvailable();
|
||||
|
||||
Vesting[] storage newVestings = vestings[newAddress];
|
||||
|
||||
for (uint256 i = 0; i < vestingCount; i++) {
|
||||
Vesting storage oldVesting = oldVestings[i];
|
||||
|
||||
// Copy vesting to new address
|
||||
newVestings.push(oldVesting);
|
||||
|
||||
// Clear old vesting
|
||||
oldVesting.amount = 0;
|
||||
oldVesting.bonus = 0;
|
||||
oldVesting.lockedUntil = 0;
|
||||
oldVesting.claimedAmount = 0;
|
||||
oldVesting.claimedBonus = 0;
|
||||
oldVesting.lastClaimed = 0;
|
||||
oldVesting.createdAt = 0;
|
||||
oldVesting.usdAmount = 0;
|
||||
oldVesting.complete = true;
|
||||
}
|
||||
|
||||
// Migrate dollars vested
|
||||
dollarsVested[newAddress] += dollarsVested[oldAddress];
|
||||
dollarsVested[oldAddress] = 0;
|
||||
|
||||
// Migrate pending vesting withdrawals
|
||||
WithdrawVesting[] storage oldWithdrawVestings = withdrawVesting[oldAddress];
|
||||
uint256 withdrawVestingCount = oldWithdrawVestings.length;
|
||||
if (withdrawVestingCount > 0) {
|
||||
WithdrawVesting[] storage newWithdrawVestings = withdrawVesting[newAddress];
|
||||
for (uint256 i = 0; i < withdrawVestingCount; i++) {
|
||||
newWithdrawVestings.push(oldWithdrawVestings[i]);
|
||||
}
|
||||
delete withdrawVesting[oldAddress];
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @dev Extends the lastClaimed and unlockTime for all stakes of a given address
|
||||
// * @param _address The address whose stakes to extend
|
||||
@@ -470,7 +551,7 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
|
||||
function createStake(uint256 _amount) external {
|
||||
// Scale up for wei comparison, USDC is 1e6
|
||||
require(_amount * 1e12 > minStakeLock, "Amount must be greater minStakeLock");
|
||||
if (_amount * 1e12 <= minStakeLock) revert AmountBelowMinimum();
|
||||
|
||||
// Transfer tokens from the user into the contract
|
||||
IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount);
|
||||
@@ -503,11 +584,11 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
|
||||
/// @notice Restake an expired stake with a bonus daily reward
|
||||
function restake(uint256 _stakeIndex, uint256 _restakePercentage) nonReentrant external {
|
||||
require(_restakePercentage <= 100, "Invalid restake percentage");
|
||||
if (_restakePercentage > 100) revert InvalidRestakePercentage();
|
||||
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");
|
||||
if (stake.amount == 0) revert NothingToClaim();
|
||||
if (block.timestamp < stake.unlockTime) revert StakeLocked();
|
||||
|
||||
uint256 _amount = stake.amount;
|
||||
uint rewards = getPoolRewards(msg.sender, _stakeIndex);
|
||||
@@ -565,7 +646,7 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
}
|
||||
|
||||
function createStakeForUser(address _user, uint256 _amount) external onlyOwner {
|
||||
require(_amount != 0, "Invalid amount");
|
||||
if (_amount == 0) revert InvalidAmount();
|
||||
|
||||
stakes[_user].push(Stake({
|
||||
amount: _amount,
|
||||
@@ -639,8 +720,8 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
}
|
||||
}
|
||||
|
||||
require(totalReward != 0, "No rewards to claim");
|
||||
require(pool.totalRewards >= totalReward, "Insufficient rewards in the pool");
|
||||
if (totalReward == 0) revert NothingToClaim();
|
||||
if (pool.totalRewards < totalReward) revert InsufficientRewards();
|
||||
|
||||
pool.totalRewards = pool.totalRewards - totalReward;
|
||||
IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward);
|
||||
@@ -651,7 +732,7 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
|
||||
function claimStake(uint256 _stakeIndex) external nonReentrant {
|
||||
// Ensure the stake index is valid
|
||||
require(_stakeIndex < stakes[msg.sender].length, "Invalid stake index");
|
||||
if (_stakeIndex >= stakes[msg.sender].length) revert InvalidStakeIndex();
|
||||
|
||||
// Load the stake
|
||||
Stake storage stake = stakes[msg.sender][_stakeIndex];
|
||||
@@ -662,10 +743,10 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
_amount = _amount + rewards;
|
||||
|
||||
// Ensure there is a stake to claim
|
||||
require(_amount != 0, "No amount to claim");
|
||||
if (_amount == 0) revert NothingToClaim();
|
||||
|
||||
// Ensure the stake is unlocked (if using lockup periods)
|
||||
require(block.timestamp >= stake.unlockTime, "Stake is still locked");
|
||||
if (block.timestamp < stake.unlockTime) revert StakeLocked();
|
||||
|
||||
// Update state before external calls
|
||||
stake.amount = 0;
|
||||
@@ -704,13 +785,13 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
|
||||
*/
|
||||
function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
WithdrawStake[] storage userStakes = withdrawStake[msg.sender];
|
||||
require(userStakes.length > 0, "No stakes available for withdrawal");
|
||||
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) {
|
||||
require(block.timestamp >= stake.unlockTime, "Withdraw Stake is still locked");
|
||||
if (block.timestamp < stake.unlockTime) revert StakeLocked();
|
||||
|
||||
uint256 _amount = stake.amount;
|
||||
|
||||
@@ -720,7 +801,7 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
}
|
||||
|
||||
uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this));
|
||||
require(poolBalance >= _amount, "Insufficient rewards in the pool");
|
||||
if (poolBalance < _amount) revert InsufficientRewards();
|
||||
|
||||
// Update state before external calls
|
||||
// withdrawLiabilities is in 1e18, deduct original amount
|
||||
@@ -735,7 +816,41 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
}
|
||||
|
||||
// Revert if no matching stake with non-zero amount was found
|
||||
revert("Invalid stake index or already withdrawn");
|
||||
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 = withdrawVesting[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;
|
||||
|
||||
// Transfer tokens
|
||||
IERC20(_token).safeTransfer(msg.sender, _amount);
|
||||
emit StakeWithdrawn(msg.sender, _amount, _vestingId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Revert if no matching vesting with non-zero amount was found
|
||||
revert StakeNotFound();
|
||||
}
|
||||
|
||||
|
||||
@@ -751,7 +866,7 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
}
|
||||
}
|
||||
|
||||
require(totalReward > minStakeLock, "Not enough to compound");
|
||||
if (totalReward <= minStakeLock) revert NotEnoughToCompound();
|
||||
|
||||
// Check if user has a fixed reward rate set
|
||||
uint256 finalRewardRate;
|
||||
@@ -776,15 +891,15 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
}
|
||||
|
||||
function createVesting(address _token, uint256 _amount) external {
|
||||
require(_amount != 0, "Amount must be greater than zero");
|
||||
if (_amount == 0) revert InvalidAmount();
|
||||
address oracle = priceOracles[_token];
|
||||
require(oracle != address(0), "Price oracle not set for this token");
|
||||
if (oracle == address(0)) revert PriceOracleNotSet();
|
||||
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
|
||||
|
||||
uint256 bonus = (_amount * BONUS_PERCENTAGE) / 100;
|
||||
|
||||
uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18;
|
||||
require(usdPrice > minStakeLock, "Amount must be greater minStakeLock");
|
||||
if (usdPrice <= minStakeLock) revert AmountBelowMinimum();
|
||||
|
||||
// Update user's dollarsVested
|
||||
dollarsVested[msg.sender] += usdPrice;
|
||||
@@ -871,12 +986,12 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
|
||||
function claimVesting(uint256 _vestingIndex) external nonReentrant {
|
||||
Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
||||
require(vesting.complete == false, "Stake is Complete");
|
||||
if (vesting.complete) revert StakeComplete();
|
||||
uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex);
|
||||
|
||||
require(maxClaim >= vesting.claimedAmount, "Invalid claim amount");
|
||||
if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount();
|
||||
uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
||||
require(amountToClaim != 0, "No vested amount to claim");
|
||||
if (amountToClaim == 0) revert NothingToClaim();
|
||||
|
||||
vesting.claimedAmount = vesting.claimedAmount + amountToClaim;
|
||||
if (vesting.claimedAmount >= vesting.amount) {
|
||||
@@ -892,7 +1007,14 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
}
|
||||
}
|
||||
vestedTotal[vesting.token] -= amountToClaim;
|
||||
IERC20(vesting.token).safeTransfer(msg.sender, amountToClaim);
|
||||
|
||||
// Add vesting claims to cooldown queue
|
||||
withdrawVesting[msg.sender].push(WithdrawVesting({
|
||||
vestingId: withdrawVestingCounter++,
|
||||
amount: amountToClaim,
|
||||
unlockTime: block.timestamp + unlockDelay,
|
||||
token: vesting.token
|
||||
}));
|
||||
|
||||
emit VestingClaimed(msg.sender, amountToClaim, 0);
|
||||
}
|
||||
@@ -906,7 +1028,7 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
|
||||
if (vesting.token == _token && !vesting.complete) {
|
||||
uint256 maxClaim = getUnlockedVesting(msg.sender, i);
|
||||
require(maxClaim >= vesting.claimedAmount, "Invalid claim amount");
|
||||
if (maxClaim < vesting.claimedAmount) revert InvalidClaimAmount();
|
||||
|
||||
uint256 amountToClaim = maxClaim - vesting.claimedAmount;
|
||||
if (amountToClaim > 0) {
|
||||
@@ -924,7 +1046,7 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
}
|
||||
}
|
||||
|
||||
require(totalReward != 0, "No rewards to claim");
|
||||
if (totalReward == 0) revert NothingToClaim();
|
||||
|
||||
// Update user's dollarsVested
|
||||
if (dollarsVested[msg.sender] > 0) {
|
||||
@@ -936,13 +1058,16 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the contract has enough balance to fulfill the claim
|
||||
uint256 poolBalance = IERC20(_token).balanceOf(address(this));
|
||||
require(poolBalance >= totalReward, "Insufficient rewards in the pool");
|
||||
// Update vesting total
|
||||
vestedTotal[_token] -= totalReward;
|
||||
// Transfer the aggregated reward
|
||||
IERC20(_token).safeTransfer(msg.sender, totalReward);
|
||||
|
||||
// Add vesting claims to cooldown queue
|
||||
withdrawVesting[msg.sender].push(WithdrawVesting({
|
||||
vestingId: withdrawVestingCounter++,
|
||||
amount: totalReward,
|
||||
unlockTime: block.timestamp + unlockDelay,
|
||||
token: _token
|
||||
}));
|
||||
|
||||
emit RewardClaimed(msg.sender, totalReward);
|
||||
}
|
||||
@@ -952,9 +1077,9 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
||||
uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex);
|
||||
|
||||
require(maxBonus >= vesting.claimedBonus, "Invalid claim amount");
|
||||
if (maxBonus < vesting.claimedBonus) revert InvalidClaimAmount();
|
||||
uint256 bonusToClaim = maxBonus - vesting.claimedBonus;
|
||||
require(bonusToClaim != 0, "No vested amount to claim");
|
||||
if (bonusToClaim == 0) revert NothingToClaim();
|
||||
|
||||
vesting.claimedBonus = vesting.claimedBonus + bonusToClaim;
|
||||
withdrawLiabilities += bonusToClaim;
|
||||
@@ -1084,7 +1209,7 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
return userStakes[i];
|
||||
}
|
||||
}
|
||||
revert("WithdrawStake with the specified stakeId not found for this user.");
|
||||
revert StakeNotFound();
|
||||
}
|
||||
|
||||
/// @notice Function that lets you look up an address’s stake by vestingId.
|
||||
@@ -1098,7 +1223,7 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
return userStakes[i];
|
||||
}
|
||||
}
|
||||
revert("WithdrawStake with the specified stakeId not found for this user.");
|
||||
revert StakeNotFound();
|
||||
}
|
||||
|
||||
/// @notice Function that returns an array of all the user's withdrawStakes.
|
||||
@@ -1108,17 +1233,30 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
return withdrawStake[user];
|
||||
}
|
||||
|
||||
/// @notice Function that returns an array of all the user's withdrawVestings.
|
||||
/// @param user The address to evaluate.
|
||||
/// @return An array of WithdrawVesting for the given user.
|
||||
function getAllWithdrawVestings(address user) external view returns (WithdrawVesting[] memory) {
|
||||
return withdrawVesting[user];
|
||||
}
|
||||
|
||||
/// @notice Returns the current withdraw vesting counter value
|
||||
/// @return Current counter value for tracking unique withdrawal IDs
|
||||
function getWithdrawVestingCounter() external view returns (uint256) {
|
||||
return withdrawVestingCounter;
|
||||
}
|
||||
|
||||
/// @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.
|
||||
/// @param price The price of the stake.
|
||||
function sellStake(uint256 _stakeId, uint256 price) external {
|
||||
Stake storage stake = stakes[msg.sender][_stakeId];
|
||||
require(!stake.complete, "Stake already complete");
|
||||
require(stake.amount != 0, "Stake amount is 0");
|
||||
if (stake.complete) revert StakeComplete();
|
||||
if (stake.amount == 0) revert InvalidAmount();
|
||||
// Ensure the stake isn't already on sale.
|
||||
require(sellStakes[msg.sender][_stakeId].amount == 0, "Stake already on sale");
|
||||
require(price >= (stake.amount * sellMin) / 100, "Price is too low");
|
||||
if (sellStakes[msg.sender][_stakeId].amount != 0) revert StakeAlreadyOnSale();
|
||||
if (price < (stake.amount * sellMin) / 100) revert PriceTooLow();
|
||||
|
||||
// Create a SellStake entry directly in the mapping.
|
||||
sellStakes[msg.sender][_stakeId] = SellStake({
|
||||
@@ -1145,11 +1283,11 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
/// @param _stakeId The stake ID to cancel the sale.
|
||||
function cancelSellStake(uint256 _stakeId) external {
|
||||
SellStake storage sellStakeEntry = sellStakes[msg.sender][_stakeId];
|
||||
require(sellStakeEntry.amount != 0, "Sell stake not found");
|
||||
if (sellStakeEntry.amount == 0) revert StakeNotFound();
|
||||
|
||||
// Access the original stake.
|
||||
Stake storage stake = stakes[msg.sender][_stakeId];
|
||||
require(stake.amount == 0, "Stake not in sell state");
|
||||
if (stake.amount != 0) revert StakeNotInSellState();
|
||||
|
||||
// Restore the original stake's amount.
|
||||
stake.amount = sellStakeEntry.amount;
|
||||
@@ -1175,8 +1313,8 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
/// @param newPrice The new price of the stake.
|
||||
function updateSellStake(uint256 _stakeId, uint256 newPrice) external {
|
||||
SellStake storage sellStakeEntry = sellStakes[msg.sender][_stakeId];
|
||||
require(sellStakeEntry.amount != 0, "Sell stake not found");
|
||||
require(newPrice >= (sellStakeEntry.amount * sellMin) / 100, "New price is too low");
|
||||
if (sellStakeEntry.amount == 0) revert StakeNotFound();
|
||||
if (newPrice < (sellStakeEntry.amount * sellMin) / 100) revert PriceTooLow();
|
||||
|
||||
sellStakeEntry.bonusAmount = (newPrice * sellKickBack) / 100;
|
||||
sellStakeEntry.price = newPrice;
|
||||
@@ -1194,7 +1332,7 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
|
||||
/// @param _stakeId The original stake id associated with the sell stake.
|
||||
function buySellStake(address seller, uint256 _stakeId) external nonReentrant {
|
||||
SellStake storage sellStakeEntry = sellStakes[seller][_stakeId];
|
||||
require(sellStakeEntry.amount != 0, "Sell stake not available");
|
||||
if (sellStakeEntry.amount == 0) revert StakeNotFound();
|
||||
|
||||
// Transfer the sale price from the buyer to this contract.
|
||||
IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), sellStakeEntry.price);
|
||||
|
||||
Reference in New Issue
Block a user