creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/MinterProxyV2.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.9;\n\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(\n        address indexed previousOwner,\n        address indexed newOwner\n    );\n\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(\n            newOwner != address(0),\n            \"Ownable: new owner is the zero address\"\n        );\n        _transferOwnership(newOwner);\n    }\n\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\nabstract contract Controller is Ownable {\n    event ControllerAdded(address controller);\n    event ControllerRemoved(address controller);\n    mapping(address => bool) controllers;\n    uint8 public controllerCnt = 0;\n\n    modifier onlyController() {\n        require(isController(_msgSender()), \"no controller rights\");\n        _;\n    }\n\n    function isController(address _controller) public view returns (bool) {\n        return _controller == owner() || controllers[_controller];\n    }\n\n    function addController(address _controller) public onlyOwner {\n        if (controllers[_controller] == false) {\n            controllers[_controller] = true;\n            controllerCnt++;\n        }\n        emit ControllerAdded(_controller);\n    }\n\n    function removeController(address _controller) public onlyOwner {\n        if (controllers[_controller] == true) {\n            controllers[_controller] = false;\n            controllerCnt--;\n        }\n        emit ControllerRemoved(_controller);\n    }\n}\n\nabstract contract ReentrancyGuard {\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        _status = _NOT_ENTERED;\n    }\n\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n}\n\ninterface IERC20 {\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address account) external view returns (uint256);\n\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    function allowance(\n        address owner,\n        address spender\n    ) external view returns (uint256);\n\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n\ninterface IERC20Permit {\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    function nonces(address owner) external view returns (uint256);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\nlibrary Address {\n    function isContract(address account) internal view returns (bool) {\n        return account.code.length > 0;\n    }\n\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(\n            address(this).balance >= amount,\n            \"Address: insufficient balance\"\n        );\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(\n            success,\n            \"Address: unable to send value, recipient may have reverted\"\n        );\n    }\n\n    function functionCall(\n        address target,\n        bytes memory data\n    ) internal returns (bytes memory) {\n        return\n            functionCallWithValue(\n                target,\n                data,\n                0,\n                \"Address: low-level call failed\"\n            );\n    }\n\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return\n            functionCallWithValue(\n                target,\n                data,\n                value,\n                \"Address: low-level call with value failed\"\n            );\n    }\n\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(\n            address(this).balance >= value,\n            \"Address: insufficient balance for call\"\n        );\n        (bool success, bytes memory returndata) = target.call{value: value}(\n            data\n        );\n        return\n            verifyCallResultFromTarget(\n                target,\n                success,\n                returndata,\n                errorMessage\n            );\n    }\n\n    function functionStaticCall(\n        address target,\n        bytes memory data\n    ) internal view returns (bytes memory) {\n        return\n            functionStaticCall(\n                target,\n                data,\n                \"Address: low-level static call failed\"\n            );\n    }\n\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return\n            verifyCallResultFromTarget(\n                target,\n                success,\n                returndata,\n                errorMessage\n            );\n    }\n\n    function functionDelegateCall(\n        address target,\n        bytes memory data\n    ) internal returns (bytes memory) {\n        return\n            functionDelegateCall(\n                target,\n                data,\n                \"Address: low-level delegate call failed\"\n            );\n    }\n\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return\n            verifyCallResultFromTarget(\n                target,\n                success,\n                returndata,\n                errorMessage\n            );\n    }\n\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(\n        bytes memory returndata,\n        string memory errorMessage\n    ) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n\ninterface IWrapToken {\n    function deposit() external payable;\n    function withdraw(uint256) external;\n}\n\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(\n            token,\n            abi.encodeWithSelector(token.transfer.selector, to, value)\n        );\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(\n            token,\n            abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n        );\n    }\n\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(\n            token,\n            abi.encodeWithSelector(token.approve.selector, spender, value)\n        );\n    }\n\n    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(\n            token,\n            abi.encodeWithSelector(\n                token.approve.selector,\n                spender,\n                oldAllowance + value\n            )\n        );\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(\n                oldAllowance >= value,\n                \"SafeERC20: decreased allowance below zero\"\n            );\n            _callOptionalReturn(\n                token,\n                abi.encodeWithSelector(\n                    token.approve.selector,\n                    spender,\n                    oldAllowance - value\n                )\n            );\n        }\n    }\n\n    function forceApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(\n            token.approve.selector,\n            spender,\n            value\n        );\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(\n                token,\n                abi.encodeWithSelector(token.approve.selector, spender, 0)\n            );\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(\n            nonceAfter == nonceBefore + 1,\n            \"SafeERC20: permit did not succeed\"\n        );\n    }\n\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        bytes memory returndata = address(token).functionCall(\n            data,\n            \"SafeERC20: low-level call failed\"\n        );\n        require(\n            returndata.length == 0 || abi.decode(returndata, (bool)),\n            \"SafeERC20: ERC20 operation did not succeed\"\n        );\n    }\n\n    function _callOptionalReturnBool(\n        IERC20 token,\n        bytes memory data\n    ) private returns (bool) {\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success &&\n            (returndata.length == 0 || abi.decode(returndata, (bool))) &&\n            Address.isContract(address(token));\n    }\n}\n\nlibrary TransferHelper {\n    function safeTransferNative(address to, uint256 value) internal {\n        (bool success, ) = to.call{value: value}(new bytes(0));\n        require(success, \"TransferHelper: NATIVE_TRANSFER_FAILED\");\n    }\n}\n\ninterface IMintBurnToken {\n    function mint(address to, uint256 amount) external;\n\n    function burn(address from, uint256 amount) external;\n}\n\ncontract MinterProxyV2 is Controller, ReentrancyGuard {\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using Address for address payable;\n\n    address public immutable NATIVE =\n        0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n    address public wNATIVE;\n\n    uint256 MAX_UINT256 =\n        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n    mapping(uint256 => bool) public completedOrder;\n\n    address public _liquidpool;\n\n    uint256 public _orderID;\n\n    bool private _paused;\n\n    event Paused(address account);\n\n    event Unpaused(address account);\n\n    event LogVaultIn(\n        address indexed token,\n        uint256 indexed orderID,\n        address indexed receiver,\n        uint256 amount,\n        uint256 serviceFee,\n        uint256 gasFee\n    );\n    event LogVaultOut(\n        address indexed token,\n        address indexed from,\n        uint256 indexed orderID,\n        uint256 amount,\n        address vault,\n        bytes order\n    );\n\n    event LogVaultCall(\n        address indexed target,\n        uint256 amount,\n        bool success,\n        bytes reason\n    );\n\n    constructor(uint256 _id_prefix, address _lp, address _wNative) {\n        _liquidpool = _lp;\n        _paused = false;\n        _orderID = _id_prefix * (10 ** 9);\n        wNATIVE = _wNative;\n    }\n\n    receive() external payable {}\n\n    fallback() external payable {}\n\n    modifier whenNotPaused() {\n        require(!_paused, \"MP: paused\");\n        _;\n    }\n\n    function chainID() public view returns (uint) {\n        return block.chainid;\n    }\n\n    function setLiquidpool(address _lp) external onlyOwner {\n        _liquidpool = _lp;\n    }\n\n    function setWrapNative(address _wNative) external onlyOwner {\n        wNATIVE = _wNative;\n    }\n\n    function needWrapNative() internal view returns (bool) {\n        return wNATIVE != address(0);\n    }\n\n    function liquidpool() internal view returns (address) {\n        if (_liquidpool != address(0)) {\n            return _liquidpool;\n        }\n        return address(this);\n    }\n\n    function pause() external onlyOwner {\n        _paused = true;\n        emit Paused(_msgSender());\n    }\n\n    function unpause() external onlyOwner {\n        _paused = false;\n        emit Unpaused(_msgSender());\n    }\n\n    function _isSelfLiquidpool() internal view returns (bool) {\n        return address(this) == liquidpool();\n    }\n\n    function isUUIDCompleted(uint256 uuid) external view returns (bool) {\n        return completedOrder[uuid];\n    }\n\n    function _registerOrder(uint256 uuid) internal {\n        require(!completedOrder[uuid], \"MP: already completed\");\n        completedOrder[uuid] = true;\n    }\n\n    function _balanceOf(address receiveToken) internal view returns (uint256) {\n        uint256 _balance;\n        if (receiveToken == NATIVE) {\n            if (needWrapNative()) {\n                _balance = IERC20(wNATIVE).balanceOf(liquidpool());\n            } else {\n                _balance = address(this).balance;\n            }\n        } else {\n            _balance = IERC20(receiveToken).balanceOf(liquidpool());\n        }\n        return _balance;\n    }\n\n    function _balanceOfSelf(\n        address receiveToken\n    ) internal view returns (uint256) {\n        uint256 _balance;\n        if (receiveToken == NATIVE) {\n            _balance = address(this).balance;\n        } else {\n            _balance = IERC20(receiveToken).balanceOf(address(this));\n        }\n        return _balance;\n    }\n\n    function _checkVaultOut(\n        address tokenAddr,\n        uint256 amount,\n        bytes calldata order\n    ) internal pure {\n        require(tokenAddr != address(0), \"MP: tokenAddress is invalid\");\n        require(amount > 0, \"MP: amount is 0\");\n        require(order.length > 0, \"MP: order is empty\");\n    }\n\n    function vaultOut(\n        address tokenAddr,\n        uint256 amount,\n        bool burnable,\n        bytes calldata order\n    ) external payable nonReentrant whenNotPaused {\n        _checkVaultOut(tokenAddr, amount, order);\n\n        if (tokenAddr == NATIVE) {\n            require(amount == msg.value, \"MP: amount is invalid\");\n            if (needWrapNative()) {\n                uint256 old = IERC20(wNATIVE).balanceOf(address(this));\n                IWrapToken(wNATIVE).deposit{value: msg.value}();\n                uint256 val = IERC20(wNATIVE).balanceOf(address(this));\n                require(val - old == amount, \"MP: warp token dismatch\");\n                if (!_isSelfLiquidpool()) {\n                    IERC20(wNATIVE).safeTransfer(_liquidpool, amount);\n                }\n            } else {\n                if (!_isSelfLiquidpool()) {\n                    TransferHelper.safeTransferNative(_liquidpool, amount);\n                }\n            }\n        } else if (burnable) {\n            uint256 old = IERC20(tokenAddr).balanceOf(_msgSender());\n            IMintBurnToken(tokenAddr).burn(_msgSender(), amount);\n            uint256 val = IERC20(tokenAddr).balanceOf(_msgSender());\n            require(val == old - amount, \"MP: burn failed\");\n        } else {\n            IERC20(tokenAddr).safeTransferFrom(\n                _msgSender(),\n                liquidpool(),\n                amount\n            );\n        }\n\n        _orderID++;\n        emit LogVaultOut(\n            tokenAddr,\n            _msgSender(),\n            _orderID,\n            amount,\n            burnable ? address(0) : liquidpool(),\n            order\n        );\n    }\n\n    function swap(\n        address tokenAddr,\n        uint256 amount,\n        address target,\n        address receiveToken,\n        address receiver,\n        uint256 minAmount,\n        bytes calldata callData,\n        bytes calldata order\n    ) external payable nonReentrant whenNotPaused {\n        _checkVaultOut(tokenAddr, amount, order);\n        require(\n            target != address(this) && target != address(0),\n            \"MP: target is invalid\"\n        );\n        require(callData.length > 0, \"MP: calldata is empty\");\n        require(receiveToken != address(0), \"MP: receiveToken is empty\");\n        require(receiver != address(0), \"MP: receiver is empty\");\n        require(minAmount > 0, \"MP: minAmount is empty\");\n\n        uint256 old_balance = _balanceOfSelf(receiveToken);\n        if (tokenAddr == NATIVE) {\n            require(amount == msg.value, \"MP: amount is invalid\");\n            target.functionCallWithValue(\n                callData,\n                amount,\n                \"MP: CallWithValue failed\"\n            );\n        } else {\n            IERC20(tokenAddr).safeTransferFrom(\n                _msgSender(),\n                address(this),\n                amount\n            );\n            if (IERC20(tokenAddr).allowance(address(this), target) < amount) {\n                IERC20(tokenAddr).safeApprove(target, MAX_UINT256);\n            }\n            target.functionCall(callData, \"MP: FunctionCall failed\");\n        }\n\n        uint256 _amountOut = 0;\n\n        uint256 new_balance = _balanceOfSelf(receiveToken);\n        require(\n            new_balance > old_balance,\n            \"MP: receive amount should above zero\"\n        );\n        _amountOut = new_balance - old_balance;\n\n        require(_amountOut >= minAmount, \"MP: receive amount not enough\");\n        if (receiveToken == NATIVE) {\n            TransferHelper.safeTransferNative(receiver, _amountOut);\n        } else {\n            IERC20(receiveToken).safeTransfer(receiver, _amountOut);\n        }\n\n        _orderID++;\n        emit LogVaultOut(\n            receiveToken,\n            _msgSender(),\n            _orderID,\n            _amountOut,\n            receiver,\n            order\n        );\n    }\n\n    function vaultIn(\n        uint256 orderID,\n        address receiveToken,\n        address receiver,\n        bool burnable,\n        uint256 amount\n    ) external onlyController whenNotPaused {\n        require(orderID > 0, \"MP: orderID empty\");\n        require(receiver != address(0), \"MP: receiver invaild\");\n        require(amount > 0, \"MP: amount is empty\");\n        if (!burnable) {\n            require(\n                _balanceOf(receiveToken) >= amount,\n                \"MP: insufficient balance\"\n            );\n        }\n        _registerOrder(orderID);\n        if (receiveToken == NATIVE) {\n            if (needWrapNative()) {\n                if (_isSelfLiquidpool()) {\n                    IERC20(wNATIVE).safeTransfer(receiver, amount);\n                } else {\n                    IERC20(wNATIVE).safeTransferFrom(\n                        liquidpool(),\n                        receiver,\n                        amount\n                    );\n                }\n            } else {\n                TransferHelper.safeTransferNative(receiver, amount);\n            }\n        } else if (burnable) {\n            uint256 old = IERC20(receiveToken).balanceOf(receiver);\n            IMintBurnToken(receiveToken).mint(receiver, amount);\n            uint256 val = IERC20(receiveToken).balanceOf(receiver);\n            require(val == old + amount, \"MP: mint failed\");\n        } else {\n            if (_isSelfLiquidpool()) {\n                IERC20(receiveToken).safeTransfer(receiver, amount);\n            } else {\n                IERC20(receiveToken).safeTransferFrom(\n                    liquidpool(),\n                    receiver,\n                    amount\n                );\n            }\n        }\n        emit LogVaultIn(receiveToken, orderID, receiver, amount, 0, 0);\n    }\n\n    // Fees[] struct\n    // 0: uint256 expectAmount\n    // 1: uint256 minAmount\n    // 2: uint256 feeRate\n    // 3: uint256 gasFee\n    function vaultInAndCall(\n        uint256 orderID,\n        address tokenAddr,\n        address toAddr,\n        bool burnable,\n        uint256 amount,\n        address receiver,\n        address receiveToken,\n        uint256[] memory fees,\n        bytes calldata data\n    ) external onlyController whenNotPaused {\n        require(orderID > 0, \"MP: orderID empty\");\n        require(data.length > 0, \"MP: data empty\");\n        require(fees.length == 4, \"MP: fees mismatch\");\n        require(amount > 0, \"MP: amount is empty\");\n        require(fees[1] > 0, \"MP: minAmount is empty\");\n        require(fees[0] > 0, \"MP: expectAmount is empty\");\n        if (!burnable) {\n            require(\n                _balanceOf(tokenAddr) >= amount,\n                \"MP: insufficient balance\"\n            );\n        }\n        require(receiver != address(0), \"MP: receiver is empty\");\n        require(\n            toAddr != address(this) && toAddr != address(0),\n            \"MP: toAddr invaild\"\n        );\n        _registerOrder(orderID);\n        bool fromTokenNative = (tokenAddr == NATIVE);\n        if (fromTokenNative) {\n            if (needWrapNative()) {\n                if (!_isSelfLiquidpool()) {\n                    IERC20(wNATIVE).safeTransferFrom(\n                        liquidpool(),\n                        address(this),\n                        amount\n                    );\n                }\n                uint256 old = address(this).balance;\n                IWrapToken(wNATIVE).withdraw(amount);\n                uint256 val = address(this).balance;\n                require(\n                    val - old == amount,\n                    \"MP: native token amount dismatch\"\n                );\n            } else {\n                // the native token in this contract, so ignore\n                require(\n                    address(this).balance >= amount,\n                    \"MP: native token insuffient\"\n                );\n            }\n        } else {\n            if (burnable) {\n                uint256 old = IERC20(tokenAddr).balanceOf(address(this));\n                IMintBurnToken(tokenAddr).mint(address(this), amount);\n                uint256 val = IERC20(tokenAddr).balanceOf(address(this));\n                require(val == old + amount, \"MP: mint failed\");\n            } else {\n                if (!_isSelfLiquidpool()) {\n                    IERC20(tokenAddr).safeTransferFrom(\n                        _liquidpool,\n                        address(this),\n                        amount\n                    );\n                }\n            }\n            if (IERC20(tokenAddr).allowance(address(this), toAddr) < amount) {\n                IERC20(tokenAddr).safeApprove(toAddr, MAX_UINT256);\n            }\n        }\n\n        (uint256 realOut, uint256 fee) = _callAndTransfer(\n            toAddr,\n            fromTokenNative ? amount : 0,\n            receiver,\n            receiveToken,\n            fees,\n            data\n        );\n        uint256 totalfee = fee + fees[3];\n        if (totalfee > 0) {\n            if (receiveToken == NATIVE) {\n                if (needWrapNative()) {\n                    IWrapToken(wNATIVE).deposit{value: totalfee}();\n                    if (!_isSelfLiquidpool()) {\n                        IERC20(wNATIVE).safeTransfer(_liquidpool, totalfee);\n                    }\n                }\n            } else {\n                IERC20(receiveToken).safeTransfer(_liquidpool, totalfee);\n            }\n        }\n\n        emit LogVaultIn(receiveToken, orderID, receiver, realOut, fee, fees[3]);\n    }\n\n    // Fees[] struct\n    // 0: uint256 expectAmount\n    // 1: uint256 minAmount\n    // 2: uint256 feeRate\n    // 3: uint256 gasFee\n    function _callAndTransfer(\n        address contractAddr,\n        uint256 fromNativeAmount,\n        address receiver,\n        address receiveToken,\n        uint256[] memory fees,\n        bytes calldata data\n    ) internal returns (uint256, uint256) {\n        uint256 old_balance = _balanceOfSelf(receiveToken);\n\n        if (fromNativeAmount > 0) {\n            contractAddr.functionCallWithValue(\n                data,\n                fromNativeAmount,\n                \"MP: CallWithValue failed\"\n            );\n        } else {\n            contractAddr.functionCall(data, \"MP: FunctionCall failed\");\n        }\n        uint256 real = 0;\n        uint256 fee = 0;\n        {\n            uint256 expectAmount = fees[0];\n            uint256 minAmount = fees[1];\n            uint256 feeRate = fees[2];\n            uint256 gasFee = fees[3];\n            uint256 new_balance = _balanceOfSelf(receiveToken);\n            require(\n                new_balance > old_balance,\n                \"MP: receiver should get assets\"\n            );\n            uint256 amountOut = new_balance - old_balance;\n            require(amountOut >= minAmount, \"MP: receive amount not enough\");\n            require(amountOut >= minAmount + gasFee, \"MP: gasFee not enough\");\n\n            fee = (amountOut / 10000) * feeRate;\n\n            require(\n                amountOut >= minAmount + gasFee + fee,\n                \"MP: fee not enough\"\n            );\n            real = amountOut - fee - gasFee;\n            real = real > expectAmount ? expectAmount : real;\n        }\n\n        if (receiver != address(this)) {\n            if (receiveToken == NATIVE) {\n                TransferHelper.safeTransferNative(receiver, real);\n            } else {\n                IERC20(receiveToken).safeTransfer(receiver, real);\n            }\n        }\n        return (real, fee);\n    }\n\n    function call(\n        address target,\n        bytes calldata _data\n    ) external payable onlyOwner {\n        (bool success, bytes memory result) = target.call{value: msg.value}(\n            _data\n        );\n        emit LogVaultCall(target, msg.value, success, result);\n    }\n\n    function withdrawFee(\n        address token,\n        address receiver,\n        uint256 amount\n    ) external onlyOwner {\n        if (token == NATIVE) {\n            uint256 balance = address(this).balance;\n            uint256 tmp = balance > amount ? amount : balance;\n            TransferHelper.safeTransferNative(receiver, tmp);\n        } else {\n            uint256 balance = IERC20(token).balanceOf(address(this));\n            uint256 tmp = balance > amount ? amount : balance;\n            IERC20(token).safeTransfer(receiver, tmp);\n        }\n    }\n\n    function mintTo(\n        address tokenAddr,\n        address receiver,\n        uint256 amount\n    ) external onlyController {\n        uint256 old = IERC20(tokenAddr).balanceOf(receiver);\n        IMintBurnToken(tokenAddr).mint(receiver, amount);\n        uint256 val = IERC20(tokenAddr).balanceOf(receiver);\n        require(val == old + amount, \"MP: mint failed\");\n    }\n\n    bytes4 constant CONTROLLER = 0xf77c4791;\n    bytes4 constant IS_CONTROLLER = 0xb429afeb;\n\n    function isMinter(address _contract) external view returns (bool) {\n        (bool success, address result) = _getMinter(_contract);\n        if (success && (result == address(this))) {\n            return true;\n        }\n\n        (bool success1, bool ok) = _isMinter(_contract, address(this));\n        if (success1 && ok) {\n            return true;\n        }\n        return false;\n    }\n\n    function isMinterWithData(\n        address _contract,\n        bytes memory data,\n        bytes memory expectRes\n    ) external view returns (bool) {\n        (bool success, address result) = _getMinter(_contract);\n        if (success && (result == address(this))) {\n            return true;\n        }\n\n        (bool success1, bool ok) = _isMinter(_contract, address(this));\n        if (success1 && ok) {\n            return true;\n        }\n        if (data.length > 0) {\n            (bool success2, bytes memory returndata) = _contract.staticcall(\n                data\n            );\n            return success2 && bytesEqual(returndata, expectRes);\n        }\n        return false;\n    }\n\n    function _getMinter(\n        address _contract\n    ) internal view returns (bool, address) {\n        (bool success, bytes memory returndata) = _contract.staticcall(\n            abi.encodeWithSelector(CONTROLLER)\n        );\n        return (success, bytesToAddress(returndata));\n    }\n\n    function _isMinter(\n        address _contract,\n        address _target\n    ) internal view returns (bool, bool) {\n        (bool success, bytes memory returndata) = _contract.staticcall(\n            abi.encodeWithSelector(IS_CONTROLLER, _target)\n        );\n\n        (bool ok, uint res) = toUint(returndata);\n        return (success && ok, res == 1);\n    }\n\n    function toUint(bytes memory bs) internal pure returns (bool, uint) {\n        if (bs.length < 32) {\n            return (false, 0);\n        }\n        uint x;\n        assembly {\n            x := mload(add(bs, add(0x20, 0)))\n        }\n        return (true, x);\n    }\n\n    function bytesToAddress(\n        bytes memory bys\n    ) internal pure returns (address addr) {\n        assembly {\n            addr := mload(add(bys, 32))\n        }\n    }\n\n    function bytesEqual(\n        bytes memory a,\n        bytes memory b\n    ) public pure returns (bool) {\n        return keccak256(a) == keccak256(b);\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 1000
      },
      "evmVersion": "london",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}