update cpV2
This commit is contained in:
@@ -59,10 +59,11 @@ contract CP is CPVesting {
|
||||
2. phase calm duration
|
||||
3. freeze duration
|
||||
4. vesting duration
|
||||
5. claim lock duration
|
||||
5. claim freeze duration
|
||||
6. claim vesting duration
|
||||
*/
|
||||
|
||||
require(timeLine.length == 6, "LIST_LENGTH_WRONG");
|
||||
require(timeLine.length == 7, "LIST_LENGTH_WRONG");
|
||||
|
||||
_PHASE_BID_STARTTIME_ = timeLine[0];
|
||||
_PHASE_BID_ENDTIME_ = _PHASE_BID_STARTTIME_.add(timeLine[1]);
|
||||
@@ -70,7 +71,8 @@ contract CP is CPVesting {
|
||||
|
||||
_FREEZE_DURATION_ = timeLine[3];
|
||||
_VESTING_DURATION_ = timeLine[4];
|
||||
_CLAIM_LOCK_DURATION_ = timeLine[5];
|
||||
_TOKEN_CLAIM_DURATION_ = timeLine[5];
|
||||
_TOKEN_VESTING_DURATION_ = timeLine[6];
|
||||
require(block.timestamp <= _PHASE_BID_STARTTIME_, "TIMELINE_WRONG");
|
||||
|
||||
/*
|
||||
@@ -78,19 +80,22 @@ contract CP is CPVesting {
|
||||
0. pool quote cap
|
||||
1. k
|
||||
2. i
|
||||
3. cliff rate
|
||||
3. lp cliff rate
|
||||
4. base token cliff rate
|
||||
*/
|
||||
|
||||
require(valueList.length == 4, "LIST_LENGTH_WRONG");
|
||||
require(valueList.length == 5, "LIST_LENGTH_WRONG");
|
||||
|
||||
_POOL_QUOTE_CAP_ = valueList[0];
|
||||
_K_ = valueList[1];
|
||||
_I_ = valueList[2];
|
||||
_CLIFF_RATE_ = valueList[3];
|
||||
_TOKEN_CLIFF_RATE_ = valueList[4];
|
||||
|
||||
require(_I_ > 0 && _I_ <= 1e36, "I_VALUE_WRONG");
|
||||
require(_K_ <= 1e18, "K_VALUE_WRONG");
|
||||
require(_CLIFF_RATE_ <= 1e18, "CLIFF_RATE_WRONG");
|
||||
require(_TOKEN_CLIFF_RATE_ <= 1e18, "TOKEN_CLIFF_RATE_WRONG");
|
||||
|
||||
_TOTAL_BASE_ = _BASE_TOKEN_.balanceOf(address(this));
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ contract CPStorage is InitializableOwnable, ReentrancyGuard {
|
||||
|
||||
uint256 public _TOTAL_SHARES_;
|
||||
mapping(address => uint256) internal _SHARES_;
|
||||
mapping(address => bool) public _CLAIMED_;
|
||||
mapping(address => bool) public _CLAIMED_QUOTE_;
|
||||
|
||||
address public _POOL_FACTORY_;
|
||||
address public _POOL_;
|
||||
@@ -75,7 +75,11 @@ contract CPStorage is InitializableOwnable, ReentrancyGuard {
|
||||
uint256 public _FREEZE_DURATION_;
|
||||
uint256 public _VESTING_DURATION_;
|
||||
uint256 public _CLIFF_RATE_;
|
||||
uint256 public _CLAIM_LOCK_DURATION_;
|
||||
|
||||
uint256 public _TOKEN_CLAIM_DURATION_;
|
||||
uint256 public _TOKEN_VESTING_DURATION_;
|
||||
uint256 public _TOKEN_CLIFF_RATE_;
|
||||
mapping(address => uint256) _CLAIMED_BASE_TOKEN_;
|
||||
|
||||
// ============ Modifiers ============
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ contract CPVesting is CPFunding {
|
||||
|
||||
// ============ Events ============
|
||||
|
||||
event Claim(address user, uint256 baseAmount, uint256 quoteAmount);
|
||||
event ClaimBaseToken(address user, uint256 baseAmount);
|
||||
event ClaimQuoteToken(address user, uint256 quoteAmount);
|
||||
event ClaimLP(uint256 amount);
|
||||
|
||||
|
||||
@@ -40,33 +41,59 @@ contract CPVesting is CPFunding {
|
||||
_;
|
||||
}
|
||||
|
||||
modifier afterClaimLockDuration() {
|
||||
require(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_CLAIM_LOCK_DURATION_), "CLAIM_LOCKED");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier afterFreeze() {
|
||||
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 ============
|
||||
|
||||
function bidderClaim(address to,bytes calldata data) external afterClaimLockDuration {
|
||||
require(!_CLAIMED_[msg.sender], "ALREADY_CLAIMED");
|
||||
_CLAIMED_[msg.sender] = true;
|
||||
function claimQuoteToken(address to,bytes calldata data) external afterSettlement {
|
||||
require(!_CLAIMED_QUOTE_[msg.sender], "ALREADY_CLAIMED_FUND");
|
||||
_CLAIMED_QUOTE_[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_);
|
||||
|
||||
_transferBaseOut(to, baseAmount);
|
||||
_transferQuoteOut(to, quoteAmount);
|
||||
|
||||
if(data.length>0){
|
||||
IDODOCallee(to).CPClaimBidCall(msg.sender,baseAmount,quoteAmount,data);
|
||||
IDODOCallee(to).CPClaimBidCall(msg.sender,0,quoteAmount,data);
|
||||
}
|
||||
|
||||
emit Claim(msg.sender, baseAmount, quoteAmount);
|
||||
emit ClaimQuoteToken(msg.sender, 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 ============
|
||||
|
||||
@@ -24,9 +24,9 @@ interface ICP {
|
||||
|
||||
function emergencySettle() external;
|
||||
|
||||
function claimBase() external;
|
||||
function claimBaseToken() external;
|
||||
|
||||
function claimQuote() external;
|
||||
function ClaimQuoteToken(address to,bytes calldata data) external;
|
||||
|
||||
function claimLPToken() external;
|
||||
}
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2021 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity 0.6.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {InitializableOwnable} from "../lib/InitializableOwnable.sol";
|
||||
import {ICloneFactory} from "../lib/CloneFactory.sol";
|
||||
import {IERC20} from "../intf/IERC20.sol";
|
||||
import {SafeMath} from "../lib/SafeMath.sol";
|
||||
|
||||
interface ICrowdPooling {
|
||||
function _QUOTE_RESERVE_() external view returns (uint256);
|
||||
function getShares(address user) external view returns (uint256);
|
||||
function _OWNER_() external returns (address);
|
||||
function _QUOTE_TOKEN_() external view returns(address);
|
||||
}
|
||||
|
||||
interface IFee {
|
||||
function getUserFee(address user) external view returns (uint256);
|
||||
}
|
||||
|
||||
interface IQuota {
|
||||
function getUserQuota(address user) external view returns (int);
|
||||
function initOwner(address newOwner) external;
|
||||
}
|
||||
|
||||
interface IPool {
|
||||
function version() external pure returns (string memory);
|
||||
function _LP_FEE_RATE_() external view returns (uint256);
|
||||
}
|
||||
|
||||
contract FeeRateImpl is InitializableOwnable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// ============ Storage ============
|
||||
address public _CLONE_FACTORY_;
|
||||
address public _QUOTA_TEMPLATE_;
|
||||
uint256 public _LP_MT_RATIO_ = 25;
|
||||
|
||||
struct CPPoolInfo {
|
||||
address quoteToken;
|
||||
int globalQuota;
|
||||
address feeAddr;
|
||||
address quotaAddr;
|
||||
}
|
||||
|
||||
mapping(address => CPPoolInfo) cpPools;
|
||||
mapping(address => uint256) public specPoolList;
|
||||
|
||||
|
||||
function init(
|
||||
address owner,
|
||||
address cloneFactory,
|
||||
address quotaTemplate
|
||||
) external {
|
||||
initOwner(owner);
|
||||
_CLONE_FACTORY_ = cloneFactory;
|
||||
_QUOTA_TEMPLATE_ = quotaTemplate;
|
||||
}
|
||||
|
||||
|
||||
// ============ Ownable Functions ============
|
||||
|
||||
function addCpPoolInfo(address cpPool, address quoteToken, int globalQuota, address feeAddr, address quotaAddr) external onlyOwner {
|
||||
CPPoolInfo memory cpPoolInfo = CPPoolInfo({
|
||||
quoteToken: quoteToken,
|
||||
feeAddr: feeAddr,
|
||||
quotaAddr: quotaAddr,
|
||||
globalQuota: globalQuota
|
||||
});
|
||||
cpPools[cpPool] = cpPoolInfo;
|
||||
}
|
||||
|
||||
function setCpPoolInfo(address cpPool, address quoteToken, int globalQuota, address feeAddr, address quotaAddr) external onlyOwner {
|
||||
cpPools[cpPool].quoteToken = quoteToken;
|
||||
cpPools[cpPool].feeAddr = feeAddr;
|
||||
cpPools[cpPool].quotaAddr = quotaAddr;
|
||||
cpPools[cpPool].globalQuota = globalQuota;
|
||||
}
|
||||
|
||||
function setLpMtRatio(uint256 newLpMtRatio) external onlyOwner {
|
||||
_LP_MT_RATIO_ = newLpMtRatio;
|
||||
}
|
||||
|
||||
|
||||
function setSpecPoolList (address poolAddr, uint256 mtFeeRate) public onlyOwner {
|
||||
specPoolList[poolAddr] = mtFeeRate;
|
||||
}
|
||||
|
||||
function setQuotaTemplate(address newQuotaTemplate) public onlyOwner {
|
||||
_QUOTA_TEMPLATE_ = newQuotaTemplate;
|
||||
}
|
||||
|
||||
function createWhitelist(address cpPool, address quotaOwner) external returns (address quotaAddr) {
|
||||
require(msg.sender == ICrowdPooling(cpPool)._OWNER_(), "Access restricted");
|
||||
|
||||
quotaAddr = ICloneFactory(_CLONE_FACTORY_).clone(_QUOTA_TEMPLATE_);
|
||||
IQuota(quotaAddr).initOwner(quotaOwner);
|
||||
address quoteToken = ICrowdPooling(cpPool)._QUOTE_TOKEN_();
|
||||
|
||||
CPPoolInfo memory cpPoolInfo = CPPoolInfo({
|
||||
quoteToken: quoteToken,
|
||||
feeAddr: address(0x0),
|
||||
quotaAddr: quotaAddr,
|
||||
globalQuota: 0
|
||||
});
|
||||
cpPools[cpPool] = cpPoolInfo;
|
||||
}
|
||||
|
||||
// ============ View Functions ============
|
||||
|
||||
function getFeeRate(address pool, address user) external view returns (uint256) {
|
||||
if(specPoolList[pool] != 0) {
|
||||
return specPoolList[pool];
|
||||
}
|
||||
|
||||
try IPool(pool).version() returns (string memory poolVersion) {
|
||||
bytes32 hashPoolVersion = keccak256(abi.encodePacked(poolVersion));
|
||||
if(hashPoolVersion == keccak256(abi.encodePacked("CP 1.0.0"))) {
|
||||
CPPoolInfo memory cpPoolInfo = cpPools[pool];
|
||||
address quoteToken = cpPoolInfo.quoteToken;
|
||||
if(quoteToken == address(0)) {
|
||||
return 0;
|
||||
}else {
|
||||
uint256 userInput = IERC20(quoteToken).balanceOf(pool).sub(ICrowdPooling(pool)._QUOTE_RESERVE_());
|
||||
uint256 userStake = ICrowdPooling(pool).getShares(user);
|
||||
address feeAddr = cpPoolInfo.feeAddr;
|
||||
address quotaAddr = cpPoolInfo.quotaAddr;
|
||||
int curQuota = cpPoolInfo.globalQuota;
|
||||
if(quotaAddr != address(0))
|
||||
curQuota = IQuota(quotaAddr).getUserQuota(user);
|
||||
|
||||
require(curQuota == -1 || (curQuota != -1 && int(userInput.add(userStake)) <= curQuota), "DODOFeeImpl: EXCEED_YOUR_QUOTA");
|
||||
|
||||
if(feeAddr == address(0)) {
|
||||
return 0;
|
||||
} else {
|
||||
return IFee(feeAddr).getUserFee(user);
|
||||
}
|
||||
}
|
||||
} else if(hashPoolVersion == keccak256(abi.encodePacked("DVM 1.0.2")) || hashPoolVersion == keccak256(abi.encodePacked("DSP 1.0.1"))) {
|
||||
uint256 lpFeeRate = IPool(pool)._LP_FEE_RATE_();
|
||||
uint256 mtFeeRate = lpFeeRate.mul(_LP_MT_RATIO_).div(100);
|
||||
if(lpFeeRate.add(mtFeeRate) >= 10**18) {
|
||||
return 0;
|
||||
} else {
|
||||
return mtFeeRate;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function getCPInfoByUser(address pool, address user) external view returns (bool isHaveCap, int curQuota, uint256 userFee) {
|
||||
CPPoolInfo memory cpPoolInfo = cpPools[pool];
|
||||
if(cpPoolInfo.quoteToken == address(0)) {
|
||||
isHaveCap = false;
|
||||
curQuota = -1;
|
||||
userFee = 0;
|
||||
}else {
|
||||
address quotaAddr = cpPoolInfo.quotaAddr;
|
||||
curQuota = cpPoolInfo.globalQuota;
|
||||
if(quotaAddr != address(0))
|
||||
curQuota = IQuota(quotaAddr).getUserQuota(user);
|
||||
|
||||
if(curQuota == -1) {
|
||||
isHaveCap = false;
|
||||
}else {
|
||||
isHaveCap = true;
|
||||
uint256 userStake = ICrowdPooling(pool).getShares(user);
|
||||
curQuota = int(uint256(curQuota).sub(userStake));
|
||||
}
|
||||
|
||||
address feeAddr = cpPoolInfo.feeAddr;
|
||||
if(feeAddr == address(0)) {
|
||||
userFee = 0;
|
||||
} else {
|
||||
userFee = IFee(feeAddr).getUserFee(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ contract DODOCpProxy is ReentrancyGuard {
|
||||
address constant _ETH_ADDRESS_ = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
address public immutable _WETH_;
|
||||
address public immutable _DODO_APPROVE_PROXY_;
|
||||
address public immutable _UPCP_FACTORY_;
|
||||
// address public immutable _UPCP_FACTORY_;
|
||||
address public immutable _CP_FACTORY_;
|
||||
|
||||
// ============ Modifiers ============
|
||||
@@ -46,55 +46,55 @@ contract DODOCpProxy is ReentrancyGuard {
|
||||
constructor(
|
||||
address payable weth,
|
||||
address cpFactory,
|
||||
address upCpFactory,
|
||||
// address upCpFactory,
|
||||
address dodoApproveProxy
|
||||
) public {
|
||||
_WETH_ = weth;
|
||||
_CP_FACTORY_ = cpFactory;
|
||||
_UPCP_FACTORY_ = upCpFactory;
|
||||
// _UPCP_FACTORY_ = upCpFactory;
|
||||
_DODO_APPROVE_PROXY_ = dodoApproveProxy;
|
||||
}
|
||||
|
||||
//============ UpCrowdPooling Functions (create) ============
|
||||
|
||||
function createUpCrowdPooling(
|
||||
address baseToken,
|
||||
address quoteToken,
|
||||
uint256 baseInAmount,
|
||||
uint256[] memory timeLine,
|
||||
uint256[] memory valueList,
|
||||
bool[] memory switches,
|
||||
uint256 deadLine
|
||||
) external payable preventReentrant judgeExpired(deadLine) returns (address payable newUpCrowdPooling) {
|
||||
address _baseToken = baseToken;
|
||||
address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken;
|
||||
// function createUpCrowdPooling(
|
||||
// address baseToken,
|
||||
// address quoteToken,
|
||||
// uint256 baseInAmount,
|
||||
// uint256[] memory timeLine,
|
||||
// uint256[] memory valueList,
|
||||
// bool[] memory switches,
|
||||
// uint256 deadLine
|
||||
// ) external payable preventReentrant judgeExpired(deadLine) returns (address payable newUpCrowdPooling) {
|
||||
// address _baseToken = baseToken;
|
||||
// address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken;
|
||||
|
||||
newUpCrowdPooling = IDODOV2(_UPCP_FACTORY_).createCrowdPooling();
|
||||
// newUpCrowdPooling = IDODOV2(_UPCP_FACTORY_).createCrowdPooling();
|
||||
|
||||
_deposit(
|
||||
msg.sender,
|
||||
newUpCrowdPooling,
|
||||
_baseToken,
|
||||
baseInAmount,
|
||||
false
|
||||
);
|
||||
// _deposit(
|
||||
// msg.sender,
|
||||
// newUpCrowdPooling,
|
||||
// _baseToken,
|
||||
// baseInAmount,
|
||||
// false
|
||||
// );
|
||||
|
||||
(bool success, ) = newUpCrowdPooling.call{value: msg.value}("");
|
||||
require(success, "DODOCpProxy: Transfer failed");
|
||||
// (bool success, ) = newUpCrowdPooling.call{value: msg.value}("");
|
||||
// require(success, "DODOCpProxy: Transfer failed");
|
||||
|
||||
address[] memory tokens = new address[](2);
|
||||
tokens[0] = _baseToken;
|
||||
tokens[1] = _quoteToken;
|
||||
// address[] memory tokens = new address[](2);
|
||||
// tokens[0] = _baseToken;
|
||||
// tokens[1] = _quoteToken;
|
||||
|
||||
IDODOV2(_UPCP_FACTORY_).initCrowdPooling(
|
||||
newUpCrowdPooling,
|
||||
msg.sender,
|
||||
tokens,
|
||||
timeLine,
|
||||
valueList,
|
||||
switches
|
||||
);
|
||||
}
|
||||
// IDODOV2(_UPCP_FACTORY_).initCrowdPooling(
|
||||
// newUpCrowdPooling,
|
||||
// msg.sender,
|
||||
// tokens,
|
||||
// timeLine,
|
||||
// valueList,
|
||||
// switches
|
||||
// );
|
||||
// }
|
||||
|
||||
//============ CrowdPooling Functions (create) ============
|
||||
|
||||
|
||||
Reference in New Issue
Block a user