第一次走查

This commit is contained in:
mingda
2020-11-28 17:44:39 +08:00
parent 7fc0ede7ea
commit 13904ae413
27 changed files with 667 additions and 856 deletions

View File

@@ -38,6 +38,8 @@ contract DPP is DPPTrader {
_GAS_PRICE_LIMIT_ = IExternalValue(gasPriceSource);
_TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager);
_resetTargetAndReserve();
_checkIK();
require(_BASE_TOKEN_ != _QUOTE_TOKEN_, "BASE_QUOTE_CAN_NOT_BE_SAME");
}
// ============ Version Control ============

View File

@@ -9,16 +9,20 @@ pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;
import {IDPP} from "../intf/IDPP.sol";
import {IDODOApprove} from '../../intf/IDODOApprove.sol';
import {IDODOApprove} from "../../intf/IDODOApprove.sol";
import {InitializableOwnable} from "../../lib/InitializableOwnable.sol";
contract DPPAdmin is InitializableOwnable {
address public _DPP_;
address public _OPERATOR_;
address public _OPERATOR_;
address public _DODO_APPROVE_;
function init(address owner, address dpp,address operator, address dodoApprove) external {
function init(
address owner,
address dpp,
address operator,
address dodoApprove
) external {
initOwner(owner);
_DPP_ = dpp;
_OPERATOR_ = operator;
@@ -29,33 +33,33 @@ contract DPPAdmin is InitializableOwnable {
_OPERATOR_ = newOperator;
}
function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner {
IDPP(_DPP_).setLpFeeRateModel(newLpFeeRateModel);
}
// function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner {
// IDPP(_DPP_).setLpFeeRateModel(newLpFeeRateModel);
// }
function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner {
IDPP(_DPP_).setMtFeeRateModel(newMtFeeRateModel);
}
// function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner {
// IDPP(_DPP_).setMtFeeRateModel(newMtFeeRateModel);
// }
function setTradePermissionManager(address newTradePermissionManager) external onlyOwner {
IDPP(_DPP_).setTradePermissionManager(newTradePermissionManager);
}
// function setTradePermissionManager(address newTradePermissionManager) external onlyOwner {
// IDPP(_DPP_).setTradePermissionManager(newTradePermissionManager);
// }
function setMaintainer(address newMaintainer) external onlyOwner {
IDPP(_DPP_).setMaintainer(newMaintainer);
}
function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner {
IDPP(_DPP_).setGasPriceSource(newGasPriceLimitSource);
}
// function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner {
// IDPP(_DPP_).setGasPriceSource(newGasPriceLimitSource);
// }
function setISource(address newISource) external onlyOwner {
IDPP(_DPP_).setISource(newISource);
}
// function setISource(address newISource) external onlyOwner {
// IDPP(_DPP_).setISource(newISource);
// }
function setKSource(address newKSource) external onlyOwner {
IDPP(_DPP_).setKSource(newKSource);
}
// function setKSource(address newKSource) external onlyOwner {
// IDPP(_DPP_).setKSource(newKSource);
// }
function setBuy(bool open) external onlyOwner {
IDPP(_DPP_).setBuy(open);
@@ -65,12 +69,16 @@ contract DPPAdmin is InitializableOwnable {
IDPP(_DPP_).setSell(open);
}
function retrieve(address payable to,address token,uint256 amount) external onlyOwner {
IDPP(_DPP_).retrieve(to,token,amount);
function retrieve(
address payable to,
address token,
uint256 amount
) external onlyOwner {
IDPP(_DPP_).retrieve(to, token, amount);
}
function reset(
address assetTo,
address operator,
uint256 newLpFeeRate,
uint256 newMtFeeRate,
uint256 newI,
@@ -78,28 +86,12 @@ contract DPPAdmin is InitializableOwnable {
uint256 baseOutAmount,
uint256 quoteOutAmount
) external {
require(msg.sender == _OWNER_ || (msg.sender == IDODOApprove(_DODO_APPROVE_).getDODOProxy() && assetTo == _OPERATOR_), "RESET FORBIDDEN");
IDPP(_DPP_).reset(
assetTo,
newLpFeeRate,
newMtFeeRate,
newI,
newK,
baseOutAmount,
quoteOutAmount
require(
msg.sender == _OWNER_ ||
(msg.sender == IDODOApprove(_DODO_APPROVE_).getDODOProxy() &&
operator == _OPERATOR_),
"RESET FORBIDDEN"
);
}
function resetETH(
address from,
uint256 newLpFeeRate,
uint256 newMtFeeRate,
uint256 newI,
uint256 newK,
uint256 baseOutAmount,
uint256 quoteOutAmount
) external {
require(msg.sender == _OWNER_ || (msg.sender == IDODOApprove(_DODO_APPROVE_).getDODOProxy() && from == _OPERATOR_), "RESET FORBIDDEN");
IDPP(_DPP_).reset(
msg.sender,
newLpFeeRate,

View File

@@ -96,6 +96,13 @@ contract DPPStorage is InitializableOwnable, ReentrancyGuard {
_SELLING_CLOSE_ = !open;
}
function _checkIK() internal view {
uint256 k = _K_.get();
uint256 i = _I_.get();
require(k > 0 && k <= 1e18, "K_OUT_OF_RANGE");
require(i > 0 && i <= 1e36, "I_OUT_OF_RANGE");
}
// ============ View Functions ============
function getLpFeeRate(address trader) external view returns (uint256 feeRate) {
@@ -105,5 +112,4 @@ contract DPPStorage is InitializableOwnable, ReentrancyGuard {
function getMtFeeRate(address trader) external view returns (uint256 feeRate) {
return _MT_FEE_RATE_MODEL_.getFeeRate(trader);
}
}

View File

@@ -117,9 +117,6 @@ contract DPPTrader is DPPVault {
"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_) {
@@ -137,8 +134,6 @@ contract DPPTrader is DPPVault {
_RState_ = newRState;
_QUOTE_TARGET_ = newQuoteTarget;
}
_syncReserve();
}
// sell base case
@@ -158,9 +153,9 @@ contract DPPTrader is DPPVault {
_RState_ = newRState;
_BASE_TARGET_ = newBaseTarget;
}
_syncReserve();
}
_syncReserve();
}
// ============ Query Functions ============
@@ -180,11 +175,10 @@ contract DPPTrader is DPPVault {
uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader);
uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader);
mtFee = DecimalMath.mulCeil(receiveQuoteAmount, mtFeeRate);
receiveQuoteAmount = DecimalMath.mulFloor(
receiveQuoteAmount,
DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate)
);
mtFee = DecimalMath.mulFloor(receiveQuoteAmount, mtFeeRate);
receiveQuoteAmount = receiveQuoteAmount
.sub(DecimalMath.mulFloor(receiveQuoteAmount, lpFeeRate))
.sub(mtFee);
return (receiveQuoteAmount, mtFee, newRState, state.B0);
}
@@ -204,11 +198,10 @@ contract DPPTrader is DPPVault {
uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader);
uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader);
mtFee = DecimalMath.mulCeil(receiveBaseAmount, mtFeeRate);
receiveBaseAmount = DecimalMath.mulFloor(
receiveBaseAmount,
DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate)
);
mtFee = DecimalMath.mulFloor(receiveBaseAmount, mtFeeRate);
receiveBaseAmount = receiveBaseAmount
.sub(DecimalMath.mulFloor(receiveBaseAmount, lpFeeRate))
.sub(mtFee);
return (receiveBaseAmount, mtFee, newRState, state.Q0);
}

View File

@@ -43,7 +43,7 @@ contract DPPVault is DPPStorage {
return (_BASE_RESERVE_, _QUOTE_RESERVE_);
}
// ============ Set Status ============
// ============ Set States ============
function setTarget(uint256 baseTarget, uint256 quoteTarget) public preventReentrant onlyOwner {
_BASE_TARGET_ = baseTarget;
@@ -68,8 +68,6 @@ contract DPPVault is DPPStorage {
uint256 baseOutAmount,
uint256 quoteOutAmount
) public preventReentrant onlyOwner {
require(newK >= 1e12 && newK <= 1e18, "K_OUT_OF_RANGE");
require(newI > 0 && newI <= 1e36, "I_OUT_OF_RANGE");
_LP_FEE_RATE_MODEL_.setFeeRate(newLpFeeRate);
_MT_FEE_RATE_MODEL_.setFeeRate(newMtFeeRate);
_I_.set(newI);
@@ -77,6 +75,7 @@ contract DPPVault is DPPStorage {
_transferBaseOut(assetTo, baseOutAmount);
_transferQuoteOut(assetTo, quoteOutAmount);
_resetTargetAndReserve();
_checkIK();
}
function _setRState() internal {

View File

@@ -22,6 +22,10 @@ interface IDPP {
address tradePermissionManager
) external;
function _LP_FEE_RATE_MODEL_() external returns (address);
function _MT_FEE_RATE_MODEL_() external returns (address);
//=========== admin ==========
function setLpFeeRateModel(address newLpFeeRateModel) external;
@@ -40,9 +44,14 @@ interface IDPP {
function setBuy(bool open) external;
function setSell(bool open) external;
//==============================
function retrieve(address payable to,address token,uint256 amount) external;
//==============================
function retrieve(
address payable to,
address token,
uint256 amount
) external;
function reset(
address assetTo,
@@ -53,6 +62,4 @@ interface IDPP {
uint256 baseOutAmount,
uint256 quoteOutAmount
) external;
}

View File

@@ -15,7 +15,6 @@ import {SafeMath} from "../lib/SafeMath.sol";
import {IERC20} from "../intf/IERC20.sol";
import {IDODORewardVault, DODORewardVault} from "./DODORewardVault.sol";
contract DODOMine is Ownable {
using SafeMath for uint256;
using SafeERC20 for IERC20;
@@ -157,7 +156,7 @@ contract DODOMine is Ownable {
.div(totalAllocPoint);
accDODOPerShare = accDODOPerShare.add(DecimalMath.divFloor(DODOReward, lpSupply));
}
return DecimalMath.mul(user.amount, accDODOPerShare).sub(user.rewardDebt);
return DecimalMath.mulFloor(user.amount, accDODOPerShare).sub(user.rewardDebt);
}
function getAllPendingReward(address _user) external view returns (uint256) {
@@ -181,7 +180,7 @@ contract DODOMine is Ownable {
accDODOPerShare = accDODOPerShare.add(DecimalMath.divFloor(DODOReward, lpSupply));
}
totalReward = totalReward.add(
DecimalMath.mul(user.amount, accDODOPerShare).sub(user.rewardDebt)
DecimalMath.mulFloor(user.amount, accDODOPerShare).sub(user.rewardDebt)
);
}
return totalReward;
@@ -237,14 +236,14 @@ contract DODOMine is Ownable {
UserInfo storage user = userInfo[pid][msg.sender];
updatePool(pid);
if (user.amount > 0) {
uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(
uint256 pending = DecimalMath.mulFloor(user.amount, pool.accDODOPerShare).sub(
user.rewardDebt
);
safeDODOTransfer(msg.sender, pending);
}
IERC20(pool.lpToken).safeTransferFrom(address(msg.sender), address(this), _amount);
user.amount = user.amount.add(_amount);
user.rewardDebt = DecimalMath.mul(user.amount, pool.accDODOPerShare);
user.rewardDebt = DecimalMath.mulFloor(user.amount, pool.accDODOPerShare);
emit Deposit(msg.sender, pid, _amount);
}
@@ -254,10 +253,12 @@ contract DODOMine is Ownable {
UserInfo storage user = userInfo[pid][msg.sender];
require(user.amount >= _amount, "withdraw too much");
updatePool(pid);
uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt);
uint256 pending = DecimalMath.mulFloor(user.amount, pool.accDODOPerShare).sub(
user.rewardDebt
);
safeDODOTransfer(msg.sender, pending);
user.amount = user.amount.sub(_amount);
user.rewardDebt = DecimalMath.mul(user.amount, pool.accDODOPerShare);
user.rewardDebt = DecimalMath.mulFloor(user.amount, pool.accDODOPerShare);
IERC20(pool.lpToken).safeTransfer(address(msg.sender), _amount);
emit Withdraw(msg.sender, pid, _amount);
}
@@ -285,8 +286,10 @@ contract DODOMine is Ownable {
PoolInfo storage pool = poolInfos[pid];
UserInfo storage user = userInfo[pid][msg.sender];
updatePool(pid);
uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt);
user.rewardDebt = DecimalMath.mul(user.amount, pool.accDODOPerShare);
uint256 pending = DecimalMath.mulFloor(user.amount, pool.accDODOPerShare).sub(
user.rewardDebt
);
user.rewardDebt = DecimalMath.mulFloor(user.amount, pool.accDODOPerShare);
safeDODOTransfer(msg.sender, pending);
}
@@ -301,9 +304,9 @@ contract DODOMine is Ownable {
UserInfo storage user = userInfo[pid][msg.sender];
updatePool(pid);
pending = pending.add(
DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt)
DecimalMath.mulFloor(user.amount, pool.accDODOPerShare).sub(user.rewardDebt)
);
user.rewardDebt = DecimalMath.mul(user.amount, pool.accDODOPerShare);
user.rewardDebt = DecimalMath.mulFloor(user.amount, pool.accDODOPerShare);
}
safeDODOTransfer(msg.sender, pending);
}

View File

@@ -14,7 +14,6 @@ import {Ownable} from "../lib/Ownable.sol";
import {SafeERC20} from "../lib/SafeERC20.sol";
import {IERC20} from "../intf/IERC20.sol";
/**
* @title LockedTokenVault
* @author DODO Breeder
@@ -154,7 +153,7 @@ contract LockedTokenVault is Ownable {
function getRemainingBalance(address holder) public view returns (uint256) {
uint256 remainingRatio = getRemainingRatio(block.timestamp);
return DecimalMath.mul(originBalances[holder], remainingRatio);
return DecimalMath.mulFloor(originBalances[holder], remainingRatio);
}
function getRemainingRatio(uint256 timestamp) public view returns (uint256) {

View File

@@ -38,7 +38,9 @@ contract DVM is DVMTrader, DVMFunding {
_GAS_PRICE_LIMIT_ = IExternalValue(gasPriceSource);
_MAINTAINER_ = maintainer;
require(i > 0 && i < 10**36);
require(_BASE_TOKEN_ != _QUOTE_TOKEN_, "BASE_QUOTE_CAN_NOT_BE_SAME");
require(i > 0 && i <= 10**36);
_I_ = i;
require(k > 0 && k <= 10**18);
@@ -46,7 +48,13 @@ contract DVM is DVMTrader, DVMFunding {
string memory connect = "_";
string memory suffix = "DLP";
string memory uid = string(abi.encodePacked(address(this)));
uint32 uid = uint32(address(this));
bytes memory id = new bytes(4);
id[0] = bytes1(uint8(48 + (uid % 10)));
id[1] = bytes1(uint8(48 + ((uid / 10) % 10)));
id[2] = bytes1(uint8(48 + ((uid / 100) % 10)));
id[3] = bytes1(uint8(48 + ((uid / 1000) % 10)));
name = string(
abi.encodePacked(
suffix,
@@ -55,7 +63,7 @@ contract DVM is DVMTrader, DVMFunding {
connect,
_QUOTE_TOKEN_.symbol(),
connect,
uid
string(id)
)
);
symbol = "DLP";

View File

@@ -10,9 +10,9 @@ pragma experimental ABIEncoderV2;
import {IDVM} from "../intf/IDVM.sol";
import {InitializableOwnable} from "../../lib/InitializableOwnable.sol";
import {IExternalValue} from "../../lib/ExternalValue.sol";
contract DVMAdmin is InitializableOwnable {
address public _DVM_;
function init(address owner, address dvm) external {
@@ -20,25 +20,33 @@ contract DVMAdmin is InitializableOwnable {
_DVM_ = dvm;
}
function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner {
IDVM(_DVM_).setLpFeeRateModel(newLpFeeRateModel);
// function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner {
// IDVM(_DVM_).setLpFeeRateModel(newLpFeeRateModel);
// }
function setLpFeeRateValue(uint256 newLpFeeRate) external onlyOwner {
IExternalValue(IDVM(_DVM_)._LP_FEE_RATE_MODEL_()).set(newLpFeeRate);
}
function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner {
IDVM(_DVM_).setMtFeeRateModel(newMtFeeRateModel);
// function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner {
// IDVM(_DVM_).setMtFeeRateModel(newMtFeeRateModel);
// }
function setMtFeeRateValue(uint256 newMtFeeRate) external onlyOwner {
IExternalValue(IDVM(_DVM_)._MT_FEE_RATE_MODEL_()).set(newMtFeeRate);
}
function setTradePermissionManager(address newTradePermissionManager) external onlyOwner {
IDVM(_DVM_).setTradePermissionManager(newTradePermissionManager);
}
// function setTradePermissionManager(address newTradePermissionManager) external onlyOwner {
// IDVM(_DVM_).setTradePermissionManager(newTradePermissionManager);
// }
function setMaintainer(address newMaintainer) external onlyOwner {
IDVM(_DVM_).setMaintainer(newMaintainer);
}
function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner {
IDVM(_DVM_).setGasPriceSource(newGasPriceLimitSource);
}
// function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner {
// IDVM(_DVM_).setGasPriceSource(newGasPriceLimitSource);
// }
function setBuy(bool open) external onlyOwner {
IDVM(_DVM_).setBuy(open);

View File

@@ -44,11 +44,10 @@ contract DVMTrader is DVMVault {
external
preventReentrant
limitGasPrice
isSellAllow(to)
isSellAllow(to) // set DVM address in trade permission
returns (uint256 receiveQuoteAmount)
{
uint256 baseInput = getBaseInput();
require(baseInput > 0, "INSUFFICIENT_BASE_INPUT");
uint256 mtFee;
(receiveQuoteAmount, mtFee) = querySellBase(tx.origin, baseInput);
_transferQuoteOut(to, receiveQuoteAmount);
@@ -65,7 +64,6 @@ contract DVMTrader is DVMVault {
returns (uint256 receiveBaseAmount)
{
uint256 quoteInput = getQuoteInput();
require(quoteInput > 0, "INSUFFICIENT_QUOTE_INPUT");
uint256 mtFee;
(receiveBaseAmount, mtFee) = querySellQuote(tx.origin, quoteInput);
_transferBaseOut(to, receiveBaseAmount);
@@ -74,8 +72,6 @@ contract DVMTrader is DVMVault {
return receiveBaseAmount;
}
// 这是一个试验性质的函数
// 没有走标准库,需要仔细考虑下
function flashLoan(
uint256 baseAmount,
uint256 quoteAmount,
@@ -96,9 +92,6 @@ contract DVMTrader is DVMVault {
"FLASH_LOAN_FAILED"
);
// no output -> pure profit
if (baseBalance >= _BASE_RESERVE_ && quoteBalance >= _QUOTE_RESERVE_) return;
if (baseBalance < _BASE_RESERVE_) {
(uint256 receiveBaseAmount, uint256 mtFee) = querySellQuote(
tx.origin,
@@ -120,6 +113,8 @@ contract DVMTrader is DVMVault {
_sync();
}
// ============ View Functions ============
function querySellBase(address trader, uint256 payBaseAmount)
public
view
@@ -129,11 +124,10 @@ contract DVMTrader is DVMVault {
uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader);
uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader);
mtFee = DecimalMath.mulCeil(receiveQuoteAmount, mtFeeRate);
receiveQuoteAmount = DecimalMath.mulFloor(
receiveQuoteAmount,
DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate)
);
mtFee = DecimalMath.mulFloor(receiveQuoteAmount, mtFeeRate);
receiveQuoteAmount = receiveQuoteAmount
.sub(DecimalMath.mulFloor(receiveQuoteAmount, lpFeeRate))
.sub(mtFee);
return (receiveQuoteAmount, mtFee);
}
@@ -147,18 +141,13 @@ contract DVMTrader is DVMVault {
uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader);
uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader);
mtFee = DecimalMath.mulCeil(receiveBaseAmount, mtFeeRate);
receiveBaseAmount = DecimalMath.mulFloor(
receiveBaseAmount,
DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate)
);
mtFee = DecimalMath.mulFloor(receiveBaseAmount, mtFeeRate);
receiveBaseAmount = receiveBaseAmount
.sub(DecimalMath.mulFloor(receiveBaseAmount, lpFeeRate))
.sub(mtFee);
return (receiveBaseAmount, mtFee);
}
function getMidPrice() public view returns (uint256 midPrice) {
return PMMPricing.getMidPrice(getPMMState());
}
// ============ Helper Functions ============
function getPMMState() public view returns (PMMPricing.PMMState memory state) {
@@ -166,30 +155,14 @@ contract DVMTrader is DVMVault {
state.K = _K_;
state.B = _BASE_RESERVE_;
state.Q = _QUOTE_RESERVE_;
state.B0 = calculateBase0(state.B, state.Q);
state.B0 = 0; // recalculate in adjustedTarget
state.Q0 = 0;
state.R = PMMPricing.RState.ABOVE_ONE;
PMMPricing.adjustedTarget(state);
return state;
}
function calculateBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) {
return
DODOMath._SolveQuadraticFunctionForTarget(
baseAmount,
quoteAmount,
DecimalMath.reciprocalFloor(_I_),
_K_
);
}
function getBase0() public view returns (uint256) {
(uint256 baseAmount, uint256 quoteAmount) = getVaultReserve();
return
DODOMath._SolveQuadraticFunctionForTarget(
baseAmount,
quoteAmount,
DecimalMath.reciprocalFloor(_I_),
_K_
);
function getMidPrice() public view returns (uint256 midPrice) {
return PMMPricing.getMidPrice(getPMMState());
}
}

View File

@@ -26,6 +26,10 @@ interface IDVM {
function _QUOTE_TOKEN_() external returns (address);
function _LP_FEE_RATE_MODEL_() external returns (address);
function _MT_FEE_RATE_MODEL_() external returns (address);
function getVaultReserve() external returns (uint256 baseReserve, uint256 quoteReserve);
function sellBase(address to) external returns (uint256);
@@ -34,7 +38,6 @@ interface IDVM {
function buyShares(address to) external returns (uint256);
//=========== admin ==========
function setLpFeeRateModel(address newLpFeeRateModel) external;
@@ -49,5 +52,5 @@ interface IDVM {
function setBuy(bool open) external;
function setSell(bool open) external;
//==============================
//==============================
}

View File

@@ -1,134 +0,0 @@
/*
Copyright 2020 DODO ZOO.
SPDX-License-Identifier: Apache-2.0
*/
pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;
import {Ownable} from "./lib/Ownable.sol";
import {IDODO} from "./intf/IDODO.sol";
import {ICloneFactory} from "./lib/CloneFactory.sol";
/**
* @title DODOZoo
* @author DODO Breeder
*
* @notice Register of All DODO
*/
contract DODOZoo is Ownable {
address public _DODO_LOGIC_;
address public _CLONE_FACTORY_;
address public _DEFAULT_SUPERVISOR_;
mapping(address => mapping(address => address)) internal _DODO_REGISTER_;
address[] public _DODOs;
// ============ Events ============
event DODOBirth(address newBorn, address baseToken, address quoteToken);
// ============ Constructor Function ============
constructor(
address _dodoLogic,
address _cloneFactory,
address _defaultSupervisor
) public {
_DODO_LOGIC_ = _dodoLogic;
_CLONE_FACTORY_ = _cloneFactory;
_DEFAULT_SUPERVISOR_ = _defaultSupervisor;
}
// ============ Admin Function ============
function setDODOLogic(address _dodoLogic) external onlyOwner {
_DODO_LOGIC_ = _dodoLogic;
}
function setCloneFactory(address _cloneFactory) external onlyOwner {
_CLONE_FACTORY_ = _cloneFactory;
}
function setDefaultSupervisor(address _defaultSupervisor) external onlyOwner {
_DEFAULT_SUPERVISOR_ = _defaultSupervisor;
}
function removeDODO(address dodo) external onlyOwner {
address baseToken = IDODO(dodo)._BASE_TOKEN_();
address quoteToken = IDODO(dodo)._QUOTE_TOKEN_();
require(isDODORegistered(baseToken, quoteToken), "DODO_NOT_REGISTERED");
_DODO_REGISTER_[baseToken][quoteToken] = address(0);
for (uint256 i = 0; i <= _DODOs.length - 1; i++) {
if (_DODOs[i] == dodo) {
_DODOs[i] = _DODOs[_DODOs.length - 1];
_DODOs.pop();
break;
}
}
}
function addDODO(address dodo) public onlyOwner {
address baseToken = IDODO(dodo)._BASE_TOKEN_();
address quoteToken = IDODO(dodo)._QUOTE_TOKEN_();
require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED");
_DODO_REGISTER_[baseToken][quoteToken] = dodo;
_DODOs.push(dodo);
}
// ============ Breed DODO Function ============
function breedDODO(
address maintainer,
address baseToken,
address quoteToken,
address oracle,
uint256 lpFeeRate,
uint256 mtFeeRate,
uint256 k,
uint256 gasPriceLimit
) external onlyOwner returns (address newBornDODO) {
require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED");
newBornDODO = ICloneFactory(_CLONE_FACTORY_).clone(_DODO_LOGIC_);
IDODO(newBornDODO).init(
_OWNER_,
_DEFAULT_SUPERVISOR_,
maintainer,
baseToken,
quoteToken,
oracle,
lpFeeRate,
mtFeeRate,
k,
gasPriceLimit
);
addDODO(newBornDODO);
emit DODOBirth(newBornDODO, baseToken, quoteToken);
return newBornDODO;
}
// ============ View Functions ============
function isDODORegistered(address baseToken, address quoteToken) public view returns (bool) {
if (
_DODO_REGISTER_[baseToken][quoteToken] == address(0) &&
_DODO_REGISTER_[quoteToken][baseToken] == address(0)
) {
return false;
} else {
return true;
}
}
function getDODO(address baseToken, address quoteToken) external view returns (address) {
return _DODO_REGISTER_[baseToken][quoteToken];
}
function getDODOs() external view returns (address[] memory) {
return _DODOs;
}
}

View File

@@ -26,20 +26,10 @@ contract DPPFactory is Ownable {
address public _VALUE_SOURCE_;
address public _DODO_SMART_APPROVE_;
//TODO: 平台修改tag的权限 && 池子标签类型
struct DPPInfo {
address creator;
uint256 createTimeStamp;
}
// base -> quote -> DPP address list
mapping(address => mapping(address => address[])) public _REGISTRY_;
// token0 -> token1 -> DPP address list
mapping(address => mapping(address => address[])) public _SORT_REGISTRY_;
// creator -> DPP address list
mapping(address => address[]) public _USER_REGISTRY_;
// DPP address -> info
mapping(address => DPPInfo) public _DPP_INFO_;
constructor(
address cloneFactory,
@@ -61,13 +51,13 @@ contract DPPFactory is Ownable {
_DEFAULT_GAS_PRICE_SOURCE_ = defaultGasPriceSource;
}
function createDODOPrivatePool() external returns(address newPrivatePool) {
function createDODOPrivatePool() external returns (address newPrivatePool) {
newPrivatePool = ICloneFactory(_CLONE_FACTORY_).clone(_DPP_TEMPLATE_);
}
function initDODOPrivatePool(
address dppAddress,
address from,
address creator,
address baseToken,
address quoteToken,
uint256 lpFeeRate,
@@ -75,38 +65,36 @@ contract DPPFactory is Ownable {
uint256 k,
uint256 i
) external {
{
address _dppAddress = dppAddress;
address adminModel = _createDPPAdminModel(from,_dppAddress,from,_DODO_SMART_APPROVE_);
IDPP(_dppAddress).init(
adminModel,
from,
baseToken,
quoteToken,
_createFeeRateModel(_dppAddress, lpFeeRate),
_createFeeRateModel(_dppAddress, mtFeeRate),
_createExternalValueModel(_dppAddress, k),
_createExternalValueModel(_dppAddress, i),
_DEFAULT_GAS_PRICE_SOURCE_,
_createPermissionManager(adminModel)
);
{
address _dppAddress = dppAddress;
address adminModel = _createDPPAdminModel(
creator,
_dppAddress,
creator,
_DODO_SMART_APPROVE_
);
IDPP(_dppAddress).init(
adminModel,
creator,
baseToken,
quoteToken,
_createFeeRateModel(_dppAddress, lpFeeRate),
_createFeeRateModel(_dppAddress, mtFeeRate),
_createExternalValueModel(_dppAddress, k),
_createExternalValueModel(_dppAddress, i),
_DEFAULT_GAS_PRICE_SOURCE_,
_createPermissionManager(adminModel)
);
}
{
(address token0, address token1) = baseToken < quoteToken ? (baseToken, quoteToken) : (quoteToken, baseToken);
_SORT_REGISTRY_[token0][token1].push(dppAddress);
}
_REGISTRY_[baseToken][quoteToken].push(dppAddress);
_USER_REGISTRY_[from].push(dppAddress);
_DPP_INFO_[dppAddress] = (
DPPInfo({
creator: from,
createTimeStamp: block.timestamp
})
);
_USER_REGISTRY_[creator].push(dppAddress);
}
function _createFeeRateModel(address owner, uint256 feeRate) internal returns (address feeRateModel){
function _createFeeRateModel(address owner, uint256 feeRate)
internal
returns (address feeRateModel)
{
feeRateModel = ICloneFactory(_CLONE_FACTORY_).clone(_FEE_RATE_MODEL_TEMPLATE_);
IFeeRateModel(feeRateModel).init(owner, feeRate);
}
@@ -116,14 +104,22 @@ contract DPPFactory is Ownable {
IPermissionManager(permissionManager).initOwner(owner);
}
function _createExternalValueModel(address owner, uint256 value) internal returns (address valueModel) {
function _createExternalValueModel(address owner, uint256 value)
internal
returns (address valueModel)
{
valueModel = ICloneFactory(_CLONE_FACTORY_).clone(_VALUE_SOURCE_);
IExternalValue(valueModel).init(owner, value);
}
function _createDPPAdminModel(address owner, address dpp,address operator, address dodoSmartApprove) internal returns (address adminModel) {
function _createDPPAdminModel(
address owner,
address dpp,
address operator,
address dodoSmartApprove
) internal returns (address adminModel) {
adminModel = ICloneFactory(_CLONE_FACTORY_).clone(_DPP_ADMIN_TEMPLATE_);
IDPPAdmin(adminModel).init(owner,dpp,operator,dodoSmartApprove);
IDPPAdmin(adminModel).init(owner, dpp, operator, dodoSmartApprove);
}
function updateAdminTemplate(address _newDPPAdminTemplate) external onlyOwner {
@@ -137,4 +133,12 @@ contract DPPFactory is Ownable {
{
return _REGISTRY_[baseToken][quoteToken];
}
function getPrivatePoolBidirection(address token0, address token1)
external
view
returns (address[] memory baseToken0Pool, address[] memory baseToken1Pool)
{
return (_REGISTRY_[token0][token1], _REGISTRY_[token1][token0]);
}
}

View File

@@ -23,20 +23,10 @@ contract DVMFactory is Ownable {
address public _PERMISSION_MANAGER_TEMPLATE_;
address public _DEFAULT_GAS_PRICE_SOURCE_;
//TODO: 平台修改tag的权限 && 池子标签类型
struct DVMInfo {
address creator;
uint256 createTimeStamp;
}
// base -> quote -> DVM address list
mapping(address => mapping(address => address[])) public _REGISTRY_;
// token0 -> token1 -> DVM address list
mapping(address => mapping(address => address[])) public _SORT_REGISTRY_;
// creator -> DVM address list
mapping(address => address[]) public _USER_REGISTRY_;
// DVM address -> info
mapping(address => DVMInfo) public _DVM_INFO_;
constructor(
address cloneFactory,
@@ -55,7 +45,7 @@ contract DVMFactory is Ownable {
}
function createDODOVendingMachine(
address from,
address creator,
address baseToken,
address quoteToken,
uint256 lpFeeRate,
@@ -65,35 +55,28 @@ contract DVMFactory is Ownable {
) external returns (address newVendingMachine) {
newVendingMachine = ICloneFactory(_CLONE_FACTORY_).clone(_DVM_TEMPLATE_);
{
address adminModel = _createDVMAdminModel(from,newVendingMachine);
IDVM(newVendingMachine).init(
adminModel,
from,
baseToken,
quoteToken,
_createFeeRateModel(newVendingMachine, lpFeeRate),
_createFeeRateModel(newVendingMachine, mtFeeRate),
_createPermissionManager(adminModel),
_DEFAULT_GAS_PRICE_SOURCE_,
i,
k
);
address adminModel = _createDVMAdminModel(creator, newVendingMachine);
IDVM(newVendingMachine).init(
adminModel,
creator,
baseToken,
quoteToken,
_createFeeRateModel(adminModel, lpFeeRate),
_createFeeRateModel(adminModel, mtFeeRate),
_createPermissionManager(adminModel),
_DEFAULT_GAS_PRICE_SOURCE_,
i,
k
);
}
_REGISTRY_[baseToken][quoteToken].push(newVendingMachine);
{
(address token0, address token1) = baseToken < quoteToken ? (baseToken, quoteToken) : (quoteToken, baseToken);
_SORT_REGISTRY_[token0][token1].push(newVendingMachine);
}
_USER_REGISTRY_[from].push(newVendingMachine);
_DVM_INFO_[newVendingMachine] = (
DVMInfo({
creator: from,
createTimeStamp: block.timestamp
})
);
_USER_REGISTRY_[creator].push(newVendingMachine);
}
function _createFeeRateModel(address owner, uint256 feeRate) internal returns (address feeRateModel) {
function _createFeeRateModel(address owner, uint256 feeRate)
internal
returns (address feeRateModel)
{
feeRateModel = ICloneFactory(_CLONE_FACTORY_).clone(_FEE_RATE_MODEL_TEMPLATE_);
IConstFeeRateModel(feeRateModel).init(owner, feeRate);
}
@@ -103,9 +86,12 @@ contract DVMFactory is Ownable {
IPermissionManager(permissionManager).initOwner(owner);
}
function _createDVMAdminModel(address owner, address dvm) internal returns (address adminModel) {
function _createDVMAdminModel(address owner, address dvm)
internal
returns (address adminModel)
{
adminModel = ICloneFactory(_CLONE_FACTORY_).clone(_DVM_ADMIN_TEMPLATE_);
IDVMAdmin(adminModel).init(owner,dvm);
IDVMAdmin(adminModel).init(owner, dvm);
}
function updateAdminTemplate(address _newDVMAdminTemplate) external onlyOwner {
@@ -119,4 +105,12 @@ contract DVMFactory is Ownable {
{
return _REGISTRY_[baseToken][quoteToken];
}
function getVendingMachineBidirection(address token0, address token1)
external
view
returns (address[] memory baseToken0Machines, address[] memory baseToken1Machines)
{
return (_REGISTRY_[token0][token1], _REGISTRY_[token1][token0]);
}
}

View File

@@ -29,7 +29,9 @@ contract DODOApprove is Ownable {
address dest,
uint256 amount
) external {
require(msg.sender == dodoProxy, 'DODOApprove:Access restricted');
IERC20(token).safeTransferFrom(who, dest, amount);
require(msg.sender == dodoProxy, "DODOApprove:Access restricted");
if (amount > 0) {
IERC20(token).safeTransferFrom(who, dest, amount);
}
}
}

View File

@@ -9,14 +9,13 @@ pragma solidity 0.6.9;
import {Ownable} from "../lib/Ownable.sol";
import {IERC20} from "../intf/IERC20.sol";
import {UniversalERC20} from "../lib/UniversalERC20.sol";
import {UniversalERC20} from "./UniversalERC20.sol";
import {SafeMath} from "../lib/SafeMath.sol";
import {IDODOSellHelper} from "../intf/IDODOSellHelper.sol";
import {IDODOApprove} from "../intf/IDODOApprove.sol";
import {IDODO} from "../intf/IDODO.sol";
import {IWETH} from "../intf/IWETH.sol";
contract DODOV1Proxy01 is Ownable {
using SafeMath for uint256;
using UniversalERC20 for IERC20;
@@ -27,7 +26,7 @@ contract DODOV1Proxy01 is Ownable {
address payable public _WETH_;
modifier judgeExpired(uint256 deadline) {
require(deadline >= block.timestamp, 'DODOV1Proxy01: EXPIRED');
require(deadline >= block.timestamp, "DODOV1Proxy01: EXPIRED");
_;
}
@@ -63,12 +62,15 @@ contract DODOV1Proxy01 is Ownable {
uint256[] memory directions,
uint256 deadline
) public payable judgeExpired(deadline) returns (uint256 returnAmount) {
require(minReturnAmount > 0, 'DODOV1Proxy01: Min return should be bigger then 0.');
if (fromToken != ETH_ADDRESS) {
IDODOApprove(dodoApprove).claimTokens(fromToken, msg.sender, address(this), fromTokenAmount);
IDODOApprove(dodoApprove).claimTokens(
fromToken,
msg.sender,
address(this),
fromTokenAmount
);
} else {
require(msg.value == fromTokenAmount, 'DODOV1Proxy01: ETH_AMOUNT_NOT_MATCH');
require(msg.value == fromTokenAmount, "DODOV1Proxy01: ETH_AMOUNT_NOT_MATCH");
IWETH(_WETH_).deposit{value: fromTokenAmount}();
}
@@ -98,9 +100,16 @@ contract DODOV1Proxy01 is Ownable {
returnAmount = IERC20(toToken).universalBalanceOf(address(this));
require(returnAmount >= minReturnAmount, 'DODOV1Proxy01: Return amount is not enough');
require(returnAmount >= minReturnAmount, "DODOV1Proxy01: Return amount is not enough");
IERC20(toToken).universalTransfer(msg.sender, returnAmount);
emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount, block.timestamp);
emit OrderHistory(
fromToken,
toToken,
msg.sender,
fromTokenAmount,
returnAmount,
block.timestamp
);
}
function externalSwap(
@@ -112,24 +121,37 @@ contract DODOV1Proxy01 is Ownable {
uint256 minReturnAmount,
bytes memory callDataConcat,
uint256 deadline
) public payable judgeExpired(deadline) returns (uint256 returnAmount) {
require(minReturnAmount > 0, 'DODOV1Proxy01: Min return should be bigger then 0.');
) public payable judgeExpired(deadline) returns (uint256 returnAmount) {
if (fromToken != ETH_ADDRESS) {
IDODOApprove(dodoApprove).claimTokens(fromToken, msg.sender, address(this), fromTokenAmount);
IERC20(fromToken).universalApprove(approveTarget, fromTokenAmount);
IDODOApprove(dodoApprove).claimTokens(
fromToken,
msg.sender,
address(this),
fromTokenAmount
);
IERC20(fromToken).universalApproveMax(approveTarget, fromTokenAmount);
}
(bool success, ) = to.call{value: fromToken == ETH_ADDRESS ? msg.value : 0}(
callDataConcat
(bool success, ) = to.call{value: fromToken == ETH_ADDRESS ? msg.value : 0}(callDataConcat);
require(success, "DODOV1Proxy01: Contract Swap execution Failed");
IERC20(fromToken).universalTransfer(
msg.sender,
IERC20(fromToken).universalBalanceOf(address(this))
);
require(success, 'DODOV1Proxy01: Contract Swap execution Failed');
returnAmount = IERC20(toToken).universalBalanceOf(address(this));
require(returnAmount >= minReturnAmount, 'DODOV1Proxy01: Return amount is not enough');
require(returnAmount >= minReturnAmount, "DODOV1Proxy01: Return amount is not enough");
IERC20(toToken).universalTransfer(msg.sender, returnAmount);
emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount, block.timestamp);
emit OrderHistory(
fromToken,
toToken,
msg.sender,
fromTokenAmount,
returnAmount,
block.timestamp
);
}
}

View File

@@ -12,7 +12,8 @@ import {IDODOV2} from "../intf/IDODOV2.sol";
import {IERC20} from "../intf/IERC20.sol";
import {IWETH} from "../intf/IWETH.sol";
import {SafeMath} from "../lib/SafeMath.sol";
import {UniversalERC20} from "../lib/UniversalERC20.sol";
import {UniversalERC20} from "./UniversalERC20.sol";
import {SafeERC20} from "../lib/SafeERC20.sol";
import {DecimalMath} from "../lib/DecimalMath.sol";
contract DODOV2Proxy01 is IDODOV2Proxy01 {
@@ -22,12 +23,11 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
address constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address payable public _WETH_;
address public dodoApprove;
address public dodoSellHelper;
address public dvmFactory;
address public dppFactory;
modifier judgeExpired(uint256 deadline) {
require(deadline >= block.timestamp, 'DODOV2Proxy01: EXPIRED');
require(deadline >= block.timestamp, "DODOV2Proxy01: EXPIRED");
_;
}
@@ -44,22 +44,21 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
uint256 returnAmount,
uint256 timeStamp
);
//========================================================================
constructor(
address _dvmFactory,
address _dppFactory,
address payable _weth,
address _dodoApprove,
address _dodoSellHelper
address _dodoApprove
) public {
dvmFactory = _dvmFactory;
dppFactory = _dppFactory;
_WETH_ = _weth;
dodoApprove = _dodoApprove;
dodoSellHelper = _dodoSellHelper;
}
function createDODOVendingMachine(
address assetTo,
address baseToken,
@@ -71,39 +70,55 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
uint256 i,
uint256 k,
uint256 deadline
) external virtual override payable judgeExpired(deadline) returns (address newVendingMachine,uint256 shares) {
)
external
virtual
override
payable
judgeExpired(deadline)
returns (address newVendingMachine, uint256 shares)
{
{
address _baseToken = baseToken == ETH_ADDRESS ? _WETH_ : baseToken;
address _quoteToken = quoteToken == ETH_ADDRESS ? _WETH_ : quoteToken;
newVendingMachine = IDODOV2(dvmFactory).createDODOVendingMachine(msg.sender, _baseToken, _quoteToken, lpFeeRate, mtFeeRate, i, k);
address _baseToken = baseToken == ETH_ADDRESS ? _WETH_ : baseToken;
address _quoteToken = quoteToken == ETH_ADDRESS ? _WETH_ : quoteToken;
newVendingMachine = IDODOV2(dvmFactory).createDODOVendingMachine(
msg.sender,
_baseToken,
_quoteToken,
lpFeeRate,
mtFeeRate,
i,
k
);
}
if(baseInAmount > 0){
if(baseToken != ETH_ADDRESS){
IDODOV2(dodoApprove).claimTokens(baseToken, msg.sender, newVendingMachine, baseInAmount);
}else {
require(msg.value == baseInAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
IWETH(_WETH_).deposit{value: baseInAmount}();
assert(IWETH(_WETH_).transfer(newVendingMachine, baseInAmount));
}
}
if(quoteInAmount > 0){
if(quoteToken != ETH_ADDRESS){
IDODOV2(dodoApprove).claimTokens(quoteToken, msg.sender, newVendingMachine, quoteInAmount);
}else {
require(msg.value == quoteInAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
IWETH(_WETH_).deposit{value: quoteInAmount}();
assert(IWETH(_WETH_).transfer(newVendingMachine, quoteInAmount));
}
}
(shares,,) = IDODOV2(newVendingMachine).buyShares(assetTo);
}
{
address _baseToken = baseToken;
address _quoteToken = quoteToken;
_deposit(
msg.sender,
newVendingMachine,
_baseToken,
baseInAmount,
_baseToken == ETH_ADDRESS
);
_deposit(
msg.sender,
newVendingMachine,
_quoteToken,
quoteInAmount,
_quoteToken == ETH_ADDRESS
);
}
(shares, , ) = IDODOV2(newVendingMachine).buyShares(assetTo);
}
function _addDVMLiquidity(
address DVMAddress,
uint256 baseInAmount,
uint256 quoteInAmount
) internal virtual view returns (uint baseAdjustedInAmount, uint quoteAdjustedInAmount) {
) internal virtual view returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount) {
(uint256 baseReserve, uint256 quoteReserve) = IDODOV2(DVMAddress).getVaultReserve();
if (quoteReserve == 0 && baseReserve == 0) {
baseAdjustedInAmount = baseInAmount;
@@ -133,59 +148,35 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
uint256 quoteInAmount,
uint256 baseMinAmount,
uint256 quoteMinAmount,
uint8 flag, // 0 - ERC20, 1 - baseInETH, 2 - quoteInETH
uint256 deadline
) external virtual override judgeExpired(deadline) returns (uint256 shares,uint256 baseAdjustedInAmount,uint256 quoteAdjustedInAmount) {
(baseAdjustedInAmount, quoteAdjustedInAmount) = _addDVMLiquidity(DVMAddress,baseInAmount,quoteInAmount);
require(baseAdjustedInAmount >= baseMinAmount && quoteAdjustedInAmount >= quoteMinAmount, 'DODOV2Proxy01: deposit amount is not enough');
)
external
virtual
override
payable
judgeExpired(deadline)
returns (
uint256 shares,
uint256 baseAdjustedInAmount,
uint256 quoteAdjustedInAmount
)
{
(baseAdjustedInAmount, quoteAdjustedInAmount) = _addDVMLiquidity(
DVMAddress,
baseInAmount,
quoteInAmount
);
require(
baseAdjustedInAmount >= baseMinAmount && quoteAdjustedInAmount >= quoteMinAmount,
"DODOV2Proxy01: deposit amount is not enough"
);
address _dvm = DVMAddress;
if(baseAdjustedInAmount > 0) {
IDODOV2(dodoApprove).claimTokens(IDODOV2(_dvm)._BASE_TOKEN_(), msg.sender, _dvm, baseAdjustedInAmount);
}
if(quoteAdjustedInAmount > 0)
IDODOV2(dodoApprove).claimTokens(IDODOV2(_dvm)._QUOTE_TOKEN_(), msg.sender, _dvm, quoteAdjustedInAmount);
(shares,,) = IDODOV2(_dvm).buyShares(to);
}
function addDVMLiquidityETH(
address DVMAddress,
address to,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 baseMinAmount,
uint256 quoteMinAmount,
uint8 flag, // 1 - baseInETH, 2 - quoteInETH
uint256 deadline
) external virtual override payable judgeExpired(deadline) returns (uint256 shares,uint256 baseAdjustedInAmount,uint256 quoteAdjustedInAmount) {
(baseAdjustedInAmount, quoteAdjustedInAmount) = _addDVMLiquidity(DVMAddress,baseInAmount,quoteInAmount);
require(baseAdjustedInAmount >= baseMinAmount && quoteAdjustedInAmount >= quoteMinAmount, 'DODOV2Proxy01: deposit amount is not enough');
address _dvm = DVMAddress;
if(baseAdjustedInAmount > 0) {
if(flag == 1) {
require(msg.value >= baseAdjustedInAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
IWETH(_WETH_).deposit{value: baseAdjustedInAmount}();
assert(IWETH(_WETH_).transfer(_dvm, baseAdjustedInAmount));
if (msg.value > baseAdjustedInAmount) {
(bool success,) = msg.sender.call{value:msg.value - baseAdjustedInAmount}(new bytes(0));
require(success, 'DODOV2Proxy01: ETH_TRANSFER_FAILED');
}
}else {
IDODOV2(dodoApprove).claimTokens(IDODOV2(_dvm)._BASE_TOKEN_(), msg.sender, _dvm, baseAdjustedInAmount);
}
}
if(quoteAdjustedInAmount > 0){
if(flag == 2) {
require(msg.value >= quoteAdjustedInAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
IWETH(_WETH_).deposit{value: quoteAdjustedInAmount}();
assert(IWETH(_WETH_).transfer(_dvm, quoteAdjustedInAmount));
if (msg.value > quoteAdjustedInAmount) {
(bool success,) = msg.sender.call{value:msg.value - quoteAdjustedInAmount}(new bytes(0));
require(success, 'DODOV2Proxy01: ETH_TRANSFER_FAILED');
}
}else {
IDODOV2(dodoApprove).claimTokens(IDODOV2(_dvm)._QUOTE_TOKEN_(), msg.sender, _dvm, quoteAdjustedInAmount);
}
}
(shares,,) = IDODOV2(_dvm).buyShares(to);
_deposit(msg.sender, _dvm, IDODOV2(_dvm)._BASE_TOKEN_(), baseAdjustedInAmount, flag == 1);
_deposit(msg.sender, _dvm, IDODOV2(_dvm)._QUOTE_TOKEN_(), quoteAdjustedInAmount, flag == 2);
(shares, , ) = IDODOV2(_dvm).buyShares(to);
}
function createDODOPrivatePool(
@@ -200,31 +191,26 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
uint256 deadline
) external virtual override payable judgeExpired(deadline) returns (address newPrivatePool) {
newPrivatePool = IDODOV2(dppFactory).createDODOPrivatePool();
if(baseInAmount > 0){
if(baseToken != ETH_ADDRESS){
IDODOV2(dodoApprove).claimTokens(baseToken, msg.sender, newPrivatePool, baseInAmount);
}else {
require(msg.value == baseInAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
IWETH(_WETH_).deposit{value: baseInAmount}();
assert(IWETH(_WETH_).transfer(newPrivatePool, baseInAmount));
baseToken = _WETH_;
}
}
if(quoteInAmount > 0){
if(quoteToken != ETH_ADDRESS){
IDODOV2(dodoApprove).claimTokens(quoteToken, msg.sender, newPrivatePool, quoteInAmount);
}else {
require(msg.value == quoteInAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
IWETH(_WETH_).deposit{value: quoteInAmount}();
assert(IWETH(_WETH_).transfer(newPrivatePool, quoteInAmount));
quoteToken = _WETH_;
}
}
address _baseToken = baseToken;
address _quoteToken = quoteToken;
_deposit(msg.sender, newPrivatePool, _baseToken, baseInAmount, _baseToken == ETH_ADDRESS);
_deposit(
msg.sender,
newPrivatePool,
_quoteToken,
quoteInAmount,
_quoteToken == ETH_ADDRESS
);
if (_baseToken == ETH_ADDRESS) _baseToken = _WETH_;
if (_quoteToken == ETH_ADDRESS) _quoteToken = _WETH_;
IDODOV2(dppFactory).initDODOPrivatePool(
newPrivatePool,
msg.sender,
baseToken,
quoteToken,
_baseToken,
_quoteToken,
lpFeeRate,
mtFeeRate,
k,
@@ -242,12 +228,24 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
uint256 quoteInAmount,
uint256 baseOutAmount,
uint256 quoteOutAmount,
uint8 flag, // 0 - ERC20, 1 - baseInETH, 2 - quoteInETH, 3 - baseOutETH, 4 - quoteOutETH
uint256 deadline
) external virtual override judgeExpired(deadline) {
if(baseInAmount > 0)
IDODOV2(dodoApprove).claimTokens(IDODOV2(DPPAddress)._BASE_TOKEN_(), msg.sender, DPPAddress, baseInAmount);
if(quoteInAmount > 0)
IDODOV2(dodoApprove).claimTokens(IDODOV2(DPPAddress)._QUOTE_TOKEN_(), msg.sender, DPPAddress, quoteInAmount);
) external virtual override payable judgeExpired(deadline) {
_deposit(
msg.sender,
DPPAddress,
IDODOV2(DPPAddress)._BASE_TOKEN_(),
baseInAmount,
flag == 1
);
_deposit(
msg.sender,
DPPAddress,
IDODOV2(DPPAddress)._QUOTE_TOKEN_(),
quoteInAmount,
flag == 2
);
IDODOV2(IDODOV2(DPPAddress)._OWNER_()).reset(
msg.sender,
newLpFeeRate,
@@ -257,81 +255,9 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
baseOutAmount,
quoteOutAmount
);
}
function resetDODOPrivatePoolETH(
address DPPAddress,
uint256 newLpFeeRate,
uint256 newMtFeeRate,
uint256 newI,
uint256 newK,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 baseOutAmount,
uint256 quoteOutAmount,
uint8 flag, // 1 - baseInETH, 2 - quoteInETH, 3 - baseOutETH, 4 - quoteOutETH
uint256 deadline
) external virtual override payable judgeExpired(deadline) {
if(baseInAmount > 0){
if(flag == 1){
require(msg.value == baseInAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
IWETH(_WETH_).deposit{value: baseInAmount}();
assert(IWETH(_WETH_).transfer(DPPAddress, baseInAmount));
}else {
IDODOV2(dodoApprove).claimTokens(IDODOV2(DPPAddress)._BASE_TOKEN_(), msg.sender, DPPAddress, baseInAmount);
}
}
if(quoteInAmount > 0){
if(flag == 2){
require(msg.value == quoteInAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
IWETH(_WETH_).deposit{value: quoteInAmount}();
assert(IWETH(_WETH_).transfer(DPPAddress, quoteInAmount));
}else {
IDODOV2(dodoApprove).claimTokens(IDODOV2(DPPAddress)._QUOTE_TOKEN_(), msg.sender, DPPAddress, quoteInAmount);
}
}
if( (flag == 3 && baseOutAmount > 0) || (flag == 4 && quoteOutAmount > 0) ) {
IDODOV2(IDODOV2(DPPAddress)._OWNER_()).resetETH(
msg.sender,
newLpFeeRate,
newMtFeeRate,
newI,
newK,
baseOutAmount,
quoteOutAmount
);
if(baseOutAmount > 0) {
if(flag == 3) {
uint256 wethAmount = IWETH(_WETH_).balanceOf(address(this));
IWETH(_WETH_).withdraw(wethAmount);
(bool success,) = msg.sender.call{value:wethAmount}(new bytes(0));
require(success, 'DODOV2Proxy01: ETH_TRANSFER_FAILED');
}else {
IERC20(IDODOV2(DPPAddress)._BASE_TOKEN_()).universalTransfer(msg.sender, baseOutAmount);
}
}
if(quoteOutAmount > 0) {
if(flag == 4) {
uint256 wethAmount = IWETH(_WETH_).balanceOf(address(this));
IWETH(_WETH_).withdraw(wethAmount);
(bool success,) = msg.sender.call{value:wethAmount}(new bytes(0));
require(success, 'DODOV2Proxy01: ETH_TRANSFER_FAILED');
}else {
IERC20(IDODOV2(DPPAddress)._QUOTE_TOKEN_()).universalTransfer(msg.sender, quoteOutAmount);
}
}
}else {
IDODOV2(IDODOV2(DPPAddress)._OWNER_()).reset(
msg.sender,
newLpFeeRate,
newMtFeeRate,
newI,
newK,
baseOutAmount,
quoteOutAmount
);
}
_withdraw(msg.sender, IDODOV2(DPPAddress)._BASE_TOKEN_(), baseOutAmount, flag == 3);
_withdraw(msg.sender, IDODOV2(DPPAddress)._QUOTE_TOKEN_(), quoteOutAmount, flag == 4);
}
function dodoSwapETHToToken(
@@ -343,28 +269,38 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
uint256[] memory directions,
uint256 deadline
) external virtual override payable judgeExpired(deadline) returns (uint256 returnAmount) {
require(minReturnAmount > 0, 'DODOV2Proxy01: Min return should be bigger than 0.');
require(msg.value == fromTokenAmount, 'DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH');
uint256 originToTokenBalance = IERC20(toToken).balanceOf(msg.sender);
require(msg.value == fromTokenAmount, "DODOV2Proxy01: ETH_AMOUNT_NOT_MATCH");
IWETH(_WETH_).deposit{value: fromTokenAmount}();
IWETH(_WETH_).transfer(dodoPairs[0],IWETH(_WETH_).balanceOf(address(this)));
IWETH(_WETH_).transfer(dodoPairs[0], fromTokenAmount);
for (uint256 i = 0; i < dodoPairs.length; i++) {
if(i == dodoPairs.length - 1){
if (i == dodoPairs.length - 1) {
if (directions[i] == 0) {
returnAmount = IDODOV2(dodoPairs[i]).sellBase(assetTo);
IDODOV2(dodoPairs[i]).sellBase(assetTo);
} else {
returnAmount = IDODOV2(dodoPairs[i]).sellQuote(assetTo);
IDODOV2(dodoPairs[i]).sellQuote(assetTo);
}
} else {
if (directions[i] == 0) {
IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i+1]);
IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i + 1]);
} else {
IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i+1]);
IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i + 1]);
}
}
}
require(returnAmount >= minReturnAmount, 'DODOV2Proxy01: Return amount is not enough');
emit OrderHistory(ETH_ADDRESS, toToken, assetTo, fromTokenAmount, returnAmount, block.timestamp);
returnAmount = IERC20(toToken).balanceOf(msg.sender).sub(originToTokenBalance);
require(returnAmount >= minReturnAmount, "DODOV2Proxy01: Return amount is not enough");
emit OrderHistory(
ETH_ADDRESS,
toToken,
assetTo,
fromTokenAmount,
returnAmount,
block.timestamp
);
}
function dodoSwapTokenToETH(
@@ -376,11 +312,10 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
uint256[] memory directions,
uint256 deadline
) external virtual override judgeExpired(deadline) returns (uint256 returnAmount) {
require(minReturnAmount > 0, 'DODOV2Proxy01: Min return should be bigger than 0.');
IDODOV2(dodoApprove).claimTokens(fromToken, msg.sender, dodoPairs[0], fromTokenAmount);
for (uint256 i = 0; i < dodoPairs.length; i++) {
if(i == dodoPairs.length - 1){
if (i == dodoPairs.length - 1) {
if (directions[i] == 0) {
IDODOV2(dodoPairs[i]).sellBase(address(this));
} else {
@@ -388,20 +323,26 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
}
} else {
if (directions[i] == 0) {
IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i+1]);
IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i + 1]);
} else {
IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i+1]);
IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i + 1]);
}
}
}
returnAmount = IWETH(_WETH_).balanceOf(address(this));
require(returnAmount >= minReturnAmount, "DODOV2Proxy01: Return amount is not enough");
IWETH(_WETH_).withdraw(returnAmount);
require(returnAmount >= minReturnAmount, 'DODOV2Proxy01: Return amount is not enough');
IERC20(ETH_ADDRESS).universalTransfer(assetTo, returnAmount);
emit OrderHistory(fromToken, ETH_ADDRESS, assetTo, fromTokenAmount, returnAmount, block.timestamp);
assetTo.transfer(returnAmount);
emit OrderHistory(
fromToken,
ETH_ADDRESS,
assetTo,
fromTokenAmount,
returnAmount,
block.timestamp
);
}
function dodoSwapTokenToToken(
address payable assetTo,
address fromToken,
@@ -412,26 +353,34 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
uint256[] memory directions,
uint256 deadline
) external virtual override judgeExpired(deadline) returns (uint256 returnAmount) {
require(minReturnAmount > 0, 'DODOV2Proxy01: Min return should be bigger than 0.');
uint256 originToTokenBalance = IERC20(toToken).balanceOf(msg.sender);
IDODOV2(dodoApprove).claimTokens(fromToken, msg.sender, dodoPairs[0], fromTokenAmount);
for (uint256 i = 0; i < dodoPairs.length; i++) {
if(i == dodoPairs.length - 1){
if (i == dodoPairs.length - 1) {
if (directions[i] == 0) {
returnAmount = IDODOV2(dodoPairs[i]).sellBase(assetTo);
IDODOV2(dodoPairs[i]).sellBase(assetTo);
} else {
returnAmount = IDODOV2(dodoPairs[i]).sellQuote(assetTo);
IDODOV2(dodoPairs[i]).sellQuote(assetTo);
}
} else {
if (directions[i] == 0) {
IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i+1]);
IDODOV2(dodoPairs[i]).sellBase(dodoPairs[i + 1]);
} else {
IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i+1]);
IDODOV2(dodoPairs[i]).sellQuote(dodoPairs[i + 1]);
}
}
}
require(returnAmount >= minReturnAmount, 'DODOV2Proxy01: Return amount is not enough');
emit OrderHistory(fromToken, toToken, assetTo, fromTokenAmount, returnAmount, block.timestamp);
returnAmount = IERC20(toToken).balanceOf(msg.sender).sub(originToTokenBalance);
require(returnAmount >= minReturnAmount, "DODOV2Proxy01: Return amount is not enough");
emit OrderHistory(
fromToken,
toToken,
assetTo,
fromTokenAmount,
returnAmount,
block.timestamp
);
}
function externalSwap(
@@ -444,21 +393,64 @@ contract DODOV2Proxy01 is IDODOV2Proxy01 {
bytes memory callDataConcat,
uint256 deadline
) external virtual override payable judgeExpired(deadline) returns (uint256 returnAmount) {
require(minReturnAmount > 0, 'DODOV2Proxy01: Min return should be bigger then 0.');
if (fromToken != ETH_ADDRESS) {
IDODOV2(dodoApprove).claimTokens(fromToken, msg.sender, address(this), fromTokenAmount);
IERC20(fromToken).universalApprove(approveTarget, fromTokenAmount);
IERC20(fromToken).universalApproveMax(approveTarget, fromTokenAmount);
}
(bool success, ) = to.call{value: fromToken == ETH_ADDRESS ? msg.value : 0}(callDataConcat);
require(success, 'DODOV2Proxy01: Contract Swap execution Failed');
require(success, "DODOV2Proxy01: Contract Swap execution Failed");
IERC20(fromToken).universalTransfer(
msg.sender,
IERC20(fromToken).universalBalanceOf(address(this))
);
IERC20(fromToken).universalTransfer(msg.sender, IERC20(fromToken).universalBalanceOf(address(this)));
returnAmount = IERC20(toToken).universalBalanceOf(address(this));
require(returnAmount >= minReturnAmount, 'DODOV2Proxy01: Return amount is not enough');
require(returnAmount >= minReturnAmount, "DODOV2Proxy01: Return amount is not enough");
IERC20(toToken).universalTransfer(msg.sender, returnAmount);
emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount, block.timestamp);
emit OrderHistory(
fromToken,
toToken,
msg.sender,
fromTokenAmount,
returnAmount,
block.timestamp
);
}
function _deposit(
address from,
address to,
address token,
uint256 amount,
bool isETH
) internal {
if (isETH) {
if (amount > 0) {
IWETH(_WETH_).deposit{value: amount}();
SafeERC20.safeTransfer(IERC20(_WETH_), to, amount);
}
} else {
IDODOV2(dodoApprove).claimTokens(token, from, to, amount);
}
}
function _withdraw(
address to,
address token,
uint256 amount,
bool isETH
) internal {
if (isETH) {
if (amount > 0) {
IWETH(_WETH_).withdraw(amount);
msg.sender.transfer(amount);
}
} else {
SafeERC20.safeTransfer(IERC20(token), to, amount);
}
}
}

View File

@@ -7,23 +7,25 @@
pragma solidity 0.6.9;
import {SafeMath} from "./SafeMath.sol";
import {SafeMath} from "../lib/SafeMath.sol";
import {IERC20} from "../intf/IERC20.sol";
import {SafeERC20} from "./SafeERC20.sol";
import {SafeERC20} from "../lib/SafeERC20.sol";
library UniversalERC20 {
using SafeMath for uint256;
using SafeERC20 for IERC20;
IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000);
IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function isETH(IERC20 token) internal pure returns (bool) {
return (token == ZERO_ADDRESS || token == ETH_ADDRESS);
return token == ETH_ADDRESS;
}
function universalTransfer(IERC20 token, address payable to, uint256 amount) internal {
function universalTransfer(
IERC20 token,
address payable to,
uint256 amount
) internal {
if (amount > 0) {
if (isETH(token)) {
to.transfer(amount);
@@ -33,32 +35,20 @@ library UniversalERC20 {
}
}
function universalApprove(IERC20 token, address to, uint256 amount) internal {
require(!isETH(token), "ETH Don't need approve");
if (amount == 0) {
token.safeApprove(to, 0);
} else {
uint256 allowance = token.allowance(address(this), to);
if (allowance < amount) {
if (allowance > 0) {
token.safeApprove(to, 0);
}
token.safeApprove(to, amount);
}
}
}
function universalApproveMax(IERC20 token, address to, uint256 amount) internal {
function universalApproveMax(
IERC20 token,
address to,
uint256 amount
) internal {
uint256 allowance = token.allowance(address(this), to);
if (allowance < amount) {
if (allowance > 0) {
token.safeApprove(to, 0);
}
token.safeApprove(to, uint(-1));
token.safeApprove(to, uint256(-1));
}
}
function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) {
if (isETH(token)) {
return who.balance;

View File

@@ -1,6 +1,6 @@
/**
*Submitted for verification at Etherscan.io on 2020-10-10
*/
*/
// File: contracts/intf/IDODO.sol
@@ -17,8 +17,8 @@ pragma experimental ABIEncoderV2;
import {IDODO} from "../intf/IDODO.sol";
import {SafeMath} from "../lib/SafeMath.sol";
import {DecimalMath} from "../lib/DecimalMath.sol";
// import {DODOMath} from "../lib/DODOMath.sol";
// import {DODOMath} from "../lib/DODOMath.sol";
library DODOMath {
using SafeMath for uint256;
@@ -37,10 +37,10 @@ library DODOMath {
uint256 i,
uint256 k
) internal pure returns (uint256) {
uint256 fairAmount = DecimalMath.mul(i, V1.sub(V2)); // i*delta
uint256 fairAmount = DecimalMath.mulFloor(i, V1.sub(V2)); // i*delta
uint256 V0V0V1V2 = DecimalMath.divCeil(V0.mul(V0).div(V1), V2);
uint256 penalty = DecimalMath.mul(k, V0V0V1V2); // k(V0^2/V1/V2)
return DecimalMath.mul(fairAmount, DecimalMath.ONE.sub(k).add(penalty));
uint256 penalty = DecimalMath.mulFloor(k, V0V0V1V2); // k(V0^2/V1/V2)
return DecimalMath.mulFloor(fairAmount, DecimalMath.ONE.sub(k).add(penalty));
}
/*
@@ -66,8 +66,8 @@ library DODOMath {
) internal pure returns (uint256) {
// calculate -b value and sig
// -b = (1-k)Q1-kQ0^2/Q1+i*deltaB
uint256 kQ02Q1 = DecimalMath.mul(k, Q0).mul(Q0).div(Q1); // kQ0^2/Q1
uint256 b = DecimalMath.mul(DecimalMath.ONE.sub(k), Q1); // (1-k)Q1
uint256 kQ02Q1 = DecimalMath.mulFloor(k, Q0).mul(Q0).div(Q1); // kQ0^2/Q1
uint256 b = DecimalMath.mulFloor(DecimalMath.ONE.sub(k), Q1); // (1-k)Q1
bool minusbSig = true;
if (deltaBSig) {
b = b.add(ideltaB); // (1-k)Q1+i*deltaB
@@ -83,9 +83,9 @@ library DODOMath {
}
// calculate sqrt
uint256 squareRoot = DecimalMath.mul(
uint256 squareRoot = DecimalMath.mulFloor(
DecimalMath.ONE.sub(k).mul(4),
DecimalMath.mul(k, Q0).mul(Q0)
DecimalMath.mulFloor(k, Q0).mul(Q0)
); // 4(1-k)kQ0^2
squareRoot = b.mul(b).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0)
@@ -117,15 +117,14 @@ library DODOMath {
uint256 fairAmount
) internal pure returns (uint256 V0) {
// V0 = V1+V1*(sqrt-1)/2k
uint256 sqrt = DecimalMath.divCeil(DecimalMath.mul(k, fairAmount).mul(4), V1);
uint256 sqrt = DecimalMath.divCeil(DecimalMath.mulFloor(k, fairAmount).mul(4), V1);
sqrt = sqrt.add(DecimalMath.ONE).mul(DecimalMath.ONE).sqrt();
uint256 premium = DecimalMath.divCeil(sqrt.sub(DecimalMath.ONE), k.mul(2));
// V0 is greater than or equal to V1 according to the solution
return DecimalMath.mul(V1, DecimalMath.ONE.add(premium));
return DecimalMath.mulFloor(V1, DecimalMath.ONE.add(premium));
}
}
contract DODOSellHelper {
using SafeMath for uint256;
@@ -191,7 +190,7 @@ contract DODOSellHelper {
uint256 B2 = DODOMath._SolveQuadraticFunctionForTrade(
state.baseTarget,
state.baseTarget,
DecimalMath.mul(i, amount),
DecimalMath.mulFloor(i, amount),
false,
state.K
);
@@ -207,7 +206,7 @@ contract DODOSellHelper {
uint256 B2 = DODOMath._SolveQuadraticFunctionForTrade(
state.baseTarget,
state.B,
DecimalMath.mul(i, amount),
DecimalMath.mulFloor(i, amount),
false,
state.K
);
@@ -223,4 +222,4 @@ contract DODOSellHelper {
uint256 i = DecimalMath.divFloor(ONE, state.oraclePrice);
return DODOMath._GeneralIntegrate(state.quoteTarget, Q1, state.Q, i, state.K);
}
}
}

View File

@@ -9,7 +9,7 @@ pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;
interface IDODOV2Proxy01 {
function dodoSwapETHToToken(
function dodoSwapETHToToken(
address payable assetTo,
address toToken,
uint256 fromTokenAmount,
@@ -51,7 +51,6 @@ interface IDODOV2Proxy01 {
uint256 deadline
) external payable returns (uint256 returnAmount);
function createDODOVendingMachine(
address assetTo,
address baseToken,
@@ -63,29 +62,25 @@ interface IDODOV2Proxy01 {
uint256 i,
uint256 k,
uint256 deadline
) external payable returns (address newVendingMachine,uint256 shares);
) external payable returns (address newVendingMachine, uint256 shares);
function addDVMLiquidity(
address DVMAddress,
address to,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 baseMinAmount,
uint256 quoteMinAmount,
uint256 deadline
) external returns (uint256 shares,uint256 baseAdjustedInAmount,uint256 quoteAdjustedInAmount);
function addDVMLiquidityETH(
address DVMAddress,
address to,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 baseMinAmount,
uint256 quoteMinAmount,
uint8 flag, // 1 - baseInETH, 2 - quoteInETH
uint8 flag, // 0 - ERC20, 1 - baseInETH, 2 - quoteInETH
uint256 deadline
) external payable returns (uint256 shares,uint256 baseAdjustedInAmount,uint256 quoteAdjustedInAmount);
)
external
payable
returns (
uint256 shares,
uint256 baseAdjustedInAmount,
uint256 quoteAdjustedInAmount
);
function createDODOPrivatePool(
address baseToken,
@@ -100,20 +95,6 @@ interface IDODOV2Proxy01 {
) external payable returns (address newPrivatePool);
function resetDODOPrivatePool(
address DPPAddress,
uint256 newLpFeeRate,
uint256 newMtFeeRate,
uint256 newI,
uint256 newK,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 baseOutAmount,
uint256 quoteOutAmount,
uint256 deadline
) external;
function resetDODOPrivatePoolETH(
address DPPAddress,
uint256 newLpFeeRate,
uint256 newMtFeeRate,
@@ -123,12 +104,11 @@ interface IDODOV2Proxy01 {
uint256 quoteInAmount,
uint256 baseOutAmount,
uint256 quoteOutAmount,
uint8 flag, // 1 - baseInETH, 2 - quoteInETH, 3 - baseOutETH, 4 - quoteOutETH
uint8 flag, // 0 - ERC20, 1 - baseInETH, 2 - quoteInETH, 3 - baseOutETH, 4 - quoteOutETH
uint256 deadline
) external payable;
//TODO: addLiquidityToClassical
//TODO: removeLiquidityToClassical
}

View File

@@ -69,7 +69,7 @@ library DODOMath {
DecimalMath.ONE
);
// V0 is greater than or equal to V1 according to the solution
return DecimalMath.mul(V1, premium);
return DecimalMath.mulFloor(V1, premium);
}
/*
@@ -103,6 +103,10 @@ library DODOMath {
uint256 k
) internal pure returns (uint256) {
require(V0 > 0, "TARGET_IS_ZERO");
if (delta == 0) {
return 0;
}
if (k == DecimalMath.ONE) {
// if k==1
// Q2=Q1/(1+ideltaBQ1/Q0/Q0)
@@ -133,9 +137,9 @@ library DODOMath {
bAbs = bAbs.div(DecimalMath.ONE);
// calculate sqrt
uint256 squareRoot = DecimalMath.mul(
uint256 squareRoot = DecimalMath.mulFloor(
DecimalMath.ONE.sub(k).mul(4),
DecimalMath.mul(k, V0).mul(V0)
DecimalMath.mulFloor(k, V0).mul(V0)
); // 4(1-k)kQ0^2
squareRoot = bAbs.mul(bAbs).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0)

View File

@@ -22,10 +22,6 @@ library DecimalMath {
uint256 constant ONE = 10**18;
uint256 constant ONE2 = 10**36;
function mul(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(d) / (10**18);
}
function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(d) / (10**18);
}

View File

@@ -1,34 +0,0 @@
/*
Copyright 2020 DODO ZOO.
SPDX-License-Identifier: Apache-2.0
*/
pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;
library ExternalCall {
// Source: https://github.com/gnosis/MultiSigWallet/blob/master/contracts/MultiSigWallet.sol
// call has been separated into its own function in order to take advantage
// of the Solidity's code generator to produce a loop that copies tx.data into memory.
function externalCall(address destination, uint value, bytes memory data, uint dataOffset, uint dataLength, uint gasLimit) internal returns(bool result) {
// solium-disable-next-line security/no-inline-assembly
if (gasLimit == 0) {
gasLimit = gasleft() - 40000;
}
assembly {
let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention)
let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that
result := call(
gasLimit,
destination,
value,
add(d, dataOffset),
dataLength, // Size of the input (in bytes) - this is what fixes the padding problem
x,
0 // Output is ignored, therefore the output size is zero
)
}
}
}

View File

@@ -234,12 +234,12 @@ library PMMPricing {
function getMidPrice(PMMState memory state) internal pure returns (uint256 midPrice) {
if (state.R == RState.BELOW_ONE) {
uint256 R = DecimalMath.divFloor(state.Q0.mul(state.Q0).div(state.Q), state.Q);
R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mul(state.K, R));
R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R));
return DecimalMath.divFloor(state.i, R);
} else {
uint256 R = DecimalMath.divFloor(state.B0.mul(state.B0).div(state.B), state.B);
R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mul(state.K, R));
return DecimalMath.mul(state.i, R);
R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R));
return DecimalMath.mulFloor(state.i, R);
}
}
}

View File

@@ -2,155 +2,155 @@ const fs = require("fs");
const file = fs.createWriteStream("../deploy-detail.txt");
let logger = new console.Console(file, file);
const SmartApprove = artifacts.require("SmartApprove");
const SmartSwap = artifacts.require("SmartSwap");
const DODOSellHelper = artifacts.require("DODOSellHelper");
const TestERC20 = artifacts.require("TestERC20");
const NaiveOracle = artifacts.require("NaiveOracle");
const DODOZoo = artifacts.require("DODOZoo");
// const SmartApprove = artifacts.require("DODOApprove");
// const SmartSwap = artifacts.require("SmartSwap");
// const DODOSellHelper = artifacts.require("DODOSellHelper");
// const TestERC20 = artifacts.require("TestERC20");
// const NaiveOracle = artifacts.require("NaiveOracle");
// const DODOZoo = artifacts.require("DODOZoo");
const DEPLOY_ROUTE = true;
const DEPLOY_ROUTE = false;
const DEPLOY_KOVAN_TOKEN = false;
module.exports = async (deployer, network, accounts) => {
let DODOSellHelperAddress = "";
let DODOZooAddress = "";
let WETHAddress = "";
let SmartApproveAddress = "";
if (network == "kovan") {
DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3";
DODOZooAddress = "0x92230e929a2226b29ed3441ae5524886347c60c8";
WETHAddress = "0x5eca15b12d959dfcf9c71c59f8b467eb8c6efd0b";
SmartApproveAddress = "0x5627b7DEb3055e1e899003FDca0716b32C382084";
} else if (network == "live") {
DODOSellHelperAddress = "0x533da777aedce766ceae696bf90f8541a4ba80eb";
DODOZooAddress = "0x3a97247df274a17c59a3bd12735ea3fcdfb49950";
WETHAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
SmartApproveAddress = "0xe380Ad3181A69BF92133D2feb609867c4adC61eA";
} else return;
// let DODOSellHelperAddress = "";
// let DODOZooAddress = "";
// let WETHAddress = "";
// let SmartApproveAddress = "";
// if (network == "kovan") {
// DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3";
// DODOZooAddress = "0x92230e929a2226b29ed3441ae5524886347c60c8";
// WETHAddress = "0x5eca15b12d959dfcf9c71c59f8b467eb8c6efd0b";
// SmartApproveAddress = "0x5627b7DEb3055e1e899003FDca0716b32C382084";
// } else if (network == "live") {
// DODOSellHelperAddress = "0x533da777aedce766ceae696bf90f8541a4ba80eb";
// DODOZooAddress = "0x3a97247df274a17c59a3bd12735ea3fcdfb49950";
// WETHAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
// SmartApproveAddress = "0xe380Ad3181A69BF92133D2feb609867c4adC61eA";
// } else return;
logger.log("====================================================");
logger.log("network type: " + network);
logger.log("Deploy time: " + new Date().toLocaleString());
// logger.log("====================================================");
// logger.log("network type: " + network);
// logger.log("Deploy time: " + new Date().toLocaleString());
if (DEPLOY_ROUTE) {
logger.log("Deploy type: Smart Route");
if (SmartApproveAddress == "") {
await deployer.deploy(SmartApprove);
SmartApproveAddress = SmartApprove.address;
}
if (DODOSellHelperAddress == "") {
await deployer.deploy(DODOSellHelper);
DODOSellHelperAddress = DODOSellHelper.address;
}
logger.log("SmartApprove Address: ", SmartApproveAddress);
logger.log("DODOSellHelper Address: ", DODOSellHelperAddress);
await deployer.deploy(
SmartSwap,
SmartApproveAddress,
DODOSellHelperAddress,
WETHAddress
);
logger.log("SmartSwap Address: ", SmartSwap.address);
// if (DEPLOY_ROUTE) {
// logger.log("Deploy type: Smart Route");
// if (SmartApproveAddress == "") {
// await deployer.deploy(SmartApprove);
// SmartApproveAddress = SmartApprove.address;
// }
// if (DODOSellHelperAddress == "") {
// await deployer.deploy(DODOSellHelper);
// DODOSellHelperAddress = DODOSellHelper.address;
// }
// logger.log("SmartApprove Address: ", SmartApproveAddress);
// logger.log("DODOSellHelper Address: ", DODOSellHelperAddress);
// await deployer.deploy(
// SmartSwap,
// SmartApproveAddress,
// DODOSellHelperAddress,
// WETHAddress
// );
// logger.log("SmartSwap Address: ", SmartSwap.address);
// const SmartApproveInstance = await SmartApprove.at(SmartApproveAddress);
// var tx = await SmartApproveInstance.setSmartSwap(SmartSwap.address);
// logger.log("SmartApprovce setSmartSwap tx: ", tx.tx);
}
// // const SmartApproveInstance = await SmartApprove.at(SmartApproveAddress);
// // var tx = await SmartApproveInstance.setSmartSwap(SmartSwap.address);
// // logger.log("SmartApprovce setSmartSwap tx: ", tx.tx);
// }
if (DEPLOY_KOVAN_TOKEN) {
logger.log("Deploy type: Create Tokens and Trading Pairs");
await deployer.deploy(TestERC20, "USDC", 6, "USDC");
const USDCAddr = TestERC20.address;
logger.log("USDC Addr: ", USDCAddr);
await deployer.deploy(TestERC20, "USDT", 6, "USDT");
const USDTAddr = TestERC20.address;
logger.log("USDT Addr: ", USDTAddr);
await deployer.deploy(TestERC20, "DODO", 18, "DODO");
const DODOAddr = TestERC20.address;
logger.log("DODO Addr: ", DODOAddr);
await deployer.deploy(TestERC20, "WOO", 18, "WOO");
const WooAddr = TestERC20.address;
logger.log("WOO Addr: ", WooAddr);
const WETHAddr = WETHAddress;
logger.log("WETH Addr: ", WETHAddr);
// if (DEPLOY_KOVAN_TOKEN) {
// logger.log("Deploy type: Create Tokens and Trading Pairs");
// await deployer.deploy(TestERC20, "USDC", 6, "USDC");
// const USDCAddr = TestERC20.address;
// logger.log("USDC Addr: ", USDCAddr);
// await deployer.deploy(TestERC20, "USDT", 6, "USDT");
// const USDTAddr = TestERC20.address;
// logger.log("USDT Addr: ", USDTAddr);
// await deployer.deploy(TestERC20, "DODO", 18, "DODO");
// const DODOAddr = TestERC20.address;
// logger.log("DODO Addr: ", DODOAddr);
// await deployer.deploy(TestERC20, "WOO", 18, "WOO");
// const WooAddr = TestERC20.address;
// logger.log("WOO Addr: ", WooAddr);
// const WETHAddr = WETHAddress;
// logger.log("WETH Addr: ", WETHAddr);
let config = {
lpFeeRate: "2000000000000000",
mtFeeRate: "1000000000000000",
k: "100000000000000000",
gasPriceLimit: "100000000000",
};
// let config = {
// lpFeeRate: "2000000000000000",
// mtFeeRate: "1000000000000000",
// k: "100000000000000000",
// gasPriceLimit: "100000000000",
// };
const DODOZooInstance = await DODOZoo.at(DODOZooAddress);
// const DODOZooInstance = await DODOZoo.at(DODOZooAddress);
//USDT-USDC
await deployer.deploy(NaiveOracle);
var USDT_USDC_Oracle = NaiveOracle.address;
await DODOZooInstance.breedDODO(
accounts[0],
USDTAddr,
USDCAddr,
USDT_USDC_Oracle,
config.lpFeeRate,
config.mtFeeRate,
config.k,
config.gasPriceLimit
);
const USDT_USDC_Addr = await DODOZooInstance.getDODO(USDTAddr, USDCAddr);
logger.log("USDT_USDC_Addr:", USDT_USDC_Addr);
// //USDT-USDC
// await deployer.deploy(NaiveOracle);
// var USDT_USDC_Oracle = NaiveOracle.address;
// await DODOZooInstance.breedDODO(
// accounts[0],
// USDTAddr,
// USDCAddr,
// USDT_USDC_Oracle,
// config.lpFeeRate,
// config.mtFeeRate,
// config.k,
// config.gasPriceLimit
// );
// const USDT_USDC_Addr = await DODOZooInstance.getDODO(USDTAddr, USDCAddr);
// logger.log("USDT_USDC_Addr:", USDT_USDC_Addr);
// DODO-USDT
await deployer.deploy(NaiveOracle);
var DODO_USDT_Oracle = NaiveOracle.address;
await DODOZooInstance.breedDODO(
accounts[0],
DODOAddr,
USDTAddr,
DODO_USDT_Oracle,
config.lpFeeRate,
config.mtFeeRate,
config.k,
config.gasPriceLimit
);
const DODO_USDT_Addr = await DODOZooInstance.getDODO(DODOAddr, USDTAddr);
logger.log("DODO_USDT_Addr:", DODO_USDT_Addr);
// // DODO-USDT
// await deployer.deploy(NaiveOracle);
// var DODO_USDT_Oracle = NaiveOracle.address;
// await DODOZooInstance.breedDODO(
// accounts[0],
// DODOAddr,
// USDTAddr,
// DODO_USDT_Oracle,
// config.lpFeeRate,
// config.mtFeeRate,
// config.k,
// config.gasPriceLimit
// );
// const DODO_USDT_Addr = await DODOZooInstance.getDODO(DODOAddr, USDTAddr);
// logger.log("DODO_USDT_Addr:", DODO_USDT_Addr);
// //WETH-USDC
await deployer.deploy(NaiveOracle);
var WETH_USDC_Oracle = NaiveOracle.address;
await DODOZooInstance.breedDODO(
accounts[0],
WETHAddr,
USDCAddr,
WETH_USDC_Oracle,
config.lpFeeRate,
config.mtFeeRate,
config.k,
config.gasPriceLimit
);
const WETH_USDC_Addr = await DODOZooInstance.getDODO(WETHAddr, USDCAddr);
logger.log("WETH_USDC_Addr:", WETH_USDC_Addr);
// // //WETH-USDC
// await deployer.deploy(NaiveOracle);
// var WETH_USDC_Oracle = NaiveOracle.address;
// await DODOZooInstance.breedDODO(
// accounts[0],
// WETHAddr,
// USDCAddr,
// WETH_USDC_Oracle,
// config.lpFeeRate,
// config.mtFeeRate,
// config.k,
// config.gasPriceLimit
// );
// const WETH_USDC_Addr = await DODOZooInstance.getDODO(WETHAddr, USDCAddr);
// logger.log("WETH_USDC_Addr:", WETH_USDC_Addr);
//WOO-USDT
await deployer.deploy(NaiveOracle);
var WOO_USDT_Oracle = NaiveOracle.address;
await DODOZooInstance.breedDODO(
accounts[0],
WooAddr,
USDTAddr,
WOO_USDT_Oracle,
config.lpFeeRate,
config.mtFeeRate,
config.k,
config.gasPriceLimit
);
const WOO_USDT_Addr = await DODOZooInstance.getDODO(WooAddr, USDTAddr);
logger.log("WOO_USDT_Addr:", WOO_USDT_Addr);
// //WOO-USDT
// await deployer.deploy(NaiveOracle);
// var WOO_USDT_Oracle = NaiveOracle.address;
// await DODOZooInstance.breedDODO(
// accounts[0],
// WooAddr,
// USDTAddr,
// WOO_USDT_Oracle,
// config.lpFeeRate,
// config.mtFeeRate,
// config.k,
// config.gasPriceLimit
// );
// const WOO_USDT_Addr = await DODOZooInstance.getDODO(WooAddr, USDTAddr);
// logger.log("WOO_USDT_Addr:", WOO_USDT_Addr);
//TODO:ing enableBaseDeposit enableQuoteDeposit enableTrading
//TODO:ing apporve pair to token
//TODO:ing mint to lp
//TODO:ing deposit to Base && quote pool
}
// //TODO:ing enableBaseDeposit enableQuoteDeposit enableTrading
// //TODO:ing apporve pair to token
// //TODO:ing mint to lp
// //TODO:ing deposit to Base && quote pool
// }
};

View File

@@ -48,16 +48,19 @@ describe("Trader", () => {
});
describe("trade", () => {
// it.only("basic check", async () => {
// console.log(await ctx.DVM.methods.getVaultReserve().call())
// console.log(await ctx.DVM.methods.getPMMState().call())
// console.log(await ctx.DVM.methods.getMidPrice().call())
// console.log(await ctx.DVM.methods.querySellQuote(ctx.Deployer, decimalStr("200")).call())
// console.log(ctx.BASE.options.address)
// console.log(await ctx.DVM.methods._BASE_TOKEN_().call())
// console.log(ctx.QUOTE.options.address)
// console.log(await ctx.DVM.methods._QUOTE_TOKEN_().call())
// })
it.only("basic check", async () => {
console.log(await ctx.DVM.methods.symbol().call())
console.log(await ctx.DVM.methods.decimals().call())
console.log(await ctx.DVM.methods.name().call())
// console.log(await ctx.DVM.methods.getVaultReserve().call())
// console.log(await ctx.DVM.methods.getPMMState().call())
// console.log(await ctx.DVM.methods.getMidPrice().call())
// console.log(await ctx.DVM.methods.querySellQuote(ctx.Deployer, decimalStr("200")).call())
// console.log(ctx.BASE.options.address)
// console.log(await ctx.DVM.methods._BASE_TOKEN_().call())
// console.log(ctx.QUOTE.options.address)
// console.log(await ctx.DVM.methods._QUOTE_TOKEN_().call())
})
// it.only("mannually buy", async () => {
// await ctx.QUOTE.methods.transfer(ctx.DVM.options.address, decimalStr("100")).send(ctx.sendParam(lp))