xanoutas/solidity-security-findings huggingface dataset:
Inaccurate Balance Checks in _lpTokenSpecified Due to Fee Application Order
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Summary:
The _lpTokenSpecified function contains a potential issue with balance checks after computing xf, yf, and computedAmount. Depending on the initial values of xi and yi, the balance checks might produce inaccurate results due to the order of operations when applying fees to the specified amounts.

## Bug Details:

- Affected Code:


if (specifiedToken == SpecifiedToken.X) {
    computedAmount = _applyFeeByRounding(xf - xi, feeDirection);
    _checkBalances(xi + computedAmount, yf);  // Potential balance check issue
} else {
    computedAmount = _applyFeeByRounding(yf - yi, feeDirection);
    _checkBalances(xf, yi + computedAmount);  // Potential balance check issue
}
#  Description:
The issue arises from the order of operations in applying fees to the computed differences (xf - xi or yf - yi). The _applyFeeByRounding function modifies the specified amounts after subtraction, which might lead to an incorrect representation of token movements considering fees.

# Impact:
Depending on the specific scenario, the impact of this bug could range from minor calculation discrepancies to major balance inconsistencies. If the applied fees are significant, the balance checks may not accurately reflect the actual movement of tokens, potentially leading to incorrect behavior or security vulnerabilities in the contract.

# Reproduction Steps:

- Set up the contract environment with appropriate initial values for xi, yi, xf, and yf.
- Call the _lpTokenSpecified function with different combinations of SpecifiedToken, specifiedAmount, feeDirection, si, xi, and yi.
- Observe the computed xf, yf, and computedAmount values and compare them to the expected values considering fees.
Compare the balance checks performed after the computations with the actual token movements.
# Suggested Solution:
To address this issue, modify the  apply fees to xf and yf before subtracting the initial values xi and yi. This ensures that the computed amount used in the balance checks accurately represents the token movement considering fees.

- Updated code snippet:


if (specifiedToken == SpecifiedToken.X) {
    int256 amountWithoutFee = xf - xi;
    int256 amountWithFee = _applyFeeByRounding(amountWithoutFee, feeDirection);
    computedAmount = amountWithFee;
    _checkBalances(xi + amountWithoutFee, yf);  // Adjusted balance check
} else {
    int256 amountWithoutFee = yf - yi;
    int256 amountWithFee = _applyFeeByRounding(amountWithoutFee, feeDirection);
    computedAmount = amountWithFee;
    _checkBalances(xf, yi + amountWithoutFee);  // Adjusted balance check
}
## Tools used

Manual Review





## Assessed type

Other
Integer Overflow Risk in swapGivenOutputAmount
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Description:

In the function swapGivenOutputAmount, there is an integer overflow risk associated with the validation check for outputAmount, xBalance, and yBalance. The code attempts to compare these values against an undefined constant INT_MAX, which is meant to represent the maximum value of an integer. However, as it stands, the code lacks a proper definition for INT_MAX, making the validation ineffective and exposing the code to potential integer overflow vulnerabilities.

## problematic line

require(
    outputAmount < INT_MAX && xBalance < INT_MAX && yBalance < INT_MAX
);

## Recommendation 

- Replace the code


     require(
         outputAmount < INT_MAX && xBalance < INT_MAX && yBalance < INT_MAX
     );

With the corrected check:


     require(
         outputAmount <= INT_MAX && xBalance <= INT_MAX && yBalance <= INT_MAX
     );

## tools used

 Manual review


## Assessed type

Other
Incorrect Validation for Deposit Amount
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

# Summary

The function depositGivenInputAmount contains an issue in the validation of the depositedAmount. The validation for the depositedAmount being less than INT_MAX (presumably the maximum value for an int256 integer) is incorrect and can lead to unexpected behavior.

# Descripton

 The function depositGivenInputAmount is meant to handle a deposit of a specified token amount and calculate the corresponding minted amount based on various balances and supply values. However, there is a bug in the validation of the depositedAmount.

The line of code that reads:


require(
    depositedAmount < INT_MAX &&
    xBalance < INT_MAX &&
    yBalance < INT_MAX &&
    totalSupply < INT_MAX
);

Here, the INT_MAX is being used as a threshold to ensure that the deposited amount, xBalance, yBalance, and totalSupply are within acceptable limits. However, the comparison here is not accurate. INT_MAX would likely refer to the maximum value that an int256 can hold, which is 2^255 - 1, and the usage in this context is not suitable for the validation of the deposit amount and other balances.


## Impact

As a result of this bug, valid deposit amounts that are greater than or equal to INT_MAX could fail the validation check, leading to an incorrect restriction on valid deposit amounts. This can cause genuine deposits to be rejected without a valid reason, hindering the proper functioning of the contract.

## Proposed Solution:
To fix this issue, the validation checks should be done based on the intended ranges for depositedAmount, xBalance, yBalance, and totalSupply, rather than using a predefined constant like INT_MAX. The appropriate maximum values should be used for these specific variables. Additionally, it's important to ensure that negative values are handled appropriately, especially since there's a subsequent requirement that result should be greater than 0.

# Tool used 

Manual Review



## Assessed type

Other
Missing Boundary Check for Negative Rounded Amount Calculation
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Description:
The  function _applyFeeByRounding lacks a necessary boundary check in the case where the feeUp flag is set to false. This omission could lead to unintended behavior or errors if the fee deduction causes the roundedAbsoluteAmount to become negative.

## Code snipped

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

In this case,  subtracting the fee from absoluteValue. If the fee subtraction results in a negative value, it could lead to unexpected behavior or errors .

## Impact:
If the feeUp flag is false and the fee deduction results in a negative roundedAbsoluteAmount, it could have several negative consequences:

- Inconsistent Results: Negative roundedAbsoluteAmount could lead to inconsistencies when used further in this, potentially causing unexpected behavior in the application.
- Error Prone: The absence of a boundary check might not trigger an error immediately, making it harder to identify the root cause of any issues that arise due to negative values.
- Data Integrity: Negative values might disrupt data integrity or calculations dependent on the roundedAbsoluteAmount.
## Concept of Bug:
The bug stems from the incomplete consideration of negative values during the calculation of roundedAbsoluteAmount when the feeUp flag is false. This performs the fee deduction operation, but it fails to ensure that the resulting roundedAbsoluteAmount is always above a certain minimum value, in this case, the FIXED_FEE.

## Tools used
Manual Review

## Recommendation:
To address this issue and ensure consistent and correct behavior, it is recommended to add a boundary check to prevent negative values for roundedAbsoluteAmount when feeUp is false. Below is the recommended modification to the code:


} else {
    require(absoluteValue >= FIXED_FEE, "AmountError");
    roundedAbsoluteAmount =
        absoluteValue -
        (absoluteValue / BASE_FEE) -
        FIXED_FEE;
}


This change ensures that the fee deduction does not cause roundedAbsoluteAmount to go below the FIXED_FEE, maintaining data integrity and consistent behavior regardless of the feeUp flag's value.





## Assessed type

Error
Final Amount to be Greater Than or Equal to the FIXED_FEE in `_applyFeeByRounding` Function NOT Guaranteed
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact

The `_applyFeeByRounding` function aims to apply a fee to transactions based on defined constants for stability and fee coverage. A discrepancy in handling fee calculations was identified, which might not guarantee that the final amount is always greater than or equal to the `FIXED_FEE`:

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

```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.
```
## Proof of Concept
The `_applyFeeByRounding` function's intent is to apply a fee by rounding values beneficially for the pool. The function checks if the absolute value of the amount is less than `FIXED_FEE * 2`, and if so, reverts. However, due to the nature of the fee calculation handling, there's a possibility that the final amount might not always be greater than or equal to the `FIXED_FEE`.

**Scenario: `feeUp` is false**
When `feeUp` is false, the function subtracts fees:

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

```solidity
            roundedAbsoluteAmount =
                absoluteValue -
                (absoluteValue / BASE_FEE) -
                FIXED_FEE;
```
Here, the largest possible fee deduction (as a proportion of `absoluteValue`) would be when `absoluteValue` is at its [minimum permissible value](https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L834), which is `FIXED_FEE * 2`. In this worst-case scenario, the fee fraction is:

(FIXED_FEE * 2) / 800 = 2.5 * 10^6

Adding the `FIXED_FEE` deduction of 10^9 to this, the maximum total fee deduction is 1.0025 * 10^9.

Given that the smallest permissible `absoluteValue` is 2 * 10^9, after the maximum possible fee deduction, the amount will be 2 * 10^9 - 1.0025 * 10^9 = 0.9975 * 10^9, which is smaller than `FIXED_FEE`.

This demonstrates that the function might not always guarantee that the magnitude of [`roundedAmount`](https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L849-L851) (or `roundedAbsoluteAmount`) is greater than or equal to the `FIXED_FEE`.

## Tools Used
Manual

## Recommended Mitigation Steps
Ensure that the final amount is always greater than or equal to the `FIXED_FEE`. This might involve adjusting the way fees are calculated or introducing additional checks. A possible refactoring could be:

```diff
function _applyFeeByRounding(int256 amount, bool feeUp)
    private
    pure
    returns (int256 roundedAmount)
{
    bool negative = amount < 0 ? true : false;
    uint256 absoluteValue = negative ? uint256(-amount) : uint256(amount);
    
    if (absoluteValue < FIXED_FEE * 2) revert AmountError();

+    uint256 fee = (absolute
The use of  `block.timestamp` may lead to inaccurate price calculations
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact

Let us assume the following scenario:

1. When the network liquidity is low, the duration of a block may be relatively long and unstable. If the user's request may be packaged in a lower order in a block, although it is in the same block at this time, the value of the `block.timestamp` will become larger than that of the front queue. It will cause a loss in the curve calculation
2. If the value of `_duration` is set smaller than the time of a block, it will cause the curve calculation to fail and only get a value that tends to balance

So, I suggest changing the `block.timestamp` to the `block.number` , and check `_duration > 1` when set the config in `constructor()`

## Proof of Concept

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

## Tools Used

manual

## Recommended Mitigation Steps

I suggest changing the `block.timestamp` to the `block.number` , and check `_duration > 1` when set the config in `constructor()`








## Assessed type

Error
Hardcoded fee introduces expensive entry points to the contract
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The EvolvingProteus contract hardcodes a fixed fee (FIXED_FEE) of 10^9, equating to 1000 units of stablecoins like USDC or USDT, which dominate the stablecoin market cap on Arbitrum. This sizeable fee could drastically hinder contract interactions for users, especially for small-scale transactions. Given that this fee is immutable due to its constant declaration, the flexibility to adapt based on market or user needs is lost.

The implications are multi-fold:

Cost Prohibitive: For many users, particularly those making small transactions, a 1000 unit fee is unsustainable.
Reduced Interactions: Many contract functionalities require a minimum absolute value to be at least twice the fixed fee (FIXED_FEE * 2). This means transactions involving less than 2000 USDC/USDT would be invalid, significantly limiting use-cases and potential interactions.
User Trust: Overpriced fees can erode user trust and deter them from further engagements, leading to reduced adoption and potentially making the contract obsolete.

## Proof of Concept
Direct references to the contract on GitHub illustrate the problematic fee structure:
https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L188-L191
```solidity
/** 
     @notice 
     When a token has 18 decimals, this is 1 nanotoken
*/ 
    uint256 constant FIXED_FEE = 10**9;
```

https://github.com/code-423n4/2023-08-shell/blob/main/src/proteus/EvolvingProteus.sol#L834
```solidity
        if (absoluteValue < FIXED_FEE * 2) revert AmountError();
```

## Tools Used
Manual code review

## Recommended Mitigation Steps
The following steps are mitigation possibilities.

### Redefine the Fixed Fee: 
Consider redefining the FIXED_FEE to a smaller value, balancing the operational costs and user convenience.
### Dynamic fee getter:
Add a dynamic fee getter that adjusts based on the token's decimals, ensuring compatibility with tokens of varying granularities:
```solidity
// Define the fee scale from 1 to 10000, where 10000 represents a 100% fee.
function getFixedFee(address tokenAddress) public view returns (uint256) {
    IERC20WithDecimals token = IERC20WithDecimals(tokenAddress);
    uint8 tokenDecimals = token.decimals();
    require(tokenDecimals > 0, "Token should have decimals greater than 0");

    return (FIXED_FEE * 10**tokenDecimals) / 10000;
}

```



## Assessed type

Decimal
Use of incorrect `BASE_FEE` in `EvolvingProteus.sol`
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
In `EvolvingProteus.sol`, `BASE_FEE` is the basis point percentage that the amounts are increased/decreased and is given as below,

```Solidity

    /** 
     @notice 
     Equivalent to roughly twenty-five basis points since fee is applied twice.
    */
    uint256 public constant BASE_FEE = 800;
```

Notice here, the Natspec states `twenty-five basis points` i.e 25 BPS but here 800 is considered which seems to be incorrect.

To understand about BPS, check out this [link](https://www.investopedia.com/terms/b/basispoint.asp)

While checking the shell documentation, I found below fee for different Token AMMs,

1) Stable Token AMMs - The fee is supposed to be `0.025%` which is equivalent to `2.5 BPS`, Reference [link](https://wiki.shellprotocol.io/getting-started/shell-primitives/stable-token-amms)

2) Volatile Token AMMs- The fee is supposed to be `0.25%` which is equivalent to `25 BPS`, Reference [link](https://wiki.shellprotocol.io/getting-started/shell-primitives/volatile-token-amms)

It means the fee for both Stable and Volatile tokens needs to be designed carefully, But with current implementation the hardcoded `BASE_FEE` seems to be `800 BPS` which is equivalent to `8%`. This is such a high fee as compared to what is documented in shell documentation.

`BASE_FEE` has been used in `_applyFeeByRounding()` which can be seen below,

```Solidity 

    function _applyFeeByRounding(int256 amount, bool feeUp)
        private
        pure
        returns (int256 roundedAmount)
    {
        bool negative = amount < 0 ? true : false;
        uint256 absoluteValue = negative ? uint256(-amount) : uint256(amount);
        // 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();

        uint256 roundedAbsoluteAmount;
        if (feeUp) {
            roundedAbsoluteAmount =
                absoluteValue +
>>              (absoluteValue / BASE_FEE) +
                FIXED_FEE;
            require(roundedAbsoluteAmount < INT_MAX);
        } else
            roundedAbsoluteAmount =
                absoluteValue -
>>              (absoluteValue / BASE_FEE) -
                FIXED_FEE;

        roundedAmount = negative
            ? -int256(roundedAbsoluteAmount)
            : int256(roundedAbsoluteAmount);
    }
```

_applyFeeByRounding() has been extensively used in EvolvingProteus.sol, Therefore a higher fee will be charged instead of designed one per the documentation. 

## Proof of Concept
https://github.com/code-423n4/2023-08-shell/blob/c61cf0e01bada04c3d6055acb81f61955ed600aa/src/proteus/EvolvingProteus.sol#L184-L186

## Tools Used
Manual Review

## Recommended Mitigation Steps
Per the Natspec [co
Protocol would revert in some edge cases
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details


## Impact

Protocol will dos in some special edge cases. Currently, protocol's fuzz.runs is set to 100, when increase fuzz.runs number to 100000, some edge cases will be triggered and protocol will dos.

Failed fuzz test results are shown below: 

[FAIL. Reason: CurveError(-1) Counterexample: calldata=0x2e2df542000000000000000000000000000000000000000000000000000000e8d4a51001000000000000000000000000000000000000000000000000015813d0037929180000000000000000000000000000000000000000000000000000000000000000, args=[1000000000001 [1e12], 96849176120863000 [9.684e16], false]] testEdgeSwaps(uint256,uint256,bool) (runs: 2051, μ: 151794, ~: 152274)
[FAIL. Reason: CurveError(-46529) Counterexample: calldata=0xc0bb8d0c00000000000000000000000000000000000000000000000000000000000009b9000000000000000000000000000000000000000000000000000000e8d4a51002000000000000000000000000000000000000000000000189a503a6acb675f49e0000000000000000000000000000000000000000000000000000000000000000, args=[2489, 1000000000002 [1e12], 7261460951669767795870 [7.261e21], false]] testEdgeSwapsOverT(uint256,uint256,uint256,bool) (runs: 857, μ: 156355, ~: 156835)
[FAIL. Reason: CurveError(-67) Counterexample: calldata=0x2e2df542000000000000000000000000000000000000000000000000000000e8d4a5100200000000000000000000000000000000000000000000000228cd2d05a623aafc0000000000000000000000000000000000000000000000000000000000000000, args=[1000000000002 [1e12], 39833543781447346940 [3.983e19], false]] testEdgeSwaps(uint256,uint256,bool) (runs: 900, μ: 151776, ~: 152259)


## Proof of Concept

We can write an poc to proof according to fuzz test result:

```solidity
    function testEdgeSwaps_fail() public {
        uint256 x0 = 1000000000001;
        uint256 y0 = 705418223925948812340;
        bool token = false;

        vm.assume(x0 > MIN_BALANCE && x0 < 1e27);
        vm.assume(y0 > MIN_BALANCE && y0 < 1e27);
        vm.assume(y0/x0 <= MAX_BALANCE_AMOUNT_RATIO);
        vm.assume(x0/y0 <= MAX_BALANCE_AMOUNT_RATIO);

        SpecifiedToken inputToken = token ? SpecifiedToken.X : SpecifiedToken.Y;
        SpecifiedToken outputToken = token ? SpecifiedToken.Y : SpecifiedToken.X;

        uint256 maxInput = DUT.getSwapMax(int256(x0), int256(y0), token);

        emit log_named_uint("maxInput", maxInput);

        //token ? assertTrue((maxInput/10) > x0, "max X input doesn't match") : assertTrue((maxInput + y0) > y0, "max Y input doesn't match");
        vm.expectRevert();
        DUT.swapGivenInputAmount(x0, y0, maxInput, inputToken);
        assertGt(DUT.p_max(), DUT.p_min());

        uint256 maxOutput = (token ? y0 : x0) - MIN_BALANCE + 1;
        vm.expectRevert();
        DUT.swapGivenOutputAmount(x0, y0,
ABDKMath64 performs multiplication on results of division
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-04-mimo/blob/main/core/contracts/libraries/ABDKMath64x64.sol#L626
https://github.com/code-423n4/2022-04-mimo/blob/main/core/contracts/libraries/ABDKMath64x64.sol#L629
https://github.com/code-423n4/2022-04-mimo/blob/main/core/contracts/libraries/ABDKMath64x64.sol#L630


# Vulnerability details

## Impact
Solidity could truncate the results, performing multiplication before division will prevent rounding/truncation in solidity math.

## Proof of Concept
https://github.com/code-423n4/2022-04-mimo/blob/main/core/contracts/libraries/ABDKMath64x64.sol#L626
https://github.com/code-423n4/2022-04-mimo/blob/main/core/contracts/libraries/ABDKMath64x64.sol#L629
https://github.com/code-423n4/2022-04-mimo/blob/main/core/contracts/libraries/ABDKMath64x64.sol#L630
## Tools Used
Manual Review
## Recommended Mitigation Steps
Consider ordering multiplication first.


## Assessed type

Math
Function swapGivenInputAmount() will always revert
Audit: 2023-08-shell-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The Function ```swapGivenInputAmount()``` will always revert due to the check ```require(result < 0)```
## Proof of Concept
In ```swapGivenInputAmount()``` function there is a check that
 ```amount can't be less than 0```
 but require statement is checking opposite condition and hence the function will always revert and never execute
## Tools Used
Manual review
## Recommended Mitigation Steps
Instead of checking ```require(result < 0)``` check ```require(result > 0)```


## Assessed type

Other