creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/base/ConfigurableRightsPool.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n// Needed to handle structures externally\npragma experimental ABIEncoderV2;\n\nimport \"./PCToken.sol\";\nimport \"../utils/DesynReentrancyGuard.sol\";\nimport \"../utils/DesynOwnable.sol\";\nimport \"../interfaces/IBFactory.sol\";\nimport {RightsManager} from \"../libraries/RightsManager.sol\";\nimport \"../libraries/SmartPoolManager.sol\";\nimport \"../libraries/SafeApprove.sol\";\nimport \"./WhiteToken.sol\";\nimport \"../libraries/SafeERC20.sol\";\nimport '../libraries/Address.sol';\n\n/**\n * @author Desyn Labs\n * @title Smart Pool with customizable features\n * @notice PCToken is the \"Desyn Smart Pool\" token (transferred upon finalization)\n * @dev Rights are defined as follows (index values into the array)\n * Note that functions called on bPool and bFactory may look like internal calls,\n *   but since they are contracts accessed through an interface, they are really external.\n * To make this explicit, we could write \"IBPool(address(bPool)).function()\" everywhere,\n *   instead of \"bPool.function()\".\n */\ncontract ConfigurableRightsPool is PCToken, DesynOwnable, DesynReentrancyGuard, WhiteToken {\n    using DesynSafeMath for uint;\n    using SafeERC20 for IERC20;\n    using Address for address;\n\n    // State variables\n    IBFactory public bFactory;\n    IBPool public bPool;\n\n    // Struct holding the rights configuration\n    RightsManager.Rights public rights;\n\n    SmartPoolManager.Status public etfStatus;\n    SmartPoolManager.Fund beginFund;\n    SmartPoolManager.Fund endFund;\n\n    // Store the list of tokens in the pool, and balances\n    // NOTE that the token list is *only* used to store the pool tokens between\n    //   construction and createPool - thereafter, use the underlying BPool's list\n    //   (avoids synchronization issues)\n    address[] private _initialTokens;\n    uint[] private _initialBalances;\n    uint[] private _initialWeights;\n\n    // Whitelist of LPs (if configured)\n    mapping(address => bool) private _liquidityProviderWhitelist;\n\n    uint public constant CLAIM_PERIOD = 30 days;\n    address public vaultAddress;\n\n    bool hasSetWhiteTokens;\n    bool initBool;\n    bool public isCompletedCollect;\n    bool public hasSetBeginFund;\n    bool public hasSetEndFund;\n    bool public hasClaimManageFee;\n\n    SmartPoolManager.Etypes public etype;\n\n    // Event declarations\n    // Anonymous logger event - can only be filtered by contract address\n    event LogCall(bytes4 indexed sig, address indexed caller, bytes data) anonymous;\n    event LogJoin(address indexed caller, address indexed tokenIn, uint tokenAmountIn);\n    event LogExit(address indexed caller, address indexed tokenOut, uint tokenAmountOut);\n    event SizeChanged(address indexed caller, string indexed sizeType, uint oldSize, uint newSize);\n    event PoolTokenInit(address indexed caller, address pool, address initToken, uint initTokenTotal, uint initShare);\n    event SetManagerFee(uint indexed managerFee, uint indexed issueFee, uint indexed redeemFee, uint perfermanceFee);\n\n    // Modifiers\n    modifier logs() {\n        emit LogCall(msg.sig, msg.sender, msg.data);\n        _;\n    }\n\n    // Mark functions that require delegation to the underlying Pool\n    modifier needsBPool() {\n        require(address(bPool) != address(0), \"ERR_NOT_CREATED\");\n        _;\n    }\n\n    modifier notPaused() {\n        require(!bFactory.isPaused(), \"!paused\");\n        _;\n    }\n \n    constructor(string memory tokenSymbol, string memory tokenName) public PCToken(tokenSymbol, tokenName) {}\n\n    /**\n     * @notice Construct a new Configurable Rights Pool (wrapper around BPool)\n     * @dev _initialTokens are only used for temporary storage between construction\n     *      and create pool, and should not be used thereafter! _initialTokens is destroyed in\n     *      createPool to prevent this is kept in sync (defensively), but\n     *      should never be used except in this constructor and createPool()\n     * @param factoryAddress - the BPoolFactory used to create the underlying pool\n     * @param poolParams - struct containing pool parameters\n     * @param rightsStruct - Set of permissions we are assigning to this smart pool\n     */\n\n    function init(\n        address factoryAddress,\n        SmartPoolManager.PoolParams memory poolParams,\n        RightsManager.Rights memory rightsStruct\n    ) public {\n        SmartPoolManager.initRequire(\n            poolParams.managerFee,\n            poolParams.issueFee,\n            poolParams.redeemFee,\n            poolParams.perfermanceFee,\n            poolParams.tokenBalances.length,\n            poolParams.tokenWeights.length,\n            poolParams.constituentTokens.length,\n            initBool\n        );\n        initBool = true;\n        rights = rightsStruct;\n        _initialTokens = poolParams.constituentTokens;\n        _initialBalances = poolParams.tokenBalances;\n        _initialWeights = poolParams.tokenWeights;\n\n        etfStatus = SmartPoolManager.Status({\n            collectPeriod: 0,\n            collectEndTime: 0,\n            closurePeriod: 0,\n            closureEndTime: 0,\n            upperCap: DesynConstants.MAX_UINT,\n            floorCap: 0,\n            managerFee: poolParams.managerFee,\n            redeemFee: poolParams.redeemFee,\n            issueFee: poolParams.issueFee,\n            perfermanceFee: poolParams.perfermanceFee,\n            startClaimFeeTime: block.timestamp\n        });\n\n        etype = poolParams.etype;\n\n        bFactory = IBFactory(factoryAddress);\n        vaultAddress = bFactory.getVault();\n        emit SetManagerFee(etfStatus.managerFee, etfStatus.issueFee, etfStatus.redeemFee, etfStatus.perfermanceFee);\n    }\n\n    /**\n     * @notice Set the cap (max # of pool tokens)\n     * @dev _bspCap defaults in the constructor to unlimited\n     *      Can set to 0 (or anywhere below the current supply), to halt new investment\n     *      Prevent setting it before creating a pool, since createPool sets to intialSupply\n     *      (it does this to avoid an unlimited cap window between construction and createPool)\n     *      Therefore setting it before then has no effect, so should not be allowed\n     * @param newCap - new value of the cap\n     */\n    function setCap(uint newCap) external logs lock needsBPool onlyOwner {\n        require(etype == SmartPoolManager.Etypes.OPENED, \"ERR_MUST_OPEN_ETF\");\n        emit SizeChanged(msg.sender, \"UPPER\", etfStatus.upperCap, newCap);\n        etfStatus.upperCap = newCap;\n    }\n\n    function execute(\n        address _target,\n        uint _value,\n        bytes calldata _data,\n        bool isUnderlying\n    ) external logs lock needsBPool returns (bytes memory _returnValue) {\n        require(bFactory.getModuleStatus(address(this), msg.sender), 'MODULE IS NOT REGISTER');\n        if (isUnderlying) {\n        _returnValue = bPool.execute(_target, _value, _data);\n        } else {\n        _returnValue = _target.functionCallWithValue(_data, _value);\n        }\n    }\n\n    function couldClaimManagerFee() public view returns(bool state,uint timePoint ,uint timeElapsed){\n        bool isCloseETF = etype == SmartPoolManager.Etypes.CLOSED;\n        timePoint = block.timestamp;\n        if(isCloseETF && timePoint > etfStatus.closureEndTime) timePoint = etfStatus.closureEndTime;\n        timeElapsed = DesynSafeMath.bsub(timePoint, etfStatus.startClaimFeeTime);\n        if(timeElapsed >= CLAIM_PERIOD) state = true;\n        if(isCloseETF && !isCompletedCollect) state = false;\n    }\n\n    function claimManagerFee() public virtual logs lock onlyAdmin needsBPool {\n        _claimManagerFee();\n    }\n\n    function _claimManagerFee() internal {\n        (bool state, uint timePoint ,uint timeElapsed) = couldClaimManagerFee();\n        if(state){\n            address[] memory poolTokens = bPool.getCurrentTokens();\n            uint[] memory tokensAmount = SmartPoolManager.handleClaim(\n                IConfigurableRightsPool(address(this)),\n                bPool,\n                poolTokens,\n                etfStatus.managerFee,\n                timeElapsed,\n                CLAIM_PERIOD\n            );\n            IVault(vaultAddress).depositManagerToken(poolTokens, tokensAmount);\n            etfStatus.startClaimFeeTime = timePoint;\n        }\n    }\n\n    /**\n     * @notice Create a new Smart Pool\n     * @dev Delegates to internal function\n     * @param initialSupply starting token balance\n     * @param closurePeriod the etf closure period\n     */\n    function createPool(\n        address creator,\n        uint initialSupply,\n        uint collectPeriod,\n        SmartPoolManager.Period closurePeriod,\n        SmartPoolManager.PoolTokenRange memory tokenRange\n    ) external virtual onlyOwner logs lock notPaused {\n        if (etype == SmartPoolManager.Etypes.CLOSED) {\n            SmartPoolManager.createPoolHandle(collectPeriod, etfStatus.upperCap, initialSupply);\n\n            uint oldCap = etfStatus.upperCap;\n            uint oldFloor = etfStatus.floorCap;\n            etfStatus.upperCap = initialSupply.bmul(tokenRange.bspCap).bdiv(_initialBalances[0]);\n            etfStatus.floorCap = initialSupply.bmul(tokenRange.bspFloor).bdiv(_initialBalances[0]);\n            emit PoolTokenInit(creator, address(this),_initialTokens[0], _initialBalances[0], initialSupply);\n            emit SizeChanged(creator, \"UPPER\", oldCap, etfStatus.upperCap);\n            emit SizeChanged(creator, \"FLOOR\", oldFloor, etfStatus.floorCap);\n\n            uint period;\n            uint collectEndTime = block.timestamp + collectPeriod;\n            if (closurePeriod == SmartPoolManager.Period.DAY90) {\n                period = 90 days;\n            } else if (closurePeriod == SmartPoolManager.Period.DAY1) {\n                period = 1 days;\n            } else if (closurePeriod == SmartPoolManager.Period.DAY3) {\n                period = 3 days;\n            } else if (closurePeriod == SmartPoolManager.Period.DAY7) {\n                period = 7 days;\n            } else if (closurePeriod == SmartPoolManager.Period.DAY14) {\n                period = 14 days;\n            } else if (closurePeriod == SmartPoolManager.Period.DAY30) {\n                period = 30 days;\n            } else if (closurePeriod == SmartPoolManager.Period.DAY180) {\n                period = 180 days;\n            } else {\n                period = 360 days;\n            }\n            uint closureEndTime = collectEndTime + period;\n\n            etfStatus.collectPeriod = collectPeriod;\n            etfStatus.collectEndTime = collectEndTime;\n            etfStatus.closurePeriod = period;\n            etfStatus.closureEndTime = closureEndTime;\n\n            IUserVault(bFactory.getUserVault()).recordTokenInfo(creator, creator, _initialTokens, _initialBalances);\n        }\n\n        createPoolInternal(initialSupply);\n    }\n\n    /**\n     * @notice Join a pool\n     * @dev Emits a LogJoin event (for each token)\n     *      bPool is a contract interface; function calls on it are external\n     * @param poolAmountOut - number of pool tokens to receive\n     * @param maxAmountsIn - Max amount of asset tokens to spend\n     */\n    function joinPool(\n        uint poolAmountOut,\n        uint[] calldata maxAmountsIn,\n        address kol,\n        address user\n    ) external logs lock needsBPool notPaused {\n        SmartPoolManager.joinPoolHandle(rights.canWhitelistLPs, canProvideLiquidity(user), etype == SmartPoolManager.Etypes.CLOSED, etfStatus.collectEndTime);\n        \n        if(rights.canTokenWhiteLists) {\n            require(_initWhiteTokenState(),\"ERR_SHOULD_SET_WHITETOKEN\");\n        }\n        // Delegate to library to save space\n\n        // Library computes actualAmountsIn, and does many validations\n        // Cannot call the push/pull/min from an external library for\n        // any of these pool functions. Since msg.sender can be anybody,\n        // they must be internal\n        uint[] memory actualAmountsIn = SmartPoolManager.joinPool(IConfigurableRightsPool(address(this)), bPool, poolAmountOut, maxAmountsIn, etfStatus.issueFee);\n\n        // After createPool, token list is maintained in the underlying BPool\n        address[] memory poolTokens = bPool.getCurrentTokens();\n        uint[] memory issueFeesReceived = new uint[](poolTokens.length);\n\n        uint _actualIssueFee = etfStatus.issueFee;\n        if (etype == SmartPoolManager.Etypes.CLOSED) {\n            IUserVault(bFactory.getUserVault()).recordTokenInfo(kol, user, poolTokens, actualAmountsIn);\n            if (!isCompletedCollect) {\n                _actualIssueFee = 0;\n            }\n        }\n\n        for (uint i = 0; i < poolTokens.length; i++) {\n            uint issueFeeReceived = SmartPoolManager.handleTransferInTokens(\n                IConfigurableRightsPool(address(this)),\n                bPool,\n                poolTokens[i],\n                actualAmountsIn[i],\n                _actualIssueFee\n            );\n\n            emit LogJoin(user, poolTokens[i], actualAmountsIn[i]);\n            issueFeesReceived[i] = issueFeeReceived;\n        }\n\n        if (_actualIssueFee != 0) {\n            IVault(vaultAddress).depositIssueRedeemPToken(poolTokens, issueFeesReceived, issueFeesReceived, false);\n        }\n        _mintPoolShare(poolAmountOut);\n        _pushPoolShare(user, poolAmountOut);\n\n        // checkout the state that elose ETF collect completed and claime fee.\n        bool isCompletedMoment = etype == SmartPoolManager.Etypes.CLOSED && varTotalSupply >= etfStatus.floorCap && !isCompletedCollect;\n        if (isCompletedMoment) {\n            isCompletedCollect = true;\n            SmartPoolManager.handleFeeClaim(\n                IConfigurableRightsPool(address(this)), bPool,\n                poolTokens,\n                etfStatus.issueFee,\n                false\n            );\n        }\n    }\n\n    /**\n     * @notice Exit a pool - redeem pool tokens for underlying assets\n     * @dev Emits a LogExit event for each token\n     *      bPool is a contract interface; function calls on it are external\n     * @param poolAmountIn - amount of pool tokens to redeem\n     * @param minAmountsOut - minimum amount of asset tokens to receive\n     */\n    function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut, address user) external logs lock needsBPool notPaused {\n        uint actualPoolAmountIn;\n        bool isCloseEtfCollectEndWithFailure;\n\n        uint _actualRedeemFee = etfStatus.redeemFee;\n        if(etype == SmartPoolManager.Etypes.CLOSED){\n            isCloseEtfCollectEndWithFailure = !isCompletedCollect && block.timestamp >= etfStatus.collectEndTime;\n            if(!isCloseEtfCollectEndWithFailure){\n                if(!hasClaimManageFee) {\n                    _claimManagerFee();\n                    hasClaimManageFee = true;\n                }\n                if(hasSetBeginFund && !hasSetEndFund) snapshotEndAssets();\n            }\n            if(isCloseEtfCollectEndWithFailure) _actualRedeemFee = 0;\n        }\n\n        actualPoolAmountIn = SmartPoolManager.exitPoolHandleB(\n            IConfigurableRightsPool(address(this)),\n            etype == SmartPoolManager.Etypes.CLOSED,\n            isCompletedCollect,\n            etfStatus.closureEndTime,\n            etfStatus.collectEndTime,\n            poolAmountIn\n        );\n        // Library computes actualAmountsOut, and does many validations\n        uint[] memory actualAmountsOut = SmartPoolManager.exitPool(IConfigurableRightsPool(address(this)), bPool, actualPoolAmountIn, minAmountsOut);\n        _pullPoolShare(msg.sender, actualPoolAmountIn);\n        _burnPoolShare(actualPoolAmountIn);\n\n        // After createPool, token list is maintained in the underlying BPool\n        address[] memory poolTokens = bPool.getCurrentTokens();\n\n        uint[] memory redeemFeesReceived = new uint[](poolTokens.length);\n        for (uint i = 0; i < poolTokens.length; i++) {\n            (, uint finalAmountOut, uint redeemFeeReceived) = SmartPoolManager.exitPoolHandleA(\n                IConfigurableRightsPool(address(this)),\n                bPool,\n                poolTokens[i],\n                actualAmountsOut[i],\n                _actualRedeemFee\n            );\n            redeemFeesReceived[i] = redeemFeeReceived;\n\n            emit LogExit(user, poolTokens[i], finalAmountOut);\n        }\n\n        if (_actualRedeemFee != 0) {\n            IVault(vaultAddress).depositIssueRedeemPToken(poolTokens, redeemFeesReceived, redeemFeesReceived, true);\n        }\n    }\n\n    /**\n     * @notice Add to the whitelist of liquidity providers (if enabled)\n     * @param provider - address of the liquidity provider\n     */\n    function whitelistLiquidityProvider(address provider) external onlyOwner lock logs {\n        SmartPoolManager.WhitelistHandle(rights.canWhitelistLPs, true, provider);\n        _liquidityProviderWhitelist[provider] = true;\n    }\n\n    /**\n     * @notice Remove from the whitelist of liquidity providers (if enabled)\n     * @param provider - address of the liquidity provider\n     */\n    function removeWhitelistedLiquidityProvider(address provider) external onlyOwner lock logs {\n        SmartPoolManager.WhitelistHandle(rights.canWhitelistLPs, _liquidityProviderWhitelist[provider], provider);\n        _liquidityProviderWhitelist[provider] = false;\n    }\n\n    /**\n     * @notice Check if an address is a liquidity provider\n     * @dev If the whitelist feature is not enabled, anyone can provide liquidity (assuming finalized)\n     * @return boolean value indicating whether the address can join a pool\n     */\n    function canProvideLiquidity(address provider) public view returns (bool) {\n        if (rights.canWhitelistLPs) {\n            return _liquidityProviderWhitelist[provider] || provider == getController() ;\n        } else {\n            // Probably don't strictly need this (could just return true)\n            // But the null address can't provide funds\n            return provider != address(0);\n        }\n    }\n\n    /**\n     * @notice Getter for specific permissions\n     * @dev value of the enum is just the 0-based index in the enumeration\n     * @return token boolean true if we have the given permission\n     */\n    function hasPermission(RightsManager.Permissions permission) external view virtual returns (bool) {\n        return RightsManager.hasPermission(rights, permission);\n    }\n\n    /**\n     * @notice Getter for the RightsManager contract\n     * @dev Convenience function to get the address of the RightsManager library (so clients can check version)\n     * @return address of the RightsManager library\n     */\n    function getRightsManagerVersion() external pure returns (address) {\n        return address(RightsManager);\n    }\n\n    /**\n     * @notice Getter for the DesynSafeMath contract\n     * @dev Convenience function to get the address of the DesynSafeMath library (so clients can check version)\n     * @return address of the DesynSafeMath library\n     */\n    function getDesynSafeMathVersion() external pure returns (address) {\n        return address(DesynSafeMath);\n    }\n\n    /**\n     * @notice Getter for the SmartPoolManager contract\n     * @dev Convenience function to get the address of the SmartPoolManager library (so clients can check version)\n     * @return address of the SmartPoolManager library\n     */\n    function getSmartPoolManagerVersion() external pure returns (address) {\n        return address(SmartPoolManager);\n    }\n\n    // \"Public\" versions that can safely be called from SmartPoolManager\n    // Allows only the contract itself to call them (not the controller or any external account)\n\n    function mintPoolShareFromLib(uint amount) public {\n        require(msg.sender == address(this), \"ERR_NOT_CONTROLLER\");\n\n        _mint(amount);\n    }\n\n    function pushPoolShareFromLib(address to, uint amount) public {\n        require(msg.sender == address(this), \"ERR_NOT_CONTROLLER\");\n\n        _push(to, amount);\n    }\n\n    function pullPoolShareFromLib(address from, uint amount) public {\n        require(msg.sender == address(this), \"ERR_NOT_CONTROLLER\");\n\n        _pull(from, amount);\n    }\n\n    function burnPoolShareFromLib(uint amount) public {\n        require(msg.sender == address(this), \"ERR_NOT_CONTROLLER\");\n\n        _burn(amount);\n    }\n\n    /**\n     * @notice Create a new Smart Pool\n     * @dev Initialize the swap fee to the value provided in the CRP constructor\n     * @param initialSupply starting token balance\n     */\n    function createPoolInternal(uint initialSupply) internal {\n        require(address(bPool) == address(0), \"ERR_IS_CREATED\");\n\n        // To the extent possible, modify state variables before calling functions\n        _mintPoolShare(initialSupply);\n        _pushPoolShare(msg.sender, initialSupply);\n\n        // Deploy new BPool (bFactory and bPool are interfaces; all calls are external)\n        bPool = bFactory.newLiquidityPool();\n        // EXIT_FEE must always be zero, or ConfigurableRightsPool._pushUnderlying will fail\n        SmartPoolManager.createPoolInternalHandle(bPool, initialSupply);\n        for (uint i = 0; i < _initialTokens.length; i++) {\n            address t = _initialTokens[i];\n            uint bal = _initialBalances[i];\n            uint denorm = _initialWeights[i];\n\n            _verifyWhiteToken(t);\n            IERC20(t).safeTransferFrom(msg.sender, address(this), bal);\n            IERC20(t).safeApprove(address(bPool), 0);\n            IERC20(t).safeApprove(address(bPool), DesynConstants.MAX_UINT);\n\n            bPool.bind(t, bal, denorm);\n        }\n\n        while (_initialTokens.length > 0) {\n            // Modifying state variable after external calls here,\n            // but not essential, so not dangerous\n            _initialTokens.pop();\n        }\n    }\n\n    function addTokenToWhitelist(uint[] memory sort, address[] memory token) external onlyOwner {\n        require(rights.canTokenWhiteLists && !hasSetWhiteTokens, \"ERR_NO_RIGHTS\");\n        require(sort.length == token.length, \"ERR_SORT_TOKEN_MISMATCH\");\n        for (uint i = 0; i < token.length; i++) {\n            bool inRange = bFactory.isTokenWhitelistedForVerify(sort[i], token[i]);\n            require(inRange, \"TOKEN_MUST_IN_WHITE_LISTS\");\n            _addTokenToWhitelist(sort[i], token[i]);\n        }\n        hasSetWhiteTokens = true;\n    }\n\n    function _verifyWhiteToken(address token) public view {\n        require(bFactory.isTokenWhitelistedForVerify(token), \"ERR_NOT_WHITE_TOKEN\");\n\n        if (hasSetWhiteTokens) {\n            require(_queryIsTokenWhitelisted(token), \"ERR_NOT_WHITE_TOKEN\");\n        }\n    }\n\n    // Rebind BPool and pull tokens from address\n    // bPool is a contract interface; function calls on it are external\n    function _pullUnderlying(\n        address erc20,\n        address from,\n        uint amount\n    ) internal needsBPool {\n        // Gets current Balance of token i, Bi, and weight of token i, Wi, from BPool.\n        uint tokenBalance = bPool.getBalance(erc20);\n        uint tokenWeight = bPool.getDenormalizedWeight(erc20);\n\n        IERC20(erc20).safeTransferFrom(from, address(this), amount);\n        bPool.rebind(erc20, DesynSafeMath.badd(tokenBalance, amount), tokenWeight);\n    }\n\n    // Rebind BPool and push tokens to address\n    // bPool is a contract interface; function calls on it are external\n    function _pushUnderlying(\n        address erc20,\n        address to,\n        uint amount\n    ) internal needsBPool {\n        // Gets current Balance of token i, Bi, and weight of token i, Wi, from BPool.\n        uint tokenBalance = bPool.getBalance(erc20);\n        uint tokenWeight = bPool.getDenormalizedWeight(erc20);\n        bPool.rebind(erc20, DesynSafeMath.bsub(tokenBalance, amount), tokenWeight);\n\n        IERC20(erc20).safeTransfer(to, amount);\n    }\n\n    // Wrappers around corresponding core functions\n\n    function _mint(uint amount) internal override {\n        super._mint(amount);\n        require(varTotalSupply <= etfStatus.upperCap, \"ERR_CAP_LIMIT_REACHED\");\n    }\n\n    function _mintPoolShare(uint amount) internal {\n        _mint(amount);\n    }\n\n    function _pushPoolShare(address to, uint amount) internal {\n        _push(to, amount);\n    }\n\n    function _pullPoolShare(address from, uint amount) internal {\n        _pull(from, amount);\n    }\n\n    function _burnPoolShare(uint amount) internal {\n        _burn(amount);\n    }\n\n    // ================ SnapshotAssets ================\n\n    function snapshotBeginAssets() external logs {\n        uint nowTime = block.timestamp;\n        require(!hasSetBeginFund && isCompletedCollect && etype == SmartPoolManager.Etypes.CLOSED && nowTime <= (etfStatus.collectEndTime + 3 days) , \"ERR_CONDITIONS_NOT_MET\");\n\n        bool inT1 = nowTime <= (etfStatus.collectEndTime + 1 days);\n        if(inT1) require(adminList[msg.sender] || msg.sender == _owner, \"onlyAdmin\");\n\n        beginFund = snapshotAssets();\n        hasSetBeginFund = true;\n\n        if(nowTime < etfStatus.collectEndTime) etfStatus.collectEndTime = block.timestamp;\n    }\n\n    function beginFundAssets() external view returns(SmartPoolManager.Fund memory){\n        return beginFund;\n    }\n\n    function endFundAssets() external view returns(SmartPoolManager.Fund memory){\n        return endFund;\n    }\n\n    function snapshotEndAssets() public logs {\n        uint nowTime = block.timestamp;\n        require(!hasSetEndFund && hasSetBeginFund && etype == SmartPoolManager.Etypes.CLOSED && nowTime >= etfStatus.closureEndTime, \"ERR_CONDITIONS_NOT_MET\");\n\n        bool inT1 = (etfStatus.closureEndTime + 1 days) >= nowTime;\n        if(inT1) require(adminList[msg.sender] || msg.sender == _owner, \"onlyAdmin\");\n\n        endFund = snapshotAssets();\n\n        uint preShareValueEnd = endFund.fundAmount.bdiv(endFund.etfAmount);\n        uint preShareValueBegin = beginFund.fundAmount.bdiv(beginFund.etfAmount);\n      \n        if(preShareValueEnd > preShareValueBegin){\n            uint perfermanceRatio = etfStatus.perfermanceFee.bmul(preShareValueEnd-preShareValueBegin).bdiv(preShareValueEnd);\n            // claim perfomance reward \n            SmartPoolManager.handleFeeClaim(\n                    IConfigurableRightsPool(address(this)), bPool,\n                    bPool.getCurrentTokens(),\n                    perfermanceRatio,\n                    true);\n        }\n\n        hasSetEndFund = true;\n    }\n\n    function snapshotAssets() public returns(SmartPoolManager.Fund memory){\n        SmartPoolManager.Fund memory tempFund;\n        tempFund.etfAmount = varTotalSupply;\n\n        (tempFund.tokens, tempFund.tokensAmount) = _getPoolTokensInfo();\n        tempFund.fundAmount = Oracles(bFactory.getOracleAddress()).getAllPrice(tempFund.tokens, tempFund.tokensAmount);\n        tempFund.snapshotTime = block.timestamp;\n        return tempFund;\n    }\n\n    function _getPoolTokensInfo() internal view returns (address[] memory, uint[] memory) {\n        address[] memory tokens = bPool.getCurrentTokens();\n        uint[] memory totalBalances = new uint[](tokens.length);\n        for(uint i; i < tokens.length ;i++) {\n            totalBalances[i] = bPool.getBalance(tokens[i]);\n        }\n        return (tokens,totalBalances);\n    }\n}"
      },
      "contracts/utils/DesynReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n/**\n * @author Desyn Labs (and OpenZeppelin)\n * @title Protect against reentrant calls (and also selectively protect view functions)\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {_lock_} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `_lock_` guard, functions marked as\n * `_lock_` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `_lock_` entry\n * points to them.\n *\n * Also adds a _lockview_ modifier, which doesn't create a lock, but fails\n *   if another _lock_ call is in progress\n */\ncontract DesynReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint private constant _NOT_ENTERED = 1;\n    uint private constant _ENTERED = 2;\n\n    uint private _status;\n\n    constructor() internal {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `_lock_` function from another `_lock_`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `_lock_` function external, and make it call a\n     * `private` function that does the actual work.\n     */\n    modifier lock() {\n        // On the first call to _lock_, _notEntered will be true\n        require(_status != _ENTERED, \"ERR_REENTRY\");\n\n        // Any calls to _lock_ after this point will fail\n        _status = _ENTERED;\n        _;\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Also add a modifier that doesn't create a lock, but protects functions that\n     *      should not be called while a _lock_ function is running\n     */\n    modifier viewlock() {\n        require(_status != _ENTERED, \"ERR_REENTRY_VIEW\");\n        _;\n    }\n}\n"
      },
      "contracts/interfaces/IBFactory.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\ninterface IBPool {\n    function rebind(\n        address token,\n        uint balance,\n        uint denorm\n    ) external;\n\n    function execute(\n        address _target,\n        uint _value,\n        bytes calldata _data\n    ) external returns (bytes memory _returnValue);\n\n    function bind(\n        address token,\n        uint balance,\n        uint denorm\n    ) external;\n\n    function unbind(address token) external;\n\n    function unbindPure(address token) external;\n\n    function isBound(address token) external view returns (bool);\n\n    function getBalance(address token) external view returns (uint);\n\n    function totalSupply() external view returns (uint);\n\n    function isPublicSwap() external view returns (bool);\n\n    function getDenormalizedWeight(address token) external view returns (uint);\n\n    function getTotalDenormalizedWeight() external view returns (uint);\n\n    function EXIT_FEE() external view returns (uint);\n\n    function getCurrentTokens() external view returns (address[] memory tokens);\n\n    function setController(address owner) external;\n}\n\ninterface IBFactory {\n    function newLiquidityPool() external returns (IBPool);\n\n    function setBLabs(address b) external;\n\n    function collect(IBPool pool) external;\n\n    function isBPool(address b) external view returns (bool);\n\n    function getBLabs() external view returns (address);\n\n    function getVault() external view returns (address);\n\n    function getUserVault() external view returns (address);\n\n    function getVaultAddress() external view returns (address);\n\n    function getOracleAddress() external view returns (address);\n\n    function isTokenWhitelistedForVerify(uint sort, address token) external view returns (bool);\n\n    function isTokenWhitelistedForVerify(address token) external view returns (bool);\n\n    function getModuleStatus(address etf, address module) external view returns (bool);\n\n    function isPaused() external view returns (bool);\n}\n\ninterface IVault {\n    function depositManagerToken(address[] calldata poolTokens, uint[] calldata tokensAmount) external;\n\n    function depositIssueRedeemPToken(\n        address[] calldata poolTokens,\n        uint[] calldata tokensAmount,\n        uint[] calldata tokensAmountP,\n        bool isPerfermance\n    ) external;\n\n    function managerClaim(address pool) external;\n\n    function getManagerClaimBool(address pool) external view returns (bool);\n}\n\ninterface IUserVault {\n    function recordTokenInfo(\n        address kol,\n        address user,\n        address[] calldata poolTokens,\n        uint[] calldata tokensAmount\n    ) external;\n}\n\ninterface Oracles {\n    function getPrice(address tokenAddress) external returns (uint price);\n\n    function getAllPrice(address[] calldata poolTokens, uint[] calldata tokensAmount) external returns (uint);\n}"
      },
      "contracts/libraries/RightsManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n// Needed to handle structures externally\npragma experimental ABIEncoderV2;\n\n/**\n * @author Desyn Labs\n * @title Manage Configurable Rights for the smart pool\n *                         by default, it is off on initialization and can only be turned on\n *      canWhitelistLPs - can limit liquidity providers to a given set of addresses\n *      canChangeCap - can change the BSP cap (max # of pool tokens)\n *      canChangeFloor - can change the BSP floor for Closure ETF (min # of pool tokens)\n */\nlibrary RightsManager {\n    // Type declarations\n\n    enum Permissions {\n        WHITELIST_LPS,\n        TOKEN_WHITELISTS\n    }\n\n    struct Rights {\n        bool canWhitelistLPs;\n        bool canTokenWhiteLists;\n    }\n\n    // State variables (can only be constants in a library)\n    bool public constant DEFAULT_CAN_WHITELIST_LPS = false;\n    bool public constant DEFAULT_CAN_TOKEN_WHITELISTS = false;\n\n    // bool public constant DEFAULT_CAN_CHANGE_CAP = false;\n    // bool public constant DEFAULT_CAN_CHANGE_FLOOR = false;\n\n    // Functions\n\n    /**\n     * @notice create a struct from an array (or return defaults)\n     * @dev If you pass an empty array, it will construct it using the defaults\n     * @param a - array input\n     * @return Rights struct\n     */\n    function constructRights(bool[] calldata a) external pure returns (Rights memory) {\n        if (a.length < 2) {\n            return\n                Rights(\n                    DEFAULT_CAN_WHITELIST_LPS,\n                    DEFAULT_CAN_TOKEN_WHITELISTS\n                );\n        } else {\n            // return Rights(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);\n            return Rights(a[0], a[1]);\n        }\n    }\n\n    /**\n     * @notice Convert rights struct to an array (e.g., for events, GUI)\n     * @dev avoids multiple calls to hasPermission\n     * @param rights - the rights struct to convert\n     * @return boolean array containing the rights settings\n     */\n    function convertRights(Rights calldata rights) external pure returns (bool[] memory) {\n        bool[] memory result = new bool[](2);\n\n        result[0] = rights.canWhitelistLPs;\n        result[1] = rights.canTokenWhiteLists;\n\n        return result;\n    }\n\n    // Though it is actually simple, the number of branches triggers code-complexity\n    /* solhint-disable code-complexity */\n\n    /**\n     * @notice Externally check permissions using the Enum\n     * @param self - Rights struct containing the permissions\n     * @param permission - The permission to check\n     * @return Boolean true if it has the permission\n     */\n    function hasPermission(Rights calldata self, Permissions permission) external pure returns (bool) {\n        if (Permissions.WHITELIST_LPS == permission) {\n            return self.canWhitelistLPs;\n        } else if (Permissions.TOKEN_WHITELISTS == permission) {\n            return self.canTokenWhiteLists;\n        }\n    }\n\n    /* solhint-enable code-complexity */\n}\n"
      },
      "contracts/base/PCToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n// Imports\n\nimport \"../libraries/DesynSafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n// Contracts\n\n/* solhint-disable func-order */\n\n/**\n * @author Desyn Labs\n * @title Highly opinionated token implementation\n */\ncontract PCToken is IERC20 {\n    using DesynSafeMath for uint;\n\n    // State variables\n    string public constant NAME = \"Desyn Smart Pool\";\n    uint8 public constant DECIMALS = 18;\n\n    // No leading underscore per naming convention (non-private)\n    // Cannot call totalSupply (name conflict)\n    // solhint-disable-next-line private-vars-leading-underscore\n    uint internal varTotalSupply;\n\n    mapping(address => uint) private _balance;\n    mapping(address => mapping(address => uint)) private _allowance;\n\n    string private _symbol;\n    string private _name;\n\n    // Event declarations\n\n    // See definitions above; must be redeclared to be emitted from this contract\n    event Approval(address indexed owner, address indexed spender, uint value);\n    event Transfer(address indexed from, address indexed to, uint value);\n\n    // Function declarations\n\n    /**\n     * @notice Base token constructor\n     * @param tokenSymbol - the token symbol\n     */\n    constructor(string memory tokenSymbol, string memory tokenName) public {\n        _symbol = tokenSymbol;\n        _name = tokenName;\n    }\n\n    // External functions\n\n    /**\n     * @notice Getter for allowance: amount spender will be allowed to spend on behalf of owner\n     * @param owner - owner of the tokens\n     * @param spender - entity allowed to spend the tokens\n     * @return uint - remaining amount spender is allowed to transfer\n     */\n    function allowance(address owner, address spender) external view override returns (uint) {\n        return _allowance[owner][spender];\n    }\n\n    /**\n     * @notice Getter for current account balance\n     * @param account - address we're checking the balance of\n     * @return uint - token balance in the account\n     */\n    function balanceOf(address account) external view override returns (uint) {\n        return _balance[account];\n    }\n\n    /**\n     * @notice Approve owner (sender) to spend a certain amount\n     * @dev emits an Approval event\n     * @param spender - entity the owner (sender) is approving to spend his tokens\n     * @param amount - number of tokens being approved\n     * @return bool - result of the approval (will always be true if it doesn't revert)\n     */\n    function approve(address spender, uint amount) external override returns (bool) {\n        /* In addition to the increase/decreaseApproval functions, could\n           avoid the \"approval race condition\" by only allowing calls to approve\n           when the current approval amount is 0\n        \n           require(_allowance[msg.sender][spender] == 0, \"ERR_RACE_CONDITION\");\n\n           Some token contracts (e.g., KNC), already revert if you call approve \n           on a non-zero allocation. To deal with these, we use the SafeApprove library\n           and safeApprove function when adding tokens to the pool.\n        */\n\n        _allowance[msg.sender][spender] = amount;\n\n        emit Approval(msg.sender, spender, amount);\n\n        return true;\n    }\n\n    /**\n     * @notice Increase the amount the spender is allowed to spend on behalf of the owner (sender)\n     * @dev emits an Approval event\n     * @param spender - entity the owner (sender) is approving to spend his tokens\n     * @param amount - number of tokens being approved\n     * @return bool - result of the approval (will always be true if it doesn't revert)\n     */\n    function increaseApproval(address spender, uint amount) external returns (bool) {\n        _allowance[msg.sender][spender] = DesynSafeMath.badd(_allowance[msg.sender][spender], amount);\n\n        emit Approval(msg.sender, spender, _allowance[msg.sender][spender]);\n\n        return true;\n    }\n\n    /**\n     * @notice Decrease the amount the spender is allowed to spend on behalf of the owner (sender)\n     * @dev emits an Approval event\n     * @dev If you try to decrease it below the current limit, it's just set to zero (not an error)\n     * @param spender - entity the owner (sender) is approving to spend his tokens\n     * @param amount - number of tokens being approved\n     * @return bool - result of the approval (will always be true if it doesn't revert)\n     */\n    function decreaseApproval(address spender, uint amount) external returns (bool) {\n        uint oldValue = _allowance[msg.sender][spender];\n        // Gas optimization - if amount == oldValue (or is larger), set to zero immediately\n        if (amount >= oldValue) {\n            _allowance[msg.sender][spender] = 0;\n        } else {\n            _allowance[msg.sender][spender] = DesynSafeMath.bsub(oldValue, amount);\n        }\n\n        emit Approval(msg.sender, spender, _allowance[msg.sender][spender]);\n\n        return true;\n    }\n\n    /**\n     * @notice Transfer the given amount from sender (caller) to recipient\n     * @dev _move emits a Transfer event if successful\n     * @param recipient - entity receiving the tokens\n     * @param amount - number of tokens being transferred\n     * @return bool - result of the transfer (will always be true if it doesn't revert)\n     */\n    function transfer(address recipient, uint amount) external override returns (bool) {\n        require(recipient != address(0), \"ERR_ZERO_ADDRESS\");\n\n        _move(msg.sender, recipient, amount);\n\n        return true;\n    }\n\n    /**\n     * @notice Transfer the given amount from sender to recipient\n     * @dev _move emits a Transfer event if successful; may also emit an Approval event\n     * @param sender - entity sending the tokens (must be caller or allowed to spend on behalf of caller)\n     * @param recipient - recipient of the tokens\n     * @param amount - number of tokens being transferred\n     * @return bool - result of the transfer (will always be true if it doesn't revert)\n     */\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint amount\n    ) external override returns (bool) {\n        require(recipient != address(0), \"ERR_ZERO_ADDRESS\");\n        require(msg.sender == sender || amount <= _allowance[sender][msg.sender], \"ERR_PCTOKEN_BAD_CALLER\");\n\n        _move(sender, recipient, amount);\n\n        // memoize for gas optimization\n        uint oldAllowance = _allowance[sender][msg.sender];\n\n        // If the sender is not the caller, adjust the allowance by the amount transferred\n        if (msg.sender != sender && oldAllowance != uint(-1)) {\n            _allowance[sender][msg.sender] = DesynSafeMath.bsub(oldAllowance, amount);\n\n            emit Approval(sender, msg.sender, _allowance[sender][msg.sender]);\n        }\n\n        return true;\n    }\n\n    // public functions\n\n    /**\n     * @notice Getter for the total supply\n     * @dev declared external for gas optimization\n     * @return uint - total number of tokens in existence\n     */\n    function totalSupply() external view override returns (uint) {\n        return varTotalSupply;\n    }\n\n    // Public functions\n\n    /**\n     * @dev Returns the name of the token.\n     *      We allow the user to set this name (as well as the symbol).\n     *      Alternatives are 1) A fixed string (original design)\n     *                       2) A fixed string plus the user-defined symbol\n     *                          return string(abi.encodePacked(NAME, \"-\", _symbol));\n     */\n    function name() external view returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() external view override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is\n     * called.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() external view override returns (uint8) {\n        return DECIMALS;\n    }\n\n    // internal functions\n\n    // Mint an amount of new tokens, and add them to the balance (and total supply)\n    // Emit a transfer amount from the null address to this contract\n    function _mint(uint amount) internal virtual {\n        _balance[address(this)] = DesynSafeMath.badd(_balance[address(this)], amount);\n        varTotalSupply = DesynSafeMath.badd(varTotalSupply, amount);\n\n        emit Transfer(address(0), address(this), amount);\n    }\n\n    // Burn an amount of new tokens, and subtract them from the balance (and total supply)\n    // Emit a transfer amount from this contract to the null address\n    function _burn(uint amount) internal virtual {\n        // Can't burn more than we have\n        // Remove require for gas optimization - bsub will revert on underflow\n        // require(_balance[address(this)] >= amount, \"ERR_INSUFFICIENT_BAL\");\n\n        _balance[address(this)] = DesynSafeMath.bsub(_balance[address(this)], amount);\n        varTotalSupply = DesynSafeMath.bsub(varTotalSupply, amount);\n\n        emit Transfer(address(this), address(0), amount);\n    }\n\n    // Transfer tokens from sender to recipient\n    // Adjust balances, and emit a Transfer event\n    function _move(\n        address sender,\n        address recipient,\n        uint amount\n    ) internal virtual {\n        // Can't send more than sender has\n        // Remove require for gas optimization - bsub will revert on underflow\n        // require(_balance[sender] >= amount, \"ERR_INSUFFICIENT_BAL\");\n\n        _balance[sender] = DesynSafeMath.bsub(_balance[sender], amount);\n        _balance[recipient] = DesynSafeMath.badd(_balance[recipient], amount);\n\n        emit Transfer(sender, recipient, amount);\n    }\n\n    // Transfer from this contract to recipient\n    // Emits a transfer event if successful\n    function _push(address recipient, uint amount) internal {\n        _move(address(this), recipient, amount);\n    }\n\n    // Transfer from recipient to this contract\n    // Emits a transfer event if successful\n    function _pull(address sender, uint amount) internal {\n        _move(sender, address(this), amount);\n    }\n}\n"
      },
      "contracts/utils/DesynOwnable.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract DesynOwnable {\n    // State variables\n    mapping(address => bool) public adminList;\n    uint public allOwnerPercentage = 10000;\n\n    address _owner;\n    address[] owners;\n    uint[] ownerPercentage;\n    bool initialized;\n    // Event declarations\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n    event AddAdmin(address indexed newAdmin, uint indexed amount);\n    event RemoveAdmin(address indexed oldAdmin, uint indexed amount);\n\n    // Modifiers\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(_owner == msg.sender, \"ERR_NOT_CONTROLLER\");\n        _;\n    }\n\n    modifier onlyAdmin() {\n        require(adminList[msg.sender] || msg.sender == _owner, \"onlyAdmin\");\n        _;\n    }\n\n    // Function declarations\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() internal {\n        _owner = msg.sender;\n    }\n\n    function initHandle(address[] memory _owners, uint[] memory _ownerPercentage) external {\n        require(_owners.length == _ownerPercentage.length, \"ownerP\");\n        require(!initialized, \"initialized!\");\n        \n        _addAdmin(_owners);\n\n        owners = _owners;\n        ownerPercentage = _ownerPercentage;\n\n        initialized = true;\n        _ownerPercentageChecker();\n    }\n\n    function setManagersInfo(address[] memory _owners, uint[] memory _ownerPercentage) external onlyOwner {\n        _beforeControllerChange();\n        _clearAdmin();\n        _addAdmin(_owners);\n        owners = _owners;\n        ownerPercentage = _ownerPercentage;\n        _ownerPercentageChecker();\n    }\n\n    function _ownerPercentageChecker() internal view {\n        uint totalPercentage;\n        for (uint i; i < ownerPercentage.length; i++) {\n            totalPercentage+=ownerPercentage[i];\n        } \n        require(totalPercentage == 10000, \"ERR_ILLEGAL_PERCENTAGE\"); \n    }\n\n    function _addAdmin(address[] memory admins) internal {\n        bool hasOwner;\n        for (uint i; i < admins.length; i++) {\n            adminList[admins[i]] = true;\n            if(admins[i] == _owner) hasOwner = true;\n        } \n\n        if(initialized) require(hasOwner, \"ERR_NEW_ADMINS_HAS_NO_OWNER\");    \n    }\n\n    function _clearAdmin() internal {\n        for(uint i; i < owners.length; i++) {\n            delete adminList[owners[i]];\n        }\n    }\n\n    /**\n     * @notice Transfers ownership of the contract to a new account (`newOwner`).\n     *         Can only be called by the current owner\n     * @dev external for gas optimization\n     * @param newOwner - address of new owner\n     */\n    function setController(address newOwner) external onlyOwner {\n        _beforeControllerChange();\n        require(newOwner != address(0), \"ERR_ZERO_ADDRESS\");\n\n        emit OwnershipTransferred(_owner, newOwner);\n\n        for (uint i;i < owners.length; i++) {\n            if (owners[i] == _owner) {\n                owners[i] = newOwner;\n            }\n        }\n\n        adminList[_owner] = false;\n        adminList[newOwner] = true;\n        _owner = newOwner;\n    }\n\n    // @dev Returns list of owners.\n    // @return List of owner addresses.\n    function getOwners() external view returns (address[] memory) {\n        return owners;\n    }\n\n    // @dev Returns list of owners.\n    // @return List of owner addresses.\n    function getOwnerPercentage() external view returns (uint[] memory) {\n        return ownerPercentage;\n    }\n\n    /**\n     * @notice Returns the address of the current owner\n     * @dev external for gas optimization\n     * @return address - of the owner (AKA controller)\n     */\n    function getController() public view returns (address) {\n        return _owner;\n    }\n\n    function _beforeControllerChange() internal virtual {}\n}\n"
      },
      "contracts/libraries/SmartPoolManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n// Needed to pass in structs\npragma experimental ABIEncoderV2;\n\n// Imports\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../interfaces/IConfigurableRightsPool.sol\";\nimport \"../interfaces/IBFactory.sol\"; // unused\nimport \"./DesynSafeMath.sol\";\nimport \"./SafeMath.sol\";\n// import \"./SafeApprove.sol\";\nimport \"../libraries/SafeERC20.sol\";\n\n/**\n * @author Desyn Labs\n * @title Factor out the weight updates\n */\nlibrary SmartPoolManager {\n    // using SafeApprove for IERC20;\n    using DesynSafeMath for uint;\n    using SafeMath for uint;\n    using SafeERC20 for IERC20;\n\n    //kol pool params\n    struct levelParams {\n        uint level;\n        uint ratio;\n    }\n\n    struct feeParams {\n        levelParams firstLevel;\n        levelParams secondLevel;\n        levelParams thirdLevel;\n        levelParams fourLevel;\n    }\n    \n    struct KolPoolParams {\n        feeParams managerFee;\n        feeParams issueFee;\n        feeParams redeemFee;\n        feeParams perfermanceFee;\n    }\n\n    // Type declarations\n    enum Etypes {\n        OPENED,\n        CLOSED\n    }\n\n    enum Period {\n        DAY90,\n        DAY180,\n        DAY360,\n        DAY1,\n        DAY3,\n        DAY7,\n        DAY14,\n        DAY30\n    }\n\n    struct Fund {\n        uint etfAmount;\n        uint fundAmount;\n        uint snapshotTime;\n        address[] tokens;\n        uint[] tokensAmount;\n    }\n\n    // updateWeight and pokeWeights are unavoidably long\n    /* solhint-disable function-max-lines */\n    struct Status {\n        uint collectPeriod;\n        uint collectEndTime;\n        uint closurePeriod;\n        uint closureEndTime;\n        uint upperCap;\n        uint floorCap;\n        uint managerFee;\n        uint redeemFee;\n        uint issueFee;\n        uint perfermanceFee;\n        uint startClaimFeeTime;\n    }\n\n    struct PoolParams {\n        // Desyn Pool Token (representing shares of the pool)\n        string poolTokenSymbol;\n        string poolTokenName;\n        // Tokens inside the Pool\n        address[] constituentTokens;\n        uint[] tokenBalances;\n        uint[] tokenWeights;\n        uint managerFee;\n        uint redeemFee;\n        uint issueFee;\n        uint perfermanceFee;\n        Etypes etype;\n    }\n\n    struct PoolTokenRange {\n        uint bspFloor;\n        uint bspCap;\n    }\n\n    function initRequire(\n        uint managerFee,\n        uint issueFee,\n        uint redeemFee,\n        uint perfermanceFee,\n        uint tokenBalancesLength,\n        uint tokenWeightsLength,\n        uint constituentTokensLength,\n        bool initBool\n    ) external pure {\n        // We don't have a pool yet; check now or it will fail later (in order of likelihood to fail)\n        // (and be unrecoverable if they don't have permission set to change it)\n        // Most likely to fail, so check first\n        require(!initBool, \"Init fail\");\n        require(managerFee >= DesynConstants.MANAGER_MIN_FEE, \"ERR_INVALID_MANAGER_FEE\");\n        require(managerFee <= DesynConstants.MANAGER_MAX_FEE, \"ERR_INVALID_MANAGER_FEE\");\n        require(issueFee >= DesynConstants.ISSUE_MIN_FEE, \"ERR_INVALID_ISSUE_MIN_FEE\");\n        require(issueFee <= DesynConstants.ISSUE_MAX_FEE, \"ERR_INVALID_ISSUE_MAX_FEE\");\n        require(redeemFee >= DesynConstants.REDEEM_MIN_FEE, \"ERR_INVALID_REDEEM_MIN_FEE\");\n        require(redeemFee <= DesynConstants.REDEEM_MAX_FEE, \"ERR_INVALID_REDEEM_MAX_FEE\");\n        require(perfermanceFee >= DesynConstants.PERFERMANCE_MIN_FEE, \"ERR_INVALID_PERFERMANCE_MIN_FEE\");\n        require(perfermanceFee <= DesynConstants.PERFERMANCE_MAX_FEE, \"ERR_INVALID_PERFERMANCE_MAX_FEE\");\n\n        // Arrays must be parallel\n        require(tokenBalancesLength == constituentTokensLength, \"ERR_START_BALANCES_MISMATCH\");\n        require(tokenWeightsLength == constituentTokensLength, \"ERR_START_WEIGHTS_MISMATCH\");\n        // Cannot have too many or too few - technically redundant, since BPool.bind() would fail later\n        // But if we don't check now, we could have a useless contract with no way to create a pool\n\n        require(constituentTokensLength >= DesynConstants.MIN_ASSET_LIMIT, \"ERR_TOO_FEW_TOKENS\");\n        require(constituentTokensLength <= DesynConstants.MAX_ASSET_LIMIT, \"ERR_TOO_MANY_TOKENS\");\n        // There are further possible checks (e.g., if they use the same token twice), but\n        // we can let bind() catch things like that (i.e., not things that might reasonably work)\n    }\n\n    /**\n     * @notice Non ERC20-conforming tokens are problematic; don't allow them in pools\n     * @dev Will revert if invalid\n     * @param token - The prospective token to verify\n     */\n    function verifyTokenCompliance(address token) external {\n        verifyTokenComplianceInternal(token);\n    }\n\n    /**\n     * @notice Non ERC20-conforming tokens are problematic; don't allow them in pools\n     * @dev Will revert if invalid - overloaded to save space in the main contract\n     * @param tokens - The prospective tokens to verify\n     */\n    function verifyTokenCompliance(address[] calldata tokens) external {\n        for (uint i = 0; i < tokens.length; i++) {\n            verifyTokenComplianceInternal(tokens[i]);\n        }\n    }\n\n    function createPoolInternalHandle(IBPool bPool, uint initialSupply) external view {\n        require(initialSupply >= DesynConstants.MIN_POOL_SUPPLY, \"ERR_INIT_SUPPLY_MIN\");\n        require(initialSupply <= DesynConstants.MAX_POOL_SUPPLY, \"ERR_INIT_SUPPLY_MAX\");\n        require(bPool.EXIT_FEE() == 0, \"ERR_NONZERO_EXIT_FEE\");\n        // EXIT_FEE must always be zero, or ConfigurableRightsPool._pushUnderlying will fail\n        require(DesynConstants.EXIT_FEE == 0, \"ERR_NONZERO_EXIT_FEE\");\n    }\n\n    function createPoolHandle(\n        uint collectPeriod,\n        uint upperCap,\n        uint initialSupply\n    ) external pure {\n        require(collectPeriod <= DesynConstants.MAX_COLLECT_PERIOD, \"ERR_EXCEEDS_FUND_RAISING_PERIOD\");\n        require(upperCap >= initialSupply, \"ERR_CAP_BIGGER_THAN_INITSUPPLY\");\n    }\n\n    function exitPoolHandleA(\n        IConfigurableRightsPool self,\n        IBPool bPool,\n        address poolToken,\n        uint _tokenAmountOut,\n        uint redeemFee\n    )\n        external\n        returns (\n            uint redeemAndPerformanceFeeReceived,\n            uint finalAmountOut,\n            uint redeemFeeReceived\n        )\n    {\n        // redeem fee\n        redeemFeeReceived = DesynSafeMath.bmul(_tokenAmountOut, redeemFee);\n\n        // performance fee\n        uint performanceFeeReceived = 0;\n        \n        // redeem fee and performance fee\n        redeemAndPerformanceFeeReceived = DesynSafeMath.badd(performanceFeeReceived, redeemFeeReceived);\n\n        // final amount the user got\n        finalAmountOut = DesynSafeMath.bsub(_tokenAmountOut, redeemAndPerformanceFeeReceived);\n\n        _pushUnderlying(bPool, poolToken, msg.sender, finalAmountOut);\n\n        if (redeemFee != 0) {\n            _pushUnderlying(bPool, poolToken, address(this), redeemAndPerformanceFeeReceived);\n            IERC20(poolToken).safeApprove(self.vaultAddress(), 0);\n            IERC20(poolToken).safeApprove(self.vaultAddress(), redeemAndPerformanceFeeReceived);\n        }\n    }\n\n    function exitPoolHandleB(\n        IConfigurableRightsPool self,\n        bool bools,\n        bool isCompletedCollect,\n        uint closureEndTime,\n        uint collectEndTime,\n        // uint _etfAmount,\n        // uint _fundAmount,\n        uint poolAmountIn\n    ) external view returns (uint actualPoolAmountIn) {\n        actualPoolAmountIn = poolAmountIn;\n        if (bools) {\n            bool isCloseEtfCollectEndWithFailure = isCompletedCollect == false && block.timestamp >= collectEndTime;\n            bool isCloseEtfClosureEnd = block.timestamp >= closureEndTime;\n            require(isCloseEtfCollectEndWithFailure || isCloseEtfClosureEnd, \"ERR_CLOSURE_TIME_NOT_ARRIVED!\");\n\n            actualPoolAmountIn = self.balanceOf(msg.sender);\n        }\n        // fundAmount = _fundAmount;\n        // etfAmount = _etfAmount;\n    }\n\n    function joinPoolHandle(\n        bool canWhitelistLPs,\n        bool isList,\n        bool bools,\n        uint collectEndTime\n    ) external view {\n        require(!canWhitelistLPs || isList, \"ERR_NOT_ON_WHITELIST\");\n\n        if (bools) {\n            require(block.timestamp <= collectEndTime, \"ERR_COLLECT_PERIOD_FINISHED!\");\n        }\n    }\n\n    /**\n     * @notice Join a pool\n     * @param self - ConfigurableRightsPool instance calling the library\n     * @param bPool - Core BPool the CRP is wrapping\n     * @param poolAmountOut - number of pool tokens to receive\n     * @param maxAmountsIn - Max amount of asset tokens to spend\n     * @return actualAmountsIn - calculated values of the tokens to pull in\n     */\n    function joinPool(\n        IConfigurableRightsPool self,\n        IBPool bPool,\n        uint poolAmountOut,\n        uint[] calldata maxAmountsIn,\n        uint issueFee\n    ) external view returns (uint[] memory actualAmountsIn) {\n        address[] memory tokens = bPool.getCurrentTokens();\n\n        require(maxAmountsIn.length == tokens.length, \"ERR_AMOUNTS_MISMATCH\");\n\n        uint poolTotal = self.totalSupply();\n        // Subtract  1 to ensure any rounding errors favor the pool\n        uint ratio = DesynSafeMath.bdiv(poolAmountOut, DesynSafeMath.bsub(poolTotal, 1));\n\n        require(ratio != 0, \"ERR_MATH_APPROX\");\n\n        // We know the length of the array; initialize it, and fill it below\n        // Cannot do \"push\" in memory\n        actualAmountsIn = new uint[](tokens.length);\n\n        // This loop contains external calls\n        // External calls are to math libraries or the underlying pool, so low risk\n        uint issueFeeRate = issueFee.bmul(1000);\n        for (uint i = 0; i < tokens.length; i++) {\n            address t = tokens[i];\n            uint bal = bPool.getBalance(t);\n            // Add 1 to ensure any rounding errors favor the pool\n            uint base = bal.badd(1).bmul(poolAmountOut * uint(1000));\n            uint tokenAmountIn = base.bdiv(poolTotal.bsub(1) * (uint(1000).bsub(issueFeeRate)));\n\n            require(tokenAmountIn != 0, \"ERR_MATH_APPROX\");\n            require(tokenAmountIn <= maxAmountsIn[i], \"ERR_LIMIT_IN\");\n\n            actualAmountsIn[i] = tokenAmountIn;\n        }\n    }\n\n    /**\n     * @notice Exit a pool - redeem pool tokens for underlying assets\n     * @param self - ConfigurableRightsPool instance calling the library\n     * @param bPool - Core BPool the CRP is wrapping\n     * @param poolAmountIn - amount of pool tokens to redeem\n     * @param minAmountsOut - minimum amount of asset tokens to receive\n     * @return actualAmountsOut - calculated amounts of each token to pull\n     */\n    function exitPool(\n        IConfigurableRightsPool self,\n        IBPool bPool,\n        uint poolAmountIn,\n        uint[] calldata minAmountsOut\n    ) external view returns (uint[] memory actualAmountsOut) {\n        address[] memory tokens = bPool.getCurrentTokens();\n\n        require(minAmountsOut.length == tokens.length, \"ERR_AMOUNTS_MISMATCH\");\n\n        uint poolTotal = self.totalSupply();\n\n        uint ratio = DesynSafeMath.bdiv(poolAmountIn, DesynSafeMath.badd(poolTotal, 1));\n\n        require(ratio != 0, \"ERR_MATH_APPROX\");\n\n        actualAmountsOut = new uint[](tokens.length);\n\n        // This loop contains external calls\n        // External calls are to math libraries or the underlying pool, so low risk\n        for (uint i = 0; i < tokens.length; i++) {\n            address t = tokens[i];\n            uint bal = bPool.getBalance(t);\n            // Subtract 1 to ensure any rounding errors favor the pool\n            uint tokenAmountOut = DesynSafeMath.bmul(ratio, DesynSafeMath.bsub(bal, 1));\n\n            require(tokenAmountOut != 0, \"ERR_MATH_APPROX\");\n            require(tokenAmountOut >= minAmountsOut[i], \"ERR_LIMIT_OUT\");\n\n            actualAmountsOut[i] = tokenAmountOut;\n        }\n    }\n\n    // Internal functions\n    // Check for zero transfer, and make sure it returns true to returnValue\n    function verifyTokenComplianceInternal(address token) internal {\n        IERC20(token).safeTransfer(msg.sender, 0);\n    }\n\n    function handleTransferInTokens(\n        IConfigurableRightsPool self,\n        IBPool bPool,\n        address poolToken,\n        uint actualAmountIn,\n        uint _actualIssueFee\n    ) external returns (uint issueFeeReceived) {\n        issueFeeReceived = DesynSafeMath.bmul(actualAmountIn, _actualIssueFee);\n        uint amount = DesynSafeMath.bsub(actualAmountIn, issueFeeReceived);\n\n        _pullUnderlying(bPool, poolToken, msg.sender, amount);\n\n        if (_actualIssueFee != 0) {\n            IERC20(poolToken).safeTransferFrom(msg.sender, address(this), issueFeeReceived);\n            IERC20(poolToken).safeApprove(self.vaultAddress(), 0);\n            IERC20(poolToken).safeApprove(self.vaultAddress(), issueFeeReceived);\n        }\n    }\n\n    function handleClaim(\n        IConfigurableRightsPool self,\n        IBPool bPool,\n        address[] calldata poolTokens,\n        uint managerFee,\n        uint timeElapsed,\n        uint claimPeriod\n    ) external returns (uint[] memory) {\n        uint[] memory tokensAmount = new uint[](poolTokens.length);\n        \n        for (uint i = 0; i < poolTokens.length; i++) {\n            address t = poolTokens[i];\n            uint tokenBalance = bPool.getBalance(t);\n            uint tokenAmountOut = tokenBalance.bmul(managerFee).mul(timeElapsed).div(claimPeriod).div(12);    \n            _pushUnderlying(bPool, t, address(this), tokenAmountOut);\n            IERC20(t).safeApprove(self.vaultAddress(), 0);\n            IERC20(t).safeApprove(self.vaultAddress(), tokenAmountOut);\n            tokensAmount[i] = tokenAmountOut;\n        }\n        \n        return tokensAmount;\n    }\n\n    function handleFeeClaim(\n        IConfigurableRightsPool self,\n        IBPool bPool,\n        address[] calldata poolTokens,\n        uint feeRatio,\n        bool isPerfermance\n    ) external {\n        if (feeRatio != 0) {\n            uint[] memory tokensAmount = new uint[](poolTokens.length);\n\n            for (uint i = 0; i < poolTokens.length; i++) {\n                address t = poolTokens[i];\n                uint currentAmount = bPool.getBalance(t);\n                uint currentAmountFee = DesynSafeMath.bmul(currentAmount, feeRatio);\n\n                _pushUnderlying(bPool, t, address(this), currentAmountFee);\n                tokensAmount[i] = currentAmountFee;\n                IERC20(t).safeApprove(self.vaultAddress(), 0);\n                IERC20(t).safeApprove(self.vaultAddress(), currentAmountFee);\n            }\n\n            if(isPerfermance) {\n                IVault(self.vaultAddress()).depositIssueRedeemPToken(poolTokens, tokensAmount, new uint[](poolTokens.length), isPerfermance);\n            } else {\n                IVault(self.vaultAddress()).depositIssueRedeemPToken(poolTokens, tokensAmount, tokensAmount, isPerfermance);\n            }\n            \n        }\n    }\n\n    function WhitelistHandle(\n        bool bool1,\n        bool bool2,\n        address adr\n    ) external pure {\n        require(bool1, \"ERR_CANNOT_WHITELIST_LPS\");\n        require(bool2, \"ERR_LP_NOT_WHITELISTED\");\n        require(adr != address(0), \"ERR_INVALID_ADDRESS\");\n    }\n\n    function _pullUnderlying(\n        IBPool bPool,\n        address erc20,\n        address from,\n        uint amount\n    ) internal {\n        uint tokenBalance = bPool.getBalance(erc20);\n        uint tokenWeight = bPool.getDenormalizedWeight(erc20);\n\n        IERC20(erc20).safeTransferFrom(from, address(this), amount);\n        bPool.rebind(erc20, DesynSafeMath.badd(tokenBalance, amount), tokenWeight);\n    }\n\n    function _pushUnderlying(\n        IBPool bPool,\n        address erc20,\n        address to,\n        uint amount\n    ) internal {\n        uint tokenBalance = bPool.getBalance(erc20);\n        uint tokenWeight = bPool.getDenormalizedWeight(erc20);\n        bPool.rebind(erc20, DesynSafeMath.bsub(tokenBalance, amount), tokenWeight);\n        IERC20(erc20).safeTransfer(to, amount);\n    }\n}\n"
      },
      "contracts/libraries/Address.sol": {
        "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity 0.6.12;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n        // for accounts without code, i.e. `keccak256('')`\n        bytes32 codehash;\n        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            codehash := extcodehash(account)\n        }\n        return (codehash != accountHash && codehash != 0x0);\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return _functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        return _functionCallWithValue(target, data, value, errorMessage);\n    }\n\n    function _functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint weiValue,\n        string memory errorMessage\n    ) private returns (bytes memory) {\n        require(isContract(target), \"Address: call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.call{value: weiValue}(data);\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                // solhint-disable-next-line no-inline-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"
      },
      "contracts/libraries/SafeApprove.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n// Imports\n\nimport \"../interfaces/IERC20.sol\";\n\n// Libraries\n\n/**\n * @author PieDAO (ported to Desyn Labs)\n * @title SafeApprove - set approval for tokens that require 0 prior approval\n * @dev Perhaps to address the known ERC20 race condition issue\n *      See https://github.com/crytic/not-so-smart-contracts/tree/master/race_condition\n *      Some tokens - notably KNC - only allow approvals to be increased from 0\n */\nlibrary SafeApprove {\n    /**\n     * @notice handle approvals of tokens that require approving from a base of 0\n     * @param token - the token we're approving\n     * @param spender - entity the owner (sender) is approving to spend his tokens\n     * @param amount - number of tokens being approved\n     */\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint amount\n    ) internal returns (bool) {\n        uint currentAllowance = token.allowance(address(this), spender);\n\n        // Do nothing if allowance is already set to this value\n        if (currentAllowance == amount) {\n            return true;\n        }\n\n        // If approval is not zero reset it to zero first\n        if (currentAllowance != 0) {\n            token.approve(spender, 0);\n        }\n\n        // do the actual approval\n        return token.approve(spender, amount);\n    }\n}\n"
      },
      "contracts/base/WhiteToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\ncontract WhiteToken {\n    // add token log\n    event LOG_WHITELIST(address indexed spender, uint indexed sort, address indexed caller, address token);\n    // del token log\n    event LOG_DEL_WHITELIST(address indexed spender, uint indexed sort, address indexed caller, address token);\n\n    // record the number of whitelists.\n    uint private _whiteTokenCount;\n    // token address => is white token.\n    mapping(address => bool) private _isTokenWhitelisted;\n    // Multi level white token.\n    // type => token address => is white token.\n    mapping(uint => mapping(address => bool)) private _tokenWhitelistedInfo;\n\n    function _queryIsTokenWhitelisted(address token) internal view returns (bool) {\n        return _isTokenWhitelisted[token];\n    }\n\n    // for factory to verify\n    function _isTokenWhitelistedForVerify(uint sort, address token) internal view returns (bool) {\n        return _tokenWhitelistedInfo[sort][token];\n    }\n\n    // add sort token\n    function _addTokenToWhitelist(uint sort, address token) internal {\n        require(token != address(0), \"ERR_INVALID_TOKEN_ADDRESS\");\n        require(_queryIsTokenWhitelisted(token) == false, \"ERR_HAS_BEEN_ADDED_WHITE\");\n\n        _tokenWhitelistedInfo[sort][token] = true;\n        _isTokenWhitelisted[token] = true;\n        _whiteTokenCount++;\n\n        emit LOG_WHITELIST(address(this), sort, msg.sender, token);\n    }\n\n    // remove sort token\n    function _removeTokenFromWhitelist(uint sort, address token) internal {\n        require(_queryIsTokenWhitelisted(token) == true, \"ERR_NOT_WHITE_TOKEN\");\n\n        require(_tokenWhitelistedInfo[sort][token], \"ERR_SORT_NOT_MATCHED\");\n\n        _tokenWhitelistedInfo[sort][token] = false;\n        _isTokenWhitelisted[token] = false;\n        _whiteTokenCount--;\n        emit LOG_DEL_WHITELIST(address(this), sort, msg.sender, token);\n    }\n\n    // already has init\n    function _initWhiteTokenState() internal view returns (bool) {\n        return _whiteTokenCount == 0 ?  false : true;\n    }\n}\n"
      },
      "contracts/libraries/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport {IERC20} from \"../interfaces/IERC20.sol\";\nimport {SafeMath} from \"./SafeMath.sol\";\nimport {Address} from \"./Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using SafeMath for uint;\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint value\n    ) internal {\n        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint value\n    ) internal {\n        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint value\n    ) internal {\n        require((value == 0) || (token.allowance(address(this), spender) == 0), \"SafeERC20: approve from non-zero to non-zero allowance\");\n        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function callOptionalReturn(IERC20 token, bytes memory data) private {\n        require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = address(token).call(data);\n        require(success, \"SafeERC20: low-level call failed\");\n\n        if (returndata.length > 0) {\n            // Return data is optional\n            // solhint-disable-next-line max-line-length\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "contracts/interfaces/IERC20.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n// Interface declarations\n\n/* solhint-disable func-order */\n\ninterface IERC20 {\n    // Emitted when the allowance of a spender for an owner is set by a call to approve.\n    // Value is the new allowance\n    event Approval(address indexed owner, address indexed spender, uint value);\n\n    // Emitted when value tokens are moved from one account (from) to another (to).\n    // Note that value may be zero\n    event Transfer(address indexed from, address indexed to, uint value);\n\n    // Returns the amount of tokens in existence\n    function totalSupply() external view returns (uint);\n\n    // Returns the amount of tokens owned by account\n    function balanceOf(address account) external view returns (uint);\n\n    // Returns the decimals of tokens\n    function decimals() external view returns (uint8);\n\n    function symbol() external view returns (string memory);\n\n    // Returns the remaining number of tokens that spender will be allowed to spend on behalf of owner\n    // through transferFrom. This is zero by default\n    // This value changes when approve or transferFrom are called\n    function allowance(address owner, address spender) external view returns (uint);\n\n    // Sets amount as the allowance of spender over the caller’s tokens\n    // Returns a boolean value indicating whether the operation succeeded\n    // Emits an Approval event.\n    function approve(address spender, uint amount) external returns (bool);\n\n    // Moves amount tokens from the caller’s account to recipient\n    // Returns a boolean value indicating whether the operation succeeded\n    // Emits a Transfer event.\n    function transfer(address recipient, uint amount) external returns (bool);\n\n    // Moves amount tokens from sender to recipient using the allowance mechanism\n    // Amount is then deducted from the caller’s allowance\n    // Returns a boolean value indicating whether the operation succeeded\n    // Emits a Transfer event\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint amount\n    ) external returns (bool);\n}\n"
      },
      "contracts/libraries/DesynSafeMath.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n// Imports\n\nimport \"./DesynConstants.sol\";\n\n/**\n * @author Desyn Labs\n * @title SafeMath - wrap Solidity operators to prevent underflow/overflow\n * @dev badd and bsub are basically identical to OpenZeppelin SafeMath; mul/div have extra checks\n */\nlibrary DesynSafeMath {\n    /**\n     * @notice Safe addition\n     * @param a - first operand\n     * @param b - second operand\n     * @dev if we are adding b to a, the resulting sum must be greater than a\n     * @return - sum of operands; throws if overflow\n     */\n    function badd(uint a, uint b) internal pure returns (uint) {\n        uint c = a + b;\n        require(c >= a, \"ERR_ADD_OVERFLOW\");\n        return c;\n    }\n\n    /**\n     * @notice Safe unsigned subtraction\n     * @param a - first operand\n     * @param b - second operand\n     * @dev Do a signed subtraction, and check that it produces a positive value\n     *      (i.e., a - b is valid if b <= a)\n     * @return - a - b; throws if underflow\n     */\n    function bsub(uint a, uint b) internal pure returns (uint) {\n        (uint c, bool negativeResult) = bsubSign(a, b);\n        require(!negativeResult, \"ERR_SUB_UNDERFLOW\");\n        return c;\n    }\n\n    /**\n     * @notice Safe signed subtraction\n     * @param a - first operand\n     * @param b - second operand\n     * @dev Do a signed subtraction\n     * @return - difference between a and b, and a flag indicating a negative result\n     *           (i.e., a - b if a is greater than or equal to b; otherwise b - a)\n     */\n    function bsubSign(uint a, uint b) internal pure returns (uint, bool) {\n        if (b <= a) {\n            return (a - b, false);\n        } else {\n            return (b - a, true);\n        }\n    }\n\n    /**\n     * @notice Safe multiplication\n     * @param a - first operand\n     * @param b - second operand\n     * @dev Multiply safely (and efficiently), rounding down\n     * @return - product of operands; throws if overflow or rounding error\n     */\n    function bmul(uint a, uint b) internal pure returns (uint) {\n        // Gas optimization (see github.com/OpenZeppelin/openzeppelin-contracts/pull/522)\n        if (a == 0) {\n            return 0;\n        }\n\n        // Standard overflow check: a/a*b=b\n        uint c0 = a * b;\n        require(c0 / a == b, \"ERR_MUL_OVERFLOW\");\n\n        // Round to 0 if x*y < BONE/2?\n        uint c1 = c0 + (DesynConstants.BONE / 2);\n        require(c1 >= c0, \"ERR_MUL_OVERFLOW\");\n        uint c2 = c1 / DesynConstants.BONE;\n        return c2;\n    }\n\n    /**\n     * @notice Safe division\n     * @param dividend - first operand\n     * @param divisor - second operand\n     * @dev Divide safely (and efficiently), rounding down\n     * @return - quotient; throws if overflow or rounding error\n     */\n    function bdiv(uint dividend, uint divisor) internal pure returns (uint) {\n        require(divisor != 0, \"ERR_DIV_ZERO\");\n\n        // Gas optimization\n        if (dividend == 0) {\n            return 0;\n        }\n\n        uint c0 = dividend * DesynConstants.BONE;\n        require(c0 / dividend == DesynConstants.BONE, \"ERR_DIV_INTERNAL\"); // bmul overflow\n\n        uint c1 = c0 + (divisor / 2);\n        require(c1 >= c0, \"ERR_DIV_INTERNAL\"); //  badd require\n\n        uint c2 = c1 / divisor;\n        return c2;\n    }\n\n    /**\n     * @notice Safe unsigned integer modulo\n     * @dev Returns the remainder of dividing two unsigned integers.\n     *      Reverts when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * @param dividend - first operand\n     * @param divisor - second operand -- cannot be zero\n     * @return - quotient; throws if overflow or rounding error\n     */\n    function bmod(uint dividend, uint divisor) internal pure returns (uint) {\n        require(divisor != 0, \"ERR_MODULO_BY_ZERO\");\n\n        return dividend % divisor;\n    }\n\n    /**\n     * @notice Safe unsigned integer max\n     * @dev Returns the greater of the two input values\n     *\n     * @param a - first operand\n     * @param b - second operand\n     * @return - the maximum of a and b\n     */\n    function bmax(uint a, uint b) internal pure returns (uint) {\n        return a >= b ? a : b;\n    }\n\n    /**\n     * @notice Safe unsigned integer min\n     * @dev returns b, if b < a; otherwise returns a\n     *\n     * @param a - first operand\n     * @param b - second operand\n     * @return - the lesser of the two input values\n     */\n    function bmin(uint a, uint b) internal pure returns (uint) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @notice Safe unsigned integer average\n     * @dev Guard against (a+b) overflow by dividing each operand separately\n     *\n     * @param a - first operand\n     * @param b - second operand\n     * @return - the average of the two values\n     */\n    function baverage(uint a, uint b) internal pure returns (uint) {\n        // (a + b) / 2 can overflow, so we distribute\n        return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);\n    }\n\n    /**\n     * @notice Babylonian square root implementation\n     * @dev (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)\n     * @param y - operand\n     * @return z - the square root result\n     */\n    function sqrt(uint y) internal pure returns (uint z) {\n        if (y > 3) {\n            z = y;\n            uint x = y / 2 + 1;\n            while (x < z) {\n                z = x;\n                x = (y / x + x) / 2;\n            }\n        } else if (y != 0) {\n            z = 1;\n        }\n    }\n}\n"
      },
      "contracts/libraries/DesynConstants.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n/**\n * @author Desyn Labs\n * @title Put all the constants in one place\n */\n\nlibrary DesynConstants {\n    // State variables (must be constant in a library)\n\n    // where numeric 1 = 10 ** 18\n    uint public constant BONE = 10**18;\n    uint public constant MIN_WEIGHT = BONE;\n    uint public constant MAX_WEIGHT = BONE * 50;\n    uint public constant MAX_TOTAL_WEIGHT = BONE * 50;\n    uint public constant MIN_BALANCE = 0;\n    uint public constant MAX_BALANCE = BONE * 10**12;\n    uint public constant MIN_POOL_SUPPLY = BONE * 100;\n    uint public constant MAX_POOL_SUPPLY = BONE * 10**9;\n    uint public constant MIN_FEE = BONE / 10**6;\n    uint public constant MAX_FEE = BONE / 10;\n    //Fee Set\n    uint public constant MANAGER_MIN_FEE = 0;\n    uint public constant MANAGER_MAX_FEE = BONE / 10;\n    uint public constant ISSUE_MIN_FEE = 0;\n    uint public constant ISSUE_MAX_FEE = BONE / 10;\n    uint public constant REDEEM_MIN_FEE = 0;\n    uint public constant REDEEM_MAX_FEE = BONE / 10;\n    uint public constant PERFERMANCE_MIN_FEE = 0;\n    uint public constant PERFERMANCE_MAX_FEE = BONE / 2;\n    // EXIT_FEE must always be zero, or ConfigurableRightsPool._pushUnderlying will fail\n    uint public constant EXIT_FEE = 0;\n    uint public constant MAX_IN_RATIO = BONE / 2;\n    uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei;\n    // Must match BConst.MIN_BOUND_TOKENS and BConst.MAX_BOUND_TOKENS\n    uint public constant MIN_ASSET_LIMIT = 1;\n    uint public constant MAX_ASSET_LIMIT = 16;\n    uint public constant MAX_UINT = uint(-1);\n    uint public constant MAX_COLLECT_PERIOD = 60 days;\n}\n"
      },
      "contracts/interfaces/IConfigurableRightsPool.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.6.12;\n\n// Interface declarations\n\n// Introduce to avoid circularity (otherwise, the CRP and SmartPoolManager include each other)\n// Removing circularity allows flattener tools to work, which enables Etherscan verification\ninterface IConfigurableRightsPool {\n    function mintPoolShareFromLib(uint amount) external;\n\n    function pushPoolShareFromLib(address to, uint amount) external;\n\n    function pullPoolShareFromLib(address from, uint amount) external;\n\n    function burnPoolShareFromLib(uint amount) external;\n\n    function balanceOf(address account) external view returns (uint);\n\n    function totalSupply() external view returns (uint);\n\n    function adminList(address) external view returns (bool);\n\n    function getController() external view returns (address);\n\n    function vaultAddress() external view returns (address);\n}\n"
      },
      "contracts/libraries/SafeMath.sol": {
        "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity 0.6.12;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     * - Addition cannot overflow.\n     */\n    function add(uint a, uint b) internal pure returns (uint) {\n        uint c = a + b;\n        require(c >= a, \"SafeMath: addition overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint a, uint b) internal pure returns (uint) {\n        return sub(a, b, \"SafeMath: subtraction overflow\");\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     * - Subtraction cannot overflow.\n     */\n    function sub(\n        uint a,\n        uint b,\n        string memory errorMessage\n    ) internal pure returns (uint) {\n        require(b <= a, errorMessage);\n        uint c = a - b;\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint a, uint b) internal pure returns (uint) {\n        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n        // benefit is lost if 'b' is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n        if (a == 0) {\n            return 0;\n        }\n\n        uint c = a * b;\n        require(c / a == b, \"SafeMath: multiplication overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers. Reverts on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     */\n    function div(uint a, uint b) internal pure returns (uint) {\n        return div(a, b, \"SafeMath: division by zero\");\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     */\n    function div(\n        uint a,\n        uint b,\n        string memory errorMessage\n    ) internal pure returns (uint) {\n        // Solidity only automatically asserts when dividing by 0\n        require(b > 0, errorMessage);\n        uint c = a / b;\n        // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * Reverts when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     */\n    function mod(uint a, uint b) internal pure returns (uint) {\n        return mod(a, b, \"SafeMath: modulo by zero\");\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * Reverts with custom message when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     */\n    function mod(\n        uint a,\n        uint b,\n        string memory errorMessage\n    ) internal pure returns (uint) {\n        require(b != 0, errorMessage);\n        return a % b;\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 20
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {
        "contracts/libraries/DesynSafeMath.sol": {
          "DesynSafeMath": "0xe91c89d7cc74b49579ac3a5ba68974bda8c3f547"
        },
        "contracts/libraries/RightsManager.sol": {
          "RightsManager": "0x495e73a680cd943020f18911e50c1fe5991cb770"
        },
        "contracts/libraries/SmartPoolManager.sol": {
          "SmartPoolManager": "0xce720c194b9fd6b196259807d579bbd2f53e39d8"
        }
      }
    }
  }}