Buyout SellStakes

This commit is contained in:
2025-10-22 02:45:03 +02:00
parent 8178311084
commit 7ce2927464
3 changed files with 206 additions and 78 deletions

View File

@@ -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
}
}