编译器
0.6.12+commit.27d51765
文件 1 的 16:Address.sol
pragma solidity 0.6.12;
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
function sendValue(address payable recipient, uint amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(
address target,
bytes memory data,
uint weiValue,
string memory errorMessage
) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: weiValue}(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 16:ConfigurableRightsPool.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import "./PCToken.sol";
import "../utils/DesynReentrancyGuard.sol";
import "../utils/DesynOwnable.sol";
import "../interfaces/IBFactory.sol";
import {RightsManager} from "../libraries/RightsManager.sol";
import "../libraries/SmartPoolManager.sol";
import "../libraries/SafeApprove.sol";
import "./WhiteToken.sol";
import "../libraries/SafeERC20.sol";
import '../libraries/Address.sol';
contract ConfigurableRightsPool is PCToken, DesynOwnable, DesynReentrancyGuard, WhiteToken {
using DesynSafeMath for uint;
using SafeERC20 for IERC20;
using Address for address;
IBFactory public bFactory;
IBPool public bPool;
RightsManager.Rights public rights;
SmartPoolManager.Status public etfStatus;
SmartPoolManager.Fund beginFund;
SmartPoolManager.Fund endFund;
address[] private _initialTokens;
uint[] private _initialBalances;
uint[] private _initialWeights;
mapping(address => bool) private _liquidityProviderWhitelist;
uint public constant CLAIM_PERIOD = 30 days;
address public vaultAddress;
bool hasSetWhiteTokens;
bool initBool;
bool public isCompletedCollect;
bool public hasSetBeginFund;
bool public hasSetEndFund;
bool public hasClaimManageFee;
SmartPoolManager.Etypes public etype;
event LogCall(bytes4 indexed sig, address indexed caller, bytes data) anonymous;
event LogJoin(address indexed caller, address indexed tokenIn, uint tokenAmountIn);
event LogExit(address indexed caller, address indexed tokenOut, uint tokenAmountOut);
event SizeChanged(address indexed caller, string indexed sizeType, uint oldSize, uint newSize);
event PoolTokenInit(address indexed caller, address pool, address initToken, uint initTokenTotal, uint initShare);
event SetManagerFee(uint indexed managerFee, uint indexed issueFee, uint indexed redeemFee, uint perfermanceFee);
modifier logs() {
emit LogCall(msg.sig, msg.sender, msg.data);
_;
}
modifier needsBPool() {
require(address(bPool) != address(0), "ERR_NOT_CREATED");
_;
}
modifier notPaused() {
require(!bFactory.isPaused(), "!paused");
_;
}
constructor(string memory tokenSymbol, string memory tokenName) public PCToken(tokenSymbol, tokenName) {}
function init(
address factoryAddress,
SmartPoolManager.PoolParams memory poolParams,
RightsManager.Rights memory rightsStruct
) public {
SmartPoolManager.initRequire(
poolParams.managerFee,
poolParams.issueFee,
poolParams.redeemFee,
poolParams.perfermanceFee,
poolParams.tokenBalances.length,
poolParams.tokenWeights.length,
poolParams.constituentTokens.length,
initBool
);
initBool = true;
rights = rightsStruct;
_initialTokens = poolParams.constituentTokens;
_initialBalances = poolParams.tokenBalances;
_initialWeights = poolParams.tokenWeights;
etfStatus = SmartPoolManager.Status({
collectPeriod: 0,
collectEndTime: 0,
closurePeriod: 0,
closureEndTime: 0,
upperCap: DesynConstants.MAX_UINT,
floorCap: 0,
managerFee: poolParams.managerFee,
redeemFee: poolParams.redeemFee,
issueFee: poolParams.issueFee,
perfermanceFee: poolParams.perfermanceFee,
startClaimFeeTime: block.timestamp
});
etype = poolParams.etype;
bFactory = IBFactory(factoryAddress);
vaultAddress = bFactory.getVault();
emit SetManagerFee(etfStatus.managerFee, etfStatus.issueFee, etfStatus.redeemFee, etfStatus.perfermanceFee);
}
function setCap(uint newCap) external logs lock needsBPool onlyOwner {
require(etype == SmartPoolManager.Etypes.OPENED, "ERR_MUST_OPEN_ETF");
emit SizeChanged(msg.sender, "UPPER", etfStatus.upperCap, newCap);
etfStatus.upperCap = newCap;
}
function execute(
address _target,
uint _value,
bytes calldata _data,
bool isUnderlying
) external logs lock needsBPool returns (bytes memory _returnValue) {
require(bFactory.getModuleStatus(address(this), msg.sender), 'MODULE IS NOT REGISTER');
if (isUnderlying) {
_returnValue = bPool.execute(_target, _value, _data);
} else {
_returnValue = _target.functionCallWithValue(_data, _value);
}
}
function couldClaimManagerFee() public view returns(bool state,uint timePoint ,uint timeElapsed){
bool isCloseETF = etype == SmartPoolManager.Etypes.CLOSED;
timePoint = block.timestamp;
if(isCloseETF && timePoint > etfStatus.closureEndTime) timePoint = etfStatus.closureEndTime;
timeElapsed = DesynSafeMath.bsub(timePoint, etfStatus.startClaimFeeTime);
if(timeElapsed >= CLAIM_PERIOD) state = true;
if(isCloseETF && !isCompletedCollect) state = false;
}
function claimManagerFee() public virtual logs lock onlyAdmin needsBPool {
_claimManagerFee();
}
function _claimManagerFee() internal {
(bool state, uint timePoint ,uint timeElapsed) = couldClaimManagerFee();
if(state){
address[] memory poolTokens = bPool.getCurrentTokens();
uint[] memory tokensAmount = SmartPoolManager.handleClaim(
IConfigurableRightsPool(address(this)),
bPool,
poolTokens,
etfStatus.managerFee,
timeElapsed,
CLAIM_PERIOD
);
IVault(vaultAddress).depositManagerToken(poolTokens, tokensAmount);
etfStatus.startClaimFeeTime = timePoint;
}
}
function createPool(
address creator,
uint initialSupply,
uint collectPeriod,
SmartPoolManager.Period closurePeriod,
SmartPoolManager.PoolTokenRange memory tokenRange
) external virtual onlyOwner logs lock notPaused {
if (etype == SmartPoolManager.Etypes.CLOSED) {
SmartPoolManager.createPoolHandle(collectPeriod, etfStatus.upperCap, initialSupply);
uint oldCap = etfStatus.upperCap;
uint oldFloor = etfStatus.floorCap;
etfStatus.upperCap = initialSupply.bmul(tokenRange.bspCap).bdiv(_initialBalances[0]);
etfStatus.floorCap = initialSupply.bmul(tokenRange.bspFloor).bdiv(_initialBalances[0]);
emit PoolTokenInit(creator, address(this),_initialTokens[0], _initialBalances[0], initialSupply);
emit SizeChanged(creator, "UPPER", oldCap, etfStatus.upperCap);
emit SizeChanged(creator, "FLOOR", oldFloor, etfStatus.floorCap);
uint period;
uint collectEndTime = block.timestamp + collectPeriod;
if (closurePeriod == SmartPoolManager.Period.DAY90) {
period = 90 days;
} else if (closurePeriod == SmartPoolManager.Period.DAY1) {
period = 1 days;
} else if (closurePeriod == SmartPoolManager.Period.DAY3) {
period = 3 days;
} else if (closurePeriod == SmartPoolManager.Period.DAY7) {
period = 7 days;
} else if (closurePeriod == SmartPoolManager.Period.DAY14) {
period = 14 days;
} else if (closurePeriod == SmartPoolManager.Period.DAY30) {
period = 30 days;
} else if (closurePeriod == SmartPoolManager.Period.DAY180) {
period = 180 days;
} else {
period = 360 days;
}
uint closureEndTime = collectEndTime + period;
etfStatus.collectPeriod = collectPeriod;
etfStatus.collectEndTime = collectEndTime;
etfStatus.closurePeriod = period;
etfStatus.closureEndTime = closureEndTime;
IUserVault(bFactory.getUserVault()).recordTokenInfo(creator, creator, _initialTokens, _initialBalances);
}
createPoolInternal(initialSupply);
}
function joinPool(
uint poolAmountOut,
uint[] calldata maxAmountsIn,
address kol,
address user
) external logs lock needsBPool notPaused {
SmartPoolManager.joinPoolHandle(rights.canWhitelistLPs, canProvideLiquidity(user), etype == SmartPoolManager.Etypes.CLOSED, etfStatus.collectEndTime);
if(rights.canTokenWhiteLists) {
require(_initWhiteTokenState(),"ERR_SHOULD_SET_WHITETOKEN");
}
uint[] memory actualAmountsIn = SmartPoolManager.joinPool(IConfigurableRightsPool(address(this)), bPool, poolAmountOut, maxAmountsIn, etfStatus.issueFee);
address[] memory poolTokens = bPool.getCurrentTokens();
uint[] memory issueFeesReceived = new uint[](poolTokens.length);
uint _actualIssueFee = etfStatus.issueFee;
if (etype == SmartPoolManager.Etypes.CLOSED) {
IUserVault(bFactory.getUserVault()).recordTokenInfo(kol, user, poolTokens, actualAmountsIn);
if (!isCompletedCollect) {
_actualIssueFee = 0;
}
}
for (uint i = 0; i < poolTokens.length; i++) {
uint issueFeeReceived = SmartPoolManager.handleTransferInTokens(
IConfigurableRightsPool(address(this)),
bPool,
poolTokens[i],
actualAmountsIn[i],
_actualIssueFee
);
emit LogJoin(user, poolTokens[i], actualAmountsIn[i]);
issueFeesReceived[i] = issueFeeReceived;
}
if (_actualIssueFee != 0) {
IVault(vaultAddress).depositIssueRedeemPToken(poolTokens, issueFeesReceived, issueFeesReceived, false);
}
_mintPoolShare(poolAmountOut);
_pushPoolShare(user, poolAmountOut);
bool isCompletedMoment = etype == SmartPoolManager.Etypes.CLOSED && varTotalSupply >= etfStatus.floorCap && !isCompletedCollect;
if (isCompletedMoment) {
isCompletedCollect = true;
SmartPoolManager.handleFeeClaim(
IConfigurableRightsPool(address(this)), bPool,
poolTokens,
etfStatus.issueFee,
false
);
}
}
function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut, address user) external logs lock needsBPool notPaused {
uint actualPoolAmountIn;
bool isCloseEtfCollectEndWithFailure;
uint _actualRedeemFee = etfStatus.redeemFee;
if(etype == SmartPoolManager.Etypes.CLOSED){
isCloseEtfCollectEndWithFailure = !isCompletedCollect && block.timestamp >= etfStatus.collectEndTime;
if(!isCloseEtfCollectEndWithFailure){
if(!hasClaimManageFee) {
_claimManagerFee();
hasClaimManageFee = true;
}
if(hasSetBeginFund && !hasSetEndFund) snapshotEndAssets();
}
if(isCloseEtfCollectEndWithFailure) _actualRedeemFee = 0;
}
actualPoolAmountIn = SmartPoolManager.exitPoolHandleB(
IConfigurableRightsPool(address(this)),
etype == SmartPoolManager.Etypes.CLOSED,
isCompletedCollect,
etfStatus.closureEndTime,
etfStatus.collectEndTime,
poolAmountIn
);
uint[] memory actualAmountsOut = SmartPoolManager.exitPool(IConfigurableRightsPool(address(this)), bPool, actualPoolAmountIn, minAmountsOut);
_pullPoolShare(msg.sender, actualPoolAmountIn);
_burnPoolShare(actualPoolAmountIn);
address[] memory poolTokens = bPool.getCurrentTokens();
uint[] memory redeemFeesReceived = new uint[](poolTokens.length);
for (uint i = 0; i < poolTokens.length; i++) {
(, uint finalAmountOut, uint redeemFeeReceived) = SmartPoolManager.exitPoolHandleA(
IConfigurableRightsPool(address(this)),
bPool,
poolTokens[i],
actualAmountsOut[i],
_actualRedeemFee
);
redeemFeesReceived[i] = redeemFeeReceived;
emit LogExit(user, poolTokens[i], finalAmountOut);
}
if (_actualRedeemFee != 0) {
IVault(vaultAddress).depositIssueRedeemPToken(poolTokens, redeemFeesReceived, redeemFeesReceived, true);
}
}
function whitelistLiquidityProvider(address provider) external onlyOwner lock logs {
SmartPoolManager.WhitelistHandle(rights.canWhitelistLPs, true, provider);
_liquidityProviderWhitelist[provider] = true;
}
function removeWhitelistedLiquidityProvider(address provider) external onlyOwner lock logs {
SmartPoolManager.WhitelistHandle(rights.canWhitelistLPs, _liquidityProviderWhitelist[provider], provider);
_liquidityProviderWhitelist[provider] = false;
}
function canProvideLiquidity(address provider) public view returns (bool) {
if (rights.canWhitelistLPs) {
return _liquidityProviderWhitelist[provider] || provider == getController() ;
} else {
return provider != address(0);
}
}
function hasPermission(RightsManager.Permissions permission) external view virtual returns (bool) {
return RightsManager.hasPermission(rights, permission);
}
function getRightsManagerVersion() external pure returns (address) {
return address(RightsManager);
}
function getDesynSafeMathVersion() external pure returns (address) {
return address(DesynSafeMath);
}
function getSmartPoolManagerVersion() external pure returns (address) {
return address(SmartPoolManager);
}
function mintPoolShareFromLib(uint amount) public {
require(msg.sender == address(this), "ERR_NOT_CONTROLLER");
_mint(amount);
}
function pushPoolShareFromLib(address to, uint amount) public {
require(msg.sender == address(this), "ERR_NOT_CONTROLLER");
_push(to, amount);
}
function pullPoolShareFromLib(address from, uint amount) public {
require(msg.sender == address(this), "ERR_NOT_CONTROLLER");
_pull(from, amount);
}
function burnPoolShareFromLib(uint amount) public {
require(msg.sender == address(this), "ERR_NOT_CONTROLLER");
_burn(amount);
}
function createPoolInternal(uint initialSupply) internal {
require(address(bPool) == address(0), "ERR_IS_CREATED");
_mintPoolShare(initialSupply);
_pushPoolShare(msg.sender, initialSupply);
bPool = bFactory.newLiquidityPool();
SmartPoolManager.createPoolInternalHandle(bPool, initialSupply);
for (uint i = 0; i < _initialTokens.length; i++) {
address t = _initialTokens[i];
uint bal = _initialBalances[i];
uint denorm = _initialWeights[i];
_verifyWhiteToken(t);
IERC20(t).safeTransferFrom(msg.sender, address(this), bal);
IERC20(t).safeApprove(address(bPool), 0);
IERC20(t).safeApprove(address(bPool), DesynConstants.MAX_UINT);
bPool.bind(t, bal, denorm);
}
while (_initialTokens.length > 0) {
_initialTokens.pop();
}
}
function addTokenToWhitelist(uint[] memory sort, address[] memory token) external onlyOwner {
require(rights.canTokenWhiteLists && !hasSetWhiteTokens, "ERR_NO_RIGHTS");
require(sort.length == token.length, "ERR_SORT_TOKEN_MISMATCH");
for (uint i = 0; i < token.length; i++) {
bool inRange = bFactory.isTokenWhitelistedForVerify(sort[i], token[i]);
require(inRange, "TOKEN_MUST_IN_WHITE_LISTS");
_addTokenToWhitelist(sort[i], token[i]);
}
hasSetWhiteTokens = true;
}
function _verifyWhiteToken(address token) public view {
require(bFactory.isTokenWhitelistedForVerify(token), "ERR_NOT_WHITE_TOKEN");
if (hasSetWhiteTokens) {
require(_queryIsTokenWhitelisted(token), "ERR_NOT_WHITE_TOKEN");
}
}
function _pullUnderlying(
address erc20,
address from,
uint amount
) internal needsBPool {
uint tokenBalance = bPool.getBalance(erc20);
uint tokenWeight = bPool.getDenormalizedWeight(erc20);
IERC20(erc20).safeTransferFrom(from, address(this), amount);
bPool.rebind(erc20, DesynSafeMath.badd(tokenBalance, amount), tokenWeight);
}
function _pushUnderlying(
address erc20,
address to,
uint amount
) internal needsBPool {
uint tokenBalance = bPool.getBalance(erc20);
uint tokenWeight = bPool.getDenormalizedWeight(erc20);
bPool.rebind(erc20, DesynSafeMath.bsub(tokenBalance, amount), tokenWeight);
IERC20(erc20).safeTransfer(to, amount);
}
function _mint(uint amount) internal override {
super._mint(amount);
require(varTotalSupply <= etfStatus.upperCap, "ERR_CAP_LIMIT_REACHED");
}
function _mintPoolShare(uint amount) internal {
_mint(amount);
}
function _pushPoolShare(address to, uint amount) internal {
_push(to, amount);
}
function _pullPoolShare(address from, uint amount) internal {
_pull(from, amount);
}
function _burnPoolShare(uint amount) internal {
_burn(amount);
}
function snapshotBeginAssets() external logs {
uint nowTime = block.timestamp;
require(!hasSetBeginFund && isCompletedCollect && etype == SmartPoolManager.Etypes.CLOSED && nowTime <= (etfStatus.collectEndTime + 3 days) , "ERR_CONDITIONS_NOT_MET");
bool inT1 = nowTime <= (etfStatus.collectEndTime + 1 days);
if(inT1) require(adminList[msg.sender] || msg.sender == _owner, "onlyAdmin");
beginFund = snapshotAssets();
hasSetBeginFund = true;
if(nowTime < etfStatus.collectEndTime) etfStatus.collectEndTime = block.timestamp;
}
function beginFundAssets() external view returns(SmartPoolManager.Fund memory){
return beginFund;
}
function endFundAssets() external view returns(SmartPoolManager.Fund memory){
return endFund;
}
function snapshotEndAssets() public logs {
uint nowTime = block.timestamp;
require(!hasSetEndFund && hasSetBeginFund && etype == SmartPoolManager.Etypes.CLOSED && nowTime >= etfStatus.closureEndTime, "ERR_CONDITIONS_NOT_MET");
bool inT1 = (etfStatus.closureEndTime + 1 days) >= nowTime;
if(inT1) require(adminList[msg.sender] || msg.sender == _owner, "onlyAdmin");
endFund = snapshotAssets();
uint preShareValueEnd = endFund.fundAmount.bdiv(endFund.etfAmount);
uint preShareValueBegin = beginFund.fundAmount.bdiv(beginFund.etfAmount);
if(preShareValueEnd > preShareValueBegin){
uint perfermanceRatio = etfStatus.perfermanceFee.bmul(preShareValueEnd-preShareValueBegin).bdiv(preShareValueEnd);
SmartPoolManager.handleFeeClaim(
IConfigurableRightsPool(address(this)), bPool,
bPool.getCurrentTokens(),
perfermanceRatio,
true);
}
hasSetEndFund = true;
}
function snapshotAssets() public returns(SmartPoolManager.Fund memory){
SmartPoolManager.Fund memory tempFund;
tempFund.etfAmount = varTotalSupply;
(tempFund.tokens, tempFund.tokensAmount) = _getPoolTokensInfo();
tempFund.fundAmount = Oracles(bFactory.getOracleAddress()).getAllPrice(tempFund.tokens, tempFund.tokensAmount);
tempFund.snapshotTime = block.timestamp;
return tempFund;
}
function _getPoolTokensInfo() internal view returns (address[] memory, uint[] memory) {
address[] memory tokens = bPool.getCurrentTokens();
uint[] memory totalBalances = new uint[](tokens.length);
for(uint i; i < tokens.length ;i++) {
totalBalances[i] = bPool.getBalance(tokens[i]);
}
return (tokens,totalBalances);
}
}
文件 3 的 16:DesynConstants.sol
pragma solidity 0.6.12;
library DesynConstants {
uint public constant BONE = 10**18;
uint public constant MIN_WEIGHT = BONE;
uint public constant MAX_WEIGHT = BONE * 50;
uint public constant MAX_TOTAL_WEIGHT = BONE * 50;
uint public constant MIN_BALANCE = 0;
uint public constant MAX_BALANCE = BONE * 10**12;
uint public constant MIN_POOL_SUPPLY = BONE * 100;
uint public constant MAX_POOL_SUPPLY = BONE * 10**9;
uint public constant MIN_FEE = BONE / 10**6;
uint public constant MAX_FEE = BONE / 10;
uint public constant MANAGER_MIN_FEE = 0;
uint public constant MANAGER_MAX_FEE = BONE / 10;
uint public constant ISSUE_MIN_FEE = 0;
uint public constant ISSUE_MAX_FEE = BONE / 10;
uint public constant REDEEM_MIN_FEE = 0;
uint public constant REDEEM_MAX_FEE = BONE / 10;
uint public constant PERFERMANCE_MIN_FEE = 0;
uint public constant PERFERMANCE_MAX_FEE = BONE / 2;
uint public constant EXIT_FEE = 0;
uint public constant MAX_IN_RATIO = BONE / 2;
uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei;
uint public constant MIN_ASSET_LIMIT = 1;
uint public constant MAX_ASSET_LIMIT = 16;
uint public constant MAX_UINT = uint(-1);
uint public constant MAX_COLLECT_PERIOD = 60 days;
}
文件 4 的 16:DesynOwnable.sol
pragma solidity 0.6.12;
contract DesynOwnable {
mapping(address => bool) public adminList;
uint public allOwnerPercentage = 10000;
address _owner;
address[] owners;
uint[] ownerPercentage;
bool initialized;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event AddAdmin(address indexed newAdmin, uint indexed amount);
event RemoveAdmin(address indexed oldAdmin, uint indexed amount);
modifier onlyOwner() {
require(_owner == msg.sender, "ERR_NOT_CONTROLLER");
_;
}
modifier onlyAdmin() {
require(adminList[msg.sender] || msg.sender == _owner, "onlyAdmin");
_;
}
constructor() internal {
_owner = msg.sender;
}
function initHandle(address[] memory _owners, uint[] memory _ownerPercentage) external {
require(_owners.length == _ownerPercentage.length, "ownerP");
require(!initialized, "initialized!");
_addAdmin(_owners);
owners = _owners;
ownerPercentage = _ownerPercentage;
initialized = true;
_ownerPercentageChecker();
}
function setManagersInfo(address[] memory _owners, uint[] memory _ownerPercentage) external onlyOwner {
_beforeControllerChange();
_clearAdmin();
_addAdmin(_owners);
owners = _owners;
ownerPercentage = _ownerPercentage;
_ownerPercentageChecker();
}
function _ownerPercentageChecker() internal view {
uint totalPercentage;
for (uint i; i < ownerPercentage.length; i++) {
totalPercentage+=ownerPercentage[i];
}
require(totalPercentage == 10000, "ERR_ILLEGAL_PERCENTAGE");
}
function _addAdmin(address[] memory admins) internal {
bool hasOwner;
for (uint i; i < admins.length; i++) {
adminList[admins[i]] = true;
if(admins[i] == _owner) hasOwner = true;
}
if(initialized) require(hasOwner, "ERR_NEW_ADMINS_HAS_NO_OWNER");
}
function _clearAdmin() internal {
for(uint i; i < owners.length; i++) {
delete adminList[owners[i]];
}
}
function setController(address newOwner) external onlyOwner {
_beforeControllerChange();
require(newOwner != address(0), "ERR_ZERO_ADDRESS");
emit OwnershipTransferred(_owner, newOwner);
for (uint i;i < owners.length; i++) {
if (owners[i] == _owner) {
owners[i] = newOwner;
}
}
adminList[_owner] = false;
adminList[newOwner] = true;
_owner = newOwner;
}
function getOwners() external view returns (address[] memory) {
return owners;
}
function getOwnerPercentage() external view returns (uint[] memory) {
return ownerPercentage;
}
function getController() public view returns (address) {
return _owner;
}
function _beforeControllerChange() internal virtual {}
}
文件 5 的 16:DesynReentrancyGuard.sol
pragma solidity 0.6.12;
contract DesynReentrancyGuard {
uint private constant _NOT_ENTERED = 1;
uint private constant _ENTERED = 2;
uint private _status;
constructor() internal {
_status = _NOT_ENTERED;
}
modifier lock() {
require(_status != _ENTERED, "ERR_REENTRY");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
modifier viewlock() {
require(_status != _ENTERED, "ERR_REENTRY_VIEW");
_;
}
}
文件 6 的 16:DesynSafeMath.sol
pragma solidity 0.6.12;
import "./DesynConstants.sol";
library DesynSafeMath {
function badd(uint a, uint b) internal pure returns (uint) {
uint c = a + b;
require(c >= a, "ERR_ADD_OVERFLOW");
return c;
}
function bsub(uint a, uint b) internal pure returns (uint) {
(uint c, bool negativeResult) = bsubSign(a, b);
require(!negativeResult, "ERR_SUB_UNDERFLOW");
return c;
}
function bsubSign(uint a, uint b) internal pure returns (uint, bool) {
if (b <= a) {
return (a - b, false);
} else {
return (b - a, true);
}
}
function bmul(uint a, uint b) internal pure returns (uint) {
if (a == 0) {
return 0;
}
uint c0 = a * b;
require(c0 / a == b, "ERR_MUL_OVERFLOW");
uint c1 = c0 + (DesynConstants.BONE / 2);
require(c1 >= c0, "ERR_MUL_OVERFLOW");
uint c2 = c1 / DesynConstants.BONE;
return c2;
}
function bdiv(uint dividend, uint divisor) internal pure returns (uint) {
require(divisor != 0, "ERR_DIV_ZERO");
if (dividend == 0) {
return 0;
}
uint c0 = dividend * DesynConstants.BONE;
require(c0 / dividend == DesynConstants.BONE, "ERR_DIV_INTERNAL");
uint c1 = c0 + (divisor / 2);
require(c1 >= c0, "ERR_DIV_INTERNAL");
uint c2 = c1 / divisor;
return c2;
}
function bmod(uint dividend, uint divisor) internal pure returns (uint) {
require(divisor != 0, "ERR_MODULO_BY_ZERO");
return dividend % divisor;
}
function bmax(uint a, uint b) internal pure returns (uint) {
return a >= b ? a : b;
}
function bmin(uint a, uint b) internal pure returns (uint) {
return a < b ? a : b;
}
function baverage(uint a, uint b) internal pure returns (uint) {
return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
}
function sqrt(uint y) internal pure returns (uint z) {
if (y > 3) {
z = y;
uint x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}
文件 7 的 16:IBFactory.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
interface IBPool {
function rebind(
address token,
uint balance,
uint denorm
) external;
function execute(
address _target,
uint _value,
bytes calldata _data
) external returns (bytes memory _returnValue);
function bind(
address token,
uint balance,
uint denorm
) external;
function unbind(address token) external;
function unbindPure(address token) external;
function isBound(address token) external view returns (bool);
function getBalance(address token) external view returns (uint);
function totalSupply() external view returns (uint);
function isPublicSwap() external view returns (bool);
function getDenormalizedWeight(address token) external view returns (uint);
function getTotalDenormalizedWeight() external view returns (uint);
function EXIT_FEE() external view returns (uint);
function getCurrentTokens() external view returns (address[] memory tokens);
function setController(address owner) external;
}
interface IBFactory {
function newLiquidityPool() external returns (IBPool);
function setBLabs(address b) external;
function collect(IBPool pool) external;
function isBPool(address b) external view returns (bool);
function getBLabs() external view returns (address);
function getVault() external view returns (address);
function getUserVault() external view returns (address);
function getVaultAddress() external view returns (address);
function getOracleAddress() external view returns (address);
function isTokenWhitelistedForVerify(uint sort, address token) external view returns (bool);
function isTokenWhitelistedForVerify(address token) external view returns (bool);
function getModuleStatus(address etf, address module) external view returns (bool);
function isPaused() external view returns (bool);
}
interface IVault {
function depositManagerToken(address[] calldata poolTokens, uint[] calldata tokensAmount) external;
function depositIssueRedeemPToken(
address[] calldata poolTokens,
uint[] calldata tokensAmount,
uint[] calldata tokensAmountP,
bool isPerfermance
) external;
function managerClaim(address pool) external;
function getManagerClaimBool(address pool) external view returns (bool);
}
interface IUserVault {
function recordTokenInfo(
address kol,
address user,
address[] calldata poolTokens,
uint[] calldata tokensAmount
) external;
}
interface Oracles {
function getPrice(address tokenAddress) external returns (uint price);
function getAllPrice(address[] calldata poolTokens, uint[] calldata tokensAmount) external returns (uint);
}
文件 8 的 16:IConfigurableRightsPool.sol
pragma solidity 0.6.12;
interface IConfigurableRightsPool {
function mintPoolShareFromLib(uint amount) external;
function pushPoolShareFromLib(address to, uint amount) external;
function pullPoolShareFromLib(address from, uint amount) external;
function burnPoolShareFromLib(uint amount) external;
function balanceOf(address account) external view returns (uint);
function totalSupply() external view returns (uint);
function adminList(address) external view returns (bool);
function getController() external view returns (address);
function vaultAddress() external view returns (address);
}
文件 9 的 16:IERC20.sol
pragma solidity 0.6.12;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function totalSupply() external view returns (uint);
function balanceOf(address account) external view returns (uint);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint amount) external returns (bool);
function transfer(address recipient, uint amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint amount
) external returns (bool);
}
文件 10 的 16:PCToken.sol
pragma solidity 0.6.12;
import "../libraries/DesynSafeMath.sol";
import "../interfaces/IERC20.sol";
contract PCToken is IERC20 {
using DesynSafeMath for uint;
string public constant NAME = "Desyn Smart Pool";
uint8 public constant DECIMALS = 18;
uint internal varTotalSupply;
mapping(address => uint) private _balance;
mapping(address => mapping(address => uint)) private _allowance;
string private _symbol;
string private _name;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
constructor(string memory tokenSymbol, string memory tokenName) public {
_symbol = tokenSymbol;
_name = tokenName;
}
function allowance(address owner, address spender) external view override returns (uint) {
return _allowance[owner][spender];
}
function balanceOf(address account) external view override returns (uint) {
return _balance[account];
}
function approve(address spender, uint amount) external override returns (bool) {
_allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function increaseApproval(address spender, uint amount) external returns (bool) {
_allowance[msg.sender][spender] = DesynSafeMath.badd(_allowance[msg.sender][spender], amount);
emit Approval(msg.sender, spender, _allowance[msg.sender][spender]);
return true;
}
function decreaseApproval(address spender, uint amount) external returns (bool) {
uint oldValue = _allowance[msg.sender][spender];
if (amount >= oldValue) {
_allowance[msg.sender][spender] = 0;
} else {
_allowance[msg.sender][spender] = DesynSafeMath.bsub(oldValue, amount);
}
emit Approval(msg.sender, spender, _allowance[msg.sender][spender]);
return true;
}
function transfer(address recipient, uint amount) external override returns (bool) {
require(recipient != address(0), "ERR_ZERO_ADDRESS");
_move(msg.sender, recipient, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint amount
) external override returns (bool) {
require(recipient != address(0), "ERR_ZERO_ADDRESS");
require(msg.sender == sender || amount <= _allowance[sender][msg.sender], "ERR_PCTOKEN_BAD_CALLER");
_move(sender, recipient, amount);
uint oldAllowance = _allowance[sender][msg.sender];
if (msg.sender != sender && oldAllowance != uint(-1)) {
_allowance[sender][msg.sender] = DesynSafeMath.bsub(oldAllowance, amount);
emit Approval(sender, msg.sender, _allowance[sender][msg.sender]);
}
return true;
}
function totalSupply() external view override returns (uint) {
return varTotalSupply;
}
function name() external view returns (string memory) {
return _name;
}
function symbol() external view override returns (string memory) {
return _symbol;
}
function decimals() external view override returns (uint8) {
return DECIMALS;
}
function _mint(uint amount) internal virtual {
_balance[address(this)] = DesynSafeMath.badd(_balance[address(this)], amount);
varTotalSupply = DesynSafeMath.badd(varTotalSupply, amount);
emit Transfer(address(0), address(this), amount);
}
function _burn(uint amount) internal virtual {
_balance[address(this)] = DesynSafeMath.bsub(_balance[address(this)], amount);
varTotalSupply = DesynSafeMath.bsub(varTotalSupply, amount);
emit Transfer(address(this), address(0), amount);
}
function _move(
address sender,
address recipient,
uint amount
) internal virtual {
_balance[sender] = DesynSafeMath.bsub(_balance[sender], amount);
_balance[recipient] = DesynSafeMath.badd(_balance[recipient], amount);
emit Transfer(sender, recipient, amount);
}
function _push(address recipient, uint amount) internal {
_move(address(this), recipient, amount);
}
function _pull(address sender, uint amount) internal {
_move(sender, address(this), amount);
}
}
文件 11 的 16:RightsManager.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
library RightsManager {
enum Permissions {
WHITELIST_LPS,
TOKEN_WHITELISTS
}
struct Rights {
bool canWhitelistLPs;
bool canTokenWhiteLists;
}
bool public constant DEFAULT_CAN_WHITELIST_LPS = false;
bool public constant DEFAULT_CAN_TOKEN_WHITELISTS = false;
function constructRights(bool[] calldata a) external pure returns (Rights memory) {
if (a.length < 2) {
return
Rights(
DEFAULT_CAN_WHITELIST_LPS,
DEFAULT_CAN_TOKEN_WHITELISTS
);
} else {
return Rights(a[0], a[1]);
}
}
function convertRights(Rights calldata rights) external pure returns (bool[] memory) {
bool[] memory result = new bool[](2);
result[0] = rights.canWhitelistLPs;
result[1] = rights.canTokenWhiteLists;
return result;
}
function hasPermission(Rights calldata self, Permissions permission) external pure returns (bool) {
if (Permissions.WHITELIST_LPS == permission) {
return self.canWhitelistLPs;
} else if (Permissions.TOKEN_WHITELISTS == permission) {
return self.canTokenWhiteLists;
}
}
}
文件 12 的 16:SafeApprove.sol
pragma solidity 0.6.12;
import "../interfaces/IERC20.sol";
library SafeApprove {
function safeApprove(
IERC20 token,
address spender,
uint amount
) internal returns (bool) {
uint currentAllowance = token.allowance(address(this), spender);
if (currentAllowance == amount) {
return true;
}
if (currentAllowance != 0) {
token.approve(spender, 0);
}
return token.approve(spender, amount);
}
}
文件 13 的 16:SafeERC20.sol
pragma solidity 0.6.12;
import {IERC20} from "../interfaces/IERC20.sol";
import {SafeMath} from "./SafeMath.sol";
import {Address} from "./Address.sol";
library SafeERC20 {
using SafeMath for uint;
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint value
) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint value
) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint value
) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance");
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function callOptionalReturn(IERC20 token, bytes memory data) private {
require(address(token).isContract(), "SafeERC20: call to non-contract");
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 14 的 16:SafeMath.sol
pragma solidity 0.6.12;
library SafeMath {
function add(uint a, uint b) internal pure returns (uint) {
uint c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint a, uint b) internal pure returns (uint) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(
uint a,
uint b,
string memory errorMessage
) internal pure returns (uint) {
require(b <= a, errorMessage);
uint c = a - b;
return c;
}
function mul(uint a, uint b) internal pure returns (uint) {
if (a == 0) {
return 0;
}
uint c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint a, uint b) internal pure returns (uint) {
return div(a, b, "SafeMath: division by zero");
}
function div(
uint a,
uint b,
string memory errorMessage
) internal pure returns (uint) {
require(b > 0, errorMessage);
uint c = a / b;
return c;
}
function mod(uint a, uint b) internal pure returns (uint) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(
uint a,
uint b,
string memory errorMessage
) internal pure returns (uint) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 15 的 16:SmartPoolManager.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import "../interfaces/IERC20.sol";
import "../interfaces/IConfigurableRightsPool.sol";
import "../interfaces/IBFactory.sol";
import "./DesynSafeMath.sol";
import "./SafeMath.sol";
import "../libraries/SafeERC20.sol";
library SmartPoolManager {
using DesynSafeMath for uint;
using SafeMath for uint;
using SafeERC20 for IERC20;
struct levelParams {
uint level;
uint ratio;
}
struct feeParams {
levelParams firstLevel;
levelParams secondLevel;
levelParams thirdLevel;
levelParams fourLevel;
}
struct KolPoolParams {
feeParams managerFee;
feeParams issueFee;
feeParams redeemFee;
feeParams perfermanceFee;
}
enum Etypes {
OPENED,
CLOSED
}
enum Period {
DAY90,
DAY180,
DAY360,
DAY1,
DAY3,
DAY7,
DAY14,
DAY30
}
struct Fund {
uint etfAmount;
uint fundAmount;
uint snapshotTime;
address[] tokens;
uint[] tokensAmount;
}
struct Status {
uint collectPeriod;
uint collectEndTime;
uint closurePeriod;
uint closureEndTime;
uint upperCap;
uint floorCap;
uint managerFee;
uint redeemFee;
uint issueFee;
uint perfermanceFee;
uint startClaimFeeTime;
}
struct PoolParams {
string poolTokenSymbol;
string poolTokenName;
address[] constituentTokens;
uint[] tokenBalances;
uint[] tokenWeights;
uint managerFee;
uint redeemFee;
uint issueFee;
uint perfermanceFee;
Etypes etype;
}
struct PoolTokenRange {
uint bspFloor;
uint bspCap;
}
function initRequire(
uint managerFee,
uint issueFee,
uint redeemFee,
uint perfermanceFee,
uint tokenBalancesLength,
uint tokenWeightsLength,
uint constituentTokensLength,
bool initBool
) external pure {
require(!initBool, "Init fail");
require(managerFee >= DesynConstants.MANAGER_MIN_FEE, "ERR_INVALID_MANAGER_FEE");
require(managerFee <= DesynConstants.MANAGER_MAX_FEE, "ERR_INVALID_MANAGER_FEE");
require(issueFee >= DesynConstants.ISSUE_MIN_FEE, "ERR_INVALID_ISSUE_MIN_FEE");
require(issueFee <= DesynConstants.ISSUE_MAX_FEE, "ERR_INVALID_ISSUE_MAX_FEE");
require(redeemFee >= DesynConstants.REDEEM_MIN_FEE, "ERR_INVALID_REDEEM_MIN_FEE");
require(redeemFee <= DesynConstants.REDEEM_MAX_FEE, "ERR_INVALID_REDEEM_MAX_FEE");
require(perfermanceFee >= DesynConstants.PERFERMANCE_MIN_FEE, "ERR_INVALID_PERFERMANCE_MIN_FEE");
require(perfermanceFee <= DesynConstants.PERFERMANCE_MAX_FEE, "ERR_INVALID_PERFERMANCE_MAX_FEE");
require(tokenBalancesLength == constituentTokensLength, "ERR_START_BALANCES_MISMATCH");
require(tokenWeightsLength == constituentTokensLength, "ERR_START_WEIGHTS_MISMATCH");
require(constituentTokensLength >= DesynConstants.MIN_ASSET_LIMIT, "ERR_TOO_FEW_TOKENS");
require(constituentTokensLength <= DesynConstants.MAX_ASSET_LIMIT, "ERR_TOO_MANY_TOKENS");
}
function verifyTokenCompliance(address token) external {
verifyTokenComplianceInternal(token);
}
function verifyTokenCompliance(address[] calldata tokens) external {
for (uint i = 0; i < tokens.length; i++) {
verifyTokenComplianceInternal(tokens[i]);
}
}
function createPoolInternalHandle(IBPool bPool, uint initialSupply) external view {
require(initialSupply >= DesynConstants.MIN_POOL_SUPPLY, "ERR_INIT_SUPPLY_MIN");
require(initialSupply <= DesynConstants.MAX_POOL_SUPPLY, "ERR_INIT_SUPPLY_MAX");
require(bPool.EXIT_FEE() == 0, "ERR_NONZERO_EXIT_FEE");
require(DesynConstants.EXIT_FEE == 0, "ERR_NONZERO_EXIT_FEE");
}
function createPoolHandle(
uint collectPeriod,
uint upperCap,
uint initialSupply
) external pure {
require(collectPeriod <= DesynConstants.MAX_COLLECT_PERIOD, "ERR_EXCEEDS_FUND_RAISING_PERIOD");
require(upperCap >= initialSupply, "ERR_CAP_BIGGER_THAN_INITSUPPLY");
}
function exitPoolHandleA(
IConfigurableRightsPool self,
IBPool bPool,
address poolToken,
uint _tokenAmountOut,
uint redeemFee
)
external
returns (
uint redeemAndPerformanceFeeReceived,
uint finalAmountOut,
uint redeemFeeReceived
)
{
redeemFeeReceived = DesynSafeMath.bmul(_tokenAmountOut, redeemFee);
uint performanceFeeReceived = 0;
redeemAndPerformanceFeeReceived = DesynSafeMath.badd(performanceFeeReceived, redeemFeeReceived);
finalAmountOut = DesynSafeMath.bsub(_tokenAmountOut, redeemAndPerformanceFeeReceived);
_pushUnderlying(bPool, poolToken, msg.sender, finalAmountOut);
if (redeemFee != 0) {
_pushUnderlying(bPool, poolToken, address(this), redeemAndPerformanceFeeReceived);
IERC20(poolToken).safeApprove(self.vaultAddress(), 0);
IERC20(poolToken).safeApprove(self.vaultAddress(), redeemAndPerformanceFeeReceived);
}
}
function exitPoolHandleB(
IConfigurableRightsPool self,
bool bools,
bool isCompletedCollect,
uint closureEndTime,
uint collectEndTime,
uint poolAmountIn
) external view returns (uint actualPoolAmountIn) {
actualPoolAmountIn = poolAmountIn;
if (bools) {
bool isCloseEtfCollectEndWithFailure = isCompletedCollect == false && block.timestamp >= collectEndTime;
bool isCloseEtfClosureEnd = block.timestamp >= closureEndTime;
require(isCloseEtfCollectEndWithFailure || isCloseEtfClosureEnd, "ERR_CLOSURE_TIME_NOT_ARRIVED!");
actualPoolAmountIn = self.balanceOf(msg.sender);
}
}
function joinPoolHandle(
bool canWhitelistLPs,
bool isList,
bool bools,
uint collectEndTime
) external view {
require(!canWhitelistLPs || isList, "ERR_NOT_ON_WHITELIST");
if (bools) {
require(block.timestamp <= collectEndTime, "ERR_COLLECT_PERIOD_FINISHED!");
}
}
function joinPool(
IConfigurableRightsPool self,
IBPool bPool,
uint poolAmountOut,
uint[] calldata maxAmountsIn,
uint issueFee
) external view returns (uint[] memory actualAmountsIn) {
address[] memory tokens = bPool.getCurrentTokens();
require(maxAmountsIn.length == tokens.length, "ERR_AMOUNTS_MISMATCH");
uint poolTotal = self.totalSupply();
uint ratio = DesynSafeMath.bdiv(poolAmountOut, DesynSafeMath.bsub(poolTotal, 1));
require(ratio != 0, "ERR_MATH_APPROX");
actualAmountsIn = new uint[](tokens.length);
uint issueFeeRate = issueFee.bmul(1000);
for (uint i = 0; i < tokens.length; i++) {
address t = tokens[i];
uint bal = bPool.getBalance(t);
uint base = bal.badd(1).bmul(poolAmountOut * uint(1000));
uint tokenAmountIn = base.bdiv(poolTotal.bsub(1) * (uint(1000).bsub(issueFeeRate)));
require(tokenAmountIn != 0, "ERR_MATH_APPROX");
require(tokenAmountIn <= maxAmountsIn[i], "ERR_LIMIT_IN");
actualAmountsIn[i] = tokenAmountIn;
}
}
function exitPool(
IConfigurableRightsPool self,
IBPool bPool,
uint poolAmountIn,
uint[] calldata minAmountsOut
) external view returns (uint[] memory actualAmountsOut) {
address[] memory tokens = bPool.getCurrentTokens();
require(minAmountsOut.length == tokens.length, "ERR_AMOUNTS_MISMATCH");
uint poolTotal = self.totalSupply();
uint ratio = DesynSafeMath.bdiv(poolAmountIn, DesynSafeMath.badd(poolTotal, 1));
require(ratio != 0, "ERR_MATH_APPROX");
actualAmountsOut = new uint[](tokens.length);
for (uint i = 0; i < tokens.length; i++) {
address t = tokens[i];
uint bal = bPool.getBalance(t);
uint tokenAmountOut = DesynSafeMath.bmul(ratio, DesynSafeMath.bsub(bal, 1));
require(tokenAmountOut != 0, "ERR_MATH_APPROX");
require(tokenAmountOut >= minAmountsOut[i], "ERR_LIMIT_OUT");
actualAmountsOut[i] = tokenAmountOut;
}
}
function verifyTokenComplianceInternal(address token) internal {
IERC20(token).safeTransfer(msg.sender, 0);
}
function handleTransferInTokens(
IConfigurableRightsPool self,
IBPool bPool,
address poolToken,
uint actualAmountIn,
uint _actualIssueFee
) external returns (uint issueFeeReceived) {
issueFeeReceived = DesynSafeMath.bmul(actualAmountIn, _actualIssueFee);
uint amount = DesynSafeMath.bsub(actualAmountIn, issueFeeReceived);
_pullUnderlying(bPool, poolToken, msg.sender, amount);
if (_actualIssueFee != 0) {
IERC20(poolToken).safeTransferFrom(msg.sender, address(this), issueFeeReceived);
IERC20(poolToken).safeApprove(self.vaultAddress(), 0);
IERC20(poolToken).safeApprove(self.vaultAddress(), issueFeeReceived);
}
}
function handleClaim(
IConfigurableRightsPool self,
IBPool bPool,
address[] calldata poolTokens,
uint managerFee,
uint timeElapsed,
uint claimPeriod
) external returns (uint[] memory) {
uint[] memory tokensAmount = new uint[](poolTokens.length);
for (uint i = 0; i < poolTokens.length; i++) {
address t = poolTokens[i];
uint tokenBalance = bPool.getBalance(t);
uint tokenAmountOut = tokenBalance.bmul(managerFee).mul(timeElapsed).div(claimPeriod).div(12);
_pushUnderlying(bPool, t, address(this), tokenAmountOut);
IERC20(t).safeApprove(self.vaultAddress(), 0);
IERC20(t).safeApprove(self.vaultAddress(), tokenAmountOut);
tokensAmount[i] = tokenAmountOut;
}
return tokensAmount;
}
function handleFeeClaim(
IConfigurableRightsPool self,
IBPool bPool,
address[] calldata poolTokens,
uint feeRatio,
bool isPerfermance
) external {
if (feeRatio != 0) {
uint[] memory tokensAmount = new uint[](poolTokens.length);
for (uint i = 0; i < poolTokens.length; i++) {
address t = poolTokens[i];
uint currentAmount = bPool.getBalance(t);
uint currentAmountFee = DesynSafeMath.bmul(currentAmount, feeRatio);
_pushUnderlying(bPool, t, address(this), currentAmountFee);
tokensAmount[i] = currentAmountFee;
IERC20(t).safeApprove(self.vaultAddress(), 0);
IERC20(t).safeApprove(self.vaultAddress(), currentAmountFee);
}
if(isPerfermance) {
IVault(self.vaultAddress()).depositIssueRedeemPToken(poolTokens, tokensAmount, new uint[](poolTokens.length), isPerfermance);
} else {
IVault(self.vaultAddress()).depositIssueRedeemPToken(poolTokens, tokensAmount, tokensAmount, isPerfermance);
}
}
}
function WhitelistHandle(
bool bool1,
bool bool2,
address adr
) external pure {
require(bool1, "ERR_CANNOT_WHITELIST_LPS");
require(bool2, "ERR_LP_NOT_WHITELISTED");
require(adr != address(0), "ERR_INVALID_ADDRESS");
}
function _pullUnderlying(
IBPool bPool,
address erc20,
address from,
uint amount
) internal {
uint tokenBalance = bPool.getBalance(erc20);
uint tokenWeight = bPool.getDenormalizedWeight(erc20);
IERC20(erc20).safeTransferFrom(from, address(this), amount);
bPool.rebind(erc20, DesynSafeMath.badd(tokenBalance, amount), tokenWeight);
}
function _pushUnderlying(
IBPool bPool,
address erc20,
address to,
uint amount
) internal {
uint tokenBalance = bPool.getBalance(erc20);
uint tokenWeight = bPool.getDenormalizedWeight(erc20);
bPool.rebind(erc20, DesynSafeMath.bsub(tokenBalance, amount), tokenWeight);
IERC20(erc20).safeTransfer(to, amount);
}
}
文件 16 的 16:WhiteToken.sol
pragma solidity 0.6.12;
contract WhiteToken {
event LOG_WHITELIST(address indexed spender, uint indexed sort, address indexed caller, address token);
event LOG_DEL_WHITELIST(address indexed spender, uint indexed sort, address indexed caller, address token);
uint private _whiteTokenCount;
mapping(address => bool) private _isTokenWhitelisted;
mapping(uint => mapping(address => bool)) private _tokenWhitelistedInfo;
function _queryIsTokenWhitelisted(address token) internal view returns (bool) {
return _isTokenWhitelisted[token];
}
function _isTokenWhitelistedForVerify(uint sort, address token) internal view returns (bool) {
return _tokenWhitelistedInfo[sort][token];
}
function _addTokenToWhitelist(uint sort, address token) internal {
require(token != address(0), "ERR_INVALID_TOKEN_ADDRESS");
require(_queryIsTokenWhitelisted(token) == false, "ERR_HAS_BEEN_ADDED_WHITE");
_tokenWhitelistedInfo[sort][token] = true;
_isTokenWhitelisted[token] = true;
_whiteTokenCount++;
emit LOG_WHITELIST(address(this), sort, msg.sender, token);
}
function _removeTokenFromWhitelist(uint sort, address token) internal {
require(_queryIsTokenWhitelisted(token) == true, "ERR_NOT_WHITE_TOKEN");
require(_tokenWhitelistedInfo[sort][token], "ERR_SORT_NOT_MATCHED");
_tokenWhitelistedInfo[sort][token] = false;
_isTokenWhitelisted[token] = false;
_whiteTokenCount--;
emit LOG_DEL_WHITELIST(address(this), sort, msg.sender, token);
}
function _initWhiteTokenState() internal view returns (bool) {
return _whiteTokenCount == 0 ? false : true;
}
}
{
"compilationTarget": {
"contracts/base/ConfigurableRightsPool.sol": "ConfigurableRightsPool"
},
"evmVersion": "istanbul",
"libraries": {
"DesynSafeMath": "0xe91c89d7cc74b49579ac3a5ba68974bda8c3f547",
"RightsManager": "0x495e73a680cd943020f18911e50c1fe5991cb770",
"SmartPoolManager": "0xce720c194b9fd6b196259807d579bbd2f53e39d8"
},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 20
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"string","name":"tokenName","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AddAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"sort","type":"uint256"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"LOG_DEL_WHITELIST","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"sort","type":"uint256"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"LOG_WHITELIST","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"internalType":"bytes4","name":"sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"LogCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"LogExit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"name":"LogJoin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"initToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"initTokenTotal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"initShare","type":"uint256"}],"name":"PoolTokenInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RemoveAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"managerFee","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"issueFee","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"redeemFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"perfermanceFee","type":"uint256"}],"name":"SetManagerFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"string","name":"sizeType","type":"string"},{"indexed":false,"internalType":"uint256","name":"oldSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSize","type":"uint256"}],"name":"SizeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"CLAIM_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"_verifyWhiteToken","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"sort","type":"uint256[]"},{"internalType":"address[]","name":"token","type":"address[]"}],"name":"addTokenToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"adminList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allOwnerPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bFactory","outputs":[{"internalType":"contract IBFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bPool","outputs":[{"internalType":"contract IBPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beginFundAssets","outputs":[{"components":[{"internalType":"uint256","name":"etfAmount","type":"uint256"},{"internalType":"uint256","name":"fundAmount","type":"uint256"},{"internalType":"uint256","name":"snapshotTime","type":"uint256"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"tokensAmount","type":"uint256[]"}],"internalType":"struct SmartPoolManager.Fund","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnPoolShareFromLib","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"}],"name":"canProvideLiquidity","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimManagerFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"couldClaimManagerFee","outputs":[{"internalType":"bool","name":"state","type":"bool"},{"internalType":"uint256","name":"timePoint","type":"uint256"},{"internalType":"uint256","name":"timeElapsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"collectPeriod","type":"uint256"},{"internalType":"enum SmartPoolManager.Period","name":"closurePeriod","type":"uint8"},{"components":[{"internalType":"uint256","name":"bspFloor","type":"uint256"},{"internalType":"uint256","name":"bspCap","type":"uint256"}],"internalType":"struct SmartPoolManager.PoolTokenRange","name":"tokenRange","type":"tuple"}],"name":"createPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"decreaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endFundAssets","outputs":[{"components":[{"internalType":"uint256","name":"etfAmount","type":"uint256"},{"internalType":"uint256","name":"fundAmount","type":"uint256"},{"internalType":"uint256","name":"snapshotTime","type":"uint256"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"tokensAmount","type":"uint256[]"}],"internalType":"struct SmartPoolManager.Fund","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"etfStatus","outputs":[{"internalType":"uint256","name":"collectPeriod","type":"uint256"},{"internalType":"uint256","name":"collectEndTime","type":"uint256"},{"internalType":"uint256","name":"closurePeriod","type":"uint256"},{"internalType":"uint256","name":"closureEndTime","type":"uint256"},{"internalType":"uint256","name":"upperCap","type":"uint256"},{"internalType":"uint256","name":"floorCap","type":"uint256"},{"internalType":"uint256","name":"managerFee","type":"uint256"},{"internalType":"uint256","name":"redeemFee","type":"uint256"},{"internalType":"uint256","name":"issueFee","type":"uint256"},{"internalType":"uint256","name":"perfermanceFee","type":"uint256"},{"internalType":"uint256","name":"startClaimFeeTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"etype","outputs":[{"internalType":"enum SmartPoolManager.Etypes","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bool","name":"isUnderlying","type":"bool"}],"name":"execute","outputs":[{"internalType":"bytes","name":"_returnValue","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"},{"internalType":"address","name":"user","type":"address"}],"name":"exitPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDesynSafeMathVersion","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getOwnerPercentage","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRightsManagerVersion","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getSmartPoolManagerVersion","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"hasClaimManageFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum RightsManager.Permissions","name":"permission","type":"uint8"}],"name":"hasPermission","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasSetBeginFund","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasSetEndFund","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"factoryAddress","type":"address"},{"components":[{"internalType":"string","name":"poolTokenSymbol","type":"string"},{"internalType":"string","name":"poolTokenName","type":"string"},{"internalType":"address[]","name":"constituentTokens","type":"address[]"},{"internalType":"uint256[]","name":"tokenBalances","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenWeights","type":"uint256[]"},{"internalType":"uint256","name":"managerFee","type":"uint256"},{"internalType":"uint256","name":"redeemFee","type":"uint256"},{"internalType":"uint256","name":"issueFee","type":"uint256"},{"internalType":"uint256","name":"perfermanceFee","type":"uint256"},{"internalType":"enum SmartPoolManager.Etypes","name":"etype","type":"uint8"}],"internalType":"struct SmartPoolManager.PoolParams","name":"poolParams","type":"tuple"},{"components":[{"internalType":"bool","name":"canWhitelistLPs","type":"bool"},{"internalType":"bool","name":"canTokenWhiteLists","type":"bool"}],"internalType":"struct RightsManager.Rights","name":"rightsStruct","type":"tuple"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_owners","type":"address[]"},{"internalType":"uint256[]","name":"_ownerPercentage","type":"uint256[]"}],"name":"initHandle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCompletedCollect","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"},{"internalType":"address","name":"kol","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"joinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintPoolShareFromLib","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"pullPoolShareFromLib","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"pushPoolShareFromLib","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"}],"name":"removeWhitelistedLiquidityProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rights","outputs":[{"internalType":"bool","name":"canWhitelistLPs","type":"bool"},{"internalType":"bool","name":"canTokenWhiteLists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_owners","type":"address[]"},{"internalType":"uint256[]","name":"_ownerPercentage","type":"uint256[]"}],"name":"setManagersInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"snapshotAssets","outputs":[{"components":[{"internalType":"uint256","name":"etfAmount","type":"uint256"},{"internalType":"uint256","name":"fundAmount","type":"uint256"},{"internalType":"uint256","name":"snapshotTime","type":"uint256"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"tokensAmount","type":"uint256[]"}],"internalType":"struct SmartPoolManager.Fund","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"snapshotBeginAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"snapshotEndAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"}],"name":"whitelistLiquidityProvider","outputs":[],"stateMutability":"nonpayable","type":"function"}]