Multiple claims + usdc tracking in withdrawliabilities
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
|
||||
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
|
||||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||
|
||||
@@ -41,6 +40,7 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
uint256 estDaysRemaining;
|
||||
uint256 currentTreasuryTvl;
|
||||
uint256 totalLiability; // Snapshot of totalBigStakes at epoch end
|
||||
uint256 paybackPercent; // Payback percentage used for this epoch (scaled by 10000)
|
||||
uint256 unlockPercentage; // Calculated unlock percentage (scaled by 10000)
|
||||
uint256 timestamp; // When this epoch ended
|
||||
}
|
||||
@@ -90,8 +90,8 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
uint256 private stakeIdCounter;
|
||||
uint256 private vestingStakeIdCounter;
|
||||
|
||||
// Track total withdraw vesting liabilities by token address
|
||||
mapping(address => uint256) public withdrawVestingLiabilities;
|
||||
// Track total withdraw liabilities by token address (all tokens including BSC_TOKEN)
|
||||
mapping(address => uint256) public withdrawLiabilities;
|
||||
|
||||
// Epoch-based staking variables
|
||||
mapping(uint256 => Epoch) public epochs;
|
||||
@@ -107,13 +107,13 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
uint256 public marketplaceMin; // Minimum value for listings (in USD, e.g., 25 * 1e18 = $25)
|
||||
uint256 public cancellationFee; // Fee percentage for cancelling listings (e.g., 500 = 5%)
|
||||
mapping(address => uint256) public marketplace_sales; // Track total sales per user
|
||||
mapping(address => uint256) public pendingSellStakes; // Track total value of pending sell stakes per user
|
||||
SellStakeKey[] public sellStakeKeys; // Array for iteration over active sell stakes
|
||||
mapping(address => mapping(uint256 => uint256)) private sellStakeKeyIndex; // Track position in keys array
|
||||
MarketplaceHistory[] public marketplaceHistory; // Complete history of all transactions
|
||||
mapping(address => uint256) public totalClaimed; // Track total amount claimed and sent to withdrawStakes per user
|
||||
|
||||
// Events
|
||||
event VestingCreated(address indexed user, uint256 amount, uint256 bonus);
|
||||
event VestingClaimed(address indexed user, uint256 amount, uint256 bonus);
|
||||
event BonusClaimed(address indexed user, uint256 bonus);
|
||||
event UnlockScheduleSet(address indexed token);
|
||||
@@ -343,6 +343,7 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
estDaysRemaining: estDaysRemaining,
|
||||
currentTreasuryTvl: currentTreasuryTvl,
|
||||
totalLiability: totalBigStakes,
|
||||
paybackPercent: _paybackPercent,
|
||||
unlockPercentage: unlockPercentage,
|
||||
timestamp: block.timestamp
|
||||
});
|
||||
@@ -366,11 +367,13 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
return totalUnclaimed;
|
||||
}
|
||||
|
||||
/// @notice Get user's net stake (big stake minus unclaimed funds)
|
||||
/// @notice Get user's net stake (big stake minus unclaimed funds minus pending sell stakes)
|
||||
function getNetStake(address user) public view returns (uint256) {
|
||||
uint256 bigStake = userBigStake[user];
|
||||
uint256 unclaimed = calculateUnclaimedFunds(user);
|
||||
return bigStake - unclaimed;
|
||||
uint256 pending = pendingSellStakes[user];
|
||||
uint256 committed = unclaimed + pending;
|
||||
return bigStake > committed ? bigStake - committed : 0;
|
||||
}
|
||||
|
||||
/// @notice Get comprehensive user stake information
|
||||
@@ -411,6 +414,9 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
token: BSC_TOKEN
|
||||
}));
|
||||
|
||||
// Increment withdraw liabilities for BSC_TOKEN
|
||||
withdrawLiabilities[BSC_TOKEN] += unclaimedAmount;
|
||||
|
||||
emit FundsClaimed(msg.sender, unclaimedAmount);
|
||||
}
|
||||
|
||||
@@ -433,10 +439,8 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
address token = stake.token;
|
||||
stake.amount = 0; // Mark as withdrawn
|
||||
|
||||
// Decrement withdraw vesting liabilities for non-BSC tokens
|
||||
if (token != BSC_TOKEN) {
|
||||
withdrawVestingLiabilities[token] -= amount;
|
||||
}
|
||||
// Decrement withdraw liabilities for all tokens
|
||||
withdrawLiabilities[token] -= amount;
|
||||
|
||||
// Transfer tokens to user based on the specified token
|
||||
IERC20(token).safeTransfer(msg.sender, amount);
|
||||
@@ -482,6 +486,9 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
token: BSC_TOKEN
|
||||
}));
|
||||
|
||||
// Increment withdraw liabilities for BSC_TOKEN
|
||||
withdrawLiabilities[BSC_TOKEN] += payoutAmount;
|
||||
|
||||
emit FundsClaimed(msg.sender, payoutAmount);
|
||||
}
|
||||
|
||||
@@ -622,9 +629,8 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
stakeIdCounter++;
|
||||
uint256 stakeId = stakeIdCounter;
|
||||
|
||||
// Deduct value from user's big stake immediately
|
||||
userBigStake[msg.sender] -= value;
|
||||
totalBigStakes -= value;
|
||||
// Add to pending sell stakes tracking (don't touch actual bigStake until sale/cancel)
|
||||
pendingSellStakes[msg.sender] += value;
|
||||
|
||||
// Create the sellStake entry
|
||||
sellStakes[msg.sender][stakeId] = SellStake({
|
||||
@@ -653,14 +659,16 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
|
||||
uint256 value = sellStakeEntry.value;
|
||||
|
||||
// Calculate cancellation fee
|
||||
// Calculate cancellation fee and apply directly to userBigStake
|
||||
uint256 fee = (value * cancellationFee) / 10000;
|
||||
uint256 valueAfterFee = value - fee;
|
||||
|
||||
// Restore value minus fee to user's big stake
|
||||
userBigStake[msg.sender] += valueAfterFee;
|
||||
totalBigStakes += valueAfterFee;
|
||||
// Note: fee reduces total liability (not added back to totalBigStakes)
|
||||
// Remove from pending and apply fee directly to bigStake
|
||||
pendingSellStakes[msg.sender] -= value;
|
||||
if (fee > 0) {
|
||||
userBigStake[msg.sender] -= fee;
|
||||
totalBigStakes -= fee;
|
||||
}
|
||||
// Note: fee reduces total liability permanently
|
||||
|
||||
// Emit fee event
|
||||
if (fee > 0) {
|
||||
@@ -720,10 +728,12 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
// Transfer payment from buyer to seller (direct transfer)
|
||||
IERC20(BSC_TOKEN).safeTransferFrom(msg.sender, seller, salePrice);
|
||||
|
||||
// Add buyerStake to buyer's big stake (value - protocol share)
|
||||
// Transfer stakes: remove from seller, add to buyer (minus protocol share)
|
||||
userBigStake[seller] -= value;
|
||||
userBigStake[msg.sender] += buyerStake;
|
||||
totalBigStakes += buyerStake;
|
||||
// Note: protocolShare reduces total liability (not added back to totalBigStakes)
|
||||
pendingSellStakes[seller] -= value;
|
||||
// Note: totalBigStakes decreases by protocolShare (value - buyerStake)
|
||||
totalBigStakes -= (value - buyerStake);
|
||||
|
||||
// Track marketplace sales for seller
|
||||
marketplace_sales[seller] += salePrice;
|
||||
@@ -759,27 +769,27 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
/// @notice This function will end and clear a user's vestings.
|
||||
/// @dev Only to be used by bots in emergencies
|
||||
/// @param user The user whose vestings will be ended and 0'd
|
||||
function clearVesting(address user) external onlyBot {
|
||||
for (uint256 i = 0; i < vestings[user].length; ++i) {
|
||||
Vesting storage vesting = vestings[user][i];
|
||||
// function clearVesting(address user) external onlyBot {
|
||||
// for (uint256 i = 0; i < vestings[user].length; ++i) {
|
||||
// Vesting storage vesting = vestings[user][i];
|
||||
|
||||
// Decrement accounting variables before clearing
|
||||
if (!vesting.complete) {
|
||||
if (dollarsVested[user] >= vesting.usdAmount) {
|
||||
dollarsVested[user] -= vesting.usdAmount;
|
||||
}
|
||||
if (vestedTotal[vesting.token] >= vesting.amount) {
|
||||
vestedTotal[vesting.token] -= vesting.amount;
|
||||
}
|
||||
}
|
||||
// // Decrement accounting variables before clearing
|
||||
// if (!vesting.complete) {
|
||||
// if (dollarsVested[user] >= vesting.usdAmount) {
|
||||
// dollarsVested[user] -= vesting.usdAmount;
|
||||
// }
|
||||
// if (vestedTotal[vesting.token] >= vesting.amount) {
|
||||
// vestedTotal[vesting.token] -= vesting.amount;
|
||||
// }
|
||||
// }
|
||||
|
||||
vesting.amount = 0;
|
||||
vesting.bonus = 0;
|
||||
vesting.claimedAmount = 0;
|
||||
vesting.claimedBonus = 0;
|
||||
vesting.complete = true;
|
||||
}
|
||||
}
|
||||
// vesting.amount = 0;
|
||||
// vesting.bonus = 0;
|
||||
// vesting.claimedAmount = 0;
|
||||
// vesting.claimedBonus = 0;
|
||||
// vesting.complete = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// @notice Creates a vesting for a given user
|
||||
/// @dev Only to be used by bots for manual vesting creation
|
||||
@@ -1025,8 +1035,8 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
token: vesting.token
|
||||
}));
|
||||
|
||||
// Increment withdraw vesting liabilities for this token
|
||||
withdrawVestingLiabilities[vesting.token] += amountToClaim;
|
||||
// Increment withdraw liabilities for this token
|
||||
withdrawLiabilities[vesting.token] += amountToClaim;
|
||||
|
||||
emit VestingClaimed(msg.sender, amountToClaim, 0);
|
||||
}
|
||||
@@ -1073,35 +1083,56 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable {
|
||||
token: _token
|
||||
}));
|
||||
|
||||
// Increment withdraw vesting liabilities for this token
|
||||
withdrawVestingLiabilities[_token] += totalReward;
|
||||
// Increment withdraw liabilities for this token
|
||||
withdrawLiabilities[_token] += totalReward;
|
||||
|
||||
emit VestingClaimed(msg.sender, totalReward, 0);
|
||||
}
|
||||
|
||||
/// @notice Claim unlocked bonus tokens from a specific vesting
|
||||
/// @param _vestingIndex The index of the vesting to claim bonus from
|
||||
function claimBonus(uint256 _vestingIndex) external nonReentrant {
|
||||
require(_vestingIndex < vestings[msg.sender].length, "Invalid vesting index");
|
||||
/// @notice Claim unlocked bonus tokens from multiple vestings
|
||||
/// @param _vestingIndices Array of vesting indices to claim bonus from
|
||||
function claimBonus(uint256[] calldata _vestingIndices) external nonReentrant {
|
||||
uint256 totalBonusClaimed = 0;
|
||||
|
||||
Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
||||
uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex);
|
||||
for (uint256 i = 0; i < _vestingIndices.length; i++) {
|
||||
uint256 _vestingIndex = _vestingIndices[i];
|
||||
|
||||
require(maxBonus >= vesting.claimedBonus, "Invalid claim amount");
|
||||
uint256 bonusToClaim = maxBonus - vesting.claimedBonus;
|
||||
require(bonusToClaim > 0, "Nothing to claim");
|
||||
// Skip invalid vesting indices
|
||||
if (_vestingIndex >= vestings[msg.sender].length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vesting.claimedBonus += bonusToClaim;
|
||||
Vesting storage vesting = vestings[msg.sender][_vestingIndex];
|
||||
uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex);
|
||||
|
||||
// Create withdrawable stake with unlock delay (add 1e6 to distinguish from normal stakes)
|
||||
withdrawStakes[msg.sender].push(WithdrawStake({
|
||||
stakeId: _vestingIndex + 1e6,
|
||||
amount: bonusToClaim,
|
||||
unlockTime: block.timestamp + unlockDelay,
|
||||
token: BSC_TOKEN
|
||||
}));
|
||||
// Skip if invalid claim amount or nothing to claim
|
||||
if (maxBonus < vesting.claimedBonus) {
|
||||
continue;
|
||||
}
|
||||
|
||||
emit BonusClaimed(msg.sender, bonusToClaim);
|
||||
uint256 bonusToClaim = maxBonus - vesting.claimedBonus;
|
||||
if (bonusToClaim == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vesting.claimedBonus += bonusToClaim;
|
||||
totalBonusClaimed += bonusToClaim;
|
||||
|
||||
// Create withdrawable stake with unlock delay (add 1e6 to distinguish from normal stakes)
|
||||
withdrawStakes[msg.sender].push(WithdrawStake({
|
||||
stakeId: _vestingIndex + 1e6,
|
||||
amount: bonusToClaim,
|
||||
unlockTime: block.timestamp + unlockDelay,
|
||||
token: BSC_TOKEN
|
||||
}));
|
||||
}
|
||||
|
||||
// Only update liabilities and emit event if something was actually claimed
|
||||
if (totalBonusClaimed > 0) {
|
||||
// Increment withdraw liabilities for BSC_TOKEN
|
||||
withdrawLiabilities[BSC_TOKEN] += totalBonusClaimed;
|
||||
emit BonusClaimed(msg.sender, totalBonusClaimed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user