xanoutas/solidity-security-findings huggingface dataset:
OpenZeppelin Ownable.sol now requires owner address must be initialized in constructor
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Some contracts has used openzeppelin ownable.sol for using owner related access functions and for initialization of owner in contract. However with recent modification of openzeppelin library the owner needs to be explicitly needs to be set in constructor during the deployment. With current impplmentation in contracts where openzeppelin ownable.sol is used, the owner is defaulted to address(0) due to not being set in constructor during deployement.

Considering for example:
In AmphoraProtocolToken.sol, With current impplmentation the owner is defaulted to address(0) due to not being set in constructor during deployement.

```Solidity
File: contracts/governance/AmphoraProtocolToken.sol

8 contract AmphoraProtocolToken is IAmphoraProtocolToken, ERC20VotesComp, Ownable {
9   constructor(
10    address _account,
11    uint256 _initialSupply
12  ) ERC20('Amphora Protocol', 'AMPH') ERC20Permit('Amphora Protocol') {
13    if (_account == address(0)) revert AmphoraProtocolToken_InvalidAddress();
14    if (_initialSupply <= 0) revert AmphoraProtocolToken_InvalidSupply();
15
16    _mint(_account, _initialSupply);
17  }
```
As seen AmphoraProtocolToken contract does not set owner in constructor therefore the said openzeppelin issue exists here.

The following owner accessed functions will be affected,

```Solidity
File: contracts/governance/AmphoraProtocolToken.sol

  function mint(address _dst, uint256 _rawAmount) public onlyOwner {
    _mint(_dst, _rawAmount);
  }
```

The OpenZeppelin Ownable.sol has changed recently. In older versions, the account which deployed the contract was automatically set the owner of the contract and onlyOwner would have been used per design. Now, the new update requires the contract owner to be specified explicitly as a constructor argument during deployment.

Openzeppelin reference: [click here](https://github.com/OpenZeppelin/openzeppelin-contracts/commit/13d5e0466a9855e9305119ed383e54fc913fdc60)

Per Openzeppelin Ownable.sol, see how the owner is set in constructor during deployment.

```Solidity
File: contracts/access/Ownable.sol

constructor(address initialOwner) {
    _transferOwnership(initialOwner);
}
```

This is explained with taking one instance however, other contracts where ownable.sol is used will have same impact.

## Proof of Concept
[AMPHClaimer.sol](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/AMPHClaimer.sol#L12)

[VaultController.sol](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L23)

[AmphoraProtocolToken.sol](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governan
possible to mint more than wusda.sol max supply 
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#L35
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/WUSDA.sol#L59


# Vulnerability details

## Impact
MAX_wUSDA_SUPPLY is set as constant in WUSDA contract but is not used in contract, thus it is possible to mint more than max wusda supply and have a totalSupply more than MAX_wUSDA_SUPPLY. 

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

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

```
  function mint(uint256 _wusdaAmount) external override returns (uint256 _usdaAmount) {
    _usdaAmount = _wUSDAToUSDA(_wusdaAmount, _usdaSupply());
    _deposit(_msgSender(), _msgSender(), _usdaAmount, _wusdaAmount);
  }
```

**Proof of concept below** 
run test file with `forge test --fork-url <rpc-link> -vvv --match-contract UnitWUSDAMintFcn --match-test testMintMoreThanMaxSupply`
```
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import {WUSDA} from '@contracts/core/WUSDA.sol';

import {DSTestPlus} from 'solidity-utils/test/DSTestPlus.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

abstract contract Base is DSTestPlus {
  event Deposit(address indexed _from, address indexed _to, uint256 _usdaAmount, uint256 _wusdaAmount);
  event Withdraw(address indexed _from, address indexed _to, uint256 _usdaAmount, uint256 _wusdaAmount);

  uint256 internal constant _DELTA = 100;

  address public usdaToken = newAddress();
  string public name = 'USDA Token';
  string public symbol = 'USDA';
  uint256 public usdaTotalSupply = 1_000_000 ether;
  WUSDA public wusda;
  uint256 public wusdaMaxSupply;

  function setUp() public virtual {
    vm.mockCall(usdaToken, abi.encodeWithSelector(IERC20.transfer.selector), abi.encode(true));
    vm.mockCall(usdaToken, abi.encodeWithSelector(IERC20.totalSupply.selector), abi.encode(usdaTotalSupply));

    // solhint-disable-next-line reentrancy
    wusda = new WUSDA(usdaToken, name, symbol);
    // solhint-disable-next-line reentrancy
    wusdaMaxSupply = wusda.MAX_wUSDA_SUPPLY();
  }
}


contract UnitWUSDAMintFcn is Base {

  function testMintMoreThanMaxSupply() public {
    wusda.mint( wusda.MAX_wUSDA_SUPPLY() + 1e10);
    assertEq(wusda.totalSupply(), wusda.MAX_wUSDA_SUPPLY() + 1e10);
  }
}
```

## Tools Used
vs code, foundry 

## Recommended Mitigation Steps
add check in _deposit() that reverts if amount to be minted + total supply is more than the set MAX_wUSDA_SUPPLY constant. 





## Assessed type

Invalid Validation
WUSDA.sol: `MAX_wUSDA_SUPPLY ` is not enforced during `wUSDA` mint.
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#L70-L73


# Vulnerability details

## Impact

MAX_wUSDA_SUPPLY is not enforced.
As a result, there will be more nunmber of wUSDA can be minted.

This will lead to incorrect calculation from the functions [_usdaToWUSDA](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/WUSDA.sol#L246C12-L248) and [_wUSDAToUSDA](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/WUSDA.sol#L253-L256). These two functions are used when deposit and withdraw.
Though the max limit is exceeded, still the above mentioned function will use constat MAX_wUSDA_SUPPLY  value for calculations.

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

limit cap can be seen from https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/WUSDA.sol#L35

But when we look at the mint function, no check for the wUSDA cap value.

```solidity
  function mintFor(address _to, uint256 _wusdaAmount) external override returns (uint256 _usdaAmount) {
    _usdaAmount = _wUSDAToUSDA(_wusdaAmount, _usdaSupply());
    _deposit(_msgSender(), _to, _usdaAmount, _wusdaAmount);
  }
```

## Tools Used

Manual review.

## Recommended Mitigation Steps

Refactor the code such that wUSDA mint should not exceed the MAX_wUSDA_SUPPLY value.


## Assessed type

Error
Frontrunning Vulnerability in liquidateVault Function
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#L646-L697


# Vulnerability details

## Impact
The `liquidateVault` function can be frontrunned every time by any bot frontrunner watching to this function in the mempool.

## Proof of Concept

```solidity
function liquidateVault(
    uint96 _id,
    address _assetAddress,
    uint256 _tokensToLiquidate
  ) external override paysInterest whenNotPaused returns (uint256 _toLiquidate) {
    // cannot liquidate 0
    if (_tokensToLiquidate == 0) revert VaultController_LiquidateZeroTokens();
    // check for registered asset
    if (tokenAddressCollateralInfo[_assetAddress].tokenId == 0) revert VaultController_TokenNotRegistered();

    // calculate the amount to liquidate and the 'bad fill price' using liquidationMath
    // see _liquidationMath for more detailed explaination of the math
    (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;
    // the USDA to repurchase is equal to the bad fill price multiplied by the amount of tokens to liquidate
    uint256 _usdaToRepurchase = _truncate(_badFillPrice * _tokensToLiquidate);
    // get the vault that the liquidator wishes to liquidate
    IVault _vault = _getVault(_id);

    // decrease the vault's liability
    _vault.modifyLiability(false, (_usdaToRepurchase * 1e18) / interest.factor);

    // decrease the total base liability
    totalBaseLiability -= _safeu192((_usdaToRepurchase * 1e18) / interest.factor);

    // decrease liquidator's USDA balance
    usda.vaultControllerBurn(_msgSender(), _usdaToRepurchase);

    // withdraw from convex
    CollateralInfo memory _assetInfo = tokenAddressCollateralInfo[_assetAddress];
    if (_vault.isTokenStaked(_assetAddress)) {
      _vault.controllerWithdrawAndUnwrap(_assetInfo.crvRewardsContract, _tokensToLiquidate);
    }

    uint192 _liquidationFee = getLiquidationFee(uint192(_tokensToLiquidate), _assetAddress);

    // finally, deliver tokens to liquidator
    _vault.controllerTransfer(_assetAddress, _msgSender(), _tokensToLiquidate - _liquidationFee);
    // and the fee to the treasury
    _vault.controllerTransfer(_assetAddress, owner(), _liquidationFee);
    // and reduces total
    _modifyTotalDeposited(_tokensToLiquidate, _assetAddress, false);

    // this mainly prevents reentrancy
    if (_getVaultBorrowingPower(_vault) > _vaultLiability(_id)) revert VaultController_OverLiquidation();

    // emit the event
    emit Liquidate(_id, _assetAddress, _usdaToRepurchase, _tokensToLiquidate - _liquidationFee, _liquidationFee);
    // return the amount of tokens liquidated (including fee)
    _toLiquidate = _tokensToLiquidate;
  }

```

Since the function basically only cares if the vault is underwater every time anyone would see the o
Can mint unlimited amount of WUSDA with 0 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#L60


# Vulnerability details

## Impact

The WUSDA smart contract has a critical vulnerability that allows an attacker to mint an unlimited amount of WUSDA tokens with 0 USDA as collateral.

## Proof of Concept

The vulnerability lies in following functions:

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

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

The `_wUSDAToUSDA()` function calculates the amount of USDA needed to mint a given amount of WUSDA, based on the `_totalUsdaSupply`. However, due to an underflow issue, when `_totalUsdaSupply` is very low (e.g., 1 * 10^18) and `_wusdaAmount` is large, the `_usdaAmount` is calculated to be 0.

As a result, an attacker can mint a significant amount of WUSDA with 0 USDA collateral, which can lead to severe economic consequences for the system. The attacker can exploit this to inflate the total supply of WUSDA without providing any actual collateral.

## Example

Initial condition:
- `MAX_wUSDA_SUPPLY` = 10,000,000 * 10^18
- `_usdaSupply()` = `INITIAL_FRAGMENTS_SUPPLY` = 1 * 10^18

Suppose Alice sends a mint transaction with `_wusdaAmount = 9,999,999`, after executing `_wUSDAToUSDA()` we got:
```solidity
	_usdaAmount = (9,999,999 * 1 * 10^18) / (10,000,000 * 10^18) = 0
```

As a result, Alice can mint 9,999,999 WUSDA tokens without providing any USDA collateral.

## Impact of the Exploit

This vulnerability allows an attacker to mint an unlimited (upto MAX_wUSDA_SUPPLY) amount of WUSDA tokens without backing them with any collateral. The attacker can exploit this flaw to manipulate the system, causing economic instability and unfair advantages.

## Recommended Mitigation Steps

To address this vulnerability, it is crucial to prevent the minting process from proceeding if the calculated `_usdaAmount` is 0. This can be achieved by adding a requirement in the `mint()` function:

```solidity
function mint(uint256 _wusdaAmount) external override returns (uint256 _usdaAmount) {
    _usdaAmount = _wUSDAToUSDA(_wusdaAmount, _usdaSupply());
    require(_usdaAmount > 0, "_usdaAmount equals 0");
    _deposit(_msgSender(), _msgSender(), _usdaAmount, _wusdaAmount);
}
```



## Assessed type

Under/Overflow
Handling Transfer Fees in depositERC20 Function
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
When the user deposits to `depositERC20(address _token, uint256 _amount)` the function is not prepared to handle future fees that will be implemented to protocols like (USDC, USDT) and is already in use by (STA and PAXG), the STA token being explored in $500K because of this fee on transfer.
 

## Proof of Concept

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

```solidity
  function depositERC20(address _token, uint256 _amount) external override onlyMinter {
    if (CONTROLLER.tokenId(_token) == 0) revert Vault_TokenNotRegistered();
    if (_amount == 0) revert Vault_AmountZero();
    SafeERC20Upgradeable.safeTransferFrom(IERC20Upgradeable(_token), _msgSender(), address(this), _amount);
    if (CONTROLLER.tokenCollateralType(_token) == IVaultController.CollateralType.CurveLPStakedOnConvex) {
      uint256 _poolId = CONTROLLER.tokenPoolId(_token);
      /// If it's type CurveLPStakedOnConvex then pool id can't be 0
      IBooster _booster = CONTROLLER.BOOSTER();
      if (isTokenStaked[_token]) {
        /// In this case the user's balance is already staked so we only stake the newly deposited amount
        _depositAndStakeOnConvex(_token, _booster, _amount, _poolId);
      } else {
        /// In this case the user's balance isn't staked so we stake the amount + his balance for the specific tokenv
        isTokenStaked[_token] = true;
        _depositAndStakeOnConvex(_token, _booster, balances[_token] + _amount, _poolId);
      }
    }
    balances[_token] += _amount;
    CONTROLLER.modifyTotalDeposited(vaultInfo.id, _amount, _token, true);
    emit Deposit(_token, _amount);
  }
```

Since the user can arbitrarily set the token and amount he wants, assuming the token is allowed by the owner, the function is not prepared to deal with future fees on transfer of tokens and are assigning the _amount direct to a bunch of internal functions and state variables. This probably leads to wrong _amount information and opens up to some very weird behaviors.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Check for the possibility of fees. a good way to check this is right after depositing the token which takes fee is to call the users balance and pass this returned value instead of the _amount.



## Assessed type

ERC20
USDA.sol#L147 : `_withdraw` function does not have reentrancy protection. The state update is done after the transfer call.
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#L147-L157


# Vulnerability details

## Impact
A bad user will re-enter the [_withdraw](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/USDA.sol#L147-L157) and drain the funds since the tokens are burned after the transfer call.

## Proof of Concept

Since the issue is pretty straight forward, lets look at the code block.

Lets look at the function `_withdraw`

```solidity
  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); ------------>> can be reentered if the target is contract address.
    _burn(_msgSender(), _susdAmount); -------------->> burn is done after the transfer call.


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

## Tools Used

Manual review.

## Recommended Mitigation Steps

Add `reentrancy` protection and do the state updates before making the transfer call.


## Assessed type

Reentrancy
The hardcoded _LOOKBACK_ being used as `_seconds` would cause wrong price to be returned from oracles built on UniswapV3OracleRelay.sol
Audit: 2023-07-amphora-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details


## Impact

Attackers would interact with protocol easily on ambigous prices

## Proof of Concept

In the UniswapV3OracleRelay contract, the `_getPriceFromUniswap` method uses the `consult` and `getQuoteAtTick` methods from the OracleLibrary to get the average tick over a specified time period and then calculate the price quote for a given base amount.
The chain of this call is `peekValue()` -> `_getLastSeconds(LOOKBACK);` -> `_getPriceFromUniswap()` as can be seen at [UniswapV3OracleRelay.sol#L56-L82](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol#L56-L82)

```solidity
  /// @notice returns the price with 18 decimals without any state changes
  /// @dev some oracles require a state change to get the exact current price.
  ///      This is updated when calling other state changing functions that query the price
  /// @return _price the current price
  function peekValue() public view virtual override returns (uint256 _price) {
    _price = _get();
  }


  /// @notice Returns the current reported value of the oracle
  /// @dev Implementation in _getLastSecond
  /// @return _value The current value
  function _get() internal view returns (uint256 _value) {
    _value = _getLastSeconds(LOOKBACK);
  }


  /// @notice Returns last second value of the oracle
  /// @param _seconds How many seconds to twap for
  /// @return _price The last second value of the oracle
  function _getLastSeconds(uint32 _seconds) internal view returns (uint256 _price) {
    uint256 _uniswapPrice = _getPriceFromUniswap(_seconds, uint128(10 ** BASE_TOKEN_DECIMALS));
    _price = _toBase18(_uniswapPrice, QUOTE_TOKEN_DECIMALS);
  }


  function _getPriceFromUniswap(uint32 _seconds, uint128 _amount) internal view virtual returns (uint256 _price) {
    (int24 _arithmeticMeanTick,) = OracleLibrary.consult(address(POOL), _seconds);
    _price = OracleLibrary.getQuoteAtTick(_arithmeticMeanTick, _amount, BASE_TOKEN, QUOTE_TOKEN);
  }

```

Most importantly note the

```solidty
    uint256 _uniswapPrice = _getPriceFromUniswap(_seconds, uint128(10 ** BASE_TOKEN_DECIMALS));
```

However, this method does not validate any inputs, this is due to the hardcoded `_seconds` value, i.e the _LOOKBACK_ being used

```solidity
  /// @notice The lookback for the oracle
  uint32 public immutable LOOKBACK;
```

Now the [scripts](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/scripts/CreateOracles.sol) suggests that the hardcoded value of _LOOKBACK_ is going to be `TWO HOURS` for most of the pools, the ETH/USD pool included, whereas this might not be an issue for stable coins pools this is a big case in the case of ETH, cause
`__wUSDAToUSDA()` creates an incentive for attackers to flash attack WUSDA.sol
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#L250-L256


# Vulnerability details


## Impact

The crux of this issue lies in the method used to calculate the conversion rate between the wrapped token (wUSDA) and the underlying token (USDA). More precisely, the total supply of USDA is used as a metric, which could be artificially inflated through a flash loan, thereby manipulating the conversion rate. This loophole could be exploited by an attacker to gain an unfair advantage, ultimately affecting other users negatively.

## Proof of Concept

Here's an insight into the [`_wUSDAToUSDA()`](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/WUSDA.sol#L250-L256) function from `WUSDA.sol`

```solidity
  /// @notice Converts _wusdaAmount amount to _usdaAmount.
  /// @param _wusdaAmount The amount of wUSDA tokens.
  /// @param _totalUsdaSupply The total usda supply.
  /// @return _usdaAmount The amount of usda tokens exchangeable.
  function _wUSDAToUSDA(uint256 _wusdaAmount, uint256 _totalUsdaSupply) private pure returns (uint256 _usdaAmount) {
    _usdaAmount = (_wusdaAmount * _totalUsdaSupply) / MAX_wUSDA_SUPPLY;
  }
```

The utilization of the total USDA supply at the time of transaction execution within the `_wUSDAToUSDA` and extensively `_usdaToWUSDA` methods is the where the attack window lies.

A probable exploit scenario would be where a user intends to burn their wUSDA to withdraw USDA. In parallel, an attacker mints an extensive amount of USDA through a flash loan, inflating the total supply artificially. Consequently, when the user burns their wUSDA, the conversion rate relies on this inflated supply, leading to the user receiving more USDA than they should have. The flash loan is repaid, and the total supply reverts to its original state. However, the user has now effectively secured extra USDA, to the detriment of other users.

Notably, this scenario highlights an instance where an attacker incurs a cost on another person. However, the attacker could also manipulate this loophole for personal gain. An example of this would be applying the issue to the `burn()` function. A user attempts to withdraw, and in the process, the attacker flash loans and mints an additional 1,000,000 USDA. If the original supply was 1,000,000, the attacker can easily double the withdrawal amount, changing the equation to (100K \* 2,000,000) / 10,000,000. This manipulation could potentially result in the attacker gaining more than a 100% profit.

## Tool Used

Manual Audit

## Recommended Mitigation Steps

Do not directly use the totalSupply at transaction's execution time.



## Assessed type

Token-Transfer