xanoutas/solidity-security-findings huggingface dataset:
WUSDA mint and deposit doesn't check WUSDA max supply
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L35
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L59-L73
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L119-L133


# Vulnerability details

## Impact
max supply is defined inside WUSDA contract, but it never checked when mint and deposit operations are performed, this will allow users to mint WUSDA greater than the defined max supply.

## Proof of Concept

max supply is defined inside WUSDA contract :

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

```solidity
uint256 public constant MAX_wUSDA_SUPPLY = 10_000_000 * (10 ** 18);
```

But when mint and deposit operations performed, it never checked against the max supply :

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L59-L62
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L70-L73
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L119-L122
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L130-L133
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L214-L219

This will allow users to mint WUSDA exceed the defined max supply.


## Tools Used

Manual review

## Recommended Mitigation Steps

Consider do add check against max total supply inside `_deposit` before mint WUSDA


## Assessed type

ERC20
Borrowers can be liquidated multiple times
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Because of how liquidations work and how the exact amount to liquidate is calculated borrowers can be placed in a state where a liquidation puts them on the edge of another one, and this combined with falling prices (usually when liquidations occur) can cause a borrower to e liquidated multiple times in a row, reducing his collateral to nothing.

## Proof of Concept
From `VaultController` we can see that liquidators liquidate users up to their solvency limit. Meaning if the solvency limit is, lets say 80%, any liquidator can liquidate any user until the given user reaches 80% of solvency. But this is no good, since if any user is at the solvency limit they need slight market change in the negative side in order to push them again underwater.

The calculations happening in [liquidateVault](https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/VaultController.sol#L831-L833) are: 

1. The exact [amount to solvency](https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/VaultController.sol#L831-L833) is extracted

2. A calculation on what are the [max tokens](https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/VaultController.sol#L790) a liquidator can liquidate

3. `_usdaToRepurchase` is calculated [with](https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/VaultController.sol#L662) 

4. The liability [is modified](https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/VaultController.sol#L667), **where our issue starts**

5. It [transfer](https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/VaultController.sol#L684) the tokens back to the liquidator

As we can see in number 3, it calculates `_usdaToRepurchase`, by using `_badFillPrice` which is the reduced price for liquidation (if incentive for liquidation is 5% , the bad fill price on USDC will be 0.95$). Under number 4 it reduces the liability by this amount (95% * 100 USDC), and under 5 it transfers the real token amount to the liquidator (100 USDC). The vulnerability here is in the fact that it lowers the collateral by an amount bigger than the amount it lowers the liability.

Example:
| *Preconditions*            | *values* |
|----------------------------|----------|
| USDA price                 | 1.00     |
| USDCprice                  | 1.00     |
| Liquidation incentive in % | 5%       |
| Solvency limit             | 80%      |
| Collateral in USDC         | 1250     |
| Borrowed balance           | 1100     |
| Underwater                 | 100      |

1. Alice has over-borrowed by 100 USD, on her collateral (1250), with 80% solvency limit she is able to borrow max 1000 USDC
2. Bob sees that he can liquidate Alice so he calls liquidate on
Attacker can utilize sUSD flash loan to temporarily inflate total USDA supply, burning their WUSDA for additional USDA
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Similar to the other high-severity finding, it is possible for an attacker to temporarily inflate the USDA total supply by taking out a sUSD flash loan and depositing on Amphora. This results in a temporarily inflated total USDA supply which is read by `WUSDA::_wUSDAToUSDA`. When called from `WUSDA::burn`, this allows the attacker to withdraw additional USDA from the contract, to which they should not be entitled.

## Proof of Concept
* Total USDA supply is 5M.
* 3M is deposited into WUSDA contract, of which attacker owns 1M.
* Attacker takes out a sUSD flash loan of 25M.
* Attacker deposits 25M sUSD into USDA.
* Attacker withdraws 1M WUSDA.
* Attacker receives 3M USDA rather than 500_000 (`_wusdaAmount` = (1e24 * 3e25) / 1e25 = 3e24.
* Attacker redeems USDA, repays the flash loan and profits 2M USDA/sUSD at the expense of other depositors.

## Tools Used
Manual review.

## Recommended Mitigation Steps
Protections against manipulation of USDA total supply within a single block would be desirable here, perhaps achievable by implementing some multi-block delay.


## Assessed type

Other
attacker can free mint WUSDA when USDA total supply still low
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L254-L256
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L59-L73
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/utils/UFragments.sol#L102
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/utils/UFragments.sol#L63


# Vulnerability details

## Impact
Due to lack of `_usdaAmount` check inside `mint` or `mintFor` function, when total supply of USDA is low enough, attacker can mint WUSDA for free.

## Proof of Concept

Inside `mint` function, it will call `_wUSDAToUSDA` to get `_usdaAmount` that user need to send from the `_wusdaAmount` that user want to mint.

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

```solidity
  function deposit(uint256 _usdaAmount) external override returns (uint256 _wusdaAmount) {
    _wusdaAmount = _usdaToWUSDA(_usdaAmount, _usdaSupply());
    _deposit(_msgSender(), _msgSender(), _usdaAmount, _wusdaAmount);
  }
```

Inside `_wusdaAmount`, the calculation will be performed : 

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

```solidity
  function _wUSDAToUSDA(uint256 _wusdaAmount, uint256 _totalUsdaSupply) private pure returns (uint256 _usdaAmount) {
    _usdaAmount = (_wusdaAmount * _totalUsdaSupply) / MAX_wUSDA_SUPPLY;
  }
```

The initial usda total supply is `1 * 10 ** 18`, and `MAX_wUSDA_SUPPLY` is `10_000_000 * (10 ** 18)`.

user can provide `_wusdaAmount` that can result in `_usdaAmount` with 0 value and mint WUSDA for free.

## Tools Used

Manual review

## Recommended Mitigation Steps

Consider to add additional check, if `_usdaAmount` returned from the operation is 0, revert the call.


## Assessed type

Invalid Validation
Incorrect decimal adjustment of price in `VaultController::_getPriceWithDecimals` results in inflated borrowing power for non-18 decimal tokens
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
`VaultController::_getPriceWithDecimals` is intended to return the decimal-adjusted price of a token; however, the decimal adjustment is incorrect and results in an inflated price for non-18 decimal tokens. Here, `_price` is the raw oracle price of the token normalized to 18 decimals:

```solidity
function _getPriceWithDecimals(uint256 _price, uint256 _decimals) internal pure returns (uint256 _priceWithDecimals) {
    _priceWithDecimals = _price * 10 ** (18 - _decimals); // @audit - this should be divide. e.g. 18 dec price -> 6 dec token = 1e18 / 1e18 - 1e6 = 1e18 / 1e12 = 1e6, but this is 1e18 * 1e12 = 1e30
  }
```

This function returns the correct value for 18 decimal tokens, as the additional factor simply becomes 1, but should instead return `_price / 10 ** (18 - decimals)` for non-18 decimal tokens rather than multiplying by this factor. For example, USDC is a 6 decimal token, so the price should be divided by `10^12` to get the correct price. Instead, the price is multiplied by `10^12`, resulting in a price that is `10^24` times too high (1e18 * 1e12 / 1e6). This results in an inflated borrowing power for non-18 decimal tokens and a lower `maxTokensToLiquidate` in liquidation math.

**_borrowing:_**
1e6 USDC is now worth 1e42 USDA rather than 1e18 USDA. Assume the vault has a balance of 1M USDC, or 1e12 USDC, its borrowing power is calculated to be 1e48 USDA rather than 1e24 USDA. This means the vault can borrow 1e48 USDA, which is 1e24 times more than it should be able to borrow.

This issue is even further exacerbated by lower decimal tokens such as GUSD. Additionally, if the minter chose to borrow only a fraction of the available USDA, they could effectively open a position that is highly unlikely to ever be liquidated.

**_liquidating:_**
So long as the minter borrows more USDA than the true value of that in their vault, the real collateral value is never enough to cover the debt to begin with, but the vault will not be liquidatable until the reported price of the collateral drops by a significant factor, and only then will a factor of `10^24` the value be recoverable. This is because the vault's borrowing power is inflated by 1e24 times, so in the example above the vault can borrow 10^30 USDA tokens, but only has 1M USDC to cover the debt.

Furthermore, this faulty price adjustment is used in the calculations of `VaultController::_calculateTokensToLiquidate` which is used to determine the maximum amount of collateral that can be liquidated from a vault, meaning that the vault can only be liquidated for a fraction of the collateral that it should be liquidated for based on the true LTV in the event a significant price change pushes the vault's borrowing power below its USDA liability.

```solidity
function _amountToSolvency(uint96 _id) internal retu
`withdrawAll()` and `withdrawAllTo()` unfairly truncates user's sUSD tokens
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details



## Impact

While attempting to withdraw sUSD by burning USDA, the amount of sUSD withdrawn is completely dependent on the contract's `reserveAmount`. This could potentially create situations where the user does not receive the full amount of sUSD they are entitled to.

- If a user's balance is greater than the `reserveAmount`, the `_susdWithdrawn` will always be set to `reserveAmount`, truncating the user's balance, causing them to lose sUSD.

```
    _susdWithdrawn = _balance > reserveAmount ? reserveAmount : _balance;
```

- For example, a user could have 1000 USDA and wishes to convert it all to sUSD. However, if the `reserveAmount` is only 500 sUSD, the user would only receive 500 sUSD, effectively losing half of their original USDA value.

## Proof of Concept

Take a look at lines [126 - 157](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/USDA.sol#L126-L157) of USDA.sol

```solidity
  /// @notice Withdraw sUSD by burning USDA
  /// @dev The caller should obtain 1 sUSD for every 1 USDA
  /// @dev This function is effectively just withdraw, but we calculate the amount for the sender
  /// @param _susdWithdrawn The amount os sUSD withdrawn
  function withdrawAll() external override returns (uint256 _susdWithdrawn) {
    uint256 _balance = this.balanceOf(_msgSender());
    //@audit
    _susdWithdrawn = _balance > reserveAmount ? reserveAmount : _balance;
    _withdraw(_susdWithdrawn, _msgSender());
  }


  /// @notice Withdraw sUSD by burning USDA
  /// @dev This function is effectively just withdraw, but we calculate the amount for the _target
  /// @param _target should obtain 1 sUSD for every 1 USDA burned from caller
  /// @param _susdWithdrawn The amount os sUSD withdrawn
  function withdrawAllTo(address _target) external override returns (uint256 _susdWithdrawn) {
    uint256 _balance = this.balanceOf(_msgSender());
    //@audit
    _susdWithdrawn = _balance > reserveAmount ? reserveAmount : _balance;
    _withdraw(_susdWithdrawn, _target);
  }


  /// @notice business logic to withdraw sUSD and burn USDA from the caller
  function _withdraw(uint256 _susdAmount, address _target) internal paysInterest whenNotPaused {
    if (reserveAmount == 0) revert USDA_EmptyReserve();
    if (_susdAmount == 0) revert USDA_ZeroAmount();
    if (_susdAmount > this.balanceOf(_msgSender())) revert USDA_InsufficientFunds();
    // Account for the susd withdrawn
    reserveAmount -= _susdAmount;
    sUSD.transfer(_target, _susdAmount);
    _burn(_msgSender(), _susdAmount);


    emit Withdraw(_target, _susdAmount);
  }
```

In both of these functions, the `_susdAmount` is limited by the `reserveAmount`.

## Tool used

Manual Audit

## Recommendation

I have two recommendations, either:

1. Track the amou
`WUSDA.withdraw` can be done for free.
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/5d1cea9410db5448760c834f001af04a72edf3e0/core/solidity/contracts/core/WUSDA.sol#L140
https://github.com/code-423n4/2023-07-amphora/blob/5d1cea9410db5448760c834f001af04a72edf3e0/core/solidity/contracts/core/WUSDA.sol#L246


# Vulnerability details

## Impact
When usda.totalSupply() gets bigger than `MAX_wUSDA_SUPPLY`, `WUSDA.withdraw` can be done for free.

## Proof of Concept
Add the below `testWithdrawWithoutDecreasingUserBalance` test in https://github.com/code-423n4/2023-07-amphora/blob/5d1cea9410db5448760c834f001af04a72edf3e0/core/solidity/test/unit/WUSDA.t.sol#L390. 
Then run `forge test --mt testWithdrawWithoutDecreasingUserBalance`.
I explain the intent in comments.
```solidity
contract UnitWUSDAWithdraw is Base {
    uint256 public usdaDeposited = 100_000 ether;
    uint256 public wusdaSupply;

    function setUp() public override {
        super.setUp();
        wusda.deposit(usdaDeposited);
        wusdaSupply = wusda.totalSupply();
    }
    
    // @audit add this test
    function testWithdrawWithoutDecreasingUserBalance() public {
        uint256 _usdaAmount = 2;
        uint128 _usdaTotalSupply = 20_000_001e18;
        vm.mockCall(usdaToken, abi.encodeWithSelector(IERC20.totalSupply.selector), abi.encode(_usdaTotalSupply));
        // @audit _withdrawAmount is 0 because (2 * 100_000e18) / 20_000_001e18 is 0
        uint256 _withdrawAmount = (_usdaAmount * wusdaMaxSupply) / _usdaTotalSupply;

        uint256 wusdaBalanceBefore = wusda.balanceOf(address(this));

        // @audit caller gets 2 usda by paying 0 wusda
        vm.expectCall(usdaToken, abi.encodeWithSelector(IERC20.transfer.selector, address(this), _usdaAmount));
        wusda.withdraw(_usdaAmount);

        uint256 wusdaBalanceAfter = wusda.balanceOf(address(this));

        // @audit However, the caller's wusda balance is not decreased
        assertEq(_withdrawAmount, 0);
        assertEq(wusdaBalanceBefore, wusdaBalanceAfter);
    }
```

## Tools Used
Manual review

## Recommended Mitigation Steps
Roundup when calculating the cost of user and keep rounding down when calculating the cost of the system.
`Math.ceilDiv` is useful.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol#L107-L115

I suggest a fix as below.
https://github.com/code-423n4/2023-07-amphora/blob/5d1cea9410db5448760c834f001af04a72edf3e0/core/solidity/contracts/core/WUSDA.sol#L139-L142
```solidity
  function withdraw(uint256 _usdaAmount) external override returns (uint256 _wusdaAmount) {
    // @audit change _usdaToWUSDA -> _usdaToWUSDACeil
    _wusdaAmount = _usdaToWUSDACeil(_usdaAmount, _usdaSupply());
    _withdraw(_msgSender(), _msgSender(), _usdaAmount, _wusdaAmount);
  }
```

https://github.com/code-423n4/2023-07-amphora/blob/5d1cea9410db5448760c834f001af04a72edf3e0/core/solidity/contracts/core/WUSDA.sol#L247
```solidity
  function _usdaToWUSDACeil(uint256 _usdaAmount, uint256 _total
The price return from Chainlink is scaled twice.
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L879
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol#L75
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/scripts/CreateOracles.sol#L39


# Vulnerability details

## Impact
The borrower can borrow more than they initially expected.

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

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

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/scripts/CreateOracles.sol#L39

## Tools Used
None

## Recommended Mitigation Steps
The price return from Chainlink should only be scaled once.


## Assessed type

Decimal
In the VaultController.sol::registerErc20 incorrect  _ltv  Ratio Check
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Vulnerability Details:

The vaultcontroller.sol contract contains a check of the Loan-to-Value (LTV) ratio in the registerErc20 function. The vulnerability arises from a flawed condition that checks the compatibility between the `_ltv` ratio and the liquidation incentive. Due to this issue, the condition can evaluate to true, even if the loan is well-collateralized, when the liquidation incentive is set too high.

```solidity
  function registerErc20(
    address _tokenAddress,
    uint256 _ltv,
    address _oracleAddress,
    uint256 _liquidationIncentive,
    uint256 _cap,
    uint256 _poolId
  ) external override onlyOwner {
    CollateralInfo storage _collateral = tokenAddressCollateralInfo[_tokenAddress];
    if (_collateral.tokenId != 0) revert VaultController_TokenAlreadyRegistered();
    uint8 _tokenDecimals = IERC20Metadata(_tokenAddress).decimals();
    if (_tokenDecimals > MAX_DECIMALS) revert VaultController_TooManyDecimals();
    if (_poolId != 0) {
      (address _lpToken,,, address _crvRewards,,) = BOOSTER.poolInfo(_poolId);
      if (_lpToken != _tokenAddress) revert VaultController_TokenAddressDoesNotMatchLpAddress();
      _collateral.collateralType = CollateralType.CurveLPStakedOnConvex;
      _collateral.crvRewardsContract = IBaseRewardPool(_crvRewards);
      _collateral.poolId = _poolId;
    } else {
      _collateral.collateralType = CollateralType.Single;
      _collateral.crvRewardsContract = IBaseRewardPool(address(0));
      _collateral.poolId = 0;
    }
    // ltv must be compatible with liquidation incentive
    if (_ltv >= (EXP_SCALE - _liquidationIncentive)) revert VaultController_LTVIncompatible();
    // increment the amount of registered token
    tokensRegistered = tokensRegistered + 1;
    // set & give the token an id
    _collateral.tokenId = tokensRegistered;
    // set the token's oracle
    _collateral.oracle = IOracleRelay(_oracleAddress);
    // set the token's ltv
```
## Impact

this can create misalignment of incentives, as liquidators might be incentivized to prioritize liquidating well-collateralized loans over legitimately under-collateralized ones.

## Proof of Concept

By setting a high liquidation incentive value and a corresponding loan-to-value ratio close to the constant EXP_SCALE (1e18) in the registerErc20 function. The flawed condition can then evaluate to true, despite the loan being well-collateralized.

```solidity

    if (_ltv >= (EXP_SCALE - _liquidationIncentive)) revert VaultController_LTVIncompatible();

```

## Tools Used

Manual Review

## Recommended Mitigation Steps

carefully calibrate the liquidation incentives and perform additional checks to ensure that the loan-to-value ratio accurately reflects the collateralization status of the loans. This can include setting reasonable limits on liquidation incentives or introducin
Reentrancy in withdrawERC20
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Classic example of reentrancy. Making a transfer before updating the vault state leads to reenter the `withdrawERC20` and execute properly given that the vault will be overcollaterialized between calls (its state is updated AFTER the call) so that it reenters passing each call the maximum amount of a given token, draining the whole vault. It must be the minter, though, but the flaw here is clear. He can behave maliciously if the "bounty" is worth it.

## Proof of Concept
```
function withdrawERC20(address _tokenAddress, uint256 _amount) external override onlyMinter {
    if (CONTROLLER.tokenId(_tokenAddress) == 0) revert Vault_TokenNotRegistered();
    if (isTokenStaked[_tokenAddress]) {
      if (!CONTROLLER.tokenCrvRewardsContract(_tokenAddress).withdrawAndUnwrap(_amount, false)) {
        revert Vault_WithdrawAndUnstakeOnConvexFailed();
      }
    }
    // reduce balance
    balances[_tokenAddress] -= _amount; // @audit each call this goes to 0 for a given _tokenAddress
    // check if the account is solvent
    if (!CONTROLLER.checkVault(vaultInfo.id)) revert Vault_OverWithdrawal(); // @audit if the first one is overcollaterized, then the next ones will be too
    // transfer the token to the owner
    SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(_tokenAddress), _msgSender(), _amount);
    // modify total deposited
    CONTROLLER.modifyTotalDeposited(vaultInfo.id, _amount, _tokenAddress, false); // @audit modify state AFTER call + lack of nonReentrant ==> reentrancy
    emit Withdraw(_tokenAddress, _amount);
  }
```

## Tools Used
Manual analysis

## Recommended Mitigation Steps
Just make the transfer the last instruction and put a `nonReentrant` modifier from OZ (it may be redundant, but that way you remove the possibility of a transaction reentering the function from within the contract)





## Assessed type

Reentrancy