xanoutas/solidity-security-findings huggingface dataset:
VaultController#changeInitialBorrowingFee Owner won't be able to set fee to MAX_INIT_BORROWING_FEE
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L426


# Vulnerability details

## Impact

As it is stated, the MAX_INIT_BORROWING_FEE = 0.05e18, denoting the max allowed to be set as borrowing fee. Unfortunately, the owner cannot set the borrowing fee to max

## Proof of Concept

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L426

There is a mistake in the logic of this [Line](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L426
), the check uses ">=".The implication of this is that the Owner can't set the borrowing fee to the MAX_INIT_BORROWING_FEE of which is not an intended behavior of the protocol. 

Instead it should be made to revert only when the _newBorrowingFee exceeds the MAX_INIT_BORROWING_FEE

## Tools Used

Manual Review

## Recommended Mitigation Steps

Change the line to if (_newBorrowingFee > MAX_INIT_BORROWING_FEE) revert VaultController_FeeTooLarge();


## Assessed type

Other
Threshold for creating proposal can be bypassed
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/governance/GovernorCharlie.sol#L170


# Vulnerability details

## Impact
Line 170 of ‘GovernorCharlie.sol’ enforces delay for reaching threshold, this can cause issue on Arbitrum as block.number return recently synced L1 blocknumber. This can be used to bypass the condition and create prosposal even if the threshold is not meet.

The same rule also apply for Optimistic as every transaction is a block in itself that can be used by anyone to create proposal.

## Proof of Concept
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/governance/GovernorCharlie.sol#L170


## Tools Used
Manual Code Review

## Recommended Mitigation Steps
The delay for threshold should be based on using block.timestamp instead of using block.number


## Assessed type

Other
function having callback should have re-entrancy guard
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L70


# Vulnerability details

## Impact
WUSDA.sol has functions mintFor, depositFor and withdrawAllTo that calls _deposit() and _withdraw(), which has callback of ‘to’ address argument. Protection should be provided from possible malicious attacks by placing re-entrancy guards in place for functions having call back

## Proof of Concept
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L70
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L130
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L169

## Tools Used
Manual Code Review

## Recommended Mitigation Steps
Place a re-entrancy guard modifier on mintFor, depositFor and withdrawAllTo functions to protect from potential attack.


## Assessed type

Reentrancy
Liquidator can bypass `_actualTokensToLiquidate` during liquidation
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/VaultController.sol#L656-L660
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/VaultController.sol#L777-L799


# Vulnerability details

## Impact
Although there is no damage to be done, the check should not be bypassed to reduce attack surface.

During liquidation, the amount that can be liquidated (`_actualTokensToLiquidate`) is controlled by minimum of `_maxTokensToLiquidate` or `_balance` calculated in `_calculateTokensToLiquidate` internal function. Liquidator can bypass the checks in 2 ways

1. Liquidate when `_usdaToSolvency * 1e18 < _badFillPrice - _ltvDiscount` aka when `_usdaToSolvency` is very small. It is possible to bypass `_maxTokensToLiquidate` due to loss during division causing `_maxTokensToLiquidate` to becomes 0.
```
    // the maximum amount of tokens to liquidate is the amount that will bring the vault to solvency
    // divided by the denominator
    uint256 _maxTokensToLiquidate = (_usdaToSolvency * 1e18) / _denominator;
    //Cannot liquidate more than is necessary to make vault over-collateralized
    if (_tokensToLiquidate > _maxTokensToLiquidate) _tokensToLiquidate = _maxTokensToLiquidate; // @audit _tokensToLiquidate now equal 0
```
Which is then used to cap the amount that they can liqudiate. But when it returns 0 the cap is bypassed.
```
    (uint256 _tokenAmount, uint256 _badFillPrice) = _liquidationMath(_id, _assetAddress, _tokensToLiquidate);
    // set _tokensToLiquidate to this calculated amount if the function does not fail
    if (_tokenAmount > 0) _tokensToLiquidate = _tokenAmount; // @audit allowing liquidator to continue with full _tokensToLiquidate
```
But no damage could be done because at the end vault solvency is checked to prevent over liquidation.
```
  // @audit safu
  if (_getVaultBorrowingPower(_vault) > _vaultLiability(_id)) revert VaultController_OverLiquidation();
```
Without this check, liquidator would be able to liquidate all of collateral.

2. Call liquidate with asset that vault doesn't have. Inside `_calculateTokensToLiquidate` cap amount to balance of vault. When try to liquidate asset that vault doesn't have, it becomes 0 and the cap is bypassed same as above.
```
    uint256 _balance = _vault.balances(_assetAddress);

    //Cannot liquidate more collateral than there is in the vault
    if (_tokensToLiquidate > _balance) _tokensToLiquidate = _balance; // _tokensToLiquidate becomes 0 since vault doesn't have any balance
```
But it is not possible to continue liquidation process since there is nothing to transfer out of vault.
```
    // finally, deliver tokens to liquidator
    _vault.controllerTransfer(_assetAddress, _msgSender(), _tokensToLiquidate - _liquidationFee); // @audit nothing to transfer here
```

## Proof of Concept
Extending `CommonE2EBase` test contract. The test showed that liquidating vault that is so close to solvency within hundreds o
Unchecked Return Value in ERC20 Transfer Function
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/USDA.sol#L103
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/USDA.sol#L153
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/USDA.sol#L206
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/USDA.sol#L216
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/USDA.sol#L246
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/Vault.sol#L194
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/Vault.sol#L223
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/Vault.sol#L224
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/AMPHClaimer.sol#L129


# Vulnerability details

## Impact
It is not safe to use the ERC20 transfer function without checking the results. Use a safe transfer library like OpenZeppelin SafeERC20 to ensure consistent handling of ERC20 return values and abstract over inconsistent ERC20 implementations. Although the SafeERC20Upgradeable library is present it's not being used to all transfers.

## Proof of Concept

```solidity
194:          _rewardToken.transfer(_msgSender(), _earnedReward);
```

in this case for example the transfer function is being called without checking its return, some tokens are known for having weird behaviors when using the transfer function. Consider using the SafeERC20 library to handle this, it's being inherited in some contracts but to some functions is not being used.

## Tools Used
Manual Review

## Recommended Mitigation Steps

Since some contracts mentioned do implement the SafeErc20 replace the transfer/transferFrom to safeTransfer/safeTransferFrom


## Assessed type

ERC20
Missing checks for whether the L2 Sequencer is active & for Grace period
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol#L12


# Vulnerability details

## Impact
Chainlink recommends that users using price oracles, check whether the Arbitrum Sequencer is [`active`](https://docs.chain.link/data-feeds/l2-sequencer-feeds#arbitrum). If the sequencer goes down, the Chainlink oracles will have stale prices from before the downtime, until a new L2 OCR transaction goes through. Users who submit their transactions via the [`L1 Dealyed Inbox`](https://developer.arbitrum.io/tx-lifecycle#1b--or-from-l1-via-the-delayed-inbox) will be able to take advantage of these stale prices. Use a [`Chainlink oracle`](https://blog.chain.link/how-to-use-chainlink-price-feeds-on-arbitrum/#almost_done!_meet_the_l2_sequencer_health_flag) to determine whether the sequencer is offline or not, and don't allow operations to take place while the sequencer is offline or outside the grace period.

## Proof of Concept
```solidity
  /// @notice Returns the current price from the aggregator
  function getCurrentPrice(AggregatorV2V3Interface _aggregator) internal view returns (uint256 _price) {
    (, int256 _answer,,,) = _aggregator.latestRoundData();
    if (_answer <= 0) revert Chainlink_NegativePrice();
    _price = uint256(_answer);
  }
```
[Link to code Here](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol#L11C1-L14C31)
## Tools Used
Manual review.
## Recommended Mitigation Steps
Check if the sequencer is active.


## Assessed type

Oracle
Less Than Expected Amount `AMPH` Token Will Be Minted
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/AMPHClaimer.sol#L194-L199


# Vulnerability details

### Impact

According to the Amphora Protocol documentation, the intended maximum amount of `AMPH` tokens to be minted is 10 billion tokens ([link](There will be a max of 10B Amphora tokens minted over time.)):

> There will be a max of 10B Amphora tokens minted over time.

However, based on the implementation, the maximum amount that can be minted is at most 8.94427 billion `AMPH` tokens.

### Proof of Concept

The [`AMPHClaimer.sol`](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/AMPHClaimer.sol#L194-L199) function calculates the `_rate` as follows:

```solidity
function _getRate(uint256 _distributedAmph) internal pure returns (uint256 _rate) {
  uint256 _foo = (_TWENTY_FIVE_THOUSANDS * BASE_SUPPLY_PER_CLIFF) / Math.max(_distributedAmph, _FIFTY_MILLIONS);
  uint256 _bar = (_distributedAmph * 1e12) / (BASE_SUPPLY_PER_CLIFF * _FIFTY);
  _rate = 1e6 + (_foo - _bar);
}
```

To calculate `_rate`, the function calculates `_foo` and `_bar`, and then combines them.

We know that `_rate` should always be positive. If `_rate` becomes negative, the function will be reverted.

Considering we want to calculate the maximum amount of `AMPH` that can be minted, in the calculation of `_foo` becomes:
$$
\text{foo} = \frac{25,000 \times 1e6 \times 8,000,000 \times 1e6}{\text{max}(\text{distributedAmph}, 50,000,000)}
$$
Since we want to calculate maximum amount of `AMPH` that can be minted, the denominator is:
$$
\text{denominator} = \text{max}(\text{distributedAmph}, 50,000,000) = \text{distributedAmph}
$$
Hence, the value of `_foo` is:
$$
\text{foo} = \frac{25,000 \times 1e6 \times 8,000,000 \times 1e6}{\text{distributedAmph}}
= \frac{2 \times 1e23}{\text{distributedAmph}}
$$
In the next step, we have to calculate `_bar`:
$$
\text{bar} = \frac{\text{distributedAmph} \times 1e12}{8,000,000 \times 1e6 \times 50 \times 1e6}
= \frac{\text{distributedAmph}}{4 \times 1e8}
$$
Then, the `_rate` is:
$$
\text{rate} = 1e6 + (\frac{2 \times 1e23}{\text{distributedAmph}} - \frac{\text{distributedAmph}}{4 \times 1e8})
$$
Now, lets show `_rate` by `y` and `distributedAmph` by `x`:
$$
y = 1e6 + (\frac{2 \times 1e23}{x} - \frac{x}{4 \times 1e8})
$$
The simplified version is:
$$
y = \frac{-x^2 + 4 \times 1e8 \times x + 8 \times 1e31}{400 \times x}
$$
Then `y` becomes negative, when the numerator of the previous equation is zero; hence, we have to solve the equatio below:
$$
-x^2 + 4 \times 1e8 \times x + 8 \times 1e31 = 0
$$
Then, if we solve this equation, we reach two following answers:
$$
x_1 = −8.94427e15, x_2 = 8.94427e15
$$
This means if `x` (or `_distributedAmph`) exceeds 8.94427e+15, `y` (or `_rate`) becomes negative. Since `_rate` must be positive, the minting process will be stopped at this point. Therefore, a
Valuation of the `cbETH/ETH ` price are wrongly inflated by 10 decimals
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol#L15-L19


# Vulnerability details


## Impact

This causes an extreme overvaluation of the cbETH/ETH (_~10 decimals_) and easily breaks any logic querying the `_get()` function

`CB_ETH_ORACLE_RELAY` and `ETH_ORACLE_RELAY`. These comments, if followed literally, would lead to a fundamental misunderstanding of the contract's functioning.

## Proof of Concept

Note that from [here](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol#L15-L19) we can see that the `CB_ETH_ORACLE_RELAY` and `ETH_ORACLE_RELAY` point to the `cbETH/ETH` and `ETH/USD` price respectively

```solidity
  /// @notice The oracle relay for the cbETH/ETH price
  IOracleRelay public immutable CB_ETH_ORACLE_RELAY;

  /// @notice The oracle relay for the ETH/USD price
  IOracleRelay public immutable ETH_ORACLE_RELAY;

```

Now take a look at the internal [`\_get()](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol#L51-L65) function:

```solidity
  /// @notice Calculated the price of 1 LP token
  /// @dev This function comes from the implementation in vyper
  /// @return _maxPrice The current value
  function _get() internal view returns (uint256 _maxPrice) {
    uint256 _vp = virtualPrice;

    //@audit
    // Get the prices from chainlink and add 10 decimals
    uint256 _cbEthPrice = CB_ETH_ORACLE_RELAY.peekValue();
    uint256 _ethPrice = ETH_ORACLE_RELAY.peekValue();

    uint256 _basePrices = (_cbEthPrice * _ethPrice);

    _maxPrice = (2 * _vp * FixedPointMathLib.sqrt(_basePrices)) / 1 ether;
    // removed discount since the % is so small that it doesn't make a difference
  }

```

As seen at [line 57](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol#L57)

`    // Get the prices from chainlink and add 10 decimals`

The comment linked above suggests adding 10 decimals to the prices fetched from the `CB_ETH_ORACLE_RELAY` and `ETH_ORACLE_RELAY`. However, the cbETH/ETH price fetched from the `CB_ETH_ORACLE_RELAY` is already in 18 decimals, making the addition of 10 decimals unnecessary and lead to overvaluation of the price returned.

## Tool used

Manual Audit

## Recommended Mitigation Steps

Keep in mind that chainlink feeds return 8 decimals for USD pairs, and 18 decimals for ETH pairs, so if an addition of 10 decimals is going to be made it should be to the price returned from the `ETH/USD` feed alone



## Assessed type

Oracle
No Implementation of claimerContract and BOOSTER function from IVaultController.sol interface
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/IVaultController.sol#L1039-L1042
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/Vault.sol#L241
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/Vault.sol#L96
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/Vault.sol#L147
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/Vault.sol#L168


# Vulnerability details

## Impact
No Implementation of claimerContract and BOOSTER function from IVaultController.sol interface in the vaultController.sol contract but it was used in the vault contract. This could create huge effect on contract component execution.

## Proof of Concept
The functions called from the CONTROLLER in L168, L241, L96 & L147 are not implemented any where in the vaultController.sol contract.
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/Vault.sol#L168
```solidity
96.   IBooster _booster = CONTROLLER.BOOSTER();
...
147.  IBooster _booster = CONTROLLER.BOOSTER();
...
168.  IAMPHClaimer _amphClaimer = CONTROLLER.claimerContract();
...
247. IAMPHClaimer _amphClaimer = CONTROLLER.claimerContract();
```
The implementation of this functions cant be found anywhere in the vaultController.sol contract which is solely responsible for the functionality of the "CONTROLLER" in this code
## Tools Used
Solidity, Foundry
## Recommended Mitigation Steps
Implementation of claimerContract() and BOOSTER() function should be added where necessary to the vaultController.sol contract


## Assessed type

Error
ETH is not refunded in terms of proposal get cancelled  .
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/governance/GovernorCharlie.sol#L398


# Vulnerability details

## Impact
ETH is not refunded when canceling proposal .

## Proof of Concept
When submitting a proposal , an Eth value for transaction is sent . But if a users proposal gets cancelled paid Eth is not refunded to the proposer . The `_cancelTransaction ` function looks like this :

```solidity 

 function _cancelTransaction(
    address _target,
    uint256 _value,
    string memory _signature,
    bytes memory _data,
    uint256 _eta
  ) internal {
    bytes32 _txHash = keccak256(abi.encode(_target, _value, _signature, _data, _eta));
    queuedTransactions[_txHash] = false;

    emit CancelTransaction(_txHash, _target, _value, _signature, _data, _eta);
  }
```
there's no logic to refund the paid amount of eth to the proposer 
## Tools Used
Manual review 

## Recommended Mitigation Steps
Track the eth value sent by the proposer and refund it if cancellation happens .


## Assessed type

Other
Access control and issue with math logic on `USDA.vaultControllerDonate()` 
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/USDA.sol#L256-L269
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/USDA.sol#L171


# Vulnerability details


## Impact

1. `vaultControllerDonate` could be called even with the protocol is paused.
2. Having `_totalSupply` greater then `_totalGons` will result in bad accounting and user can lose their tokens.

## Proof of Concept

In the code: 

```solidity
  /// @notice Function for the vaultController to scale all USDA balances
  /// @param _amount The amount of USDA (e18) to donate
  function vaultControllerDonate(uint256 _amount) external override onlyVaultController {
    _donation(_amount);
  }https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/USDA.sol#L256-L269

  /// @notice Function for distributing the donation to all USDA holders
  /// @param _amount The amount of USDA to donate
  function _donation(uint256 _amount) internal {
    _totalSupply += _amount;
    if (_totalSupply > MAX_SUPPLY) _totalSupply = MAX_SUPPLY;
    _gonsPerFragment = _totalGons / _totalSupply;
    emit Donation(_msgSender(), _amount, _totalSupply);
  }
```

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/USDA.sol#L256-L269

1. The function misses the modifier `whenNotPaused` modifier, which allows the `VaultController` to call the function even when the protocol functions are paused. I believe this is not intended functionality and devs should take note.

2. If `_totalSupply > _totalGons`, then `_gonsPerFragment` is set to 0 (zero), which can break other functions like:

```solidity
function _mint(address _target, uint256 _amount) internal {
    uint256 __gonsPerFragment = _gonsPerFragment;
    // the gonbalances of the sender is in gons, therefore we must multiply the deposit amount, which is in fragments, by gonsperfragment
    _gonBalances[_target] += _amount * __gonsPerFragment;
    https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/USDA.sol#L171-L172
    // total supply is in fragments, and so we add amount
    _totalSupply += _amount;
    // and totalgons of course is i
    n gons, and so we multiply amount by gonsperfragment to get the amount of gons we must add to totalGons
    _totalGons += _amount * __gonsPerFragment;
    // emit both a mint and transfer event
    emit Transfer(address(0), _target, _amount);
    emit Mint(_target, _amount);
  }
```

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/USDA.sol#L171-L172

```solidity
_gonBalances[_target] += _amount * __gonsPerFragment;
```

where `_gonBalances` value for `_target` account will be set to 0, and thus user wi