Contract Name:
UserStakeDetails
Contract Source Code:
File 1 of 1 : UserStakeDetails
/**
*Submitted for verification at BscScan.com on 2025-01-17
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IPacaFinance {
struct Stake {
uint256 amount;
uint256 lastClaimed;
uint256 dailyRewardRate;
uint256 unlockTime;
bool complete;
}
function stakes(address user, uint256 index) external view returns (Stake memory);
}
contract UserStakeDetails {
IPacaFinance public pacaFinanceContract;
constructor(address _pacaFinanceAddress) {
pacaFinanceContract = IPacaFinance(_pacaFinanceAddress);
}
/**
* @dev Returns all stakes of a user as sorted by a chosen field.
* @param user The address of the user to check.
* @param sortBy 0 = amount, 1 = remaining days.
* @return stakeIds Sorted array of stake IDs.
* @return amounts Sorted array of stake amounts.
* @return dailyRewardRates Sorted array of daily reward rates.
* @return remainingDays Sorted array of remaining unlock times in days.
* @return completions Sorted array of stake completion statuses.
*/
function getSortedStakeDetails(address user, uint8 sortBy)
external
view
returns (
uint256[] memory stakeIds,
uint256[] memory amounts,
uint256[] memory dailyRewardRates,
uint256[] memory remainingDays,
bool[] memory completions
)
{
// Get all stakes first
(
uint256[] memory tempStakeIds,
uint256[] memory tempAmounts,
uint256[] memory tempDailyRates,
uint256[] memory tempRemainingDays,
bool[] memory tempCompletions
) = getAllStakeDetails(user);
uint256 stakeCount = tempStakeIds.length;
// Perform bubble sort based on the chosen criterion in descending order
for (uint256 i = 0; i < stakeCount; i++) {
for (uint256 j = 0; j < stakeCount - 1; j++) {
bool shouldSwap = false;
if (sortBy == 0 && tempAmounts[j] < tempAmounts[j + 1]) {
// Sort by amount (descending)
shouldSwap = true;
} else if (sortBy == 1 && tempRemainingDays[j] < tempRemainingDays[j + 1]) {
// Sort by remaining days (descending)
shouldSwap = true;
}
if (shouldSwap) {
// Swap all relevant fields
(tempStakeIds[j], tempStakeIds[j + 1]) = (tempStakeIds[j + 1], tempStakeIds[j]);
(tempAmounts[j], tempAmounts[j + 1]) = (tempAmounts[j + 1], tempAmounts[j]);
(tempDailyRates[j], tempDailyRates[j + 1]) = (tempDailyRates[j + 1], tempDailyRates[j]);
(tempRemainingDays[j], tempRemainingDays[j + 1]) = (tempRemainingDays[j + 1], tempRemainingDays[j]);
(tempCompletions[j], tempCompletions[j + 1]) = (tempCompletions[j + 1], tempCompletions[j]);
}
}
}
// Return sorted arrays
return (tempStakeIds, tempAmounts, tempDailyRates, tempRemainingDays, tempCompletions);
}
/**
* @dev Returns all stakes of a user as a single array split into individual arrays for each field.
* Adds stake IDs, converts unlock time to remaining days.
* Loops dynamically until an invalid (zeroed) stake is found.
* @param user The address of the user to check.
* @return stakeIds An array containing all stake IDs.
* @return amounts An array containing all stake amounts.
* @return dailyRewardRates An array containing all daily reward rates.
* @return remainingDays An array containing all remaining unlock times in days.
* @return completions An array containing all stake completion statuses.
*/
function getAllStakeDetails(address user)
public
view
returns (
uint256[] memory stakeIds,
uint256[] memory amounts,
uint256[] memory dailyRewardRates,
uint256[] memory remainingDays,
bool[] memory completions
)
{
uint256 maxIterations = 750; // Prevent infinite loops
uint256 index = 0;
uint256 currentTime = block.timestamp;
// Temporary storage arrays to collect stake details
uint256[] memory tempStakeIds = new uint256[](maxIterations);
uint256[] memory tempAmounts = new uint256[](maxIterations);
uint256[] memory tempDailyRates = new uint256[](maxIterations);
uint256[] memory tempRemainingDays = new uint256[](maxIterations);
bool[] memory tempCompletions = new bool[](maxIterations);
while (index < maxIterations) {
try pacaFinanceContract.stakes(user, index) returns (IPacaFinance.Stake memory stake) {
if (stake.amount == 0 && stake.unlockTime == 0) {
break; // Exit when invalid stake is reached
}
tempStakeIds[index] = index; // Add stake ID
tempAmounts[index] = stake.amount;
tempDailyRates[index] = stake.dailyRewardRate;
if (stake.unlockTime > currentTime) {
tempRemainingDays[index] = (stake.unlockTime - currentTime) / 1 days;
} else {
tempRemainingDays[index] = 0; // Unlock time passed
}
tempCompletions[index] = stake.complete;
} catch {
break; // Exit safely on error
}
index++;
}
// Final arrays sized correctly
stakeIds = new uint256[](index);
amounts = new uint256[](index);
dailyRewardRates = new uint256[](index);
remainingDays = new uint256[](index);
completions = new bool[](index);
for (uint256 i = 0; i < index; i++) {
stakeIds[i] = tempStakeIds[i];
amounts[i] = tempAmounts[i];
dailyRewardRates[i] = tempDailyRates[i];
remainingDays[i] = tempRemainingDays[i];
completions[i] = tempCompletions[i];
}
return (stakeIds, amounts, dailyRewardRates, remainingDays, completions);
}
}