Farseen0/scar-pairs huggingface dataset:
HIGH severity: HEALTH — Incorrect calculation. Attacker can perform price manipulation by transferring HEALTH token 999 times to reduce HEALTH token in uniswap pair.. Attacker can perform price manipulation by transferring HEALTH token 999 times to reduce HEALTH token in uniswap pair.

```solidity
function _transfer(address from, address to, uint256 value) private {
        require(value <= _balances[from]);
        require(to != address(0));
        
        uin

Vulnerable code:
function _transfer(address from, address to, uint256 value) private {
        require(value <= _balances[from]);
        require(to != address(0));
        
        uint256 contractTokenBalance = balanceOf(address(this));

        bool overMinTokenBalance = contractTokenBalance >= numTokensSellToAddToLiquidity;
if ( 
overMinTokenBalance &&
            !inSwapAndLiquify &&
            to == uniswapV2Pair &&
            swapAndLiquifyEnabled
        ) {
            contractTokenBalance = numTokensSellToAddToLiquidity;
            //add liquidity
swapAndLiquify(contractTokenBalance);
        }
if (block.timestamp >= pairStartTime.add(jgTime) && pairStartTime != 0) {
            if (from != uniswapV2Pair) {
                uint256 burnValue = _balances[uniswapV2Pair].mul(burnFee).div(1000);  **//vulnerable point**
                _balances[uniswapV2Pair] = _balances[uniswapV2Pair].sub(burnValue);  **//vulnerable point**
                _balances[_burnAddress] = _balances[_burnAddress].add(burnValue);  **//vulnerable point**
                if (block.timestamp >= pairStartTime.add(jgTime)) {
                    pairStartTime += jgTime;
                }
                emit Transfer(uniswapV2Pair,_burnAddress, burnValue);
                IPancakePair(uniswapV2Pair).sync();
            }
        }

Vulnerability type: ERC20, Miscalculation
HIGH severity: GPT Token — Fee Mechanism issue. https://twitter.com/Phalcon_xyz/status/1661424685320634368

Vulnerable code:
function transferFrom(address _from, address _to, uint256 _value) {
    require(balanceOf[_from] >= _value, "Insufficient balance");
    require(allowance[_from][msg.sender] >= _value, "Not allowed");
    if (_to == swapLPAddr) {sellBurnToken(_value);}
    balanceOf[_from] -= _value;
    balanceOf[_to] += _value;
    allowance[_from][msg.sender] -= _value;
    emit Transfer(_from, _to, _value);
    return true;
}

Vulnerability type: Incorrect logic, skim
HIGH severity: NeutraFinance — The root cause of the attack lay in the spot price utilized within the conversion function. This stemmed from the existence of two pools sharing the same LP token name (CMLT-LP), allowing conversion between them—specifically, from one pool (CMLT-LP-65eb) to another (CMLT-LP-2ea3) via the conversion function.. https://twitter.com/phalcon_xyz/status/1686654241111429120?s=46&t=Oc_WAGUoXqc9c0LidD-zww

Vulnerable code:
function convert(uint256 _amount) external whenNotPaused {
    inputToken.transferFrom(msg.sender, address(this), _amount);
    uint256 amountOut = getAmountOut(_amount);
    require(outputToken.balanceOf(address(this)) >= amountOut, "not enough output token");
    outputToken.transfer(msg.sender, amountOut);
    emit Converted(msg.sender, _amount, amountOut);
}

function getAmountOut(uint256 _amount) view public returns (uint256) {
    (uint256 reserves0, uint256 reserves1,) = inputToken.getReserves();
    uint256 inputTotalSupply = inputToken.totalSupply();

    uint256 pairTokenAmount;
    if (pairTokenAmount == inputToken.token0()) {
        pairTokenAmount = reserves0 * _amount / inputTotalSupply;
    } else {
        pairTokenAmount = reserves1 * _amount / inputTotalSupply;
    }

    (uint256 reserves2, uint256 reserves3,) = outputToken.getReserves();
    uint256 outputTotalSupply = outputToken.totalSupply();

    if (pairTokenAmount == outputToken.token0()) {
        return outputTotalSupply * pairTokenAmount / reserves2;
    } else {
        return outputTotalSupply * pairTokenAmount / reserves3;
    }
}

Vulnerability type: Price Manipulation
HIGH severity: Gamma — The primary issue stemmed from the deposit proxy settings related to the price change threshold, which were set excessively high. This oversight allowed for significant price fluctuations of -50% to +100% in certain LST and stablecoin vaults. The attacker exploited this flaw by targeting these specific vaults.. https://medium.com/neptune-mutual/how-was-gamma-protocol-exploited-6b63e6c127ba

Vulnerable code:
function deposit(uint256 deposit0, uint256 deposit1, address to, address from, uint256[4] memory inMin) external nonReentrant returns (uint256 shares) {
  require(deposit0 > 0 || deposit1 > 0);
  require(deposit0 <= deposit0Max && deposit1 <= deposit1Max);
  require(to != address(0) && to != address(this), "to");
  require(msg.sender == whitelistedAddress, "WHE");

  /// update fees
  zeroBurn();

  (uint160 sqrtPrice, , , , , , , ) = pool.globalState();
  uint256 price = FullMath.mulDiv(uint256(sqrtPrice).mul(uint256(sqrtPrice)), PRECISION, 2 ** (96 * 2));

  (uint256 pool0, uint256 pool1) = getTotalAmounts();

  shares = deposit1.add(deposit0.mul(price).div(PRECISION));

  if (deposit0 > 0) {
    token0.safeTransferFrom(from, address(this), deposit0);
  }
  if (deposit1 > 0) {
    token1.safeTransferFrom(from, address(this), deposit1);
  }

  uint256 total = totalSupply();
  if (total != 0) {
    uint256 pool0PricedInToken1 = pool0.mul(price).div(PRECISION);
    shares = shares.mul(total).div(pool0PricedInToken1.add(pool1));
    if (directDeposit) {
      uint128 liquidity = _liquidityForAmounts(baseLower, baseUpper, token0.balanceOf(address(this)), token1.balanceOf(address(this)));
      _mintLiquidity(baseLower, baseUpper, liquidity, address(this), inMin[0], inMin[1]);
      liquidity = _liquidityForAmounts(limitLower, limitUpper, token0.balanceOf(address(this)), token1.balanceOf(address(this)));
      _mintLiquidity(limitLower, limitUpper, liquidity, address(this), inMin[2], inMin[3]);
    }
  }
  _mint(to, shares);
  emit Deposit(from, to, shares, deposit0, deposit1);
  /// Check total supply cap not exceeded. A value of 0 means no limit.
  require(maxTotalSupply == 0 || total <= maxTotalSupply, "max");
}

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: RoeFinance — The root cause is the limited liquidity of the pool, which resulted in the manipulation of the price oracle.. https://twitter.com/BlockSecTeam/status/1612701106982862849 https://quillaudits.medium.com/decoding-roe-finances-flash-loan-exploit-quillaudits-df8494e2090f#:~:text=On%20the%2011th%20of%20January,the%20loss%20of%20%2480K https://blog.solidityscan.com/roe-finance-hack-analysis-price-manipulation-6993

Vulnerable code:
function borrow(
    address asset,
    uint256 amount,
    uint256 interestRateMode,
    uint16 referralCode,
    address onBehalfOf
) external override whenNotPaused {
    DataTypes.ReserveData storage reserve = _reserves[asset];

    _executeBorrow(
      ExecuteBorrowParams(
        asset,
        msg.sender,
        onBehalfOf,
        amount,
        interestRateMode,
        reserve.aTokenAddress,
        referralCode,
        true
      )
    );
}

function _executeBorrow(ExecuteBorrowParams memory vars) internal {
    DataTypes.ReserveData storage reserve = _reserves[vars.asset];
    DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf];

    address oracle = _addressesProvider.getPriceOracle();

    uint256 amountInETH =
      IPriceOracleGetter(oracle).getAssetPrice(vars.asset).mul(vars.amount).div(
        10**reserve.configuration.getDecimals()
      );

    ValidationLogic.validateBorrow(
      vars.asset,
      reserve,
      vars.onBehalfOf,
      vars.amount,
      amountInETH,
      vars.interestRateMode,
      _maxStableRateBorrowSizePercent,
      _reserves,
      userConfig,
      _reservesList,
      _reservesCount,
      oracle
    );

    reserve.updateState();

    uint256 currentStableRate = 0;

    bool isFirstBorrowing = false;
    if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) {
      currentStableRate = reserve.currentStableBorrowRate;

      isFirstBorrowing = IStableDebtToken(reserve.stableDebtTokenAddress).mint(
        vars.user,
        vars.onBehalfOf,
        vars.amount,
        currentStableRate
      );
    } else {
      isFirstBorrowing = IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
        vars.user,
        vars.onBehalfOf,
        vars.amount,
        reserve.variableBorrowIndex
      );
    }

    if (isFirstBorrowing) {
      userConfig.setBorrowing(reserve.id, true);
    }

    reserve.updateInterestRates(
      vars.asset,
      vars.aTokenAddress,
      0,
      vars.releaseUnderlying ? vars.amount : 0
    );

    if (vars.releaseUnderlying) {
      IAToken(vars.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount);
    }

    emit Borrow(
      vars.asset,
      vars.user,
      vars.onBehalfOf,
      vars.amount,
      vars.interestRateMode,
      DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE
        ? currentStableRate
        : reserve.currentVariableBorrowRate,
      vars.referralCode
    );
}

Vulnerability type: Oracle, lending
HIGH severity: Dexible — Arbitrary External Call allowing an attacker to steal a user's approved funds.. https://twitter.com/peckshield/status/1626493024879673344 https://twitter.com/MevRefund/status/1626450002254958592

Vulnerable code:
function fill(SwapTypes.SwapRequest calldata request, SwapMeta memory meta) external onlySelf returns (SwapMeta memory) {
    preCheck(request, meta);
    meta.outAmount = request.tokenOut.token.balanceOf(address(this));

    for (uint i = 0; i < request.routes.length; ++i) {
        SwapTypes.RouterRequest calldata rr = request.routes[i];
        IERC20(rr.routeAmount.token).safeApprove(rr.spender, rr.routeAmount.amount);
        (bool s, ) = rr.router.call(routerData); //Vulnerable Point: The attacker can make an arbitrary external call from the contract.

        if (!s) {
            revert("Failed to swap");
        }
    }
}

Vulnerability type: Arbitrary call, Dex/AMM
HIGH severity: MIMSpell — The attack exploited an accuracy issue in calculating loan variables, allowing manipulation of key variables elastic and base. This imbalance led to errors in collateral and loan amount calculations, resulting in excessive lending of MIM tokens.. https://twitter.com/kankodu/status/1752581744803680680

Vulnerable code:
function _borrow(address to, uint256 amount) internal returns (uint256 part, uint256 share) {
        uint256 feeAmount = amount.mul(BORROW_OPENING_FEE) / BORROW_OPENING_FEE_PRECISION; // A flat % fee is charged for any borrow
        (totalBorrow, part) = totalBorrow.add(amount.add(feeAmount), true);

        BorrowCap memory cap =  borrowLimit;

        require(totalBorrow.elastic <= cap.total, "Borrow Limit reached");

        accrueInfo.feesEarned = accrueInfo.feesEarned.add(uint128(feeAmount));
        
        uint256 newBorrowPart = userBorrowPart[msg.sender].add(part);
        require(newBorrowPart <= cap.borrowPartPerAddress, "Borrow Limit reached");
        _preBorrowAction(to, amount, newBorrowPart, part);

        userBorrowPart[msg.sender] = newBorrowPart;

        // As long as there are tokens on this contract you can 'mint'... this enables limiting borrows
        share = bentoBox.toShare(magicInternetMoney, amount, false);
        bentoBox.transfer(magicInternetMoney, address(this), to, share);

        emit LogBorrow(msg.sender, to, amount.add(feeAmount), part);
    }

Vulnerability type: Flashloans
HIGH severity: AurumNodePool (AUR) — Incorrect access control. The changeRewardPerNode function lacks proper access control validation, which allows an attacker to call this function and set any value. The attacker first calls the changeRewardPerNode function to set the daily reward value to an extremely large number. Subsequently, the attacker calls the claimNodeReward function to extract the node reward, which is calculated based on the rewardPerDay value that the attacker has set.. https://twitter.com/AnciliaInc/status/1595142246570958848 https://quillaudits.medium.com/hackers-steal-42m-from-fenbushi-capital-founders-wallet-dcce2b0a4e5b

Vulnerable code:
function changeRewardPerNode(uint256 _rewardPerDay) external { //vulnerable point - Incorrect access control
    rewardPerDay = _rewardPerDay;
}

Vulnerability type: Access Control
HIGH severity: AzukiDAO — The contract recorded the extracted signature, but did not verify the signature. As long as the passed parameters remain unchanged, multiple extractions can be achieved before the signature time limit expires, causing the attacker to use one signature to perform multiple token extraction operations.. https://twitter.com/sharkteamorg/status/1676892088930271232

Vulnerable code:
function claim(
    address[] memory _contracts,
    uint256[] memory _amounts,
    uint256[] memory _tokenIds,
    uint256 _claimAmount,
    bytes memory _signature,
    uint256 endTime
) external nonPaused nonReentrant {
    // check length
    require(_contracts.length == _amounts.length, "contracts length not match amounts length");

    // check contracts
    for (uint256 i = 0; i < _contracts.length; i++) {
        require(contractSupports[_contracts[i]], "contract not support");
    }

    uint256 totalAmount;
    for (uint256 j = 0; j < _amounts.length; j++) {
        totalAmount += _amounts[j];
    }
    require(totalAmount == _tokenIds.length, "total amount not match tokenId length");

    // check signature
    bytes32 message = keccak256(abi.encodePacked(msg.sender, _contracts, _tokenIds, _claimAmount, endTime));
    require(signatureManager == message.toEthSignedMessageHash().recover(_signature, "invalid signature");
    require(block.timestamp <= endTime, "signature expired");

    // check NFT
    uint256 endIndex;
    for (uint256 i = 0; i < _amounts.length; i++) {
        endIndex = startIndex + _amounts[i];
    }

    for (uint256 j = startIndex; j < endIndex; j++) {
        address contractAddr = _contracts[i];
        address tokenId = _tokenIds[j];
        require(ERC721(contractAddr).ownerOf(tokenId) == msg.sender, "not owner");
        tokenClaimed[contractAddr][tokenId] = true;
    }
    startIndex = endIndex;
    signatureClaimed[_signature] = true;
    // transfer token
    _transfer(address(this), msg.sender, _claimAmount);
}

Vulnerability type: Access Control
HIGH severity: SellToken02 — The flaw in the token price calculation allowed malicious actors to manipulate the price of the token, leading to significant losses for users and potentially creating an opportunity for the attackers to profit unfairly. KALOS: This type of vulnerability occurs through the ShortStart() function of SellToken.Router, specifically due to an issue with the getToken2Price() function used internally. This function retrieves the token price from PancakeSwap’s Router and utilizes it. The attacker leveraged a flash loan to borrow a significant amount of funds and executed an Inflation Attack using this method.. https://twitter.com/BlockSecTeam/status/1657324561577435136 https://twitter.com/kalos_security/status/1668092971483561985

Vulnerable code:
function ShortStart(address coin, address addr, uint terrace) payable public {
    address bnbOrUsdt = mkt.getPair(coin);
    require(terraces;
        routePath;
        routePath[0] = token;
        routePath[1] = isbnb;
        routePath[2] = _WBNB;
        return IRouter(_router).getAmountsOut(bnb, routePath)[2]; // vulnerable point
    }
}

Vulnerability type: Price Manipulation
HIGH severity: Lifiprotocol — Arbitrary call. The internal swap() function would call out to any address using whatever message the attacker passed in. This allowed the attacker to have the contract transferFrom() out the funds from anyone who had approved the contract. https://x.com/danielvf/status/1505689981385334784

Vulnerable code:
function swap(bytes32 transactionId, SwapData calldata _swapData) internal {
    uint256 fromAmount = _swapData.fromAmount;
    uint256 toAmount = LibAsset.getBalance(_swapData.receivingAssetId);
    address fromAssetId = _swapData.sendingAssetId;
    if (LibAsset.isNativeAsset(fromAssetId) && LibAsset.getOwnBalance(fromAssetId) < fromAmount) {
        LibAsset.transferFromERC20(_swapData.sendingAssetId, msg.sender, address(this), fromAmount);
    }

    if (!LibAsset.isNativeAsset(fromAssetId)) {
        LibAsset.approveERC20(IERC20(fromAssetId), _swapData.approveTo, fromAmount);
    }

    // solhint-disable-next-line avoid-low-level-calls
    bool success;
    bytes memory res = _swapData.call({ value: msg.value } ); // Vulnerable point
    if (!success) {
        string memory reason = LibUtil.getRevertMsg(res);
        revert(reason);
    }
}

Vulnerability type: Insufficient validation
HIGH severity: SSS — Simple logic error `transferFrom(me, me, amount)` will multiply the balance.. https://twitter.com/SSS_HQ/status/1771054306520867242 https://twitter.com/dot_pengun/status/1770989208125272481

Vulnerable code:
function _update(address from, address to, uint256 amount) internal override virtual {
    // don't check if it is minting or burning
    if (from == address(0) || to == address(0) || to == address(0xdead)) {
        super._update(from, to, amount);
        return;
    }

    _botCheck(from, to);
    uint256 fromBalanceBeforeTransfer = _preCheck(from, to, amount);

    uint256 amountAfterTax = amount - _taxApply(from, to, amount);
    uint256 toBalance = _postCheck(from, to, amountAfterTax);

    _balances[from] = fromBalanceBeforeTransfer - amount;
    _balances[to] = toBalance;

    _unlockTokenForDev(from, to, amount);

    emit Transfer(from, to, amountAfterTax);
}

Vulnerability type: Incorrect logic
HIGH severity: GoodDollar — _stakingContracts lack of Input Validation & Reentrancy. https://x.com/MetaSec_xyz/status/1736428284756607386

Vulnerable code:
function collectInterest(
    address[] calldata _stakingContracts, // 1. Lack of validation for untrusted user input
    bool _forceAndWaiverRewards
) external {
    uint256 currentBalance = daiToken.balanceOf(reserveAddress);
    uint256 startingCDAIBalance = iToken.balanceOf(reserveAddress);
    for (uint256 i = _stakingContracts.length; i > 0; i--) {
        if (_stakingContracts[i - 1] != address(0x0)) {
            IGoodStaking(_stakingContracts[i - 1]).collectUBIInterest(
                reserveAddress
            );
        }
    }
    // 2. Reentrancy to manipulated iToken.balanceOf(reserveAddress)
    uint256 daiToConvert = daiToken.balanceOf(reserveAddress) - currentBalance;

    // 3. Interest is boosted due to manipulated iToken.balanceOf(reserveAddress)
    (gdUBI, interestInCdai) = GoodReserveCDai(reserveAddress).mintUBI(
        daiToConvert,
        startingCDAIBalance,
        iToken
    );
}

Vulnerability type: Insufficient validation, Reentrancy
HIGH severity: OpenLeverage — The initialize function in the upgradeable proxy lacks access control, allowing an attacker to re-initialize the proxy, become the owner of the contract, and withdraw all the tokens as a reward.. https://defimon.xyz/exploit/bsc/0x5366c6ba729d9cf8d472500afc1a2976ac2fe9ff

Vulnerable code:
function initialize(address payable _admin, address _distributor, uint64 _defaultExpireDuration) public {
    require(_defaultExpireDuration > 0, "Incorrect inputs");
    admin = _admin;
    distributor = _distributor;
    defaultExpireDuration = _defaultExpireDuration;
}

Vulnerability type: Access Control, Insufficient validation
HIGH severity: Libertify — `deposit()` function lack of reentrancy protection, which allows the hacker to mint more shares via re-entering `deposit()` routine.. https://twitter.com/peckshield/status/1678688731908411393 https://twitter.com/Phalcon_xyz/status/1678694679767031809

Vulnerable code:
function _deposit(
    uint256 assets,
    address receiver,
    bytes calldata data,
    uint256 nav
) private returns (uint256 shares) {
    ...
    if (BASIS_POINT_MAX > invariant) {
        swapAmount = assetsToToken1(assets);
        returnAmount = userSwap(
            data,
            address(this),
            swapAmount,
            address(asset),
            address(other)
        ); // Re-enter deposit()
    }

    uint256 supply = totalSupply(); // Mint share before totalSupply update via reentrancy
    if (0 < supply) {
        shares = INITIAL_SHARE;
        uint256 feeAmount = shares.mulDiv(entryFee, BASIS_POINT_MAX, MathUpgradeable.Rounding.Down);
        _mint(receiver, shares - feeAmount);
        _mint(owner(), feeAmount); // mint(feeTo)
    } else {
        ...
    }
}

Vulnerability type: Reentrancy
HIGH severity: BonqDAO — Price Oracle manipulation due to incorrect integration of the Tellor Oracle.. https://quillaudits.medium.com/decoding-bonq-daos-120-million-exploit-quillaudits-bd8e50eec4ac https://twitter.com/BlockSecTeam/status/1621043757390123008

Vulnerable code:
function submitValue(
        bytes32 _queryId,
        bytes calldata _value,
        uint256 _nonce,
        bytes calldata _queryData
    ) external {
        require(keccak256(_value) != keccak256(""), "value must be submitted");
        Report storage _report = reports[_queryId];
        require(
            _nonce == _report.timestamps.length || _nonce == 0,
            "nonce must match timestamp index"
        );
        StakeInfo storage _staker = stakerDetails[msg.sender];
        require(
            _staker.stakedBalance >= stakeAmount, // Its checks if the staker balance is more than stakeAmount i.e. 10 TRB
            "balance must be greater than stake amount"
        );

        require(
            (block.timestamp - _staker.reporterLastTimestamp) * 1000 >
                (reportingLock * 1000) / (_staker.stakedBalance / stakeAmount),
            "still in reporter time lock, please wait!"
        );

        _report.timestampIndex[block.timestamp] = _report.timestamps.length;
        _report.timestamps.push(block.timestamp);
        _report.timestampToBlockNum[block.timestamp] = block.number;
        _report.valueByTimestamp[block.timestamp] = _value; // Vulnerable Point: The value is assigned here. Anyone who has staked 10TRB can submit the balance.
        _report.reporterByTimestamp[block.timestamp] = msg.sender;
        // Disperse Time Based Reward
        uint256 _reward = ((block.timestamp - timeOfLastNewValue) * timeBasedReward) / 300; //.5 TRB per 5 minutes
    }

Vulnerability type: Insufficient validation, Oracle
HIGH severity: Burner — Incorrect logic so sandwich.. https://medium.com/@daleewong/burner-exploit-analysis-0733a69ddc27

Vulnerable code:
function burn() public {
    require(!paused, 'cannot burn when paused');
    uint total = token.balanceOf(address(this));
    uint toBurn = total.mul(percentageToBurn).div(100);
    token.burn(toBurn, '');
    uint notBurned = token.balanceOf(address(this));
    require(token.transfer(unburnedDestination, notBurned), 'cannot transfer unburned tokens');
    emit Burn(toBurn, notBurned);
}

function convertAndBurn(address[] calldata tokens) external {
    for (uint i = 0; i < tokens.length; i++) {
        _convert(tokens[i]);
    }
    burn();
}

function _convert(address srcToken) internal {
    uint srcAmount;
    uint converted;
    if (srcToken == ETHER || srcToken == address(0)) {
        srcAmount = address(this).balance;
        converted = kyberNetwork.trade
            .value(srcAmount)(ETHER, srcAmount, address(token), address(uint160(address(this))), BIG_LIMIT, 1, kyberFeeWallet); // <-- vulnerable point
    } else {
        srcAmount = IERC20(srcToken).balanceOf(address(this));
        if (IERC20(srcToken).allowance(address(this), address(kyberNetwork)) > 0) {
            IERC20(srcToken).safeApprove(address(kyberNetwork), 0);
        }
        IERC20(srcToken).safeApprove(address(kyberNetwork), srcAmount);
        converted = kyberNetwork.trade(srcToken, srcAmount, address(token), address(uint160(address(this))), BIG_LIMIT, 1, kyberFeeWallet);
    }
    emit TokenTrade(srcToken, srcAmount, converted);
}

Vulnerability type: Business Logic Flaw, Sandwich