Skip to content

Latest commit

 

History

History
136 lines (103 loc) · 4.71 KB

File metadata and controls

136 lines (103 loc) · 4.71 KB

Fast Khaki Raccoon

High

flashMint would mint the admins an enourmous amounts of fees, leading to TX reverting in most cases

Summary

flashMint upon minting to the user would mint an enormous amounts of fees to the admin, due to _mint invoking _update with the flash loan amount.

    function flashMint(address _recipient, uint256 _amount, bytes calldata _data) external override lock {
        _shortCircuitRewards = 1;
        uint256 _fee = _amount / 1000;
        _mint(_recipient, _amount); // @audit it would trigger update and mint the admins fees from transfers that are not of "real" tokens
    function _update(address _from, address _to, uint256 _amount) internal override {
        require(!_blacklist[_to], "BK");

        bool _buy = _from == V2_POOL && _to != V2_ROUTER;
        bool _sell = _to == V2_POOL;
        uint256 _fee;

        if (_swapping == 0 && _swapAndFeeOn == 1) {
            if (_from != V2_POOL) {
                _processPreSwapFeesAndSwap();
            }
            if (_buy && _fees.buy > 0) {
                _fee = (_amount * _fees.buy) / DEN;
                super._update(_from, address(this), _fee);
            } else if (_sell && _fees.sell > 0) {
                _fee = (_amount * _fees.sell) / DEN;
                super._update(_from, address(this), _fee);

            //@audit right here
            } else if (!_buy && !_sell && _config.hasTransferTax) {
                _fee = _amount / 10000; // 0.01%
                _fee = _fee == 0 && _amount > 0 
                    ? 1 
                    : _fee;
                super._update(_from, address(this), _fee);
            }
        }

        _processBurnFee(_fee);
        super._update(_from, _to, _amount - _fee);
    }

This is dangerous as these transfers are not from "real" tokens, but ones that are used for 1 time use during rush moments, like liquidations, leveraging and so on...

Note that the same happens in burn, which is also invoked inside this function. This would not only cause the fee to be higher, but also to be taken 2 times, as both mint and burn would charge it.

        _mint(_recipient, _amount);
        IFlashLoanRecipient(_recipient).callback(_data);
        _burn(_recipient, _amount);

Root Cause

_mint triggers _update minting an enormous amounts of fees, reducing the FL amount that our user receives, leading to his inability to repay the loan and the TX reverting.

https://github.com/sherlock-audit/2025-01-peapods-finance/blob/main/contracts/contracts/DecentralizedIndex.sol#L427

    function flashMint(address _recipient, uint256 _amount, bytes calldata _data) external override lock {
        _shortCircuitRewards = 1;
        uint256 _fee = _amount / 1000;
        _mint(_recipient, _amount); // @audit it would trigger update and mint the admins fees from transfers that are not of "real" tokens

https://github.com/sherlock-audit/2025-01-peapods-finance/blob/main/contracts/contracts/DecentralizedIndex.sol#L174-L177

    function _update(address _from, address _to, uint256 _amount) internal override {
        require(!_blacklist[_to], "BK");

        bool _buy = _from == V2_POOL && _to != V2_ROUTER;
        bool _sell = _to == V2_POOL;
        uint256 _fee;

        if (_swapping == 0 && _swapAndFeeOn == 1) {
            if (_from != V2_POOL) {
                _processPreSwapFeesAndSwap();
            }
            if (_buy && _fees.buy > 0) {
                _fee = (_amount * _fees.buy) / DEN;
                super._update(_from, address(this), _fee);
            } else if (_sell && _fees.sell > 0) {
                _fee = (_amount * _fees.sell) / DEN;
                super._update(_from, address(this), _fee);

            //@audit right here
            } else if (!_buy && !_sell && _config.hasTransferTax) {
                _fee = _amount / 10000; // 0.01%
                _fee = _fee == 0 && _amount > 0 
                    ? 1 
                    : _fee;
                super._update(_from, address(this), _fee);
            }
        }

        _processBurnFee(_fee);
        super._update(_from, _to, _amount - _fee);
    }

Internal Pre-conditions

No response

External Pre-conditions

No response

Attack Path

  1. User uses flashmint to perform some kind of arbitrage
  2. Needs 10m
  3. Fees are 0.1%, so 10k gets minted to the admin as a fee
  4. User is unable to repay the loan, so the TX reverts

Impact

Users unable to use flash-loans due to _mint triggering _update which would mint percentage fee to the system. FL revert in most cases. Fee is taken 2 times, as mint and burn would take a part each time they are invoked.

PoC

No response

Mitigation

Don't charge percentage based fees on FL.