Farseen0/scar-pairs huggingface dataset:
HIGH severity: Market — Market.xyz had been utilizing the Curve LP Oracle for their lending and borrowing markets. However, a price manipulation vulnerability arose because of the presence of Read-Only Reentrancy in the Curve LP Oracle.. The attack flow as follow:
1. Execute a flashloan of WMATIC and stMATIC tokens.
2. Provide liquidity to the WMATIC/stMATIC Curve pool and receive Curve LP tokens.
3. Utilize a portion of the Curve LP tokens as collateral on [\"http://market.xyz\"](http://market.xyz/).
4. **Increase** the collateral'

Vulnerable code:
@external
@nonreentrant('lock')
def remove_liquidity(_amount: uint256, min_amounts: uint256[N_COINS],
                     use_eth: bool = False, receiver: address = msg.sender):
    """
    This withdrawal method is very safe, does no complex math
    """
    lp_token: address = self.token
    total_supply: uint256 = CurveToken(lp_token).totalSupply()
    CurveToken(lp_token).burnFrom(msg.sender, _amount)
    balances: uint256[N_COINS] = self.balances
    amount: uint256 = _amount - 1  # Make rounding errors favoring other LPs a tiny bit

    for i in range(N_COINS):
        d_balance: uint256 = balances[i] * amount / total_supply
        assert d_balance >= min_amounts[i]
        self.balances[i] = balances[i] - d_balance
        balances[i] = d_balance  # now it's the amounts going out
        coin: address = self.coins[i]
        if use_eth and coin == WETH20:
            raw_call(receiver, b"", value=d_balance)
        else:
            if coin == WETH20:
                WETH(WETH20).deposit(value=d_balance)
            response: Bytes[32] = raw_call(
                coin,
                _abi_encode(receiver, d_balance, method_id=method_id("transfer(address,uint256)")),
                max_outsize=32,
            )
            if len(response) != 0:
                assert convert(response, bool)

    D: uint256 = self.D
    self.D = D - D * amount / total_supply

    log RemoveLiquidity(msg.sender, balances, total_supply - _amount)

Vulnerability type: Flashloans, Reentrancy
HIGH severity: UPS — The UPS token was exploited due to a flawed transfer implementation. When tokens are transferred to the Pancake pair, they are burned at the pair and the "skim" function is called. This caused the UPS reserve to shrink significantly, allowing the hacker to drain BUSD from the pair using just a few UPS tokens.. Root cause: Vulnerable code snippet: Attack tx: Analysis:

Vulnerable code:
super._update(from, to, amount);
else if (to == pairAddress) { // 交易对地址
    uint256 fee = amount * 5 / 100;
    if (!inSwapAndLiquify) {
        _swapBurn(amount - fee); // Vulnerable Point: potential reentrancy issue
    }
    if (nodeList.length > 0) {
        uint256 every = fee / nodeList.length;
        for (uint256 i = 0; i < nodeList.length; i++) {
            super._update(from, nodeList[i], every);
        }
    } else {
        _burn(from, fee);
    }
    super._update(from, to, amount - fee);

Vulnerability type: Business Logic Flaw
HIGH severity: VTF Token — The function `updateUserBalance` does not ascertain the duration for which a user has retained the token. Exploiting this, the attacker pre-deploys numerous malicious contracts, secures the initial $VTF via a flashloan, and subsequently transfers the VTF tokens to each attack contract sequentially. This maneuver enables the attacker to claim the rewards for holding.. https://twitter.com/BlockSecTeam/status/1585575129936977920 https://twitter.com/peckshield/status/1585572694241988609 https://twitter.com/BeosinAlert/status/1585587030981218305

Vulnerable code:
function updateUserBalance(address _user) public {
	uint256 totalAmountOver = super.totalSupply();
	if (maxTotal <= totalAmountOver) {
		maxCanMint = false;
	}

	if (userBalanceTime[_user] > 0) {
		uint256 canMint = getUserCanMint(_user);
		if (canMint > 0) {
			userBalanceTime[_user] = block.timestamp;
			_mint(_user, canMint);
		}
	} else {
		userBalanceTime[_user] = block.timestamp;
	}
}

Vulnerability type: Business Logic Flaw, Flashloans
HIGH severity: Juice — The root cause is in Staking Contract, the `harvest()` mishandling the `rewardPerShare`. None

Vulnerable code:
function harvest(uint256 stakeCount) external {
    require(mapStakingInfo[address(msg.sender)][stakeCount].stakedAmount > 0, "Staking not found");
    require(mapStakingInfo[address(msg.sender)][stakeCount].unstakeStatus == 0, "Staking already unstake");
    
    _updatePool();
    
    (uint256 pending, uint256 bonus) = pendingReward(address(msg.sender), stakeCount);
    IERC20(Juice).safeTransfer(address(msg.sender), (pending + bonus));
    
    mapStakingInfo[address(msg.sender)][stakeCount].rewardDebt += pending;
    emit Harvest(msg.sender, (pending + bonus));
}

function _updatePool() internal {
    if (block.timestamp <= lastRewardUpdateTime) {
        return;
    }
    if (JuiceStaked == 0) {
        lastRewardUpdateTime = block.timestamp;
        return;
    }
    uint256 multiplier = _getMultiplier(lastRewardUpdateTime, block.timestamp);
    uint256 stakingReward = multiplier * rewardPerSecond;
    rewardPerShare = rewardPerShare + (stakingReward * precisionFactor) / JuiceStaked;
    lastRewardUpdateTime = block.timestamp;
}

Vulnerability type: Business Logic Flaw
HIGH severity: wsm — Using a flash loan to create a price disparity in the BNB_WSM pool, the attacker then manipulated the price through the `buyWithBNB()` function in the presale contract.. None

Vulnerable code:
function buyWithBNB(uint256 amount, bool _stakeStaus) external payable whenNotPaused nonReentrant returns (bool) {
    require(dynamicSaleState, 'dynamic sale not active');
    require(amount <= maxTokensToSell - directTotalTokensSold, 'amount exceeds max tokens to be sold');
    directTotalTokensSold += amount;
    uint256 ethAmount = fetchPrice(amount * baseDecimals);
    require(msg.value >= ethAmount, 'Less payment');
    uint256 excess = msg.value - ethAmount;
    sendValue(payable(paymentWallet), ethAmount);
    if (excess > 0) sendValue(payable(_msgSender()), excess);
    if (!_stakeStaus) {
        bool success = IERC20Upgradeable(saleToken).transfer(_msgSender(), (amount * baseDecimals));
        require(success, 'Token transfer failed');
        emit TokensBought(_msgSender(), amount, address(0), ethAmount, 0, block.timestamp);
    } else {
        stakingManagerInterface.depositByPresale(_msgSender(), amount * baseDecimals);
        emit TokensBoughtAndStaked(_msgSender(), amount, address(0), ethAmount, 0, block.timestamp);
    }

    return true;
}

function fetchPrice(uint256 amountOut) public returns (uint256) {
    bytes memory data = abi.encodeWithSelector(quoter.quoteExactOutputSingle.selector, 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c, 0x62694D43Ccb9B64e76e38385d15e325c7712A735, 3000, amountOut, 0);
    (bool success, bytes memory result) = address(quoter).call(data);
    require(success, 'Call to Quoter failed');
    uint256 amountIn = abi.decode(result, (uint256));
    return amountIn + ((amountIn * percent) / 100);
}

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: UFDao — It's due to the incorrect parameter setting. The attacker bought a public offer of the UF Dao with 1:1 rate using USDC, then redeemed almost all in UF Dao.. https://twitter.com/BlockSecTeam/status/1613507804412940289

Vulnerable code:
function buyPublicOffer(address _dao, uint256 _lpAmount)
        external
        nonReentrant
        returns (bool) {
        require(
            IFactory(factory).containsDao(_dao),
            "Shop: only DAO can sell LPs"
        );

        PublicOffer memory publicOffer = publicOffers[_dao]; // Vulnerable point

        require(publicOffer.isActive, "Shop: this offer is disabled");

        IERC20(publicOffer.currency).safeTransferFrom(
            msg.sender,
            _dao,
            (_lpAmount * publicOffer.rate) / 1e18   // Vulnerable point
        );

        address lp = IDao(_dao).lp();

        bool b = ILP(lp).mint(msg.sender, _lpAmount);

        require(b, "Shop: mint error");

        return true;
    }

Vulnerability type: Misconfiguration
HIGH severity: AIS — There is no access control in `AIS::setSwapPairs`, allowing the attacker to set pairs to arbitrary addresses. The attacker sets Pancakeswap as a valid pair and transfers tokens to the pair through `AIS::transfer`, subsequently executing the `Pancakeswap::skim` operation to profit.. https://x.com/Phalcon_xyz/status/1729861048004391306/photo/1

Vulnerable code:
function setSwapPairs(address _address) public { //onlyOwner {
    Pairs[_address] = true;
}

Vulnerability type: Insufficient validation
HIGH severity: RL Token — Incorrect Reward calculation. Vulnerable code snippet:

[https://bscscan.com/address/0x4bbfae575dd47bcfd5770ab4bc54eb83db088888#code#F1#L129](https://bscscan.com/address/0x4bbfae575dd47bcfd5770ab4bc54eb83db088888#code#F1#L129)

Custom transferFrom function
```solidity
function transferFrom( 
        address from, 
        addres

Vulnerable code:
function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        if (from != address(pancakeSwapV2Pair) && from != address(pancakeSwapV2Router)) {
            incentive.distributeAirdrop(from);
        }
        if (to != address(pancakeSwapV2Pair) && to != address(pancakeSwapV2Router)) {
            incentive.distributeAirdrop(to); // trace function
        }
        if (msg.sender != address(pancakeSwapV2Pair) && msg.sender != address(pancakeSwapV2Router)) {
            incentive.distributeAirdrop(msg.sender); // trace function
        }
        require(allowance(from, msg.sender) >= amount, "insufficient allowance");
        if (govIDO != address(0)) {
            if (IKBKGovIDO(govIDO).isPriSaler(from)) {
                IKBKGovIDO(govIDO).releasePriSale(from);
            }
            if (IKBKGovIDO(govIDO).isPriSaler(to)) {
                IKBKGovIDO(govIDO).releasePriSale(to);
            }
        }
        // sell
        if (to == address(pancakeSwapV2Pair) && msg.sender == address(pancakeSwapV2Router)) {
            if (!isCommunityAddress[from]) {
                uint burnAmt = amount / 100;
                _burn(from, burnAmt);
                uint slideAmt = amount * 2 / 100;
                _transfer(from, slideReceiver, slideAmt);
                amount -= (burnAmt + slideAmt);
            }
        } else {
            if (!isCommunityAddress[from] && !isCommunityAddress[to]) {
                uint burnAmt = amount / 100;
                amount -= burnAmt;
                _burn(from, burnAmt);
            }
        }
        return super.transferFrom(from, to, amount);
    } ...  function distributeAirdrop(address user) public override {
    if (block.timestamp < airdropStartTime) {
        return;
    }
    updateIndex();
    uint256 rewards = getUserUnclaimedRewards(user); // vulnerable point
    usersIndex[user] = globalAirdropInfo.index;
    if (rewards > 0) {
        uint256 bal = rewardToken.balanceOf(address(this));
        if (bal >= rewards) {
            rewardToken.transfer(user, rewards);
            userUnclaimedRewards[user] = 0;
        }
    }
}

function getUserUnclaimedRewards(address user) public view returns (uint256) {
    if (block.timestamp < airdropStartTime) {
        return 0;
    }
    (uint256 newIndex,) = getNewIndex();
    uint256 userIndex = usersIndex[user];
    if (userIndex >= newIndex || userIndex == 0) {
        return userUnclaimedRewards[user];
    } else {
        // vulnerable point, Incorrect Reward calculation. only check balanceOf of user without any requirement.
        return userUnclaimedRewards[user] + (newIndex - userIndex) * lpToken.balanceOf(user) / PRECISION;
    }
}

Vulnerability type: ERC20, Flashloans
HIGH severity: SellToken01 — In the StakingRewards contract, the listToken[] can be set  in the addLiquidity() function. However, this operation *should*  be restricted to 'OwnerOnly'. By exploiting this vulnerability, a hacker can add their self-created token to listToken and subsequently call the sell function.. https://twitter.com/AnciliaInc/status/1656341587054702598

Vulnerable code:
function addLiquidity(address _token, address token1, uint amount1) public {  // @audit: pass in fake _token 
    uint lp = IERC20(_token).totalSupply() * 90 / 100;
    uint miner = IERC20(_token).totalSupply() * 10 / 100;
    bool isok = IERC20(_token).transferFrom(msg.sender, address(this), IERC20(_token).totalSupply());
    isok = IERC20(token1).transferFrom(msg.sender, address(this), amount1);
    require(isok);
    IERC20(_token).approve(address(address(IRouters)), 2 ** 256 - 1);
    IRouters.addLiquidity(_token, token1, lp, amount1, 0, 0, address(this), block.timestamp + 100);
    address pair = ISwapFactory(IRouters.factory()).getPair(_token, token1);
    if (pairs(pair).IRouter() == address(0)) {
        pairs(pair).setIRouter(0xBDDFA43dbBfb5120738C922fa0212ef1E4a0850B);
    }
    if (myReward[_token] == address(0)) {
        myReward[_token] = token1;
    }
    listToken[_token] = true; // vulnerable point
    users[_token][0x2F98Fa813Ced7Aa9Fd6788aB624b2F3F292B9239].tz += 100 ether;
}

Vulnerability type: Access Control
HIGH severity: BTC20 — The vulnerable fetchPrice function calls getAmountsIn on the Uniswap router using the WETH-BTC20 pair, which relies on the pair's reserves. The attacker bought a large amount of BTC20 in the WETH-BTC20 pair to manipulate the price. https://twitter.com/DecurityHQ/status/1692924369662513472

Vulnerable code:
function fetchPrice(uint256 amountOut) public view returns (uint256) {
    address;
    path[0] = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    path[1] = 0xE86DF1970055e9CaEe93Dae9B7D5fD71595d0e18;
    uint256[] memory amounts = router.getAmountsIn(amountOut, path);
    return amounts[0] + ((amounts[0] * percent) / 100);
}

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: NORMIE — Improper verification mechanism for assigning the "premarket user" role. The system only checks if the transfer amount equals the balance of the `teamWalletAddress`, which is public information and easily exploitable.. https://extropy-io.medium.com/block-forensics-an-in-depth-analysis-of-the-normie-memecoin-incident-0daf5baed08b

Vulnerable code:
function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) private returns (bool) {
        ... // code
        if (
            isMarketPair[sender] &&
            !isExcludedFromFee[recipient] &&
            premarket_user[recipient] // checks that the recipient is a "premarket user"
        ) {
            _balances[address(this)] = _balances[address(this)].add(amount); // contract balance is increased
        }
        ... // code
        _balances[sender] = _balances[sender].sub(
            amount,
            "Insufficient Balance"
        ); // sender balance decreased
        uint256 finalAmount = (isExcludedFromFee[sender] ||
            isExcludedFromFee[recipient])
            ? amount
            : takeFee(sender, recipient, amount);
        if (checkWalletLimit && !isWalletLimitExempt[recipient])
            require(balanceOf(recipient).add(finalAmount) <= _walletMax);
        _balances[recipient] = _balances[recipient].add(finalAmount); // recipient balance increased
        _get_premarket_user(recipient, amount); // <--VUlNERABLE POINT
        emit Transfer(sender, recipient, finalAmount);
        return true;
    }

Vulnerability type: Business Logic Flaw
HIGH severity: BabyDogeCoin02 — In the process between `swapTokensForEth` and `addLiquidity`, there exists a time window that attackers can exploit to manipulate the market price.. https://x.com/hexagate_/status/1671517819840745475

Vulnerable code:
function swapAndLiquify(uint256 contractTokenBalance) private lockTheSwap {
        // split the contract balance into halves
        uint256 half = contractTokenBalance.div(2);
        uint256 otherHalf = contractTokenBalance.sub(half);

        // capture the contract's current ETH balance.
        // this is so that we can capture exactly the amount of ETH that the
        // swap creates, and not make the liquidity event include any ETH that
        // has been manually sent to the contract
        uint256 initialBalance = address(this).balance;

        // swap tokens for ETH
        swapTokensForEth(half); // <- this breaks the ETH -> HATE swap when swap+liquify is triggered

        // how much ETH did we just swap into?
        uint256 newBalance = address(this).balance.sub(initialBalance);

        // add liquidity to uniswap
        addLiquidity(otherHalf, newBalance);
        
        emit SwapAndLiquify(half, newBalance, otherHalf);
    }

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: EulerFinance — The primary problem here with Euler was its `donateToReserves()` function. which allows the user to transfer tokens from their own balance to a protocol variable called `assetStorage.reserveBalance.`.This function allowed the attacker to`donate` eDAI to Euler reserves, removing assets from their wallet without removing a corresponding amount of debt. Here borrower minted 195 million e-DAI and 200 million d-DAI tokens. A logical error in the `donateToReserve()` method resulted in the burning of e-DAI tokens but not d-DAI tokens, leading to unbacked `d-DAI` token debt that will never be repaid.. https://twitter.com/FrankResearcher/status/1635241475989721089 https://twitter.com/nomorebear/status/1635230621856600064 https://twitter.com/peckshield/status/1635229594596036608 https://twitter.com/BlockSecTeam/status/1635262150624305153 https://twitter.com/SlowMist_Team/status/1635288963580825606

Vulnerable code:
function donateToReserves(uint subAccountId, uint amount) external nonReentrant {
        (address underlying, AssetStorage storage assetStorage, address proxyAddr, address msgSender) = CALLER();
        address account = getSubAccount(msgSender, subAccountId);

        updateAverageLiquidity(account);
        emit RequestDonate(account, amount);

        AssetCache memory assetCache = loadAssetCache(underlying, assetStorage);

        uint origBalance = assetStorage.users[account].balance;
        uint newBalance;

        if (amount == type(uint).max) {
            amount = origBalance;
            newBalance = 0;
        } else {
            require(origBalance >= amount, "e/insufficient-balance");
            unchecked { newBalance = origBalance - amount; }
        }

        assetStorage.users[account].balance = encodeAmount(newBalance);
        assetStorage.reserveBalance = assetCache.reserveBalance = encodeSmallAmount(assetCache.reserveBalance + amount);

        emit Withdraw(assetCache.underlying, account, amount);
        emitViaProxy_Transfer(proxyAddr, account, address(0), amount);

        logAssetStatus(assetCache);
    }

Vulnerability type: Business Logic Flaw, Flashloans
HIGH severity: Biswap — Biswap's V3Migrator contract lacks parameter check, which allows the attacker to steal tokens from the users who approved LP tokens to the V3Migrator contract.. https://twitter.com/MetaTrustAlert/status/1674814217122349056?s=20

Vulnerable code:
function migrate(MigrateParams calldata params) external override returns (uint refund0, uint refund1) {
    // burn v2 liquidity to this address
    IBiswapPair(params.pair).transferFrom(params.pair, params.liquidityToMigrate);
    (uint256 amount0V2, uint256 amount1V2) = IBiswapPair(params.pair).burn(address(this));

    // calculate the amounts to migrate to v3
    uint128 amount0V2ToMigrate = uint128(amount0V2);
    uint128 amount1V2ToMigrate = uint128(amount1V2);

    // approve the position manager up to the maximum amounts
    safeApprove(params.token, liquidityManager, amount0V2ToMigrate);
    safeApprove(params.token, liquidityManager, amount1V2ToMigrate);

    // mint v3 position
    (, uint256 amount0V3, uint256 amount1V3) = ILiquidtyManager(liquidityManager).mint(
        ILiquidtyManager.MintParam(
            miner: params.recipient,
            tokenX: params.token,
            tokenY: params.token1,
            fee: params.fee,
            pl: params.tickLower,
            xLm: amount0V2ToMigrate,
            yLm: amount1V2ToMigrate
        )
    );
}

Vulnerability type: Access Control
HIGH severity: InverseFinance — Incorrect LP price calculation via balanceOf. Insecure way to calculation of LP price via balanceOf in the pool.. Insecure way to calculation of LP price via balanceOf in the pool.

Vulnerable code:
function latestAnswer() public view returns (uint256) {
        uint256 crvPoolBtcVal = WBTC.balanceOf(address(CRV3CRYPTO)) * uint256(BTCFeed.latestAnswer()) * 1e2; // vulnerable point
        uint256 crvPoolWethVal = WETH.balanceOf(address(CRV3CRYPTO)) * uint256(ETHFeed.latestAnswer()) / 1e8; // vulnerable point
        uint256 crvPoolUsdtVal = USDT.balanceOf(address(CRV3CRYPTO)) * uint256(USDTFeed.latestAnswer()) * 1e4; // vulnerable point

        uint256 crvLPTokenPrice = (crvPoolBtcVal + crvPoolWethVal + crvPoolUsdtVal) * 1e18 / crv3CryptoLPToken.totalSupply();

        return (crvLPTokenPrice * vault.pricePerShare()) / 1e18;
    }

Vulnerability type: Flashloans, lending
HIGH severity: SUT — The Root cause  is that the tokenPrice in the tokenPrice() function in the `0xF075c5C7BA59208c0B9c41afcCd1f60da9EC9c37` contract is much smaller than the token price in the pool.. https://twitter.com/bulu4477/status/1682983956080377857

Vulnerable code:
function buyTokens(uint256 _numberOfTokens) public payable {
    uint256 _bnbValue = (_numberOfTokens / 10000000000000000) * tokenPrice;
    require(msg.value >= _bnbValue, "Not enough BNB");
    require(tokenContract.balanceOf(address(this)) >= _numberOfTokens, "Not enough tokens");
    require(tokenContract.transfer(msg.sender, _numberOfTokens), "Transfer failed");

    tokensSold += _numberOfTokens;
    emit Sell(msg.sender, _numberOfTokens);
}

Vulnerability type: Arbitrage
HIGH severity: NOVO Protocol — No sender address validation. There is no sender address validation in the overridden transferFrom function.. There is no sender address validation in the overridden transferFrom function

Vulnerable code:
function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public override returns (bool) {
        // locked the NOVO of staking holders
        uint256 lockedAmount = getLockedAmount(sender);
        if (lockedAmount > 0) {
            require(
                (balanceOf(sender) - amount) >= lockedAmount,
                "Your balance was locked"
            );
        }
        // _approve(  //vulnerable point - commented out
        //     sender,
        //     _msgSender(),
        //     _allowances[sender][_msgSender()].sub(
        //         amount,
        //         "BEP20: transfer amount exceeds allowance"
        //     )
        // );
        // additional code ...
    }

Vulnerability type: Deflationary token, Flashloans