Farseen0/scar-pairs huggingface dataset:
LOW severity: Lack of `accountHash` check in `isContract` function. **Severity**: Low

**Status**:  Unresolved

**Source**: BalanceFetcher.sol

**Description**: 

The `isContract` function, as currently implemented, checks if an address contains code by examining the size of the code at that address. This method, however, can yield misleading results due to...

Vulnerable code:
/**
 * @dev Returns true if `account` is a contract.
 *
 * [IMPORTANT]
 * ====
 * It is unsafe to assume that an address for which this function returns
 * false is an externally-owned account (EOA) and not a contract.
 *
 * Among others, `isContract` will return false for the following
 * types of addresses:
 *
 *  - an externally-owned account
 *  - a contract in construction
 *  - an address where a contract will be created
 *  - an address where a contract lived, but was destroyed
 * ====
 */
function isContract(address account) internal view returns (bool) {
    // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
    // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
    // for accounts without code, i.e. `keccak256('')`
    bytes32 codehash;
    bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
    // solhint-disable-next-line no-inline-assembly
    assembly {
        codehash := extcodehash(account)
    }
    return (codehash != accountHash && codehash != 0x0);
}
LOW severity: Lack of Minimum Waiting Period for `pendingRewards` Function Calls in `LpNFTPool` Contract. **Severity**: Low

**Status**:  Unresolved

**Source**: LpNFTPool.sol , HyperPool.sol

**Description**:

The `pendingRewards` function in the `LpNFTPool` contract calculates the pending rewards for a staking position based on the current block timestamp and the last reward time. However, it lacks...

Vulnerable code:
// SPDX-License-Identifier: MIT
pragma solidity =0.7.6;

// Import statements...

contract LpNFTPool is ReentrancyGuard, ILpNFTPool, ERC721("Planar Locked Position NFT", "lpNFT"), Blast {
  // Existing variable and function declarations...

  mapping(uint256 => uint256) private lastRewardCalculationTime; // Tracks the last time rewards were calculated for each tokenId
  uint256 private constant SECONDS_PER_HOUR = 3600; // Define the minimum waiting period

  // Existing constructor and function definitions...

  /**
   * @dev Returns pending rewards for a position with a minimum waiting period enforcement
   */
  function pendingRewards(uint256 tokenId) external view returns (uint256) {
    require(_currentBlockTimestamp() > lastRewardCalculationTime[tokenId] + SECONDS_PER_HOUR, "Wait for the minimum period before recalculating");

    StakingPosition storage position = _stakingPositions[tokenId];
    uint256 accRewardsPerShare = _accRewardsPerShare;
    (,,uint256 lastRewardTime, uint256 reserve, uint256 poolEmissionRate) = master.getPoolInfo(address(this));

    // Existing logic to recompute accRewardsPerShare if not up to date...

    return position.amountWithMultiplier.mul(accRewardsPerShare).div(1e18).sub(position.rewardDebt)
      .add(position.pendingXPlaneRewards).add(position.pendingPlaneRewards);
  }

  // Additional or modified functions as necessary...
}
LOW severity: Potential for Zero Allocation in `updateAllocations` Function Without Validation. **Severity**: Low

**Status**:  Unresolved

**Source**: PlaneToken.sol

**Description**:

The `updateAllocations` function allows the owner to update the allocations for farming and legacy holders. However, the function lacks validation to prevent either `farmingAllocation_` or `legacyAllocation_`.....

Vulnerable code:
function updateAllocations(uint256 farmingAllocation_, uint256 legacyAllocation_) external onlyOwner {
    // apply emissions before changes
    emitAllocations();

    // total sum of allocations can't be > 100%
    uint256 totalAllocationsSet = farmingAllocation_.add(legacyAllocation_);
    require(totalAllocationsSet <= 100, "updateAllocations: total allocation is too high");

    // Ensure neither allocation is set to zero unintentionally
    require(farmingAllocation_ > 0 && legacyAllocation_ > 0, "updateAllocations: allocations must be greater than zero");

    // set new allocations
    farmingAllocation = farmingAllocation_;
    legacyAllocation = legacyAllocation_;

    emit UpdateAllocations(farmingAllocation_, legacyAllocation_, treasuryAllocation());
}
HIGH severity: Incorrect Loop Condition.. **Severity**: Critical

**Status**: Resolved

**description**

1. PROPCStakingV2.sol: redeem().

The function contains a critical flaw in its loop construct that results in the function not accounting for the very first staking position (stake ID 0) when calculating the rewards for redemption. As...

Vulnerable code:
for(uint256 stakeId = _stakes.length; stakeId > 0; stakeId--) {
Stake storage_stake = _stakes[stakeId];
}
HIGH severity: Incorrect loop condition.. **Severity**: High

**Status**: Resolved

**Description**

PROPCStakingV2.sol: redeem(), redeemAll().
The function redeem uses the loop to go through the array of all the user's stakes. Since the array is walked from the last to the first stake, the loop sooner or later comes to a point when...

Vulnerable code:
uint256 stakeId=0; stakeId < stakeId.length;stakeId++
LOW severity: Possible loss of rewards due to precision loss. **Severity**: Low

**Status**: Resolved

**Description**

In `MasternodeStakingContract.sol`, the method claim rewards calculate the total dividends as follows:

Here, there is a `wei` loss of rewards funds due to automatic truncation in the solidity division.

Although a small amount, if repeated.....

Vulnerable code:
if (totalRegistrations > 0) {
           // All categories of registered accounts are treated as having identical 'staking' amounts for the purposes of dividing up the rewards.
           totalDividends += (amount / totalRegistrations);            lastBalance += amount;
       }

function test_precisionLoss() public {
       // user 1
       registerALegacyAccount();


       // 31 ether as rewards
       vm.deal(
           address(stakingContract),
           address(stakingContract).balance + 31 ether
       );


       // user 2
       registerANonLegacyAccount();


       // 31 ether as rewards
       vm.deal(
           address(stakingContract),
           address(stakingContract).balance + 31 ether
       );


       // user 3
       address user3 = makeAddr("user3");
       vm.deal(user3, 1_000_000 ether);
       vm.startPrank(user3);
       stakingContract.register{value: 1_000_000 ether}();


       // 31 ether as rewards
       vm.deal(
           address(stakingContract),
           address(stakingContract).balance + 31 ether
       );


       vm.stopPrank();


       uint256 user1BalanceBeforeClaimingRewards = user.balance;
       uint256 user2BalanceBeforeClaimingRewards = legacyAccounts[0].balance;
       uint256 user3BalanceBeforeClaimingRewards = user3.balance;


       vm.prank(user);
       stakingContract.claimRewards();


       vm.prank(legacyAccounts[0]);
       stakingContract.claimRewards();


       vm.prank(user3);
       stakingContract.claimRewards();


       uint256 user1BalanceAfterClaimingRewards = user.balance;
       uint256 user2BalanceAfterClaimingRewards = legacyAccounts[0].balance;
       uint256 user3BalanceAfterClaimingRewards = user3.balance;


       uint totalRewardsClaimedByUsers = user1BalanceAfterClaimingRewards -
           user1BalanceBeforeClaimingRewards +
           user2BalanceAfterClaimingRewards -
           user2BalanceBeforeClaimingRewards +
           user3BalanceAfterClaimingRewards -
           user3BalanceBeforeClaimingRewards;


       assertEq(totalRewardsClaimedByUsers, 93 ether);
   }

├─ emit log(val: "Error: a == b not satisfied [uint]")
    ├─ emit log_named_uint(key: "      Left", val: 92999999999999999999 [9.299e19])
    ├─ emit log_named_uint(key: "     Right", val: 93000000000000000000 [9.3e19])
MEDIUM severity: Missing sanity checks and division by Zero Error. **Severity**: Medium

**Status**: Acknowledged

**Description**

In contract CORGI, there are missing sanity checks for `txFee`, `burnFee` and `FeeAddress`.
The `txFee` and `burnFee` can be arbitrarily set to any value, including value above 100. The same sanity checks are also missing in the...

Vulnerable code:
txFee = _txFee;
        burnFee = _burnFee;
        FeeAddress = _FeeAddress;

Line: 421              uint256 DenverDeflaionaryDecay = tempValue.div(uint256(100 / txFee));
Line: 428              uint256 Burnvalue = tempValue.div(uint256(100 / burnFee));
LOW severity: For loop over Dynamic Array. **Severity**: Low

**Status**: Acknowledged

**Description** 

In ParibusOracleDelegate.sol, there is for loop over dynamic array in `_setCollectionWhitelisted()` function on line: 32 as follows: 

Similarly, there is for loop over dynamic array on line: 62 in `setCollectionPricesWei()`...

Vulnerable code:
for (uint i = 0; i < nfts.length; i++) {
           collectionWhitelist[nfts[i]] = whitelisted;
       }

for (uint i = 0; i < dataLen; i++) {
           TokenPrice storage tokenPrice = collectionPrices[tokenIds[i]];
           tokenPrice.priceWei = pricesWei[i];
           tokenPrice.updatedAt = getBlockTimestamp();
       }

for (uint i = 0; i < dataLen; i++) {
           TokenPrice storage tokenPrice = tokenPrices[nfts[i]][tokenIds[i]];
           tokenPrice.priceWei = pricesWei[i];
           tokenPrice.updatedAt = getBlockTimestamp();
       }
HIGH severity: Withdrawals are stuck Forever if Staking is done at a time sufficiently before endTime. **Severity**: High

**Status**: Resolved

**Description**

In contract `StakingManager.sol`, if a user stakes at a time such that the `stake.timestamp + poolDuration > EndTime`, then the users funds will be stuck forever.
This is because of the following reasons-
 `withdraw()` internally calls the.....

Vulnerable code:
function always returns endTime as the timestamp. This is because of the else if statement on line: 194.
       else if (timeStamp > configurator.getEndTime()) {
           timeStamp = configurator.getEndTime();
       }

require(currentIntervalTimestamp > stake.timestamp + poolDuration, "Withdraw not yet available");

=> require(endTime > stake.timestamp + poolDuration, "Withdraw not yet available")
HIGH severity: Withdrawals are stuck Forever if Staking is done at a time after `endTime`. **Severity**: High

**Status**: Resolved

In contract `StakingManager.sol`, if a user stakes at a time such that the `stake.timestamp > EndTime`, then the users funds will be stuck forever. In other words, if the user stakes or deposits his funds after endTime, then user’s funds will be stuck...

Vulnerable code:
describe("Withdraw", function () {
   const poolId = 0;
   const stakeId = 0;
   const depositAmount = ethers.parseEther(Number(100_000).toString());


   beforeEach(async function () {
     const startTime = await stakingConfigurator.getStartTime();
     await time.increaseTo(Number(startTime) + DAY_IN_SECONDS * 365 * 2 + 10_000);
     const lat = await time.latest();
    
     console.log("Staked at: ", lat);


     await token.connect(user1).approve(stakingManager, depositAmount);
     await stakingManager.connect(user1).deposit(poolId, depositAmount);


     // Simulate passing time when the staking period has ended
     const endTime = await stakingConfigurator.getEndTime();


     await time.increaseTo(Number(endTime) + DAY_IN_SECONDS * 365 * 10); // Forwarding time in order to withdraw after 10 years
     const lat2 = await time.latest();
    
     console.log("Withdrawal at time: ", lat2);
     console.log("End Time: ", endTime);
   });
HIGH severity: Burn method allows anyone to burn anyones’ tokens. **Severity**: Critical

**Status**: Resolved

**Description**

In Contract MPRO.sol and MPROLight.sol, the `burn` method has the following logic:

Here, any malicious user can pass any other users address and all their token balance and burn it all leading to loss of funds for users and the...

Vulnerable code:
function burn(address account, uint256 amount) external virtual {
        _burn(account, amount);
    }
LOW severity: Beneficiary Might Lose Existing Claimable Reward If Registered Again. **Severity** - Low

**Status** - Resolved

**Description**

A beneficiary can be registered through the `registerBeneficiaries()` function in `MPROVesting.sol` , if the beneficiary already had an amount then this code is executed 

This means that if the beneficiary already had an amount and a new.....

Vulnerable code:
if (beneficiary.amount > 0) {
                if (beneficiary.claimed > _amounts[i]) {
                    beneficiary.amount = beneficiary.claimed;
                } else {
                    beneficiary.amount = _amounts[i];
                }
HIGH severity: Unrestricted call to destroyInstance. **Severity**: Critical

**Status**: Resolved

**Locaton**: Admin.sol

**Description**

The `destroyInstance()` function within the smart contract poses a significant security risk due to its unrestricted accessibility. Any wallet or address can call this function, allowing any caller to delete the.....

Vulnerable code:
function destroyInstance(
        address _instance
    ) external onlyExist(_instance) onlyIncoming(_instance) {
        _removeFromSales(_instance);
        ITokenSale(_instance).destroy();
    }
HIGH severity: Reentrance can lead to loss of funds. **Severity**: Critical

**Status**: Resolved

**Description**

In Contract Vesting.sol, the method `claim()` allows users to claim the deposited tokens once the vesting time is over.

Since the deposited asset can be ETH/Native token as well, it will be sent to the user as per the following...

Vulnerable code:
if (pctAmount != 0) {
           if (address(token) == address(1)) {
               (bool sent, ) = payable(sender).call{value: pctAmount}(""); 
               require(sent, "Failed to send BNB to receiver");
           } else {
               token.safeTransfer(sender, pctAmount);
           }
           s.index = uint128(i);
           s.amountClaimed += pctAmount;
       }
HIGH severity: Incorrect Return Of `userMaxAllc`. **Severity** - High

**Status** - Resolved

**Description**

In the contract TokenSale.sol the function `calculateMaxAllocation` calculate the max allocation for the user (L259) . The function incorrectly assign `userMaxAlloc` as the max allocation then `userMaxAlloc > maxAllocation` , in this...

Vulnerable code:
if (userMaxAllc > maxAllocation) {
            return maxAllocation;
HIGH severity: Incorrect decimals precision. **Severity**: High

**Status**: Resolved

**Description**

In Contract TokenSale.sol, the method `_processPrivate(...)` calculates the amount as below:

Here, `amount = 1e6 * 1e18 =  1e24`, if `_amount` is in USDC decimals 6.
Further same amount is transferred from user’s wallet here:

Since USDC...

Vulnerable code:
Staked storage s = stakes[_sender];
       uint256 amount = _amount * PCT_BASE; 
       uint256 sum = s.amount + amount;

usdc.safeTransferFrom(_sender, address(this), amount);

if (userTaxAmount > 0) {
           s.taxAmount += userTaxAmount;
           usdc.safeTransferFrom(_sender, marketingWallet, userTaxAmount);        }
HIGH severity: Method `takeUSDCRaised()` transfer wrong funds. **Severity**: High

**Status**: Resolved

In Contract TokenSale.sol, the method `takeUSDCRaised()` calculates earned USDC as follows:

Here, `state.totalPrivateSold` is in 1e24 and `state.totalSupplyInValue` is in 1e18 so most likely `earned` will be `state.totalSupplyInValue` which will not be...

Vulnerable code:
uint256 earned;


       if (state.totalPrivateSold > state.totalSupplyInValue) {
           earned = uint256(state.totalSupplyInValue);
       } else {
           earned = uint256(state.totalPrivateSold);
       }

if (earned > 0) { 
           uint256 bal = usdc.balanceOf(address(this));
           uint256 returnValue = earned <= bal ? earned : bal;
           usdc.safeTransfer(admin.wallet(), returnValue);
       }
HIGH severity: Method `_claim(...)` calculates wrong shares and left values. **Severity**: High

**Status**: Resolved

**Description**

In Contract TokenSale.sol, the method _claim has the following logic:

Here, `state.totalPrivateSold` is in 1e24, and `state.totalSupplyInValue` is in 1e18 which will make the `if` condition mostly true leading to rate, share, and left...

Vulnerable code:
uint256 left;
       if (state.totalPrivateSold > (state.totalSupplyInValue)) {            uint256 rate = (state.totalSupplyInValue * PCT_BASE) /
               state.totalPrivateSold;
           _s.share = uint120((uint256(_s.amount) * rate) / PCT_BASE); 
           left = uint256(_s.amount) - uint256(_s.share);
       } else {
           _s.share = uint120(_s.amount);        }


       return (_s.share, left);
HIGH severity: Unrestricted call to `setConfig`. **Severity**: Critical

**Status**: Resolved

**Location:** TokenSaleUSDB.sol, TokenSaleETH.sol

**description**

The `setConfig()` function within the smart contracts poses a significant security risk due to
its unrestricted accessibility. Any wallet or address can call this function, allowing...

Vulnerable code:
function setConfig(Config memory _config, address _creator) external {
require(creator == _creator,"Only Creator can Call");
config = _config;
}
HIGH severity: Lack of ERToken Transfer Validation. **Severity**: Medium

**Status**: Resolved

**Location:** Admin.sol, TokenSaleUSDB.sol

**description**

Function `createPoolNew()` initiates ERC20 token transfers without validating the return
value of the transfer operation. This oversight can result in unhandled transfer failures,
compromising...

Vulnerable code:
310 IERC20D(_params.tokenAddress).transferFrom(msg.sender, instance,
(_params.totalSupply + _params.tokenLiquidity));

236 if(params.tokenLiquidity - tokenAmount > 0)
IERC20D(params.tokenAddress).transfer(creator, params.tokenLiquidity -
tokenAmount);
...
246 if (liquidity > 0) IERC20D(pair).transfer(creator,liquidity);
LOW severity: Unsafe cast. **Severity**: Low

**Status**: Partially resolved

**Description**

In Contract TokenSale.sol, the method initialize calculated the totalSupplyInValue as follows: 

Here, `uint256` value is cast to `uint128` unsafely.

In `_claim(..)` method `s.share` is calculated as following:

Here also...

Vulnerable code:
state.totalSupplyInValue = uint128(            (uint256(_params.totalSupply) *
               uint256(_params.privateTokenPrice)) / 10 ** 18            // removes USDB hardcode of six, awful
       );

_s.share = uint120((uint256(_s.amount) * rate) / PCT_BASE);
LOW severity: Flawed logic in `_processPrivate()` method. **Severity**: Low

**Status**: Resolved

**Description**

In Contract TokenSale.sol, the method `_processPrivate()` has the following logic:

Here, `sum = s.amount + _amount`, since `_amount > 0 => sum > 0`.
So the condition `sum > taxFreeAllOfUser` wil always be true as `taxFreeAllOfUser` is...

Vulnerable code:
if (sum > taxFreeAllcOfUser) { //@audit always true
           uint256 userTxRate = userTaxRate(sum, _sender);
           if (s.amount < taxFreeAllcOfUser) { //@audit true only once
               userTaxAmount = //@audit unreachable code after once
                   ((sum - taxFreeAllcOfUser) * userTxRate) /
                   POINT_BASE;
           } else {
               userTaxAmount = (amount * userTxRate) / POINT_BASE;           }
       }
LOW severity: Modifiers duplicated. **Severity**: Low

**Status**: Resolved

**Location**: Admin.sol

**Description**

Functions `addOperator()` and `removeOperator()` carry out redundant checks. Modifier `onlyAdmin` checks whether the caller is wallet or not (i.e. owner of contract as referred to in initialize ). Function...

Vulnerable code:
function addOperator(address _address) external virtual onlyAdmin {
        grantRole(OPERATOR, _address);
    }

    /**
     * @dev Only Admin can remove an Operator
     */

    function removeOperator(address _address) external virtual onlyAdmin {
        revokeRole(OPERATOR, _address);
    }
LOW severity: Reentrance Attack Exploit in `claim()` Function. **Severity**: Low

**Status**: Resolved

**Location:** TokenSaleETH.sol, TokenSaleUSDB.sol

**description**

The `claim()` function is susceptible to a reentrancy attack due to its design allowing
external calls (i.e. line 240) to be made to other contracts (i.e. `msg.sender`) before...

Vulnerable code:
225 function claim() external {
226 require(isRaiseClaimed, "takeUSDBRaised not called");
227 require(
228 uint8(epoch) > 1 && !admin.blockClaim(address(this)),
229 "Not time or not allowed"
230 );
231
232 Staked storage s = stakes[msg.sender];
233 require(s.amount != 0, "No Deposit");
234 if(s.share == 0) (s.share, s.left) = _claim(s);
235 require(s.left != 0, "Nothing to Claim");

237 if(s.left > 0){
238 uint bal = address(this).balance;
239 uint left = s.left < bal ? s.left : bal;
240 ETHTransfer(msg.sender, left);
241 s.left -= s.left;
242 emit Claim(msg.sender, left);
}
}
LOW severity: Non-upgradeable contracts inherited. **Severity**: Low

**Status**: Resolved

**Location:** Admin.sol, TokenSaleETH.sol, TokenSaleUSDB.sol

**description**

Across the protocol, several contracts that are upgradeable are inheriting non upgradeable
Base Contracts:

OpenZeppelin has provided an upgradeable version of the same contracts.....

Vulnerable code:
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
MEDIUM severity: Vulnerability in updatePair Function Allows Creation of Duplicate pairName Entries. **Severity**: Medium

**Status**: Resolved

**Location**: PairInfos.sol

**Description**

In PairInfos.sol, the `updatePair` function is susceptible to a critical vulnerability that allows for the creation of duplicate `pairName` entries for pairs. This vulnerability arises from the scenario where.....

Vulnerable code:
require(!isPairListed[_pair.pairName], "PAIR_ALREADY_LISTED");
MEDIUM severity: Redundant Calculation of `positionChange` in updateMargin Function. **Severity**: Medium

**Status**: Acknowledged

**Location**: Trading.sol

**Description**:

The `updateMargin` function within Trading contract intended for trading operations contains a logical inconsistency that results in the `positionChange` variable always evaluating to zero. This issue...

Vulnerable code:
uint256 position = ot.base.margin * ot.base.leverage;
...
uint256 leverage = position / newMargin;
...
uint positionChange = position / LEV_DENOMINATOR - (newMargin * leverage) / LEV_DENOMINATOR;
MEDIUM severity: Potential Denial of Service (DoS) via Unchecked External Calls in `FeeHelper` Contract. **Severity**: Medium

**Status**: Resolved

**Location**: FeeHelper.sol

**Description**:

The `dealReferralAward` function in the `FeeHelper` contract makes external calls to the referral contract without validating the return values (rebase and discount). This oversight can lead to a situation...

Vulnerable code:
function dealReferralAward(uint256 totalFee, address trader, uint256 position) private returns (uint256 left) {
    if (address(referral) == address(0)) return totalFee;
    (uint256 rebase, uint256 discount) = referral.distributeRefReward(trader, totalFee, position);
    
    // Validate the sum of rebase and discount does not exceed totalFee
    if (rebase + discount > totalFee) {
        // Implement alternative logic here
        // For example, log the incident and continue without transferring funds
        emit ReferralRewardExceedsTotalFee(trader, rebase, discount, totalFee);
        return totalFee;
    }

    if (discount != 0) {
        SafeERC20.safeTransfer(standardToken, trader, discount);
    }
    if (rebase != 0) {
        SafeERC20.safeTransfer(standardToken, address(referral), rebase);
    }
    left = totalFee - discount - rebase;
}