xanoutas/solidity-security-findings huggingface dataset:
Mint/Burn amount during LP addition/removal changes with time
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L563-L595


# Vulnerability details

## Impact

When a user adds LP to the pool, they get LP tokens which they can later use to redeem their positions. The issue is that since the utility and the curve parameters change with time, so does the value of the LP tokens.

Say a user wants to deposit 1 ETH to the pool. The pool has a curve with certain parameters, where the curve changes over time. If the user deposits 1 ETH in the beginning, they get a certain number of LP tokens. If the user waits and deposits the same 1 ETH later, they can get more LP tokens depending on the change in price.

This leads to users providing LP to lose tokens. In the POC below, we show that a user deposits 1 ETH at the beginning, and the same 1 ETH at the end. We show that if they deposit at the very end, they will get 10x more LP tokens. This means that if the user deposited that 1 ETH early, they can withdraw 1/10th of the funds from the LP.

## Proof of Concept

A simple POC is developed showing the following steps:

1. User deposits 1 ETH and records amount of LP tokens minted to them
2. vm.warp to the end
3. User deposits 1 ETH and records amount of LP tokens minted to them again
4. LP minted in step 3 is much higher than in step 1.

The parameters used for the price is the same as present in the `EvolvingProteusProperties.t.sol` file.

```solidity
function testAttack() public {
    uint256 x0 = 100e18;
    uint256 y0 = 100e18;
    uint256 s0 = 100e18;
    uint256 depositedAmount = 1e18;

    SpecifiedToken depositedToken = SpecifiedToken.X;
    uint256 minted1 = DUT.depositGivenInputAmount(
        x0,
        y0,
        s0,
        depositedAmount,
        depositedToken
    );

    emit log_named_uint("minted1", minted1);

    vm.warp(DUT.tFinal() + 1);

    uint256 minted2 = DUT.depositGivenInputAmount(
        x0,
        y0,
        s0,
        depositedAmount,
        depositedToken
    );

    emit log_named_uint("minted2", minted2);
}
```

The output shows:

```bash
Running 1 test for src/test/EvolvingProteusProperties.t.sol:EvolvingProteusProperties
[PASS] testAttack() (gas: 96394)
Logs:
  minted1: 6801162225772413
  minted2: 245982734610703745
```

This shows user gains more LP depositing later, and thus depositing early loses the user purchasing power. Even though both users deposited 1 ETH, at the time of removal, the later user can claim more tokens from the LP.

## Tools Used

Foundry

## Recommended Mitigation Steps

The LP tokens in the user's wallet must be scaled over time to keep its stake of the pool constant over time. This might done by scaling the LP tokens by the ratio of the current utility to the utility at the time of minting, but would require more testing.


## Assessed type

Math
Error of computation break the LpTokens supply, causes users to lose funds and make functions using `_getUtilityFinalLp()` broken.
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L426-L453
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L463-L490
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/LiquidityPool.sol#L297-L306


# Vulnerability details

## Impact

`withdrawGivenOutputAmount()` and `withdrawGivenInputAmount()` functions doesn't revert when balance of tokenX/tokenY = 0 and create an offset between reserve tokens and LP total supply. This lead to unwanted behaviors for the next operations on the protocol.

## Proof of Concept

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L426-L453

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L463-L490

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/LiquidityPool.sol#L297-L306

The `withdrawGivenOutputAmount()` function is used to retrieve the reserve tokens (liquidity) in exchange of LP tokens, we give an output amount of reserve tokens we want and the function compute an amount of LP tokens that must be burned in order to decrease the total supply.
When we call the `withdrawGivenOutputAmount()` function with a balance of X tokens = 0, the function doesn't revert, give an amout of LP tokens to "burn" and update the LP total supply is made in the `LiquidityPool.sol` contract.


This error of computation could lead, for example, to the following scenario where Alice lose her funds:

1) Alice want to retrieve her liquidity (Tokens X) with her LP, she call `withdrawGivenOutputAmount()` to make the operation.
2) Bob see the transaction of Alice and frontrun it with a swap (in example with `swapGivenInput()` function) to make the xBalance = 0.
3) Bob's transaction is executed first, followed by Alice's.
4) Because `withdrawGivenOutputAmount()` doesn't revert with the xBalance = 0, Alice "burn" her LP Tokens and receive 0 Tokens X.

Alice lose her LP Tokens and therefore her liquidity. And because the LP total supply balance is broken, computations using `_getUtilityFinalLp()` becomes broken.
All the users on the pool are impacted and can't recover all the liquidity they have gived to the pool.

Another scenario, less interesting for the attacker but possible.
The attacker can make a swap to reduce the balance of Tokens X to 0, use `withdrawGivenOutputAmount()` with his LP tokens, he lose his LP Tokens but impact all the users operations.

### PoC :
You can add this test to `EvolvingProteusProperties.t.sol`


		function testBadComputationForBalance0() public {
        //ADD FOR TEST
        address attacker = address(0xaa);
        //Balance of xToken
        uint256 xi = 0;
        //Balance of yToken
        uint256 y
`withdrawGivenInputAmount()` calls `_lpTokenSpecified` with the wrong value of `feeDirection`
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L481


# Vulnerability details

## Impact

`withdrawGivenInputAmount()` calls `_lpTokenSpecified` with the wrong value of `feeDirection`:

```solidity
function withdrawGivenInputAmount(
        uint256 xBalance,
        uint256 yBalance,
        uint256 totalSupply,
        uint256 burnedAmount,
        SpecifiedToken withdrawnToken
    ) external view returns (uint256 withdrawnAmount) {
        // lp amount validations against the current balance
        require(
            burnedAmount < INT_MAX &&
                xBalance < INT_MAX &&
                yBalance < INT_MAX &&
                totalSupply < INT_MAX
        );
  
        int256 result = _lpTokenSpecified(
            withdrawnToken,
            -int256(burnedAmount),
            FEE_DOWN,   
            int256(totalSupply),
            int256(xBalance),
            int256(yBalance)
        );

        // amount cannot be less than 0
        require(result < 0);
        withdrawnAmount = uint256(-result);
    }
```

This will affect the fee application logic and consequently, the final computed amount for withdrawals.

If `FEE_DOWN` is used in the withdrawal context instead of `FEE_UP`, it would apply the fee in the opposite direction than intended. This might give users slightly more tokens upon withdrawal than they should have received or reduce the fee impact.
## Proof of Concept

The purpose of `FEE_UP` and `FEE_DOWN` is to be to adjust the fee direction. From the NatSpec above function, we see:

```solidity
     * @dev We use FEE_UP because we want to increase the perceived amount of
     *  reserve tokens leaving the pool and to increase the observed amount of
     *  LP tokens being burned.
```


If the fee is reduced or not applied as intended, the pool might give out more reserve tokens than it should during a withdrawal. This would impact the reserve balance and possibly the pool's overall "utility" or invariant. Over time and with many withdrawals, this might pose a liquidity risk or a potential imbalance in the pool's reserves.
## Tools Used

Visual Studio Code

## Recommended Mitigation Steps

In `withdrawGivenInputAmount()` function when calling `_lpTokenSpecified()` need to change `FEE_DOWN` with  `FEE_UP`.


## Assessed type

Other
Missing slippage protection in `_swap()`
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L266-L344


# Vulnerability details

## Impact

Without slippage, If the price of the tokens changes significantly during the swap, it could result in a large slippage, causing users to lose a significant amount of funds.
An attacker can watch the mempool and then (using flash bots) execute a sandwich attack to manipulate the price before and after the swap.

## Proof of Concept

The functions `swapGivenInputAmount()` and `swapGivenOutputAmount()` calls function `_swap()` and perform swapping but without any slippage protection.

```solidity
int256 result = _swap(
            FEE_UP,
            -int256(outputAmount),
            int256(xBalance),
            int256(yBalance),
            outputToken
        );
```

In a volatile market, or when dealing with large orders, the price can shift while the transaction is being mined, and the actual amount of tokens added can be less than the desired amount.

## Tools Used

Visual Studio Code

## Recommended Mitigation Steps

Add a parameter (for example `amountOutMin`) to choose how many tokens you would like to get at least or the function to revert.


## Assessed type

MEV
Accounting for Fixed_Fee and Base_Fee twice leading to less amount or token recieved
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L548
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L594
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L641
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L551
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L644


# Vulnerability details

## Impact
There are multiple instances where fees is deducted twice.
I will explain this with one function similar logic follows in other functions as well.So whenever the swapGivenInputAmount function is called by the user with inputAmount provided by the user then inside that function _swap function is called with FEE_DOWN and the input amount then the _swap function calls the _applyFeeByRounding function which reduces the amount of inputAmount and returns roundedSpecifiedAmount which is added to the initial xi(xi is xbalance),after that (xf,yf) is calculated using _findFinalPoint function which calls the _getPointGivenXandUtility function if x is specified input token(for y token similarly other function is called) which gives the final points (xf,yf) after that if specified token is x then the computed amount of y tokens the user will be calculated (i.e outputAmount) by again calling the _applyFeeByRounding function with yf - yi(outputTokens the user should receive ), feeDirection(in this case this is fee_down thus false) this _applyFeeByRounding function again reduces the amount by reducing it by fees. So the issue is here because the fees should only be applied once whereas here it is applied twice resulting in loss for the user who will recieve less tokens as output without even realizing.

Similar issue is with the following functions 1.swapGivenOutputAmount with the same _swap function
2. depositGivenInputAmount function with _reserveTokenSpecified function which reduces the xf value by using _applyFeeByRounding function which in return reduces the final utility thus decreasing the amount of output LP tokens that are being recieved by the user(sf-si) but again the _applyFeeByRounding function is applied thus again applying the fees and reducing the output LP tokens.
3.depositGivenOutputAmount function with _lpTokenSpecified function with similar logic as mentioned in the previous function(2.)
4.withdrawGivenOutputAmount with the _reserveTokenSpecified function
5.withdrawGivenInputAmount with the _lpTokenSpecified function 

## Proof of Concept
I will be explaining this with smaller values similar logic can be applied to the larger values
For swapGivenInputAmount let's assume inputAmount = 10 and xBalance = 100 and yBalance = 100 Specified input token = x
Now it will call
Using incorrect parameter for checking the reserve
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/8ed551004f470489e070c1dd617d67eb4bf114e6/src/proteus/EvolvingProteus.sol#L549; https://github.com/code-423n4/2023-08-shell/blob/8ed551004f470489e070c1dd617d67eb4bf114e6/src/proteus/EvolvingProteus.sol#L552


# Vulnerability details

## Impact
At line 549 within the `_swap()` function's code, the internal call to the function `_checkBalances()` checks the reserve for token `x` is carried out using `xi + specifiedAmount` instead of `xi + roundedSpecifiedAmount`. When using `roundedSpecifiedAmount` passes the check balance, but using `specifiedAmount` may cause the check balance to revert.

## Proof of Concept
The function `_checkBalances()` is employed to verify whether the token reserve in the pool satisfies specific conditions. The reserves of tokens y and x should exceed MIN_BALANCE, and their ratio should also fall within the MIN_M and MAX_M range.
```solidity=809
    function _checkBalances(int256 x, int256 y) private pure {
        if (x < MIN_BALANCE || y < MIN_BALANCE) revert BalanceError(x,y);
        int128 finalBalanceRatio = y.divi(x);
        if (finalBalanceRatio < MIN_M) revert BoundaryError(x,y);
        else if (MAX_M <= finalBalanceRatio) revert BoundaryError(x,y);
    }
```


The variable `specifiedAmount` represents the reserve of tokens the user intends to swap in or out. 

The variable `roundedSpecifiedAmount` represents the quantity of tokens after accounting for fees.

Consequently, this implies that the data from the deduction is not being utilized. As a result, the accuracy of the validation process within the `_checkBalances()` function might be somewhat compromised.

#### Testing

```solidity

    function testCheckBalances() public {
        uint256 x0 = 1_000_000 * 10 ** 18;
        uint256 y0 = 100_000_000 * 10 ** 9;
        uint256 inputAmount = 12959923 * 10 ** 14;
        bool token = true;
        vm.assume(x0 >= MIN_BALANCE);
        vm.assume(y0 >= MIN_BALANCE);
        vm.assume(inputAmount >= MIN_OPERATING_AMOUNT);
        vm.assume(y0/x0 <= MAX_BALANCE_AMOUNT_RATIO);
        vm.assume(x0/y0 <= MAX_BALANCE_AMOUNT_RATIO);
        SpecifiedToken inputToken = token ? SpecifiedToken.X : SpecifiedToken.Y;
        DUT.swapGivenInputAmount(x0, y0, inputAmount, inputToken);
    }
```

```solidity
    function setUp() public {
       py_init_val = 6951000000000000;
       px_init_val = 69510000000000;
       py_final_val = 695100000000000000;
       px_final_val = 69510000000000;

       py_init = ABDKMath64x64.divu(py_init_val, 1e18);
       px_init = ABDKMath64x64.divu(px_init_val, 1e18);
       py_final = ABDKMath64x64.divu(py_final_val, 1e18);
       px_final = ABDKMath64x64.divu(px_final_val, 1e18);

       duration = T_DURATION;
       DUT = new EvolvingInstrumentedProteus(py_init, px_init, py_final, px_final, duration);
    }
```

When using `xi + roundedSpecifiedAmount`:
```solidity

[PASS] testCheckBalances() (gas: 56674)
Traces:
  [56674] Evolv
Vulnerability in swapGivenInputAmount Function that could Leads to Unintended Token Draining
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L296


# Vulnerability details

## Impact

The vulnerability discovered in the swapGivenInputAmount function has the potential to cause unintended token draining in the smart contract. Due to an incorrect check for a negative result in the code (require(result < 0);), the function may allow swaps to succeed even when no tokens are paid. This vulnerability could be exploited by an attacker to drain tokens from the contract without providing the required amount of tokens for the swap

## Exploit Scenario

Consider a scenario where an attacker exploits the vulnerability in the swapGivenInputAmount function. The attacker initiates a swap with input tokens, but deliberately transfers zero tokens to the contract. Due to the incorrect conditional check, the swap succeeds without the attacker actually providing any tokens. As a result, the attacker is able to drain tokens from the contract without proper payment.

## Tools Used
Manual 

## Recommended Mitigation Steps
Replace < with <= in the require(result < 0); 


## Assessed type

Invalid Validation
RESERVE BALANCE BOUNDRY CHECKS IN `_checkBalances` FUNCTION IS ERRORNEOUS DUE TO WRONG INPUT PARAMETERS PASSED IN
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L516-L519
https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L548-L549
https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L551-L552


# Vulnerability details

## Impact

The `EvolvingProteus._swap` function is used to swap one token (Specified token) to another (non-specified token)using the liquidity pool. The protocol charges the `fee` on the swap transactions by calling the `_applyFeeByRounding` function as shown below:

            roundedSpecifiedAmount = _applyFeeByRounding( //@audit-info - return the final amount after accounting for fees via rounding in the direction favorable to the pool
                specifiedAmount,
                feeDirection
            );

The returned value `roundedSpecifiedAmount` is used to calculate the known token final balance of the specified token as shown below (If X token is the specified token):

                int256 fixedPoint = xi + roundedSpecifiedAmount; 

The `fixedPoint` is passed into the `_findFinalPoint` function to get the final point on the bonding curve for the swap transaction.

The resulting `non-specified token amount` is again rounded by calling the `_applyFeeByRounding` function and charges the fee on it as shown below (If X token is the specified token):

            computedAmount = _applyFeeByRounding(yf - yi, feeDirection)

Then the `_checkBalances` function is called to verify the reserve balances and their respective ratios are within the valid boundaries as shown below:

            _checkBalances(xi + specifiedAmount, yi + computedAmount)

The issue lies in the above line of code. Because here the `y (non-specified token final balance amount)` amount passed in to the `_checkBalances` function, is calculated by adding the rounded value amount (`computedAmount`) to the `yi`. But the `x` value passed in uses the original passed in `specifiedAmount` to add to the `xi` value. But this value is not accounted for the `fee` amount charged by the protocol. The actual amount which is added to the pool and which is used in the bonding curve calculations is the rounded value `roundedSpecifiedAmount`.

Due to this the `_checkBalances` function is called with erroneous values. Hence the checks performed inside the `_checkBalances` function to validate the boundaries of the reserve balances will give erroneous results. 

For example if the `feeDirection == FEE_DOWN` then the `specifiedAmount > roundedSpecifiedAmount`. Hence the calculated `xi + specifiedAmount` will be greater than the `xi + roundedSpecifiedAmount`. Hence in the `_checkBalances` function the above vulnerability could break the minimum reserve balance check and the final balance ratio check (shown below) due to erroneous `x value` passed in (In the mentioned scenario the passed in x value is more than the correct x value that should have been passed in).
Missing balance checks in `_reserveTokenSpecified()`
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L563


# Vulnerability details

### Impact
By calling `depositGivenInputAmount()` and `withdrawGivenOutputAmount()` (which both call '_reserveTokenSpecified()'), users may potentially create scenarios where the balance ratio allowed for the `EvolvedProtocol.sol` deployment is violated.

### POC
`depositGivenInputAmount()` and `withdrawGivenOutputAmount()` return the amount of LP tokens minted/burned given a deposit/withdrawal of some reserve tokens. They both rely on the internal function `_reserveTokenSpecified()` for this calculation. In contrast, the other deposit and withdrawal functions rely on the internal function`_lpTokenSatisfied()`.

Within `_lpTokenSatisfied()`, there is a check `_checkBalances()` after the deposit/withdraw that ensures that the supplies of token `x` and token `y` reserve tokens are above minimum amounts and also satisfy a balance ratio. 

This check is missing completely within the main bodies of `depositGivenInputAmount()` and `withdrawGivenOutputAmount()` as well as `_reserveTokenSpecified()`, hence it is possible to create a scenario where the final result after a deposit/withdrawal does not satisfy the balance ratio, yet the deposit/withdrawal does not revert.

We have created a runnable test to demonstrate the POC, however, it requires some minor changes to the code body, detailed below:

#### Preconditions

To run the POC, the following things should be done:

1) Within `EvolvingProteus.sol`, add the following two functions. These two functions are a nearly identical copy of the `withdrawGivenOutputAmount()` and `_reserveTokenSatisifed()` function, with the only difference being a toggleable `_checkBalances(xi + specifiedAmount, yf)` function call to demonstrate the impact of the bug. The reasoning for the parameters of the function call being `xi + specifiedAmount` instead of `xf` is to keep the withdraw consistant with the `_swap()` function in favoring the pool during fee rounding. 
```=solidity
function withdrawGivenOutputAmountWithChecks(
        uint256 xBalance,
        uint256 yBalance,
        uint256 totalSupply,
        uint256 withdrawnAmount,
        SpecifiedToken withdrawnToken,
        bool checksOn //@audit toggleable bool
    ) external view returns (uint256 burnedAmount) {
        // withdraw amount validations against the current balance
        require(
            withdrawnAmount < INT_MAX &&
                xBalance < INT_MAX &&
                yBalance < INT_MAX &&
                totalSupply < INT_MAX
        );
        int256 result = _reserveTokenSpecifiedWithChecks(
            withdrawnToken,
            -int256(withdrawnAmount),
            FEE_UP,
            int256(totalSupply),
            int256(xBalance),
            int256(yBalance),
            checksOn //@audit toggleable bool
        );
        // amount cannot be less than 0
        req