# cpV2-diff

cpV2-diff
已产生： 2021/12/5 上午10:56:57
模式： 全部
文件：

| -+ | /**
|  | *Submitted for verification at BscScan.com on 2021-03-14
|  | */
// File: contracts/lib/SafeMath.sol | = | // File: contracts/lib/SafeMath.sol
/* |  | /*
Copyright 2020 DODO ZOO. |  | Copyright 2020 DODO ZOO.
SPDX-License-Identifier: Apache-2.0 |  | SPDX-License-Identifier: Apache-2.0
*/ |  | */
pragma solidity 0.6.9; |  | pragma solidity 0.6.9;
pragma experimental ABIEncoderV2; |  | pragma experimental ABIEncoderV2;
/** |  | /**
* @title SafeMath |  | * @title SafeMath
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice Math operations with safety checks that revert on error |  | * @notice Math operations with safety checks that revert on error
*/ |  | */
library SafeMath { |  | library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) { |  | function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) { |  | if (a == 0) {
return 0; |  | return 0;
} |  | }
uint256 c = a * b; |  | uint256 c = a * b;
require(c / a == b, "MUL_ERROR"); |  | require(c / a == b, "MUL_ERROR");
return c; |  | return c;
} |  | }
function div(uint256 a, uint256 b) internal pure returns (uint256) { |  | function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "DIVIDING_ERROR"); |  | require(b > 0, "DIVIDING_ERROR");
return a / b; |  | return a / b;
} |  | }
function divCeil(uint256 a, uint256 b) internal pure returns (uint256) { |  | function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 quotient = div(a, b); |  | uint256 quotient = div(a, b);
uint256 remainder = a - quotient * b; |  | uint256 remainder = a - quotient * b;
if (remainder > 0) { |  | if (remainder > 0) {
return quotient + 1; |  | return quotient + 1;
} else { |  | } else {
return quotient; |  | return quotient;
} |  | }
} |  | }
function sub(uint256 a, uint256 b) internal pure returns (uint256) { |  | function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SUB_ERROR"); |  | require(b <= a, "SUB_ERROR");
return a - b; |  | return a - b;
} |  | }
function add(uint256 a, uint256 b) internal pure returns (uint256) { |  | function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b; |  | uint256 c = a + b;
require(c >= a, "ADD_ERROR"); |  | require(c >= a, "ADD_ERROR");
return c; |  | return c;
} |  | }
function sqrt(uint256 x) internal pure returns (uint256 y) { |  | function sqrt(uint256 x) internal pure returns (uint256 y) {
uint256 z = x / 2 + 1; |  | uint256 z = x / 2 + 1;
y = x; |  | y = x;
while (z < y) { |  | while (z < y) {
y = z; |  | y = z;
z = (x / z + z) / 2; |  | z = (x / z + z) / 2;
} |  | }
} |  | }
} |  | }
// File: contracts/lib/DecimalMath.sol |  | // File: contracts/lib/DecimalMath.sol
| -+ |
/** | = | /**
* @title DecimalMath |  | * @title DecimalMath
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice Functions for fixed point number with 18 decimals |  | * @notice Functions for fixed point number with 18 decimals
*/ |  | */
library DecimalMath { |  | library DecimalMath {
using SafeMath for uint256; |  | using SafeMath for uint256;
uint256 internal constant ONE = 10**18; |  | uint256 internal constant ONE = 10**18;
uint256 internal constant ONE2 = 10**36; |  | uint256 internal constant ONE2 = 10**36;
function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) { |  | function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(d) / (10**18); |  | return target.mul(d) / (10**18);
} |  | }
function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) { |  | function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(d).divCeil(10**18); |  | return target.mul(d).divCeil(10**18);
} |  | }
function divFloor(uint256 target, uint256 d) internal pure returns (uint256) { |  | function divFloor(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(10**18).div(d); |  | return target.mul(10**18).div(d);
} |  | }
function divCeil(uint256 target, uint256 d) internal pure returns (uint256) { |  | function divCeil(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(10**18).divCeil(d); |  | return target.mul(10**18).divCeil(d);
} |  | }
function reciprocalFloor(uint256 target) internal pure returns (uint256) { |  | function reciprocalFloor(uint256 target) internal pure returns (uint256) {
return uint256(10**36).div(target); |  | return uint256(10**36).div(target);
} |  | }
function reciprocalCeil(uint256 target) internal pure returns (uint256) { |  | function reciprocalCeil(uint256 target) internal pure returns (uint256) {
return uint256(10**36).divCeil(target); |  | return uint256(10**36).divCeil(target);
} |  | }
| +- |
function powFloor(uint256 target, uint256 e) internal pure returns (uint256) { |  |
if (e == 0) { |  |
return 10 ** 18; |  |
} else if (e == 1) { |  |
return target; |  |
} else { |  |
uint p = powFloor(target, e.div(2)); |  |
p = p.mul(p) / (10**18); |  |
if (e % 2 == 1) { |  |
p = p.mul(target) / (10**18); |  |
} |  |
return p; |  |
} |  |
} |  |
} | = | }
// File: contracts/lib/Ownable.sol |  | // File: contracts/lib/Ownable.sol
/** |  | /**
* @title Ownable |  | * @title Ownable
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice Ownership related functions |  | * @notice Ownership related functions
*/ |  | */
contract Ownable { |  | contract Ownable {
address public _OWNER_; |  | address public _OWNER_;
address public _NEW_OWNER_; |  | address public _NEW_OWNER_;
// ============ Events ============ |  | // ============ Events ============
event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner); |  | event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); |  | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
// ============ Modifiers ============ |  | // ============ Modifiers ============
modifier onlyOwner() { |  | modifier onlyOwner() {
require(msg.sender == _OWNER_, "NOT_OWNER"); |  | require(msg.sender == _OWNER_, "NOT_OWNER");
_; |  | _;
} |  | }
// ============ Functions ============ |  | // ============ Functions ============
constructor() internal { |  | constructor() internal {
_OWNER_ = msg.sender; |  | _OWNER_ = msg.sender;
emit OwnershipTransferred(address(0), _OWNER_); |  | emit OwnershipTransferred(address(0), _OWNER_);
} |  | }
function transferOwnership(address newOwner) external virtual onlyOwner { | <> | function transferOwnership(address newOwner) external onlyOwner {
emit OwnershipTransferPrepared(_OWNER_, newOwner); | = | emit OwnershipTransferPrepared(_OWNER_, newOwner);
_NEW_OWNER_ = newOwner; |  | _NEW_OWNER_ = newOwner;
} |  | }
function claimOwnership() external { |  | function claimOwnership() external {
require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); |  | require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM");
emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); |  | emit OwnershipTransferred(_OWNER_, _NEW_OWNER_);
_OWNER_ = _NEW_OWNER_; |  | _OWNER_ = _NEW_OWNER_;
_NEW_OWNER_ = address(0); |  | _NEW_OWNER_ = address(0);
} |  | }
} |  | }
// File: contracts/intf/IERC20.sol |  | // File: contracts/intf/IERC20.sol
/** |  | /**
* @dev Interface of the ERC20 standard as defined in the EIP. |  | * @dev Interface of the ERC20 standard as defined in the EIP.
*/ |  | */
interface IERC20 { |  | interface IERC20 {
/** |  | /**
* @dev Returns the amount of tokens in existence. |  | * @dev Returns the amount of tokens in existence.
*/ |  | */
function totalSupply() external view returns (uint256); |  | function totalSupply() external view returns (uint256);
function decimals() external view returns (uint8); |  | function decimals() external view returns (uint8);
function name() external view returns (string memory); |  | function name() external view returns (string memory);
function symbol() external view returns (string memory); |  | function symbol() external view returns (string memory);
/** |  | /**
* @dev Returns the amount of tokens owned by `account`. |  | * @dev Returns the amount of tokens owned by `account`.
*/ |  | */
function balanceOf(address account) external view returns (uint256); |  | function balanceOf(address account) external view returns (uint256);
/** |  | /**
* @dev Moves `amount` tokens from the caller's account to `recipient`. |  | * @dev Moves `amount` tokens from the caller's account to `recipient`.
* |  | *
* Returns a boolean value indicating whether the operation succeeded. |  | * Returns a boolean value indicating whether the operation succeeded.
* |  | *
* Emits a {Transfer} event. |  | * Emits a {Transfer} event.
*/ |  | */
function transfer(address recipient, uint256 amount) external returns (bool); |  | function transfer(address recipient, uint256 amount) external returns (bool);
/** |  | /**
* @dev Returns the remaining number of tokens that `spender` will be |  | * @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is |  | * allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default. |  | * zero by default.
* |  | *
* This value changes when {approve} or {transferFrom} are called. |  | * This value changes when {approve} or {transferFrom} are called.
*/ |  | */
function allowance(address owner, address spender) external view returns (uint256); |  | function allowance(address owner, address spender) external view returns (uint256);
/** |  | /**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens. |  | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
* |  | *
* Returns a boolean value indicating whether the operation succeeded. |  | * Returns a boolean value indicating whether the operation succeeded.
* |  | *
* IMPORTANT: Beware that changing an allowance with this method brings the risk |  | * IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate |  | * that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race |  | * transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the |  | * condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards: |  | * desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 |  | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* |  | *
* Emits an {Approval} event. |  | * Emits an {Approval} event.
*/ |  | */
function approve(address spender, uint256 amount) external returns (bool); |  | function approve(address spender, uint256 amount) external returns (bool);
/** |  | /**
* @dev Moves `amount` tokens from `sender` to `recipient` using the |  | * @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's |  | * allowance mechanism. `amount` is then deducted from the caller's
* allowance. |  | * allowance.
* |  | *
* Returns a boolean value indicating whether the operation succeeded. |  | * Returns a boolean value indicating whether the operation succeeded.
* |  | *
* Emits a {Transfer} event. |  | * Emits a {Transfer} event.
*/ |  | */
function transferFrom( |  | function transferFrom(
address sender, |  | address sender,
address recipient, |  | address recipient,
uint256 amount |  | uint256 amount
) external returns (bool); |  | ) external returns (bool);
} |  | }
// File: contracts/lib/SafeERC20.sol |  | // File: contracts/lib/SafeERC20.sol
| +- |
/** | = | /**
* @title SafeERC20 |  | * @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token |  | * @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or |  | * contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be |  | * throw on failure) are also supported, non-reverting calls are assumed to be
* successful. |  | * successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, |  | * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc. |  | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/ |  | */
library SafeERC20 { |  | library SafeERC20 {
using SafeMath for uint256; |  | using SafeMath for uint256;
function safeTransfer( |  | function safeTransfer(
IERC20 token, |  | IERC20 token,
address to, |  | address to,
uint256 value |  | uint256 value
) internal { |  | ) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); |  | _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
} |  | }
function safeTransferFrom( |  | function safeTransferFrom(
IERC20 token, |  | IERC20 token,
address from, |  | address from,
address to, |  | address to,
uint256 value |  | uint256 value
) internal { |  | ) internal {
_callOptionalReturn( |  | _callOptionalReturn(
token, |  | token,
abi.encodeWithSelector(token.transferFrom.selector, from, to, value) |  | abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
); |  | );
} |  | }
function safeApprove( |  | function safeApprove(
IERC20 token, |  | IERC20 token,
address spender, |  | address spender,
uint256 value |  | uint256 value
) internal { |  | ) internal {
// safeApprove should only be called when setting an initial allowance, |  | // safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use |  | // or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance' |  | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length |  | // solhint-disable-next-line max-line-length
require( |  | require(
(value == 0) || (token.allowance(address(this), spender) == 0), |  | (value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance" |  | "SafeERC20: approve from non-zero to non-zero allowance"
); |  | );
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); |  | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
} |  | }
/** |  | /**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement |  | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false). |  | * on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call. |  | * @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants). |  | * @param data The call data (encoded using abi.encode or one of its variants).
*/ |  | */
function _callOptionalReturn(IERC20 token, bytes memory data) private { |  | function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since |  | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. |  | // we're implementing it ourselves.
// A Solidity high level call has three parts: |  | // A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code |  | // 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted |  | // 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data. |  | // 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length |  | // solhint-disable-next-line max-line-length
// solhint-disable-next-line avoid-low-level-calls |  | // solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data); |  | (bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed"); |  | require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) { |  | if (returndata.length > 0) {
// Return data is optional |  | // Return data is optional
// solhint-disable-next-line max-line-length |  | // solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); |  | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
} |  | }
} |  | }
} |  | }
// File: contracts/DODOVendingMachine/intf/IDVM.sol |  | // File: contracts/DODOVendingMachine/intf/IDVM.sol
interface IDVM { |  | interface IDVM {
function init( |  | function init(
address maintainer, |  | address maintainer,
address baseTokenAddress, |  | address baseTokenAddress,
address quoteTokenAddress, |  | address quoteTokenAddress,
uint256 lpFeeRate, |  | uint256 lpFeeRate,
address mtFeeRateModel, |  | address mtFeeRateModel,
uint256 i, |  | uint256 i,
uint256 k, |  | uint256 k,
bool isOpenTWAP |  | bool isOpenTWAP
) external; |  | ) external;
function _BASE_TOKEN_() external returns (address); |  | function _BASE_TOKEN_() external returns (address);
function _QUOTE_TOKEN_() external returns (address); |  | function _QUOTE_TOKEN_() external returns (address);
function _MT_FEE_RATE_MODEL_() external returns (address); |  | function _MT_FEE_RATE_MODEL_() external returns (address);
function getVaultReserve() external returns (uint256 baseReserve, uint256 quoteReserve); |  | function getVaultReserve() external returns (uint256 baseReserve, uint256 quoteReserve);
function sellBase(address to) external returns (uint256); |  | function sellBase(address to) external returns (uint256);
function sellQuote(address to) external returns (uint256); |  | function sellQuote(address to) external returns (uint256);
function buyShares(address to) external returns (uint256,uint256,uint256); |  | function buyShares(address to) external returns (uint256,uint256,uint256);
function addressToShortString(address _addr) external pure returns (string memory); | +- |
function getMidPrice() external view returns (uint256 midPrice); |  |
function sellShares( |  |
uint256 shareAmount, |  |
address to, |  |
uint256 baseMinAmount, |  |
uint256 quoteMinAmount, |  |
bytes calldata data, |  |
uint256 deadline |  |
) external returns (uint256 baseAmount, uint256 quoteAmount); |  |
} | = | }
// File: contracts/lib/InitializableOwnable.sol |  | // File: contracts/lib/InitializableOwnable.sol
/** |  | /**
* @title Ownable |  | * @title Ownable
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice Ownership related functions |  | * @notice Ownership related functions
*/ |  | */
contract InitializableOwnable { |  | contract InitializableOwnable {
address public _OWNER_; |  | address public _OWNER_;
address public _NEW_OWNER_; |  | address public _NEW_OWNER_;
bool internal _INITIALIZED_; |  | bool internal _INITIALIZED_;
// ============ Events ============ |  | // ============ Events ============
event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner); |  | event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); |  | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
// ============ Modifiers ============ |  | // ============ Modifiers ============
modifier notInitialized() { |  | modifier notInitialized() {
require(!_INITIALIZED_, "DODO_INITIALIZED"); |  | require(!_INITIALIZED_, "DODO_INITIALIZED");
_; |  | _;
} |  | }
modifier onlyOwner() { |  | modifier onlyOwner() {
require(msg.sender == _OWNER_, "NOT_OWNER"); |  | require(msg.sender == _OWNER_, "NOT_OWNER");
_; |  | _;
} |  | }
// ============ Functions ============ |  | // ============ Functions ============
function initOwner(address newOwner) public notInitialized { |  | function initOwner(address newOwner) public notInitialized {
_INITIALIZED_ = true; |  | _INITIALIZED_ = true;
_OWNER_ = newOwner; |  | _OWNER_ = newOwner;
} |  | }
function transferOwnership(address newOwner) public onlyOwner { |  | function transferOwnership(address newOwner) public onlyOwner {
emit OwnershipTransferPrepared(_OWNER_, newOwner); |  | emit OwnershipTransferPrepared(_OWNER_, newOwner);
_NEW_OWNER_ = newOwner; |  | _NEW_OWNER_ = newOwner;
} |  | }
function claimOwnership() public { |  | function claimOwnership() public {
require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); |  | require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM");
emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); |  | emit OwnershipTransferred(_OWNER_, _NEW_OWNER_);
_OWNER_ = _NEW_OWNER_; |  | _OWNER_ = _NEW_OWNER_;
_NEW_OWNER_ = address(0); |  | _NEW_OWNER_ = address(0);
} |  | }
} |  | }
// File: contracts/lib/CloneFactory.sol |  | // File: contracts/lib/CloneFactory.sol
interface ICloneFactory { |  | interface ICloneFactory {
function clone(address prototype) external returns (address proxy); |  | function clone(address prototype) external returns (address proxy);
} |  | }
// introduction of proxy mode design: https://docs.openzeppelin.com/upgrades/2.8/ |  | // introduction of proxy mode design: https://docs.openzeppelin.com/upgrades/2.8/
// minimum implementation of transparent proxy: https://eips.ethereum.org/EIPS/eip-1167 |  | // minimum implementation of transparent proxy: https://eips.ethereum.org/EIPS/eip-1167
contract CloneFactory is ICloneFactory { |  | contract CloneFactory is ICloneFactory {
function clone(address prototype) external override returns (address proxy) { |  | function clone(address prototype) external override returns (address proxy) {
bytes20 targetBytes = bytes20(prototype); |  | bytes20 targetBytes = bytes20(prototype);
assembly { |  | assembly {
let clone := mload(0x40) |  | let clone := mload(0x40)
mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) |  | mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(clone, 0x14), targetBytes) |  | mstore(add(clone, 0x14), targetBytes)
mstore( |  | mstore(
add(clone, 0x28), |  | add(clone, 0x28),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 |  | 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
) |  | )
proxy := create(0, clone, 0x37) |  | proxy := create(0, clone, 0x37)
} |  | }
return proxy; |  | return proxy;
} |  | }
} |  | }
// File: contracts/Factory/DVMFactory.sol |  | // File: contracts/Factory/DVMFactory.sol
| -+ |
interface IDVMFactory { | = | interface IDVMFactory {
function createDODOVendingMachine( |  | function createDODOVendingMachine(
address baseToken, |  | address baseToken,
address quoteToken, |  | address quoteToken,
uint256 lpFeeRate, |  | uint256 lpFeeRate,
uint256 i, |  | uint256 i,
uint256 k, |  | uint256 k,
bool isOpenTWAP |  | bool isOpenTWAP
) external returns (address newVendingMachine); |  | ) external returns (address newVendingMachine);
} |  | }
/** |  | /**
* @title DODO VendingMachine Factory |  | * @title DODO VendingMachine Factory
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice Create And Register DVM Pools |  | * @notice Create And Register DVM Pools
*/ |  | */
contract DVMFactory is InitializableOwnable { |  | contract DVMFactory is InitializableOwnable {
// ============ Templates ============ |  | // ============ Templates ============
address public immutable _CLONE_FACTORY_; |  | address public immutable _CLONE_FACTORY_;
| -+ | address public immutable _DEFAULT_MAINTAINER_;
address public immutable _DEFAULT_MT_FEE_RATE_MODEL_; | = | address public immutable _DEFAULT_MT_FEE_RATE_MODEL_;
address public _DEFAULT_MAINTAINER_; | +- |
address public _DVM_TEMPLATE_; | = | address public _DVM_TEMPLATE_;
// ============ Registry ============ |  | // ============ Registry ============
// base -> quote -> DVM address list |  | // base -> quote -> DVM address list
mapping(address => mapping(address => address[])) public _REGISTRY_; |  | mapping(address => mapping(address => address[])) public _REGISTRY_;
// creator -> DVM address list |  | // creator -> DVM address list
mapping(address => address[]) public _USER_REGISTRY_; |  | mapping(address => address[]) public _USER_REGISTRY_;
// ============ Events ============ |  | // ============ Events ============
event NewDVM( |  | event NewDVM(
address baseToken, |  | address baseToken,
address quoteToken, |  | address quoteToken,
address creator, |  | address creator,
address dvm |  | address dvm
); |  | );
event RemoveDVM(address dvm); |  | event RemoveDVM(address dvm);
// ============ Functions ============ |  | // ============ Functions ============
constructor( |  | constructor(
address cloneFactory, |  | address cloneFactory,
address dvmTemplate, |  | address dvmTemplate,
address defaultMaintainer, |  | address defaultMaintainer,
address defaultMtFeeRateModel |  | address defaultMtFeeRateModel
) public { |  | ) public {
_CLONE_FACTORY_ = cloneFactory; |  | _CLONE_FACTORY_ = cloneFactory;
_DVM_TEMPLATE_ = dvmTemplate; |  | _DVM_TEMPLATE_ = dvmTemplate;
_DEFAULT_MAINTAINER_ = defaultMaintainer; |  | _DEFAULT_MAINTAINER_ = defaultMaintainer;
_DEFAULT_MT_FEE_RATE_MODEL_ = defaultMtFeeRateModel; |  | _DEFAULT_MT_FEE_RATE_MODEL_ = defaultMtFeeRateModel;
} |  | }
function createDODOVendingMachine( |  | function createDODOVendingMachine(
address baseToken, |  | address baseToken,
address quoteToken, |  | address quoteToken,
uint256 lpFeeRate, |  | uint256 lpFeeRate,
uint256 i, |  | uint256 i,
uint256 k, |  | uint256 k,
bool isOpenTWAP |  | bool isOpenTWAP
) external returns (address newVendingMachine) { |  | ) external returns (address newVendingMachine) {
newVendingMachine = ICloneFactory(_CLONE_FACTORY_).clone(_DVM_TEMPLATE_); |  | newVendingMachine = ICloneFactory(_CLONE_FACTORY_).clone(_DVM_TEMPLATE_);
{ |  | {
IDVM(newVendingMachine).init( |  | IDVM(newVendingMachine).init(
_DEFAULT_MAINTAINER_, |  | _DEFAULT_MAINTAINER_,
baseToken, |  | baseToken,
quoteToken, |  | quoteToken,
lpFeeRate, |  | lpFeeRate,
_DEFAULT_MT_FEE_RATE_MODEL_, |  | _DEFAULT_MT_FEE_RATE_MODEL_,
i, |  | i,
k, |  | k,
isOpenTWAP |  | isOpenTWAP
); |  | );
} |  | }
_REGISTRY_[baseToken][quoteToken].push(newVendingMachine); |  | _REGISTRY_[baseToken][quoteToken].push(newVendingMachine);
_USER_REGISTRY_[tx.origin].push(newVendingMachine); |  | _USER_REGISTRY_[tx.origin].push(newVendingMachine);
emit NewDVM(baseToken, quoteToken, tx.origin, newVendingMachine); |  | emit NewDVM(baseToken, quoteToken, tx.origin, newVendingMachine);
} |  | }
// ============ Admin Operation Functions ============ |  | // ============ Admin Operation Functions ============
function updateDvmTemplate(address _newDVMTemplate) external onlyOwner { |  | function updateDvmTemplate(address _newDVMTemplate) external onlyOwner {
_DVM_TEMPLATE_ = _newDVMTemplate; |  | _DVM_TEMPLATE_ = _newDVMTemplate;
} | +- |
function updateDefaultMaintainer(address _newMaintainer) external onlyOwner { |  |
_DEFAULT_MAINTAINER_ = _newMaintainer; |  |
} | = | }
function addPoolByAdmin( |  | function addPoolByAdmin(
address creator, |  | address creator,
address baseToken, |  | address baseToken,
address quoteToken, |  | address quoteToken,
address pool |  | address pool
) external onlyOwner { |  | ) external onlyOwner {
_REGISTRY_[baseToken][quoteToken].push(pool); |  | _REGISTRY_[baseToken][quoteToken].push(pool);
_USER_REGISTRY_[creator].push(pool); |  | _USER_REGISTRY_[creator].push(pool);
emit NewDVM(baseToken, quoteToken, creator, pool); |  | emit NewDVM(baseToken, quoteToken, creator, pool);
} |  | }
function removePoolByAdmin( |  | function removePoolByAdmin(
address creator, |  | address creator,
address baseToken, |  | address baseToken,
address quoteToken, |  | address quoteToken,
address pool |  | address pool
) external onlyOwner { |  | ) external onlyOwner {
address[] memory registryList = _REGISTRY_[baseToken][quoteToken]; |  | address[] memory registryList = _REGISTRY_[baseToken][quoteToken];
for (uint256 i = 0; i < registryList.length; i++) { |  | for (uint256 i = 0; i < registryList.length; i++) {
if (registryList[i] == pool) { |  | if (registryList[i] == pool) {
registryList[i] = registryList[registryList.length - 1]; |  | registryList[i] = registryList[registryList.length - 1];
break; |  | break;
} |  | }
} |  | }
_REGISTRY_[baseToken][quoteToken] = registryList; |  | _REGISTRY_[baseToken][quoteToken] = registryList;
_REGISTRY_[baseToken][quoteToken].pop(); |  | _REGISTRY_[baseToken][quoteToken].pop();
address[] memory userRegistryList = _USER_REGISTRY_[creator]; |  | address[] memory userRegistryList = _USER_REGISTRY_[creator];
for (uint256 i = 0; i < userRegistryList.length; i++) { |  | for (uint256 i = 0; i < userRegistryList.length; i++) {
if (userRegistryList[i] == pool) { |  | if (userRegistryList[i] == pool) {
userRegistryList[i] = userRegistryList[userRegistryList.length - 1]; |  | userRegistryList[i] = userRegistryList[userRegistryList.length - 1];
break; |  | break;
} |  | }
} |  | }
_USER_REGISTRY_[creator] = userRegistryList; |  | _USER_REGISTRY_[creator] = userRegistryList;
_USER_REGISTRY_[creator].pop(); |  | _USER_REGISTRY_[creator].pop();
emit RemoveDVM(pool); |  | emit RemoveDVM(pool);
} |  | }
// ============ View Functions ============ |  | // ============ View Functions ============
function getDODOPool(address baseToken, address quoteToken) |  | function getDODOPool(address baseToken, address quoteToken)
external |  | external
view |  | view
returns (address[] memory machines) |  | returns (address[] memory machines)
{ |  | {
return _REGISTRY_[baseToken][quoteToken]; |  | return _REGISTRY_[baseToken][quoteToken];
} |  | }
function getDODOPoolBidirection(address token0, address token1) |  | function getDODOPoolBidirection(address token0, address token1)
external |  | external
view |  | view
returns (address[] memory baseToken0Machines, address[] memory baseToken1Machines) |  | returns (address[] memory baseToken0Machines, address[] memory baseToken1Machines)
{ |  | {
return (_REGISTRY_[token0][token1], _REGISTRY_[token1][token0]); |  | return (_REGISTRY_[token0][token1], _REGISTRY_[token1][token0]);
} |  | }
function getDODOPoolByUser(address user) |  | function getDODOPoolByUser(address user)
external |  | external
view |  | view
returns (address[] memory machines) |  | returns (address[] memory machines)
{ |  | {
return _USER_REGISTRY_[user]; |  | return _USER_REGISTRY_[user];
} |  | }
} |  | }
// File: contracts/lib/ReentrancyGuard.sol |  | // File: contracts/lib/ReentrancyGuard.sol
/** |  | /**
* @title ReentrancyGuard |  | * @title ReentrancyGuard
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice Protect functions from Reentrancy Attack |  | * @notice Protect functions from Reentrancy Attack
*/ |  | */
contract ReentrancyGuard { |  | contract ReentrancyGuard {
// https://solidity.readthedocs.io/en/latest/control-structures.html?highlight=zero-state#scoping-and-declarations |  | // https://solidity.readthedocs.io/en/latest/control-structures.html?highlight=zero-state#scoping-and-declarations
// zero-state of _ENTERED_ is false |  | // zero-state of _ENTERED_ is false
bool private _ENTERED_; |  | bool private _ENTERED_;
modifier preventReentrant() { |  | modifier preventReentrant() {
require(!_ENTERED_, "REENTRANT"); |  | require(!_ENTERED_, "REENTRANT");
_ENTERED_ = true; |  | _ENTERED_ = true;
_; |  | _;
_ENTERED_ = false; |  | _ENTERED_ = false;
} |  | }
} |  | }
// File: contracts/lib/PermissionManager.sol |  | // File: contracts/lib/PermissionManager.sol
interface IPermissionManager { |  | interface IPermissionManager {
function initOwner(address) external; |  | function initOwner(address) external;
function isAllowed(address) external view returns (bool); |  | function isAllowed(address) external view returns (bool);
} |  | }
contract PermissionManager is InitializableOwnable { |  | contract PermissionManager is InitializableOwnable {
bool public _WHITELIST_MODE_ON_; |  | bool public _WHITELIST_MODE_ON_;
mapping(address => bool) internal _whitelist_; |  | mapping(address => bool) internal _whitelist_;
mapping(address => bool) internal _blacklist_; |  | mapping(address => bool) internal _blacklist_;
function isAllowed(address account) external view returns (bool) { |  | function isAllowed(address account) external view returns (bool) {
if (_WHITELIST_MODE_ON_) { |  | if (_WHITELIST_MODE_ON_) {
return _whitelist_[account]; |  | return _whitelist_[account];
} else { |  | } else {
return !_blacklist_[account]; |  | return !_blacklist_[account];
} |  | }
} |  | }
function openBlacklistMode() external onlyOwner { |  | function openBlacklistMode() external onlyOwner {
_WHITELIST_MODE_ON_ = false; |  | _WHITELIST_MODE_ON_ = false;
} |  | }
function openWhitelistMode() external onlyOwner { |  | function openWhitelistMode() external onlyOwner {
_WHITELIST_MODE_ON_ = true; |  | _WHITELIST_MODE_ON_ = true;
} |  | }
function addToWhitelist(address account) external onlyOwner { |  | function addToWhitelist(address account) external onlyOwner {
_whitelist_[account] = true; |  | _whitelist_[account] = true;
} |  | }
function removeFromWhitelist(address account) external onlyOwner { |  | function removeFromWhitelist(address account) external onlyOwner {
_whitelist_[account] = false; |  | _whitelist_[account] = false;
} |  | }
function addToBlacklist(address account) external onlyOwner { |  | function addToBlacklist(address account) external onlyOwner {
_blacklist_[account] = true; |  | _blacklist_[account] = true;
} |  | }
function removeFromBlacklist(address account) external onlyOwner { |  | function removeFromBlacklist(address account) external onlyOwner {
_blacklist_[account] = false; |  | _blacklist_[account] = false;
} |  | }
} |  | }
// File: contracts/lib/FeeRateModel.sol |  | // File: contracts/lib/FeeRateModel.sol
| +- |
interface IFeeRateImpl { | = | interface IFeeRateImpl {
function getFeeRate(address pool, address trader) external view returns (uint256); |  | function getFeeRate(address pool, address trader) external view returns (uint256);
} |  | }
interface IFeeRateModel { |  | interface IFeeRateModel {
function getFeeRate(address trader) external view returns (uint256); |  | function getFeeRate(address trader) external view returns (uint256);
} |  | }
contract FeeRateModel is InitializableOwnable { |  | contract FeeRateModel is InitializableOwnable {
address public feeRateImpl; |  | address public feeRateImpl;
function setFeeProxy(address _feeRateImpl) public onlyOwner { |  | function setFeeProxy(address _feeRateImpl) public onlyOwner {
feeRateImpl = _feeRateImpl; |  | feeRateImpl = _feeRateImpl;
} |  | }
function getFeeRate(address trader) external view returns (uint256) { |  | function getFeeRate(address trader) external view returns (uint256) {
if(feeRateImpl == address(0)) |  | if(feeRateImpl == address(0))
return 0; |  | return 0;
return IFeeRateImpl(feeRateImpl).getFeeRate(msg.sender,trader); |  | return IFeeRateImpl(feeRateImpl).getFeeRate(msg.sender,trader);
} |  | }
} |  | }
// File: contracts/CrowdPooling/impl/CPStorage.sol |  | // File: contracts/CrowdPooling/impl/CPStorage.sol
| +- |
contract CPStorage is InitializableOwnable, ReentrancyGuard { | = | contract CPStorage is InitializableOwnable, ReentrancyGuard {
using SafeMath for uint256; |  | using SafeMath for uint256;
// ============ Constant ============ |  | // ============ Constant ============
uint256 internal constant _SETTLEMENT_EXPIRE_ = 86400 * 7; |  | uint256 internal constant _SETTLEMENT_EXPIRE_ = 86400 * 7;
uint256 internal constant _SETTEL_FUND_ = 200 finney; |  | uint256 internal constant _SETTEL_FUND_ = 200 finney;
bool public _IS_OPEN_TWAP_ = false; |  | bool public _IS_OPEN_TWAP_ = false;
bool public _IS_OVERCAP_STOP = false; | +- |
bool public _FORCE_STOP_ = false; |  |
| = |
// ============ Timeline ============ |  | // ============ Timeline ============
uint256 public _PHASE_BID_STARTTIME_; |  | uint256 public _PHASE_BID_STARTTIME_;
uint256 public _PHASE_BID_ENDTIME_; |  | uint256 public _PHASE_BID_ENDTIME_;
uint256 public _PHASE_CALM_ENDTIME_; |  | uint256 public _PHASE_CALM_ENDTIME_;
uint256 public _SETTLED_TIME_; |  | uint256 public _SETTLED_TIME_;
bool public _SETTLED_; |  | bool public _SETTLED_;
// ============ Core Address ============ |  | // ============ Core Address ============
IERC20 public _BASE_TOKEN_; |  | IERC20 public _BASE_TOKEN_;
IERC20 public _QUOTE_TOKEN_; |  | IERC20 public _QUOTE_TOKEN_;
// ============ Distribution Parameters ============ |  | // ============ Distribution Parameters ============
uint256 public _TOTAL_BASE_; |  | uint256 public _TOTAL_BASE_;
uint256 public _POOL_QUOTE_CAP_; |  | uint256 public _POOL_QUOTE_CAP_;
// ============ Settlement ============ |  | // ============ Settlement ============
uint256 public _QUOTE_RESERVE_; |  | uint256 public _QUOTE_RESERVE_;
uint256 public _UNUSED_BASE_; |  | uint256 public _UNUSED_BASE_;
uint256 public _UNUSED_QUOTE_; |  | uint256 public _UNUSED_QUOTE_;
uint256 public _TOTAL_SHARES_; |  | uint256 public _TOTAL_SHARES_;
mapping(address => uint256) internal _SHARES_; |  | mapping(address => uint256) internal _SHARES_;
mapping(address => bool) public _CLAIMED_QUOTE_; | <> | mapping(address => bool) public _CLAIMED_;
| = |
address public _POOL_FACTORY_; |  | address public _POOL_FACTORY_;
address public _POOL_; |  | address public _POOL_;
uint256 public _POOL_FEE_RATE_; | +- |
uint256 public _AVG_SETTLED_PRICE_; | = | uint256 public _AVG_SETTLED_PRICE_;
// ============ Advanced Control ============ |  | // ============ Advanced Control ============
address public _MAINTAINER_; |  | address public _MAINTAINER_;
IFeeRateModel public _MT_FEE_RATE_MODEL_; |  | IFeeRateModel public _MT_FEE_RATE_MODEL_;
IPermissionManager public _BIDDER_PERMISSION_; |  | IPermissionManager public _BIDDER_PERMISSION_;
// ============ PMM Parameters ============ |  | // ============ PMM Parameters ============
uint256 public _K_; |  | uint256 public _K_;
uint256 public _I_; |  | uint256 public _I_;
// ============ LP Token Vesting && Claim Params ============ | <> | // ============ LP Token Vesting ============
| = |
uint256 public _TOTAL_LP_AMOUNT_; |  | uint256 public _TOTAL_LP_AMOUNT_;
uint256 public _FREEZE_DURATION_; |  | uint256 public _FREEZE_DURATION_;
uint256 public _VESTING_DURATION_; |  | uint256 public _VESTING_DURATION_;
uint256 public _CLIFF_RATE_; |  | uint256 public _CLIFF_RATE_;
uint256 public _TOKEN_CLAIM_DURATION_; | +- |
uint256 public _TOKEN_VESTING_DURATION_; |  |
uint256 public _TOKEN_CLIFF_RATE_; |  |
mapping(address => uint256) _CLAIMED_BASE_TOKEN_; |  |
// ============ Modifiers ============ | = | // ============ Modifiers ============
modifier isForceStop() { | +- |
require(!_FORCE_STOP_, "FORCE_STOP"); |  |
_; |  |
} |  |
| = |
modifier phaseBid() { |  | modifier phaseBid() {
require( |  | require(
block.timestamp >= _PHASE_BID_STARTTIME_ && block.timestamp < _PHASE_BID_ENDTIME_, |  | block.timestamp >= _PHASE_BID_STARTTIME_ && block.timestamp < _PHASE_BID_ENDTIME_,
"NOT_PHASE_BID" |  | "NOT_PHASE_BID"
); |  | );
_; |  | _;
} |  | }
modifier phaseCalm() { |  | modifier phaseCalm() {
require( |  | require(
block.timestamp >= _PHASE_BID_ENDTIME_ && block.timestamp < _PHASE_CALM_ENDTIME_, |  | block.timestamp >= _PHASE_BID_ENDTIME_ && block.timestamp < _PHASE_CALM_ENDTIME_,
"NOT_PHASE_CALM" |  | "NOT_PHASE_CALM"
); |  | );
_; |  | _;
} |  | }
modifier phaseBidOrCalm() { |  | modifier phaseBidOrCalm() {
require( |  | require(
block.timestamp >= _PHASE_BID_STARTTIME_ && block.timestamp < _PHASE_CALM_ENDTIME_, |  | block.timestamp >= _PHASE_BID_STARTTIME_ && block.timestamp < _PHASE_CALM_ENDTIME_,
"NOT_PHASE_BID_OR_CALM" |  | "NOT_PHASE_BID_OR_CALM"
); |  | );
_; |  | _;
} |  | }
modifier phaseSettlement() { |  | modifier phaseSettlement() {
require(block.timestamp >= _PHASE_CALM_ENDTIME_, "NOT_PHASE_EXE"); |  | require(block.timestamp >= _PHASE_CALM_ENDTIME_, "NOT_PHASE_EXE");
_; |  | _;
} |  | }
modifier phaseVesting() { |  | modifier phaseVesting() {
require(_SETTLED_, "NOT_VESTING"); |  | require(_SETTLED_, "NOT_VESTING");
_; |  | _;
} | +- |
function forceStop() external onlyOwner { |  |
require(block.timestamp < _PHASE_BID_STARTTIME_, "CP_ALREADY_STARTED"); |  |
_FORCE_STOP_ = true; |  |
_TOTAL_BASE_ = 0; |  |
uint256 baseAmount = _BASE_TOKEN_.balanceOf(address(this)); |  |
_BASE_TOKEN_.transfer(_OWNER_, baseAmount); |  |
} | = | }
} |  | }
// File: contracts/lib/DODOMath.sol |  | // File: contracts/lib/DODOMath.sol
/** |  | /**
* @title DODOMath |  | * @title DODOMath
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice Functions for complex calculating. Including ONE Integration and TWO Quadratic solutions |  | * @notice Functions for complex calculating. Including ONE Integration and TWO Quadratic solutions
*/ |  | */
library DODOMath { |  | library DODOMath {
using SafeMath for uint256; |  | using SafeMath for uint256;
/* |  | /*
Integrate dodo curve from V1 to V2 |  | Integrate dodo curve from V1 to V2
require V0>=V1>=V2>0 |  | require V0>=V1>=V2>0
res = (1-k)i(V1-V2)+ikV0*V0(1/V2-1/V1) |  | res = (1-k)i(V1-V2)+ikV0*V0(1/V2-1/V1)
let V1-V2=delta |  | let V1-V2=delta
res = i*delta*(1-k+k(V0^2/V1/V2)) |  | res = i*delta*(1-k+k(V0^2/V1/V2))
i is the price of V-res trading pair |  | i is the price of V-res trading pair
support k=1 & k=0 case |  | support k=1 & k=0 case
[round down] |  | [round down]
*/ |  | */
function _GeneralIntegrate( |  | function _GeneralIntegrate(
uint256 V0, |  | uint256 V0,
uint256 V1, |  | uint256 V1,
uint256 V2, |  | uint256 V2,
uint256 i, |  | uint256 i,
uint256 k |  | uint256 k
) internal pure returns (uint256) { |  | ) internal pure returns (uint256) {
require(V0 > 0, "TARGET_IS_ZERO"); |  | require(V0 > 0, "TARGET_IS_ZERO");
uint256 fairAmount = i.mul(V1.sub(V2)); // i*delta |  | uint256 fairAmount = i.mul(V1.sub(V2)); // i*delta
if (k == 0) { |  | if (k == 0) {
return fairAmount.div(DecimalMath.ONE); |  | return fairAmount.div(DecimalMath.ONE);
} |  | }
uint256 V0V0V1V2 = DecimalMath.divFloor(V0.mul(V0).div(V1), V2); |  | uint256 V0V0V1V2 = DecimalMath.divFloor(V0.mul(V0).div(V1), V2);
uint256 penalty = DecimalMath.mulFloor(k, V0V0V1V2); // k(V0^2/V1/V2) |  | uint256 penalty = DecimalMath.mulFloor(k, V0V0V1V2); // k(V0^2/V1/V2)
return DecimalMath.ONE.sub(k).add(penalty).mul(fairAmount).div(DecimalMath.ONE2); |  | return DecimalMath.ONE.sub(k).add(penalty).mul(fairAmount).div(DecimalMath.ONE2);
} |  | }
/* |  | /*
Follow the integration function above |  | Follow the integration function above
i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2) |  | i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2)
Assume Q2=Q0, Given Q1 and deltaB, solve Q0 |  | Assume Q2=Q0, Given Q1 and deltaB, solve Q0
i is the price of delta-V trading pair |  | i is the price of delta-V trading pair
give out target of V |  | give out target of V
support k=1 & k=0 case |  | support k=1 & k=0 case
[round down] |  | [round down]
*/ |  | */
function _SolveQuadraticFunctionForTarget( |  | function _SolveQuadraticFunctionForTarget(
uint256 V1, |  | uint256 V1,
uint256 delta, |  | uint256 delta,
uint256 i, |  | uint256 i,
uint256 k |  | uint256 k
) internal pure returns (uint256) { |  | ) internal pure returns (uint256) {
if (V1 == 0) { |  | if (V1 == 0) {
return 0; |  | return 0;
} |  | }
if (k == 0) { |  | if (k == 0) {
return V1.add(DecimalMath.mulFloor(i, delta)); |  | return V1.add(DecimalMath.mulFloor(i, delta));
} |  | }
// V0 = V1*(1+(sqrt-1)/2k) |  | // V0 = V1*(1+(sqrt-1)/2k)
// sqrt = √(1+4kidelta/V1) |  | // sqrt = √(1+4kidelta/V1)
// premium = 1+(sqrt-1)/2k |  | // premium = 1+(sqrt-1)/2k
// uint256 sqrt = (4 * k).mul(i).mul(delta).div(V1).add(DecimalMath.ONE2).sqrt(); |  | // uint256 sqrt = (4 * k).mul(i).mul(delta).div(V1).add(DecimalMath.ONE2).sqrt();
uint256 sqrt; |  | uint256 sqrt;
uint256 ki = (4 * k).mul(i); |  | uint256 ki = (4 * k).mul(i);
if (ki == 0) { |  | if (ki == 0) {
sqrt = DecimalMath.ONE; |  | sqrt = DecimalMath.ONE;
} else if ((ki * delta) / ki == delta) { |  | } else if ((ki * delta) / ki == delta) {
sqrt = (ki * delta).div(V1).add(DecimalMath.ONE2).sqrt(); |  | sqrt = (ki * delta).div(V1).add(DecimalMath.ONE2).sqrt();
} else { |  | } else {
sqrt = ki.div(V1).mul(delta).add(DecimalMath.ONE2).sqrt(); |  | sqrt = ki.div(V1).mul(delta).add(DecimalMath.ONE2).sqrt();
} |  | }
uint256 premium = |  | uint256 premium =
DecimalMath.divFloor(sqrt.sub(DecimalMath.ONE), k * 2).add(DecimalMath.ONE); |  | DecimalMath.divFloor(sqrt.sub(DecimalMath.ONE), k * 2).add(DecimalMath.ONE);
// V0 is greater than or equal to V1 according to the solution |  | // V0 is greater than or equal to V1 according to the solution
return DecimalMath.mulFloor(V1, premium); |  | return DecimalMath.mulFloor(V1, premium);
} |  | }
/* |  | /*
Follow the integration expression above, we have: |  | Follow the integration expression above, we have:
i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2) |  | i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2)
Given Q1 and deltaB, solve Q2 |  | Given Q1 and deltaB, solve Q2
This is a quadratic function and the standard version is |  | This is a quadratic function and the standard version is
aQ2^2 + bQ2 + c = 0, where |  | aQ2^2 + bQ2 + c = 0, where
a=1-k |  | a=1-k
-b=(1-k)Q1-kQ0^2/Q1+i*deltaB |  | -b=(1-k)Q1-kQ0^2/Q1+i*deltaB
c=-kQ0^2 |  | c=-kQ0^2
and Q2=(-b+sqrt(b^2+4(1-k)kQ0^2))/2(1-k) |  | and Q2=(-b+sqrt(b^2+4(1-k)kQ0^2))/2(1-k)
note: another root is negative, abondan |  | note: another root is negative, abondan
if deltaBSig=true, then Q2>Q1, user sell Q and receive B |  | if deltaBSig=true, then Q2>Q1, user sell Q and receive B
if deltaBSig=false, then Q2<Q1, user sell B and receive Q |  | if deltaBSig=false, then Q2<Q1, user sell B and receive Q
return |Q1-Q2| |  | return |Q1-Q2|
as we only support sell amount as delta, the deltaB is always negative |  | as we only support sell amount as delta, the deltaB is always negative
the input ideltaB is actually -ideltaB in the equation |  | the input ideltaB is actually -ideltaB in the equation
i is the price of delta-V trading pair |  | i is the price of delta-V trading pair
support k=1 & k=0 case |  | support k=1 & k=0 case
[round down] |  | [round down]
*/ |  | */
function _SolveQuadraticFunctionForTrade( |  | function _SolveQuadraticFunctionForTrade(
uint256 V0, |  | uint256 V0,
uint256 V1, |  | uint256 V1,
uint256 delta, |  | uint256 delta,
uint256 i, |  | uint256 i,
uint256 k |  | uint256 k
) internal pure returns (uint256) { |  | ) internal pure returns (uint256) {
require(V0 > 0, "TARGET_IS_ZERO"); |  | require(V0 > 0, "TARGET_IS_ZERO");
if (delta == 0) { |  | if (delta == 0) {
return 0; |  | return 0;
} |  | }
if (k == 0) { |  | if (k == 0) {
return DecimalMath.mulFloor(i, delta) > V1 ? V1 : DecimalMath.mulFloor(i, delta); |  | return DecimalMath.mulFloor(i, delta) > V1 ? V1 : DecimalMath.mulFloor(i, delta);
} |  | }
if (k == DecimalMath.ONE) { |  | if (k == DecimalMath.ONE) {
// if k==1 |  | // if k==1
// Q2=Q1/(1+ideltaBQ1/Q0/Q0) |  | // Q2=Q1/(1+ideltaBQ1/Q0/Q0)
// temp = ideltaBQ1/Q0/Q0 |  | // temp = ideltaBQ1/Q0/Q0
// Q2 = Q1/(1+temp) |  | // Q2 = Q1/(1+temp)
// Q1-Q2 = Q1*(1-1/(1+temp)) = Q1*(temp/(1+temp)) |  | // Q1-Q2 = Q1*(1-1/(1+temp)) = Q1*(temp/(1+temp))
// uint256 temp = i.mul(delta).mul(V1).div(V0.mul(V0)); |  | // uint256 temp = i.mul(delta).mul(V1).div(V0.mul(V0));
uint256 temp; |  | uint256 temp;
uint256 idelta = i.mul(delta); |  | uint256 idelta = i.mul(delta);
if (idelta == 0) { |  | if (idelta == 0) {
temp = 0; |  | temp = 0;
} else if ((idelta * V1) / idelta == V1) { |  | } else if ((idelta * V1) / idelta == V1) {
temp = (idelta * V1).div(V0.mul(V0)); |  | temp = (idelta * V1).div(V0.mul(V0));
} else { |  | } else {
temp = delta.mul(V1).div(V0).mul(i).div(V0); |  | temp = delta.mul(V1).div(V0).mul(i).div(V0);
} |  | }
return V1.mul(temp).div(temp.add(DecimalMath.ONE)); |  | return V1.mul(temp).div(temp.add(DecimalMath.ONE));
} |  | }
// calculate -b value and sig |  | // calculate -b value and sig
// b = kQ0^2/Q1-i*deltaB-(1-k)Q1 |  | // b = kQ0^2/Q1-i*deltaB-(1-k)Q1
// part1 = (1-k)Q1 >=0 |  | // part1 = (1-k)Q1 >=0
// part2 = kQ0^2/Q1-i*deltaB >=0 |  | // part2 = kQ0^2/Q1-i*deltaB >=0
// bAbs = abs(part1-part2) |  | // bAbs = abs(part1-part2)
// if part1>part2 => b is negative => bSig is false |  | // if part1>part2 => b is negative => bSig is false
// if part2>part1 => b is positive => bSig is true |  | // if part2>part1 => b is positive => bSig is true
uint256 part2 = k.mul(V0).div(V1).mul(V0).add(i.mul(delta)); // kQ0^2/Q1-i*deltaB |  | uint256 part2 = k.mul(V0).div(V1).mul(V0).add(i.mul(delta)); // kQ0^2/Q1-i*deltaB
uint256 bAbs = DecimalMath.ONE.sub(k).mul(V1); // (1-k)Q1 |  | uint256 bAbs = DecimalMath.ONE.sub(k).mul(V1); // (1-k)Q1
bool bSig; |  | bool bSig;
if (bAbs >= part2) { |  | if (bAbs >= part2) {
bAbs = bAbs - part2; |  | bAbs = bAbs - part2;
bSig = false; |  | bSig = false;
} else { |  | } else {
bAbs = part2 - bAbs; |  | bAbs = part2 - bAbs;
bSig = true; |  | bSig = true;
} |  | }
bAbs = bAbs.div(DecimalMath.ONE); |  | bAbs = bAbs.div(DecimalMath.ONE);
// calculate sqrt |  | // calculate sqrt
uint256 squareRoot = |  | uint256 squareRoot =
DecimalMath.mulFloor( |  | DecimalMath.mulFloor(
DecimalMath.ONE.sub(k).mul(4), |  | DecimalMath.ONE.sub(k).mul(4),
DecimalMath.mulFloor(k, V0).mul(V0) |  | DecimalMath.mulFloor(k, V0).mul(V0)
); // 4(1-k)kQ0^2 |  | ); // 4(1-k)kQ0^2
squareRoot = bAbs.mul(bAbs).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0) |  | squareRoot = bAbs.mul(bAbs).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0)
// final res |  | // final res
uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k) |  | uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k)
uint256 numerator; |  | uint256 numerator;
if (bSig) { |  | if (bSig) {
numerator = squareRoot.sub(bAbs); |  | numerator = squareRoot.sub(bAbs);
} else { |  | } else {
numerator = bAbs.add(squareRoot); |  | numerator = bAbs.add(squareRoot);
} |  | }
uint256 V2 = DecimalMath.divCeil(numerator, denominator); |  | uint256 V2 = DecimalMath.divCeil(numerator, denominator);
if (V2 > V1) { |  | if (V2 > V1) {
return 0; |  | return 0;
} else { |  | } else {
return V1 - V2; |  | return V1 - V2;
} |  | }
} |  | }
} |  | }
// File: contracts/lib/PMMPricing.sol |  | // File: contracts/lib/PMMPricing.sol
/** |  | /**
* @title Pricing |  | * @title Pricing
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice DODO Pricing model |  | * @notice DODO Pricing model
*/ |  | */
library PMMPricing { |  | library PMMPricing {
using SafeMath for uint256; |  | using SafeMath for uint256;
enum RState {ONE, ABOVE_ONE, BELOW_ONE} |  | enum RState {ONE, ABOVE_ONE, BELOW_ONE}
struct PMMState { |  | struct PMMState {
uint256 i; |  | uint256 i;
uint256 K; |  | uint256 K;
uint256 B; |  | uint256 B;
uint256 Q; |  | uint256 Q;
uint256 B0; |  | uint256 B0;
uint256 Q0; |  | uint256 Q0;
RState R; |  | RState R;
} |  | }
// ============ buy & sell ============ |  | // ============ buy & sell ============
function sellBaseToken(PMMState memory state, uint256 payBaseAmount) |  | function sellBaseToken(PMMState memory state, uint256 payBaseAmount)
internal |  | internal
pure |  | pure
returns (uint256 receiveQuoteAmount, RState newR) |  | returns (uint256 receiveQuoteAmount, RState newR)
{ |  | {
if (state.R == RState.ONE) { |  | if (state.R == RState.ONE) {
// case 1: R=1 |  | // case 1: R=1
// R falls below one |  | // R falls below one
receiveQuoteAmount = _ROneSellBaseToken(state, payBaseAmount); |  | receiveQuoteAmount = _ROneSellBaseToken(state, payBaseAmount);
newR = RState.BELOW_ONE; |  | newR = RState.BELOW_ONE;
} else if (state.R == RState.ABOVE_ONE) { |  | } else if (state.R == RState.ABOVE_ONE) {
uint256 backToOnePayBase = state.B0.sub(state.B); |  | uint256 backToOnePayBase = state.B0.sub(state.B);
uint256 backToOneReceiveQuote = state.Q.sub(state.Q0); |  | uint256 backToOneReceiveQuote = state.Q.sub(state.Q0);
// case 2: R>1 |  | // case 2: R>1
// complex case, R status depends on trading amount |  | // complex case, R status depends on trading amount
if (payBaseAmount < backToOnePayBase) { |  | if (payBaseAmount < backToOnePayBase) {
// case 2.1: R status do not change |  | // case 2.1: R status do not change
receiveQuoteAmount = _RAboveSellBaseToken(state, payBaseAmount); |  | receiveQuoteAmount = _RAboveSellBaseToken(state, payBaseAmount);
newR = RState.ABOVE_ONE; |  | newR = RState.ABOVE_ONE;
if (receiveQuoteAmount > backToOneReceiveQuote) { |  | if (receiveQuoteAmount > backToOneReceiveQuote) {
// [Important corner case!] may enter this branch when some precision problem happens. And consequently contribute to negative spare quote amount |  | // [Important corner case!] may enter this branch when some precision problem happens. And consequently contribute to negative spare quote amount
// to make sure spare quote>=0, mannually set receiveQuote=backToOneReceiveQuote |  | // to make sure spare quote>=0, mannually set receiveQuote=backToOneReceiveQuote
receiveQuoteAmount = backToOneReceiveQuote; |  | receiveQuoteAmount = backToOneReceiveQuote;
} |  | }
} else if (payBaseAmount == backToOnePayBase) { |  | } else if (payBaseAmount == backToOnePayBase) {
// case 2.2: R status changes to ONE |  | // case 2.2: R status changes to ONE
receiveQuoteAmount = backToOneReceiveQuote; |  | receiveQuoteAmount = backToOneReceiveQuote;
newR = RState.ONE; |  | newR = RState.ONE;
} else { |  | } else {
// case 2.3: R status changes to BELOW_ONE |  | // case 2.3: R status changes to BELOW_ONE
receiveQuoteAmount = backToOneReceiveQuote.add( |  | receiveQuoteAmount = backToOneReceiveQuote.add(
_ROneSellBaseToken(state, payBaseAmount.sub(backToOnePayBase)) |  | _ROneSellBaseToken(state, payBaseAmount.sub(backToOnePayBase))
); |  | );
newR = RState.BELOW_ONE; |  | newR = RState.BELOW_ONE;
} |  | }
} else { |  | } else {
// state.R == RState.BELOW_ONE |  | // state.R == RState.BELOW_ONE
// case 3: R<1 |  | // case 3: R<1
receiveQuoteAmount = _RBelowSellBaseToken(state, payBaseAmount); |  | receiveQuoteAmount = _RBelowSellBaseToken(state, payBaseAmount);
newR = RState.BELOW_ONE; |  | newR = RState.BELOW_ONE;
} |  | }
} |  | }
function sellQuoteToken(PMMState memory state, uint256 payQuoteAmount) |  | function sellQuoteToken(PMMState memory state, uint256 payQuoteAmount)
internal |  | internal
pure |  | pure
returns (uint256 receiveBaseAmount, RState newR) |  | returns (uint256 receiveBaseAmount, RState newR)
{ |  | {
if (state.R == RState.ONE) { |  | if (state.R == RState.ONE) {
receiveBaseAmount = _ROneSellQuoteToken(state, payQuoteAmount); |  | receiveBaseAmount = _ROneSellQuoteToken(state, payQuoteAmount);
newR = RState.ABOVE_ONE; |  | newR = RState.ABOVE_ONE;
} else if (state.R == RState.ABOVE_ONE) { |  | } else if (state.R == RState.ABOVE_ONE) {
receiveBaseAmount = _RAboveSellQuoteToken(state, payQuoteAmount); |  | receiveBaseAmount = _RAboveSellQuoteToken(state, payQuoteAmount);
newR = RState.ABOVE_ONE; |  | newR = RState.ABOVE_ONE;
} else { |  | } else {
uint256 backToOnePayQuote = state.Q0.sub(state.Q); |  | uint256 backToOnePayQuote = state.Q0.sub(state.Q);
uint256 backToOneReceiveBase = state.B.sub(state.B0); |  | uint256 backToOneReceiveBase = state.B.sub(state.B0);
if (payQuoteAmount < backToOnePayQuote) { |  | if (payQuoteAmount < backToOnePayQuote) {
receiveBaseAmount = _RBelowSellQuoteToken(state, payQuoteAmount); |  | receiveBaseAmount = _RBelowSellQuoteToken(state, payQuoteAmount);
newR = RState.BELOW_ONE; |  | newR = RState.BELOW_ONE;
if (receiveBaseAmount > backToOneReceiveBase) { |  | if (receiveBaseAmount > backToOneReceiveBase) {
receiveBaseAmount = backToOneReceiveBase; |  | receiveBaseAmount = backToOneReceiveBase;
} |  | }
} else if (payQuoteAmount == backToOnePayQuote) { |  | } else if (payQuoteAmount == backToOnePayQuote) {
receiveBaseAmount = backToOneReceiveBase; |  | receiveBaseAmount = backToOneReceiveBase;
newR = RState.ONE; |  | newR = RState.ONE;
} else { |  | } else {
receiveBaseAmount = backToOneReceiveBase.add( |  | receiveBaseAmount = backToOneReceiveBase.add(
_ROneSellQuoteToken(state, payQuoteAmount.sub(backToOnePayQuote)) |  | _ROneSellQuoteToken(state, payQuoteAmount.sub(backToOnePayQuote))
); |  | );
newR = RState.ABOVE_ONE; |  | newR = RState.ABOVE_ONE;
} |  | }
} |  | }
} |  | }
// ============ R = 1 cases ============ |  | // ============ R = 1 cases ============
function _ROneSellBaseToken(PMMState memory state, uint256 payBaseAmount) |  | function _ROneSellBaseToken(PMMState memory state, uint256 payBaseAmount)
internal |  | internal
pure |  | pure
returns ( |  | returns (
uint256 // receiveQuoteToken |  | uint256 // receiveQuoteToken
) |  | )
{ |  | {
// in theory Q2 <= targetQuoteTokenAmount |  | // in theory Q2 <= targetQuoteTokenAmount
// however when amount is close to 0, precision problems may cause Q2 > targetQuoteTokenAmount |  | // however when amount is close to 0, precision problems may cause Q2 > targetQuoteTokenAmount
return |  | return
DODOMath._SolveQuadraticFunctionForTrade( |  | DODOMath._SolveQuadraticFunctionForTrade(
state.Q0, |  | state.Q0,
state.Q0, |  | state.Q0,
payBaseAmount, |  | payBaseAmount,
state.i, |  | state.i,
state.K |  | state.K
); |  | );
} |  | }
function _ROneSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) |  | function _ROneSellQuoteToken(PMMState memory state, uint256 payQuoteAmount)
internal |  | internal
pure |  | pure
returns ( |  | returns (
uint256 // receiveBaseToken |  | uint256 // receiveBaseToken
) |  | )
{ |  | {
return |  | return
DODOMath._SolveQuadraticFunctionForTrade( |  | DODOMath._SolveQuadraticFunctionForTrade(
state.B0, |  | state.B0,
state.B0, |  | state.B0,
payQuoteAmount, |  | payQuoteAmount,
DecimalMath.reciprocalFloor(state.i), |  | DecimalMath.reciprocalFloor(state.i),
state.K |  | state.K
); |  | );
} |  | }
// ============ R < 1 cases ============ |  | // ============ R < 1 cases ============
function _RBelowSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) |  | function _RBelowSellQuoteToken(PMMState memory state, uint256 payQuoteAmount)
internal |  | internal
pure |  | pure
returns ( |  | returns (
uint256 // receiveBaseToken |  | uint256 // receiveBaseToken
) |  | )
{ |  | {
return |  | return
DODOMath._GeneralIntegrate( |  | DODOMath._GeneralIntegrate(
state.Q0, |  | state.Q0,
state.Q.add(payQuoteAmount), |  | state.Q.add(payQuoteAmount),
state.Q, |  | state.Q,
DecimalMath.reciprocalFloor(state.i), |  | DecimalMath.reciprocalFloor(state.i),
state.K |  | state.K
); |  | );
} |  | }
function _RBelowSellBaseToken(PMMState memory state, uint256 payBaseAmount) |  | function _RBelowSellBaseToken(PMMState memory state, uint256 payBaseAmount)
internal |  | internal
pure |  | pure
returns ( |  | returns (
uint256 // receiveQuoteToken |  | uint256 // receiveQuoteToken
) |  | )
{ |  | {
return |  | return
DODOMath._SolveQuadraticFunctionForTrade( |  | DODOMath._SolveQuadraticFunctionForTrade(
state.Q0, |  | state.Q0,
state.Q, |  | state.Q,
payBaseAmount, |  | payBaseAmount,
state.i, |  | state.i,
state.K |  | state.K
); |  | );
} |  | }
// ============ R > 1 cases ============ |  | // ============ R > 1 cases ============
function _RAboveSellBaseToken(PMMState memory state, uint256 payBaseAmount) |  | function _RAboveSellBaseToken(PMMState memory state, uint256 payBaseAmount)
internal |  | internal
pure |  | pure
returns ( |  | returns (
uint256 // receiveQuoteToken |  | uint256 // receiveQuoteToken
) |  | )
{ |  | {
return |  | return
DODOMath._GeneralIntegrate( |  | DODOMath._GeneralIntegrate(
state.B0, |  | state.B0,
state.B.add(payBaseAmount), |  | state.B.add(payBaseAmount),
state.B, |  | state.B,
state.i, |  | state.i,
state.K |  | state.K
); |  | );
} |  | }
function _RAboveSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) |  | function _RAboveSellQuoteToken(PMMState memory state, uint256 payQuoteAmount)
internal |  | internal
pure |  | pure
returns ( |  | returns (
uint256 // receiveBaseToken |  | uint256 // receiveBaseToken
) |  | )
{ |  | {
return |  | return
DODOMath._SolveQuadraticFunctionForTrade( |  | DODOMath._SolveQuadraticFunctionForTrade(
state.B0, |  | state.B0,
state.B, |  | state.B,
payQuoteAmount, |  | payQuoteAmount,
DecimalMath.reciprocalFloor(state.i), |  | DecimalMath.reciprocalFloor(state.i),
state.K |  | state.K
); |  | );
} |  | }
// ============ Helper functions ============ |  | // ============ Helper functions ============
function adjustedTarget(PMMState memory state) internal pure { |  | function adjustedTarget(PMMState memory state) internal pure {
if (state.R == RState.BELOW_ONE) { |  | if (state.R == RState.BELOW_ONE) {
state.Q0 = DODOMath._SolveQuadraticFunctionForTarget( |  | state.Q0 = DODOMath._SolveQuadraticFunctionForTarget(
state.Q, |  | state.Q,
state.B.sub(state.B0), |  | state.B.sub(state.B0),
state.i, |  | state.i,
state.K |  | state.K
); |  | );
} else if (state.R == RState.ABOVE_ONE) { |  | } else if (state.R == RState.ABOVE_ONE) {
state.B0 = DODOMath._SolveQuadraticFunctionForTarget( |  | state.B0 = DODOMath._SolveQuadraticFunctionForTarget(
state.B, |  | state.B,
state.Q.sub(state.Q0), |  | state.Q.sub(state.Q0),
DecimalMath.reciprocalFloor(state.i), |  | DecimalMath.reciprocalFloor(state.i),
state.K |  | state.K
); |  | );
} |  | }
} |  | }
function getMidPrice(PMMState memory state) internal pure returns (uint256) { |  | function getMidPrice(PMMState memory state) internal pure returns (uint256) {
if (state.R == RState.BELOW_ONE) { |  | if (state.R == RState.BELOW_ONE) {
uint256 R = DecimalMath.divFloor(state.Q0.mul(state.Q0).div(state.Q), state.Q); |  | uint256 R = DecimalMath.divFloor(state.Q0.mul(state.Q0).div(state.Q), state.Q);
R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R)); |  | R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R));
return DecimalMath.divFloor(state.i, R); |  | return DecimalMath.divFloor(state.i, R);
} else { |  | } else {
uint256 R = DecimalMath.divFloor(state.B0.mul(state.B0).div(state.B), state.B); |  | uint256 R = DecimalMath.divFloor(state.B0.mul(state.B0).div(state.B), state.B);
R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R)); |  | R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R));
return DecimalMath.mulFloor(state.i, R); |  | return DecimalMath.mulFloor(state.i, R);
} |  | }
} |  | }
} |  | }
// File: contracts/intf/IDODOCallee.sol |  | // File: contracts/intf/IDODOCallee.sol
interface IDODOCallee { |  | interface IDODOCallee {
function DVMSellShareCall( |  | function DVMSellShareCall(
address sender, |  | address sender,
uint256 burnShareAmount, |  | uint256 burnShareAmount,
uint256 baseAmount, |  | uint256 baseAmount,
uint256 quoteAmount, |  | uint256 quoteAmount,
bytes calldata data |  | bytes calldata data
) external; |  | ) external;
function DVMFlashLoanCall( |  | function DVMFlashLoanCall(
address sender, |  | address sender,
uint256 baseAmount, |  | uint256 baseAmount,
uint256 quoteAmount, |  | uint256 quoteAmount,
bytes calldata data |  | bytes calldata data
) external; |  | ) external;
function DPPFlashLoanCall( |  | function DPPFlashLoanCall(
address sender, |  | address sender,
uint256 baseAmount, |  | uint256 baseAmount,
uint256 quoteAmount, |  | uint256 quoteAmount,
bytes calldata data |  | bytes calldata data
) external; |  | ) external;
function DSPFlashLoanCall( | +- |
address sender, |  |
uint256 baseAmount, |  |
uint256 quoteAmount, |  |
bytes calldata data |  |
) external; |  |
function CPCancelCall( | = | function CPCancelCall(
address sender, |  | address sender,
uint256 amount, |  | uint256 amount,
bytes calldata data |  | bytes calldata data
) external; |  | ) external;
function CPClaimBidCall( |  | function CPClaimBidCall(
address sender, |  | address sender,
uint256 baseAmount, |  | uint256 baseAmount,
uint256 quoteAmount, |  | uint256 quoteAmount,
bytes calldata data |  | bytes calldata data
) external; |  | ) external;
| +- |
function NFTRedeemCall( |  |
address payable assetTo, |  |
uint256 quoteAmount, |  |
bytes calldata |  |
) external; |  |
} | = | }
// File: contracts/CrowdPooling/impl/CPFunding.sol |  | // File: contracts/CrowdPooling/impl/CPFunding.sol
| -+ |
| = |
contract CPFunding is CPStorage { |  | contract CPFunding is CPStorage {
using SafeERC20 for IERC20; |  | using SafeERC20 for IERC20;
// ============ Events ============ |  | // ============ Events ============
event Bid(address to, uint256 amount, uint256 fee); |  | event Bid(address to, uint256 amount, uint256 fee);
event Cancel(address to,uint256 amount); |  | event Cancel(address to,uint256 amount);
event Settle(); |  | event Settle();
// ============ BID & CALM PHASE ============ |  | // ============ BID & CALM PHASE ============
modifier isBidderAllow(address bidder) { |  | modifier isBidderAllow(address bidder) {
require(_BIDDER_PERMISSION_.isAllowed(bidder), "BIDDER_NOT_ALLOWED"); |  | require(_BIDDER_PERMISSION_.isAllowed(bidder), "BIDDER_NOT_ALLOWED");
if(_IS_OVERCAP_STOP) { | +- |
require(_QUOTE_TOKEN_.balanceOf(address(this)) < _POOL_QUOTE_CAP_, "ALREADY_OVER_CAP"); |  |
} |  |
_; | = | _;
} |  | }
function bid(address to) external isForceStop phaseBid preventReentrant isBidderAllow(to) { | <> | function bid(address to) external phaseBid preventReentrant isBidderAllow(to) {
uint256 input = _getQuoteInput(); | = | uint256 input = _getQuoteInput();
uint256 mtFee = DecimalMath.mulFloor(input, _MT_FEE_RATE_MODEL_.getFeeRate(to)); |  | uint256 mtFee = DecimalMath.mulFloor(input, _MT_FEE_RATE_MODEL_.getFeeRate(to));
_transferQuoteOut(_MAINTAINER_, mtFee); |  | _transferQuoteOut(_MAINTAINER_, mtFee);
_mintShares(to, input.sub(mtFee)); |  | _mintShares(to, input.sub(mtFee));
_sync(); |  | _sync();
emit Bid(to, input, mtFee); |  | emit Bid(to, input, mtFee);
} |  | }
function cancel(address to, uint256 amount, bytes calldata data) external phaseBidOrCalm preventReentrant { |  | function cancel(address to, uint256 amount, bytes calldata data) external phaseBidOrCalm preventReentrant {
require(_SHARES_[msg.sender] >= amount, "SHARES_NOT_ENOUGH"); |  | require(_SHARES_[msg.sender] >= amount, "SHARES_NOT_ENOUGH");
_burnShares(msg.sender, amount); |  | _burnShares(msg.sender, amount);
_transferQuoteOut(to, amount); |  | _transferQuoteOut(to, amount);
_sync(); |  | _sync();
if(data.length > 0){ |  | if(data.length > 0){
IDODOCallee(to).CPCancelCall(msg.sender,amount,data); |  | IDODOCallee(to).CPCancelCall(msg.sender,amount,data);
} |  | }
emit Cancel(msg.sender,amount); |  | emit Cancel(msg.sender,amount);
} |  | }
function _mintShares(address to, uint256 amount) internal { |  | function _mintShares(address to, uint256 amount) internal {
_SHARES_[to] = _SHARES_[to].add(amount); |  | _SHARES_[to] = _SHARES_[to].add(amount);
_TOTAL_SHARES_ = _TOTAL_SHARES_.add(amount); |  | _TOTAL_SHARES_ = _TOTAL_SHARES_.add(amount);
} |  | }
function _burnShares(address from, uint256 amount) internal { |  | function _burnShares(address from, uint256 amount) internal {
_SHARES_[from] = _SHARES_[from].sub(amount); |  | _SHARES_[from] = _SHARES_[from].sub(amount);
_TOTAL_SHARES_ = _TOTAL_SHARES_.sub(amount); |  | _TOTAL_SHARES_ = _TOTAL_SHARES_.sub(amount);
} |  | }
// ============ SETTLEMENT ============ |  | // ============ SETTLEMENT ============
function settle() external isForceStop phaseSettlement preventReentrant { | <> | function settle() external phaseSettlement preventReentrant {
_settle(); | = | _settle();
(uint256 poolBase, uint256 poolQuote, uint256 poolI, uint256 unUsedBase, uint256 unUsedQuote) = getSettleResult(); |  | (uint256 poolBase, uint256 poolQuote, uint256 poolI, uint256 unUsedBase, uint256 unUsedQuote) = getSettleResult();
_UNUSED_BASE_ = unUsedBase; |  | _UNUSED_BASE_ = unUsedBase;
_UNUSED_QUOTE_ = unUsedQuote; |  | _UNUSED_QUOTE_ = unUsedQuote;
address _poolBaseToken; |  | address _poolBaseToken;
address _poolQuoteToken; |  | address _poolQuoteToken;
if (_UNUSED_BASE_ > poolBase) { |  | if (_UNUSED_BASE_ > poolBase) {
_poolBaseToken = address(_QUOTE_TOKEN_); |  | _poolBaseToken = address(_QUOTE_TOKEN_);
_poolQuoteToken = address(_BASE_TOKEN_); |  | _poolQuoteToken = address(_BASE_TOKEN_);
} else { |  | } else {
_poolBaseToken = address(_BASE_TOKEN_); |  | _poolBaseToken = address(_BASE_TOKEN_);
_poolQuoteToken = address(_QUOTE_TOKEN_); |  | _poolQuoteToken = address(_QUOTE_TOKEN_);
} |  | }
_POOL_ = IDVMFactory(_POOL_FACTORY_).createDODOVendingMachine( |  | _POOL_ = IDVMFactory(_POOL_FACTORY_).createDODOVendingMachine(
_poolBaseToken, |  | _poolBaseToken,
_poolQuoteToken, |  | _poolQuoteToken,
_POOL_FEE_RATE_, | <> | 3e15, // 0.3% lp feeRate
poolI, | = | poolI,
DecimalMath.ONE, |  | DecimalMath.ONE,
_IS_OPEN_TWAP_ |  | _IS_OPEN_TWAP_
); |  | );
uint256 avgPrice = unUsedBase == 0 ? _I_ : DecimalMath.divCeil(poolQuote, unUsedBase); |  | uint256 avgPrice = unUsedBase == 0 ? _I_ : DecimalMath.divCeil(poolQuote, unUsedBase);
_AVG_SETTLED_PRICE_ = avgPrice; |  | _AVG_SETTLED_PRICE_ = avgPrice;
_transferBaseOut(_POOL_, poolBase); |  | _transferBaseOut(_POOL_, poolBase);
_transferQuoteOut(_POOL_, poolQuote); |  | _transferQuoteOut(_POOL_, poolQuote);
(_TOTAL_LP_AMOUNT_, ,) = IDVM(_POOL_).buyShares(address(this)); |  | (_TOTAL_LP_AMOUNT_, ,) = IDVM(_POOL_).buyShares(address(this));
msg.sender.transfer(_SETTEL_FUND_); |  | msg.sender.transfer(_SETTEL_FUND_);
emit Settle(); |  | emit Settle();
} |  | }
// in case something wrong with base token contract |  | // in case something wrong with base token contract
function emergencySettle() external isForceStop phaseSettlement preventReentrant { | <> | function emergencySettle() external phaseSettlement preventReentrant {
require(block.timestamp >= _PHASE_CALM_ENDTIME_.add(_SETTLEMENT_EXPIRE_), "NOT_EMERGENCY"); | = | require(block.timestamp >= _PHASE_CALM_ENDTIME_.add(_SETTLEMENT_EXPIRE_), "NOT_EMERGENCY");
_settle(); |  | _settle();
_UNUSED_QUOTE_ = _QUOTE_TOKEN_.balanceOf(address(this)); |  | _UNUSED_QUOTE_ = _QUOTE_TOKEN_.balanceOf(address(this));
} |  | }
function _settle() internal { |  | function _settle() internal {
require(!_SETTLED_, "ALREADY_SETTLED"); |  | require(!_SETTLED_, "ALREADY_SETTLED");
_SETTLED_ = true; |  | _SETTLED_ = true;
_SETTLED_TIME_ = block.timestamp; |  | _SETTLED_TIME_ = block.timestamp;
} |  | }
// ============ Pricing ============ |  | // ============ Pricing ============
function getSettleResult() public view returns (uint256 poolBase, uint256 poolQuote, uint256 poolI, uint256 unUsedBase, uint256 unUsedQuote) { |  | function getSettleResult() public view returns (uint256 poolBase, uint256 poolQuote, uint256 poolI, uint256 unUsedBase, uint256 unUsedQuote) {
poolQuote = _QUOTE_TOKEN_.balanceOf(address(this)); |  | poolQuote = _QUOTE_TOKEN_.balanceOf(address(this));
if (poolQuote > _POOL_QUOTE_CAP_) { |  | if (poolQuote > _POOL_QUOTE_CAP_) {
poolQuote = _POOL_QUOTE_CAP_; |  | poolQuote = _POOL_QUOTE_CAP_;
} |  | }
(uint256 soldBase,) = PMMPricing.sellQuoteToken(_getPMMState(), poolQuote); |  | (uint256 soldBase,) = PMMPricing.sellQuoteToken(_getPMMState(), poolQuote);
poolBase = _TOTAL_BASE_.sub(soldBase); |  | poolBase = _TOTAL_BASE_.sub(soldBase);
unUsedQuote = _QUOTE_TOKEN_.balanceOf(address(this)).sub(poolQuote); |  | unUsedQuote = _QUOTE_TOKEN_.balanceOf(address(this)).sub(poolQuote);
unUsedBase = _BASE_TOKEN_.balanceOf(address(this)).sub(poolBase); |  | unUsedBase = _BASE_TOKEN_.balanceOf(address(this)).sub(poolBase);
// Try to make midPrice equal to avgPrice |  | // Try to make midPrice equal to avgPrice
// k=1, If quote and base are not balanced, one side must be cut off |  | // k=1, If quote and base are not balanced, one side must be cut off
// DVM truncated quote, but if more quote than base entering the pool, we need set the quote to the base |  | // DVM truncated quote, but if more quote than base entering the pool, we need set the quote to the base
// m = avgPrice |  | // m = avgPrice
// i = m (1-quote/(m*base)) |  | // i = m (1-quote/(m*base))
// if quote = m*base i = 1 |  | // if quote = m*base i = 1
// if quote > m*base reverse |  | // if quote > m*base reverse
uint256 avgPrice = unUsedBase == 0 ? _I_ : DecimalMath.divCeil(poolQuote, unUsedBase); |  | uint256 avgPrice = unUsedBase == 0 ? _I_ : DecimalMath.divCeil(poolQuote, unUsedBase);
uint256 baseDepth = DecimalMath.mulFloor(avgPrice, poolBase); |  | uint256 baseDepth = DecimalMath.mulFloor(avgPrice, poolBase);
if (poolQuote == 0) { |  | if (poolQuote == 0) {
// ask side only DVM |  | // ask side only DVM
poolI = _I_; |  | poolI = _I_;
} else if (unUsedBase== poolBase) { |  | } else if (unUsedBase== poolBase) {
// standard bonding curve |  | // standard bonding curve
poolI = 1; |  | poolI = 1;
} else if (unUsedBase < poolBase) { |  | } else if (unUsedBase < poolBase) {
// poolI up round |  | // poolI up round
uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divFloor(poolQuote, baseDepth)); |  | uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divFloor(poolQuote, baseDepth));
poolI = avgPrice.mul(ratio).mul(ratio).divCeil(DecimalMath.ONE2); |  | poolI = avgPrice.mul(ratio).mul(ratio).divCeil(DecimalMath.ONE2);
} else if (unUsedBase > poolBase) { |  | } else if (unUsedBase > poolBase) {
// poolI down round |  | // poolI down round
uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divCeil(baseDepth, poolQuote)); |  | uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divCeil(baseDepth, poolQuote));
poolI = ratio.mul(ratio).div(avgPrice); |  | poolI = ratio.mul(ratio).div(avgPrice);
} |  | }
} |  | }
function _getPMMState() internal view returns (PMMPricing.PMMState memory state) { |  | function _getPMMState() internal view returns (PMMPricing.PMMState memory state) {
state.i = _I_; |  | state.i = _I_;
state.K = _K_; |  | state.K = _K_;
state.B = _TOTAL_BASE_; |  | state.B = _TOTAL_BASE_;
state.Q = 0; |  | state.Q = 0;
state.B0 = state.B; |  | state.B0 = state.B;
state.Q0 = 0; |  | state.Q0 = 0;
state.R = PMMPricing.RState.ONE; |  | state.R = PMMPricing.RState.ONE;
} |  | }
function getExpectedAvgPrice() external view returns (uint256) { |  | function getExpectedAvgPrice() external view returns (uint256) {
require(!_SETTLED_, "ALREADY_SETTLED"); |  | require(!_SETTLED_, "ALREADY_SETTLED");
(uint256 poolBase, uint256 poolQuote, , , ) = getSettleResult(); |  | (uint256 poolBase, uint256 poolQuote, , , ) = getSettleResult();
return DecimalMath.divCeil(poolQuote, _BASE_TOKEN_.balanceOf(address(this)).sub(poolBase)); |  | return DecimalMath.divCeil(poolQuote, _BASE_TOKEN_.balanceOf(address(this)).sub(poolBase));
} |  | }
// ============ Asset In ============ |  | // ============ Asset In ============
function _getQuoteInput() internal view returns (uint256 input) { |  | function _getQuoteInput() internal view returns (uint256 input) {
return _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_); |  | return _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_);
} |  | }
// ============ Set States ============ |  | // ============ Set States ============
function _sync() internal { |  | function _sync() internal {
uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); |  | uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this));
if (quoteBalance != _QUOTE_RESERVE_) { |  | if (quoteBalance != _QUOTE_RESERVE_) {
_QUOTE_RESERVE_ = quoteBalance; |  | _QUOTE_RESERVE_ = quoteBalance;
} |  | }
} |  | }
// ============ Asset Out ============ |  | // ============ Asset Out ============
function _transferBaseOut(address to, uint256 amount) internal { |  | function _transferBaseOut(address to, uint256 amount) internal {
if (amount > 0) { |  | if (amount > 0) {
_BASE_TOKEN_.safeTransfer(to, amount); |  | _BASE_TOKEN_.safeTransfer(to, amount);
} |  | }
} |  | }
function _transferQuoteOut(address to, uint256 amount) internal { |  | function _transferQuoteOut(address to, uint256 amount) internal {
if (amount > 0) { |  | if (amount > 0) {
_QUOTE_TOKEN_.safeTransfer(to, amount); |  | _QUOTE_TOKEN_.safeTransfer(to, amount);
} |  | }
} |  | }
function getShares(address user) external view returns (uint256) { |  | function getShares(address user) external view returns (uint256) {
return _SHARES_[user]; |  | return _SHARES_[user];
} |  | }
} |  | }
// File: contracts/CrowdPooling/impl/CPVesting.sol |  | // File: contracts/CrowdPooling/impl/CPVesting.sol
| -+ |
/** | = | /**
* @title CPVesting |  | * @title CPVesting
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice Lock Token and release it linearly |  | * @notice Lock Token and release it linearly
*/ |  | */
contract CPVesting is CPFunding { |  | contract CPVesting is CPFunding {
using SafeMath for uint256; |  | using SafeMath for uint256;
using SafeERC20 for IERC20; |  | using SafeERC20 for IERC20;
// ============ Events ============ |  | // ============ Events ============
event ClaimBaseToken(address user, uint256 baseAmount); | <> |
event ClaimQuoteToken(address user, uint256 quoteAmount); |  | event Claim(address user, uint256 baseAmount, uint256 quoteAmount);
event ClaimLP(uint256 amount); | = | event ClaimLP(uint256 amount);
// ================ Modifiers ================ |  | // ================ Modifiers ================
modifier afterSettlement() { |  | modifier afterSettlement() {
require(_SETTLED_, "NOT_SETTLED"); |  | require(_SETTLED_, "NOT_SETTLED");
_; |  | _;
} |  | }
modifier afterFreeze() { |  | modifier afterFreeze() {
require(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_FREEZE_DURATION_), "FREEZED"); |  | require(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_FREEZE_DURATION_), "FREEZED");
_; |  | _;
} |  | }
modifier afterClaimFreeze() { | +- |
require(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_TOKEN_CLAIM_DURATION_), "CLAIM_FREEZED"); |  |
_; |  |
} |  |
// ============ Bidder Functions ============ | = | // ============ Bidder Functions ============
function claimQuoteToken(address to,bytes calldata data) external afterSettlement { | <> | function bidderClaim(address to,bytes calldata data) external afterSettlement {
require(!_CLAIMED_QUOTE_[msg.sender], "ALREADY_CLAIMED_FUND"); |  | require(!_CLAIMED_[msg.sender], "ALREADY_CLAIMED");
_CLAIMED_QUOTE_[msg.sender] = true; |  | _CLAIMED_[msg.sender] = true;
| = |
| -+ | uint256 baseAmount = _UNUSED_BASE_.mul(_SHARES_[msg.sender]).div(_TOTAL_SHARES_);
uint256 quoteAmount = _UNUSED_QUOTE_.mul(_SHARES_[msg.sender]).div(_TOTAL_SHARES_); | = | uint256 quoteAmount = _UNUSED_QUOTE_.mul(_SHARES_[msg.sender]).div(_TOTAL_SHARES_);
| -+ | _transferBaseOut(to, baseAmount);
_transferQuoteOut(to, quoteAmount); | = | _transferQuoteOut(to, quoteAmount);
if(data.length>0){ |  | if(data.length>0){
IDODOCallee(to).CPClaimBidCall(msg.sender,0,quoteAmount,data); | <> | IDODOCallee(to).CPClaimBidCall(msg.sender,baseAmount,quoteAmount,data);
} | = | }
emit ClaimQuoteToken(msg.sender, quoteAmount); | <> | emit Claim(msg.sender, baseAmount, quoteAmount);
} |  |
function claimBaseToken() external afterClaimFreeze { |  |
uint256 claimableBaseAmount = getClaimableBaseToken(msg.sender); |  |
_transferBaseOut(msg.sender, claimableBaseAmount); |  |
_CLAIMED_BASE_TOKEN_[msg.sender] = _CLAIMED_BASE_TOKEN_[msg.sender].add(claimableBaseAmount); |  |
emit ClaimBaseToken(msg.sender, claimableBaseAmount); |  |
} |  |
function getClaimableBaseToken(address user) public view afterClaimFreeze returns (uint256) { |  |
uint256 baseTotalAmount = _UNUSED_BASE_.mul(_SHARES_[user]).div(_TOTAL_SHARES_); |  |
uint256 remainingBaseToken = DecimalMath.mulFloor( |  |
getRemainingBaseTokenRatio(block.timestamp), |  |
baseTotalAmount |  |
); |  |
return baseTotalAmount.sub(remainingBaseToken).sub(_CLAIMED_BASE_TOKEN_[user]); |  |
} |  |
function getRemainingBaseTokenRatio(uint256 timestamp) public view afterClaimFreeze returns (uint256) { |  |
uint256 timePast = timestamp.sub(_SETTLED_TIME_.add(_TOKEN_CLAIM_DURATION_)); |  |
if (timePast < _TOKEN_VESTING_DURATION_) { |  |
uint256 remainingTime = _TOKEN_VESTING_DURATION_.sub(timePast); |  |
return DecimalMath.ONE.sub(_TOKEN_CLIFF_RATE_).mul(remainingTime).div(_TOKEN_VESTING_DURATION_); |  |
} else { |  |
return 0; |  |
} |  |
} | = | }
// ============ Owner Functions ============ |  | // ============ Owner Functions ============
function claimLPToken() external onlyOwner afterFreeze { |  | function claimLPToken() external onlyOwner afterFreeze {
uint256 lpAmount = getClaimableLPToken(); |  | uint256 lpAmount = getClaimableLPToken();
IERC20(_POOL_).safeTransfer(_OWNER_, lpAmount); |  | IERC20(_POOL_).safeTransfer(_OWNER_, lpAmount);
emit ClaimLP(lpAmount); |  | emit ClaimLP(lpAmount);
} |  | }
function getClaimableLPToken() public view afterFreeze returns (uint256) { |  | function getClaimableLPToken() public view afterFreeze returns (uint256) {
uint256 remainingLPToken = DecimalMath.mulFloor( |  | uint256 remainingLPToken = DecimalMath.mulFloor(
getRemainingLPRatio(block.timestamp), |  | getRemainingLPRatio(block.timestamp),
_TOTAL_LP_AMOUNT_ |  | _TOTAL_LP_AMOUNT_
); |  | );
return IERC20(_POOL_).balanceOf(address(this)).sub(remainingLPToken); |  | return IERC20(_POOL_).balanceOf(address(this)).sub(remainingLPToken);
} |  | }
function getRemainingLPRatio(uint256 timestamp) public view afterFreeze returns (uint256) { |  | function getRemainingLPRatio(uint256 timestamp) public view afterFreeze returns (uint256) {
uint256 timePast = timestamp.sub(_SETTLED_TIME_.add(_FREEZE_DURATION_)); |  | uint256 timePast = timestamp.sub(_SETTLED_TIME_.add(_FREEZE_DURATION_));
if (timePast < _VESTING_DURATION_) { |  | if (timePast < _VESTING_DURATION_) {
uint256 remainingTime = _VESTING_DURATION_.sub(timePast); |  | uint256 remainingTime = _VESTING_DURATION_.sub(timePast);
return DecimalMath.ONE.sub(_CLIFF_RATE_).mul(remainingTime).div(_VESTING_DURATION_); |  | return DecimalMath.ONE.sub(_CLIFF_RATE_).mul(remainingTime).div(_VESTING_DURATION_);
} else { |  | } else {
return 0; |  | return 0;
} |  | }
} |  | }
} |  | }
// File: contracts/CrowdPooling/impl/CP.sol |  | // File: contracts/CrowdPooling/impl/CP.sol
| -+ |
/** | = | /**
* @title DODO CrowdPooling |  | * @title DODO CrowdPooling
* @author DODO Breeder |  | * @author DODO Breeder
* |  | *
* @notice CrowdPooling initialization |  | * @notice CrowdPooling initialization
*/ |  | */
contract CP is CPVesting { |  | contract CP is CPVesting {
using SafeMath for uint256; |  | using SafeMath for uint256;
receive() external payable { |  | receive() external payable {
require(_INITIALIZED_ == false, "WE_NOT_SAVE_ETH_AFTER_INIT"); |  | require(_INITIALIZED_ == false, "WE_NOT_SAVE_ETH_AFTER_INIT");
} |  | }
function init( |  | function init(
address[] calldata addressList, |  | address[] calldata addressList,
uint256[] calldata timeLine, |  | uint256[] calldata timeLine,
uint256[] calldata valueList, |  | uint256[] calldata valueList,
bool[] calldata switches //0 isOverCapStop 1 isOpenTWAP | <> | bool isOpenTWAP
) external { | = | ) external {
/* |  | /*
Address List |  | Address List
0. owner |  | 0. owner
1. maintainer |  | 1. maintainer
2. baseToken |  | 2. baseToken
3. quoteToken |  | 3. quoteToken
4. permissionManager |  | 4. permissionManager
5. feeRateModel |  | 5. feeRateModel
6. poolFactory |  | 6. poolFactory
*/ |  | */
require(addressList.length == 7, "LIST_LENGTH_WRONG"); |  | require(addressList.length == 7, "LIST_LENGTH_WRONG");
initOwner(addressList[0]); |  | initOwner(addressList[0]);
_MAINTAINER_ = addressList[1]; |  | _MAINTAINER_ = addressList[1];
_BASE_TOKEN_ = IERC20(addressList[2]); |  | _BASE_TOKEN_ = IERC20(addressList[2]);
_QUOTE_TOKEN_ = IERC20(addressList[3]); |  | _QUOTE_TOKEN_ = IERC20(addressList[3]);
_BIDDER_PERMISSION_ = IPermissionManager(addressList[4]); |  | _BIDDER_PERMISSION_ = IPermissionManager(addressList[4]);
_MT_FEE_RATE_MODEL_ = IFeeRateModel(addressList[5]); |  | _MT_FEE_RATE_MODEL_ = IFeeRateModel(addressList[5]);
_POOL_FACTORY_ = addressList[6]; |  | _POOL_FACTORY_ = addressList[6];
/* |  | /*
Time Line |  | Time Line
0. phase bid starttime |  | 0. phase bid starttime
1. phase bid duration |  | 1. phase bid duration
2. phase calm duration |  | 2. phase calm duration
3. freeze duration |  | 3. freeze duration
4. vesting duration |  | 4. vesting duration
5. claim freeze duration | +- |
6. claim vesting duration |  |
*/ | = | */
require(timeLine.length == 7, "LIST_LENGTH_WRONG"); | <> | require(timeLine.length == 5, "LIST_LENGTH_WRONG");
| = |
_PHASE_BID_STARTTIME_ = timeLine[0]; |  | _PHASE_BID_STARTTIME_ = timeLine[0];
_PHASE_BID_ENDTIME_ = _PHASE_BID_STARTTIME_.add(timeLine[1]); |  | _PHASE_BID_ENDTIME_ = _PHASE_BID_STARTTIME_.add(timeLine[1]);
_PHASE_CALM_ENDTIME_ = _PHASE_BID_ENDTIME_.add(timeLine[2]); |  | _PHASE_CALM_ENDTIME_ = _PHASE_BID_ENDTIME_.add(timeLine[2]);
_FREEZE_DURATION_ = timeLine[3]; |  | _FREEZE_DURATION_ = timeLine[3];
_VESTING_DURATION_ = timeLine[4]; |  | _VESTING_DURATION_ = timeLine[4];
_TOKEN_CLAIM_DURATION_ = timeLine[5]; | <> |
_TOKEN_VESTING_DURATION_ = timeLine[6]; |  |
require(block.timestamp <= _PHASE_BID_STARTTIME_, "TIMELINE_WRONG"); | = | require(block.timestamp <= _PHASE_BID_STARTTIME_, "TIMELINE_WRONG");
/* |  | /*
Value List |  | Value List
0. pool quote cap |  | 0. pool quote cap
1. k |  | 1. k
2. i |  | 2. i
3. lp cliff rate | <> | 3. cliff rate
4. base token cliff rate |  |
5. lp fee rate |  |
*/ | = | */
require(valueList.length == 6, "LIST_LENGTH_WRONG"); | <> | require(valueList.length == 4, "LIST_LENGTH_WRONG");
| = |
_POOL_QUOTE_CAP_ = valueList[0]; |  | _POOL_QUOTE_CAP_ = valueList[0];
_K_ = valueList[1]; |  | _K_ = valueList[1];
_I_ = valueList[2]; |  | _I_ = valueList[2];
_CLIFF_RATE_ = valueList[3]; |  | _CLIFF_RATE_ = valueList[3];
_TOKEN_CLIFF_RATE_ = valueList[4]; | +- |
_POOL_FEE_RATE_ = valueList[5]; |  |
| = |
require(_I_ > 0 && _I_ <= 1e36, "I_VALUE_WRONG"); |  | require(_I_ > 0 && _I_ <= 1e36, "I_VALUE_WRONG");
require(_K_ <= 1e18, "K_VALUE_WRONG"); |  | require(_K_ <= 1e18, "K_VALUE_WRONG");
require(_CLIFF_RATE_ <= 1e18, "CLIFF_RATE_WRONG"); |  | require(_CLIFF_RATE_ <= 1e18, "CLIFF_RATE_WRONG");
require(_TOKEN_CLIFF_RATE_ <= 1e18, "TOKEN_CLIFF_RATE_WRONG"); | +- |
| = |
_TOTAL_BASE_ = _BASE_TOKEN_.balanceOf(address(this)); |  | _TOTAL_BASE_ = _BASE_TOKEN_.balanceOf(address(this));
_IS_OVERCAP_STOP = switches[0]; | <> |
_IS_OPEN_TWAP_ = switches[1]; |  | _IS_OPEN_TWAP_ = isOpenTWAP;
| = |
require(address(this).balance == _SETTEL_FUND_, "SETTLE_FUND_NOT_MATCH"); |  | require(address(this).balance == _SETTEL_FUND_, "SETTLE_FUND_NOT_MATCH");
} |  | }
| +- |
// ============ Version Control ============ |  |
function version() virtual external pure returns (string memory) { |  |
return "CP 2.0.0"; |  |
} |  |
} | = | }