Skip to content

Latest commit

 

History

History
83 lines (63 loc) · 3.68 KB

File metadata and controls

83 lines (63 loc) · 3.68 KB

Fantasm Finance

Step-by-step

  1. Call mint without providing any backing for your mint
  2. Profit

Detailed Description

As most tokens, you can mint Fantasm on some conditions. Particularly, Fantasm wanted to ask for some native tokens _ftmIn and some amount of an extra token _fantasmIn to mint some XFTM.

So, in short, you need to give FTM (native token) and FXM (non-native, is burned) to mint some XFTM.

The problem is that the mint function never checks for the amount of FMT deposited, allowing the attacker to mint with only FXM.

    function mint(uint256 _fantasmIn, uint256 _minXftmOut) external payable nonReentrant {
        require(!mintPaused, "Pool::mint: Minting is paused");
        uint256 _ftmIn = msg.value;
        address _minter = msg.sender;

        // This is  supposed to mint. There are three parameters:
        // 1. Native token passed `_ftmIn`
        // 2. _fantasmIn an amount
        // 3.`_minXftmOut` slippage protection
        // What you say here is "Giving you _ftmIn native, I want at least minXftmOut, and I will put _fantasmIn as collateral"

        (uint256 _xftmOut, , uint256 _minFantasmIn, uint256 _ftmFee) = calcMint(_ftmIn, _fantasmIn);
        require(_minXftmOut <= _xftmOut, "Pool::mint: slippage");
        require(_minFantasmIn <= _fantasmIn, "Pool::mint: Not enough Fantasm input");
        require(maxXftmSupply >= xftm.totalSupply() + _xftmOut, "Pool::mint: > Xftm supply limit");

        WethUtils.wrap(_ftmIn);
        userInfo[_minter].lastAction = block.number;

        if (_xftmOut > 0) {
            userInfo[_minter].xftmBalance = userInfo[_minter].xftmBalance + _xftmOut;
            unclaimedXftm = unclaimedXftm + _xftmOut;
        }

        if (_minFantasmIn > 0) {
            fantasm.safeTransferFrom(_minter, address(this), _minFantasmIn);
            fantasm.burn(_minFantasmIn);
        }

        if (_ftmFee > 0) {
            WethUtils.transfer(feeReserve, _ftmFee);
        }
        
        emit Mint(_minter, _xftmOut, _ftmIn, _fantasmIn, _ftmFee);
    }

Possible mitigations

  1. The obvious recommendation here is "check that counterpart token is received", but...
  2. ... this can be covered by a test. Make sure to have negative testing as part of the suite of your contract, with tests that check that "should not mint XFTM without backing native token"

Diagrams and graphs

Class

class

Sources and references