Buyout SellStakes
This commit is contained in:
@@ -115,6 +115,8 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
MarketplaceHistory[] public marketplaceHistory; // Complete history of all transactions
|
||||
mapping(address => uint256) public totalClaimed; // Track total amount claimed and sent to withdrawStakes per user
|
||||
uint256 public highestRatio; // Track the highest TVL/liability ratio ever achieved (scaled by 10000)
|
||||
mapping(address => mapping(uint256 => uint256)) public contractOwnedSellStakes; // Track contract-owned sellStakes linked to user withdrawStake IDs
|
||||
uint256 public sellStakePremiumPercent; // Premium percentage for contract-owned sellStakes (e.g., 1000 = 10%)
|
||||
|
||||
// Events
|
||||
event VestingClaimed(address indexed user, uint256 amount, uint256 bonus);
|
||||
@@ -163,6 +165,7 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
|
||||
unlockDelay = 60 * 60 * 72;
|
||||
maxUnlockPercentage = 100; // 1% maximum unlock per epoch
|
||||
sellStakePremiumPercent = 1000; // 10% premium for contract-owned sellStakes
|
||||
}
|
||||
|
||||
// Ownership Management
|
||||
@@ -212,40 +215,40 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
priceOracles[_token] = _oracle;
|
||||
}
|
||||
|
||||
/// @notice Set unlock schedule for a token using percentage-based steps
|
||||
/// @param _token The token address to set the schedule for
|
||||
/// @param _lockTime The initial lock time in seconds
|
||||
/// @param _percentagePerStep The percentage to unlock at each step (scaled by 10000)
|
||||
function setUnlockScheduleByPercentage(address _token, uint256 _lockTime, uint256 _percentagePerStep) external onlyOwner {
|
||||
require(_token != address(0), "Invalid token address");
|
||||
require(_percentagePerStep > 0 && _percentagePerStep <= 10000, "Invalid percentage");
|
||||
// /// @notice Set unlock schedule for a token using percentage-based steps
|
||||
// /// @param _token The token address to set the schedule for
|
||||
// /// @param _lockTime The initial lock time in seconds
|
||||
// /// @param _percentagePerStep The percentage to unlock at each step (scaled by 10000)
|
||||
// function setUnlockScheduleByPercentage(address _token, uint256 _lockTime, uint256 _percentagePerStep) external onlyOwner {
|
||||
// require(_token != address(0), "Invalid token address");
|
||||
// require(_percentagePerStep > 0 && _percentagePerStep <= 10000, "Invalid percentage");
|
||||
|
||||
// Clear existing schedule
|
||||
delete unlockSchedules[_token];
|
||||
// // Clear existing schedule
|
||||
// delete unlockSchedules[_token];
|
||||
|
||||
uint256 totalPercentage = 0;
|
||||
uint256 timeOffset = _lockTime;
|
||||
// uint256 totalPercentage = 0;
|
||||
// uint256 timeOffset = _lockTime;
|
||||
|
||||
// Create unlock steps until we reach 100%
|
||||
while (totalPercentage < 10000) {
|
||||
uint256 stepPercentage = _percentagePerStep;
|
||||
// // Create unlock steps until we reach 100%
|
||||
// while (totalPercentage < 10000) {
|
||||
// uint256 stepPercentage = _percentagePerStep;
|
||||
|
||||
// Adjust last step to exactly reach 100%
|
||||
if (totalPercentage + stepPercentage > 10000) {
|
||||
stepPercentage = 10000 - totalPercentage;
|
||||
}
|
||||
// // Adjust last step to exactly reach 100%
|
||||
// if (totalPercentage + stepPercentage > 10000) {
|
||||
// stepPercentage = 10000 - totalPercentage;
|
||||
// }
|
||||
|
||||
unlockSchedules[_token].push(UnlockStep({
|
||||
timeOffset: timeOffset,
|
||||
percentage: stepPercentage
|
||||
}));
|
||||
// unlockSchedules[_token].push(UnlockStep({
|
||||
// timeOffset: timeOffset,
|
||||
// percentage: stepPercentage
|
||||
// }));
|
||||
|
||||
totalPercentage += stepPercentage;
|
||||
timeOffset += _lockTime; // Each step adds the same time interval
|
||||
}
|
||||
// totalPercentage += stepPercentage;
|
||||
// timeOffset += _lockTime; // Each step adds the same time interval
|
||||
// }
|
||||
|
||||
emit UnlockScheduleSet(_token);
|
||||
}
|
||||
// emit UnlockScheduleSet(_token);
|
||||
// }
|
||||
|
||||
// /// @notice Set custom unlock schedule for a token with specific steps
|
||||
// /// @param _token The token address to set the schedule for
|
||||
@@ -297,6 +300,13 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
instantBuyoutPercent = _newPercent;
|
||||
}
|
||||
|
||||
/// @notice Update contract-owned sellStake premium percentage
|
||||
/// @param _newPremium The premium percentage (scaled by 10000), ex: 1000 = 10%
|
||||
function updateSellStakePremiumPercent(uint256 _newPremium) external onlyOwner {
|
||||
require(_newPremium <= 5000, "Premium cannot exceed 50%");
|
||||
sellStakePremiumPercent = _newPremium;
|
||||
}
|
||||
|
||||
// Epoch-based Staking Functions
|
||||
|
||||
/// @notice Internal function to calculate unlock percentage based on ratio improvement vs historical high
|
||||
@@ -440,17 +450,44 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
WithdrawStake storage stake = userStakes[i];
|
||||
if (stake.stakeId == stakeId && stake.amount > 0) {
|
||||
require(block.timestamp >= stake.unlockTime, "Stake locked");
|
||||
|
||||
|
||||
// Check if there's a contract-owned sellStake linked to this withdrawStake
|
||||
uint256 contractSellStakeId = contractOwnedSellStakes[msg.sender][stakeId];
|
||||
if (contractSellStakeId > 0) {
|
||||
SellStake storage contractSellStake = sellStakes[address(this)][contractSellStakeId];
|
||||
if (contractSellStake.value > 0) {
|
||||
uint256 sellValue = contractSellStake.value;
|
||||
|
||||
// Cancel the contract-owned sellStake (no fee)
|
||||
pendingSellStakes[address(this)] -= sellValue;
|
||||
delete sellStakes[address(this)][contractSellStakeId];
|
||||
|
||||
// Remove from keys array using swap-and-pop
|
||||
uint256 keyIndex = sellStakeKeyIndex[address(this)][contractSellStakeId];
|
||||
uint256 lastKeyIndex = sellStakeKeys.length - 1;
|
||||
if (keyIndex != lastKeyIndex) {
|
||||
SellStakeKey memory lastKey = sellStakeKeys[lastKeyIndex];
|
||||
sellStakeKeys[keyIndex] = lastKey;
|
||||
sellStakeKeyIndex[lastKey.seller][lastKey.stakeId] = keyIndex;
|
||||
}
|
||||
sellStakeKeys.pop();
|
||||
delete sellStakeKeyIndex[address(this)][contractSellStakeId];
|
||||
|
||||
emit StakeSaleCancelled(address(this), contractSellStakeId);
|
||||
}
|
||||
delete contractOwnedSellStakes[msg.sender][stakeId];
|
||||
}
|
||||
|
||||
uint256 amount = stake.amount;
|
||||
address token = stake.token;
|
||||
stake.amount = 0; // Mark as withdrawn
|
||||
|
||||
|
||||
// Decrement withdraw liabilities for all tokens
|
||||
withdrawLiabilities[token] -= amount;
|
||||
|
||||
|
||||
// Transfer tokens to user based on the specified token
|
||||
IERC20(token).safeTransfer(msg.sender, amount);
|
||||
|
||||
|
||||
emit StakeWithdrawn(msg.sender, amount, stakeId);
|
||||
found = true;
|
||||
break;
|
||||
@@ -485,16 +522,40 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
|
||||
// Create withdrawable stake with unlock delay (like claimUnlockedFunds)
|
||||
stakeIdCounter++;
|
||||
uint256 withdrawStakeId = stakeIdCounter;
|
||||
withdrawStakes[msg.sender].push(WithdrawStake({
|
||||
stakeId: stakeIdCounter,
|
||||
stakeId: withdrawStakeId,
|
||||
amount: payoutAmount,
|
||||
unlockTime: block.timestamp + unlockDelay,
|
||||
token: BSC_TOKEN
|
||||
}));
|
||||
|
||||
|
||||
// Increment withdraw liabilities for BSC_TOKEN
|
||||
withdrawLiabilities[BSC_TOKEN] += payoutAmount;
|
||||
|
||||
|
||||
// Create contract-owned sellStake at premium price
|
||||
uint256 sellStakePrice = (payoutAmount * (10000 + sellStakePremiumPercent)) / 10000;
|
||||
stakeIdCounter++;
|
||||
uint256 sellStakeId = stakeIdCounter;
|
||||
|
||||
sellStakes[address(this)][sellStakeId] = SellStake({
|
||||
value: amount, // Original amount - what buyer receives in stake
|
||||
salePrice: sellStakePrice, // Premium price buyer pays
|
||||
seller: address(this),
|
||||
listTime: block.timestamp
|
||||
});
|
||||
|
||||
pendingSellStakes[address(this)] += amount;
|
||||
contractOwnedSellStakes[msg.sender][withdrawStakeId] = sellStakeId; // Link withdrawStake ID to sellStake ID
|
||||
|
||||
// Add to iteration keys
|
||||
sellStakeKeys.push(SellStakeKey({
|
||||
seller: address(this),
|
||||
stakeId: sellStakeId
|
||||
}));
|
||||
sellStakeKeyIndex[address(this)][sellStakeId] = sellStakeKeys.length - 1;
|
||||
|
||||
emit StakeUpForSale(address(this), sellStakePrice, sellStakeId);
|
||||
emit FundsClaimed(msg.sender, payoutAmount);
|
||||
}
|
||||
|
||||
@@ -822,10 +883,17 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
userLastClaimedEpoch[msg.sender] = currentEpochId;
|
||||
}
|
||||
|
||||
// Transfer stakes: remove from seller, add to buyer (minus protocol share)
|
||||
userBigStake[seller] -= value;
|
||||
userBigStake[msg.sender] += buyerStake;
|
||||
pendingSellStakes[seller] -= value;
|
||||
// Transfer stakes: handle contract seller differently
|
||||
if (seller == address(this)) {
|
||||
// Contract is seller - only add to buyer, don't deduct from contract
|
||||
userBigStake[msg.sender] += buyerStake;
|
||||
pendingSellStakes[address(this)] -= value;
|
||||
} else {
|
||||
// Normal seller flow - remove from seller, add to buyer (minus protocol share)
|
||||
userBigStake[seller] -= value;
|
||||
userBigStake[msg.sender] += buyerStake;
|
||||
pendingSellStakes[seller] -= value;
|
||||
}
|
||||
|
||||
// Increment buyer's original stake tracking (marketplace purchases count as original stake)
|
||||
userOriginalStake[msg.sender] += buyerStake;
|
||||
@@ -1383,7 +1451,7 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
/// @notice Test function for upgrade verification
|
||||
/// @return Returns a constant value to verify upgrade worked
|
||||
function testUpgradeFunction() external pure returns (uint256) {
|
||||
return 1001; // Different value from bsc_paca to distinguish contracts
|
||||
return 1003; // Different value from bsc_paca to distinguish contracts
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user