xanoutas/solidity-security-findings huggingface dataset:
Malicious user can drain the Singularity contract of it's liquidity
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCollateral.sol#L21
https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCollateral.sol#L35


# Vulnerability details

## Impact

The [SGLCollateral contract](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCollateral.sol#L8) has functionality to allow users to [remove](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCollateral.sol#L35) and [add](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCollateral.sol#L21) collateral for the Singularity market. The addCollateral function accepts a [`skim`](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCollateral.sol#L24) parameter that, if defined as true, will cause the internal _addTokens function to [assert](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCommon.sol#L187-L190) that the contract has a large enough balance for the respective token that has not been already allocated, otherwise, tokens will be [transferred](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCommon.sol#L192) from the user. An important note with this functionality, is that the contract's un-allocated funds for a respective token is calculated by subtracting the [sum](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLLendingCommon.sol#L28) of the market's total collateral shares plus the specified share amount from the [contract's yeildbox balance](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCommon.sol#L188C26-L188C69). Because the removeCollateral function accepts a [to](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLCollateral.sol#L37) parameter that defines to which address the collateral should be [transferred](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLLendingCommon.sol#L49), a malicious user can double their collateral by invoking the removeCollateral function with the `to` parameter specified as the respective Singularity contract's address which will then [subtract](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLLendingCommon.sol#L
The amount of debt removed during `liquidation` may be worth more than the account's collateral
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L822


# Vulnerability details

### Impact
The contract decreases user's debts but may not take the full worth in collateral from the user, leading to the contract losing potential funds from the missing collateral.

### Proof of concept
During the `liquidate()` function call, the function `_updateBorrowAndCollateralShare()` is eventually invoked. This function liquidates a user's debt and collateral based on the value of the __collateral__ they own. 

In particular, the equivalent amount of debt, `availableBorrowPart` is calculated from the user's collateral on line 225 through the `computeClosingFactor()` function call.

Then, an additional fee through the `liquidationBonusAmount` is applied to the debt, which is then compared to the user's debt on line 240. The minimum of the two is assigned `borrowPart`, which intuitively means the maximum amount of debt that can be removed from the user's debt.

`borrowPart` is then increased by a bonus through `liquidationMultiplier`, and then converted to generate `collateralShare`, which represents the amount of collateral equivalent in value to `borrowPart` (plus some fees and bonus).

This new `collateralShare` may be more than the collateral that the user owns. In that case, the `collateralShare` is simply decreased to the user's collateral.

`collateralShare` is then removed from the user's collateral.

The problem lies in that although the `collateralShare` is equivalent to the `borrowPart`, or the debt removed from the user's account, it could be worth more than the collateral that the user owns in the first place. Hence, the contract loses out on funds, as debt is removed for less than it is actually worth.

To demonstrate, we provide a runnable POC.

#### Preconditions
```solidity
... 
if (collateralShare > userCollateralShare[user]) {
        require(false, "collateralShare and borrowPart not worth the same"); //@audit add this line
        collateralShare = userCollateralShare[user];
    }
    userCollateralShare[user] -= collateralShare;
...
```
Add the `require` statement to line [261](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLLiquidation.sol#L261). This require statement essentially reverts the contract when the `if` condition satisfies. The `if` condition holds true when the `collateralShare` is greater that the user's collateral, which is the target bug.

Once the changes have been made, add the following test into the `singularity.test.ts` test in `tapioca-bar-audit/test`

#### Code


```typescript=
it('POC', async () => {
            const {
                usdc,
                wbtc,
                yieldBox,
                wbtcDepositAndAddAsset,
                usdcDepositAndAddCollateralWbtcSingularity,
                eoa1,
                approveToke
rate is wrong
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-sdk-audit/blob/90d1e8a16ebe278e86720bc9b69596f74320e749/src/contracts/YieldBox/contracts/YieldBox.sol#L130
https://github.com/Tapioca-DAO/tapioca-yieldbox-strategies-audit/blob/05ba7108a83c66dada98bc5bc75cf18004f2a49b/contracts/lido/LidoEthStrategy.sol#L118


# Vulnerability details

## Impact
attacker can manipulate pool price to make strategy have eth lower as it should have (1 seth < 1 eth) then mint new steth (1 steth = 1 eth) so attacker can gain share more than normal
## Proof of Concept
1. attacker manipulate pool price (1 seth < 1 eth)
2. attacker deposit fund to strategy to gain share at the manipulated rate 
3. the attacker restores the pool price back to its normal value.
4. attacker withdraws the funds from the strategy, effectively profiting from the higher share value acquired during the manipulation.

## Recommended Mitigation Steps
- using oracle price


## Assessed type

Oracle
LiquidationQueue brings centralization risk in the contract. 
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/Singularity.sol#L583
https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/Singularity.sol#L588
https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/Singularity.sol#L593


# Vulnerability details

## Impact
the owner  has too much unilateral control over liquidations and can manipulate te country in the following ways:
- The owner of LiquidationQueue sees a profitable liquidation opportunity
- Before anyone else can liquidate, they use LiquidationQueue to place a bid and liquidate the position
- They earn the liquidation bonus and profit from the arbitrage
- They repeat this to systematically front-run and profit from liquidations


## Proof of Concept
The owner has full control to set the LiquidationQueue address. This gives them power over a critical part of the liquidation workflow.There is no timelock or checks on the LiquidationQueue contract. The owner could set a malicious contract without waiting period.The LiquidationQueue likely has special privileges and access to make critical state changes during liquidation. A malicious LQ could exploit its powers.


## Tools Used 
Manual

## Recommended Mitigation Steps 
- Make LiquidationQueue a transparent on-chain system that is decentralized and not controlled by any single party
- Remove the ability for LiquidationQueue to earn liquidation bonuses or limit the amount it can earn



## Assessed type

Other
There is no decrease for the share allowance from _addCollateral when share passed zero
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L543-L558


# Vulnerability details

## Impact
When calling `_addCollateral`, and if the share passed as zero, it is calculated based on the passed amount. However, this happens after `allowanceBorrow` was already called in `addCollateral`. So, deduction never occur for the share.  Eventually, the borrow allowance never decreases. This allows a user (who has borrow allowance) to call addCollateral without borrow allowance limit set by the owner.

## Proof of Concept

No deduction for the share allowance from _addCollateral() for `from` address:
```
    function _addCollateral(
        address from,
        address to,
        bool skim,
        uint256 amount,
        uint256 share
    ) internal {
        if (share == 0) {
            share = yieldBox.toShare(collateralId, amount, false);
        }
        userCollateralShare[to] += share;
        uint256 oldTotalCollateralShare = totalCollateralShare;
        totalCollateralShare = oldTotalCollateralShare + share;
        _addTokens(from, collateralId, share, oldTotalCollateralShare, skim);
        emit LogAddCollateral(skim ? address(yieldBox) : from, to, share);
    }
```
[Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L543-L558)

The `share` is calculated here:
```
        if (share == 0) {
            share = yieldBox.toShare(collateralId, amount, false);
        }
        userCollateralShare[to] += share;
```

but there is no decrease for the share from `allowanceBorrow` map afterwards (incase the amount > 0 and the share is 0).  
We know it is already done in `allowedBorrow` modifier in `_allowedBorrow()` method but since the share was passed zero, it had no effect.
```
 allowanceBorrow[from][msg.sender] -= share;
```
[Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/MarketERC20.sol#L89)


## Tools Used
Manual Review


## Recommended Mitigation Steps
decrease the allowanceBorrow for the share after being calucalted in _addCollateral() method in case the share passed is zero.
```
//add this line in _addCollateral() after share being calculated only if share was passed zero.
 allowanceBorrow[from][msg.sender] -= share;
```


## Assessed type

Other
Cross-chain replay attacks are possible
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/master/contracts/markets/MarketERC20.sol#L251-L284


# Vulnerability details

## Impact

In `MarketERC20.sol` we have `_permit()` function:
```solidity
function _permit( /
        bool asset, // 1 = asset, 0 = collateral
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        require(block.timestamp <= deadline, "ERC20Permit: expired deadline");

        bytes32 structHash = keccak256(
            abi.encode(
                asset ? _PERMIT_TYPEHASH : _PERMIT_TYPEHASH_BORROW,
                owner,
                spender,
                value,
                _useNonce(owner),
                deadline
            )
        );

        bytes32 hash = _hashTypedDataV4(structHash);

        address signer = ECDSA.recover(hash, v, r, s);
        require(signer == owner, "ERC20Permit: invalid signature");

        if (asset) {
            _approve(owner, spender, value);
        } else {
            _approveBorrow(owner, spender, value);
        }
    }
```

In this function, the signed data doesn't include the `chainId` and because of this cross-chain replay attacks are possible.
## Proof of Concept

According to [EIP4337](https://eips.ethereum.org/EIPS/eip-4337) standard to prevent replay attacks the signature should depend on `chainId`. But in these functions, `chainId` is not used. 
A valid signature that was used on one chain could be copied by an attacker and propagated onto another chain.
## Tools Used

Manual review
## Recommended Mitigation Steps

Add `chainId`  `_permit()` function `structHash`.

```solidity
bytes32 structHash = keccak256(
            abi.encode(
                asset ? _PERMIT_TYPEHASH : _PERMIT_TYPEHASH_BORROW,
                owner,
                spender,
                value,
                _useNonce(owner),
                deadline,
                block.chainId
            )
        );
```


## Assessed type

Other
addCollateral allows anyone to addCollateral on behalf of others
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L282-L290


# Vulnerability details

## Impact
addCollateral allows anyone to addCollateral on behalf of others. In other words, bypassing the borrow allowance check.

## Proof of Concept

`allowedBorrow` modifier will not revert if passed share == 0. `addCollateral()` method uses `allowedBorrow` modifier  
```
        function addCollateral(
        address from,
        address to,
        bool skim,
        uint256 amount,
        uint256 share
    ) public allowedBorrow(from, share) notPaused {
        _addCollateral(from, to, skim, amount, share);
    }
```
[Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L282-L290)

Now let's have a look at the modifier. It basically calls `_allowedBorrow()`
```
    modifier allowedBorrow(address from, uint share) virtual {
        _allowedBorrow(from, share);
        _;
    }
```


The method `_allowedBorrow()` is aware only of the share and not aware of the amount passed. If the share was passed as zero, then it bypass the modifier.

```
    function _allowedBorrow(address from, uint share) internal {
        if (from != msg.sender) {
            if (allowanceBorrow[from][msg.sender] < share) {
                revert NotApproved(from, msg.sender);
            }
            allowanceBorrow[from][msg.sender] -= share;
        }
    }
```
 [Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/MarketERC20.sol#L84-L91)


Then in `_addCollateral()` , share is calculated (since it was passed zero) based on the amount 
```
	if (share == 0) {
		share = yieldBox.toShare(collateralId, amount, false);
	}
```
[Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L550-L552)

This calculation happen afte bypassing the modifier. Which means anyone can bypass the allowance validation for anyone.

## Tools Used
Manual Review

## Recommended Mitigation Steps

Use _allowedBorrow method instead of the modifier. Call the method after the share calculation.






## Assessed type

Other
protocol fee amount is burned on _repay() BigBang market
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L726-L735


# Vulnerability details

## Impact
Protocol fee amount is burned in `BigBang._repay()` . Fee amount shouldn't be burned as it is supposed to be collected by Penrose (owner of BigBang) along with other fees. This leads to loss of all fees charged for all borrows.

## Proof of Concept

#### Explanation:
`_borrow()`  calculates the fee amount + borrowed amount, adds it to userBorrowPart but on `_repay()` a burn is done for both (fee amount + borrowed amount). Therefore, not keeping the fee amount out of the burn call. 

In `_borrow()` , both borrowed amount + feeAmount are stored in userBorrowPart 
```solidity
        uint256 feeAmount = (amount * borrowOpeningFee) / FEE_PRECISION; // A flat % fee is charged for any borrow


        (totalBorrow, part) = totalBorrow.add(amount + feeAmount, true);
        require(
            totalBorrowCap == 0 || totalBorrow.elastic <= totalBorrowCap,
            "BigBang: borrow cap reached"
        );


        userBorrowPart[from] += part;
```
 [Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L747-L755)

However,  `_repay()` method doesn't exclude the fee amount. So it gets burned.
```solidity
        (totalBorrow, amount) = totalBorrow.sub(part, true);


        userBorrowPart[to] -= part;


        uint256 toWithdraw = (amount - part); //acrrued
        uint256 toBurn = amount - toWithdraw;
        yieldBox.withdraw(assetId, from, address(this), amount, 0);
        //burn USDO
        if (toBurn > 0) {
            IUSDOBase(address(asset)).burn(address(this), toBurn);
```
 [Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L726-L735)


#### Coded PoC:

- When you run the PoC below, you will get the following results:
```sh
[PASS] test_borrow_repay() (gas: 87829)
Logs:
  ===BORROW 1e18===
  borrowedAmount: 1000000000000000000
  borrowedPart: 1000500000000000000
  ===REPAY AMOUNT WITH FEE 1e18+1e15===
  borrowedPartAfter: 0
  paidAmount: 1000500000000000000
  burnedAsset: 1000500000000000000
  ===RESULT===
  burnedAsset equals paidAmount
  Since paidAmount had the fee, fee amount was burned with it

Test result: ok. 1 passed; 0 failed; finished in 1.24ms
```


- Code
```solidity
// PoC => BIGBANG = fee amounts are burned
// Command => forge test -vv
pragma solidity >=0.8.4 <0.9.0;

import {Test} from "forge-std/Test.sol";
import "forge-std/console.sol";

import {DSTest} from "ds-test/test.sol";

struct Rebase {
    uint128 elastic;
    uint128 base;
}

/// @notice A rebasing library using overflow-/underflow-safe math.
library RebaseLibrary {
    /// @notice Calculates the base value in relationship to `elastic` and `total`.
    function toBase(
        Rebase memory
Read-Only Reentrancy
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-yieldbox-strategies-audit/blob/05ba7108a83c66dada98bc5bc75cf18004f2a49b/contracts/lido/LidoEthStrategy.sol#L121


# Vulnerability details

## Impact
curve eth-steth pool can be manipulated by Read-Only Reentrancy


## Proof of Concept
https://chainsecurity.com/curve-lp-oracle-manipulation-post-mortem/

## Recommended Mitigation Steps
- using oracle price 


## Assessed type

Reentrancy
borrowPart is not denormalized before deducting it from userBorrowPart on liquidation
Audit: 2023-07-tapioca-findings
Severity: HIGH

# Lines of code

https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L805


# Vulnerability details

## Impact
In BigBang, `_updateBorrowAndCollateralShare` is used to deduct values from `userBorrowPart` and `userCollateralShare` on Liquidation. This is the flow:
 `liquidate` => `_closedLiquidation` => `_liquidateUser` => `_updateBorrowAndCollateralShare`
 
Now `_updateBorrowAndCollateralShare` method **picks the minimum between maxBorrowPart and availableBorrowPart**
```solidity
	borrowPart = maxBorrowPart > availableBorrowPart
		? availableBorrowPart
		: maxBorrowPart;
```
[Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L797-L799)

Let's assume it picked availableBorrowPart. The issue is that **borrowPart is not denormalized before deducting it from userBorrowPart** of the user. borrowPart should be denormalized to borrowAssetDecimals because the returned value by `computeClosingFactor` is normalized to 18 decimals.
```
	.
	.
	userBorrowPart[user] = userBorrowPart[user] - borrowPart;
```
[Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L805)

This leads to wrong deduction from userBorrowPart. Which could possibly be in favour of the user or the protocol. However, it is unfair for the other party (user,  protocol, or even other borrowers). It causes wrong accountings across the protocol (e.g. interests don't reflect the real interests ...etc). 


## Proof of Concept

- `computeClosingFactor` method where **normalization to 18 decimals** occurs
```
	function computeClosingFactor(
		uint256 borrowPart,
		uint256 collateralPartInAsset,
		uint256 borrowPartDecimals,
		uint256 collateralPartDecimals,
		uint256 ratesPrecision
	) public view returns (uint256) {
		uint256 borrowPartScaled = borrowPart;
		if (borrowPartDecimals > 18) {
			borrowPartScaled = borrowPart / (10 ** (borrowPartDecimals - 18));
		}
		if (borrowPartDecimals < 18) {
			borrowPartScaled = borrowPart * (10 ** (18 - borrowPartDecimals));
		}
```
[Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/Market.sol#L256-L269)

- `_updateBorrowAndCollateralShare` method where **there is no denormalization** before deduction
```solidity
	.
	.
	uint256 availableBorrowPart = computeClosingFactor(
		userBorrowPart[user],
		collateralPartInAsset,
		borrowAssetDecimals,
		collateralDecimals,
		FEE_PRECISION_DECIMALS
	);
	borrowPart = maxBorrowPart > availableBorrowPart
		? availableBorrowPart
		: maxBorrowPart;

	if (borrowPart > userBorrowPart[user]) {
		borrowPart = userBorrowPart[user];
	}

	userBorrowPart[user] = userBorrowPart[user] - borrowPart;
	.
	.
```
[Code link](https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba