diff --git a/contracts/CunaFinanceBsc.sol b/contracts/CunaFinanceBsc.sol index b4a6f1a..b89218d 100644 --- a/contracts/CunaFinanceBsc.sol +++ b/contracts/CunaFinanceBsc.sol @@ -35,12 +35,6 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { uint256 percentage; } - struct WithdrawVesting { - uint256 vestingId; - uint256 amount; - uint256 unlockTime; - address token; - } // Epoch-based staking structures struct Epoch { @@ -55,6 +49,7 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { uint256 stakeId; uint256 amount; uint256 unlockTime; + address token; } struct SellStake { @@ -94,9 +89,8 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { // BSC USDT token address for stake rewards and marketplace payments address private constant BSC_TOKEN = 0x55d398326f99059fF775485246999027B3197955; - mapping(address => WithdrawVesting[]) private withdrawVestingActual; - uint256 private withdrawVestingCounterActual; uint256 private stakeIdCounter; + uint256 private vestingStakeIdCounter; // Track total withdraw vesting liabilities by token address mapping(address => uint256) public withdrawVestingLiabilities; @@ -118,6 +112,7 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { 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); @@ -415,11 +410,15 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { // Reset their last claimed epoch to current userLastClaimedEpoch[msg.sender] = currentEpochId; + // Track total claimed amount + totalClaimed[msg.sender] += unclaimedAmount; + // Create withdrawable stake with unlock delay withdrawStakes[msg.sender].push(WithdrawStake({ - stakeId: block.timestamp, // Using timestamp as unique ID + stakeId: stakeIdCounter, amount: unclaimedAmount, - unlockTime: block.timestamp + unlockDelay + unlockTime: block.timestamp + unlockDelay, + token: BSC_TOKEN })); emit FundsClaimed(msg.sender, unclaimedAmount); @@ -436,10 +435,16 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { require(block.timestamp >= stake.unlockTime, "Stake locked"); uint256 amount = stake.amount; + address token = stake.token; stake.amount = 0; // Mark as withdrawn - // Transfer BSC USDT tokens to user - IERC20(BSC_TOKEN).safeTransfer(msg.sender, amount); + // Decrement withdraw vesting liabilities for non-BSC tokens + if (token != BSC_TOKEN) { + withdrawVestingLiabilities[token] -= amount; + } + + // Transfer tokens to user based on the specified token + IERC20(token).safeTransfer(msg.sender, amount); emit StakeWithdrawn(msg.sender, amount, stakeId); return; @@ -465,12 +470,16 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { userBigStake[msg.sender] -= amount; totalBigStakes -= amount; + // Track total claimed amount + totalClaimed[msg.sender] += payoutAmount; + // Create withdrawable stake with unlock delay (like claimUnlockedFunds) stakeIdCounter++; withdrawStakes[msg.sender].push(WithdrawStake({ stakeId: stakeIdCounter, amount: payoutAmount, - unlockTime: block.timestamp + unlockDelay + unlockTime: block.timestamp + unlockDelay, + token: BSC_TOKEN })); emit FundsClaimed(msg.sender, payoutAmount); @@ -1008,9 +1017,9 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { } vestedTotal[vesting.token] -= amountToClaim; - // Add vesting claims to cooldown queue - withdrawVestingActual[msg.sender].push(WithdrawVesting({ - vestingId: withdrawVestingCounterActual++, + // Add vesting claims to unified withdrawal queue + withdrawStakes[msg.sender].push(WithdrawStake({ + stakeId: vestingStakeIdCounter++, amount: amountToClaim, unlockTime: block.timestamp + unlockDelay, token: vesting.token @@ -1056,9 +1065,9 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { } vestedTotal[_token] -= totalReward; - // Add vesting claims to cooldown queue - withdrawVestingActual[msg.sender].push(WithdrawVesting({ - vestingId: withdrawVestingCounterActual++, + // Add vesting claims to unified withdrawal queue + withdrawStakes[msg.sender].push(WithdrawStake({ + stakeId: vestingStakeIdCounter++, amount: totalReward, unlockTime: block.timestamp + unlockDelay, token: _token @@ -1083,59 +1092,21 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { require(bonusToClaim > 0, "Nothing to claim"); vesting.claimedBonus += bonusToClaim; + + // Track total claimed amount + totalClaimed[msg.sender] += 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 + unlockTime: block.timestamp + unlockDelay, + token: BSC_TOKEN })); emit BonusClaimed(msg.sender, bonusToClaim); } - /// @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 withdrawVestingActual[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 withdrawVestingCounterActual; - } - - /// @notice Withdraws vesting tokens after cooldown period - /// @param _vestingId The vesting ID to withdraw - function withdrawVestingToken(uint256 _vestingId) external nonReentrant { - WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender]; - require(userVestings.length > 0, "No vestings available"); - - for (uint256 i = 0; i < userVestings.length; i++) { - WithdrawVesting storage vestingWithdraw = userVestings[i]; - if (vestingWithdraw.vestingId == _vestingId && vestingWithdraw.amount > 0) { - require(block.timestamp >= vestingWithdraw.unlockTime, "Vesting locked"); - - uint256 amount = vestingWithdraw.amount; - address token = vestingWithdraw.token; - - // Mark as withdrawn - vestingWithdraw.amount = 0; - - // Decrement withdraw vesting liabilities for this token - withdrawVestingLiabilities[token] -= amount; - - // Transfer tokens - IERC20(token).safeTransfer(msg.sender, amount); - emit StakeWithdrawn(msg.sender, amount, _vestingId); - return; - } - } - - revert("Vesting not found"); - } // Marketplace View Functions @@ -1205,6 +1176,47 @@ contract CunaFinanceBsc is Initializable, ReentrancyGuardUpgradeable { function getUserMarketplaceSales(address user) external view returns (uint256) { return marketplace_sales[user]; } + + /// @notice Get user's total claimed amount sent to withdrawStakes + /// @param user The user address + /// @return Total amount claimed and sent to withdrawStakes for the user + function getUserTotalClaimed(address user) external view returns (uint256) { + return totalClaimed[user]; + } + + /// @notice Search marketplace history for stakes where address was seller or buyer + /// @param targetAddress The address to search for as seller or buyer + /// @return Array of MarketplaceHistory structs where address was involved + function searchMarketplaceHistory(address targetAddress) external view returns (MarketplaceHistory[] memory) { + require(targetAddress != address(0), "Invalid address"); + + // Count matches first to size the result array properly + uint256 matchCount = 0; + for (uint256 i = 0; i < marketplaceHistory.length; i++) { + if (marketplaceHistory[i].seller == targetAddress || marketplaceHistory[i].buyer == targetAddress) { + matchCount++; + } + } + + // Return empty array if no matches + if (matchCount == 0) { + return new MarketplaceHistory[](0); + } + + // Create result array with exact size needed + MarketplaceHistory[] memory result = new MarketplaceHistory[](matchCount); + uint256 resultIndex = 0; + + // Populate result array + for (uint256 i = 0; i < marketplaceHistory.length; i++) { + if (marketplaceHistory[i].seller == targetAddress || marketplaceHistory[i].buyer == targetAddress) { + result[resultIndex] = marketplaceHistory[i]; + resultIndex++; + } + } + + return result; + } /// @notice Test function for upgrade verification /// @return Returns a constant value to verify upgrade worked