cp whitelist binding

This commit is contained in:
owen05
2021-11-09 10:53:38 +08:00
parent 7fdb3cc7db
commit 7d8fde8297
14 changed files with 264 additions and 48 deletions

111
archive/FeeRateImpl.sol Normal file
View File

@@ -0,0 +1,111 @@
/*
Copyright 2020 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);
}
contract FeeRateImpl is InitializableOwnable {
using SafeMath for uint256;
struct CPPoolInfo {
address quoteToken;
int globalQuota;
address feeAddr;
address quotaAddr;
}
mapping(address => CPPoolInfo) cpPools;
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 getFeeRate(address pool, address user) external view returns (uint256) {
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);
}
}
}
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);
}
}
}
}

View File

@@ -23,7 +23,9 @@ module.exports = {
//Template
CloneFactory: "0x1ddD02f6d31C1eF04cFA0a1AA811406B5B2884E7",
FeeRateModel: "0x668E7f4d8051511279d3BD6d6854e7D39cc94873",
FeeRateDIP3: "0xc6DE76f82a3456D75212a454E83B37659886e190",
// FeeRateDIP3: "0xc6DE76f82a3456D75212a454E83B37659886e190",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0xb8132c7112aAf11fed09c7218AD2fcB42Da84773",
DVM: "0x790B4A80Fb1094589A3c0eFC8740aA9b0C1733fB",
DPP: "0xFF83897590Ac2f48aDFdEb9f497fe68A34B893C0",

View File

@@ -22,6 +22,8 @@ module.exports = {
CloneFactory: "0x6B208E08dcF6BD51F50C5Da09d15B2D8E5C46Cf2",
FeeRateModel: "0xb57Dd5c265dBb13CA014F2332069E90CD0e22e65",
//FeeRateDIP3: "0x7737fd30535c69545deeEa54AB8Dd590ccaEBD3c",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0xE55154D09265b18aC7CDAC6E646672A5460389a1",
DVM: "0x043957f7554275b90c5178872faE851dcfC1089D",
DPP: "0x85351262f7474Ebe23FfAcD633cf20A491F1325D",

View File

@@ -21,7 +21,9 @@ module.exports = {
//Template
CloneFactory: "0x4A82CD9E93f35b67962695268Afc602aCd34d088",
FeeRateModel: "0xa0f3499CE2fBF18dd179452d5dA52Db2E38c77d9",
FeeRateDIP3: "0x4b408F5FeE325De4B9D4fe73a49b08601b3c0aCD",
// FeeRateDIP3: "0x4b408F5FeE325De4B9D4fe73a49b08601b3c0aCD",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0xcB0Ae9A103CC0aCB74267a8a738dee21B965b463",
DVM: "0x4d6F9Ec882B0faE906D130789Df9004A79A61809",
DPP: "0xBCFBed364e1e9Ac687fD6430A31B1a097F19c5e6",

View File

@@ -16,6 +16,8 @@ module.exports = {
//Template
CloneFactory: "0x03E2427859119E497EB856a166F616a2Ce5f8c88",
FeeRateModel: "0x18DFdE99F578A0735410797e949E8D3e2AFCB9D2",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0x729f7f44bf64Ce814716b6261e267DbE6cdf021c",
DVM: "0x409E377A7AfFB1FD3369cfc24880aD58895D1dD9",
DPP: "0x85351262f7474Ebe23FfAcD633cf20A491F1325D",

View File

@@ -15,6 +15,8 @@ module.exports = {
//Template
CloneFactory: "0x5e5a7b76462e4bdf83aa98795644281bdba80b88",
FeeRateModel: "0x5e84190a270333aCe5B9202a3F4ceBf11b81bB01",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0x6B208E08dcF6BD51F50C5Da09d15B2D8E5C46Cf2",
DVM: "0x7cA7B5EAAf526d93705d28c1b47E9739595C90E7",
DPP: "0xB76de21f04F677f07D9881174a1D8E624276314C",

View File

@@ -16,6 +16,8 @@ module.exports = {
//Template
CloneFactory: "0x5dCEAe50CF8C3B885430E0E79226C513Db0318f2",
FeeRateModel: "0x07911226E710dd0b9B1c4a2Dd3c85DeFd821D492",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0xC142FBA5948c372f49aDa159748EA224de6cC9AA",
DVM: "0x05061d7f9353a7B5EB550840974B71A7465c2E86",
DPP: "0x824083c29f99cd1E31D4A6bD859b1B5C2F0EA3EE",

View File

@@ -16,6 +16,8 @@ module.exports = {
//Template
CloneFactory: "0x729f7f44bf64Ce814716b6261e267DbE6cdf021c",
FeeRateModel: "0x18b0bD918b55f995Fd404B872404378A62cb403b",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0x550B2e7bD9605b8dcdd20d01bA73f1feB6ce289b",
DVM: "0x041ABa00c57Dd47abC37A2931dF569a2A2cc57Be",
DPP: "0x80930Cb1849F7D42531506fF45E66724338A821b",

View File

@@ -12,15 +12,17 @@ module.exports = {
//DODO: "0xB5397B2210f49e96a5EB2c9747Aa2bD9397d90C0",
//ERC20Helper: "0x6373ceB657C83C91088d328622573FB766064Ac4",
DODOSellHelper: "0x5e84190a270333aCe5B9202a3F4ceBf11b81bB01",
DODOCalleeHelper: "", //0xc4436fBAE6eBa5d95bf7d53Ae515F8A707Bd402A replace weth
DODOCalleeHelper: "0xc4436fBAE6eBa5d95bf7d53Ae515F8A707Bd402A", // replace weth need to redeploy
DODOV1PmmHelper: "0x3CD6D7F5fF977bf8069548eA1F9441b061162b42",
DODOV2RouteHelper: "",//待升级
DODOV2RouteHelper: "0x8a6998b9A4E4f63c8aDB46ceEB01857A956A8122",
CurveSample: "",
//Template
CloneFactory: "0xDfaf9584F5d229A9DBE5978523317820A8897C5A",
FeeRateModel: "0x2BBD66fC4898242BDBD2583BBe1d76E8b8f71445",
//FeeRateDIP3: "0xbef0C8Cd420b76e9d31509abbfd7f8C9f664527c",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0x729f7f44bf64Ce814716b6261e267DbE6cdf021c",
DVM: "0xC3BeD579CaB3EC29B22D9AB99F4E586af42496b9",
DPP: "0x6fdDB76c93299D985f4d3FC7ac468F9A168577A4",
@@ -37,7 +39,7 @@ module.exports = {
//Factory
DVMFactory: "0x738Ebf387A0CE0eb46b0eF8Fa5DEa2EaE6B1Df51",
DPPFactory: "0xd0e1aA51dF0896c126Ce6F8A064E551e0DD3D39b",
DSPFactory: "0xB76de21f04F677f07D9881174a1D8E624276314C", //待修改DSP模板
DSPFactory: "0xB76de21f04F677f07D9881174a1D8E624276314C",
UpCpFactory: "0x043957f7554275b90c5178872faE851dcfC1089D",
CrowdPoolingFactory: "0x0596908263Ef2724fBfBcAfA1c983FCD7a629038",
ERC20V2Factory: "0xaeB5CF31b97dce6134e416129845e01106fFB177",
@@ -54,15 +56,13 @@ module.exports = {
UniAdapter: "0xa356867fDCEa8e71AEaF87805808803806231FdC",
CurveAdapter: "",
//not verify
//Proxy
DODOV2Proxy: "0xd9deC7c3C06e62a4c1BeEB07CadF568f496b14c2",
DSPProxy: "0x9f015aa5557ffBb47850c045Df67Bf229B07f2eA",
CpProxy: "0x357c5E9cfA8B834EDcef7C7aAbD8F9Db09119d11",
DPPProxy: "",//待配置
RouteProxy: "0x0125Cd41312F72a0774112Ca639D65A2C02e3627",
DODOMineV3Proxy: "0xb159260989012fA98af560A3Fa6D9cd11a64cf6E", //替换ERC20MineV3
DPPProxy: "0xB8605027F9a29D6a68eC489561c9a7ec9180aECC", //添加至ApproveProxy 等待时间锁
RouteProxy: "0x0125Cd41312F72a0774112Ca639D65A2C02e3627",
DODOMineV3Proxy: "0xb159260989012fA98af560A3Fa6D9cd11a64cf6E",
//Account
multiSigAddress: "0xef49a6DBa1C8DF859E49c17E9A485B439c7689d3",

View File

@@ -16,6 +16,8 @@ module.exports = {
//Template
CloneFactory: "0x2BBD66fC4898242BDBD2583BBe1d76E8b8f71445",
FeeRateModel: "0x18DFdE99F578A0735410797e949E8D3e2AFCB9D2",
FeeRateImpl: "",
UserQuota: "",
PermissionManager: "0x18b0bD918b55f995Fd404B872404378A62cb403b",
DVM: "0x550B2e7bD9605b8dcdd20d01bA73f1feB6ce289b",
DPP: "0x02fcb21dc1cf221939c1d4277fb54016b5d32bc7",

View File

@@ -14,6 +14,8 @@ module.exports = {
//Template
CloneFactory: "0x823ECBfCCD3e6Cb67d4c9334F743BEe0E60A7349",
FeeRateModel: "0x0ae835f585638CCbD4D7eAA339ED033f8194Bcfe",
UserQuota: "0x20D68Cf24211F24Fa0F78a48ab44Dc7da5f55e38",
FeeRateImpl:"0x08E485cF3A2d62DC43c37A783abBC85df540E821",
PermissionManager: "0x7949a4D350F69ef5Ff4c3079751250f5b7B86a00",
DVM: "0x44BD801ACAf994bD628d01d84299BE94010dc08B",
DPP: "0x604BFaDa2EAC7E011DdF9aA8848b38e8b02aDdD2",

View File

@@ -1,6 +1,6 @@
/*
Copyright 2020 DODO ZOO.
Copyright 2021 DODO ZOO.
SPDX-License-Identifier: Apache-2.0
*/
@@ -9,12 +9,15 @@ 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 {
@@ -23,11 +26,22 @@ interface IFee {
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;
@@ -36,7 +50,22 @@ contract FeeRateImpl is InitializableOwnable {
}
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,
@@ -54,31 +83,82 @@ contract FeeRateImpl is InitializableOwnable {
cpPools[cpPool].globalQuota = globalQuota;
}
function getFeeRate(address pool, address user) external view returns (uint256) {
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);
}
}
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)) {
@@ -106,6 +186,5 @@ contract FeeRateImpl is InitializableOwnable {
userFee = IFee(feeAddr).getUserFee(user);
}
}
}
}

View File

@@ -7,13 +7,13 @@
pragma solidity 0.6.9;
import {Ownable} from "../lib/Ownable.sol";
import {InitializableOwnable} from "../lib/InitializableOwnable.sol";
interface IQuota {
function getUserQuota(address user) external view returns (int);
}
contract UserQuota is Ownable, IQuota {
contract UserQuota is InitializableOwnable, IQuota {
mapping(address => uint256) public userQuota;

View File

@@ -6,7 +6,8 @@ const { GetConfig } = require("../configAdapter.js")
const CloneFactory = artifacts.require("CloneFactory");
const FeeRateModelTemplate = artifacts.require("FeeRateModel");
const FeeRateDIP3 = artifacts.require("FeeRateDIP3Impl");
const UserQuota = artifacts.require("UserQuota");
const FeeRateImpl = artifacts.require("FeeRateImpl");
const PermissionManagerTemplate = artifacts.require("PermissionManager");
const DODOSellHelper = artifacts.require("DODOSellHelper");
const DODOV1PmmHelper = artifacts.require("DODOV1PmmHelper");
@@ -68,7 +69,8 @@ module.exports = async (deployer, network, accounts) => {
//Template
let CloneFactoryAddress = CONFIG.CloneFactory;
let DefaultMtFeeRateAddress = CONFIG.FeeRateModel;
let FeeRateDIP3Address = CONFIG.FeeRateDIP3;
let UserQuotaAddress = CONFIG.UserQuota;
let FeeRateImplAddress = CONFIG.FeeRateImpl;
let DefaultPermissionAddress = CONFIG.PermissionManager;
let DvmTemplateAddress = CONFIG.DVM;
let DspTemplateAddress = CONFIG.DSP;
@@ -171,13 +173,19 @@ module.exports = async (deployer, network, accounts) => {
logger.log("Init DefaultMtFeeRateAddress Tx:", tx.tx);
}
if (FeeRateDIP3Address == "") {
await deployer.deploy(FeeRateDIP3);
FeeRateDIP3Address = FeeRateDIP3.address;
logger.log("FeeRateDIP3 Address: ", FeeRateDIP3Address);
const feeRateDIP3Instance = await FeeRateDIP3.at(FeeRateDIP3Address);
var tx = await feeRateDIP3Instance.initOwner(multiSigAddress);
logger.log("Init FeeRateDIP3 Tx:", tx.tx);
if (UserQuotaAddress == "") {
await deployer.deploy(UserQuota);
UserQuotaAddress = UserQuota.address;
logger.log("UserQuotaAddress: ", UserQuotaAddress);
}
if (FeeRateImplAddress == "") {
await deployer.deploy(FeeRateImpl);
FeeRateImplAddress = FeeRateImpl.address;
logger.log("FeeRateImpl Address: ", FeeRateImplAddress);
const feeRateImplInstance = await FeeRateImpl.at(FeeRateImplAddress);
var tx = await feeRateImplInstance.init(multiSigAddress,CloneFactoryAddress,UserQuotaAddress);
logger.log("Init FeeRateImpl Tx:", tx.tx);
}
if (DefaultPermissionAddress == "") {
@@ -485,10 +493,10 @@ module.exports = async (deployer, network, accounts) => {
tx = await DODOApproveInstance.init(multiSigAddress, DODOApproveProxy.address);
logger.log("DODOApprove Init tx: ", tx.tx);
//Set FeeRateDIP3
//Set FeeRateImpl
const FeeRateModelInstance = await FeeRateModelTemplate.at(DefaultMtFeeRateAddress);
tx = await FeeRateModelInstance.setFeeProxy(FeeRateDIP3Address);
logger.log("Set FeeRateDIP3 tx: ", tx.tx);
tx = await FeeRateModelInstance.setFeeProxy(FeeRateImplAddress);
logger.log("Set FeeRateImpl tx: ", tx.tx);
//ERC20V2Factory 设置fee
const ERC20V2FactoryInstance = await ERC20V2Factory.at(ERC20V2FactoryAddress);