/* Copyright 2020 DODO ZOO. SPDX-License-Identifier: Apache-2.0 */ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; import {DPPVault} from "./DPPVault.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {PMMPricing} from "../../lib/PMMPricing.sol"; import {IDODOCallee} from "../../intf/IDODOCallee.sol"; contract DPPTrader is DPPVault { using SafeMath for uint256; // ============ Modifiers ============ modifier isBuyAllow(address trader) { require(!_BUYING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), "TRADER_BUY_NOT_ALLOWED"); _; } modifier isSellAllow(address trader) { require( !_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), "TRADER_SELL_NOT_ALLOWED" ); _; } modifier limitGasPrice() { require(tx.gasprice <= _GAS_PRICE_LIMIT_.get(), "GAS_PRICE_EXCEED"); _; } // ============ Trade Functions ============ function sellBase(address to) external preventReentrant limitGasPrice isSellAllow(to) returns (uint256 receiveQuoteAmount) { uint256 baseInput = getBaseInput(); uint256 mtFee; uint256 newBaseTarget; PMMPricing.RState newRState; (receiveQuoteAmount, mtFee, newRState, newBaseTarget) = querySellBase(tx.origin, baseInput); _transferQuoteOut(to, receiveQuoteAmount); _transferQuoteOut(_MAINTAINER_, mtFee); // update TARGET if (_RState_ != newRState) { _RState_ = newRState; _BASE_TARGET_ = newBaseTarget; } _syncReserve(); return receiveQuoteAmount; } function sellQuote(address to) external preventReentrant limitGasPrice isBuyAllow(to) returns (uint256 receiveBaseAmount) { uint256 quoteInput = getQuoteInput(); uint256 mtFee; uint256 newQuoteTarget; PMMPricing.RState newRState; (receiveBaseAmount, mtFee, newRState, newQuoteTarget) = querySellQuote( tx.origin, quoteInput ); _transferBaseOut(to, receiveBaseAmount); _transferBaseOut(_MAINTAINER_, mtFee); // update TARGET if (_RState_ != newRState) { _RState_ = newRState; _QUOTE_TARGET_ = newQuoteTarget; } _syncReserve(); return receiveBaseAmount; } function flashLoan( uint256 baseAmount, uint256 quoteAmount, address assetTo, bytes calldata data ) external preventReentrant { _transferBaseOut(assetTo, baseAmount); _transferQuoteOut(assetTo, quoteAmount); if (data.length > 0) IDODOCallee(assetTo).DPPFlashLoanCall(msg.sender, baseAmount, quoteAmount, data); uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); // no input -> pure loss require( baseBalance >= _BASE_RESERVE_ || quoteBalance >= _QUOTE_RESERVE_, "FLASH_LOAN_FAILED" ); // no output -> pure profit if (baseBalance >= _BASE_RESERVE_ && quoteBalance >= _QUOTE_RESERVE_) return; // sell quote case // quote input + base output if (baseBalance < _BASE_RESERVE_) { ( uint256 receiveBaseAmount, uint256 mtFee, PMMPricing.RState newRState, uint256 newQuoteTarget ) = querySellQuote(tx.origin, quoteBalance.sub(_QUOTE_RESERVE_)); // revert if quoteBalance