dodo-start && cpV2 ing

This commit is contained in:
owen05
2021-12-02 16:15:22 +08:00
parent 63c1d9c70c
commit 4471274053
13 changed files with 555 additions and 111 deletions

View File

@@ -8,43 +8,112 @@
pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;
import {InitializableOwnable} from "../../lib/InitializableOwnable.sol";
import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol";
import {IQuota} from "../../DODOFee/UserQuota.sol";
import {SafeMath} from "../../lib/SafeMath.sol";
import {DecimalMath} from "../../lib/DecimalMath.sol";
import {IERC20} from "../../intf/IERC20.sol";
import {SafeERC20} from "../../lib/SafeERC20.sol";
import {Vesting} from "./Vesting.sol";
contract FairFunding is InitializableOwnable, ReentrancyGuard {
contract FairFunding is Vesting {
using SafeMath for uint256;
using SafeERC20 for IERC20;
// ============ Token & Balance ============
uint256 public _FUNDS_RESERVE_;
address public _FUNDS_ADDRESS_;
address public _TOKEN_ADDRESS_;
uint256 public _TOTAL_TOKEN_AMOUNT_;
// ============ Fair Mode ============
uint256 public _START_TIME_;
uint256 public _BIDDING_DURATION_;
uint256 public _COOLING_DURATION_;
address _QUOTA_;
mapping(address => uint256) _FUNDS_DEPOSITED_;
mapping(address => bool) _FUNDS_CLAIMED_;
uint256 public _TOTAL_RAISED_FUNDS_;
uint256 public _USED_FUND_RATIO_;
uint256 public _FINAL_PRICE_;
// ============ Parameters ============
uint256 public _LOWER_LIMIT_PRICE_;
uint256 public _UPPER_LIMIT_PRICE_;
// ============ Init ============
function init(
address[] calldata addressList,
uint256[] calldata timeLine,
uint256[] calldata valueList
) external {
/*
Address List
0. owner
1. sellToken
2. fundToken
3. quotaManager
4. poolFactory
*/
require(addressList.length == 5, "ADDR_LENGTH_WRONG");
initOwner(addressList[0]);
_TOKEN_ADDRESS_ = addressList[1];
_FUNDS_ADDRESS_ = addressList[2];
_QUOTA_ = addressList[3];
_POOL_FACTORY_ = addressList[4];
/*
Time Line
0. starttime
1. bid duration
2. calm duration
3. token vesting starttime
4. token vesting duration
5. fund vesting starttime
6. fund vesting duration
7. lp vesting starttime
8. lp vesting duration
*/
require(timeLine.length == 9, "TIME_LENGTH_WRONG");
_START_TIME_ = timeLine[0];
_BIDDING_DURATION_ = timeLine[1];
_COOLING_DURATION_ = timeLine[2];
_TOKEN_VESTING_START_ = timeLine[3];
_TOKEN_VESTING_DURATION_ = timeLine[4];
_FUNDS_VESTING_START_ = timeLine[5];
_FUNDS_VESTING_DURATION_ = timeLine[6];
_LP_VESTING_START_ = timeLine[7];
_LP_VESTING_DURATION_ = timeLine[8];
require(block.timestamp <= _START_TIME_, "START_TIME_WRONG");
require(_START_TIME_.add(_BIDDING_DURATION_).add(_COOLING_DURATION_) <= _TOKEN_VESTING_START_, "TOKEN_VESTING_TIME_WRONG");
require(_START_TIME_.add(_BIDDING_DURATION_).add(_COOLING_DURATION_) <= _FUNDS_VESTING_START_, "FUND_VESTING_TIME_WRONG");
/*
Value List
0. lower price
1. upper price
2. token cliffRate
3. fund cliffRate
4. lp cliffRate
5. initial liquidity
*/
require(valueList.length == 6, "VALUE_LENGTH_WRONG");
_LOWER_LIMIT_PRICE_ = valueList[0];
_UPPER_LIMIT_PRICE_ = valueList[1];
_TOKEN_CLIFF_RATE_ = valueList[2];
_FUNDS_CLIFF_RATE_ = valueList[3];
_LP_CLIFF_RATE_ = valueList[4];
_INITIAL_FUND_LIQUIDITY_ = valueList[5];
require(_LOWER_LIMIT_PRICE_ <= _UPPER_LIMIT_PRICE_, "PRICE_WRONG");
require(_TOKEN_CLIFF_RATE_ <= 1e18, "TOKEN_CLIFF_RATE_WRONG");
require(_FUNDS_CLIFF_RATE_ <= 1e18, "FUND_CLIFF_RATE_WRONG");
require(_LP_CLIFF_RATE_ <= 1e18, "LP_CLIFF_RATE_WRONG");
_TOTAL_TOKEN_AMOUNT_ = IERC20(_TOKEN_ADDRESS_).balanceOf(address(this));
}
// ============ View Functions ============
function getCurrentPrice() public view returns (uint256) {
@@ -84,7 +153,7 @@ contract FairFunding is InitializableOwnable, ReentrancyGuard {
// ============ Settle Functions ============
function settle() public {
function settle() public isForceStop {
require(_FINAL_PRICE_ == 0 && isFundingEnd(), "CAN_NOT_SETTLE");
_FINAL_PRICE_ = getCurrentPrice();
_USED_FUND_RATIO_ = DecimalMath.divFloor(
@@ -98,13 +167,7 @@ contract FairFunding is InitializableOwnable, ReentrancyGuard {
// ============ Funding Functions ============
function depositToken(uint256 amount) external preventReentrant onlyOwner {
require(block.timestamp < _START_TIME_, "FUNDING_ALREADY_STARTED");
IERC20(_TOKEN_ADDRESS_).safeTransferFrom(msg.sender, address(this), amount);
_TOTAL_TOKEN_AMOUNT_ = _TOTAL_TOKEN_AMOUNT_.add(amount);
}
function depositFunds(address to) external preventReentrant {
function depositFunds(address to) external preventReentrant isForceStop {
require(isDepositOpen(), "DEPOSIT_NOT_OPEN");
// input fund check
uint256 inputFund = IERC20(_FUNDS_ADDRESS_).balanceOf(address(this)).sub(_FUNDS_RESERVE_);
@@ -141,6 +204,11 @@ contract FairFunding is InitializableOwnable, ReentrancyGuard {
_TOTAL_TOKEN_AMOUNT_ = allocatedToken;
}
function claimToken(address to) external {
uint256 totalAllocation = getUserTokenAllocation(msg.sender);
_claimToken(to, totalAllocation);
}
// ============ Timeline Control Functions ============
function isDepositOpen() public view returns (bool) {

View File

@@ -8,49 +8,118 @@
pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;
import {InitializableOwnable} from "../../lib/InitializableOwnable.sol";
import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol";
import {IQuota} from "../../DODOFee/UserQuota.sol";
import {SafeMath} from "../../lib/SafeMath.sol";
import {DecimalMath} from "../../lib/DecimalMath.sol";
import {IERC20} from "../../intf/IERC20.sol";
import {SafeERC20} from "../../lib/SafeERC20.sol";
import {Vesting} from "./Vesting.sol";
contract InstantFunding is InitializableOwnable, ReentrancyGuard {
contract InstantFunding is Vesting {
using SafeMath for uint256;
using SafeERC20 for IERC20;
// ============ Token & Balance ============
uint256 public _FUNDS_RESERVE_;
address public _FUNDS_ADDRESS_;
address public _TOKEN_ADDRESS_;
uint256 public _TOTAL_TOKEN_AMOUNT_;
// ============ Instant Commit Mode ============
uint256 public _START_TIME_;
uint256 public _DURATION_;
uint256 public _START_PRICE_;
uint256 public _END_PRICE_;
address _QUOTA_;
mapping(address => uint256) _FUNDS_USED_;
mapping(address => uint256) _FUNDS_UNUSED_;
mapping(address => uint256) _TOKEN_ALLOCATION_;
uint256 public _TOTAL_ALLOCATED_TOKEN_;
uint256 public _TOTAL_RAISED_FUNDS_;
// ============ Init ============
function init(
address[] calldata addressList,
uint256[] calldata timeLine,
uint256[] calldata valueList
) external {
/*
Address List
0. owner
1. sellToken
2. fundToken
3. quotaManager
4. poolFactory
*/
require(addressList.length == 5, "ADDR_LENGTH_WRONG");
initOwner(addressList[0]);
_TOKEN_ADDRESS_ = addressList[1];
_FUNDS_ADDRESS_ = addressList[2];
_QUOTA_ = addressList[3];
_POOL_FACTORY_ = addressList[4];
/*
Time Line
0. starttime
1. bid duration
2. token vesting starttime
3. token vesting duration
4. fund vesting starttime
5. fund vesting duration
6. lp vesting starttime
7. lp vesting duration
*/
require(timeLine.length == 8, "TIME_LENGTH_WRONG");
_START_TIME_ = timeLine[0];
_BIDDING_DURATION_ = timeLine[1];
_TOKEN_VESTING_START_ = timeLine[2];
_TOKEN_VESTING_DURATION_ = timeLine[3];
_FUNDS_VESTING_START_ = timeLine[4];
_FUNDS_VESTING_DURATION_ = timeLine[5];
_LP_VESTING_START_ = timeLine[6];
_LP_VESTING_DURATION_ = timeLine[7];
require(block.timestamp <= _START_TIME_, "START_TIME_WRONG");
require(_START_TIME_.add(_BIDDING_DURATION_) <= _TOKEN_VESTING_START_, "TOKEN_VESTING_TIME_WRONG");
require(_START_TIME_.add(_BIDDING_DURATION_) <= _FUNDS_VESTING_START_, "FUND_VESTING_TIME_WRONG");
/*
Value List
0. start price
1. end price
2. token cliffRate
3. fund cliffRate
4. lp cliffRate
5. initial liquidity
*/
require(valueList.length == 6, "VALUE_LENGTH_WRONG");
_START_PRICE_ = valueList[0];
_END_PRICE_ = valueList[1];
_TOKEN_CLIFF_RATE_ = valueList[2];
_FUNDS_CLIFF_RATE_ = valueList[3];
_LP_CLIFF_RATE_ = valueList[4];
_INITIAL_FUND_LIQUIDITY_ = valueList[5];
require(_TOKEN_CLIFF_RATE_ <= 1e18, "TOKEN_CLIFF_RATE_WRONG");
require(_FUNDS_CLIFF_RATE_ <= 1e18, "FUND_CLIFF_RATE_WRONG");
require(_LP_CLIFF_RATE_ <= 1e18, "LP_CLIFF_RATE_WRONG");
_TOTAL_TOKEN_AMOUNT_ = IERC20(_TOKEN_ADDRESS_).balanceOf(address(this));
}
// ============ View Functions ============
function getCurrentPrice() public view returns (uint256 price) {
if (block.timestamp <= _START_TIME_) {
price = _START_PRICE_;
} else if (block.timestamp >= _START_TIME_.add(_DURATION_)) {
} else if (block.timestamp >= _START_TIME_.add(_BIDDING_DURATION_)) {
price = _END_PRICE_;
} else {
uint256 timePast = block.timestamp.sub(_START_TIME_);
price = _START_PRICE_.mul(_DURATION_.sub(timePast)).div(_DURATION_).add(
_END_PRICE_.mul(timePast).div(_DURATION_)
price = _START_PRICE_.mul(_BIDDING_DURATION_.sub(timePast)).div(_BIDDING_DURATION_).add(
_END_PRICE_.mul(timePast).div(_BIDDING_DURATION_)
);
}
}
@@ -68,16 +137,11 @@ contract InstantFunding is InitializableOwnable, ReentrancyGuard {
}
// ============ Funding Functions ============
//TODO:强制转入,适配通缩代币
function depositToken(uint256 amount) external preventReentrant onlyOwner {
require(block.timestamp < _START_TIME_, "FUNDING_ALREADY_STARTED");
IERC20(_TOKEN_ADDRESS_).safeTransferFrom(msg.sender, address(this), amount);
_TOTAL_TOKEN_AMOUNT_ = _TOTAL_TOKEN_AMOUNT_.add(amount);
}
function depositFunds(address to)
external
preventReentrant
isForceStop
returns (uint256 newTokenAllocation)
{
require(isDepositOpen(), "DEPOSIT_NOT_OPEN");
@@ -124,15 +188,20 @@ contract InstantFunding is InitializableOwnable, ReentrancyGuard {
_TOTAL_TOKEN_AMOUNT_ = _TOTAL_ALLOCATED_TOKEN_;
}
function claimToken(address to) external {
uint256 totalAllocation = getUserTokenAllocation(msg.sender);
_claimToken(to, totalAllocation);
}
// ============ Timeline Control Functions ============
function isDepositOpen() public view returns (bool) {
return
block.timestamp >= _START_TIME_ &&
block.timestamp < _START_TIME_.add(_DURATION_);
block.timestamp < _START_TIME_.add(_BIDDING_DURATION_);
}
function isFundingEnd() public view returns (bool) {
return block.timestamp > _START_TIME_.add(_DURATION_);
return block.timestamp > _START_TIME_.add(_BIDDING_DURATION_);
}
}

View File

@@ -0,0 +1,73 @@
/*
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 {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol";
import {SafeMath} from "../../lib/SafeMath.sol";
import {IERC20} from "../../intf/IERC20.sol";
contract Storage is InitializableOwnable, ReentrancyGuard {
using SafeMath for uint256;
bool public _FORCE_STOP_ = false;
address public _QUOTA_;
// ============ Token & Balance ============
uint256 public _FUNDS_RESERVE_;
address public _FUNDS_ADDRESS_;
address public _TOKEN_ADDRESS_;
uint256 public _TOTAL_TOKEN_AMOUNT_;
uint256 public _TOTAL_RAISED_FUNDS_;
// ============ Vesting Timeline ============
uint256 public _TOKEN_VESTING_START_;
uint256 public _TOKEN_VESTING_DURATION_;
uint256 public _TOKEN_CLIFF_RATE_;
mapping(address => uint256) _CLAIMED_TOKEN_;
uint256 public _FUNDS_VESTING_START_;
uint256 public _FUNDS_VESTING_DURATION_;
uint256 public _FUNDS_CLIFF_RATE_;
uint256 _CLAIMED_FUNDS_;
uint256 public _LP_VESTING_START_;
uint256 public _LP_VESTING_DURATION_;
uint256 public _LP_CLIFF_RATE_;
uint256 _CLAIMED_LP_;
// ============ Liquidity Params ============
address public _POOL_FACTORY_;
address public _INITIAL_POOL_;
uint256 public _INITIAL_FUND_LIQUIDITY_;
uint256 public _TOTAL_LP_;
// ============ Timeline ==============
uint256 public _START_TIME_;
uint256 public _BIDDING_DURATION_;
// ============ Modifiers ============
modifier isForceStop() {
require(!_FORCE_STOP_, "FORCE_STOP");
_;
}
function forceStop() external onlyOwner {
require(block.timestamp < _START_TIME_, "FUNDING_ALREADY_STARTED");
_FORCE_STOP_ = true;
_TOTAL_TOKEN_AMOUNT_ = 0;
uint256 tokenAmount = IERC20(_TOKEN_ADDRESS_).balanceOf(address(this));
IERC20(_TOKEN_ADDRESS_).transfer(_OWNER_, tokenAmount);
}
}

View File

@@ -8,7 +8,7 @@
pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;
import {InstantFunding} from "./InstantFunding.sol";
import {Storage} from "./Storage.sol";
import {IDVM} from "../../DODOVendingMachine/intf/IDVM.sol";
import {IDVMFactory} from "../../Factory/DVMFactory.sol";
import {SafeMath} from "../../lib/SafeMath.sol";
@@ -16,69 +16,82 @@ import {DecimalMath} from "../../lib/DecimalMath.sol";
import {IERC20} from "../../intf/IERC20.sol";
import {SafeERC20} from "../../lib/SafeERC20.sol";
contract Vesting is InstantFunding {
contract Vesting is Storage {
using SafeMath for uint256;
using SafeERC20 for IERC20;
// ============ Timeline ============
uint256 public _TOKEN_VESTING_START_;
uint256 public _TOKEN_VESTING_DURATION_;
mapping(address => uint256) _CLAIMED_TOKEN_;
uint256 public _FUNDS_VESTING_START_;
uint256 public _FUNDS_VESTING_DURATION_;
uint256 _CLAIMED_FUNDS_;
uint256 public _LP_VESTING_START_;
uint256 public _LP_VESTING_DURATION_;
uint256 _CLAIMED_LP_;
// ============ Liquidity Params ============
address public _POOL_FACTORY_;
address public _INITIAL_POOL_;
uint256 public _INITIAL_FUND_LIQUIDITY_;
uint256 public _TOTAL_LP_;
function claimToken(address to) external {
uint256 totalAllocation = getUserTokenAllocation(msg.sender);
uint256 unlockedAllocation = totalAllocation
.mul(block.timestamp.sub(_TOKEN_VESTING_START_))
.div(_TOKEN_VESTING_DURATION_);
IERC20(_TOKEN_ADDRESS_).safeTransfer(
to,
unlockedAllocation.sub(_CLAIMED_TOKEN_[msg.sender])
function _claimToken(address to, uint256 totalAllocation) internal {
uint256 remainingToken = DecimalMath.mulFloor(
getRemainingRatio(block.timestamp,0),
totalAllocation
);
_CLAIMED_TOKEN_[msg.sender] = unlockedAllocation;
uint256 claimableTokenAmount = totalAllocation.sub(remainingToken).sub(_CLAIMED_TOKEN_[msg.sender]);
IERC20(_TOKEN_ADDRESS_).safeTransfer(to,claimableTokenAmount);
_CLAIMED_TOKEN_[msg.sender] = _CLAIMED_TOKEN_[msg.sender].add(claimableTokenAmount);
}
function claimFunds(address to) external preventReentrant onlyOwner {
uint256 vestingFunds = _TOTAL_RAISED_FUNDS_.sub(_INITIAL_FUND_LIQUIDITY_);
uint256 unlockedFunds = vestingFunds.mul(block.timestamp.sub(_FUNDS_VESTING_START_)).div(
_FUNDS_VESTING_DURATION_
uint256 remainingFund = DecimalMath.mulFloor(
getRemainingRatio(block.timestamp,1),
vestingFunds
);
IERC20(_TOKEN_ADDRESS_).safeTransfer(to, unlockedFunds.sub(_CLAIMED_FUNDS_));
_CLAIMED_FUNDS_ = unlockedFunds;
uint256 claimableFund = vestingFunds.sub(remainingFund).sub(_CLAIMED_FUNDS_);
IERC20(_FUNDS_ADDRESS_).safeTransfer(to, claimableFund);
_CLAIMED_FUNDS_ = _CLAIMED_FUNDS_.add(claimableFund);
}
function claimLp(address to) external preventReentrant onlyOwner {
require(_INITIAL_POOL_ != address(0), "LIQUIDITY_NOT_ESTABLISHED");
uint256 unlockedLp = _TOTAL_LP_.mul(block.timestamp.sub(_LP_VESTING_START_)).div(
_LP_VESTING_DURATION_
uint256 remainingLp = DecimalMath.mulFloor(
getRemainingRatio(block.timestamp,2),
_TOTAL_LP_
);
IERC20(_TOKEN_ADDRESS_).safeTransfer(to, unlockedLp.sub(_CLAIMED_LP_));
_CLAIMED_LP_ = unlockedLp;
uint256 claimableLp = _TOTAL_LP_.sub(remainingLp).sub(_CLAIMED_LP_);
IERC20(_INITIAL_POOL_).safeTransfer(to, claimableLp);
_CLAIMED_LP_ = _CLAIMED_LP_.add(claimableLp);
}
function initializeLiquidity(uint256 initialTokenAmount) external preventReentrant onlyOwner {
//tokenType 0: BaseToken, 1: Fund, 2: LpToken
function getRemainingRatio(uint256 timestamp, uint256 tokenType) public view returns (uint256) {
uint256 vestingStart;
uint256 vestingDuration;
uint256 cliffRate;
if(tokenType == 0) {
vestingStart = _TOKEN_VESTING_START_;
vestingDuration = _TOKEN_VESTING_DURATION_;
cliffRate = _TOKEN_CLIFF_RATE_;
} else if(tokenType == 1) {
vestingStart = _FUNDS_VESTING_START_;
vestingDuration = _FUNDS_VESTING_DURATION_;
cliffRate = _FUNDS_CLIFF_RATE_;
} else {
vestingStart = _LP_VESTING_START_;
vestingDuration = _LP_VESTING_DURATION_;
cliffRate = _LP_CLIFF_RATE_;
}
uint256 timePast = timestamp.sub(vestingStart);
if (timePast < vestingDuration) {
uint256 remainingTime = vestingDuration.sub(timePast);
return DecimalMath.ONE.sub(cliffRate).mul(remainingTime).div(vestingDuration);
} else {
return 0;
}
}
function initializeLiquidity(uint256 initialTokenAmount, uint256 lpFeeRate, bool isOpenTWAP) external preventReentrant onlyOwner {
_INITIAL_POOL_ = IDVMFactory(_POOL_FACTORY_).createDODOVendingMachine(
_TOKEN_ADDRESS_,
_FUNDS_ADDRESS_,
3e15, // 0.3% lp feeRate DIP3
lpFeeRate,
1,
DecimalMath.ONE,
true //TODO:是否开启
isOpenTWAP
);
IERC20(_TOKEN_ADDRESS_).transferFrom(msg.sender, _INITIAL_POOL_, initialTokenAmount);
IERC20(_FUNDS_ADDRESS_).transfer(_INITIAL_POOL_, _INITIAL_FUND_LIQUIDITY_);