xanoutas/solidity-security-findings huggingface dataset:
KEY INVARIANT RELATED TO THE `FIXED_FEE` AMOUNT CAN BE BROKEN
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

The `EvolvingProteus._applyFeeByRounding` function is used to charge fees by rounding values in directions that are beneficial to the pool. Within this function there is a `if` condition which verifies that the calculated final amount is not less than the `FIXED_FEE` amount as shown below:

    if (absoluteValue < FIXED_FEE * 2) revert AmountError();

But this conditional check alone is not enough to verify that the final amount is not less than teh `FIXED_FEE` amount.

Please consider the following scenario:

1. When the `feeUp == false` the final amount (`roundedAbsoluteAmount`) is calculated as follows:

        roundedAbsoluteAmount =
            absoluteValue -
            (absoluteValue / BASE_FEE) -
            FIXED_FEE;

2. There could be a scenario where `absoluteValue = FIXED_FEE * 2`. If this is the case then the above `if` statement will not revert (It will only revert if absoluteValue < FIXED_FEE * 2).

3. Assume `feeUp == false` hence the `roundedAbsoluteAmount` will be calculated as follows:

        roundedAbsoluteAmount =
            absoluteValue -
            (absoluteValue / BASE_FEE) -
            FIXED_FEE;

4. Now `absoluteValue = FIXED_FEE * 2` hence above equation can be modified as follows:

        roundedAbsoluteAmount =
            FIXED_FEE * 2 -
            (absoluteValue / BASE_FEE) -
            FIXED_FEE;

5. Simplified equation will look as follows:

        roundedAbsoluteAmount =
            FIXED_FEE -
            (absoluteValue / BASE_FEE);

Hence it is clear that the final amount (`roundedAbsoluteAmount`) is less than the `FIXED_FEE` value which the protocol wanted to stop from happening. If this condition is considered as an invariant then the invariant is broken.

## Proof of Concept

Make the `EvolvingProteus._applyFeeByRounding` a public function for the purpose of testing and add the following testcase to the `EvolvingProteusProperties.t.sol` test file.

```solidity
 function testApplyFeeByRounding() public {

    int256 inputAmount = FIXED_FEE * 2;
    int256 returnedValue = DUT._applyFeeByRounding(inputAmount, false);

    assertLt(uint256(returnedValue), uint256(FIXED_FEE));
}
```
Above test shows that the `returnedValue < FIXED_FEE` which breaks the invariant of this function which states that the `final amount should not be less than the FIXED_FEE`.

Following are the areas of the code affected.

```solidity
    // FIXED_FEE * 2 because we will possibly deduct the FIXED_FEE from
    // this amount, and we don't want the final amount to be less than
    // the FIXED_FEE.
    if (absoluteValue < FIXED_FEE * 2) revert AmountError();
```

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

```solidity
    } else
Lack of  balance checks in the `depositGivenInputAmount` function
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Lack of balance checks in the `depositGivenInputAmount` function can lead to various unpredictable consequences due to the breach of requirement "The pool's ratio of y to x must be within the interval [MIN_M, MAX_M)".

## Proof of Concept
The [`depositGivenInputAmount`](https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L353-L380) receive an `depositedAmount` parameter which describes how many reserve tokens the user wants to deposit. There are no balance checks in the `depositGivenInputAmount` function and in the [`_reserveTokenSpecified`](https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L563-L595) function, similar with [checks](https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L546-L552) in the `_swap` function. So users can deposit such an amount of tokens which breach the pool's ratio.

## Tools Used
Manual review

## Recommended Mitigation Steps
I suggest using the `_checkBalances` function at the `depositGivenInputAmount` function or at the `_reserveTokenSpecified` function.



## Assessed type

Other
Max Price Ratio Manipulation
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

Vulnerable Part in Code: 

```solidity
py_init.div(py_init.sub(px_init)) > ABDKMath64x64.divu(uint(MAX_PRICE_RATIO), 1)
```

- here is A scenario where the  range of acceptable price ratios is between 1 and 100 (
for instance, due to a misconfiguration or oversight, the constant MAX_PRICE_RATIO is set to a ridiculously high value of 10^10.
Now, 
let's say an attacker submits input values such that the calculated price ratio using the provided formula is slightly below the abnormally high value of MAX_PRICE_RATIO. For instance, imagine the following values:

```solidity
py_init (initial y-axis price) = 10^12 (1 trillion)
px_init (initial x-axis price) = 1
```

The calculation ratio is 1 

```solidity
price_ratio = 10^12 / (10^12 - 1) ≈ 1 (approximately)
```

MAX_PRICE_RATIO is set to 10^10 (10 billion), the condition for the vulnerability is met:

```solidity
1 > 10^10 (condition is true)
```

This show the vulnerability triggers, and the system accepts this price ratio as valid, even though it's vastly different from what's expected and reasonable within the context of the application.

With this manipulation, an attacker can:

- Bypass intended bounds checks.
- Trick the system into processing transactions based on anomalous price ratios.
- manipulate the outcome of calculations, leading to financial gain for the attacker and loss for other users. 

## Proof of Concept

Scenario:
Imagine an Automated Market Maker as AMM protocol that uses the code you provided, including the MAX_PRICE_RATIO value set to an unexpectedly high value. This protocol allows users to swap between two tokens, X and Y, based on their price ratio. The legitimate and reasonable price ratio range for this scenario is 1 to 100.

Exploitation Steps:

Attacker examines the smart contract code and discovers the MAX_PRICE_RATIO vulnerability.
Attacker prepares a transaction to exploit the vulnerability.

Let's assume the following values:

```solidity
MAX_PRICE_RATIO = 10^10
py_init (initial y-axis price) = 1000 (1,000 units of token Y)
px_init (initial x-axis price) = 10 (10 units of token X)
```

The attacker calculates the expected price ratio:

```solidity
expected_price_ratio = 1000 / (1000 - 10) = 1.010101...
```

Since expected_price_ratio is significantly lower than MAX_PRICE_RATIO, the attacker knows that a transaction involving this price ratio should be accepted, even though it's not reasonable.

The attacker crafts a swap transaction with the following parameters:

```solidity
Input amount: 1000 units of token X
Output amount: 990 units of token Y based on the expected price ratio
```

The attacker submits the transaction, and the system processes it successfully. The smart contract doesn't reject the transaction due to the vulnerability.

## Tools Used
- Manual review 
## Recommended Mit
Lack of  balance checks in the `withdrawGivenOutputAmount` function
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-L448


# Vulnerability details

## Impact
Lack of balance checks in the `withdrawGivenOutputAmount` function can lead to various unpredictable consequences due to the breach of requirements "The pool's balances of the x reserve and y reserve tokens must be greater than the MIN_BALANCE" and "The pool's ratio of y to x must be within the interval [MIN_M, MAX_M)".

## Proof of Concept
The [`withdrawGivenOutputAmount`](https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L426-L453) receive an `withdrawnAmount` parameter which describes how many reserve tokens the user wants to withdraw. There are no balance checks in the `withdrawGivenOutputAmount` function and in the [`_reserveTokenSpecified`](https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L563-L595) function, similar with [checks](https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L546-L552) in the `_swap` function. So users can withdraw more tokens than is safety for the contract.

## Tools Used
Manual review

## Recommended Mitigation Steps
I suggest using the `_checkBalances` function at the `withdrawGivenOutputAmount` function or at the `_reserveTokenSpecified` function.


## Assessed type

Other
_reserveTokenSpecified does not check if price is in allowed range
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
- Price could go out of range


## Proof of Concept
EvolvingProteus defines a price range using 2 constants, `MAX_M` and `MIN_M`:
```solidity
int128 constant MAX_M = 0x5f5e1000000000000000000;
int128 constant MIN_M = 0x00000000000002af31dc461;
```
These constants are used in `_checkBalances` to make sure the ratio of x reserve
and y reserve tokens must be within [MIN_M, MAX_M):
```solidity
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);
}
```

However, function `_reserveTokenSpecified` does not call this function to verify the ratio, `_reserveTokenSpecified` is used in `depositGivenInputAmount` and `withdrawGivenOutputAmount`. So if a user deposit or withdraw tokens using these functions, the ratio could go out of bound.

Below is a POC for this issue, place this in file `test/EvolvingProteusProperties.t.sol` under contract `EvolvingProteusProperties` and run it using command:
`forge test --match-path src/test/EvolvingProteusProperties.t.sol --match-test test_deposit_push_price_over_limit -vvvv`

```solidity
    function test_deposit_push_price_over_limit() public {

        uint256 max_price = 0x5f5e1000000000000000000/2**64;
        uint256 yBalance = 1e15;
        uint256 xBalance = 1e15;
        uint256 totalSupply = 1e15;
        uint256 specifiedAmount = 1e30;

        uint256 mintedAmount = DUT.depositGivenInputAmount(
            yBalance,
            xBalance,
            totalSupply,
            specifiedAmount,
            SpecifiedToken.X
        );
        uint256 price = (xBalance + specifiedAmount)/(yBalance);
        assertGt(price, max_price);


    }
```
In the above POC, a really large X token is deposited and the price is greater than maximum. 
## Tools Used
Manual Review

## Recommended Mitigation Steps
I recommend calling `_checkBalances` in function `_reserveTokenSpecified` to make sure the price is within [MIN_M, MAX_M) as specified.



## Assessed type

Invalid Validation
Malicious user can drain the reserve during swaping and withdrawal
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#L551
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L506-L554
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L288-L303
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L299-L303
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L452


# Vulnerability details

## Impact
A malicious user can drain pool reserves by calling the ```swapGivenInputAmount(...)``` function during swapping and also during withdrawal by calling ```withdrawGivenOutputAmount(...)``` and ```withdrawGivenInputAmount(...)``` during withdrawal leading to a loss of funds.

## Proof of Concept

during swapping, the ```swapGivenInputAmount(...)``` function makes a call to ```_swap(...)``` which in turn makes a call to ```_applyFeeByRounding(...)```

```
    function _swap(
        bool feeDirection,
        int256 specifiedAmount,
        int256 xi,
        int256 yi,
        SpecifiedToken specifiedToken
    ) internal view returns (int256 computedAmount) {
        ...
        
        if (specifiedToken == SpecifiedToken.X) {
            computedAmount = _applyFeeByRounding(yf - yi, feeDirection);
            ...
        } else {
            computedAmount = _applyFeeByRounding(xf - xi, feeDirection);
            ...
        }
    }
```

although for swaps, if ```SpecifiedToken``` is X, then ```yf - yi``` is negative (vice versa)  and ```_applyFeeByRounding(...)``` handles that correctly and returns a positive swap output amount that is cached in ```result ``` which is a signed integer

```
    function _applyFeeByRounding(int256 amount, bool feeUp)
        private
        pure
        returns (int256 roundedAmount)
    {
        bool negative = amount < 0 ? true : false;
        ...

        roundedAmount = negative
            ? -int256(roundedAbsoluteAmount)
            : int256(roundedAbsoluteAmount);
    }
```
However, the ```swapGivenInputAmount(...)``` checks that the ```result``` is less than zero before proceeding to calculate the ```outputAmount``` which also is evaluated by first casting and then negating the value of result. this can lead an amount lower than the actual ```outputAmount```.  

The same vulnerability described above is present in the ```withdrawGivenOutputAmount(...)``` function as shown below
```
    function withdrawGivenOutputAmount(
        uint256 xBalance,
        uint256 yBalance,
        uint256 totalSupply,
        uint256 withdrawnAmount,
        SpecifiedToken withdrawnToken
    ) external vie
Attacker can profitable trade with the pool
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The swap invariant used is unstable with large pool reserves locked. An attacker can generate a profit by trading with the pool, hurting Liquidity Providers.

## Proof of Concept
To find some vulernable configurations we fuzzed the `_swap` function of the Proteus Contract. We defined a profitable strategy when a user can 

1. Trade some amount x of Token A for y of Token B
2. Trade y of Token B for MORE than x of token A.

We specified the input in both swaps. We can define equivalent strategies that define the output amount or start trading with token B.
We restricted the available values to *economic reasonable* attack vectors with up to 10 Billion of reserves.

The fuzz test used for finding unsafe configurations can be found here:

```
function test_FuzzSwap(int256 xBalance, int256 yBalance, int256 inputAmount) public {
    // default values
    proteus = new EvolvingInstrumentedProteus(
    ABDKMath64x64.divu(695000000000000, 1e18),
    ABDKMath64x64.divu(692930500000000, 1e18),
    ABDKMath64x64.divu(695000000000000, 1e18),
    ABDKMath64x64.divu(692930500000000, 1e18),
    3 days
    );

    // input validation
    inputAmount = bound(inputAmount, -1_000_000_000 * 10e18, 1_000_000_000 * 10e18);
    xBalance = bound(xBalance, MIN_BALANCE, int256(10_000_000_000 * 1e18)); // int256(MAX_64x64)
    yBalance = bound(yBalance, MIN_BALANCE, int256(10_000_000_000 * 1e18)); // int256(MAX_64x64)
    inputAmount = bound(inputAmount, 0, xBalance / int256(MAX_BALANCE_AMOUNT_RATIO));
    inputAmount = bound(inputAmount, 1e17, type(int256).max);

    // Case 1: Swap inputAmount of Token X for outputAmount of Token Y.
    //         Then trade outputAmount of Token Y for reverseInput of Token X.
    // Case 2-4: Trade with Token Y, Output Swap are can be defined equivalently
    try proteus.swap(false, inputAmount, xBalance, yBalance, SpecifiedToken.X) returns (int256 outputAmount) {
        if (outputAmount > 0) {
            try proteus.swap(false, outputAmount, xBalance + inputAmount, yBalance - outputAmount, SpecifiedToken.Y)
            returns (int256 reverseInput) {
                if (reverseInput >= inputAmount) { // ignore economic "insignificant" profits
                    require(reverseInput - inputAmount <= 1e17, "swap");
                    console.log("Found a profitable swap!");
                    console.log("int256 inputAmount = %s;", uint256(inputAmount));
                    console.log("int256 xBalance = %s;", uint256(xBalance));
                    console.log("int256 yBalance = %s;", uint256(yBalance));
                }   
            } catch {}
        }
    } catch {}
}
```

One example unsafe configuration we found can be seen below. Here the user bought
their tokens for a price of 5'500 and could then sell them for 18'888:


```solidity
functi
overflow vulnerability in the _lpTokenSpecified() function when calculating computedAmount
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
uf will be incorrect, which will lead to incorrect final price points xf, yf and ultimately an incorrect computedAmount. It also allows an attacker to manipulate the pool in their favor by depositing or withdrawing more assets than they should be able to.

## Proof of Concept
The key issue is this line:https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L616-L621

If si + _applyFeeByRounding(specifiedAmount, feeDirection) overflows, then uf will be calculated incorrectly.

This could happen if:

- si is a large positive number close to INT_MAX
- specifiedAmount is a large positive number
- The sum of si and specifiedAmount overflows INT_MAX 

In addition:
The vulnerability is in the calculation of computedAmount.  This is done by subtracting two int256 values (xf - xi or yf - yi). If xf and xi (or yf and yi) are very large values, their difference can overflow and wrap around, resulting in an incorrect value for computedAmount.

For example:

xi = 115792089237316195423570985008687907853269984665640564039457584007913129639935 (2^256 - 1)
xf = 10
computedAmount = xf - xi = 10 - (2^256 - 1) = 9 (overflows and wraps around)
The actual correct value should be computedAmount = 10 - (2^256 - 1) = -115792089237316195423570985008687907853269984665640564039457584007913129639925.



## Tools Used

## Recommended Mitigation Steps
 add overflow checks when calculating uf


## Assessed type

Other
Improper handling of cases when total supply = 0
Audit: 2023-08-shell-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
- Improper handling of cases when total supply = 0
- AMM engine may not be started.

## Proof of Concept
Considering if a vault uses Shell as its AMM engine. At the start, the vault has 0 X and Y balance and someone try to deposit tokens to it, this process will calls function `_reserveTokenSpecified` and it contains this line of code:
```solidity
uint256 result = Math.mulDiv(uint256(uf), uint256(si), uint256(ui));
```
In the above code, `si` is the total supply of LP token at the start.
This will cause the function to revert with `Division or modulo by 0` and thus the deposit is failed.

As an AMM engine, Shell should pay close attention to this case because many Vault will have 0 X and Y tokens balances unless someone deposits. If deposit fails, X and Y tokens balance remains 0 and the AMM engine could not be used at all.

Below is a POC for this issue, place this under file `test/EvolvingProteusProperties.t.sol`, contract `EvolvingProteusProperties` and run it using command:
`forge test --match-path src/test/EvolvingProteusProperties.t.sol --match-test test_deposit_at_vault_start -vvvv`

```solidity
    function test_deposit_at_vault_start() public {
        uint256 yBalance = 0;
        uint256 xBalance = 0;
        uint256 totalSupply = 0;

        uint256 specifiedAmount = 1e18;
        vm.expectRevert();
        uint256 mintedAmount = DUT.depositGivenInputAmount(
            yBalance,
            xBalance,
            totalSupply,
            specifiedAmount,
            SpecifiedToken.X
        );
    }
```
## Tools Used
Manual Review

## Recommended Mitigation Steps
I recommend making deep analysis about the starting states when X,Y balances and total LP tokens supply = 0 and return a result suitable with Shell design since there is a lot to consider.



## Assessed type

Invalid Validation