msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: ETH withdrawers do not earn yield while waiting for a withdrawal
Severity: medium

Description:
In the Rio doc we can read the following\\n"Users will continue to earn yield as they wait for their withdrawal request to be processed."\\nThis is not true for withdrawals in ETH since they will simply receive an equivalent to the `sharesOWed` calculated when requesting a withdrawal.\\nWhen `requestWithdrawal()` is called to withdraw ETH `sharesOwed` is calculated\\n```\\nsharesOwed = convertToSharesFromRestakingTokens(asset, amountIn);\\n```\\n\\nThe total `sharesOwed` in ETH is added to `epcohWithdrawals.assetsReceived` if we settle with `settleCurrentEpoch()` or `settleEpochFromEigenlayer()`\\nBelow are the places where `assetsReceived` is is set and accumulated\\n```\\nepochWithdrawals.assetsReceived = SafeCast.toUint120(assetsReceived);\\n```\\n\\n```\\nepochWithdrawals.assetsReceived = SafeCast.toUint120(assetsReceived); \\n```\\n\\n```\\nepochWithdrawals.assetsReceived += SafeCast.toUint120(assetsReceived);\\n```\\n\\nwhen claiming rewards this is used to calculate users share\\n```\\namountOut = userSummary.sharesOwed.mulDiv(epochWithdrawals.assetsReceived, epochWithdrawals.sharesOwed);\\n```\\n\\nThe portion of staking rewards accumulated during withdrawal that belongs to LRT holders is never accounted for so withdrawing users do not earn any rewards when waiting for a withdrawal to be completed.

Impact:
Since a portion of the staking reward belongs to the LRT holders and since the docs mentions that yield is accumulated while in the queue It is fair to assume that withdrawing users have a proportional claim to the yield.\\nAs shown above this is not true, users withdrawing in ETH do no earn any rewards when withdrawing.\\nNot all depositors will be able to withdraw their assets/principal for non-ETH assets.\\nCzar102\\nI see. I will leave it a duplicate of #109, as it was, which will not change the reward distribution from the scenario where it was invalidated. cc @nevillehuang\\nThanks for reminding me to remove #177 from the duplicates @0xmonrel.\\nCzar102\\nResult: Medium Has Duplicates\\nConsidering this a Medium since the loss is constrained to the interest during some of the withdrawal time, which is a small part of the deposits.\\nsherlock-admin3\\nEscalations have been resolved successfully!\\nEscalation status:\\n0xmonrel: accepted

Recommended mitigation:
Account for the accumulate rewards during the withdrawal period that belongs to the deposit pool. This can be calculated based on data in DelayedWithdrawalRouter on Eigenlayer.
Vulnerability: Whenever swapPrice > oraclePrice, minting via PositionManager will revert, due to not enough funds being obtained from user.
Severity: medium

Description:
In `PositionManager::mint()`, `obtainedPremium` is calculated in a different way to the actual premium needed, and this will lead to a revert, denying service to users.\\nIn `PositionManager::mint()`, the PM gets `obtainedPremium` from DVP::premium():\\n```\\n(obtainedPremium, ) = dvp.premium(params.strike, params.notionalUp, params.notionalDown);\\n```\\n\\nThen the actual premium used when minting by the DVP is obtained via the following code:\\n\\nFrom the code above, we can see that the actual premium uses the greater of the two price options. However, `DVP::premium()` only uses the oracle price to determine the `obtainedPremium`.\\nThis leads to the opportunity for `premiumSwap > premiumOrac`, so in the PositionManager, `obtainedPremium` is less than the actual premium required to mint the position in the DVP contract.\\nThus, when the DVP contract tries to collect the premium from the PositionManager, it will revert due to insufficient balance in the PositionManager:\\n```\\nIERC20Metadata(baseToken).safeTransferFrom(msg.sender, vault, premium_ + vaultFee);\\n```\\n

Impact:
Whenever `swapPrice > oraclePrice`, minting positions via the PositionManager will revert. This is a denial of service to users and this disruption of core protocol functionality can last extended periods of time.

Recommended mitigation:
When calculating `obtainedPremium`, consider also using the premium from `swapPrice` if it is greater than the premium calculated from `oraclePrice`.
Vulnerability: PositionManager will revert when trying to return back to user excess of the premium transferred from the user when minting position
Severity: medium

Description:
`PositionManager.mint` calculates preliminary premium to be paid for buying the option and transfers it from the user. The actual premium paid may differ, and if it's smaller, excess is returned back to user. However, it is returned using the safeTransferFrom:\\n```\\n    if (obtainedPremium > premium) {\\n        baseToken.safeTransferFrom(address(this), msg.sender, obtainedPremium - premium);\\n    }\\n```\\n\\nThe problem is that `PositionManager` doesn't approve itself to transfer baseToken to `msg.sender`, and USDC `transferFrom` implementation requires approval even if address is transferring from its own address. Thus the transfer will revert and user will be unable to open position.\\n```\\n    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {\\n        _transfer(sender, recipient, amount);\\n        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));\\n        return true;\\n    }\\n```\\n\\n```\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 value\\n    )\\n        external\\n        override\\n        whenNotPaused\\n        notBlacklisted(msg.sender)\\n        notBlacklisted(from)\\n        notBlacklisted(to)\\n        returns (bool)\\n    {\\n        require(\\n            value <= allowed[from][msg.sender],\\n            "ERC20: transfer amount exceeds allowance"\\n        );\\n        _transfer(from, to, value);\\n        allowed[from][msg.sender] = allowed[from][msg.sender].sub(value);\\n        return true;\\n    }\\n```\\n\\n`PositionManager` doesn't approve itself to do transfers anywhere, so `baseToken.safeTransferFrom(address(this), msg.sender, obtainedPremium - premium);` will always revert, preventing the user from opening position via `PositionManager`, breaking important protocol function.

Impact:
User is unable to open positions via `PositionManager` in certain situations as all such transactions will revert, breaking important protocol functionality and potentially losing user funds / profit due to failure to open position.

Recommended mitigation:
Consider using `safeTransfer` instead of `safeTransferFrom` when transferring token from self.
Vulnerability: Mint and sales can be dossed due to lack of safeApprove to 0
Severity: medium

Description:
The lack of approval to 0 to the dvp contract, and the fee managers during DVP mints and sales will cause that subsequent transactions involving approval of these contracts to spend the basetoken will fail, breaking their functionality.\\nWhen DVPs are to be minted and sold through the PositionManager, the `mint` and `sell` functions are invoked. The first issue appears here, where the DVP contract is approved to spend the basetoken using the OpenZeppelin's `safeApprove` function, without first approving to zero. Further down the line, the `mint` and `sell` functions make calls to the DVP contract to `mint` and burn DVP respectively.\\nThe _mint and _burn functions in the DVP contract approves the fee manager to spend the fee - vaultFee/netFee.\\nThis issue here is that OpenZeppelin's `safeApprove()` function does not allow changing a non-zero allowance to another non-zero allowance. This will therefore cause all subsequent approval of the basetoken to fail after the first approval, dossing the contract's minting and selling/burning functionality.\\nOpenZeppelin's `safeApprove()` will revert if the account already is approved and the new `safeApprove()` is done with a non-zero value.\\n```\\n    function safeApprove(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        // safeApprove should only be called when setting an initial allowance,\\n        // or when resetting it to zero. To increase and decrease it, use\\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n        require(\\n            (value == 0) || (token.allowance(address(this), spender) == 0),\\n            "SafeERC20: approve from non-zero to non-zero allowance"\\n        );\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n    }\\n```\\n

Impact:
This causes that after the first approval for the baseToken has been given, subsequent approvals will fail causing the functions to fail.

Recommended mitigation:
Approve first to 0;\\nUpdate the OpenZeppelin version to the latest and use the `forceApprove` functions instead;\\nRefactor the functions to allow for direct transfer of base tokens to the DVP and FeeManager contracts directly.
Vulnerability: JalaPair potential permanent DoS due to overflow
Severity: medium

Description:
In the `JalaPair::_update` function, overflow is intentionally desired in the calculations for `timeElapsed` and `priceCumulative`. This is forked from the UniswapV2 source code, and it's meant and known to overflow. UniswapV2 was developed using Solidity 0.6.6, where arithmetic operations overflow and underflow by default. However, Jala utilizes Solidity >=0.8.0, where such operations will automatically revert.\\n```\\nuint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired\\nif (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {\\n    // * never overflows, and + overflow is desired\\n    price0CumulativeLast += uint256(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;\\n    price1CumulativeLast += uint256(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;\\n}\\n```\\n

Impact:
This issue could potentially lead to permanent denial of service for a pool. All the core functionalities such as `mint`, `burn`, or `swap` would be broken. Consequently, all funds would be locked within the contract.\\nI think issue with High impact and a Low probability (merely due to the extended timeframe for the event's occurrence, it's important to note that this event will occur with 100% probability if the protocol exists at that time), should be considered at least as Medium.\\nReferences\\nThere are cases where the same issue is considered High.

Recommended mitigation:
Use the `unchecked` block to ensure everything overflows as expected
Vulnerability: Fees aren't distributed properly for positions with multiple lenders, causing loss of funds for lenders
Severity: high

Description:
Fees distributed are calculated according to a lender's amount lent divided by the total amount lent, which causes more recent lenders to steal fees from older lenders.\\n```\\n                uint256 feesAmt = FullMath.mulDiv(feesOwed, cache.holdTokenDebt, borrowedAmount); //fees owed multiplied by the individual amount lent, divided by the total amount lent\\n                // rest of code\\n                loansFeesInfo[creditor][cache.holdToken] += feesAmt;\\n                harvestedAmt += feesAmt;\\n```\\n\\nThe above is from harvest(); `repay()` calculates the fees similarly. Because `borrow()` doesn't distribute fees, the following scenario will occur when a borrower increases an existing position:\\nBorrower has an existing position with fees not yet collected by the lenders.\\nBorrower increases the position with a loan from a new lender.\\n`harvest()` or `repay()` is called, and the new lender is credited with some of the previous fees earned by the other lenders due to the fees calculation. Other lenders lose fees.\\nThis scenario can naturally occur during the normal functioning of the protocol, or a borrower/attacker with a position with a large amount of uncollected fees can maliciously open a proportionally large loan with an attacker to steal most of the fees.\\nAlso note that ANY UDPATE ISSUE? LOW PRIO

Impact:
Loss of funds for lenders, potential for borrowers to steal fees.

Recommended mitigation:
A potential fix is to harvest fees in the borrow() function; the scenario above will no longer be possible.
Vulnerability: Entrance fees are distributed wrongly in loans with multiple lenders
Severity: medium

Description:
Entrance fees are distributed improperly, some lenders are likely to lose some portion of their entrance fees. Also, calling `updateHoldTokenEntranceFee()` can cause improper entrance fee distribution in loans with multiple lenders.\\nNote that entrance fees are added to the borrower's `feesOwed` when borrowing:\\n```\\n        borrowing.feesOwed += entranceFee;\\n```\\n\\n```\\n                uint256 feesAmt = FullMath.mulDiv(feesOwed, cache.holdTokenDebt, borrowedAmount); //fees owed multiplied by the individual amount lent, divided by the total amount lent\\n                // rest of code\\n                loansFeesInfo[creditor][cache.holdToken] += feesAmt;\\n                harvestedAmt += feesAmt;\\n```\\n\\nThis is a problem because the entrance fees will be distributed among all lenders instead of credited to each lender. Example:\\nA borrower takes a loan of 100 tokens from a lender and pays an entrance fee of 10 tokens.\\nAfter some time, the lender harvests fees and fees are set to zero. (This step could be frontrunning the below step.)\\nThe borrower immediately takes out another loan of 100 tokens and pays and entrance fee of 10 tokens.\\nWhen fees are harvested again, due to the calculation in the code block above, 5 tokens of the entrance fee go to the first lender and 5 tokens go to the second lender. The first lender has collected 15 tokens of entrance fees, while the second lender has collected only 5- despite both loans having the same borrowed amount.\\nFurthermore, if the entrance fee is increased then new lenders will lose part of their entrance fee. Example:\\nA borrower takes a loan of 100 tokens from a lender and pays an entrance fee of 10 tokens.\\nThe entrance fee is increased.\\nThe borrower increases the position by taking a loan of 100 tokens from a new lender, and pays an entrance fee of 20 tokens.\\n`harvest()` is called, and both lenders receive 15 tokens out of the total 30 tokens paid as entrance fees. This is wrong since the first lender should receive 10 and the second lender should receive 20.

Impact:
Lenders are likely to lose entrance fees.

Recommended mitigation:
Could add the entrance fee directly to the lender's fees balance instead of adding it to feesOwed, and then track the entrance fee in the loan data to be used in min fee enforcement calculations.
Vulnerability: A borrower eligible for liquidation can pay an improperly large amount of fees, and may be unfairly liquidated
Severity: medium

Description:
If a borrower is partially liquidated and then increases the collateral balance to avoid further liquidation, they will pay an improperly large amount of fees and can be unfairly liquidated.\\n```\\n            (collateralBalance, currentFees) = _calculateCollateralBalance(\\n                borrowing.borrowedAmount,\\n                borrowing.accLoanRatePerSeconds,\\n                borrowing.dailyRateCollateralBalance,\\n                accLoanRatePerSeconds\\n            );\\n            // rest of code\\n            if (collateralBalance > 0) {\\n                // rest of code\\n            } else {\\n                currentFees = borrowing.dailyRateCollateralBalance; //entire collateral amount\\n            }\\n            // rest of code\\n            borrowing.feesOwed += _pickUpPlatformFees(borrowing.holdToken, currentFees);\\n```\\n\\nWhen liquidation occurs right after becoming liquidatable, the `collateralBalance` calculation in `repay()` above will be a small value like -1; and essentially all the fees owed will be collected.\\nIf the borrower notices the partial liquidation and wishes to avoid further liquidation, `increaseCollateralBalance()` can be called to become solvent again. But since the `accLoanRatePerSeconds` wasn't updated, the borrower will have to doubly pay all the fees that were just collected. This will happen if a lender calls `harvest()` or the loan is liquidated again. The loan can also be liquidated unfairly, because the `collateralBalance` calculated above will be much lower than it should be.

Impact:
The borrower may pay too many fees, and it's also possible to unfairly liquidate the position.

Recommended mitigation:
Update `accLoanRatePerSeconds` for incomplete emergency liquidations.
Vulnerability: Victim's fund can be stolen due to rounding error and exchange rate manipulation
Severity: high

Description:
Victim's funds can be stolen by malicious users by exploiting the rounding error and through exchange rate manipulation.\\nThe LST Adaptor attempts to guard against the well-known vault inflation attack by reverting the TX when the amount of shares minted is rounded down to zero in Line 78 below.\\n```\\nFile: BaseLSTAdapter.sol\\n    function prefundedDeposit() external nonReentrant returns (uint256, uint256) {\\n        uint256 bufferEthCache = bufferEth; // cache storage reads\\n        uint256 queueEthCache = withdrawalQueueEth; // cache storage reads\\n        uint256 assets = IWETH9(WETH).balanceOf(address(this)) - bufferEthCache; // amount of WETH deposited at this time\\n        uint256 shares = previewDeposit(assets);\\n\\n        if (assets == 0) return (0, 0);\\n        if (shares == 0) revert ZeroShares();\\n```\\n\\nHowever, this control alone is not sufficient to guard against vault inflation attacks.\\nLet's assume the following scenario (ignoring fee for simplicity's sake):\\nThe victim initiates a transaction that deposits 10 ETH as the underlying asset when there are no issued estETH shares.\\nThe attacker observes the victim's transaction and deposits 1 wei of ETH (issuing 1 wei of estETH share) before the victim's transaction. 1 wei of estETH share worth of PT and TY will be minted to the attacker.\\nThen, the attacker executes a transaction to directly transfer 5 stETH to the adaptor. The exchange rate at this point is `1 wei / (5 ETH + 1 wei)`. Note that the `totalAssets` function uses the `balanceOf` function to compute the total underlying assets owned by the adaptor. Thus, this direct transfer will increase the total assets amount.\\nWhen the victim's transaction is executed, the number of estETH shares issued is calculated as 10 ETH * `1 wei / (5 ETH + 1 wei)`, resulting in 1 wei being issued due to round-down.\\nThe attacker will combine the PT + YT obtained earlier to redeem 1 wei of estETH share from the adaptor.\\nThe attacker, holding 50% of the issued estETH shares (indirectly via the PT+YT he owned), receives `(15 ETH + 1 wei) / 2` as the underlying asset.\\nThe attacker seizes 25% of the underlying asset (2.5 ETH) deposited by the victim.\\nThis scenario demonstrates that even when a revert is triggered due to the number of issued estETH share being 0, it does not prevent the attacker from capturing the user's funds through exchange rate manipulation.

Impact:
Loss of assets for the victim.

Recommended mitigation:
Following are some of the measures that could help to prevent such an attack:\\nMint a certain amount of shares to zero address (dead address) during contract deployment (similar to what has been implemented in Uniswap V2)\\nAvoid using the `balanceOf` so that malicious users cannot transfer directly to the contract to increase the assets per share. Track the total assets internally via a variable.
Vulnerability: Anyone can convert someone's unclaimed yield to PT + YT
Severity: medium

Description:
Anyone can convert someone's unclaimed yield to PT + YT, leading to a loss of assets for the victim.\\nAssume that Alice has accumulated 100 Target Tokens in her account's unclaimed yields. She is only interested in holding the Target token (e.g., she is might be long Target token). She intends to collect those Target Tokens sometime later.\\nBob could disrupt Alice's plan by calling `issue` function with the parameter (to=Alice, underlyingAmount=0). The function will convert all 100 Target Tokens stored within Alice's account's unclaimed yield to PT + YT and send them to her, which Alice does not want or need in the first place.\\nLine 196 below will clear Alice's entire unclaimed yield before computing the accrued interest at Line 203. The accrued interest will be used to mint the PT and YT (Refer to Line 217 and Line 224 below).\\n```\\nFile: Tranche.sol\\n    function issue(\\n        address to,\\n        uint256 underlyingAmount\\n    ) external nonReentrant whenNotPaused notExpired returns (uint256 issued) {\\n..SNIP..\\n        lscales[to] = _maxscale;\\n        delete unclaimedYields[to];\\n\\n        uint256 yBal = _yt.balanceOf(to);\\n        // If recipient has unclaimed interest, claim it and then reinvest it to issue more PT and YT.\\n        // Reminder: lscale is the last scale when the YT balance of the user was updated.\\n        if (_lscale != 0) {\\n            accruedInTarget += _computeAccruedInterestInTarget(_maxscale, _lscale, yBal);\\n        }\\n..SNIP..\\n        uint256 sharesUsed = sharesMinted + accruedInTarget;\\n        uint256 fee = sharesUsed.mulDivUp(issuanceFeeBps, MAX_BPS);\\n        issued = (sharesUsed - fee).mulWadDown(_maxscale);\\n\\n        // Accumulate issueance fee in units of target token\\n        issuanceFees += fee;\\n        // Mint PT and YT to user\\n        _mint(to, issued);\\n        _yt.mint(to, issued);\\n```\\n\\nThe market value of the PT + YT might be lower than the market value of the Target Token. In this case, Alice will lose due to Bob's malicious action.\\nAnother `issue` is that when Bob calls `issue` function on behalf of Alice's account, the unclaimed target tokens will be subjected to the issuance fee (See Line 218 above). Thus, even if the market value of PT + YT is exactly the same as that of the Target Token, Alice is still guaranteed to suffer a loss from Bob's malicious action.\\nIf Alice had collected the unclaimed yield via the collect function, she would have received the total value of the yield in the underlying asset terms, as a collection of yield is not subjected to any fee.

Impact:
Loss of assets for the victim.

Recommended mitigation:
Consider not allowing anyone to issue PY+YT on behalf of someone's account.