xanoutas/solidity-security-findings huggingface dataset:
Division by zero could cause DOS in function `harvest()` and `claim()` in PirexRewards contract
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L802-L804


# Vulnerability details

## Impact

When functions `harvest()` or `claim()` of PirexRewards are called, they will claim rewards by calling `PirexGmx.claimRewards()` function. If there is any case that esGmx reward is existed but not base rewards or vice versa, the value returned from `_calculateRewards()` is 0 and it leads to division by zero and revert.

For example,
```solidity
if (baseRewards != 0) {
    // This may not be necessary and is more of a hedge against a discrepancy between
    // the actual rewards and the calculated amounts. Needs further consideration
    rewardAmounts[0] =
        (gmxBaseRewards * baseRewards) /
        (gmxBaseRewards + glpBaseRewards); // @audit division by zero
    rewardAmounts[1] = baseRewards - rewardAmounts[0];
}
```

Since `baseRewards` is calculated by using pre and post balance, attacker can simply trigger it by transferring `gmxBaseReward` to the contract, passing the check `if (baseRewards != 0)`. 

## Proof of Concept

Function `harvest()` calls `claimRewards()`. 
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L338-L348
```solidity
function harvest()
    public
    returns (
        ERC20[] memory _producerTokens,
        ERC20[] memory rewardTokens,
        uint256[] memory rewardAmounts
    )
{
    (_producerTokens, rewardTokens, rewardAmounts) = producer
        .claimRewards();
    uint256 pLen = _producerTokens.length;
```

In function `claimRewards()`, rewards amount is calculated by substracting post balance with pre balance
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L785-L790
```solidity
uint256 baseRewards = gmxBaseReward.balanceOf(address(this)) -
    baseRewardBeforeClaim;
uint256 esGmxRewards = stakedGmx.depositBalances(
    address(this),
    address(esGmx)
) - esGmxBeforeClaim;
```

Function `_calculateRewards()` can return zero when there is lacking rewards in distributor.
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L250-L254
```solidity
uint256 distributorBalance = (isBaseReward ? gmxBaseReward : esGmx)
    .balanceOf(distributor);
uint256 blockReward = pendingRewards > distributorBalance
    ? distributorBalance
    : pendingRewards;
```


## Tools Used
Manual Review

## Recommended Mitigation Steps
Consider adding zero check before doing the division.
Attackers can manipulate ERC4626 price per share to take an unfair share of future users
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
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L80


# Vulnerability details

## Impact
The attacker can get funds from future users, and the future users will lose their funds.

## Proof of Concept
A malicious early user can deposit() with 1 wei of asset token and get 1 wei of shares. Then he/she can send 10000e18 - 1 of asset tokens and inflate the price per share from 1 to an extreme value of 1e22

`(1 + 10000e18 - 1) / 1 = 1e22`

A future user who deposits 19999e18 will only receive 1 wei of shares token.

`19999e18 * 1 / 10000e18 = 1`

he/she would lose 9999e18 if they redeem() right after the deposit().

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

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L80

## Tools Used
Manual Review

## Recommended Mitigation Steps
Require minimum amount of share in deposit function and mint function.
Unlimited minting of pxGmx in PirexGmx.sol which may break protocol
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L392-L402


# Vulnerability details



## Impact

Unlimited minting of pxGmx which may break protocol.

## Proof of Concept

A user can call depositGmx() on PirexGmx.sol and mint some pxGmx after staking some Gmx via gmxRewardRouterV2.stakeGmx(amount) and transferring GMX into the contract. 

        // Transfer the caller's GMX to this contract and stake it for rewards
        gmx.safeTransferFrom(msg.sender, address(this), amount);
        gmxRewardRouterV2.stakeGmx(amount);

Afterwards, the user can go to GMX directly to call unstakeGmx

    function unstakeGmx(uint256 _amount) external nonReentrant {
        _unstakeGmx(msg.sender, gmx, _amount, true);
    }

Since pxGmx is minted, User can have unlimited amount of pxGmx which can be sold in the liquidity pool.

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L392-L402
https://arbiscan.io/address/0xa906f338cb21815cbc4bc87ace9e68c87ef8d8f1#contracts

https://arbiscan.io/address/0xa906f338cb21815cbc4bc87ace9e68c87ef8d8f1#contracts

## Tools Used

Manual Review

## Recommended Mitigation Steps

Make sure the user cannot unstake on GMX itself.
First depositer can break Vault share distributions
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L164-L175


# Vulnerability details

The calculation of exchange rate for shares in PirexERC4626 Vault is done by dividing the total supply of shares by the totalAssets of the vault. The first depositor can mint a very small number of shares, then donate to the vault to manipulate the share price. When subsequent depositors deposit, they will lose value due to precision loss. This is a common attack vector for almost all shares based liquidity pool contracts using ERC4626.

## Impact

First depositor can manipulate shares from later users; later users will not get equivalent shares when converting their underlying asset.

## Proof of Concept

1. Malicious user Alice can deposit() with 1 wei of asset token to get 1 wei of shares.
2. Next, Alice sends 10000e18 -1 of asset tokens and inflate the price per share from 1 to 1e22.
3. Subsequent depositor who deposits shares, eg 19999e18 of assets, will only receive 1 wei of shares token.
4. Victim will lose 9999e18 if they redeem() right after deposit() due to precision loss.

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

Relatable issue: https://github.com/sherlock-audit/2022-08-sentiment-judging#issue-h-1-a-malicious-early-userattacker-can-manipulate-the-ltokens-pricepershare-to-take-an-unfair-share-of-future-users-deposits

## Tools Used

Manual Review

## Recommended Mitigation Steps

Consider requiring a minimum amount of share tokens to be minted for the first minter or follow Uniswap V2 which mints 10,000 share first to balance liquidity.

https://github.com/Uniswap/v2-core/blob/ee547b17853e71ed4e0101ccfd52e70d5acded58/contracts/UniswapV2Pair.sol#L119-L124
incorrect commend and/or rounding issues in `AutoPxGmx` and `AutoPxGlp`
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L323
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGlp.sol#L184


# Vulnerability details

## Impact

The comments on the affected lines state `previewWithdraw` will round up. However, the implementation, an inner call to convertToShares is made, which actually calls mulDivDown.

From further inspection, this pair of functions `withdraw`, `previewWithdraw` as well as the "rounds up" comment exists in both the base PirexERC4626 as well as `AutoPxGmx`, but the latter overrides it to slightly change the logic. The superclass implementation doesn't suffer from this problem, since the original `previewWithdraw` directly calls `mulDivUp`, and does not delegate to `convertToShares`

This has all the code smells of a copy&paste oversight.

Additionally, the second `previewWithdraw` implementation does one additional mathematical division that implicitly rounds down a second time.

Also, it must be said that this fees like a fragile solution. Why implement hooks on the base ERC4626 contract if those hooks are then not enough to prevent overriding whole functions in your final contracts?

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

## Recommended Mitigation Steps

It is unclear wether this constitutes a serious issue, or just potential for dust amounts to be left on the contract.
Best case scenario: the comment is actually what's wrong, and should just be ammended to reflect the current behaviour
Underlying assets stealing in `AutoPxGmx` and `AutoPxGlp` via share price manipulation
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L156-L165
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L167-L176


# Vulnerability details

## Impact
pxGMX and pxGLP tokens can be stolen from depositors in `AutoPxGmx` and `AutoPxGlp` vaults by manipulating the price of a share.
## Proof of Concept
ERC4626 vaults are subject to a share price manipulation attack that allows an attacker to steal underlying tokens from other depositors (this is a [known issue](https://github.com/transmissions11/solmate/issues/178) of Solmate's ERC4626 implementation). Consider this scenario (this is applicable to `AutoPxGmx` and `AutoPxGlp` vaults):
1. Alice is the first depositor of the `AutoPxGmx` vault;
1. Alice deposits 1 wei of pxGMX tokens;
1. in the `deposit` function ([PirexERC4626.sol#L60](https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L60)), the amount of shares is calculated using the `previewDeposit` function:
    ```solidity
    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());
    }
    ```
1. since Alice is the first depositor (totalSupply is 0), she gets 1 share (1 wei);
1. Alice then *sends* 9999999999999999999 pxGMX tokens (10e18 - 1) to the vault;
1. the price of 1 share is 10 pxGMX tokens now: Alice is the only depositor in the vault, she's holding 1 wei of shares, and the balance of the pool is 10 pxGMX tokens;
1. Bob deposits 19 pxGMX tokens and gets only 1 share due to the rounding in the `convertToShares` function: `19e18 * 1 / 10e18 == 1`;
1. Alice redeems her share and gets a half of the deposited assets, 14.5 pxGMX tokens (less the withdrawal fee);
1. Bob redeems his share and gets only 14.5 pxGMX (less the withdrawal fee), instead of the 19 pxGMX he deposited.

```solidity
// test/AutoPxGmx.t.sol
function testSharePriceManipulation_AUDIT() external {
    address alice = address(0x31337);
    address bob = address(0x12345);
    vm.label(alice, "Alice");
    vm.label(bob, "Bob");

    // Resetting the withdrawal fee for cleaner amounts.
    autoPxGmx.setWithdrawalPenalty(0);

    vm.startPrank(address(pirexGmx));        
    pxGmx.mint(alice, 10e18);
    pxGmx.mint(bob, 19e18);
    vm.stopPrank();

    vm.startPrank(alice);
    pxGmx.approve(address(autoPxGmx), 1);
    // Alice deposits 1 wei of pxGMX and gets 1 wei of shares.
    autoPxGmx.deposit(1, alice);
    // Alice sends 10e18-1 of px
Steal deposit fund in ERC4626 vault by exchange rate manipulation
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PirexERC4626.sol#L68
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGlp.sol#L311-L315
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L394-L398
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGlp.sol#L142-L144
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L164-L166


# Vulnerability details

## Impact

Although the `PirexERC4626` and `AutoPxGlp` contract check for 0 shares, the rounding down error can still be used to steal new user deposit. Part of the new deposit could be stolen. The attacker may monitor the pool activities to catch the steal opportunities.

Part of the deposit fund from the 2nd user will be stolen by the attacker for new vault. Potentially the attacker can intentionally monitor the pool activities to find steal conditions.


## Proof of Concept


The checks for 0 share are not enough to prevent the exchange rate manipulation, just slightly better.
```solidity
File: src/vaults/PirexERC4626.sol
68:         require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

File: src/vaults/AutoPxGlp.sol
311:         if (
312:             (shares = supply == 0
313:                 ? assets
314:                 : assets.mulDivDown(supply, totalAssets() - assets)) == 0
315:         ) revert ZeroShares();

File: src/vaults/AutoPxGmx.sol
    function depositGmx(uint256 amount, address receiver) {
385:         (, uint256 assets, ) = PirexGmx(platform).depositGmx(
386:             amount,
387:             address(this)
388:         );

392:         uint256 supply = totalSupply;
393: 
394:         if (
395:             (shares = supply == 0
396:                 ? assets
397:                 : assets.mulDivDown(supply, totalAssets() - assets)) == 0
398:         ) revert ZeroShares();

File: src/PirexGmx.sol
    function depositGmx(uint256 amount, address receiver) {
388:         if (amount == 0) revert ZeroAmount();
389:         if (receiver == address(0)) revert ZeroAddress();
```


Take `depositGlp()` in AutoPxGlp.sol for example, assuming no fee. Others are analogous.
An attacker will do the following:
1. watch the mempool to monitor new AutoPxGlp ERC4626 vault deployment.
2. make sure to be the first to `depositGlp()` in the pool.
3. when a new user tries to call `depositGlp()`, the attacker will front run it, transfer some PxGlp into the AutoPxGlp vault, not through `depositGlp()` function through AutoPxGlp.sol, but direct transfer with `ERC20(GLP).transfer(address(vault), amount)`, in this way the `totalAssets` / `shares` ratio will be inflated. 
4. after the manipulation, the new user will only get 1 wei of share, but the f
Possible double spending issue for `PirexERC4626` vault
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PirexERC4626.sol#L19


# Vulnerability details

## Impact
Solmate's ERC20 does not provide option to increase/decrease allowance, and only option to do so is by setting it via `approve` - which sets this amount directly. This poses a problem of double spending, when a user want to check current allowance, and bad actor frontruns the transaction to get tokens for previous and current allowance.

## Proof of Concept
1. Alice sets Bob’s allowance to 1000 of her tokens, but sends 1100 by mistake
2. Alice realizes her mistake, and sends another transaction with correct amount (1000 tokens)
3. Malicious Bob watches the mempool for new transactions, frontruns the second allowance and transfers to himself 1100 tokens Alice sent at first, and then gets remaining 1000. So, he made it with 2100 tokens, and not 1000 as planned.

## Tools Used
VS Code

## Recommended Mitigation Steps
Use `increaseAllowance` and `decreaseAllowance` functions for your own ERC20’s.
Rewards calculation does not consider GMX reward rate fluctuation
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L289-L291
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L315-L317
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L402-L403
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PxGmxReward.sol#L53-L55
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PxGmxReward.sol#L75-L77
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PxGmxReward.sol#L121-L122


# Vulnerability details

## Impact

The current time based px rewards calculation system is not accurate, and not fair for users. Due to GMX protocol reward rate fluctuation, px users stake and claim at different time could get less or more rewards they deserve. 

Some users could abuse the rule to time the high and low GMX rewards periods, effectively steal rewards from other users. Evermore, anyone can call `claim()` for other users. Innocent users could lose px rewards unconsciously.


## Proof of Concept

Take PirexRewards.sol as example, PxGmxReward.sol is analogous.

Users rewards and `globalRewards`/`globalState.rewards` are purely time based weights:
```solidity
File: src/PirexRewards.sol
    function userAccrue(ERC20 producerToken, address user) public {
289:         uint256 rewards = u.rewards +
290:             u.lastBalance *
291:             (block.timestamp - u.lastUpdate);

    function _globalAccrue(GlobalState storage globalState, ERC20 producerToken)
315:             uint256 rewards = globalState.rewards +
316:                 (block.timestamp - lastUpdate) *
317:                 lastSupply;

File: src\vaults\PxGmxReward.sol
    function _userAccrue(address user) internal {
75:         uint256 rewards = u.rewards +
76:             u.lastBalance *
77:             (block.timestamp - u.lastUpdate);

    function _globalAccrue() internal {
53:         uint256 rewards = globalState.rewards +
54:             (block.timestamp - globalState.lastUpdate) *
55:             globalState.lastSupply;
```


The rewards users get is based on the above weights in the real claimed rewards from GMX.
```solidity
File: src\PirexRewards.sol
    function claim(ERC20 producerToken, address user) external {
402:                 uint256 rewardState = p.rewardStates[rewardToken];
403:                 uint256 amount = (rewardState * userRewards) / globalRewards;

File: src\vaults\PxGmxReward.sol
105:     function claim(address receiver) external {
121:             uint256 _rewardState = rewardState;
122:             uint256 amount = (_rewardState * userRewards) / globalRewards;
```

Assuming: 
Here use GLP as example.There are only 2 users Alice and Bob. Will
First depositor can inflate share price
Audit: 2022-11-redactedcartel-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/684627b7889e34ba7799e50074d138361f0f532b/src/vaults/AutoPxGmx.sol#L397
https://github.com/code-423n4/2022-11-redactedcartel/blob/684627b7889e34ba7799e50074d138361f0f532b/src/vaults/AutoPxGlp.sol#L314


# Vulnerability details

## Impact
A [well-known vulnerability](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706) for ERC4626 vaults is the inflation of the share price on the first deposit. Because `AutoPxGlp` and `AutoPxGmx` use the balance of the underlying asset for `totalAssets()` and do not have an initial minimum deposit amount, they are also suspectible to this attack. This will cause subsequent depositors to lose significant parts of their deposits due to rounding errors.

## Proof Of Concept
Bob deposits a very small amount of GMX such that he gets 1 wei of pxGMX. Afterwards, he transfers 1e18 pxGMX to the vault address. `totalAssets()` is defined like that:
```solidity
		/**
        @notice Get the pxGMX custodied by the AutoPxGmx contract
        @return uint256  Amount of pxGMX custodied by the autocompounder
     */
    function totalAssets() public view override returns (uint256) {
        return asset.balanceOf(address(this));
    }
```
It will therefore now return 1e18 + 1.

When Alice now deposits 2e18 pxGMX, the following calculation will be performed:
```solidity
assets.mulDivDown(supply, totalAssets() - assets)
= 2e18 * 1 / (1e18 + 1) = 1
```
Therefore, she receives only 1 share and ~1e18 pxGMX are lost due to rounding.

## Recommended Mitigation Steps
There are multiple mitigations (minimium initial deposit, internal total assets, creating dead shares), see the OpenZeppelin issue for an extensive discussion: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706