add dppOracle
This commit is contained in:
255
contracts/DODOPrivatePool/impl/DPPOracle/DPPTrader.sol
Normal file
255
contracts/DODOPrivatePool/impl/DPPOracle/DPPTrader.sol
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
|
||||
Copyright 2021 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";
|
||||
import {IOracle} from "../../intf/IOracle.sol";
|
||||
|
||||
contract DPPTrader is DPPVault {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// ============ Events ============
|
||||
|
||||
event DODOSwap(
|
||||
address fromToken,
|
||||
address toToken,
|
||||
uint256 fromAmount,
|
||||
uint256 toAmount,
|
||||
address trader,
|
||||
address receiver
|
||||
);
|
||||
|
||||
event DODOFlashLoan(
|
||||
address borrower,
|
||||
address assetTo,
|
||||
uint256 baseAmount,
|
||||
uint256 quoteAmount
|
||||
);
|
||||
|
||||
event RChange(PMMPricing.RState newRState);
|
||||
|
||||
modifier isOraclePriceValid() {
|
||||
(, bool isValid, bool isStale,) = IOracle(_I_).getPrice(address(_BASE_TOKEN_));
|
||||
require(isValid, "ORACLE_PRICE_INVALID");
|
||||
require(!isStale, "ORACLE_PRICE_STALE");
|
||||
_;
|
||||
}
|
||||
|
||||
// ============ Trade Functions ============
|
||||
|
||||
function sellBase(address to)
|
||||
external
|
||||
preventReentrant
|
||||
isOraclePriceValid
|
||||
returns (uint256 receiveQuoteAmount)
|
||||
{
|
||||
uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this));
|
||||
uint256 baseInput = baseBalance.sub(uint256(_BASE_RESERVE_));
|
||||
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_ != uint32(newRState)) {
|
||||
require(newBaseTarget <= uint112(-1),"OVERFLOW");
|
||||
_BASE_TARGET_ = uint112(newBaseTarget);
|
||||
_RState_ = uint32(newRState);
|
||||
emit RChange(newRState);
|
||||
}
|
||||
|
||||
_setReserve(baseBalance, _QUOTE_TOKEN_.balanceOf(address(this)));
|
||||
|
||||
emit DODOSwap(
|
||||
address(_BASE_TOKEN_),
|
||||
address(_QUOTE_TOKEN_),
|
||||
baseInput,
|
||||
receiveQuoteAmount,
|
||||
msg.sender,
|
||||
to
|
||||
);
|
||||
}
|
||||
|
||||
function sellQuote(address to)
|
||||
external
|
||||
preventReentrant
|
||||
isOraclePriceValid
|
||||
returns (uint256 receiveBaseAmount)
|
||||
{
|
||||
uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this));
|
||||
uint256 quoteInput = quoteBalance.sub(uint256(_QUOTE_RESERVE_));
|
||||
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_ != uint32(newRState)) {
|
||||
require(newQuoteTarget <= uint112(-1),"OVERFLOW");
|
||||
_QUOTE_TARGET_ = uint112(newQuoteTarget);
|
||||
_RState_ = uint32(newRState);
|
||||
emit RChange(newRState);
|
||||
}
|
||||
|
||||
_setReserve(_BASE_TOKEN_.balanceOf(address(this)), quoteBalance);
|
||||
|
||||
emit DODOSwap(
|
||||
address(_QUOTE_TOKEN_),
|
||||
address(_BASE_TOKEN_),
|
||||
quoteInput,
|
||||
receiveBaseAmount,
|
||||
msg.sender,
|
||||
to
|
||||
);
|
||||
}
|
||||
|
||||
function flashLoan(
|
||||
uint256 baseAmount,
|
||||
uint256 quoteAmount,
|
||||
address _assetTo,
|
||||
bytes calldata data
|
||||
) external isOraclePriceValid preventReentrant {
|
||||
address assetTo = _assetTo;
|
||||
_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"
|
||||
);
|
||||
|
||||
// sell quote case
|
||||
// quote input + base output
|
||||
if (baseBalance < _BASE_RESERVE_) {
|
||||
uint256 quoteInput = quoteBalance.sub(uint256(_QUOTE_RESERVE_));
|
||||
(
|
||||
uint256 receiveBaseAmount,
|
||||
uint256 mtFee,
|
||||
PMMPricing.RState newRState,
|
||||
uint256 newQuoteTarget
|
||||
) = querySellQuote(tx.origin, quoteInput); // revert if quoteBalance<quoteReserve
|
||||
require(uint256(_BASE_RESERVE_).sub(baseBalance) <= receiveBaseAmount, "FLASH_LOAN_FAILED");
|
||||
|
||||
_transferBaseOut(_MAINTAINER_, mtFee);
|
||||
if (_RState_ != uint32(newRState)) {
|
||||
require(newQuoteTarget <= uint112(-1),"OVERFLOW");
|
||||
_QUOTE_TARGET_ = uint112(newQuoteTarget);
|
||||
_RState_ = uint32(newRState);
|
||||
emit RChange(newRState);
|
||||
}
|
||||
emit DODOSwap(
|
||||
address(_QUOTE_TOKEN_),
|
||||
address(_BASE_TOKEN_),
|
||||
quoteInput,
|
||||
receiveBaseAmount,
|
||||
msg.sender,
|
||||
assetTo
|
||||
);
|
||||
}
|
||||
|
||||
// sell base case
|
||||
// base input + quote output
|
||||
if (quoteBalance < _QUOTE_RESERVE_) {
|
||||
uint256 baseInput = baseBalance.sub(uint256(_BASE_RESERVE_));
|
||||
(
|
||||
uint256 receiveQuoteAmount,
|
||||
uint256 mtFee,
|
||||
PMMPricing.RState newRState,
|
||||
uint256 newBaseTarget
|
||||
) = querySellBase(tx.origin, baseInput); // revert if baseBalance<baseReserve
|
||||
require(uint256(_QUOTE_RESERVE_).sub(quoteBalance) <= receiveQuoteAmount, "FLASH_LOAN_FAILED");
|
||||
|
||||
_transferQuoteOut(_MAINTAINER_, mtFee);
|
||||
if (_RState_ != uint32(newRState)) {
|
||||
require(newBaseTarget <= uint112(-1),"OVERFLOW");
|
||||
_BASE_TARGET_ = uint112(newBaseTarget);
|
||||
_RState_ = uint32(newRState);
|
||||
emit RChange(newRState);
|
||||
}
|
||||
emit DODOSwap(
|
||||
address(_BASE_TOKEN_),
|
||||
address(_QUOTE_TOKEN_),
|
||||
baseInput,
|
||||
receiveQuoteAmount,
|
||||
msg.sender,
|
||||
assetTo
|
||||
);
|
||||
}
|
||||
|
||||
_sync();
|
||||
|
||||
emit DODOFlashLoan(msg.sender, assetTo, baseAmount, quoteAmount);
|
||||
}
|
||||
|
||||
// ============ Query Functions ============
|
||||
|
||||
function querySellBase(address trader, uint256 payBaseAmount)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
uint256 receiveQuoteAmount,
|
||||
uint256 mtFee,
|
||||
PMMPricing.RState newRState,
|
||||
uint256 newBaseTarget
|
||||
)
|
||||
{
|
||||
PMMPricing.PMMState memory state = getPMMState();
|
||||
(receiveQuoteAmount, newRState) = PMMPricing.sellBaseToken(state, payBaseAmount);
|
||||
|
||||
uint256 lpFeeRate = _LP_FEE_RATE_;
|
||||
uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader);
|
||||
mtFee = DecimalMath.mulFloor(receiveQuoteAmount, mtFeeRate);
|
||||
receiveQuoteAmount = receiveQuoteAmount
|
||||
.sub(DecimalMath.mulFloor(receiveQuoteAmount, lpFeeRate))
|
||||
.sub(mtFee);
|
||||
newBaseTarget = state.B0;
|
||||
}
|
||||
|
||||
function querySellQuote(address trader, uint256 payQuoteAmount)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
uint256 receiveBaseAmount,
|
||||
uint256 mtFee,
|
||||
PMMPricing.RState newRState,
|
||||
uint256 newQuoteTarget
|
||||
)
|
||||
{
|
||||
PMMPricing.PMMState memory state = getPMMState();
|
||||
(receiveBaseAmount, newRState) = PMMPricing.sellQuoteToken(state, payQuoteAmount);
|
||||
|
||||
uint256 lpFeeRate = _LP_FEE_RATE_;
|
||||
uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader);
|
||||
mtFee = DecimalMath.mulFloor(receiveBaseAmount, mtFeeRate);
|
||||
receiveBaseAmount = receiveBaseAmount
|
||||
.sub(DecimalMath.mulFloor(receiveBaseAmount, lpFeeRate))
|
||||
.sub(mtFee);
|
||||
newQuoteTarget = state.Q0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user