user fund lose in deposit() of PirexERC4626 contract because A MALICIOUS EARLY USER/ATTACKER CAN MANIPULATE THE VAULT’S PRICEPERSHARE TO TAKE AN UNFAIR SHARE OF FUTURE USERS’ DEPOSITS
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L60-L78
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L178-L185
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L156-L165


# Vulnerability details

## Impact
This is a well-known attack vector for new contracts that utilize pricePerShare for accounting. Attacker can cause `totalAssets() / totalSupply()` ratio to go as high as he wants and then because of rounding error in `convertToShares()` lower amount of share would be mint for users.
if `totalSupply()` is `0` attacker can directly transfer `1000 e 18` tokens to contract address(even before contract deployment, because the address of contract can be calculated even before deployment) and then deposit `1 wei` to contract  so then `totalAssets()` would be very high and `totalSupply()` would be low and  `totalAssets() / totalSupply()` could be as high as `1000 e 18` which would make rounding error as `1000 e 1e18` token and users would lose funds, for example if a user deposits `1999 * 1e18` tokens he would receive shares only based on `1000 * 1e18` of his tokens because of rounding error.

## Proof of Concept
This is `deposit()`  and `previewDeposit()` and `convertToShares()` code in `PirexERC4626` contract:
```
    function deposit(uint256 assets, address receiver)
        public
        virtual
        returns (uint256 shares)
    {
        if (totalAssets() != 0) beforeDeposit(receiver, assets, shares);

        // Check for rounding error since we round down in previewDeposit.
        require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(receiver, assets, shares);
    }


    function previewDeposit(uint256 assets)
        public
        view
        virtual
        returns (uint256)
    {
        return convertToShares(assets);
    }

    function convertToShares(uint256 assets)
        public
        view
        virtual
        returns (uint256)
    {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

```
As you can see the amount of `shares` users received for depositing `asset` is calculated by `convertToShares()` function. imagine this scenario for `AutoPxGmx` contract which is extended `PirexERC4626`:
1. A malicious early user can `deposit()` with `1 wei` of `PxGmx` token as the first depositor of the `AutoPxGmx`, and get `1 wei` of shares token.
2. Then the attacker can send `1000e18 - 1` of `PxGmx` t