From 0b6402ad9af1a859cb4ea0817ae633558fe798d6 Mon Sep 17 00:00:00 2001 From: owen05 Date: Mon, 28 Jun 2021 23:20:15 +0800 Subject: [PATCH] dip3 --- config/arb-config.js | 2 +- contracts/CrowdPooling/impl/CP.sol | 6 ++ contracts/DODOFee/FeeRateDIP3Impl.sol | 143 ++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 contracts/DODOFee/FeeRateDIP3Impl.sol diff --git a/config/arb-config.js b/config/arb-config.js index 554cb5a..e3a2084 100644 --- a/config/arb-config.js +++ b/config/arb-config.js @@ -3,7 +3,7 @@ module.exports = { //TOKEN WETH: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", CHI: "0x0000000000000000000000000000000000000000", - DODO: "", + DODO: "0x69Eb4FA4a2fbd498C257C57Ea8b7655a2559A581", //Helper DODOSellHelper: "0x18AA6Bb215CDBd179E7beAE10F66C21B26971306", diff --git a/contracts/CrowdPooling/impl/CP.sol b/contracts/CrowdPooling/impl/CP.sol index 258143b..8cc4f13 100644 --- a/contracts/CrowdPooling/impl/CP.sol +++ b/contracts/CrowdPooling/impl/CP.sol @@ -97,4 +97,10 @@ contract CP is CPVesting { require(address(this).balance == _SETTEL_FUND_, "SETTLE_FUND_NOT_MATCH"); } + + // ============ Version Control ============ + + function version() virtual external pure returns (string memory) { + return "CP 1.0.0"; + } } diff --git a/contracts/DODOFee/FeeRateDIP3Impl.sol b/contracts/DODOFee/FeeRateDIP3Impl.sol new file mode 100644 index 0000000..4972bfe --- /dev/null +++ b/contracts/DODOFee/FeeRateDIP3Impl.sol @@ -0,0 +1,143 @@ +/* + + 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 {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); +} + +interface IFee { + function getUserFee(address user) external view returns (uint256); +} + +interface IQuota { + function getUserQuota(address user) external view returns (int); +} + +interface IPool { + function version() external pure returns (string memory); + function _LP_FEE_RATE_() external view returns (uint256); +} + +contract FeeRateDIP3Impl is InitializableOwnable { + using SafeMath for uint256; + + // ============ Storage ============ + + uint256 public _LP_MT_RATIO_ = 25; + + struct CPPoolInfo { + address quoteToken; + int globalQuota; + address feeAddr; + address quotaAddr; + } + + mapping(address => CPPoolInfo) cpPools; + + // ============ 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; + } + + // ============ View Functions ============ + + function getFeeRate(address pool, address user) external view returns (uint256) { + 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); + } + } + } +}