Source Code
Overview
S Balance
More Info
ContractCreator
Loading...
Loading
Contract Name:
Actions
Compiler Version
v0.6.12+commit.27d51765
Optimization Enabled:
Yes with 20 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import {RightsManager} from "../libraries/RightsManager.sol"; import {SmartPoolManager} from "../libraries/SmartPoolManager.sol"; import {DesynSafeMath} from "../libraries/DesynSafeMath.sol"; import "../libraries/SafeERC20.sol"; import "../interfaces/IWETH.sol"; import "../utils/DesynReentrancyGuard.sol"; abstract contract IAggregator { enum SwapType { UNISWAPV2, UNISWAPV3, ONEINCH, CURVE } struct SwapInfoBase { address aggregator; // the swap router to use address rebalanceAdapter; SwapType swapType; } struct SwapData { uint256 quantity; bytes data; // v3: (uint,uint256[]) v2: (uint256,address[]) } function swapExactTokensForTokens(uint256, uint256, address[] calldata, address, uint256) external virtual; function uniswapV3Swap(uint256, uint256, uint256[] calldata) external virtual; } abstract contract DesynOwnable { function setController(address controller) external virtual; function setManagersInfo(address[] memory _owners, uint[] memory _ownerPercentage) external virtual; } abstract contract AbstractPool is IERC20, DesynOwnable { function setPublicSwap(bool public_) external virtual; function joinPool( uint poolAmountOut, uint[] calldata maxAmountsIn, address kol, address user ) external virtual; function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut, address user) external virtual; } abstract contract LiquidityPoolActions is AbstractPool { function finalize() external virtual; function bind( address token, uint balance, uint denorm ) external virtual; function rebind( address token, uint balance, uint denorm ) external virtual; function unbind(address token) external virtual; function isBound(address t) external view virtual returns (bool); function getCurrentTokens() external view virtual returns (address[] memory); function getFinalTokens() external view virtual returns (address[] memory); function getBalance(address token) external view virtual returns (uint); } abstract contract FactoryActions { function newLiquidityPool() external virtual returns (LiquidityPoolActions); function getModuleStatus(address etf, address module) external view virtual returns (bool); function isTokenWhitelistedForVerify(address token) external view virtual returns (bool); } abstract contract RebalaceAdapter { enum SwapType { UNISWAPV2, UNISWAPV3, ONEINCH } struct RebalanceInfo { address etf; // etf address address token0; address token1; address aggregator; // the swap router to use SwapType swapType; uint256 quantity; bytes data; // v3: (uint,uint256[]) v2: (uint256,address[]) } function rebalance(RebalanceInfo calldata rebalanceInfo) external virtual; function approve(address etf, address token, address spender, uint256 amount) external virtual; function isRouterApproved(address router) external virtual returns (bool); } abstract contract IConfigurableRightsPool is AbstractPool { struct PoolParams { string poolTokenSymbol; string poolTokenName; address[] constituentTokens; uint[] tokenBalances; uint[] tokenWeights; uint managerFee; uint redeemFee; uint issueFee; uint perfermanceFee; SmartPoolManager.Etypes etype; } struct CrpParams { uint initialSupply; uint collectPeriod; SmartPoolManager.Period period; } function createPool( address creator, uint initialSupply, uint collectPeriod, SmartPoolManager.Period period, SmartPoolManager.PoolTokenRange memory tokenRange ) external virtual; function createPool(uint initialSupply) external virtual; function setCap(uint newCap) external virtual; function commitAddToken( address token, uint balance, uint denormalizedWeight ) external virtual; function applyAddToken() external virtual; function whitelistLiquidityProvider(address provider) external virtual; function removeWhitelistedLiquidityProvider(address provider) external virtual; function bPool() external view virtual returns (LiquidityPoolActions); function addTokenToWhitelist(uint[] memory sort, address[] memory token) external virtual; function claimManagerFee() external virtual; function etype() external virtual returns(SmartPoolManager.Etypes); function vaultAddress() external virtual view returns(address); function snapshotBeginAssets() external virtual; function snapshotEndAssets() external virtual; function etfStatus() external virtual returns(SmartPoolManager.Status memory); } abstract contract ICRPFactory { function newCrp( address factoryAddress, IConfigurableRightsPool.PoolParams calldata params, RightsManager.Rights calldata rights, SmartPoolManager.KolPoolParams calldata kolPoolParams, address[] memory owners, uint[] memory ownerPercentage ) external virtual returns (IConfigurableRightsPool); } abstract contract IVault { function userVault() external virtual returns(address); } abstract contract IUserVault { function kolClaim(address pool) external virtual; function managerClaim(address pool) external virtual; function getManagerClaimBool(address pool) external view virtual returns(bool); } interface ICurve { function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) external; function coins(uint i) external view returns(address); } /********************************** WARNING **********************************/ // // // This contract is only meant to be used in conjunction with ds-proxy. // // Calling this contract directly will lead to loss of funds. // // // /********************************** WARNING **********************************/ contract Actions is DesynReentrancyGuard { using SafeERC20 for IERC20; using DesynSafeMath for uint256; IERC20 public constant STBT = IERC20(0x530824DA86689C9C17CdC2871Ff29B058345b44a); address public constant FACTORY = 0xF49a0Cab1F8B3c08d98bcf77b0b4216D24be49f2; address constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address constant WETH = 0xca0E11E5576Ff113Ff3028b940A5498dD216D18C; event SmartJoinPool(address caller, address token, uint amount, address shareReturn, uint amountReturn); event SmartExitPool(address caller, address share, uint shareAmount, address tokenReturn, uint amountReturn); // --- Pool Creation --- function create( FactoryActions factory, address[] calldata tokens, uint[] calldata balances, uint[] calldata weights, bool finalize ) external returns (LiquidityPoolActions pool) { require(tokens.length == balances.length, "ERR_LENGTH_MISMATCH"); require(tokens.length == weights.length, "ERR_LENGTH_MISMATCH"); pool = factory.newLiquidityPool(); for (uint i = 0; i < tokens.length; i++) { IERC20 token = IERC20(tokens[i]); token.safeTransferFrom(msg.sender, address(this), balances[i]); token.safeApprove(address(pool), 0); token.safeApprove(address(pool), balances[i]); pool.bind(tokens[i], balances[i], weights[i]); } if (finalize) { pool.finalize(); require(pool.transfer(msg.sender, pool.balanceOf(address(this))), "ERR_TRANSFER_FAILED"); } else { pool.setPublicSwap(true); } } function createSmartPool( ICRPFactory factory, FactoryActions coreFactory, IConfigurableRightsPool.PoolParams calldata poolParams, IConfigurableRightsPool.CrpParams calldata crpParams, RightsManager.Rights calldata rights, SmartPoolManager.KolPoolParams calldata kolPoolParams, address[] memory owners, uint[] memory ownerPercentage, SmartPoolManager.PoolTokenRange memory tokenRange ) external returns (IConfigurableRightsPool crp) { require(poolParams.constituentTokens.length == poolParams.tokenBalances.length, "ERR_LENGTH_MISMATCH"); require(poolParams.constituentTokens.length == poolParams.tokenWeights.length, "ERR_LENGTH_MISMATCH"); crp = factory.newCrp(address(coreFactory), poolParams, rights, kolPoolParams, owners, ownerPercentage); for (uint i = 0; i < poolParams.constituentTokens.length; i++) { IERC20 token = IERC20(poolParams.constituentTokens[i]); token.safeTransferFrom(msg.sender, address(this), poolParams.tokenBalances[i]); token.safeApprove(address(crp), 0); token.safeApprove(address(crp), poolParams.tokenBalances[i]); } crp.createPool(msg.sender,crpParams.initialSupply, crpParams.collectPeriod, crpParams.period, tokenRange); require(crp.transfer(msg.sender, crpParams.initialSupply), "ERR_TRANSFER_FAILED"); crp.setController(msg.sender); // DSProxy instance keeps pool ownership to enable management } // --- Joins --- function joinPool( LiquidityPoolActions pool, uint poolAmountOut, uint[] calldata maxAmountsIn ) external { address[] memory tokens = pool.getFinalTokens(); _join(pool, tokens, poolAmountOut, maxAmountsIn, msg.sender); } function autoExitSmartPool( IConfigurableRightsPool pool, uint poolAmountIn, uint[] memory minAmountsOut, uint minSwapReturn, address handleToken, IAggregator.SwapInfoBase calldata swapBase, IAggregator.SwapData[] memory swapDatas) external payable lock { address[] memory tokens = pool.bPool().getCurrentTokens(); uint len = swapDatas.length; require(FactoryActions(FACTORY).isTokenWhitelistedForVerify(handleToken),"ERR_TOKEN_NOT_WHITELISTED"); require(tokens.length == swapDatas.length,"ERR_TOKENLENGTH_MISMATCH"); require(tokens.length == minAmountsOut.length,"ERR_TOKENLENGTH_MISMATCH"); IERC20 receiveToken = IERC20(handleToken); if (handleToken == NATIVE_TOKEN) { receiveToken = IERC20(WETH); } uint preReceiveAmount = receiveToken.balanceOf(address(this)); uint[] memory initialAmounts = new uint[](len); for(uint i = 0; i < len; i++){ initialAmounts[i] = IERC20(tokens[i]).balanceOf(address(this)); } _exit(pool, poolAmountIn, minAmountsOut, tokens, true); for(uint j = 0; j < len; j++) { IAggregator.SwapData memory swapData = swapDatas[j]; IERC20 swapToken = IERC20(tokens[j]); if(tokens[j] != address(receiveToken)){ swapData.quantity = SafeMath.sub(swapToken.balanceOf(address(this)), initialAmounts[j]); swapToken.safeApprove(swapBase.aggregator, 0); swapToken.safeApprove(swapBase.aggregator, swapData.quantity); _makeSwap(swapBase, swapData, receiveToken); } } uint receiveAmount = SafeMath.sub(receiveToken.balanceOf(address(this)), preReceiveAmount); require(minSwapReturn <= receiveAmount,"ERR_RECEIVE_AMOUNT_TO_SMALL"); if (handleToken == NATIVE_TOKEN) { IWETH(WETH).withdraw(receiveAmount); msg.sender.transfer(receiveAmount); } else { receiveToken.safeTransfer(msg.sender, receiveAmount); } emit SmartExitPool(msg.sender, address(pool) ,poolAmountIn, handleToken, receiveAmount); } function joinSmartPool( IConfigurableRightsPool pool, uint poolAmountOut, uint[] calldata maxAmountsIn, address kol ) external { address[] memory tokens = pool.bPool().getCurrentTokens(); _join(pool, tokens, poolAmountOut, maxAmountsIn, kol); } struct JoinVar { uint actualShareAmountOut; uint issueFee; uint totalPoolShares; LiquidityPoolActions bPool; } function autoJoinSmartPool( IConfigurableRightsPool pool, address kol, uint issueAmount, uint minPoolAmountOut, address handleToken, IAggregator.SwapInfoBase calldata swapBase, IAggregator.SwapData[] memory swapDatas ) external payable lock { require(FactoryActions(FACTORY).isTokenWhitelistedForVerify(handleToken), "ERR_TOKEN_NOT_WHITELISTED"); address[] memory poolTokens = pool.bPool().getCurrentTokens(); require(poolTokens.length == swapDatas.length,"ERR_TOKENLENGTH_MISMATCH"); uint[] memory maxAmountsIn = new uint[](poolTokens.length); address user = msg.sender; // Transfer ETH into the contract and authorize the aggregator to operate IERC20 issueToken; if (handleToken == NATIVE_TOKEN) { require(msg.value > 0 && msg.value == issueAmount, 'ERROR_ETH'); IWETH(WETH).deposit{value: msg.value}(); issueToken = IERC20(WETH); } else { issueToken = IERC20(handleToken); issueToken.safeTransferFrom(user, address(this), issueAmount); } issueToken.safeApprove(swapBase.aggregator, 0); issueToken.safeApprove(swapBase.aggregator, issueAmount); JoinVar memory joinVar = JoinVar({ actualShareAmountOut: type(uint).max, issueFee:pool.etfStatus().issueFee, totalPoolShares:pool.totalSupply(), bPool:pool.bPool() }); // Perform a swap and authorize the pool call for (uint i; i < poolTokens.length; i++) { IAggregator.SwapData memory swapData = swapDatas[i]; poolTokens[i] == address(issueToken) ? maxAmountsIn[i] = swapData.quantity : maxAmountsIn[i] = _makeSwap(swapBase, swapData, IERC20(poolTokens[i])); uint shareAmountOutPerToken = _calculateShare(joinVar.bPool,joinVar.totalPoolShares,joinVar.issueFee, poolTokens[i], maxAmountsIn[i]); if(shareAmountOutPerToken < joinVar.actualShareAmountOut) joinVar.actualShareAmountOut = shareAmountOutPerToken; IERC20(poolTokens[i]).safeApprove(address(pool), 0); IERC20(poolTokens[i]).safeApprove(address(pool), maxAmountsIn[i]); } // Adding Tokens to a Pool require(minPoolAmountOut <= joinVar.actualShareAmountOut,"ERR_SHARE_AMOUNT_TO_SMALL"); pool.joinPool(joinVar.actualShareAmountOut, maxAmountsIn, kol, user); // Return excess funds to users for (uint i; i < poolTokens.length; i++) { IERC20 token = IERC20(poolTokens[i]); if (token.balanceOf(address(this)) > 0) token.safeTransfer(user, token.balanceOf(address(this))); } issueToken.safeTransfer(user, issueToken.balanceOf(address(this))); require(pool.transfer(user, pool.balanceOf(address(this))), "ERR_TRANSFER_FAILED"); emit SmartJoinPool(msg.sender, handleToken, issueAmount, address(pool), joinVar.actualShareAmountOut); } function exitPool( IConfigurableRightsPool pool, uint poolAmountIn, uint[] memory minAmountsOut ) external { address[] memory tokens = pool.bPool().getCurrentTokens(); _exit(pool, poolAmountIn, minAmountsOut, tokens, false); } // --- Pool management (common) --- function setPublicSwap(AbstractPool pool, bool publicSwap) external { pool.setPublicSwap(publicSwap); } function setController(AbstractPool pool, address newController) external { _beforeOwnerChange(address(pool)); pool.setController(newController); } function setManagersInfo(AbstractPool pool ,address[] memory _owners, uint[] memory _ownerPercentage) public { _beforeOwnerChange(address(pool)); pool.setManagersInfo(_owners, _ownerPercentage); } function _beforeOwnerChange(address pool) internal { claimManagementFee(IConfigurableRightsPool(pool)); _claimManagersReward(pool); } function snapshotBeginAssets(IConfigurableRightsPool pool) external virtual { pool.snapshotBeginAssets(); } function snapshotEndAssets(IConfigurableRightsPool pool) external virtual { pool.snapshotEndAssets(); } function approveUnderlying(RebalaceAdapter rebalanceAdapter, address etf, address token, address spender, uint amount) external { rebalanceAdapter.approve(etf, token, spender, amount); } function rebalance(RebalaceAdapter rebalanceAdapter, RebalaceAdapter.RebalanceInfo calldata rebalanceInfo) external { rebalanceAdapter.rebalance(rebalanceInfo); } // --- Private pool management --- function finalize(LiquidityPoolActions pool) external { pool.finalize(); require(pool.transfer(msg.sender, pool.balanceOf(address(this))), "ERR_TRANSFER_FAILED"); } // --- Smart pool management --- function setCap(IConfigurableRightsPool crp, uint newCap) external { crp.setCap(newCap); } function whitelistLiquidityProvider(IConfigurableRightsPool crp, address provider) external { crp.whitelistLiquidityProvider(provider); } function removeWhitelistedLiquidityProvider(IConfigurableRightsPool crp, address provider) external { crp.removeWhitelistedLiquidityProvider(provider); } function addTokenToWhitelist(IConfigurableRightsPool crp, uint[] memory sort, address[] memory token) public { crp.addTokenToWhitelist(sort, token); } function claimManagementFee(IConfigurableRightsPool crp) public { crp.claimManagerFee(); } // --- Internals --- function _safeApprove( IERC20 token, address spender, uint amount ) internal { if (token.allowance(address(this), spender) > 0) { token.approve(spender, 0); } token.approve(spender, amount); } function _join( AbstractPool pool, address[] memory tokens, uint poolAmountOut, uint[] memory maxAmountsIn, address kol ) internal { require(maxAmountsIn.length == tokens.length, "ERR_LENGTH_MISMATCH"); for (uint i = 0; i < tokens.length; i++) { IERC20 token = IERC20(tokens[i]); token.safeTransferFrom(msg.sender, address(this), maxAmountsIn[i]); token.safeApprove(address(pool), 0); token.safeApprove(address(pool), maxAmountsIn[i]); } pool.joinPool(poolAmountOut, maxAmountsIn, kol, msg.sender); for (uint i = 0; i < tokens.length; i++) { IERC20 token = IERC20(tokens[i]); if (token.balanceOf(address(this)) > 0) { token.safeTransfer(msg.sender, token.balanceOf(address(this))); } } require(pool.transfer(msg.sender, pool.balanceOf(address(this))), "ERR_TRANSFER_FAILED"); } function _exit( IConfigurableRightsPool pool, uint poolAmountIn, uint[] memory minAmountsOut, address[] memory tokens, bool isSmartMode ) internal { uint shareToBurn = poolAmountIn; if (pool.etype() == SmartPoolManager.Etypes.CLOSED) { shareToBurn = pool.balanceOf(msg.sender); } require(pool.transferFrom(msg.sender, address(this), shareToBurn), "ERR_TRANSFER_FAILED"); // _safeApprove(pool, address(pool), shareToBurn); pool.exitPool(shareToBurn, minAmountsOut, msg.sender); if(!isSmartMode){ for (uint i = 0; i < tokens.length; i++) { IERC20 token = IERC20(tokens[i]); if (token.balanceOf(address(this)) > 0) { token.safeTransfer(msg.sender, token.balanceOf(address(this))); } } } } function claimKolReward(address pool) public { address uservault = _getUserVault(pool); IUserVault(uservault).kolClaim(pool); } function claimManagersReward(address vault_,address pool) external { IUserVault(vault_).managerClaim(pool); } function _claimManagersReward(address pool) internal { address vault = _getVault(pool); address uservault = _getUserVault(pool); bool vaultCanClaim = IUserVault(vault).getManagerClaimBool(pool); bool uservaultCanClaim = IUserVault(uservault).getManagerClaimBool(pool); SmartPoolManager.Etypes type_ = IConfigurableRightsPool(pool).etype(); if(type_ == SmartPoolManager.Etypes.OPENED && vaultCanClaim) IUserVault(vault).managerClaim(pool); if(type_ == SmartPoolManager.Etypes.CLOSED && uservaultCanClaim) IUserVault(uservault).managerClaim(pool); } function _makeSwap(IAggregator.SwapInfoBase calldata swapBase, IAggregator.SwapData memory swapData, IERC20 swapAcceptToken) internal returns (uint256 postSwap) { require(FactoryActions(FACTORY).getModuleStatus(address(0), swapBase.rebalanceAdapter), 'MODULE_ILLEGAL'); require(RebalaceAdapter(swapBase.rebalanceAdapter).isRouterApproved(swapBase.aggregator), 'ROUTER_ILLEGAL'); uint preSwap = swapAcceptToken.balanceOf(address(this)); if (swapBase.swapType == IAggregator.SwapType.UNISWAPV3) { (uint256 minReturn, uint256[] memory pools) = abi.decode(swapData.data, (uint256, uint256[])); IAggregator(swapBase.aggregator).uniswapV3Swap(swapData.quantity, minReturn, pools); } else if (swapBase.swapType == IAggregator.SwapType.UNISWAPV2) { (uint256 minReturn, address[] memory paths) = abi.decode(swapData.data, (uint256, address[])); IAggregator(swapBase.aggregator).swapExactTokensForTokens(swapData.quantity, minReturn, paths, address(this), SafeMath.add(block.timestamp, 1800)); } else if (swapBase.swapType == IAggregator.SwapType.ONEINCH){ Address.functionCallWithValue(swapBase.aggregator, swapData.data, 0); // _validateData(swapBase.quantity, swapBase.data, address(this)); } else if (swapBase.swapType == IAggregator.SwapType.CURVE){ // only supports stbt/usdc/usdt/dai curve pool (int128 i, int128 j, uint256 dx, uint256 minDy) = abi.decode(swapData.data, (int128, int128, uint256, uint256)); ICurve(swapBase.aggregator).exchange_underlying(i, j, dx, minDy); } else { revert("ERR_INVALID_SWAP_TYPE"); } postSwap = SafeMath.sub(swapAcceptToken.balanceOf(address(this)), preSwap); } function _getVault(address pool) internal view returns(address){ return IConfigurableRightsPool(pool).vaultAddress(); } function _getUserVault(address pool) internal returns(address){ address vault = _getVault(pool); return IVault(vault).userVault(); } function _calculateShare(LiquidityPoolActions bPool,uint totalPoolShares, uint issueFee, address t, uint actualTokenAmountIn) internal view returns(uint) { uint totalTokenBalance = bPool.getBalance(t); uint issueFeeRate = issueFee.bmul(1000); uint share = (totalPoolShares.bsub(1).bmul(actualTokenAmountIn) * (uint(1000).bsub(issueFeeRate))).bdiv((1000 * totalTokenBalance.badd(1))); return share; } receive() external payable {} }
// This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; import "../base/Math.sol"; import "../base/Num.sol"; // Contract to wrap internal functions for testing contract TMath is Math { function calc_btoi(uint a) external pure returns (uint) { return btoi(a); } function calc_bfloor(uint a) external pure returns (uint) { return bfloor(a); } function calc_badd(uint a, uint b) external pure returns (uint) { return badd(a, b); } function calc_bsub(uint a, uint b) external pure returns (uint) { return bsub(a, b); } function calc_bsubSign(uint a, uint b) external pure returns (uint, bool) { return bsubSign(a, b); } function calc_bmul(uint a, uint b) external pure returns (uint) { return bmul(a, b); } function calc_bdiv(uint a, uint b) external pure returns (uint) { return bdiv(a, b); } function calc_bpowi(uint a, uint n) external pure returns (uint) { return bpowi(a, n); } function calc_bpow(uint base, uint exp) external pure returns (uint) { return bpow(base, exp); } function calc_bpowApprox( uint base, uint exp, uint precision ) external pure returns (uint) { return bpowApprox(base, exp, precision); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; import "./Num.sol"; contract Math is BBronze, Const, Num { /********************************************************************************************** // calcSpotPrice // // sP = spotPrice // // bI = tokenBalanceIn ( bI / wI ) 1 // // bO = tokenBalanceOut sP = ----------- * ---------- // // wI = tokenWeightIn ( bO / wO ) ( 1 - sF ) // // wO = tokenWeightOut // // sF = swapFee // **********************************************************************************************/ function calcSpotPrice( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint swapFee ) external pure returns (uint spotPrice) { uint numer = bdiv(tokenBalanceIn, tokenWeightIn); uint denom = bdiv(tokenBalanceOut, tokenWeightOut); uint ratio = bdiv(numer, denom); uint scale = bdiv(BONE, bsub(BONE, swapFee)); return (spotPrice = bmul(ratio, scale)); } /********************************************************************************************** // calcOutGivenIn // // aO = tokenAmountOut // // bO = tokenBalanceOut // // bI = tokenBalanceIn / / bI \ (wI / wO) \ // // aI = tokenAmountIn aO = bO * | 1 - | -------------------------- | ^ | // // wI = tokenWeightIn \ \ ( bI + ( aI * ( 1 - sF )) / / // // wO = tokenWeightOut // // sF = swapFee // **********************************************************************************************/ function calcOutGivenIn( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint tokenAmountIn, uint swapFee ) external pure returns (uint tokenAmountOut) { uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut); uint adjustedIn = bsub(BONE, swapFee); adjustedIn = bmul(tokenAmountIn, adjustedIn); uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn)); uint foo = bpow(y, weightRatio); uint bar = bsub(BONE, foo); tokenAmountOut = bmul(tokenBalanceOut, bar); return tokenAmountOut; } /********************************************************************************************** // calcInGivenOut // // aI = tokenAmountIn // // bO = tokenBalanceOut / / bO \ (wO / wI) \ // // bI = tokenBalanceIn bI * | | ------------ | ^ - 1 | // // aO = tokenAmountOut aI = \ \ ( bO - aO ) / / // // wI = tokenWeightIn -------------------------------------------- // // wO = tokenWeightOut ( 1 - sF ) // // sF = swapFee // **********************************************************************************************/ function calcInGivenOut( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint tokenAmountOut, uint swapFee ) external pure returns (uint tokenAmountIn) { uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn); uint diff = bsub(tokenBalanceOut, tokenAmountOut); uint y = bdiv(tokenBalanceOut, diff); uint foo = bpow(y, weightRatio); foo = bsub(foo, BONE); tokenAmountIn = bsub(BONE, swapFee); tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn); return tokenAmountIn; } /********************************************************************************************** // calcPoolOutGivenSingleIn // // pAo = poolAmountOut / \ // // tAi = tokenAmountIn /// / // wI \ \\ \ wI \ // // wI = tokenWeightIn //| tAi *| 1 - || 1 - -- | * sF || + tBi \ -- \ // // tW = totalWeight pAo=|| \ \ \\ tW / // | ^ tW | * pS - pS // // tBi = tokenBalanceIn \\ ------------------------------------- / / // // pS = poolSupply \\ tBi / / // // sF = swapFee \ / // **********************************************************************************************/ function calcPoolOutGivenSingleIn( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint tokenAmountIn, uint swapFee ) external pure returns (uint poolAmountOut) { // Charge the trading fee for the proportion of tokenAi // which is implicitly traded to the other pool tokens. // That proportion is (1- weightTokenIn) // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee); uint normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz)); uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee); uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn); // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply; uint poolRatio = bpow(tokenInRatio, normalizedWeight); uint newPoolSupply = bmul(poolRatio, poolSupply); poolAmountOut = bsub(newPoolSupply, poolSupply); return poolAmountOut; } /********************************************************************************************** // calcSingleInGivenPoolOut // // tAi = tokenAmountIn //(pS + pAo)\ / 1 \\ // // pS = poolSupply || --------- | ^ | --------- || * bI - bI // // pAo = poolAmountOut \\ pS / \(wI / tW)// // // bI = balanceIn tAi = -------------------------------------------- // // wI = weightIn / wI \ // // tW = totalWeight | 1 - ---- | * sF // // sF = swapFee \ tW / // **********************************************************************************************/ function calcSingleInGivenPoolOut( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint poolAmountOut, uint swapFee ) external pure returns (uint tokenAmountIn) { uint normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint newPoolSupply = badd(poolSupply, poolAmountOut); uint poolRatio = bdiv(newPoolSupply, poolSupply); //uint newBalTi = poolRatio^(1/weightTi) * balTi; uint boo = bdiv(BONE, normalizedWeight); uint tokenInRatio = bpow(poolRatio, boo); uint newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn); uint tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn); // Do reverse order of fees charged in joinswap_ExternAmountIn, this way // ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ``` //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ; uint zar = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar)); return tokenAmountIn; } /********************************************************************************************** // calcSingleOutGivenPoolIn // // tAo = tokenAmountOut / / \\ // // bO = tokenBalanceOut / // pS - (pAi * (1 - eF)) \ / 1 \ \\ // // pAi = poolAmountIn | bO - || ----------------------- | ^ | --------- | * b0 || // // ps = poolSupply \ \\ pS / \(wO / tW)/ // // // wI = tokenWeightIn tAo = \ \ // // // tW = totalWeight / / wO \ \ // // sF = swapFee * | 1 - | 1 - ---- | * sF | // // eF = exitFee \ \ tW / / // **********************************************************************************************/ function calcSingleOutGivenPoolIn( uint tokenBalanceOut, uint tokenWeightOut, uint poolSupply, uint totalWeight, uint poolAmountIn, uint swapFee ) external pure returns (uint tokenAmountOut) { uint normalizedWeight = bdiv(tokenWeightOut, totalWeight); // charge exit fee on the pool token side // pAiAfterExitFee = pAi*(1-exitFee) uint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE)); uint newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee); uint poolRatio = bdiv(newPoolSupply, poolSupply); // newBalTo = poolRatio^(1/weightTo) * balTo; uint tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight)); uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut); uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut); // charge swap fee on the output token side //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee) uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz)); return tokenAmountOut; } /********************************************************************************************** // calcPoolInGivenSingleOut // // pAi = poolAmountIn // / tAo \\ / wO \ \ // // bO = tokenBalanceOut // | bO - -------------------------- |\ | ---- | \ // // tAo = tokenAmountOut pS - || \ 1 - ((1 - (tO / tW)) * sF)/ | ^ \ tW / * pS | // // ps = poolSupply \\ -----------------------------------/ / // // wO = tokenWeightOut pAi = \\ bO / / // // tW = totalWeight ------------------------------------------------------------- // // sF = swapFee ( 1 - eF ) // // eF = exitFee // **********************************************************************************************/ function calcPoolInGivenSingleOut( uint tokenBalanceOut, uint tokenWeightOut, uint poolSupply, uint totalWeight, uint tokenAmountOut, uint swapFee ) external pure returns (uint poolAmountIn) { // charge swap fee on the output token side uint normalizedWeight = bdiv(tokenWeightOut, totalWeight); //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ; uint zoo = bsub(BONE, normalizedWeight); uint zar = bmul(zoo, swapFee); uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar)); uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee); uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut); //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply; uint poolRatio = bpow(tokenOutRatio, normalizedWeight); uint newPoolSupply = bmul(poolRatio, poolSupply); uint poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply); // charge exit fee on the pool token side // pAi = pAiAfterExitFee/(1-exitFee) poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE)); return poolAmountIn; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; import "./Const.sol"; // Core contract; can't be changed. So disable solhint (reminder for v2) /* solhint-disable private-vars-leading-underscore */ contract Num is Const { function btoi(uint a) internal pure returns (uint) { return a / BONE; } function bfloor(uint a) internal pure returns (uint) { return btoi(a) * BONE; } function badd(uint a, uint b) internal pure returns (uint) { uint c = a + b; require(c >= a, "ERR_ADD_OVERFLOW"); return c; } function bsub(uint a, uint b) internal pure returns (uint) { (uint c, bool flag) = bsubSign(a, b); require(!flag, "ERR_SUB_UNDERFLOW"); return c; } function bsubSign(uint a, uint b) internal pure returns (uint, bool) { if (a >= b) { return (a - b, false); } else { return (b - a, true); } } function bmul(uint a, uint b) internal pure returns (uint) { uint c0 = a * b; require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW"); uint c1 = c0 + (BONE / 2); require(c1 >= c0, "ERR_MUL_OVERFLOW"); uint c2 = c1 / BONE; return c2; } function bdiv(uint a, uint b) internal pure returns (uint) { require(b != 0, "ERR_DIV_ZERO"); uint c0 = a * BONE; require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow uint c1 = c0 + (b / 2); require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require uint c2 = c1 / b; return c2; } // DSMath.wpow function bpowi(uint a, uint n) internal pure returns (uint) { uint z = n % 2 != 0 ? a : BONE; for (n /= 2; n != 0; n /= 2) { a = bmul(a, a); if (n % 2 != 0) { z = bmul(z, a); } } return z; } // Compute b^(e.w) by splitting it into (b^e)*(b^0.w). // Use `bpowi` for `b^e` and `bpowK` for k iterations // of approximation of b^0.w function bpow(uint base, uint exp) internal pure returns (uint) { require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW"); require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH"); uint whole = bfloor(exp); uint remain = bsub(exp, whole); uint wholePow = bpowi(base, btoi(whole)); if (remain == 0) { return wholePow; } uint partialResult = bpowApprox(base, remain, BPOW_PRECISION); return bmul(wholePow, partialResult); } function bpowApprox( uint base, uint exp, uint precision ) internal pure returns (uint) { // term 0: uint a = exp; (uint x, bool xneg) = bsubSign(base, BONE); uint term = BONE; uint sum = term; bool negative = false; // term(k) = numer / denom // = (product(a - i - 1, i=1-->k) * x^k) / (k!) // each iteration, multiply previous term by (a-(k-1)) * x / k // continue until term is less than precision for (uint i = 1; term >= precision; i++) { uint bigK = i * BONE; (uint c, bool cneg) = bsubSign(a, bsub(bigK, BONE)); term = bmul(term, bmul(c, x)); term = bdiv(term, bigK); if (term == 0) break; if (xneg) negative = !negative; if (cneg) negative = !negative; if (negative) { sum = bsub(sum, term); } else { sum = badd(sum, term); } } return sum; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; import "./Color.sol"; contract Const is BBronze { uint public constant BONE = 10**18; uint public constant MIN_BOUND_TOKENS = 1; uint public constant MAX_BOUND_TOKENS = 16; uint public constant MIN_FEE = BONE / 10**6; uint public constant MAX_FEE = BONE / 10; uint public constant EXIT_FEE = 0; uint public constant MIN_WEIGHT = BONE; uint public constant MAX_WEIGHT = BONE * 50; uint public constant MAX_TOTAL_WEIGHT = BONE * 50; uint public constant MIN_BALANCE = 0; uint public constant INIT_POOL_SUPPLY = BONE * 100; uint public constant MIN_BPOW_BASE = 1 wei; uint public constant MAX_BPOW_BASE = (2 * BONE) - 1 wei; uint public constant BPOW_PRECISION = BONE / 10**10; uint public constant MAX_IN_RATIO = BONE / 2; uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // abstract contract BColor { // function getColor() // external view virtual // returns (bytes32); // } contract BBronze { function getColor() external pure returns (bytes32) { return bytes32("BRONZE"); } }
pragma solidity 0.6.12; import "../base/Num.sol"; import "../interfaces/IERC20.sol"; import "../interfaces/AggregatorV2V3Interface.sol"; import "../interfaces/IUniswapOracle.sol"; library SafeMath { function add(uint a, uint b) internal pure returns (uint) { uint c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint a, uint b) internal pure returns (uint) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub( uint a, uint b, string memory errorMessage ) internal pure returns (uint) { require(b <= a, errorMessage); uint c = a - b; return c; } function mul(uint a, uint b) internal pure returns (uint) { if (a == 0) { return 0; } uint c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint a, uint b) internal pure returns (uint) { return div(a, b, "SafeMath: division by zero"); } function div( uint a, uint b, string memory errorMessage ) internal pure returns (uint) { require(b > 0, errorMessage); uint c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function mod(uint a, uint b) internal pure returns (uint) { return mod(a, b, "SafeMath: modulo by zero"); } function mod( uint a, uint b, string memory errorMessage ) internal pure returns (uint) { require(b != 0, errorMessage); return a % b; } function abs(uint a, uint b) internal pure returns(uint result, bool isFirstBigger) { if(a > b){ result = a - b; isFirstBigger = true; } else { result = b - a; isFirstBigger = false; } } } contract DesynChainlinkOracle is Num { address public admin; using SafeMath for uint; IUniswapOracle public twapOracle; mapping(address => uint) internal prices; mapping(bytes32 => AggregatorV2V3Interface) internal feeds; event PricePosted(address asset, uint previousPriceMantissa, uint requestedPriceMantissa, uint newPriceMantissa); event NewAdmin(address oldAdmin, address newAdmin); event FeedSet(address feed, string symbol); constructor(address twapOracle_) public { admin = msg.sender; twapOracle = IUniswapOracle(twapOracle_); } function getPrice(address tokenAddress) public returns (uint price) { IERC20 token = IERC20(tokenAddress); AggregatorV2V3Interface feed = getFeed(token.symbol()); if (prices[address(token)] != 0) { price = prices[address(token)]; } else if (address(feed) != address(0)) { price = getChainlinkPrice(feed); } else { try twapOracle.update(address(token)) {} catch {} price = getUniswapPrice(tokenAddress); } (uint decimalDelta, bool isUnderFlow18) = uint(18).abs(uint(token.decimals())); if(isUnderFlow18){ return price.mul(10**decimalDelta); } if(!isUnderFlow18){ return price.div(10**decimalDelta); } } function getAllPrice(address[] calldata poolTokens, uint[] calldata actualAmountsOut) external returns (uint fundAll) { require(poolTokens.length == actualAmountsOut.length, "Invalid Length"); for (uint i = 0; i < poolTokens.length; i++) { address t = poolTokens[i]; uint tokenAmountOut = actualAmountsOut[i]; fundAll = badd(fundAll, bmul(getPrice(t), tokenAmountOut)); } } function getChainlinkPrice(AggregatorV2V3Interface feed) internal view returns (uint) { // Chainlink USD-denominated feeds store answers at 8 decimals uint decimalDelta = bsub(uint(18), feed.decimals()); // Ensure that we don't multiply the result by 0 if (decimalDelta > 0) { return uint(feed.latestAnswer()).mul(10**decimalDelta); } else { return uint(feed.latestAnswer()); } } function getUniswapPrice(address tokenAddress) internal view returns (uint) { IERC20 token = IERC20(tokenAddress); uint price = twapOracle.consult(tokenAddress, uint(10) ** token.decimals()); return price; } function setDirectPrice(address asset, uint price) external onlyAdmin { emit PricePosted(asset, prices[asset], price, price); prices[asset] = price; } function setFeed(string calldata symbol, address feed) external onlyAdmin { require(feed != address(0) && feed != address(this), "invalid feed address"); emit FeedSet(feed, symbol); feeds[keccak256(abi.encodePacked(symbol))] = AggregatorV2V3Interface(feed); } function getFeed(string memory symbol) public view returns (AggregatorV2V3Interface) { return feeds[keccak256(abi.encodePacked(symbol))]; } function assetPrices(address asset) external view returns (uint) { return prices[asset]; } function compareStrings(string memory a, string memory b) internal pure returns (bool) { return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); } function setAdmin(address newAdmin) external onlyAdmin { require(newAdmin != address(0),"ERR_ZERO_ADDRESS"); address oldAdmin = admin; admin = newAdmin; emit NewAdmin(oldAdmin, newAdmin); } modifier onlyAdmin() { require(msg.sender == admin, "only admin may call"); _; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Interface declarations /* solhint-disable func-order */ interface IERC20 { // Emitted when the allowance of a spender for an owner is set by a call to approve. // Value is the new allowance event Approval(address indexed owner, address indexed spender, uint value); // Emitted when value tokens are moved from one account (from) to another (to). // Note that value may be zero event Transfer(address indexed from, address indexed to, uint value); // Returns the amount of tokens in existence function totalSupply() external view returns (uint); // Returns the amount of tokens owned by account function balanceOf(address account) external view returns (uint); // Returns the decimals of tokens function decimals() external view returns (uint8); function symbol() external view returns (string memory); // Returns the remaining number of tokens that spender will be allowed to spend on behalf of owner // through transferFrom. This is zero by default // This value changes when approve or transferFrom are called function allowance(address owner, address spender) external view returns (uint); // Sets amount as the allowance of spender over the caller’s tokens // Returns a boolean value indicating whether the operation succeeded // Emits an Approval event. function approve(address spender, uint amount) external returns (bool); // Moves amount tokens from the caller’s account to recipient // Returns a boolean value indicating whether the operation succeeded // Emits a Transfer event. function transfer(address recipient, uint amount) external returns (bool); // Moves amount tokens from sender to recipient using the allowance mechanism // Amount is then deducted from the caller’s allowance // Returns a boolean value indicating whether the operation succeeded // Emits a Transfer event function transferFrom( address sender, address recipient, uint amount ) external returns (bool); }
pragma solidity 0.6.12; /** * @title The V2 & V3 Aggregator Interface * @notice Solidity V0.5 does not allow interfaces to inherit from other * interfaces so this contract is a combination of v0.5 AggregatorInterface.sol * and v0.5 AggregatorV3Interface.sol. */ interface AggregatorV2V3Interface { // // V2 Interface: // function latestAnswer() external view returns (int); function latestTimestamp() external view returns (uint); function latestRound() external view returns (uint); function getAnswer(uint roundId) external view returns (int); function getTimestamp(uint roundId) external view returns (uint); event AnswerUpdated(int indexed current, uint indexed roundId, uint timestamp); event NewRound(uint indexed roundId, address indexed startedBy, uint startedAt); // // V3 Interface: // function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int answer, uint startedAt, uint updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int answer, uint startedAt, uint updatedAt, uint80 answeredInRound ); }
pragma solidity 0.6.12; interface IUniswapOracle { function update(address token) external; function consult(address token, uint amountIn) external view returns (uint amountOut); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to pass in structs pragma experimental ABIEncoderV2; // Imports import "../interfaces/IERC20.sol"; import "../interfaces/IConfigurableRightsPool.sol"; import "../interfaces/IBFactory.sol"; // unused import "./DesynSafeMath.sol"; import "./SafeMath.sol"; // import "./SafeApprove.sol"; import "../libraries/SafeERC20.sol"; /** * @author Desyn Labs * @title Factor out the weight updates */ library SmartPoolManager { // using SafeApprove for IERC20; using DesynSafeMath for uint; using SafeMath for uint; using SafeERC20 for IERC20; //kol pool params struct levelParams { uint level; uint ratio; } struct feeParams { levelParams firstLevel; levelParams secondLevel; levelParams thirdLevel; levelParams fourLevel; } struct KolPoolParams { feeParams managerFee; feeParams issueFee; feeParams redeemFee; feeParams perfermanceFee; } // Type declarations enum Etypes { OPENED, CLOSED } enum Period { DAY90, DAY180, DAY360, DAY1, DAY3, DAY7, DAY14, DAY30 } struct Fund { uint etfAmount; uint fundAmount; uint snapshotTime; address[] tokens; uint[] tokensAmount; } // updateWeight and pokeWeights are unavoidably long /* solhint-disable function-max-lines */ struct Status { uint collectPeriod; uint collectEndTime; uint closurePeriod; uint closureEndTime; uint upperCap; uint floorCap; uint managerFee; uint redeemFee; uint issueFee; uint perfermanceFee; uint startClaimFeeTime; } struct PoolParams { // Desyn Pool Token (representing shares of the pool) string poolTokenSymbol; string poolTokenName; // Tokens inside the Pool address[] constituentTokens; uint[] tokenBalances; uint[] tokenWeights; uint managerFee; uint redeemFee; uint issueFee; uint perfermanceFee; Etypes etype; } struct PoolTokenRange { uint bspFloor; uint bspCap; } function initRequire( uint managerFee, uint issueFee, uint redeemFee, uint perfermanceFee, uint tokenBalancesLength, uint tokenWeightsLength, uint constituentTokensLength, bool initBool ) external pure { // We don't have a pool yet; check now or it will fail later (in order of likelihood to fail) // (and be unrecoverable if they don't have permission set to change it) // Most likely to fail, so check first require(!initBool, "Init fail"); require(managerFee >= DesynConstants.MANAGER_MIN_FEE, "ERR_INVALID_MANAGER_FEE"); require(managerFee <= DesynConstants.MANAGER_MAX_FEE, "ERR_INVALID_MANAGER_FEE"); require(issueFee >= DesynConstants.ISSUE_MIN_FEE, "ERR_INVALID_ISSUE_MIN_FEE"); require(issueFee <= DesynConstants.ISSUE_MAX_FEE, "ERR_INVALID_ISSUE_MAX_FEE"); require(redeemFee >= DesynConstants.REDEEM_MIN_FEE, "ERR_INVALID_REDEEM_MIN_FEE"); require(redeemFee <= DesynConstants.REDEEM_MAX_FEE, "ERR_INVALID_REDEEM_MAX_FEE"); require(perfermanceFee >= DesynConstants.PERFERMANCE_MIN_FEE, "ERR_INVALID_PERFERMANCE_MIN_FEE"); require(perfermanceFee <= DesynConstants.PERFERMANCE_MAX_FEE, "ERR_INVALID_PERFERMANCE_MAX_FEE"); // Arrays must be parallel require(tokenBalancesLength == constituentTokensLength, "ERR_START_BALANCES_MISMATCH"); require(tokenWeightsLength == constituentTokensLength, "ERR_START_WEIGHTS_MISMATCH"); // Cannot have too many or too few - technically redundant, since BPool.bind() would fail later // But if we don't check now, we could have a useless contract with no way to create a pool require(constituentTokensLength >= DesynConstants.MIN_ASSET_LIMIT, "ERR_TOO_FEW_TOKENS"); require(constituentTokensLength <= DesynConstants.MAX_ASSET_LIMIT, "ERR_TOO_MANY_TOKENS"); // There are further possible checks (e.g., if they use the same token twice), but // we can let bind() catch things like that (i.e., not things that might reasonably work) } /** * @notice Non ERC20-conforming tokens are problematic; don't allow them in pools * @dev Will revert if invalid * @param token - The prospective token to verify */ function verifyTokenCompliance(address token) external { verifyTokenComplianceInternal(token); } /** * @notice Non ERC20-conforming tokens are problematic; don't allow them in pools * @dev Will revert if invalid - overloaded to save space in the main contract * @param tokens - The prospective tokens to verify */ function verifyTokenCompliance(address[] calldata tokens) external { for (uint i = 0; i < tokens.length; i++) { verifyTokenComplianceInternal(tokens[i]); } } function createPoolInternalHandle(IBPool bPool, uint initialSupply) external view { require(initialSupply >= DesynConstants.MIN_POOL_SUPPLY, "ERR_INIT_SUPPLY_MIN"); require(initialSupply <= DesynConstants.MAX_POOL_SUPPLY, "ERR_INIT_SUPPLY_MAX"); require(bPool.EXIT_FEE() == 0, "ERR_NONZERO_EXIT_FEE"); // EXIT_FEE must always be zero, or ConfigurableRightsPool._pushUnderlying will fail require(DesynConstants.EXIT_FEE == 0, "ERR_NONZERO_EXIT_FEE"); } function createPoolHandle( uint collectPeriod, uint upperCap, uint initialSupply ) external pure { require(collectPeriod <= DesynConstants.MAX_COLLECT_PERIOD, "ERR_EXCEEDS_FUND_RAISING_PERIOD"); require(upperCap >= initialSupply, "ERR_CAP_BIGGER_THAN_INITSUPPLY"); } function exitPoolHandleA( IConfigurableRightsPool self, IBPool bPool, address poolToken, uint _tokenAmountOut, uint redeemFee ) external returns ( uint redeemAndPerformanceFeeReceived, uint finalAmountOut, uint redeemFeeReceived ) { // redeem fee redeemFeeReceived = DesynSafeMath.bmul(_tokenAmountOut, redeemFee); // performance fee uint performanceFeeReceived = 0; // redeem fee and performance fee redeemAndPerformanceFeeReceived = DesynSafeMath.badd(performanceFeeReceived, redeemFeeReceived); // final amount the user got finalAmountOut = DesynSafeMath.bsub(_tokenAmountOut, redeemAndPerformanceFeeReceived); _pushUnderlying(bPool, poolToken, msg.sender, finalAmountOut); if (redeemFee != 0) { _pushUnderlying(bPool, poolToken, address(this), redeemAndPerformanceFeeReceived); IERC20(poolToken).safeApprove(self.vaultAddress(), 0); IERC20(poolToken).safeApprove(self.vaultAddress(), redeemAndPerformanceFeeReceived); } } function exitPoolHandleB( IConfigurableRightsPool self, bool bools, bool isCompletedCollect, uint closureEndTime, uint collectEndTime, // uint _etfAmount, // uint _fundAmount, uint poolAmountIn ) external view returns (uint actualPoolAmountIn) { actualPoolAmountIn = poolAmountIn; if (bools) { bool isCloseEtfCollectEndWithFailure = isCompletedCollect == false && block.timestamp >= collectEndTime; bool isCloseEtfClosureEnd = block.timestamp >= closureEndTime; require(isCloseEtfCollectEndWithFailure || isCloseEtfClosureEnd, "ERR_CLOSURE_TIME_NOT_ARRIVED!"); actualPoolAmountIn = self.balanceOf(msg.sender); } // fundAmount = _fundAmount; // etfAmount = _etfAmount; } function joinPoolHandle( bool canWhitelistLPs, bool isList, bool bools, uint collectEndTime ) external view { require(!canWhitelistLPs || isList, "ERR_NOT_ON_WHITELIST"); if (bools) { require(block.timestamp <= collectEndTime, "ERR_COLLECT_PERIOD_FINISHED!"); } } /** * @notice Join a pool * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param poolAmountOut - number of pool tokens to receive * @param maxAmountsIn - Max amount of asset tokens to spend * @return actualAmountsIn - calculated values of the tokens to pull in */ function joinPool( IConfigurableRightsPool self, IBPool bPool, uint poolAmountOut, uint[] calldata maxAmountsIn, uint issueFee ) external view returns (uint[] memory actualAmountsIn) { address[] memory tokens = bPool.getCurrentTokens(); require(maxAmountsIn.length == tokens.length, "ERR_AMOUNTS_MISMATCH"); uint poolTotal = self.totalSupply(); // Subtract 1 to ensure any rounding errors favor the pool uint ratio = DesynSafeMath.bdiv(poolAmountOut, DesynSafeMath.bsub(poolTotal, 1)); require(ratio != 0, "ERR_MATH_APPROX"); // We know the length of the array; initialize it, and fill it below // Cannot do "push" in memory actualAmountsIn = new uint[](tokens.length); // This loop contains external calls // External calls are to math libraries or the underlying pool, so low risk uint issueFeeRate = issueFee.bmul(1000); for (uint i = 0; i < tokens.length; i++) { address t = tokens[i]; uint bal = bPool.getBalance(t); // Add 1 to ensure any rounding errors favor the pool uint base = bal.badd(1).bmul(poolAmountOut * uint(1000)); uint tokenAmountIn = base.bdiv(poolTotal.bsub(1) * (uint(1000).bsub(issueFeeRate))); require(tokenAmountIn != 0, "ERR_MATH_APPROX"); require(tokenAmountIn <= maxAmountsIn[i], "ERR_LIMIT_IN"); actualAmountsIn[i] = tokenAmountIn; } } /** * @notice Exit a pool - redeem pool tokens for underlying assets * @param self - ConfigurableRightsPool instance calling the library * @param bPool - Core BPool the CRP is wrapping * @param poolAmountIn - amount of pool tokens to redeem * @param minAmountsOut - minimum amount of asset tokens to receive * @return actualAmountsOut - calculated amounts of each token to pull */ function exitPool( IConfigurableRightsPool self, IBPool bPool, uint poolAmountIn, uint[] calldata minAmountsOut ) external view returns (uint[] memory actualAmountsOut) { address[] memory tokens = bPool.getCurrentTokens(); require(minAmountsOut.length == tokens.length, "ERR_AMOUNTS_MISMATCH"); uint poolTotal = self.totalSupply(); uint ratio = DesynSafeMath.bdiv(poolAmountIn, DesynSafeMath.badd(poolTotal, 1)); require(ratio != 0, "ERR_MATH_APPROX"); actualAmountsOut = new uint[](tokens.length); // This loop contains external calls // External calls are to math libraries or the underlying pool, so low risk for (uint i = 0; i < tokens.length; i++) { address t = tokens[i]; uint bal = bPool.getBalance(t); // Subtract 1 to ensure any rounding errors favor the pool uint tokenAmountOut = DesynSafeMath.bmul(ratio, DesynSafeMath.bsub(bal, 1)); require(tokenAmountOut != 0, "ERR_MATH_APPROX"); require(tokenAmountOut >= minAmountsOut[i], "ERR_LIMIT_OUT"); actualAmountsOut[i] = tokenAmountOut; } } // Internal functions // Check for zero transfer, and make sure it returns true to returnValue function verifyTokenComplianceInternal(address token) internal { IERC20(token).safeTransfer(msg.sender, 0); } function handleTransferInTokens( IConfigurableRightsPool self, IBPool bPool, address poolToken, uint actualAmountIn, uint _actualIssueFee ) external returns (uint issueFeeReceived) { issueFeeReceived = DesynSafeMath.bmul(actualAmountIn, _actualIssueFee); uint amount = DesynSafeMath.bsub(actualAmountIn, issueFeeReceived); _pullUnderlying(bPool, poolToken, msg.sender, amount); if (_actualIssueFee != 0) { IERC20(poolToken).safeTransferFrom(msg.sender, address(this), issueFeeReceived); IERC20(poolToken).safeApprove(self.vaultAddress(), 0); IERC20(poolToken).safeApprove(self.vaultAddress(), issueFeeReceived); } } function handleClaim( IConfigurableRightsPool self, IBPool bPool, address[] calldata poolTokens, uint managerFee, uint timeElapsed, uint claimPeriod ) external returns (uint[] memory) { uint[] memory tokensAmount = new uint[](poolTokens.length); for (uint i = 0; i < poolTokens.length; i++) { address t = poolTokens[i]; uint tokenBalance = bPool.getBalance(t); uint tokenAmountOut = tokenBalance.bmul(managerFee).mul(timeElapsed).div(claimPeriod).div(12); _pushUnderlying(bPool, t, address(this), tokenAmountOut); IERC20(t).safeApprove(self.vaultAddress(), 0); IERC20(t).safeApprove(self.vaultAddress(), tokenAmountOut); tokensAmount[i] = tokenAmountOut; } return tokensAmount; } function handleFeeClaim( IConfigurableRightsPool self, IBPool bPool, address[] calldata poolTokens, uint feeRatio, bool isPerfermance ) external { if (feeRatio != 0) { uint[] memory tokensAmount = new uint[](poolTokens.length); for (uint i = 0; i < poolTokens.length; i++) { address t = poolTokens[i]; uint currentAmount = bPool.getBalance(t); uint currentAmountFee = DesynSafeMath.bmul(currentAmount, feeRatio); _pushUnderlying(bPool, t, address(this), currentAmountFee); tokensAmount[i] = currentAmountFee; IERC20(t).safeApprove(self.vaultAddress(), 0); IERC20(t).safeApprove(self.vaultAddress(), currentAmountFee); } if(isPerfermance) { IVault(self.vaultAddress()).depositIssueRedeemPToken(poolTokens, tokensAmount, new uint[](poolTokens.length), isPerfermance); } else { IVault(self.vaultAddress()).depositIssueRedeemPToken(poolTokens, tokensAmount, tokensAmount, isPerfermance); } } } function WhitelistHandle( bool bool1, bool bool2, address adr ) external pure { require(bool1, "ERR_CANNOT_WHITELIST_LPS"); require(bool2, "ERR_LP_NOT_WHITELISTED"); require(adr != address(0), "ERR_INVALID_ADDRESS"); } function _pullUnderlying( IBPool bPool, address erc20, address from, uint amount ) internal { uint tokenBalance = bPool.getBalance(erc20); uint tokenWeight = bPool.getDenormalizedWeight(erc20); IERC20(erc20).safeTransferFrom(from, address(this), amount); bPool.rebind(erc20, DesynSafeMath.badd(tokenBalance, amount), tokenWeight); } function _pushUnderlying( IBPool bPool, address erc20, address to, uint amount ) internal { uint tokenBalance = bPool.getBalance(erc20); uint tokenWeight = bPool.getDenormalizedWeight(erc20); bPool.rebind(erc20, DesynSafeMath.bsub(tokenBalance, amount), tokenWeight); IERC20(erc20).safeTransfer(to, amount); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Interface declarations // Introduce to avoid circularity (otherwise, the CRP and SmartPoolManager include each other) // Removing circularity allows flattener tools to work, which enables Etherscan verification interface IConfigurableRightsPool { function mintPoolShareFromLib(uint amount) external; function pushPoolShareFromLib(address to, uint amount) external; function pullPoolShareFromLib(address from, uint amount) external; function burnPoolShareFromLib(uint amount) external; function balanceOf(address account) external view returns (uint); function totalSupply() external view returns (uint); function adminList(address) external view returns (bool); function getController() external view returns (address); function vaultAddress() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; pragma experimental ABIEncoderV2; interface IBPool { function rebind( address token, uint balance, uint denorm ) external; function execute( address _target, uint _value, bytes calldata _data ) external returns (bytes memory _returnValue); function bind( address token, uint balance, uint denorm ) external; function unbind(address token) external; function unbindPure(address token) external; function isBound(address token) external view returns (bool); function getBalance(address token) external view returns (uint); function totalSupply() external view returns (uint); function isPublicSwap() external view returns (bool); function getDenormalizedWeight(address token) external view returns (uint); function getTotalDenormalizedWeight() external view returns (uint); function EXIT_FEE() external view returns (uint); function getCurrentTokens() external view returns (address[] memory tokens); function setController(address owner) external; } interface IBFactory { function newLiquidityPool() external returns (IBPool); function setBLabs(address b) external; function collect(IBPool pool) external; function isBPool(address b) external view returns (bool); function getBLabs() external view returns (address); function getVault() external view returns (address); function getUserVault() external view returns (address); function getVaultAddress() external view returns (address); function getOracleAddress() external view returns (address); function isTokenWhitelistedForVerify(uint sort, address token) external view returns (bool); function isTokenWhitelistedForVerify(address token) external view returns (bool); function getModuleStatus(address etf, address module) external view returns (bool); function isPaused() external view returns (bool); } interface IVault { function depositManagerToken(address[] calldata poolTokens, uint[] calldata tokensAmount) external; function depositIssueRedeemPToken( address[] calldata poolTokens, uint[] calldata tokensAmount, uint[] calldata tokensAmountP, bool isPerfermance ) external; function managerClaim(address pool) external; function getManagerClaimBool(address pool) external view returns (bool); } interface IUserVault { function recordTokenInfo( address kol, address user, address[] calldata poolTokens, uint[] calldata tokensAmount ) external; } interface Oracles { function getPrice(address tokenAddress) external returns (uint price); function getAllPrice(address[] calldata poolTokens, uint[] calldata tokensAmount) external returns (uint); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Imports import "./DesynConstants.sol"; /** * @author Desyn Labs * @title SafeMath - wrap Solidity operators to prevent underflow/overflow * @dev badd and bsub are basically identical to OpenZeppelin SafeMath; mul/div have extra checks */ library DesynSafeMath { /** * @notice Safe addition * @param a - first operand * @param b - second operand * @dev if we are adding b to a, the resulting sum must be greater than a * @return - sum of operands; throws if overflow */ function badd(uint a, uint b) internal pure returns (uint) { uint c = a + b; require(c >= a, "ERR_ADD_OVERFLOW"); return c; } /** * @notice Safe unsigned subtraction * @param a - first operand * @param b - second operand * @dev Do a signed subtraction, and check that it produces a positive value * (i.e., a - b is valid if b <= a) * @return - a - b; throws if underflow */ function bsub(uint a, uint b) internal pure returns (uint) { (uint c, bool negativeResult) = bsubSign(a, b); require(!negativeResult, "ERR_SUB_UNDERFLOW"); return c; } /** * @notice Safe signed subtraction * @param a - first operand * @param b - second operand * @dev Do a signed subtraction * @return - difference between a and b, and a flag indicating a negative result * (i.e., a - b if a is greater than or equal to b; otherwise b - a) */ function bsubSign(uint a, uint b) internal pure returns (uint, bool) { if (b <= a) { return (a - b, false); } else { return (b - a, true); } } /** * @notice Safe multiplication * @param a - first operand * @param b - second operand * @dev Multiply safely (and efficiently), rounding down * @return - product of operands; throws if overflow or rounding error */ function bmul(uint a, uint b) internal pure returns (uint) { // Gas optimization (see github.com/OpenZeppelin/openzeppelin-contracts/pull/522) if (a == 0) { return 0; } // Standard overflow check: a/a*b=b uint c0 = a * b; require(c0 / a == b, "ERR_MUL_OVERFLOW"); // Round to 0 if x*y < BONE/2? uint c1 = c0 + (DesynConstants.BONE / 2); require(c1 >= c0, "ERR_MUL_OVERFLOW"); uint c2 = c1 / DesynConstants.BONE; return c2; } /** * @notice Safe division * @param dividend - first operand * @param divisor - second operand * @dev Divide safely (and efficiently), rounding down * @return - quotient; throws if overflow or rounding error */ function bdiv(uint dividend, uint divisor) internal pure returns (uint) { require(divisor != 0, "ERR_DIV_ZERO"); // Gas optimization if (dividend == 0) { return 0; } uint c0 = dividend * DesynConstants.BONE; require(c0 / dividend == DesynConstants.BONE, "ERR_DIV_INTERNAL"); // bmul overflow uint c1 = c0 + (divisor / 2); require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require uint c2 = c1 / divisor; return c2; } /** * @notice Safe unsigned integer modulo * @dev Returns the remainder of dividing two unsigned integers. * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * @param dividend - first operand * @param divisor - second operand -- cannot be zero * @return - quotient; throws if overflow or rounding error */ function bmod(uint dividend, uint divisor) internal pure returns (uint) { require(divisor != 0, "ERR_MODULO_BY_ZERO"); return dividend % divisor; } /** * @notice Safe unsigned integer max * @dev Returns the greater of the two input values * * @param a - first operand * @param b - second operand * @return - the maximum of a and b */ function bmax(uint a, uint b) internal pure returns (uint) { return a >= b ? a : b; } /** * @notice Safe unsigned integer min * @dev returns b, if b < a; otherwise returns a * * @param a - first operand * @param b - second operand * @return - the lesser of the two input values */ function bmin(uint a, uint b) internal pure returns (uint) { return a < b ? a : b; } /** * @notice Safe unsigned integer average * @dev Guard against (a+b) overflow by dividing each operand separately * * @param a - first operand * @param b - second operand * @return - the average of the two values */ function baverage(uint a, uint b) internal pure returns (uint) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2); } /** * @notice Babylonian square root implementation * @dev (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) * @param y - operand * @return z - the square root result */ function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.6.12; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint a, uint b) internal pure returns (uint) { uint c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint a, uint b) internal pure returns (uint) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub( uint a, uint b, string memory errorMessage ) internal pure returns (uint) { require(b <= a, errorMessage); uint c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint a, uint b) internal pure returns (uint) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint a, uint b) internal pure returns (uint) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div( uint a, uint b, string memory errorMessage ) internal pure returns (uint) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint a, uint b) internal pure returns (uint) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod( uint a, uint b, string memory errorMessage ) internal pure returns (uint) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import {IERC20} from "../interfaces/IERC20.sol"; import {SafeMath} from "./SafeMath.sol"; import {Address} from "./Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint; using Address for address; function safeTransfer( IERC20 token, address to, uint value ) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint value ) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove( IERC20 token, address spender, uint value ) internal { require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function callOptionalReturn(IERC20 token, bytes memory data) private { require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; /** * @author Desyn Labs * @title Put all the constants in one place */ library DesynConstants { // State variables (must be constant in a library) // where numeric 1 = 10 ** 18 uint public constant BONE = 10**18; uint public constant MIN_WEIGHT = BONE; uint public constant MAX_WEIGHT = BONE * 50; uint public constant MAX_TOTAL_WEIGHT = BONE * 50; uint public constant MIN_BALANCE = 0; uint public constant MAX_BALANCE = BONE * 10**12; uint public constant MIN_POOL_SUPPLY = BONE * 100; uint public constant MAX_POOL_SUPPLY = BONE * 10**9; uint public constant MIN_FEE = BONE / 10**6; uint public constant MAX_FEE = BONE / 10; //Fee Set uint public constant MANAGER_MIN_FEE = 0; uint public constant MANAGER_MAX_FEE = BONE / 10; uint public constant ISSUE_MIN_FEE = 0; uint public constant ISSUE_MAX_FEE = BONE / 10; uint public constant REDEEM_MIN_FEE = 0; uint public constant REDEEM_MAX_FEE = BONE / 10; uint public constant PERFERMANCE_MIN_FEE = 0; uint public constant PERFERMANCE_MAX_FEE = BONE / 2; // EXIT_FEE must always be zero, or ConfigurableRightsPool._pushUnderlying will fail uint public constant EXIT_FEE = 0; uint public constant MAX_IN_RATIO = BONE / 2; uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei; // Must match BConst.MIN_BOUND_TOKENS and BConst.MAX_BOUND_TOKENS uint public constant MIN_ASSET_LIMIT = 1; uint public constant MAX_ASSET_LIMIT = 16; uint public constant MAX_UINT = uint(-1); uint public constant MAX_COLLECT_PERIOD = 60 days; }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.6.12; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue( address target, bytes memory data, uint weiValue, string memory errorMessage ) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{value: weiValue}(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "../interfaces/IERC20.sol"; import "../openzeppelin/Ownable.sol"; import "../interfaces/IDSProxy.sol"; import "../libraries/SafeMath.sol"; import "../libraries/Address.sol"; import "../libraries/SafeERC20.sol"; import "../base/Logs.sol"; interface ICRPPool { function getController() external view returns (address); enum Etypes { OPENED, CLOSED } function etype() external view returns (Etypes); } interface IDesynOwnable { function adminList(address adr) external view returns (bool); function getController() external view returns (address); function getOwners() external view returns (address[] memory); function getOwnerPercentage() external view returns (uint[] memory); function allOwnerPercentage() external view returns (uint); } interface IUserVault { function depositToken( address pool, uint types, address[] calldata poolTokens, uint[] calldata tokensAmount ) external; } interface ICRPFactory { function isCrp(address addr) external view returns (bool); } /** * @author Desyn Labs * @title Vault managerFee */ contract Vault is Ownable, Logs { using SafeMath for uint; using Address for address; using SafeERC20 for IERC20; ICRPFactory crpFactory; address public userVault; event ManagersClaim(address indexed caller,address indexed pool, address token, uint amount, uint time); event ManagerClaim(address indexed caller, address indexed pool, address indexed manager, address token, uint amount, uint time); // pool of tokens struct PoolTokens { address[] tokenList; uint[] managerAmount; uint[] issueAmount; uint[] redeemAmount; uint[] perfermanceAmount; } struct PoolStatus { bool couldManagerClaim; bool isBlackList; } struct ClaimTokens { address[] tokens; uint[] amounts; } // pool tokens mapping(address => PoolTokens) poolsTokens; mapping(address => PoolStatus) public poolsStatus; mapping (address => ClaimTokens) manageHasClaimed; // default ratio config uint public TOTAL_RATIO = 1000; uint public management_portion = 800; uint public issuance_portion = 800; uint public redemption_portion = 800; uint public performance_portion = 800; receive() external payable {} function depositManagerToken(address[] calldata tokensIn, uint[] calldata amountsIn) external { address pool = msg.sender; require(crpFactory.isCrp(pool), "ERR_INVALID_POOL_ADDRESS"); require(tokensIn.length == amountsIn.length, "ERR_TOKEN_LENGTH_NOT_MATCH"); _depositTokenIM(0, pool, tokensIn, amountsIn); poolsStatus[pool].couldManagerClaim = true; if (_isClosePool(pool)) managerClaim(pool); } function depositIssueRedeemPToken( address[] calldata tokensIn, uint[] calldata amountsIn, uint[] calldata tokensAmountIR, bool isPerfermance ) external { address pool = msg.sender; require(crpFactory.isCrp(pool), "ERR_INVALID_POOL_ADDRESS"); require(tokensIn.length == amountsIn.length, "ERR_TOKEN_LENGTH_NOT_MATCH"); isPerfermance // I-issuce; M-mamager; R-redeem;p-performance ? _depositTokenRP(pool, tokensIn, amountsIn, tokensAmountIR) : _depositTokenIM(1, pool, tokensIn, amountsIn); poolsStatus[pool].couldManagerClaim = true; if (_isClosePool(pool)) managerClaim(pool); } function getManagerClaimBool(address pool) external view returns (bool) { return poolsStatus[pool].couldManagerClaim; } function setBlackList(address pool, bool bools) external onlyOwner _logs_ { poolsStatus[pool].isBlackList = bools; } function setUserVaultAdr(address adr) external onlyOwner _logs_ { require(adr != address(0), "ERR_INVALID_USERVAULT_ADDRESS"); userVault = adr; } function setCrpFactory(address adr) external onlyOwner _logs_ { crpFactory = ICRPFactory(adr); } function claimToken( address token, address user, uint amount ) external onlyOwner { IERC20(token).safeTransfer(user, amount); } function claimEther() external payable onlyOwner { msg.sender.transfer(address(this).balance); } function setManagerRatio(uint amount) external onlyOwner _logs_ { require(amount <= TOTAL_RATIO, "Maximum limit exceeded"); management_portion = amount; } function setIssueRatio(uint amount) external onlyOwner _logs_ { require(amount <= TOTAL_RATIO, "Maximum limit exceeded"); issuance_portion = amount; } function setRedeemRatio(uint amount) external onlyOwner _logs_ { require(amount <= TOTAL_RATIO, "Maximum limit exceeded"); redemption_portion = amount; } function setPerfermanceRatio(uint amount) external onlyOwner _logs_{ performance_portion = amount; } function managerClaim(address pool) public { PoolStatus storage status = poolsStatus[pool]; if(status.couldManagerClaim){ require(crpFactory.isCrp(pool), "ERR_INVALID_POOL_ADDRESS"); address managerAddr = ICRPPool(pool).getController(); bool isCloseETF = _isClosePool(pool); PoolTokens memory tokens = poolsTokens[pool]; address[] memory poolManageTokens = tokens.tokenList; uint len = poolManageTokens.length; require(!status.isBlackList, "ERR_POOL_IS_BLACKLIST"); require(len > 0, "ERR_NOT_MANGER_FEE"); require(status.couldManagerClaim, "ERR_MANAGER_COULD_NOT_CLAIM"); status.couldManagerClaim = false; uint[] memory managerTokenAmount = new uint[](len); uint[] memory issueTokenAmount = new uint[](len); uint[] memory redeemTokenAmount = new uint[](len); uint[] memory perfermanceTokenAmount = new uint[](len); for (uint i; i < len; i++) { address t = poolManageTokens[i]; uint b; (b, managerTokenAmount[i], issueTokenAmount[i], redeemTokenAmount[i], perfermanceTokenAmount[i]) = _computeBalance(i, pool); if(!isCloseETF) b = b.sub(_getManagerHasClaimed(pool,t)); if(b != 0) _transferHandle(pool, managerAddr, t, b); } if (isCloseETF) { _recordUserVault(pool, poolManageTokens, managerTokenAmount, issueTokenAmount, redeemTokenAmount, perfermanceTokenAmount); _clearPool(pool); } } } function getManagerFeeTypes(address pool) external view returns(PoolTokens memory result){ PoolTokens memory tokens = poolsTokens[pool]; address[] memory poolManageTokens = tokens.tokenList; uint len = poolManageTokens.length; result.tokenList = tokens.tokenList; result.managerAmount = new uint[](len); result.issueAmount = new uint[](len); result.redeemAmount = new uint[](len); result.perfermanceAmount = new uint[](len); for(uint i; i< len; i++){ (,result.managerAmount[i],result.issueAmount[i],result.redeemAmount[i],result.perfermanceAmount[i]) = _computeBalance(i,pool); } } function getUnManagerReward(address pool) external view returns (address[] memory tokensList, uint[] memory amounts) { PoolTokens memory tokens = poolsTokens[pool]; address[] memory poolManageTokens = tokens.tokenList; uint len = poolManageTokens.length; tokensList = new address[](len); amounts = new uint[](len); for (uint i; i < len; i++) { address t = poolManageTokens[i]; tokensList[i] = t; (amounts[i],,,,) = _computeBalance(i,pool); amounts[i] = amounts[i].sub(_getManagerHasClaimed(pool, t)); } } function _addTokenInPool(address pool, address tokenAddr) internal { PoolTokens storage tokens = poolsTokens[pool]; tokens.tokenList.push(tokenAddr); tokens.managerAmount.push(0); tokens.issueAmount.push(0); tokens.redeemAmount.push(0); tokens.perfermanceAmount.push(0); } // for old token function _updateTokenAmountInPool(uint types, address pool, uint tokenIndex, uint amount) internal { PoolTokens storage tokens = poolsTokens[pool]; if(types == 0) tokens.managerAmount[tokenIndex] = tokens.managerAmount[tokenIndex].add(amount); else if(types == 1) tokens.issueAmount[tokenIndex] = tokens.issueAmount[tokenIndex].add(amount); else if(types == 2) tokens.redeemAmount[tokenIndex] = tokens.redeemAmount[tokenIndex].add(amount); else if(types == 3) tokens.perfermanceAmount[tokenIndex] = tokens.perfermanceAmount[tokenIndex].add(amount); } // for new token function _updateTokenAmountInPool(uint types, address pool, uint amount) internal { PoolTokens storage tokens = poolsTokens[pool]; uint tokenIndex = tokens.tokenList.length - 1; if(types == 0) tokens.managerAmount[tokenIndex] = amount; else if(types == 1) tokens.issueAmount[tokenIndex] = amount; else if(types == 2) tokens.redeemAmount[tokenIndex] = amount; else if(types == 3) tokens.perfermanceAmount[tokenIndex] = amount; } function _depositTokenIM( uint types, address pool, address[] memory tokensIn, uint[] memory amountsIn ) internal { PoolTokens memory tokens = poolsTokens[pool]; uint len = tokensIn.length; for (uint i; i < len; i++) { address t = tokensIn[i]; uint b = amountsIn[i]; IERC20(t).safeTransferFrom(msg.sender, address(this), b); (bool isExit, uint index) = _arrIncludeAddr(tokens.tokenList,t); if (isExit) { _updateTokenAmountInPool(types,pool,index,b); } else { _addTokenInPool(pool,t); _updateTokenAmountInPool(types,pool,b); } } } function _arrIncludeAddr(address[] memory tokens, address target) internal pure returns(bool isInclude, uint index){ for(uint i; i<tokens.length; i++){ if(tokens[i] == target){ isInclude = true; index = i; break; } } } function _depositTokenRP( address pool, address[] calldata tokenIns, uint[] calldata tokensAmount, uint[] calldata tokensAmountIR ) internal { address[] memory tokenList = poolsTokens[pool].tokenList; uint len = tokensAmount.length; for (uint i; i < len; i++) { address t = tokenIns[i]; uint b = tokensAmount[i]; // uint bIR = tokensAmountIR[i]; IERC20(t).safeTransferFrom(msg.sender, address(this), b); (bool isExit,uint index) = _arrIncludeAddr(tokenList, t); if(isExit){ _updateTokenAmountInPool(2, pool, index, tokensAmountIR[i]); _updateTokenAmountInPool(3, pool, index, b.sub(tokensAmountIR[i])); } else { _addTokenInPool(pool, t); _updateTokenAmountInPool(2,pool, tokensAmountIR[i]); _updateTokenAmountInPool(3, pool,b.sub(tokensAmountIR[i])); } } } function _isClosePool(address pool) internal view returns (bool) { return ICRPPool(pool).etype() == ICRPPool.Etypes.CLOSED; } function _computeBalance(uint i, address pool) internal view returns ( uint balance, uint bManagerAmount, uint bIssueAmount, uint bRedeemAmount, uint bPerfermanceAmount ) { PoolTokens memory tokens = poolsTokens[pool]; if (tokens.tokenList.length != 0) { bManagerAmount = tokens.managerAmount[i].mul(management_portion).div(TOTAL_RATIO); bIssueAmount = tokens.issueAmount[i].mul(issuance_portion).div(TOTAL_RATIO); bRedeemAmount = tokens.redeemAmount[i].mul(redemption_portion).div(TOTAL_RATIO); bPerfermanceAmount = tokens.perfermanceAmount[i].mul(performance_portion).div(TOTAL_RATIO); balance = bManagerAmount.add(bIssueAmount).add(bRedeemAmount).add(bPerfermanceAmount); } } function _clearPool(address pool) internal { delete poolsTokens[pool]; } function _recordUserVault( address pool, address[] memory tokenList, uint[] memory managerTokenAmount, uint[] memory issueTokenAmount, uint[] memory redeemTokenAmount, uint[] memory perfermanceTokenAmount ) internal { if (tokenList.length != 0) { IUserVault(userVault).depositToken(pool, 0, tokenList, managerTokenAmount); IUserVault(userVault).depositToken(pool, 1, tokenList, issueTokenAmount); IUserVault(userVault).depositToken(pool, 2, tokenList, redeemTokenAmount); IUserVault(userVault).depositToken(pool, 3, tokenList, perfermanceTokenAmount); } } function _transferHandle( address pool, address managerAddr, address t, uint balance ) internal { require(balance != 0, "ERR_ILLEGAL_BALANCE"); bool isCloseETF = _isClosePool(pool); bool isOpenETF = !isCloseETF; if(isCloseETF){ IERC20(t).safeTransfer(userVault, balance); } // if(isOpenETF && isContractManager){ if(isOpenETF) { address[] memory managerAddressList = IDesynOwnable(pool).getOwners(); uint[] memory ownerPercentage = IDesynOwnable(pool).getOwnerPercentage(); uint allOwnerPercentage = IDesynOwnable(pool).allOwnerPercentage(); for (uint k; k < managerAddressList.length; k++) { address reciver = address(managerAddressList[k]).isContract()? IDSProxy(managerAddressList[k]).owner(): managerAddressList[k]; uint b = balance.mul(ownerPercentage[k]).div(allOwnerPercentage); IERC20(t).safeTransfer(reciver, b); emit ManagerClaim(msg.sender, pool, reciver,t,b,block.timestamp); } _updateManageHasClaimed(pool,t,balance); emit ManagersClaim(msg.sender, pool, t, balance, block.timestamp); } } function _updateManageHasClaimed(address pool, address token, uint amount) internal { ClaimTokens storage claimInfo = manageHasClaimed[pool]; (bool isExit, uint index) = _arrIncludeAddr(claimInfo.tokens, token); if(isExit){ claimInfo.amounts[index] = claimInfo.amounts[index].add(amount); } else{ claimInfo.tokens.push(token); claimInfo.amounts.push(amount); } } function _getManagerHasClaimed(address pool, address token) internal view returns(uint){ require(!_isClosePool(pool),"ERR_NOT_OPEN_POOL"); ClaimTokens memory claimInfo = manageHasClaimed[pool]; (bool isExit,uint index) = _arrIncludeAddr(claimInfo.tokens, token); if(isExit) return claimInfo.amounts[index]; if(!isExit) return 0; } }
pragma solidity >=0.6.0 <0.8.0; abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; interface IDSProxy { function owner() external view returns(address); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; contract Logs { event LOG_CALL(bytes4 indexed sig, address indexed caller, bytes data) anonymous; modifier _logs_() { emit LOG_CALL(msg.sig, msg.sender, msg.data); _; } }
pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "../interfaces/IERC20.sol"; import "../interfaces/IDSProxy.sol"; import "../openzeppelin/Ownable.sol"; import "../libraries/SmartPoolManager.sol"; import "../libraries/EnumerableSet.sol"; import "../libraries/SafeMath.sol"; import "../libraries/Address.sol"; import "../libraries/SafeERC20.sol"; import "../base/Logs.sol"; interface ICRPPool { function getController() external view returns (address); enum Etypes { OPENED, CLOSED } function etype() external view returns (Etypes); function isCompletedCollect() external view returns (bool); } interface ICRPFactory { function isCrp(address addr) external view returns (bool); } interface IDesynOwnable { function adminList(address adr) external view returns (bool); function getController() external view returns (address); function getOwners() external view returns (address[] memory); function getOwnerPercentage() external view returns (uint[] memory); function allOwnerPercentage() external view returns (uint); } /** * @author Desyn Labs * @title Vault managerFee */ contract UserVault is Ownable, Logs { using SafeMath for uint; using Address for address; using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; event ManagersClaim(address indexed caller,address indexed pool, address token, uint amount, uint time); event ManagerClaim(address indexed caller,address indexed pool, address indexed manager, address token, uint amount, uint time); event KolClaim(address indexed caller,address indexed kol, address token, uint amount, uint time); event TypeAmountIn(address indexed pool, uint types, address caller, address token, uint balance); ICRPFactory crpFactory; address vaultAddress; // pool of tokens struct PoolTokens { address[] tokenList; uint[] managerAmount; uint[] issueAmount; uint[] redeemAmount; uint[] perfermanceAmount; } struct PoolStatus { bool couldManagerClaim; bool isBlackList; bool isSetParams; SmartPoolManager.KolPoolParams kolPoolConfig; } // kol list struct KolUserInfo { address userAdr; uint[] userAmount; } struct UserKolInfo { address kol; uint index; } struct ClaimTokens { address[] tokens; uint[] amounts; } // pool => kol => KolUserInfo[] mapping(address => mapping(address => KolUserInfo[])) kolUserInfo; // pool tokens mapping(address => PoolTokens) poolsTokens; mapping(address => PoolStatus) poolsStatus; //pool => initTotalAmount[] mapping(address => uint) public poolInviteTotal; //pool => kol[] mapping(address => EnumerableSet.AddressSet) kolsList; //pool => kol => totalAmount[] mapping(address => mapping(address => uint[])) public kolTotalAmountList; // pool => user => kol mapping(address => mapping(address => UserKolInfo)) public userKolList; // pool=>kol=>tokens mapping(address => mapping(address => ClaimTokens)) kolHasClaimed; // pool=>manage=>tokens mapping (address => ClaimTokens) manageHasClaimed; receive() external payable {} uint constant RATIO_BASE = 100; function getManagerClaimBool(address pool) external view returns(bool){ return poolsStatus[pool].couldManagerClaim; } // one type call and receiver token function depositToken( address pool, uint types, address[] calldata tokensIn, uint[] calldata amountsIn ) external onlyVault { require(tokensIn.length == amountsIn.length, "ERR_TOKEN_LENGTH_NOT_MATCH"); _updatePool(pool, types, tokensIn, amountsIn); poolsStatus[pool].couldManagerClaim = true; } // total tokens in pool function getPoolReward(address pool) external view returns (address[] memory tokenList, uint[] memory balances) { PoolTokens memory tokens = poolsTokens[pool]; uint len = tokens.tokenList.length; balances = new uint[](len); tokenList = tokens.tokenList; for(uint i; i<len ;i++){ balances[i] = tokens.managerAmount[i] .add(tokens.issueAmount[i]) .add(tokens.redeemAmount[i]) .add(tokens.perfermanceAmount[i]); } } struct RewardVars { address pool; uint t0Ratio; uint t1Ratio; uint t2Ratio; uint t3Ratio; uint[] managementAmounts; uint[] issueAmounts; uint[] redemptionAmounts; uint[] performanceAmounts; } // one kol total reward function getKolReward( address pool, address kol ) external view returns (address[] memory tokenList, uint[] memory balances) { uint contributionByCurKol = kolTotalAmountList[pool][kol].length > 0 ? kolTotalAmountList[pool][kol][0] : 0; uint allContributionByKol = poolInviteTotal[pool]; SmartPoolManager.KolPoolParams memory params = poolsStatus[pool].kolPoolConfig; PoolTokens memory tokens = poolsTokens[pool]; balances = new uint[](tokens.tokenList.length); tokenList = tokens.tokenList; RewardVars memory vars = RewardVars( pool, _levelJudge(contributionByCurKol, params.managerFee), _levelJudge(contributionByCurKol, params.issueFee), _levelJudge(contributionByCurKol, params.redeemFee), _levelJudge(contributionByCurKol, params.perfermanceFee), tokens.managerAmount, tokens.issueAmount, tokens.redeemAmount, tokens.perfermanceAmount ); for(uint i; i < tokenList.length; i++){ balances[i] = vars.managementAmounts[i].mul(vars.t0Ratio).div(RATIO_BASE) .add(vars.issueAmounts[i].mul(vars.t1Ratio).div(RATIO_BASE)) .add(vars.redemptionAmounts[i].mul(vars.t2Ratio).div(RATIO_BASE)) .add(vars.performanceAmounts[i].mul(vars.t3Ratio).div(RATIO_BASE)) .mul(contributionByCurKol) .div(allContributionByKol); } } function kolClaim(address pool) external { if (_isClosePool(pool)) { require(crpFactory.isCrp(pool), "ERR_INVALID_POOL_ADDRESS"); require(ICRPPool(pool).isCompletedCollect(), "ERR_NOT_COMPLETED_COLLECT"); (address[] memory tokens, uint[] memory amounts) = this.getKolReward(pool, msg.sender); ClaimTokens storage kolClaimedInfo = kolHasClaimed[pool][msg.sender]; // update length kolClaimedInfo.tokens = tokens; uint amountsLen = kolClaimedInfo.amounts.length; uint tokensLen = tokens.length; if(amountsLen != tokensLen){ uint delta = tokensLen - amountsLen; for(uint i; i < delta; i++){ kolClaimedInfo.amounts.push(0); } } address receiver = address(msg.sender).isContract()? IDSProxy(msg.sender).owner(): msg.sender; for(uint i; i< tokens.length; i++) { uint b = amounts[i] - kolClaimedInfo.amounts[i]; if(b != 0){ IERC20(tokens[i]).safeTransfer(receiver, b); kolClaimedInfo.amounts[i] = kolClaimedInfo.amounts[i].add(b); emit KolClaim(msg.sender,receiver,tokens[i],b,block.timestamp); } } } } // manager claim function managerClaim(address pool) external { // try {} catch {} if (_isClosePool(pool) && poolsStatus[pool].couldManagerClaim) { bool isManager = IDesynOwnable(pool).adminList(msg.sender) || IDesynOwnable(pool).getController() == msg.sender; bool isCollectSuccee = ICRPPool(pool).isCompletedCollect(); require(isCollectSuccee, "ERR_NOT_COMPLETED_COLLECT"); require(isManager, "ERR_NOT_MANAGER"); (address[] memory tokens, uint[] memory amounts) = this.getUnManagerReward(pool); poolsStatus[pool].couldManagerClaim = false; ClaimTokens storage manageHasClimed = manageHasClaimed[pool]; // update length manageHasClimed.tokens = tokens; uint amountsLen = manageHasClimed.amounts.length; uint tokensLen = tokens.length; if(amountsLen != tokensLen){ uint delta = tokensLen - amountsLen; for(uint i; i < delta; i++){ manageHasClimed.amounts.push(0); } } // update tokens for(uint i; i< tokens.length; i++){ address t = tokens[i]; if(amounts[i]!=0){ _transferHandle(pool, t, amounts[i]); manageHasClimed.amounts[i] = manageHasClimed.amounts[i].add(amounts[i]); } } } } function getManagerReward(address pool) external view returns (address[] memory, uint[] memory) { (address[] memory totalTokens, uint[] memory totalFee) = this.getPoolReward(pool); (, uint[] memory kolFee) = this.getKolsReward(pool); uint len = totalTokens.length; uint[] memory balances = new uint[](len); for(uint i; i<len; i++){ balances[i] = totalFee[i] - kolFee[i]; } return (totalTokens, balances); } // for all manager function getUnManagerReward(address pool) external returns (address[] memory, uint[] memory) { (address[] memory totalTokens, uint[] memory totalAmounts) = this.getManagerReward(pool); ClaimTokens storage manageHasClimed = manageHasClaimed[pool]; // update length manageHasClimed.tokens = totalTokens; uint amountsLen = manageHasClimed.amounts.length; uint tokensLen = totalTokens.length; if(amountsLen != tokensLen){ uint delta = tokensLen - amountsLen; for(uint i; i < delta; i++){ manageHasClimed.amounts.push(0); } } uint len = totalTokens.length; uint[] memory balances = new uint[](len); for(uint i; i < totalTokens.length; i++){ balances[i] = totalAmounts[i] - manageHasClimed.amounts[i]; } return (totalTokens,balances); } function getPoolFeeTypes(address pool) external view returns(PoolTokens memory result){ return poolsTokens[pool]; } function getManagerFeeTypes(address pool) external view returns(PoolTokens memory result){ result = this.getPoolFeeTypes(pool); PoolTokens memory allKolFee = _getKolsFeeTypes(pool); uint len = result.tokenList.length; for(uint i; i< len; i++){ result.managerAmount[i] = result.managerAmount[i].sub(allKolFee.managerAmount[i]); result.issueAmount[i] = result.issueAmount[i].sub(allKolFee.issueAmount[i]); result.redeemAmount[i] = result.redeemAmount[i].sub(allKolFee.redeemAmount[i]); result.perfermanceAmount[i] = result.perfermanceAmount[i].sub(allKolFee.perfermanceAmount[i]); } } function _getKolsFeeTypes(address pool) internal view returns(PoolTokens memory result) { PoolTokens memory poolInfo = poolsTokens[pool]; uint len = poolInfo.tokenList.length; result.tokenList = poolInfo.tokenList; EnumerableSet.AddressSet storage list = kolsList[pool]; uint kolLen = list.length(); // init result result.managerAmount = new uint[](len); result.issueAmount = new uint[](len); result.redeemAmount = new uint[](len); result.perfermanceAmount = new uint[](len); for(uint types; types<4; types++){ for(uint i; i<len; i++){ for (uint j; j < kolLen; j++) { if(types == 0) result.managerAmount[i] = result.managerAmount[i].add(_computeKolTotalReward(pool, list.at(j), 0, i)); else if(types == 1) result.issueAmount[i] = result.issueAmount[i].add(_computeKolTotalReward(pool, list.at(j), 1, i)); else if(types == 2) result.redeemAmount[i] = result.redeemAmount[i].add(_computeKolTotalReward(pool, list.at(j), 2, i)); else if(types == 3) result.perfermanceAmount[i] = result.perfermanceAmount[i].add(_computeKolTotalReward(pool, list.at(j), 3, i)); } } } } function getKolFeeType(address pool, address kol) external view returns(PoolTokens memory result) { PoolTokens memory poolInfo = poolsTokens[pool]; result.tokenList = poolInfo.tokenList; uint len = poolInfo.tokenList.length; // init result result.managerAmount = new uint[](len); result.issueAmount = new uint[](len); result.redeemAmount = new uint[](len); result.perfermanceAmount = new uint[](len); // more for to save gas for(uint i; i<len; i++){ result.managerAmount[i] = result.managerAmount[i].add(_computeKolTotalReward(pool, kol, 0, i)); result.issueAmount[i] = result.issueAmount[i].add(_computeKolTotalReward(pool, kol, 1, i)); result.redeemAmount[i] = result.redeemAmount[i].add(_computeKolTotalReward(pool, kol, 2, i)); result.perfermanceAmount[i] = result.perfermanceAmount[i].add(_computeKolTotalReward(pool, kol, 3, i)); } } function getKolsReward(address pool) external view returns (address[] memory, uint[] memory) { EnumerableSet.AddressSet storage list = kolsList[pool]; uint len = list.length(); address[] memory tokens = poolsTokens[pool].tokenList; uint[] memory balances = new uint[](tokens.length); for (uint i = 0; i < len; i++) { (, uint[] memory singleReward) = this.getKolReward(pool, list.at(i)); for(uint k; k < singleReward.length; k++){ balances[k] = balances[k] + singleReward[k]; } } return (tokens,balances); } function getUnKolReward(address pool, address kol) external returns (address[] memory,uint[] memory) { (address[] memory totalTokens, uint[] memory totalReward) = this.getKolReward(pool, kol); ClaimTokens storage singleKolHasReward = kolHasClaimed[pool][kol]; // update length singleKolHasReward.tokens = totalTokens; uint amountsLen = singleKolHasReward.amounts.length; uint tokensLen = totalTokens.length; if(amountsLen != tokensLen){ uint delta = tokensLen - amountsLen; for(uint i; i < delta; i++){ singleKolHasReward.amounts.push(0); } } uint len = totalTokens.length; uint[] memory balances = new uint[](len); for(uint i; i<len; i++){ balances[i] = totalReward[i] - singleKolHasReward.amounts[i]; } return (totalTokens, balances); } function recordTokenInfo( address kol, address user, address[] calldata poolTokens, uint[] calldata tokensAmount ) external { address pool = msg.sender; uint len = poolTokens.length; require(len == tokensAmount.length, "ERR_TOKEN_LENGTH_NOT_MATCH"); require(crpFactory.isCrp(pool), "ERR_INVALID_POOL_ADDRESS"); UserKolInfo storage userKolBind = userKolList[pool][user]; if (userKolBind.kol == address(0)) { userKolBind.kol = kol; if (!kolsList[pool].contains(kol)) kolsList[pool].addValue(kol); } address newKol = userKolBind.kol; require(newKol != address(0), "ERR_INVALID_KOL_ADDRESS"); //total amount record poolInviteTotal[pool] = poolInviteTotal[pool].add(tokensAmount[0]); uint[] memory totalAmounts = new uint[](len); for (uint i; i < len; i++) { bool kolHasInvitations = kolTotalAmountList[pool][newKol].length == 0; kolHasInvitations ? totalAmounts[i] = tokensAmount[i] : totalAmounts[i] = tokensAmount[i].add(kolTotalAmountList[pool][newKol][i]); } kolTotalAmountList[pool][newKol] = totalAmounts; //kol user info record KolUserInfo[] storage userInfoArray = kolUserInfo[pool][newKol]; uint index = userKolBind.index; if (index == 0) { KolUserInfo memory userInfo; userInfo.userAdr = user; userInfo.userAmount = tokensAmount; userInfoArray.push(userInfo); userKolBind.index = userInfoArray.length; } else { KolUserInfo storage userInfo = kolUserInfo[pool][newKol][index - 1]; for (uint a; a < userInfo.userAmount.length; a++) { userInfo.userAmount[a] = userInfo.userAmount[a].add(tokensAmount[a]); } } } function setPoolParams(address pool, SmartPoolManager.KolPoolParams memory _poolParams) external onlyCrpFactory { PoolStatus storage status = poolsStatus[pool]; require(crpFactory.isCrp(pool), "ERR_INVALID_POOL_ADDRESS"); require(!status.isSetParams, "ERR_HAS_SETED"); status.isSetParams = true; status.kolPoolConfig = _poolParams; } // function _getRatioTotal(address pool, uint types) internal view returns(uint){ // SmartPoolManager.KolPoolParams memory params = poolsStatus[pool].kolPoolConfig; // if(types == 0) return params.managerFee.firstLevel.ratio.add(params.managerFee.secondLevel.ratio).add(params.managerFee.thirdLevel.ratio).add(params.managerFee.fourLevel.ratio); // else if(types == 1) return params.issueFee.firstLevel.ratio.add(params.issueFee.secondLevel.ratio).add(params.issueFee.thirdLevel.ratio).add(params.issueFee.fourLevel.ratio); // else if(types == 2) return params.redeemFee.firstLevel.ratio.add(params.redeemFee.secondLevel.ratio).add(params.redeemFee.thirdLevel.ratio).add(params.redeemFee.fourLevel.ratio); // else if(types == 3) return params.perfermanceFee.firstLevel.ratio.add(params.perfermanceFee.secondLevel.ratio).add(params.perfermanceFee.thirdLevel.ratio).add(params.perfermanceFee.fourLevel.ratio); // } function getKolsAdr(address pool) external view returns (address[] memory) { return kolsList[pool].values(); } function getPoolConfig(address pool) external view returns (SmartPoolManager.KolPoolParams memory) { return poolsStatus[pool].kolPoolConfig; } function setBlackList(address pool, bool bools) external onlyOwner _logs_ { poolsStatus[pool].isBlackList = bools; } function setCrpFactory(address adr) external onlyOwner _logs_ { crpFactory = ICRPFactory(adr); } function claimToken( address token, address user, uint amount ) external onlyOwner { IERC20(token).safeTransfer(user, amount); } function claimEther() external payable onlyOwner { msg.sender.transfer(address(this).balance); } function setVaultAdr(address adr) external onlyOwner _logs_ { vaultAddress = adr; } function getKolHasClaimed(address pool,address kol) external view returns(ClaimTokens memory) { return kolHasClaimed[pool][kol]; } function getManageHasClaimed(address pool) external view returns(ClaimTokens memory) { return manageHasClaimed[pool]; } function getKolUserInfo(address pool, address kol) external view returns (KolUserInfo[] memory) { return kolUserInfo[pool][kol]; } function getUserKolInfo(address pool, address user) external view returns (UserKolInfo memory) { return userKolList[pool][user]; } function _updatePool( address pool, uint types, address[] memory tokenIn, uint[] memory amountIn ) internal { PoolTokens storage tokens = poolsTokens[pool]; for(uint i; i < tokenIn.length; i++){ address t = tokenIn[i]; uint b = amountIn[i]; (bool isExit,uint index) = _arrIncludeAddr(tokens.tokenList, t); // update token and init value if(!isExit){ tokens.tokenList.push(t); tokens.managerAmount.push(0); tokens.issueAmount.push(0); tokens.redeemAmount.push(0); tokens.perfermanceAmount.push(0); index = tokens.tokenList.length -1; } // update valut if(b != 0){ if(types == 0) tokens.managerAmount[index] = tokens.managerAmount[index].add(b); else if(types == 1) tokens.issueAmount[index] = tokens.issueAmount[index].add(b); else if(types == 2) tokens.redeemAmount[index] = tokens.redeemAmount[index].add(b); else if(types == 3) tokens.perfermanceAmount[index] = tokens.perfermanceAmount[index].add(b); emit TypeAmountIn(pool, types, msg.sender, t, b); } } } function _arrIncludeAddr(address[] memory tokens, address target) internal pure returns(bool isInclude, uint index){ for(uint i; i<tokens.length; i++){ if(tokens[i] == target){ isInclude = true; index = i; break; } } } function _transferHandle( address pool, address t, uint balance ) internal { require(balance != 0, "ERR_ILLEGAL_BALANCE"); address[] memory managerAddressList = IDesynOwnable(pool).getOwners(); uint[] memory ownerPercentage = IDesynOwnable(pool).getOwnerPercentage(); uint allOwnerPercentage = IDesynOwnable(pool).allOwnerPercentage(); for (uint k = 0; k < managerAddressList.length; k++) { address reciver = address(managerAddressList[k]).isContract()? IDSProxy(managerAddressList[k]).owner(): managerAddressList[k]; uint b = balance.mul(ownerPercentage[k]).div(allOwnerPercentage); IERC20(t).safeTransfer(reciver, b); emit ManagerClaim(msg.sender, pool, reciver,t,b,block.timestamp); } emit ManagersClaim(msg.sender,pool,t,balance,block.timestamp); } function _levelJudge(uint amount, SmartPoolManager.feeParams memory _feeParams) internal pure returns (uint) { if (_feeParams.firstLevel.level <= amount && amount < _feeParams.secondLevel.level) return _feeParams.firstLevel.ratio; else if (_feeParams.secondLevel.level <= amount && amount < _feeParams.thirdLevel.level) return _feeParams.secondLevel.ratio; else if (_feeParams.thirdLevel.level <= amount && amount < _feeParams.fourLevel.level) return _feeParams.thirdLevel.ratio; else if (_feeParams.fourLevel.level <= amount) return _feeParams.fourLevel.ratio; return 0; } function _isClosePool(address pool) internal view returns (bool) { return ICRPPool(pool).etype() == ICRPPool.Etypes.CLOSED; } function _computeKolTotalReward( address pool, address kol, uint types, uint tokenIndex ) internal view returns (uint totalFee) { uint kolTotalAmount = kolTotalAmountList[pool][kol].length > 0 ? kolTotalAmountList[pool][kol][0] : 0; SmartPoolManager.KolPoolParams memory params = poolsStatus[pool].kolPoolConfig; PoolTokens memory tokens = poolsTokens[pool]; if(kolTotalAmount == 0 || tokens.tokenList.length == 0) return 0; uint allKolTotalAmount = poolInviteTotal[pool]; if (types == 0) totalFee = tokens.managerAmount[tokenIndex].mul(_levelJudge(kolTotalAmount, params.managerFee)).div(RATIO_BASE); else if (types == 1) totalFee = tokens.issueAmount[tokenIndex].mul(_levelJudge(kolTotalAmount, params.issueFee)).div(RATIO_BASE); else if (types == 2) totalFee = tokens.redeemAmount[tokenIndex].mul(_levelJudge(kolTotalAmount, params.redeemFee)).div(RATIO_BASE); else if (types == 3) totalFee = tokens.perfermanceAmount[tokenIndex].mul(_levelJudge(kolTotalAmount, params.perfermanceFee)).div(RATIO_BASE); return totalFee.mul(kolTotalAmount).div(allKolTotalAmount); } modifier onlyCrpFactory() { require(address(crpFactory) == msg.sender, "ERR_NOT_CRP_FACTORY"); _; } modifier onlyVault() { require(vaultAddress == msg.sender, "ERR_NOT_CONTROLLER"); _; } }
pragma solidity 0.6.12; library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint toDeleteIndex = valueIndex - 1; uint lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function addValue(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint index) internal view returns (address) { return address(uint160(uint(_at(set._inner, index)))); } function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly { result := store } return result; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; import {RightsManager} from "../libraries/RightsManager.sol"; import {SmartPoolManager} from "../libraries/SmartPoolManager.sol"; import "../base/Logs.sol"; // Needed to handle structures externally pragma experimental ABIEncoderV2; // Imports abstract contract IConfigurableRightsPool { struct PoolParams { string poolTokenSymbol; string poolTokenName; address[] constituentTokens; uint[] tokenBalances; uint[] tokenWeights; uint managerFee; uint redeemFee; uint issueFee; uint perfermanceFee; SmartPoolManager.Etypes etype; } struct CrpParams { uint initialSupply; uint collectPeriod; SmartPoolManager.Period period; } function setController(address owner) external virtual; function init( address factoryAddress, IConfigurableRightsPool.PoolParams calldata poolParams, RightsManager.Rights calldata rights ) external virtual; function initHandle(address[] memory owners, uint[] memory ownerPercentage) external virtual; } interface IUserVault { function setPoolParams(address pool, SmartPoolManager.KolPoolParams memory kolPoolParams) external; } interface ICRPFactory { function isCrp(address addr) external view returns (bool); } // Contracts /** * @author Desyn Labs * @title Configurable Rights Pool Factory - create parameterized smart pools * @dev Rights are held in a corresponding struct in ConfigurableRightsPool * Index values are as follows: * by default, it is off on initialization and can only be turned on * 4: canWhitelistLPs - if set, only whitelisted addresses can join pools * (enables private pools with more than one LP) * 5: canChangeCap - can change the BSP cap (max # of pool tokens) */ contract CRPFactory is Logs { // State variables // Keep a list of all Configurable Rights Pools mapping(address => bool) private _isCrp; // Event declarations // Log the address of each new smart pool, and its creator event LogNewCrp(address indexed caller, address indexed pool); event LOG_USER_VAULT(address indexed vault, address indexed caller); event LOG_MIDDLEWARE(address indexed middleware, address indexed caller); event AddCRPFactory(address caller, address indexed factory); event RemoveCRPFactory(address caller, address indexed factory); uint private counters; bytes public bytecodes; address private _blabs = msg.sender; address public userVault; address[] public CRPFactorys; // constructor(bytes memory _bytecode) public { // bytecodes = _bytecode; // _blabs = msg.sender; // } function createPool(IConfigurableRightsPool.PoolParams calldata poolParams) internal returns (address base) { bytes memory bytecode = bytecodes; bytes memory deploymentData = abi.encodePacked(bytecode, abi.encode(poolParams.poolTokenSymbol, poolParams.poolTokenName)); bytes32 salt = keccak256(abi.encodePacked(counters++)); assembly { base := create2(0, add(deploymentData, 32), mload(deploymentData), salt) if iszero(extcodesize(base)) { revert(0, 0) } } } // Function declarations /** * @notice Create a new CRP * @dev emits a LogNewCRP event * @param factoryAddress - the BFactory instance used to create the underlying pool * @param poolParams - struct containing the names, tokens, weights, balances, and swap fee * @param rights - struct of permissions, configuring this CRP instance (see above for definitions) */ function newCrp( address factoryAddress, IConfigurableRightsPool.PoolParams calldata poolParams, RightsManager.Rights calldata rights, SmartPoolManager.KolPoolParams calldata kolPoolParams, address[] memory owners, uint[] memory ownerPercentage ) external returns (IConfigurableRightsPool) { // require(poolParams.constituentTokens.length >= DesynConstants.MIN_ASSET_LIMIT, "ERR_TOO_FEW_TOKENS"); // Arrays must be parallel address crp = createPool(poolParams); emit LogNewCrp(msg.sender, crp); _isCrp[crp] = true; IConfigurableRightsPool(crp).init(factoryAddress, poolParams, rights); IUserVault(userVault).setPoolParams(crp, kolPoolParams); // The caller is the controller of the CRP // The CRP will be the controller of the underlying Core BPool IConfigurableRightsPool(crp).setController(msg.sender); IConfigurableRightsPool(crp).initHandle(owners, ownerPercentage); return IConfigurableRightsPool(crp); } modifier onlyBlabs() { require(msg.sender == _blabs, "ERR_NOT_BLABS"); _; } function setUserVault(address newVault) external onlyBlabs { userVault = newVault; emit LOG_USER_VAULT(newVault, msg.sender); } function setByteCodes(bytes memory _bytecodes) external onlyBlabs _logs_ { bytecodes = _bytecodes; } /** * @notice Check to see if a given address is a CRP * @param addr - address to check * @return boolean indicating whether it is a CRP */ function isCrp(address addr) external view returns (bool) { if(_isCrp[addr]) return _isCrp[addr]; for(uint i=0; i<CRPFactorys.length; i++){ if(ICRPFactory(CRPFactorys[i]).isCrp(addr)) return true; } } /** * @notice add CRPFactory * @param _crpFactory CRPFactory address * @dev add CRPFactory */ function addCRPFactory(address _crpFactory) external onlyBlabs { require(_crpFactory != address(this),"ERR_CAN_NOT_ADD_SELF"); uint len = CRPFactorys.length; for(uint i=0; i<len; i++){ require(CRPFactorys[i] != _crpFactory, "ERR_HAS_BEEN_ADDED"); } CRPFactorys.push(_crpFactory); emit AddCRPFactory(msg.sender, _crpFactory); } /** * @notice remove CRPFactory * @param _crpFactory CRPFactory address * @dev remove CRPFactory */ function removeCRPFactory(address _crpFactory) external onlyBlabs { uint len = CRPFactorys.length; for(uint i=0; i<len; i++){ if(CRPFactorys[i] == _crpFactory){ CRPFactorys[i] = CRPFactorys[len-1]; CRPFactorys.pop(); emit RemoveCRPFactory(msg.sender, _crpFactory); break; } } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to handle structures externally pragma experimental ABIEncoderV2; /** * @author Desyn Labs * @title Manage Configurable Rights for the smart pool * by default, it is off on initialization and can only be turned on * canWhitelistLPs - can limit liquidity providers to a given set of addresses * canChangeCap - can change the BSP cap (max # of pool tokens) * canChangeFloor - can change the BSP floor for Closure ETF (min # of pool tokens) */ library RightsManager { // Type declarations enum Permissions { WHITELIST_LPS, TOKEN_WHITELISTS } struct Rights { bool canWhitelistLPs; bool canTokenWhiteLists; } // State variables (can only be constants in a library) bool public constant DEFAULT_CAN_WHITELIST_LPS = false; bool public constant DEFAULT_CAN_TOKEN_WHITELISTS = false; // bool public constant DEFAULT_CAN_CHANGE_CAP = false; // bool public constant DEFAULT_CAN_CHANGE_FLOOR = false; // Functions /** * @notice create a struct from an array (or return defaults) * @dev If you pass an empty array, it will construct it using the defaults * @param a - array input * @return Rights struct */ function constructRights(bool[] calldata a) external pure returns (Rights memory) { if (a.length < 2) { return Rights( DEFAULT_CAN_WHITELIST_LPS, DEFAULT_CAN_TOKEN_WHITELISTS ); } else { // return Rights(a[0], a[1], a[2], a[3], a[4], a[5], a[6]); return Rights(a[0], a[1]); } } /** * @notice Convert rights struct to an array (e.g., for events, GUI) * @dev avoids multiple calls to hasPermission * @param rights - the rights struct to convert * @return boolean array containing the rights settings */ function convertRights(Rights calldata rights) external pure returns (bool[] memory) { bool[] memory result = new bool[](2); result[0] = rights.canWhitelistLPs; result[1] = rights.canTokenWhiteLists; return result; } // Though it is actually simple, the number of branches triggers code-complexity /* solhint-disable code-complexity */ /** * @notice Externally check permissions using the Enum * @param self - Rights struct containing the permissions * @param permission - The permission to check * @return Boolean true if it has the permission */ function hasPermission(Rights calldata self, Permissions permission) external pure returns (bool) { if (Permissions.WHITELIST_LPS == permission) { return self.canWhitelistLPs; } else if (Permissions.TOKEN_WHITELISTS == permission) { return self.canTokenWhiteLists; } } /* solhint-enable code-complexity */ }
pragma solidity 0.6.12; interface IWETH { function balanceOf(address account) external view returns (uint); function deposit() external payable; function withdraw(uint) external; function approve(address guy, uint wad) external returns (bool); function transferFrom( address src, address dst, uint wad ) external returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; /** * @author Desyn Labs (and OpenZeppelin) * @title Protect against reentrant calls (and also selectively protect view functions) * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {_lock_} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `_lock_` guard, functions marked as * `_lock_` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `_lock_` entry * points to them. * * Also adds a _lockview_ modifier, which doesn't create a lock, but fails * if another _lock_ call is in progress */ contract DesynReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint private constant _NOT_ENTERED = 1; uint private constant _ENTERED = 2; uint private _status; constructor() internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `_lock_` function from another `_lock_` * function is not supported. It is possible to prevent this from happening * by making the `_lock_` function external, and make it call a * `private` function that does the actual work. */ modifier lock() { // On the first call to _lock_, _notEntered will be true require(_status != _ENTERED, "ERR_REENTRY"); // Any calls to _lock_ after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Also add a modifier that doesn't create a lock, but protects functions that * should not be called while a _lock_ function is running */ modifier viewlock() { require(_status != _ENTERED, "ERR_REENTRY_VIEW"); _; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Needed to handle structures externally pragma experimental ABIEncoderV2; import "./PCToken.sol"; import "../utils/DesynReentrancyGuard.sol"; import "../utils/DesynOwnable.sol"; import "../interfaces/IBFactory.sol"; import {RightsManager} from "../libraries/RightsManager.sol"; import "../libraries/SmartPoolManager.sol"; import "../libraries/SafeApprove.sol"; import "./WhiteToken.sol"; import "../libraries/SafeERC20.sol"; import '../libraries/Address.sol'; /** * @author Desyn Labs * @title Smart Pool with customizable features * @notice PCToken is the "Desyn Smart Pool" token (transferred upon finalization) * @dev Rights are defined as follows (index values into the array) * Note that functions called on bPool and bFactory may look like internal calls, * but since they are contracts accessed through an interface, they are really external. * To make this explicit, we could write "IBPool(address(bPool)).function()" everywhere, * instead of "bPool.function()". */ contract ConfigurableRightsPool is PCToken, DesynOwnable, DesynReentrancyGuard, WhiteToken { using DesynSafeMath for uint; using SafeERC20 for IERC20; using Address for address; // State variables IBFactory public bFactory; IBPool public bPool; // Struct holding the rights configuration RightsManager.Rights public rights; SmartPoolManager.Status public etfStatus; SmartPoolManager.Fund beginFund; SmartPoolManager.Fund endFund; // Store the list of tokens in the pool, and balances // NOTE that the token list is *only* used to store the pool tokens between // construction and createPool - thereafter, use the underlying BPool's list // (avoids synchronization issues) address[] private _initialTokens; uint[] private _initialBalances; uint[] private _initialWeights; // Whitelist of LPs (if configured) mapping(address => bool) private _liquidityProviderWhitelist; // TODO // uint public constant CLAIM_PERIOD = 30 days; // production uint public constant CLAIM_PERIOD = 15 minutes; // test address public vaultAddress; bool hasSetWhiteTokens; bool initBool; bool public isCompletedCollect; bool public hasSetBeginFund; bool public hasSetEndFund; bool public hasClaimManageFee; SmartPoolManager.Etypes public etype; // Event declarations // Anonymous logger event - can only be filtered by contract address event LogCall(bytes4 indexed sig, address indexed caller, bytes data) anonymous; event LogJoin(address indexed caller, address indexed tokenIn, uint tokenAmountIn); event LogExit(address indexed caller, address indexed tokenOut, uint tokenAmountOut); event SizeChanged(address indexed caller, string indexed sizeType, uint oldSize, uint newSize); event PoolTokenInit(address indexed caller, address pool, address initToken, uint initTokenTotal, uint initShare); event SetManagerFee(uint indexed managerFee, uint indexed issueFee, uint indexed redeemFee, uint perfermanceFee); // Modifiers modifier logs() { emit LogCall(msg.sig, msg.sender, msg.data); _; } // Mark functions that require delegation to the underlying Pool modifier needsBPool() { require(address(bPool) != address(0), "ERR_NOT_CREATED"); _; } modifier notPaused() { require(!bFactory.isPaused(), "!paused"); _; } constructor(string memory tokenSymbol, string memory tokenName) public PCToken(tokenSymbol, tokenName) {} /** * @notice Construct a new Configurable Rights Pool (wrapper around BPool) * @dev _initialTokens are only used for temporary storage between construction * and create pool, and should not be used thereafter! _initialTokens is destroyed in * createPool to prevent this is kept in sync (defensively), but * should never be used except in this constructor and createPool() * @param factoryAddress - the BPoolFactory used to create the underlying pool * @param poolParams - struct containing pool parameters * @param rightsStruct - Set of permissions we are assigning to this smart pool */ function init( address factoryAddress, SmartPoolManager.PoolParams memory poolParams, RightsManager.Rights memory rightsStruct ) public { SmartPoolManager.initRequire( poolParams.managerFee, poolParams.issueFee, poolParams.redeemFee, poolParams.perfermanceFee, poolParams.tokenBalances.length, poolParams.tokenWeights.length, poolParams.constituentTokens.length, initBool ); initBool = true; rights = rightsStruct; _initialTokens = poolParams.constituentTokens; _initialBalances = poolParams.tokenBalances; _initialWeights = poolParams.tokenWeights; etfStatus = SmartPoolManager.Status({ collectPeriod: 0, collectEndTime: 0, closurePeriod: 0, closureEndTime: 0, upperCap: DesynConstants.MAX_UINT, floorCap: 0, managerFee: poolParams.managerFee, redeemFee: poolParams.redeemFee, issueFee: poolParams.issueFee, perfermanceFee: poolParams.perfermanceFee, startClaimFeeTime: block.timestamp }); etype = poolParams.etype; bFactory = IBFactory(factoryAddress); vaultAddress = bFactory.getVault(); emit SetManagerFee(etfStatus.managerFee, etfStatus.issueFee, etfStatus.redeemFee, etfStatus.perfermanceFee); } /** * @notice Set the cap (max # of pool tokens) * @dev _bspCap defaults in the constructor to unlimited * Can set to 0 (or anywhere below the current supply), to halt new investment * Prevent setting it before creating a pool, since createPool sets to intialSupply * (it does this to avoid an unlimited cap window between construction and createPool) * Therefore setting it before then has no effect, so should not be allowed * @param newCap - new value of the cap */ function setCap(uint newCap) external logs lock needsBPool onlyOwner { require(etype == SmartPoolManager.Etypes.OPENED, "ERR_MUST_OPEN_ETF"); emit SizeChanged(msg.sender, "UPPER", etfStatus.upperCap, newCap); etfStatus.upperCap = newCap; } function execute( address _target, uint _value, bytes calldata _data, bool isUnderlying ) external logs lock needsBPool returns (bytes memory _returnValue) { require(bFactory.getModuleStatus(address(this), msg.sender), 'MODULE IS NOT REGISTER'); if (isUnderlying) { _returnValue = bPool.execute(_target, _value, _data); } else { _returnValue = _target.functionCallWithValue(_data, _value); } } function couldClaimManagerFee() public view returns(bool state,uint timePoint ,uint timeElapsed){ bool isCloseETF = etype == SmartPoolManager.Etypes.CLOSED; timePoint = block.timestamp; if(isCloseETF && timePoint > etfStatus.closureEndTime) timePoint = etfStatus.closureEndTime; timeElapsed = DesynSafeMath.bsub(timePoint, etfStatus.startClaimFeeTime); if(timeElapsed >= CLAIM_PERIOD) state = true; if(isCloseETF && !isCompletedCollect) state = false; } function claimManagerFee() public virtual logs lock onlyAdmin needsBPool { _claimManagerFee(); } function _claimManagerFee() internal { (bool state, uint timePoint ,uint timeElapsed) = couldClaimManagerFee(); if(state){ address[] memory poolTokens = bPool.getCurrentTokens(); uint[] memory tokensAmount = SmartPoolManager.handleClaim( IConfigurableRightsPool(address(this)), bPool, poolTokens, etfStatus.managerFee, timeElapsed, CLAIM_PERIOD ); IVault(vaultAddress).depositManagerToken(poolTokens, tokensAmount); etfStatus.startClaimFeeTime = timePoint; } } /** * @notice Create a new Smart Pool * @dev Delegates to internal function * @param initialSupply starting token balance * @param closurePeriod the etf closure period */ function createPool( address creator, uint initialSupply, uint collectPeriod, SmartPoolManager.Period closurePeriod, SmartPoolManager.PoolTokenRange memory tokenRange ) external virtual onlyOwner logs lock notPaused { if (etype == SmartPoolManager.Etypes.CLOSED) { SmartPoolManager.createPoolHandle(collectPeriod, etfStatus.upperCap, initialSupply); uint oldCap = etfStatus.upperCap; uint oldFloor = etfStatus.floorCap; etfStatus.upperCap = initialSupply.bmul(tokenRange.bspCap).bdiv(_initialBalances[0]); etfStatus.floorCap = initialSupply.bmul(tokenRange.bspFloor).bdiv(_initialBalances[0]); emit PoolTokenInit(creator, address(this),_initialTokens[0], _initialBalances[0], initialSupply); emit SizeChanged(creator, "UPPER", oldCap, etfStatus.upperCap); emit SizeChanged(creator, "FLOOR", oldFloor, etfStatus.floorCap); uint period; uint collectEndTime = block.timestamp + collectPeriod; if (closurePeriod == SmartPoolManager.Period.DAY90) { // TODO period = 20 minutes; // test // period = 90 days; // production } else if (closurePeriod == SmartPoolManager.Period.DAY1) { period = 1 days; } else if (closurePeriod == SmartPoolManager.Period.DAY3) { period = 3 days; } else if (closurePeriod == SmartPoolManager.Period.DAY7) { period = 7 days; } else if (closurePeriod == SmartPoolManager.Period.DAY14) { period = 14 days; } else if (closurePeriod == SmartPoolManager.Period.DAY30) { period = 30 days; } else if (closurePeriod == SmartPoolManager.Period.DAY180) { period = 180 days; } else { period = 360 days; } uint closureEndTime = collectEndTime + period; etfStatus.collectPeriod = collectPeriod; etfStatus.collectEndTime = collectEndTime; etfStatus.closurePeriod = period; etfStatus.closureEndTime = closureEndTime; IUserVault(bFactory.getUserVault()).recordTokenInfo(creator, creator, _initialTokens, _initialBalances); } createPoolInternal(initialSupply); } /** * @notice Join a pool * @dev Emits a LogJoin event (for each token) * bPool is a contract interface; function calls on it are external * @param poolAmountOut - number of pool tokens to receive * @param maxAmountsIn - Max amount of asset tokens to spend */ function joinPool( uint poolAmountOut, uint[] calldata maxAmountsIn, address kol, address user ) external logs lock needsBPool notPaused { SmartPoolManager.joinPoolHandle(rights.canWhitelistLPs, canProvideLiquidity(user), etype == SmartPoolManager.Etypes.CLOSED, etfStatus.collectEndTime); if(rights.canTokenWhiteLists) { require(_initWhiteTokenState(),"ERR_SHOULD_SET_WHITETOKEN"); } // Delegate to library to save space // Library computes actualAmountsIn, and does many validations // Cannot call the push/pull/min from an external library for // any of these pool functions. Since msg.sender can be anybody, // they must be internal uint[] memory actualAmountsIn = SmartPoolManager.joinPool(IConfigurableRightsPool(address(this)), bPool, poolAmountOut, maxAmountsIn, etfStatus.issueFee); // After createPool, token list is maintained in the underlying BPool address[] memory poolTokens = bPool.getCurrentTokens(); uint[] memory issueFeesReceived = new uint[](poolTokens.length); uint _actualIssueFee = etfStatus.issueFee; if (etype == SmartPoolManager.Etypes.CLOSED) { IUserVault(bFactory.getUserVault()).recordTokenInfo(kol, user, poolTokens, actualAmountsIn); if (!isCompletedCollect) { _actualIssueFee = 0; } } for (uint i = 0; i < poolTokens.length; i++) { uint issueFeeReceived = SmartPoolManager.handleTransferInTokens( IConfigurableRightsPool(address(this)), bPool, poolTokens[i], actualAmountsIn[i], _actualIssueFee ); emit LogJoin(user, poolTokens[i], actualAmountsIn[i]); issueFeesReceived[i] = issueFeeReceived; } if (_actualIssueFee != 0) { IVault(vaultAddress).depositIssueRedeemPToken(poolTokens, issueFeesReceived, issueFeesReceived, false); } _mintPoolShare(poolAmountOut); _pushPoolShare(user, poolAmountOut); // checkout the state that elose ETF collect completed and claime fee. bool isCompletedMoment = etype == SmartPoolManager.Etypes.CLOSED && varTotalSupply >= etfStatus.floorCap && !isCompletedCollect; if (isCompletedMoment) { isCompletedCollect = true; SmartPoolManager.handleFeeClaim( IConfigurableRightsPool(address(this)), bPool, poolTokens, etfStatus.issueFee, false ); } } /** * @notice Exit a pool - redeem pool tokens for underlying assets * @dev Emits a LogExit event for each token * bPool is a contract interface; function calls on it are external * @param poolAmountIn - amount of pool tokens to redeem * @param minAmountsOut - minimum amount of asset tokens to receive */ function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut, address user) external logs lock needsBPool notPaused { uint actualPoolAmountIn; bool isCloseEtfCollectEndWithFailure; uint _actualRedeemFee = etfStatus.redeemFee; if(etype == SmartPoolManager.Etypes.CLOSED){ isCloseEtfCollectEndWithFailure = !isCompletedCollect && block.timestamp >= etfStatus.collectEndTime; if(!isCloseEtfCollectEndWithFailure){ // TODO // require(etfStatus.closureEndTime + 5 minutes <= block.timestamp,"ERR_CLOSURE_TIME_NOT_ARRIVED!"); if(!hasClaimManageFee) { _claimManagerFee(); hasClaimManageFee = true; } if(hasSetBeginFund && !hasSetEndFund) snapshotEndAssets(); } if(isCloseEtfCollectEndWithFailure) _actualRedeemFee = 0; } actualPoolAmountIn = SmartPoolManager.exitPoolHandleB( IConfigurableRightsPool(address(this)), etype == SmartPoolManager.Etypes.CLOSED, isCompletedCollect, etfStatus.closureEndTime, etfStatus.collectEndTime, poolAmountIn ); // Library computes actualAmountsOut, and does many validations uint[] memory actualAmountsOut = SmartPoolManager.exitPool(IConfigurableRightsPool(address(this)), bPool, actualPoolAmountIn, minAmountsOut); _pullPoolShare(msg.sender, actualPoolAmountIn); _burnPoolShare(actualPoolAmountIn); // After createPool, token list is maintained in the underlying BPool address[] memory poolTokens = bPool.getCurrentTokens(); uint[] memory redeemFeesReceived = new uint[](poolTokens.length); for (uint i = 0; i < poolTokens.length; i++) { (, uint finalAmountOut, uint redeemFeeReceived) = SmartPoolManager.exitPoolHandleA( IConfigurableRightsPool(address(this)), bPool, poolTokens[i], actualAmountsOut[i], _actualRedeemFee ); redeemFeesReceived[i] = redeemFeeReceived; emit LogExit(user, poolTokens[i], finalAmountOut); } if (_actualRedeemFee != 0) { IVault(vaultAddress).depositIssueRedeemPToken(poolTokens, redeemFeesReceived, redeemFeesReceived, true); } } /** * @notice Add to the whitelist of liquidity providers (if enabled) * @param provider - address of the liquidity provider */ function whitelistLiquidityProvider(address provider) external onlyOwner lock logs { SmartPoolManager.WhitelistHandle(rights.canWhitelistLPs, true, provider); _liquidityProviderWhitelist[provider] = true; } /** * @notice Remove from the whitelist of liquidity providers (if enabled) * @param provider - address of the liquidity provider */ function removeWhitelistedLiquidityProvider(address provider) external onlyOwner lock logs { SmartPoolManager.WhitelistHandle(rights.canWhitelistLPs, _liquidityProviderWhitelist[provider], provider); _liquidityProviderWhitelist[provider] = false; } /** * @notice Check if an address is a liquidity provider * @dev If the whitelist feature is not enabled, anyone can provide liquidity (assuming finalized) * @return boolean value indicating whether the address can join a pool */ function canProvideLiquidity(address provider) public view returns (bool) { if (rights.canWhitelistLPs) { return _liquidityProviderWhitelist[provider] || provider == getController() ; } else { // Probably don't strictly need this (could just return true) // But the null address can't provide funds return provider != address(0); } } /** * @notice Getter for specific permissions * @dev value of the enum is just the 0-based index in the enumeration * @return token boolean true if we have the given permission */ function hasPermission(RightsManager.Permissions permission) external view virtual returns (bool) { return RightsManager.hasPermission(rights, permission); } /** * @notice Getter for the RightsManager contract * @dev Convenience function to get the address of the RightsManager library (so clients can check version) * @return address of the RightsManager library */ function getRightsManagerVersion() external pure returns (address) { return address(RightsManager); } /** * @notice Getter for the DesynSafeMath contract * @dev Convenience function to get the address of the DesynSafeMath library (so clients can check version) * @return address of the DesynSafeMath library */ function getDesynSafeMathVersion() external pure returns (address) { return address(DesynSafeMath); } /** * @notice Getter for the SmartPoolManager contract * @dev Convenience function to get the address of the SmartPoolManager library (so clients can check version) * @return address of the SmartPoolManager library */ function getSmartPoolManagerVersion() external pure returns (address) { return address(SmartPoolManager); } // "Public" versions that can safely be called from SmartPoolManager // Allows only the contract itself to call them (not the controller or any external account) function mintPoolShareFromLib(uint amount) public { require(msg.sender == address(this), "ERR_NOT_CONTROLLER"); _mint(amount); } function pushPoolShareFromLib(address to, uint amount) public { require(msg.sender == address(this), "ERR_NOT_CONTROLLER"); _push(to, amount); } function pullPoolShareFromLib(address from, uint amount) public { require(msg.sender == address(this), "ERR_NOT_CONTROLLER"); _pull(from, amount); } function burnPoolShareFromLib(uint amount) public { require(msg.sender == address(this), "ERR_NOT_CONTROLLER"); _burn(amount); } /** * @notice Create a new Smart Pool * @dev Initialize the swap fee to the value provided in the CRP constructor * @param initialSupply starting token balance */ function createPoolInternal(uint initialSupply) internal { require(address(bPool) == address(0), "ERR_IS_CREATED"); // To the extent possible, modify state variables before calling functions _mintPoolShare(initialSupply); _pushPoolShare(msg.sender, initialSupply); // Deploy new BPool (bFactory and bPool are interfaces; all calls are external) bPool = bFactory.newLiquidityPool(); // EXIT_FEE must always be zero, or ConfigurableRightsPool._pushUnderlying will fail SmartPoolManager.createPoolInternalHandle(bPool, initialSupply); for (uint i = 0; i < _initialTokens.length; i++) { address t = _initialTokens[i]; uint bal = _initialBalances[i]; uint denorm = _initialWeights[i]; _verifyWhiteToken(t); IERC20(t).safeTransferFrom(msg.sender, address(this), bal); IERC20(t).safeApprove(address(bPool), 0); IERC20(t).safeApprove(address(bPool), DesynConstants.MAX_UINT); bPool.bind(t, bal, denorm); } while (_initialTokens.length > 0) { // Modifying state variable after external calls here, // but not essential, so not dangerous _initialTokens.pop(); } } function addTokenToWhitelist(uint[] memory sort, address[] memory token) external onlyOwner { require(rights.canTokenWhiteLists && !hasSetWhiteTokens, "ERR_NO_RIGHTS"); require(sort.length == token.length, "ERR_SORT_TOKEN_MISMATCH"); for (uint i = 0; i < token.length; i++) { bool inRange = bFactory.isTokenWhitelistedForVerify(sort[i], token[i]); require(inRange, "TOKEN_MUST_IN_WHITE_LISTS"); _addTokenToWhitelist(sort[i], token[i]); } hasSetWhiteTokens = true; } function _verifyWhiteToken(address token) public view { require(bFactory.isTokenWhitelistedForVerify(token), "ERR_NOT_WHITE_TOKEN"); if (hasSetWhiteTokens) { require(_queryIsTokenWhitelisted(token), "ERR_NOT_WHITE_TOKEN"); } } // Rebind BPool and pull tokens from address // bPool is a contract interface; function calls on it are external function _pullUnderlying( address erc20, address from, uint amount ) internal needsBPool { // Gets current Balance of token i, Bi, and weight of token i, Wi, from BPool. uint tokenBalance = bPool.getBalance(erc20); uint tokenWeight = bPool.getDenormalizedWeight(erc20); IERC20(erc20).safeTransferFrom(from, address(this), amount); bPool.rebind(erc20, DesynSafeMath.badd(tokenBalance, amount), tokenWeight); } // Rebind BPool and push tokens to address // bPool is a contract interface; function calls on it are external function _pushUnderlying( address erc20, address to, uint amount ) internal needsBPool { // Gets current Balance of token i, Bi, and weight of token i, Wi, from BPool. uint tokenBalance = bPool.getBalance(erc20); uint tokenWeight = bPool.getDenormalizedWeight(erc20); bPool.rebind(erc20, DesynSafeMath.bsub(tokenBalance, amount), tokenWeight); IERC20(erc20).safeTransfer(to, amount); } // Wrappers around corresponding core functions function _mint(uint amount) internal override { super._mint(amount); require(varTotalSupply <= etfStatus.upperCap, "ERR_CAP_LIMIT_REACHED"); } function _mintPoolShare(uint amount) internal { _mint(amount); } function _pushPoolShare(address to, uint amount) internal { _push(to, amount); } function _pullPoolShare(address from, uint amount) internal { _pull(from, amount); } function _burnPoolShare(uint amount) internal { _burn(amount); } // ================ SnapshotAssets ================ function snapshotBeginAssets() external logs { uint nowTime = block.timestamp; // TODO require(!hasSetBeginFund && isCompletedCollect && etype == SmartPoolManager.Etypes.CLOSED && nowTime <= (etfStatus.collectEndTime + 15 minutes) , "ERR_CONDITIONS_NOT_MET"); // TODO // bool inT1 = nowTime <= (etfStatus.collectEndTime + 1 days) ; bool inT1 = nowTime <= (etfStatus.collectEndTime + 5 minutes) ; // for test if(inT1) require(adminList[msg.sender] || msg.sender == _owner, "onlyAdmin"); beginFund = snapshotAssets(); hasSetBeginFund = true; if(nowTime < etfStatus.collectEndTime) etfStatus.collectEndTime = block.timestamp; } function beginFundAssets() external view returns(SmartPoolManager.Fund memory){ return beginFund; } function endFundAssets() external view returns(SmartPoolManager.Fund memory){ return endFund; } function snapshotEndAssets() public logs { uint nowTime = block.timestamp; require(!hasSetEndFund && hasSetBeginFund && etype == SmartPoolManager.Etypes.CLOSED && nowTime >= etfStatus.closureEndTime, "ERR_CONDITIONS_NOT_MET"); // TODO bool inT1 = (etfStatus.closureEndTime + 5 minutes) >= nowTime ; // for test // bool inT1 = nowTime >= etfStatus.closureEndTime && (etfStatus.closureEndTime + 1 days) >= nowTime ; if(inT1) require(adminList[msg.sender] || msg.sender == _owner, "onlyAdmin"); endFund = snapshotAssets(); uint preShareValueEnd = endFund.fundAmount.bdiv(endFund.etfAmount); uint preShareValueBegin = beginFund.fundAmount.bdiv(beginFund.etfAmount); if(preShareValueEnd > preShareValueBegin){ uint perfermanceRatio = etfStatus.perfermanceFee.bmul(preShareValueEnd-preShareValueBegin).bdiv(preShareValueEnd); // claim perfomance reward SmartPoolManager.handleFeeClaim( IConfigurableRightsPool(address(this)), bPool, bPool.getCurrentTokens(), perfermanceRatio, true); } hasSetEndFund = true; } function snapshotAssets() public returns(SmartPoolManager.Fund memory){ SmartPoolManager.Fund memory tempFund; tempFund.etfAmount = varTotalSupply; (tempFund.tokens, tempFund.tokensAmount) = _getPoolTokensInfo(); tempFund.fundAmount = Oracles(bFactory.getOracleAddress()).getAllPrice(tempFund.tokens, tempFund.tokensAmount); tempFund.snapshotTime = block.timestamp; return tempFund; } function _getPoolTokensInfo() internal view returns (address[] memory, uint[] memory) { address[] memory tokens = bPool.getCurrentTokens(); uint[] memory totalBalances = new uint[](tokens.length); for(uint i; i < tokens.length ;i++) { totalBalances[i] = bPool.getBalance(tokens[i]); } return (tokens,totalBalances); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Imports import "../libraries/DesynSafeMath.sol"; import "../interfaces/IERC20.sol"; // Contracts /* solhint-disable func-order */ /** * @author Desyn Labs * @title Highly opinionated token implementation */ contract PCToken is IERC20 { using DesynSafeMath for uint; // State variables string public constant NAME = "Desyn Smart Pool"; uint8 public constant DECIMALS = 18; // No leading underscore per naming convention (non-private) // Cannot call totalSupply (name conflict) // solhint-disable-next-line private-vars-leading-underscore uint internal varTotalSupply; mapping(address => uint) private _balance; mapping(address => mapping(address => uint)) private _allowance; string private _symbol; string private _name; // Event declarations // See definitions above; must be redeclared to be emitted from this contract event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); // Function declarations /** * @notice Base token constructor * @param tokenSymbol - the token symbol */ constructor(string memory tokenSymbol, string memory tokenName) public { _symbol = tokenSymbol; _name = tokenName; } // External functions /** * @notice Getter for allowance: amount spender will be allowed to spend on behalf of owner * @param owner - owner of the tokens * @param spender - entity allowed to spend the tokens * @return uint - remaining amount spender is allowed to transfer */ function allowance(address owner, address spender) external view override returns (uint) { return _allowance[owner][spender]; } /** * @notice Getter for current account balance * @param account - address we're checking the balance of * @return uint - token balance in the account */ function balanceOf(address account) external view override returns (uint) { return _balance[account]; } /** * @notice Approve owner (sender) to spend a certain amount * @dev emits an Approval event * @param spender - entity the owner (sender) is approving to spend his tokens * @param amount - number of tokens being approved * @return bool - result of the approval (will always be true if it doesn't revert) */ function approve(address spender, uint amount) external override returns (bool) { /* In addition to the increase/decreaseApproval functions, could avoid the "approval race condition" by only allowing calls to approve when the current approval amount is 0 require(_allowance[msg.sender][spender] == 0, "ERR_RACE_CONDITION"); Some token contracts (e.g., KNC), already revert if you call approve on a non-zero allocation. To deal with these, we use the SafeApprove library and safeApprove function when adding tokens to the pool. */ _allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } /** * @notice Increase the amount the spender is allowed to spend on behalf of the owner (sender) * @dev emits an Approval event * @param spender - entity the owner (sender) is approving to spend his tokens * @param amount - number of tokens being approved * @return bool - result of the approval (will always be true if it doesn't revert) */ function increaseApproval(address spender, uint amount) external returns (bool) { _allowance[msg.sender][spender] = DesynSafeMath.badd(_allowance[msg.sender][spender], amount); emit Approval(msg.sender, spender, _allowance[msg.sender][spender]); return true; } /** * @notice Decrease the amount the spender is allowed to spend on behalf of the owner (sender) * @dev emits an Approval event * @dev If you try to decrease it below the current limit, it's just set to zero (not an error) * @param spender - entity the owner (sender) is approving to spend his tokens * @param amount - number of tokens being approved * @return bool - result of the approval (will always be true if it doesn't revert) */ function decreaseApproval(address spender, uint amount) external returns (bool) { uint oldValue = _allowance[msg.sender][spender]; // Gas optimization - if amount == oldValue (or is larger), set to zero immediately if (amount >= oldValue) { _allowance[msg.sender][spender] = 0; } else { _allowance[msg.sender][spender] = DesynSafeMath.bsub(oldValue, amount); } emit Approval(msg.sender, spender, _allowance[msg.sender][spender]); return true; } /** * @notice Transfer the given amount from sender (caller) to recipient * @dev _move emits a Transfer event if successful * @param recipient - entity receiving the tokens * @param amount - number of tokens being transferred * @return bool - result of the transfer (will always be true if it doesn't revert) */ function transfer(address recipient, uint amount) external override returns (bool) { require(recipient != address(0), "ERR_ZERO_ADDRESS"); _move(msg.sender, recipient, amount); return true; } /** * @notice Transfer the given amount from sender to recipient * @dev _move emits a Transfer event if successful; may also emit an Approval event * @param sender - entity sending the tokens (must be caller or allowed to spend on behalf of caller) * @param recipient - recipient of the tokens * @param amount - number of tokens being transferred * @return bool - result of the transfer (will always be true if it doesn't revert) */ function transferFrom( address sender, address recipient, uint amount ) external override returns (bool) { require(recipient != address(0), "ERR_ZERO_ADDRESS"); require(msg.sender == sender || amount <= _allowance[sender][msg.sender], "ERR_PCTOKEN_BAD_CALLER"); _move(sender, recipient, amount); // memoize for gas optimization uint oldAllowance = _allowance[sender][msg.sender]; // If the sender is not the caller, adjust the allowance by the amount transferred if (msg.sender != sender && oldAllowance != uint(-1)) { _allowance[sender][msg.sender] = DesynSafeMath.bsub(oldAllowance, amount); emit Approval(sender, msg.sender, _allowance[sender][msg.sender]); } return true; } // public functions /** * @notice Getter for the total supply * @dev declared external for gas optimization * @return uint - total number of tokens in existence */ function totalSupply() external view override returns (uint) { return varTotalSupply; } // Public functions /** * @dev Returns the name of the token. * We allow the user to set this name (as well as the symbol). * Alternatives are 1) A fixed string (original design) * 2) A fixed string plus the user-defined symbol * return string(abi.encodePacked(NAME, "-", _symbol)); */ function name() external view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() external view override returns (uint8) { return DECIMALS; } // internal functions // Mint an amount of new tokens, and add them to the balance (and total supply) // Emit a transfer amount from the null address to this contract function _mint(uint amount) internal virtual { _balance[address(this)] = DesynSafeMath.badd(_balance[address(this)], amount); varTotalSupply = DesynSafeMath.badd(varTotalSupply, amount); emit Transfer(address(0), address(this), amount); } // Burn an amount of new tokens, and subtract them from the balance (and total supply) // Emit a transfer amount from this contract to the null address function _burn(uint amount) internal virtual { // Can't burn more than we have // Remove require for gas optimization - bsub will revert on underflow // require(_balance[address(this)] >= amount, "ERR_INSUFFICIENT_BAL"); _balance[address(this)] = DesynSafeMath.bsub(_balance[address(this)], amount); varTotalSupply = DesynSafeMath.bsub(varTotalSupply, amount); emit Transfer(address(this), address(0), amount); } // Transfer tokens from sender to recipient // Adjust balances, and emit a Transfer event function _move( address sender, address recipient, uint amount ) internal virtual { // Can't send more than sender has // Remove require for gas optimization - bsub will revert on underflow // require(_balance[sender] >= amount, "ERR_INSUFFICIENT_BAL"); _balance[sender] = DesynSafeMath.bsub(_balance[sender], amount); _balance[recipient] = DesynSafeMath.badd(_balance[recipient], amount); emit Transfer(sender, recipient, amount); } // Transfer from this contract to recipient // Emits a transfer event if successful function _push(address recipient, uint amount) internal { _move(address(this), recipient, amount); } // Transfer from recipient to this contract // Emits a transfer event if successful function _pull(address sender, uint amount) internal { _move(sender, address(this), amount); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract DesynOwnable { // State variables mapping(address => bool) public adminList; uint public allOwnerPercentage = 10000; address _owner; address[] owners; uint[] ownerPercentage; bool initialized; // Event declarations event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); event AddAdmin(address indexed newAdmin, uint indexed amount); event RemoveAdmin(address indexed oldAdmin, uint indexed amount); // Modifiers /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == msg.sender, "ERR_NOT_CONTROLLER"); _; } modifier onlyAdmin() { require(adminList[msg.sender] || msg.sender == _owner, "onlyAdmin"); _; } // Function declarations /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() internal { _owner = msg.sender; } function initHandle(address[] memory _owners, uint[] memory _ownerPercentage) external { require(_owners.length == _ownerPercentage.length, "ownerP"); require(!initialized, "initialized!"); _addAdmin(_owners); owners = _owners; ownerPercentage = _ownerPercentage; initialized = true; _ownerPercentageChecker(); } function setManagersInfo(address[] memory _owners, uint[] memory _ownerPercentage) external onlyOwner { _beforeControllerChange(); _clearAdmin(); _addAdmin(_owners); owners = _owners; ownerPercentage = _ownerPercentage; _ownerPercentageChecker(); } function _ownerPercentageChecker() internal view { uint totalPercentage; for (uint i; i < ownerPercentage.length; i++) { totalPercentage+=ownerPercentage[i]; } require(totalPercentage == 10000, "ERR_ILLEGAL_PERCENTAGE"); } function _addAdmin(address[] memory admins) internal { bool hasOwner; for (uint i; i < admins.length; i++) { adminList[admins[i]] = true; if(admins[i] == _owner) hasOwner = true; } if(initialized) require(hasOwner, "ERR_NEW_ADMINS_HAS_NO_OWNER"); } function _clearAdmin() internal { for(uint i; i < owners.length; i++) { delete adminList[owners[i]]; } } /** * @notice Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner * @dev external for gas optimization * @param newOwner - address of new owner */ function setController(address newOwner) external onlyOwner { _beforeControllerChange(); require(newOwner != address(0), "ERR_ZERO_ADDRESS"); emit OwnershipTransferred(_owner, newOwner); for (uint i;i < owners.length; i++) { if (owners[i] == _owner) { owners[i] = newOwner; } } adminList[_owner] = false; adminList[newOwner] = true; _owner = newOwner; } // @dev Returns list of owners. // @return List of owner addresses. function getOwners() external view returns (address[] memory) { return owners; } // @dev Returns list of owners. // @return List of owner addresses. function getOwnerPercentage() external view returns (uint[] memory) { return ownerPercentage; } /** * @notice Returns the address of the current owner * @dev external for gas optimization * @return address - of the owner (AKA controller) */ function getController() public view returns (address) { return _owner; } function _beforeControllerChange() internal virtual {} }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; // Imports import "../interfaces/IERC20.sol"; // Libraries /** * @author PieDAO (ported to Desyn Labs) * @title SafeApprove - set approval for tokens that require 0 prior approval * @dev Perhaps to address the known ERC20 race condition issue * See https://github.com/crytic/not-so-smart-contracts/tree/master/race_condition * Some tokens - notably KNC - only allow approvals to be increased from 0 */ library SafeApprove { /** * @notice handle approvals of tokens that require approving from a base of 0 * @param token - the token we're approving * @param spender - entity the owner (sender) is approving to spend his tokens * @param amount - number of tokens being approved */ function safeApprove( IERC20 token, address spender, uint amount ) internal returns (bool) { uint currentAllowance = token.allowance(address(this), spender); // Do nothing if allowance is already set to this value if (currentAllowance == amount) { return true; } // If approval is not zero reset it to zero first if (currentAllowance != 0) { token.approve(spender, 0); } // do the actual approval return token.approve(spender, amount); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; contract WhiteToken { // add token log event LOG_WHITELIST(address indexed spender, uint indexed sort, address indexed caller, address token); // del token log event LOG_DEL_WHITELIST(address indexed spender, uint indexed sort, address indexed caller, address token); // record the number of whitelists. uint private _whiteTokenCount; // token address => is white token. mapping(address => bool) private _isTokenWhitelisted; // Multi level white token. // type => token address => is white token. mapping(uint => mapping(address => bool)) private _tokenWhitelistedInfo; function _queryIsTokenWhitelisted(address token) internal view returns (bool) { return _isTokenWhitelisted[token]; } // for factory to verify function _isTokenWhitelistedForVerify(uint sort, address token) internal view returns (bool) { return _tokenWhitelistedInfo[sort][token]; } // add sort token function _addTokenToWhitelist(uint sort, address token) internal { require(token != address(0), "ERR_INVALID_TOKEN_ADDRESS"); require(_queryIsTokenWhitelisted(token) == false, "ERR_HAS_BEEN_ADDED_WHITE"); _tokenWhitelistedInfo[sort][token] = true; _isTokenWhitelisted[token] = true; _whiteTokenCount++; emit LOG_WHITELIST(address(this), sort, msg.sender, token); } // remove sort token function _removeTokenFromWhitelist(uint sort, address token) internal { require(_queryIsTokenWhitelisted(token) == true, "ERR_NOT_WHITE_TOKEN"); require(_tokenWhitelistedInfo[sort][token], "ERR_SORT_NOT_MATCHED"); _tokenWhitelistedInfo[sort][token] = false; _isTokenWhitelisted[token] = false; _whiteTokenCount--; emit LOG_DEL_WHITELIST(address(this), sort, msg.sender, token); } // already has init function _initWhiteTokenState() internal view returns (bool) { return _whiteTokenCount == 0 ? false : true; } }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is disstributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity 0.6.12; import "../base/WhiteToken.sol"; import "../interfaces/IBFactory.sol"; import "../libraries/SafeERC20.sol"; contract Factory is WhiteToken { using SafeERC20 for IERC20; event LOG_NEW_POOL(address indexed caller, address indexed pool); event LOG_BLABS(address indexed caller, address indexed blabs); event LOG_ROUTER(address indexed caller, address indexed router); event LOG_VAULT(address indexed vault, address indexed caller); event LOG_USER_VAULT(address indexed vault, address indexed caller); event LOG_MANAGER(address indexed manager, address indexed caller); event LOG_ORACLE(address indexed caller, address indexed oracle); event SYSTEM_MODULE_CHANGED(address module, bool state); event MODULE_STATUS_CHANGE(address etf, address module, bool status); event PAUSED_STATUS(bool state); mapping(address => bool) private _isLiquidityPool; mapping(address => bool) private _isSystemModule; mapping(address => mapping(address => bool)) private _isModuleRegistered; uint private counters; bytes private bytecodes; bool public isPaused; address private _blabs; address private _oracle; address private _vaultAddress; address private _userVaultAddress; constructor( address oracle, address vault, address userVault ) public { _blabs = msg.sender; _oracle = oracle; _vaultAddress = vault; _userVaultAddress = userVault; } function addTokenToWhitelist(uint[] memory sort, address[] memory token) external onlyBlabs { require(sort.length == token.length, "ERR_SORT_TOKEN_MISMATCH"); for (uint i = 0; i < sort.length; i++) { _addTokenToWhitelist(sort[i], token[i]); } } function removeTokenFromWhitelist(uint[] memory sort, address[] memory token) external onlyBlabs { require(sort.length == token.length, "ERR_SORT_TOKEN_MISMATCH"); for (uint i = 0; i < sort.length; i++) { _removeTokenFromWhitelist(sort[i], token[i]); } } function isTokenWhitelistedForVerify(uint sort, address token) external view returns (bool) { return _isTokenWhitelistedForVerify(sort, token); } function isTokenWhitelistedForVerify(address token) external view returns (bool) { return _queryIsTokenWhitelisted(token); } function isLiquidityPool(address b) external view returns (bool) { return _isLiquidityPool[b]; } function createPool() internal returns (address base) { bytes memory bytecode = bytecodes; bytes32 salt = keccak256(abi.encodePacked(counters++)); assembly { base := create2(0, add(bytecode, 32), mload(bytecode), salt) if iszero(extcodesize(base)) { revert(0, 0) } } counters++; } function newLiquidityPool() external returns (IBPool) { address lpool = createPool(); _isLiquidityPool[lpool] = true; emit LOG_NEW_POOL(msg.sender, lpool); IBPool(lpool).setController(msg.sender); return IBPool(lpool); } function getBLabs() external view returns (address) { return _blabs; } function setBLabs(address b) external onlyBlabs { require(b != address(0), "ERR_ZERO_ADDRESS"); emit LOG_BLABS(msg.sender, b); _blabs = b; } function getModuleStatus(address etf, address module) external view returns (bool) { return _isSystemModule[module] || _isModuleRegistered[etf][module]; } function getOracleAddress() external view returns (address) { return _oracle; } function setSystemModule(address module, bool state) external onlyBlabs { require(module != address(0), "ZERO ADDRESS"); _isSystemModule[module] = state; emit SYSTEM_MODULE_CHANGED(module, state); } function registerModule(address etf, address module) external onlyBlabs { require(etf != address(0), "ZERO ETF ADDRESS"); require(module != address(0), "ZERO ADDRESS"); _isModuleRegistered[etf][module] = true; emit MODULE_STATUS_CHANGE(etf, module, true); } function removeModule(address etf, address module) external onlyBlabs { require(etf != address(0), "ZERO ETF ADDRESS"); require(module != address(0), "ZERO ADDRESS"); _isModuleRegistered[etf][module] = false; emit MODULE_STATUS_CHANGE(etf, module, false); } function setOracle(address oracle) external onlyBlabs { require(oracle != address(0), "ERR_ZERO_ADDRESS"); emit LOG_ORACLE(msg.sender, oracle); _oracle = oracle; } function collect(IERC20 token) external onlyBlabs { uint collected = token.balanceOf(address(this)); token.safeTransfer(_blabs, collected); } function getVault() external view returns (address) { return _vaultAddress; } function setVault(address newVault) external onlyBlabs { require(newVault != address(0), "ERR_ZERO_ADDRESS"); _vaultAddress = newVault; emit LOG_VAULT(newVault, msg.sender); } function getUserVault() external view returns (address) { return _userVaultAddress; } function setUserVault(address newVault) external onlyBlabs { require(newVault != address(0), "ERR_ZERO_ADDRESS"); _userVaultAddress = newVault; emit LOG_USER_VAULT(newVault, msg.sender); } function setProtocolPaused(bool state) external onlyBlabs { isPaused = state; emit PAUSED_STATUS(state); } function setByteCodes(bytes memory _bytecode) external onlyBlabs { bytecodes = _bytecode; } modifier onlyBlabs() { require(msg.sender == _blabs, "ERR_NOT_BLABS"); _; } }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity 0.6.12; import "./LpToken.sol"; import "./Math.sol"; import "../interfaces/IBFactory.sol"; import "../interfaces/IConfigurableRightsPool.sol"; import "../libraries/Address.sol"; import "../libraries/SafeERC20.sol"; contract LiquidityPool is BBronze, LpToken, Math { using Address for address; using SafeERC20 for IERC20; struct Record { bool bound; // is token bound to pool uint index; // private uint denorm; // denormalized weight uint balance; } event LOG_JOIN(address indexed caller, address indexed tokenIn, uint tokenAmountIn); event LOG_EXIT(address indexed caller, address indexed tokenOut, uint tokenAmountOut); event LOG_REBALANCE(address indexed tokenA, address indexed tokenB, uint newWeightA, uint newWeightB, uint newBalanceA, uint newBalanceB, bool isSoldout); event LOG_CALL(bytes4 indexed sig, address indexed caller, bytes data) anonymous; modifier _logs_() { emit LOG_CALL(msg.sig, msg.sender, msg.data); _; } modifier _lock_() { require(!_mutex, "ERR_REENTRY"); _mutex = true; _; _mutex = false; } modifier _viewlock_() { require(!_mutex, "ERR_REENTRY"); _; } bool private _mutex; IBFactory private _factory; // Factory address to push token exitFee to address private _controller; // has CONTROL role bool private _publicSwap; // true if PUBLIC can call SWAP functions // `finalize` sets `PUBLIC can SWAP`, `PUBLIC can JOIN` bool private _finalized; address[] private _tokens; mapping(address => Record) private _records; uint private _totalWeight; constructor() public { _controller = msg.sender; _factory = IBFactory(msg.sender); _publicSwap = false; _finalized = false; } function isPublicSwap() external view returns (bool) { return _publicSwap; } function isFinalized() external view returns (bool) { return _finalized; } function isBound(address t) external view returns (bool) { return _records[t].bound; } function getNumTokens() external view returns (uint) { return _tokens.length; } function getCurrentTokens() external view _viewlock_ returns (address[] memory tokens) { return _tokens; } function getFinalTokens() external view _viewlock_ returns (address[] memory tokens) { require(_finalized, "ERR_NOT_FINALIZED"); return _tokens; } function getDenormalizedWeight(address token) external view _viewlock_ returns (uint) { // require(_records[token].bound, "ERR_NOT_BOUND"); return _records[token].denorm; } function getTotalDenormalizedWeight() external view _viewlock_ returns (uint) { return _totalWeight; } function getNormalizedWeight(address token) external _viewlock_ returns (uint) { require(_records[token].bound, "ERR_NOT_BOUND"); Oracles oracle = Oracles(_factory.getOracleAddress()); uint denorm = _records[token].denorm; uint price = oracle.getPrice(token); uint[] memory _balances = new uint[](_tokens.length); for (uint i = 0; i < _tokens.length; i++) { _balances[i] = getBalance(_tokens[i]); } uint totalValue = oracle.getAllPrice(_tokens, _balances); uint currentValue = bmul(price, getBalance(token)); return bdiv(currentValue, totalValue); } function getBalance(address token) public view _viewlock_ returns (uint) { // require(_records[token].bound, "ERR_NOT_BOUND"); return _records[token].balance; } function getController() external view _viewlock_ returns (address) { return _controller; } function setController(address manager) external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(manager != address(0), "ERR_ZERO_ADDRESS"); _controller = manager; } function setPublicSwap(bool public_) external _logs_ _lock_ { require(!_finalized, "ERR_IS_FINALIZED"); require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); _publicSwap = public_; } function finalize() external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(!_finalized, "ERR_IS_FINALIZED"); require(_tokens.length >= MIN_BOUND_TOKENS, "ERR_MIN_TOKENS"); _finalized = true; _publicSwap = true; _mintPoolShare(INIT_POOL_SUPPLY); _pushPoolShare(msg.sender, INIT_POOL_SUPPLY); } function bind( address token, uint balance, uint denorm ) external _logs_ // _lock_ Bind does not lock because it jumps to `rebind`, which does { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(!_records[token].bound, "ERR_IS_BOUND"); require(!_finalized, "ERR_IS_FINALIZED"); require(_tokens.length < MAX_BOUND_TOKENS, "ERR_MAX_TOKENS"); _records[token] = Record({ bound: true, index: _tokens.length, denorm: 0, // balance and denorm will be validated balance: 0 // and set by `rebind` }); _tokens.push(token); rebind(token, balance, denorm); } function rebind( address token, uint balance, uint denorm ) public _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(_records[token].bound, "ERR_NOT_BOUND"); require(!_finalized, "ERR_IS_FINALIZED"); require(denorm >= MIN_WEIGHT, "ERR_MIN_WEIGHT"); require(denorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT"); require(balance >= MIN_BALANCE, "ERR_MIN_BALANCE"); // Adjust the denorm and totalWeight uint oldWeight = _records[token].denorm; if (denorm > oldWeight) { _totalWeight = badd(_totalWeight, bsub(denorm, oldWeight)); require(_totalWeight <= MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT"); } else if (denorm < oldWeight) { _totalWeight = bsub(_totalWeight, bsub(oldWeight, denorm)); } _records[token].denorm = denorm; // Adjust the balance record and actual token balance uint oldBalance = _records[token].balance; _records[token].balance = balance; if (balance > oldBalance) { _pullUnderlying(token, msg.sender, bsub(balance, oldBalance)); } else if (balance < oldBalance) { // In this case liquidity is being withdrawn, so charge EXIT_FEE uint tokenBalanceWithdrawn = bsub(oldBalance, balance); _pushUnderlying(token, msg.sender, tokenBalanceWithdrawn); } } function execute( address _target, uint _value, bytes calldata _data ) external _logs_ _lock_ returns (bytes memory _returnValue) { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(!_finalized, "ERR_IS_FINALIZED"); _returnValue = _target.functionCallWithValue(_data, _value); return _returnValue; } function unbind(address token) external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(_records[token].bound, "ERR_NOT_BOUND"); require(!_finalized, "ERR_IS_FINALIZED"); uint tokenBalance = _records[token].balance; _totalWeight = bsub(_totalWeight, _records[token].denorm); // Swap the token-to-unbind with the last token, // then delete the last token uint index = _records[token].index; uint last = _tokens.length - 1; _tokens[index] = _tokens[last]; _records[_tokens[index]].index = index; _tokens.pop(); _records[token] = Record({bound: false, index: 0, denorm: 0, balance: 0}); _pushUnderlying(token, msg.sender, tokenBalance); } function unbindPure(address token) external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(_records[token].bound, "ERR_NOT_BOUND"); require(!_finalized, "ERR_IS_FINALIZED"); // Swap the token-to-unbind with the last token, // then delete the last token uint index = _records[token].index; uint last = _tokens.length - 1; _tokens[index] = _tokens[last]; _records[_tokens[index]].index = index; _tokens.pop(); _records[token] = Record({bound: false, index: 0, denorm: 0, balance: 0}); } function rebindPure( address token, uint balance, uint denorm, bool isBound ) public _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); if (!isBound) { require(_tokens.length < MAX_BOUND_TOKENS, "ERR_MAX_TOKENS"); _records[token] = Record({ bound: true, index: _tokens.length, denorm: denorm, balance: balance }); _tokens.push(token); } else { _records[token].denorm = denorm; _records[token].balance = balance; } } // Absorb any tokens that have been sent to this contract into the pool function gulp(address token) external _logs_ _lock_ { require(IConfigurableRightsPool(_controller).adminList(msg.sender), 'NOT_ADMIN'); require(_records[token].bound, "ERR_NOT_BOUND"); _records[token].balance = IERC20(token).balanceOf(address(this)); } function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(_finalized, "ERR_NOT_FINALIZED"); uint poolTotal = this.totalSupply(); uint ratio = bdiv(poolAmountOut, poolTotal); require(ratio != 0, "ERR_MATH_APPROX"); for (uint i = 0; i < _tokens.length; i++) { address t = _tokens[i]; uint bal = _records[t].balance; uint tokenAmountIn = bmul(ratio, bal); require(tokenAmountIn != 0, "ERR_MATH_APPROX"); require(tokenAmountIn <= maxAmountsIn[i], "ERR_LIMIT_IN"); _records[t].balance = badd(_records[t].balance, tokenAmountIn); emit LOG_JOIN(msg.sender, t, tokenAmountIn); _pullUnderlying(t, msg.sender, tokenAmountIn); } _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); } function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external _logs_ _lock_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); require(_finalized, "ERR_NOT_FINALIZED"); uint poolTotal = this.totalSupply(); uint ratio = bdiv(poolAmountIn, poolTotal); require(ratio != 0, "ERR_MATH_APPROX"); _pullPoolShare(msg.sender, poolAmountIn); _burnPoolShare(poolAmountIn); for (uint i = 0; i < _tokens.length; i++) { address t = _tokens[i]; uint bal = _records[t].balance; uint tokenAmountOut = bmul(ratio, bal); require(tokenAmountOut != 0, "ERR_MATH_APPROX"); require(tokenAmountOut >= minAmountsOut[i], "ERR_LIMIT_OUT"); _records[t].balance = bsub(_records[t].balance, tokenAmountOut); emit LOG_EXIT(msg.sender, t, tokenAmountOut); _pushUnderlying(t, msg.sender, tokenAmountOut); } } function _pullUnderlying( address erc20, address from, uint amount ) internal { IERC20(erc20).safeTransferFrom(from, address(this), amount); } function _pushUnderlying( address erc20, address to, uint amount ) internal { IERC20(erc20).safeTransfer(to, amount); } function _pullPoolShare(address from, uint amount) internal { _pull(from, amount); } function _pushPoolShare(address to, uint amount) internal { _push(to, amount); } function _mintPoolShare(uint amount) internal { _mint(amount); } function _burnPoolShare(uint amount) internal { _burn(amount); } receive() external payable {} }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.6.12; import "./Num.sol"; import "../interfaces/IERC20.sol"; // Highly opinionated token implementation contract LpTokenBase is Num { mapping(address => uint) internal _balance; mapping(address => mapping(address => uint)) internal _allowance; uint internal _totalSupply; event Approval(address indexed src, address indexed dst, uint amt); event Transfer(address indexed src, address indexed dst, uint amt); function _mint(uint amt) internal { _balance[address(this)] = badd(_balance[address(this)], amt); _totalSupply = badd(_totalSupply, amt); emit Transfer(address(0), address(this), amt); } function _burn(uint amt) internal { require(_balance[address(this)] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[address(this)] = bsub(_balance[address(this)], amt); _totalSupply = bsub(_totalSupply, amt); emit Transfer(address(this), address(0), amt); } function _move( address src, address dst, uint amt ) internal { require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[src] = bsub(_balance[src], amt); _balance[dst] = badd(_balance[dst], amt); emit Transfer(src, dst, amt); } function _push(address to, uint amt) internal { _move(address(this), to, amt); } function _pull(address from, uint amt) internal { _move(from, address(this), amt); } } contract LpToken is LpTokenBase, IERC20 { string private _name = "Desyn Pool Token"; string private _symbol = "DPT"; uint8 private _decimals = 18; function name() external view returns (string memory) { return _name; } function symbol() external view override returns (string memory) { return _symbol; } function decimals() external view override returns (uint8) { return _decimals; } function allowance(address src, address dst) external view override returns (uint) { return _allowance[src][dst]; } function balanceOf(address whom) external view override returns (uint) { return _balance[whom]; } function totalSupply() external view override returns (uint) { return _totalSupply; } function approve(address dst, uint amt) external override returns (bool) { _allowance[msg.sender][dst] = amt; emit Approval(msg.sender, dst, amt); return true; } function increaseApproval(address dst, uint amt) external returns (bool) { _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt); emit Approval(msg.sender, dst, _allowance[msg.sender][dst]); return true; } function decreaseApproval(address dst, uint amt) external returns (bool) { uint oldValue = _allowance[msg.sender][dst]; if (amt > oldValue) { _allowance[msg.sender][dst] = 0; } else { _allowance[msg.sender][dst] = bsub(oldValue, amt); } emit Approval(msg.sender, dst, _allowance[msg.sender][dst]); return true; } function transfer(address dst, uint amt) external override returns (bool) { require(dst != address(0),"ERR_BAD_RECIVER"); _move(msg.sender, dst, amt); return true; } function transferFrom( address src, address dst, uint amt ) external override returns (bool) { require(dst != address(0),"ERR_BAD_RECIVER"); require(msg.sender == src || amt <= _allowance[src][msg.sender], "ERR_LPTOKEN_BAD_CALLER"); _move(src, dst, amt); if (msg.sender != src && _allowance[src][msg.sender] != uint(-1)) { _allowance[src][msg.sender] = bsub(_allowance[src][msg.sender], amt); emit Approval(src, msg.sender, _allowance[src][msg.sender]); } return true; } }
{ "optimizer": { "enabled": true, "runs": 20 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"share","type":"address"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenReturn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReturn","type":"uint256"}],"name":"SmartExitPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"shareReturn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReturn","type":"uint256"}],"name":"SmartJoinPool","type":"event"},{"inputs":[],"name":"FACTORY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STBT","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"crp","type":"address"},{"internalType":"uint256[]","name":"sort","type":"uint256[]"},{"internalType":"address[]","name":"token","type":"address[]"}],"name":"addTokenToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RebalaceAdapter","name":"rebalanceAdapter","type":"address"},{"internalType":"address","name":"etf","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approveUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"pool","type":"address"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"},{"internalType":"uint256","name":"minSwapReturn","type":"uint256"},{"internalType":"address","name":"handleToken","type":"address"},{"components":[{"internalType":"address","name":"aggregator","type":"address"},{"internalType":"address","name":"rebalanceAdapter","type":"address"},{"internalType":"enum IAggregator.SwapType","name":"swapType","type":"uint8"}],"internalType":"struct IAggregator.SwapInfoBase","name":"swapBase","type":"tuple"},{"components":[{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IAggregator.SwapData[]","name":"swapDatas","type":"tuple[]"}],"name":"autoExitSmartPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"pool","type":"address"},{"internalType":"address","name":"kol","type":"address"},{"internalType":"uint256","name":"issueAmount","type":"uint256"},{"internalType":"uint256","name":"minPoolAmountOut","type":"uint256"},{"internalType":"address","name":"handleToken","type":"address"},{"components":[{"internalType":"address","name":"aggregator","type":"address"},{"internalType":"address","name":"rebalanceAdapter","type":"address"},{"internalType":"enum IAggregator.SwapType","name":"swapType","type":"uint8"}],"internalType":"struct IAggregator.SwapInfoBase","name":"swapBase","type":"tuple"},{"components":[{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IAggregator.SwapData[]","name":"swapDatas","type":"tuple[]"}],"name":"autoJoinSmartPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"claimKolReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"crp","type":"address"}],"name":"claimManagementFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"name":"claimManagersReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract FactoryActions","name":"factory","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256[]","name":"weights","type":"uint256[]"},{"internalType":"bool","name":"finalize","type":"bool"}],"name":"create","outputs":[{"internalType":"contract LiquidityPoolActions","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICRPFactory","name":"factory","type":"address"},{"internalType":"contract FactoryActions","name":"coreFactory","type":"address"},{"components":[{"internalType":"string","name":"poolTokenSymbol","type":"string"},{"internalType":"string","name":"poolTokenName","type":"string"},{"internalType":"address[]","name":"constituentTokens","type":"address[]"},{"internalType":"uint256[]","name":"tokenBalances","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenWeights","type":"uint256[]"},{"internalType":"uint256","name":"managerFee","type":"uint256"},{"internalType":"uint256","name":"redeemFee","type":"uint256"},{"internalType":"uint256","name":"issueFee","type":"uint256"},{"internalType":"uint256","name":"perfermanceFee","type":"uint256"},{"internalType":"enum SmartPoolManager.Etypes","name":"etype","type":"uint8"}],"internalType":"struct IConfigurableRightsPool.PoolParams","name":"poolParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"collectPeriod","type":"uint256"},{"internalType":"enum SmartPoolManager.Period","name":"period","type":"uint8"}],"internalType":"struct IConfigurableRightsPool.CrpParams","name":"crpParams","type":"tuple"},{"components":[{"internalType":"bool","name":"canWhitelistLPs","type":"bool"},{"internalType":"bool","name":"canTokenWhiteLists","type":"bool"}],"internalType":"struct RightsManager.Rights","name":"rights","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"firstLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"secondLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"thirdLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"fourLevel","type":"tuple"}],"internalType":"struct SmartPoolManager.feeParams","name":"managerFee","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"firstLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"secondLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"thirdLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"fourLevel","type":"tuple"}],"internalType":"struct SmartPoolManager.feeParams","name":"issueFee","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"firstLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"secondLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"thirdLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"fourLevel","type":"tuple"}],"internalType":"struct SmartPoolManager.feeParams","name":"redeemFee","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"firstLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"secondLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"thirdLevel","type":"tuple"},{"components":[{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct SmartPoolManager.levelParams","name":"fourLevel","type":"tuple"}],"internalType":"struct SmartPoolManager.feeParams","name":"perfermanceFee","type":"tuple"}],"internalType":"struct SmartPoolManager.KolPoolParams","name":"kolPoolParams","type":"tuple"},{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ownerPercentage","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"bspFloor","type":"uint256"},{"internalType":"uint256","name":"bspCap","type":"uint256"}],"internalType":"struct SmartPoolManager.PoolTokenRange","name":"tokenRange","type":"tuple"}],"name":"createSmartPool","outputs":[{"internalType":"contract IConfigurableRightsPool","name":"crp","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"pool","type":"address"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"}],"name":"exitPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract LiquidityPoolActions","name":"pool","type":"address"}],"name":"finalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract LiquidityPoolActions","name":"pool","type":"address"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"}],"name":"joinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"pool","type":"address"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"},{"internalType":"address","name":"kol","type":"address"}],"name":"joinSmartPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RebalaceAdapter","name":"rebalanceAdapter","type":"address"},{"components":[{"internalType":"address","name":"etf","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"aggregator","type":"address"},{"internalType":"enum RebalaceAdapter.SwapType","name":"swapType","type":"uint8"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct RebalaceAdapter.RebalanceInfo","name":"rebalanceInfo","type":"tuple"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"crp","type":"address"},{"internalType":"address","name":"provider","type":"address"}],"name":"removeWhitelistedLiquidityProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"crp","type":"address"},{"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AbstractPool","name":"pool","type":"address"},{"internalType":"address","name":"newController","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AbstractPool","name":"pool","type":"address"},{"internalType":"address[]","name":"_owners","type":"address[]"},{"internalType":"uint256[]","name":"_ownerPercentage","type":"uint256[]"}],"name":"setManagersInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AbstractPool","name":"pool","type":"address"},{"internalType":"bool","name":"publicSwap","type":"bool"}],"name":"setPublicSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"pool","type":"address"}],"name":"snapshotBeginAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"pool","type":"address"}],"name":"snapshotEndAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConfigurableRightsPool","name":"crp","type":"address"},{"internalType":"address","name":"provider","type":"address"}],"name":"whitelistLiquidityProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b5060016000556152b2806100256000396000f3fe60806040526004361061011f5760003560e01c806307f4e3471461012b5780630ebb327114610161578063135b968d146101835780631eccc185146101a3578063271b7895146101c35780632dd31000146101e3578063333fbeef146101f857806339f8a39f146102185780633e67f1571461022d57806349f77d551461024d5780634ef39b751461026d5780635135aafb1461028d578063555e129d146102ad57806363ced092146102c05780636936674d146102e05780637b7d6c681461030057806380ad2cf3146103205780638a5c57df146103405780639589da7614610360578063a7f28da714610380578063a92f00ff146103a0578063d2536ec0146103c0578063e221e73a146103d3578063fb411265146103f357610126565b3661012657005b600080fd5b34801561013757600080fd5b5061014b610146366004613eab565b610413565b604051610158919061475b565b60405180910390f35b34801561016d57600080fd5b5061018161017c366004613c81565b610780565b005b34801561018f57600080fd5b5061018161019e3660046140c8565b6107d6565b3480156101af57600080fd5b506101816101be366004613dc3565b610908565b3480156101cf57600080fd5b506101816101de366004613c81565b610962565b3480156101ef57600080fd5b5061014b61099d565b34801561020457600080fd5b50610181610213366004613d3f565b6109b5565b34801561022457600080fd5b5061014b6109e1565b34801561023957600080fd5b506101816102483660046142e1565b6109f9565b34801561025957600080fd5b5061018161026836600461427e565b610a25565b34801561027957600080fd5b50610181610288366004613c81565b610a90565b34801561029957600080fd5b506101816102a8366004613d51565b610bf7565b6101816102bb366004613f9c565b610c65565b3480156102cc57600080fd5b506101816102db366004614139565b611662565b3480156102ec57600080fd5b506101816102fb366004613c81565b61175f565b34801561030c57600080fd5b5061018161031b366004613d3f565b611799565b34801561032c57600080fd5b5061018161033b36600461409d565b6117ce565b34801561034c57600080fd5b5061018161035b366004614225565b6117fa565b34801561036c57600080fd5b5061018161037b366004614035565b6118b4565b34801561038c57600080fd5b5061018161039b366004613d3f565b6118e2565b3480156103ac57600080fd5b5061014b6103bb366004613df0565b61190e565b6101816103ce366004614185565b611cb8565b3480156103df57600080fd5b506101816103ee366004613cb9565b6123a4565b3480156103ff57600080fd5b5061018161040e366004613c81565b6123d0565b600061042260608901896150a8565b905061043160408a018a6150a8565b9050146104595760405162461bcd60e51b815260040161045090614acb565b60405180910390fd5b61046660808901896150a8565b905061047560408a018a6150a8565b9050146104945760405162461bcd60e51b815260040161045090614acb565b604051632c60e63560e01b81526001600160a01b038b1690632c60e635906104ca908c908c908b908b908b908b9060040161486c565b602060405180830381600087803b1580156104e457600080fd5b505af11580156104f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051c9190613c9d565b905060005b61052e60408a018a6150a8565b90508110156105fd57600061054660408b018b6150a8565b8381811061055057fe5b90506020020160208101906105659190613c81565b90506105a4333061057960608e018e6150a8565b8681811061058357fe5b90506020020135846001600160a01b031661240b909392919063ffffffff16565b6105b96001600160a01b038216846000612463565b6105f4836105ca60608d018d6150a8565b858181106105d457fe5b90506020020135836001600160a01b03166124639092919063ffffffff16565b50600101610521565b506001600160a01b03811663eff4955733893560208b013561062560608d0160408e01614345565b876040518663ffffffff1660e01b81526004016106469594939291906147f9565b600060405180830381600087803b15801561066057600080fd5b505af1158015610674573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038416925063a9059cbb91506106a79033908b35906004016147e0565b602060405180830381600087803b1580156106c157600080fd5b505af11580156106d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f99190613d23565b6107155760405162461bcd60e51b815260040161045090614d5e565b6040516392eefe9b60e01b81526001600160a01b038216906392eefe9b9061074190339060040161475b565b600060405180830381600087803b15801561075b57600080fd5b505af115801561076f573d6000803e3d6000fd5b505050509998505050505050505050565b806001600160a01b03166343774a6b6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107bb57600080fd5b505af11580156107cf573d6000803e3d6000fd5b5050505050565b6060856001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561081157600080fd5b505afa158015610825573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108499190613c9d565b6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561088157600080fd5b505afa158015610895573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108bd9190810190613cf1565b905061090086828787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525089925061252b915050565b505050505050565b6040516324dacaa960e11b81526001600160a01b038316906349b5955290610934908490600401614a47565b600060405180830381600087803b15801561094e57600080fd5b505af1158015610900573d6000803e3d6000fd5b806001600160a01b0316631296548f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107bb57600080fd5b73f49a0cab1f8b3c08d98bcf77b0b4216d24be49f281565b60405163c83a1c2d60e01b81526001600160a01b0383169063c83a1c2d9061093490849060040161475b565b73530824da86689c9c17cdc2871ff29b058345b44a81565b604051637051b85760e11b81526001600160a01b0383169063e0a370ae90610934908490600401614f23565b60405163167ae91560e21b81526001600160a01b038616906359eba45490610a57908790879087908790600401614842565b600060405180830381600087803b158015610a7157600080fd5b505af1158015610a85573d6000803e3d6000fd5b505050505050505050565b806001600160a01b0316634bb278f36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610acb57600080fd5b505af1158015610adf573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038416925063a9059cbb9150339083906370a0823190610b1990309060040161475b565b60206040518083038186803b158015610b3157600080fd5b505afa158015610b45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b699190614460565b6040518363ffffffff1660e01b8152600401610b869291906147e0565b602060405180830381600087803b158015610ba057600080fd5b505af1158015610bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd89190613d23565b610bf45760405162461bcd60e51b815260040161045090614d5e565b50565b610c008361284a565b6040516303c153ef60e61b81526001600160a01b0384169063f054fbc090610c2e90859085906004016149fd565b600060405180830381600087803b158015610c4857600080fd5b505af1158015610c5c573d6000803e3d6000fd5b50505050505050565b60026000541415610c885760405162461bcd60e51b815260040161045090614c8e565b600260005560405163db7ca46b60e01b815273f49a0cab1f8b3c08d98bcf77b0b4216d24be49f29063db7ca46b90610cc490869060040161475b565b60206040518083038186803b158015610cdc57600080fd5b505afa158015610cf0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d149190613d23565b610d305760405162461bcd60e51b815260040161045090614b5f565b6060876001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6b57600080fd5b505afa158015610d7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da39190613c9d565b6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b158015610ddb57600080fd5b505afa158015610def573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e179190810190613cf1565b90508151815114610e3a5760405162461bcd60e51b815260040161045090614b2d565b606081516001600160401b0381118015610e5357600080fd5b50604051908082528060200260200182016040528015610e7d578160200160208202803683370190505b5090503360006001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610f5757600034118015610eb757508834145b610ed35760405162461bcd60e51b815260040161045090614aa8565b73ca0e11e5576ff113ff3028b940a5498dd216d18c6001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f2257600080fd5b505af1158015610f36573d6000803e3d6000fd5b505050505073ca0e11e5576ff113ff3028b940a5498dd216d18c9050610f6e565b5085610f6e6001600160a01b03821683308c61240b565b610f90610f7e6020880188613c81565b6001600160a01b038316906000612463565b610fb1610fa06020880188613c81565b6001600160a01b038316908b612463565b610fb961392b565b604051806080016040528060001981526020018d6001600160a01b0316637228c87b6040518163ffffffff1660e01b815260040161016060405180830381600087803b15801561100857600080fd5b505af115801561101c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104091906143ca565b610100015181526020018d6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561108357600080fd5b505afa158015611097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110bb9190614460565b81526020018d6001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156110f957600080fd5b505afa15801561110d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111319190613c9d565b6001600160a01b03169052905060005b855181101561129d5761115261395c565b87828151811061115e57fe5b60200260200101519050836001600160a01b031687838151811061117e57fe5b60200260200101516001600160a01b0316146111ce576111b289828985815181106111a557fe5b602002602001015161285c565b8683815181106111be57fe5b60200260200101818152506111eb565b80600001518683815181106111df57fe5b60200260200101818152505b50600061122d8460600151856040015186602001518b878151811061120c57fe5b60200260200101518b888151811061122057fe5b6020026020010151612d47565b845190915081101561123d578084525b61126f8f60008a868151811061124f57fe5b60200260200101516001600160a01b03166124639092919063ffffffff16565b6112938f88858151811061127f57fe5b60200260200101518a868151811061124f57fe5b5050600101611141565b5080518911156112bf5760405162461bcd60e51b815260040161045090614cdb565b8b6001600160a01b031663276990f68260000151868e876040518563ffffffff1660e01b81526004016112f59493929190615013565b600060405180830381600087803b15801561130f57600080fd5b505af1158015611323573d6000803e3d6000fd5b5050505060005b855181101561146957600086828151811061134157fe5b602002602001015190506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611379919061475b565b60206040518083038186803b15801561139157600080fd5b505afa1580156113a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c99190614460565b11156114605761146085826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016113ff919061475b565b60206040518083038186803b15801561141757600080fd5b505afa15801561142b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144f9190614460565b6001600160a01b0384169190612e2a565b5060010161132a565b506114fb83836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161149a919061475b565b60206040518083038186803b1580156114b257600080fd5b505afa1580156114c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ea9190614460565b6001600160a01b0385169190612e2a565b6040516370a0823160e01b81526001600160a01b038d169063a9059cbb90859083906370a082319061153190309060040161475b565b60206040518083038186803b15801561154957600080fd5b505afa15801561155d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115819190614460565b6040518363ffffffff1660e01b815260040161159e9291906147e0565b602060405180830381600087803b1580156115b857600080fd5b505af11580156115cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f09190613d23565b61160c5760405162461bcd60e51b815260040161045090614d5e565b7fa1906a9ec8b18f0b22525421de8e6d162eac414db71d7a6a26ee6a349579139933898c8f85600001516040516116479594939291906147ad565b60405180910390a15050600160005550505050505050505050565b6060836001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561169d57600080fd5b505afa1580156116b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d59190613c9d565b6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561170d57600080fd5b505afa158015611721573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117499190810190613cf1565b9050611759848484846000612e49565b50505050565b600061176a82613135565b60405163325a48a760e21b81529091506001600160a01b0382169063c969229c9061093490859060040161475b565b6117a28261284a565b6040516392eefe9b60e01b81526001600160a01b038316906392eefe9b9061093490849060040161475b565b6040516347786d3760e01b81526001600160a01b038316906347786d3790610934908490600401614fd9565b6060846001600160a01b031663be3bbd2e6040518163ffffffff1660e01b815260040160006040518083038186803b15801561183557600080fd5b505afa158015611849573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118719190810190613cf1565b90506107cf85828686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525033925061252b915050565b6040516329b0917160e21b81526001600160a01b0384169063a6c245c490610c2e9085908590600401614a22565b60405163e2762d4b60e01b81526001600160a01b0383169063e2762d4b9061093490849060040161475b565b600086851461192f5760405162461bcd60e51b815260040161045090614acb565b86831461194e5760405162461bcd60e51b815260040161045090614acb565b886001600160a01b03166391cefde46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561198957600080fd5b505af115801561199d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c19190613c9d565b905060005b87811015611adc5760008989838181106119dc57fe5b90506020020160208101906119f19190613c81565b9050611a0433308a8a8681811061058357fe5b611a196001600160a01b038216846000612463565b611a29838989858181106105d457fe5b826001600160a01b031663e4e1e5388b8b85818110611a4457fe5b9050602002016020810190611a599190613c81565b8a8a86818110611a6557fe5b90506020020135898987818110611a7857fe5b905060200201356040518463ffffffff1660e01b8152600401611a9d939291906149dc565b600060405180830381600087803b158015611ab757600080fd5b505af1158015611acb573d6000803e3d6000fd5b5050600190930192506119c6915050565b508115611c4c57806001600160a01b0316634bb278f36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611b1e57600080fd5b505af1158015611b32573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038416925063a9059cbb9150339083906370a0823190611b6c90309060040161475b565b60206040518083038186803b158015611b8457600080fd5b505afa158015611b98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bbc9190614460565b6040518363ffffffff1660e01b8152600401611bd99291906147e0565b602060405180830381600087803b158015611bf357600080fd5b505af1158015611c07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2b9190613d23565b611c475760405162461bcd60e51b815260040161045090614d5e565b611cac565b6040516324dacaa960e11b81526001600160a01b038216906349b5955290611c7990600190600401614a47565b600060405180830381600087803b158015611c9357600080fd5b505af1158015611ca7573d6000803e3d6000fd5b505050505b98975050505050505050565b60026000541415611cdb5760405162461bcd60e51b815260040161045090614c8e565b60026000819055506060876001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d1e57600080fd5b505afa158015611d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d569190613c9d565b6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b158015611d8e57600080fd5b505afa158015611da2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611dca9190810190613cf1565b825160405163db7ca46b60e01b81529192509073f49a0cab1f8b3c08d98bcf77b0b4216d24be49f29063db7ca46b90611e0790889060040161475b565b60206040518083038186803b158015611e1f57600080fd5b505afa158015611e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190613d23565b611e735760405162461bcd60e51b815260040161045090614b5f565b8251825114611e945760405162461bcd60e51b815260040161045090614b2d565b8651825114611eb55760405162461bcd60e51b815260040161045090614b2d565b846001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415611ef2575073ca0e11e5576ff113ff3028b940a5498dd216d18c5b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190611f2190309060040161475b565b60206040518083038186803b158015611f3957600080fd5b505afa158015611f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f719190614460565b90506060836001600160401b0381118015611f8b57600080fd5b50604051908082528060200260200182016040528015611fb5578160200160208202803683370190505b50905060005b8481101561207157858181518110611fcf57fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612002919061475b565b60206040518083038186803b15801561201a57600080fd5b505afa15801561202e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120529190614460565b82828151811061205e57fe5b6020908102919091010152600101611fbb565b506120808c8c8c886001612e49565b60005b848110156121d25761209361395c565b87828151811061209f57fe5b6020026020010151905060008783815181106120b757fe5b60200260200101519050856001600160a01b03168884815181106120d757fe5b60200260200101516001600160a01b0316146121c8576040516370a0823160e01b8152612186906001600160a01b038316906370a082319061211d90309060040161475b565b60206040518083038186803b15801561213557600080fd5b505afa158015612149573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216d9190614460565b85858151811061217957fe5b60200260200101516131bd565b8252612198610f7e60208c018c613c81565b6121bb6121a860208c018c613c81565b83516001600160a01b0384169190612463565b6121c68a838861285c565b505b5050600101612083565b50600061225a846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612204919061475b565b60206040518083038186803b15801561221c57600080fd5b505afa158015612230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122549190614460565b846131bd565b9050808a111561227c5760405162461bcd60e51b815260040161045090614dc2565b6001600160a01b03891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561233d57604051632e1a7d4d60e01b815273ca0e11e5576ff113ff3028b940a5498dd216d18c90632e1a7d4d906122d8908490600401614fd9565b600060405180830381600087803b1580156122f257600080fd5b505af1158015612306573d6000803e3d6000fd5b505060405133925083156108fc02915083906000818181858888f19350505050158015612337573d6000803e3d6000fd5b50612351565b6123516001600160a01b0385163383612e2a565b7f2390bb834dbab89c25583d7e45b1f1b35709ffb807ccc79cd1e028c4d1d1dd89338e8e8c856040516123889594939291906147ad565b60405180910390a1505060016000555050505050505050505050565b60405163edb12adf60e01b81526001600160a01b0383169063edb12adf9061093490849060040161475b565b806001600160a01b031663d2fed42e6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107bb57600080fd5b611759846323b872dd60e01b85858560405160240161242c93929190614789565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613208565b8015806124eb5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90612499903090869060040161476f565b60206040518083038186803b1580156124b157600080fd5b505afa1580156124c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124e99190614460565b155b6125075760405162461bcd60e51b815260040161045090614e96565b6125268363095ea7b360e01b848460405160240161242c9291906147e0565b505050565b835182511461254c5760405162461bcd60e51b815260040161045090614acb565b60005b84518110156125f257600085828151811061256657fe5b602002602001015190506125a3333086858151811061258157fe5b6020026020010151846001600160a01b031661240b909392919063ffffffff16565b6125b86001600160a01b038216886000612463565b6125e9878584815181106125c857fe5b6020026020010151836001600160a01b03166124639092919063ffffffff16565b5060010161254f565b506040516313b4c87b60e11b81526001600160a01b0386169063276990f690612625908690869086903390600401615013565b600060405180830381600087803b15801561263f57600080fd5b505af1158015612653573d6000803e3d6000fd5b5050505060005b845181101561273857600085828151811061267157fe5b602002602001015190506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016126a9919061475b565b60206040518083038186803b1580156126c157600080fd5b505afa1580156126d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f99190614460565b111561272f5761272f33826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016113ff919061475b565b5060010161265a565b506040516370a0823160e01b81526001600160a01b0386169063a9059cbb90339083906370a082319061276f90309060040161475b565b60206040518083038186803b15801561278757600080fd5b505afa15801561279b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127bf9190614460565b6040518363ffffffff1660e01b81526004016127dc9291906147e0565b602060405180830381600087803b1580156127f657600080fd5b505af115801561280a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061282e9190613d23565b6107cf5760405162461bcd60e51b815260040161045090614d5e565b612853816123d0565b610bf4816132ed565b600073f49a0cab1f8b3c08d98bcf77b0b4216d24be49f26338f0d245826128896040880160208901613c81565b6040518363ffffffff1660e01b81526004016128a692919061476f565b60206040518083038186803b1580156128be57600080fd5b505afa1580156128d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f69190613d23565b6129125760405162461bcd60e51b815260040161045090614bc7565b6129226040850160208601613c81565b6001600160a01b03166337f6213861293d6020870187613c81565b6040518263ffffffff1660e01b8152600401612959919061475b565b602060405180830381600087803b15801561297357600080fd5b505af1158015612987573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ab9190613d23565b6129c75760405162461bcd60e51b815260040161045090614cb3565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906129f690309060040161475b565b60206040518083038186803b158015612a0e57600080fd5b505afa158015612a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a469190614460565b90506001612a5a6060870160408801614364565b6003811115612a6557fe5b1415612b0457600060608560200151806020019051810190612a8791906144bc565b9092509050612a996020880188613c81565b8651604051637224811760e11b81526001600160a01b03929092169163e449022e91612acb9186908690600401615089565b600060405180830381600087803b158015612ae557600080fd5b505af1158015612af9573d6000803e3d6000fd5b505050505050612cb8565b6000612b166060870160408801614364565b6003811115612b2157fe5b1415612b9757600060608560200151806020019051810190612b439190614478565b9092509050612b556020880188613c81565b6001600160a01b03166338ed17398760000151848430612b774261070861357d565b6040518663ffffffff1660e01b8152600401612acb95949392919061504d565b6002612ba96060870160408801614364565b6003811115612bb457fe5b1415612bdc57612bd6612bca6020870187613c81565b856020015160006135a2565b50612cb8565b6003612bee6060870160408801614364565b6003811115612bf957fe5b1415612ca0576000806000808760200151806020019051810190612c1d9190614383565b92965090945092509050612c3460208a018a613c81565b6001600160a01b031663a6417ed6858585856040518563ffffffff1660e01b8152600401612c659493929190614a52565b600060405180830381600087803b158015612c7f57600080fd5b505af1158015612c93573d6000803e3d6000fd5b5050505050505050612cb8565b60405162461bcd60e51b815260040161045090614c35565b6040516370a0823160e01b8152612d3e906001600160a01b038516906370a0823190612ce890309060040161475b565b60206040518083038186803b158015612d0057600080fd5b505afa158015612d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d389190614460565b826131bd565b95945050505050565b600080866001600160a01b031663f8b2cb4f856040518263ffffffff1660e01b8152600401612d76919061475b565b60206040518083038186803b158015612d8e57600080fd5b505afa158015612da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc69190614460565b90506000612dd6866103e86135d0565b90506000612e1d612de884600161364d565b6103e802612e01846103e861367290919063ffffffff16565b612e1688612e108d6001613672565b906135d0565b02906136ab565b9998505050505050505050565b6125268363a9059cbb60e01b848460405160240161242c9291906147e0565b836001866001600160a01b03166373a9855c6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e8757600080fd5b505af1158015612e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebf9190614329565b6001811115612eca57fe5b1415612f4f576040516370a0823160e01b81526001600160a01b038716906370a0823190612efc90339060040161475b565b60206040518083038186803b158015612f1457600080fd5b505afa158015612f28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f4c9190614460565b90505b6040516323b872dd60e01b81526001600160a01b038716906323b872dd90612f7f90339030908690600401614789565b602060405180830381600087803b158015612f9957600080fd5b505af1158015612fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd19190613d23565b612fed5760405162461bcd60e51b815260040161045090614d5e565b6040516305369ecb60e11b81526001600160a01b03871690630a6d3d969061301d90849088903390600401614fe2565b600060405180830381600087803b15801561303757600080fd5b505af115801561304b573d6000803e3d6000fd5b50505050816109005760005b8351811015610c5c57600084828151811061306e57fe5b602002602001015190506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016130a6919061475b565b60206040518083038186803b1580156130be57600080fd5b505afa1580156130d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f69190614460565b111561312c5761312c33826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016113ff919061475b565b50600101613057565b6000806131418361373c565b9050806001600160a01b0316639daafec76040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561317e57600080fd5b505af1158015613192573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131b69190613c9d565b9392505050565b60006131ff83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506137af565b90505b92915050565b61321a826001600160a01b03166137db565b6132365760405162461bcd60e51b815260040161045090614eec565b60006060836001600160a01b031683604051613252919061473f565b6000604051808303816000865af19150503d806000811461328f576040519150601f19603f3d011682016040523d82523d6000602084013e613294565b606091505b5091509150816132b65760405162461bcd60e51b815260040161045090614b92565b80511561175957808060200190518101906132d19190613d23565b6117595760405162461bcd60e51b815260040161045090614e4c565b60006132f88261373c565b9050600061330583613135565b90506000826001600160a01b031663c0fcb166856040518263ffffffff1660e01b8152600401613335919061475b565b60206040518083038186803b15801561334d57600080fd5b505afa158015613361573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133859190613d23565b90506000826001600160a01b031663c0fcb166866040518263ffffffff1660e01b81526004016133b5919061475b565b60206040518083038186803b1580156133cd57600080fd5b505afa1580156133e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134059190613d23565b90506000856001600160a01b03166373a9855c6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561344457600080fd5b505af1158015613458573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347c9190614329565b9050600081600181111561348c57fe5b1480156134965750825b156134fa5760405163edb12adf60e01b81526001600160a01b0386169063edb12adf906134c790899060040161475b565b600060405180830381600087803b1580156134e157600080fd5b505af11580156134f5573d6000803e3d6000fd5b505050505b600181600181111561350857fe5b1480156135125750815b156109005760405163edb12adf60e01b81526001600160a01b0385169063edb12adf9061354390899060040161475b565b600060405180830381600087803b15801561355d57600080fd5b505af1158015613571573d6000803e3d6000fd5b50505050505050505050565b6000828201838110156131ff5760405162461bcd60e51b815260040161045090614af8565b60606135c884848460405180606001604052806029815260200161525460299139613814565b949350505050565b6000826135df57506000613202565b828202828482816135ec57fe5b041461360a5760405162461bcd60e51b815260040161045090614d0e565b6706f05b59d3b200008101818110156136355760405162461bcd60e51b815260040161045090614d0e565b6000670de0b6b3a7640000825b049695505050505050565b6000828201838110156131ff5760405162461bcd60e51b815260040161045090614e22565b60008060006136818585613842565b9150915080156136a35760405162461bcd60e51b815260040161045090614df7565b509392505050565b6000816136ca5760405162461bcd60e51b815260040161045090614d38565b826136d757506000613202565b670de0b6b3a7640000838102908482816136ed57fe5b041461370b5760405162461bcd60e51b815260040161045090614c64565b600283048101818110156137315760405162461bcd60e51b815260040161045090614c64565b600084828161364257fe5b6000816001600160a01b031663430bf08a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561377757600080fd5b505afa15801561378b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132029190613c9d565b600081848411156137d35760405162461bcd60e51b81526004016104509190614a75565b505050900390565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906135c8575050151592915050565b6060824710156138365760405162461bcd60e51b815260040161045090614bef565b612d3e85858585613867565b6000808383116138585750508082036000613860565b505081810360015b9250929050565b6060613872856137db565b61388e5760405162461bcd60e51b815260040161045090614d8b565b60006060866001600160a01b031685876040516138ab919061473f565b60006040518083038185875af1925050503d80600081146138e8576040519150601f19603f3d011682016040523d82523d6000602084013e6138ed565b606091505b509150915081156139015791506135c89050565b8051156139115780518082602001fd5b8360405162461bcd60e51b81526004016104509190614a75565b604051806080016040528060008152602001600081526020016000815260200160006001600160a01b031681525090565b604051806040016040528060008152602001606081525090565b803561320281615214565b60008083601f840112613992578182fd5b5081356001600160401b038111156139a8578182fd5b602083019150836020808302850101111561386057600080fd5b600082601f8301126139d2578081fd5b81356139e56139e082615114565b6150ee565b818152915060208083019084810181840286018201871015613a0657600080fd5b60005b84811015613a2e578135613a1c81615214565b84529282019290820190600101613a09565b505050505092915050565b600082601f830112613a49578081fd5b8151613a576139e082615114565b818152915060208083019084810181840286018201871015613a7857600080fd5b60005b84811015613a2e578151613a8e81615214565b84529282019290820190600101613a7b565b600082601f830112613ab0578081fd5b8135613abe6139e082615114565b818152915060208083019084810160005b84811015613a2e5781358701604080601f19838c03011215613af057600080fd5b613af9816150ee565b82860135815290820135906001600160401b03821115613b1857600080fd5b613b268b8784860101613b9c565b81870152865250509282019290820190600101613acf565b600082601f830112613b4e578081fd5b8135613b5c6139e082615114565b818152915060208083019084810181840286018201871015613b7d57600080fd5b60005b84811015613a2e57813584529282019290820190600101613b80565b600082601f830112613bac578081fd5b81356001600160401b03811115613bc1578182fd5b613bd4601f8201601f19166020016150ee565b9150808252836020828501011115613beb57600080fd5b8060208401602084013760009082016020015292915050565b600060608284031215613c15578081fd5b50919050565b60006104008284031215613c15578081fd5b60006101408284031215613c15578081fd5b600060408284031215613c50578081fd5b613c5a60406150ee565b9050813581526020820135602082015292915050565b600060408284031215613c15578081fd5b600060208284031215613c92578081fd5b81356131ff81615214565b600060208284031215613cae578081fd5b81516131ff81615214565b60008060408385031215613ccb578081fd5b8235613cd681615214565b91506020830135613ce681615214565b809150509250929050565b600060208284031215613d02578081fd5b81516001600160401b03811115613d17578182fd5b6135c884828501613a39565b600060208284031215613d34578081fd5b81516131ff81615229565b60008060408385031215613ccb578182fd5b600080600060608486031215613d65578081fd5b8335613d7081615214565b925060208401356001600160401b0380821115613d8b578283fd5b613d97878388016139c2565b93506040860135915080821115613dac578283fd5b50613db986828701613b3e565b9150509250925092565b60008060408385031215613dd5578182fd5b8235613de081615214565b91506020830135613ce681615229565b60008060008060008060008060a0898b031215613e0b578586fd5b8835613e1681615214565b975060208901356001600160401b0380821115613e31578788fd5b613e3d8c838d01613981565b909950975060408b0135915080821115613e55578586fd5b613e618c838d01613981565b909750955060608b0135915080821115613e79578485fd5b50613e868b828c01613981565b9094509250506080890135613e9a81615229565b809150509295985092959890939650565b60008060008060008060008060006105808a8c031215613ec9578283fd5b613ed38b8b613976565b9850613ee28b60208c01613976565b975060408a01356001600160401b0380821115613efd578485fd5b613f098d838e01613c2d565b9850613f188d60608e01613c04565b9750613f278d60c08e01613c70565b9650613f378d6101008e01613c1b565b95506105008c0135915080821115613f4d578485fd5b613f598d838e016139c2565b94506105208c0135915080821115613f6f578283fd5b50613f7c8c828d01613b3e565b925050613f8d8b6105408c01613c3f565b90509295985092959850929598565b6000806000806000806000610120888a031215613fb7578081fd5b8735613fc281615214565b96506020880135613fd281615214565b955060408801359450606088013593506080880135613ff081615214565b9250613fff8960a08a01613c04565b91506101008801356001600160401b0381111561401a578182fd5b6140268a828b01613aa0565b91505092959891949750929550565b600080600060608486031215614049578081fd5b833561405481615214565b925060208401356001600160401b038082111561406f578283fd5b61407b87838801613b3e565b93506040860135915080821115614090578283fd5b50613db9868287016139c2565b600080604083850312156140af578182fd5b82356140ba81615214565b946020939093013593505050565b6000806000806000608086880312156140df578283fd5b85356140ea81615214565b94506020860135935060408601356001600160401b0381111561410b578384fd5b61411788828901613981565b909450925050606086013561412b81615214565b809150509295509295909350565b60008060006060848603121561414d578081fd5b833561415881615214565b92506020840135915060408401356001600160401b03811115614179578182fd5b613db986828701613b3e565b6000806000806000806000610120888a0312156141a0578081fd5b87356141ab81615214565b96506020880135955060408801356001600160401b03808211156141cd578283fd5b6141d98b838c01613b3e565b965060608a0135955060808a013591506141f282615214565b8194506142028b60a08c01613c04565b93506101008a0135915080821115614218578283fd5b506140268a828b01613aa0565b6000806000806060858703121561423a578182fd5b843561424581615214565b93506020850135925060408501356001600160401b03811115614266578283fd5b61427287828801613981565b95989497509550505050565b600080600080600060a08688031215614295578283fd5b85356142a081615214565b945060208601356142b081615214565b935060408601356142c081615214565b925060608601356142d081615214565b949793965091946080013592915050565b600080604083850312156142f3578182fd5b82356142fe81615214565b915060208301356001600160401b03811115614318578182fd5b830160e08186031215613ce6578182fd5b60006020828403121561433a578081fd5b81516131ff81615237565b600060208284031215614356578081fd5b8135600881106131ff578182fd5b600060208284031215614375578081fd5b8135600481106131ff578182fd5b60008060008060808587031215614398578182fd5b84516143a381615244565b60208601519094506143b481615244565b6040860151606090960151949790965092505050565b60006101608083850312156143dd578182fd5b6143e6816150ee565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152508091505092915050565b600060208284031215614471578081fd5b5051919050565b6000806040838503121561448a578182fd5b8251915060208301516001600160401b038111156144a6578182fd5b6144b285828601613a39565b9150509250929050565b600080604083850312156144ce578182fd5b825191506020808401516001600160401b038111156144eb578283fd5b8401601f810186136144fb578283fd5b80516145096139e082615114565b81815283810190838501858402850186018a1015614525578687fd5b8694505b83851015614547578051835260019490940193918501918501614529565b5080955050505050509250929050565b6001600160a01b03169052565b60008284526020808501945082825b858110156145a157813561458681615214565b6001600160a01b031687529582019590820190600101614573565b509495945050505050565b6000815180845260208085019450808401835b838110156145a15781516001600160a01b0316875295820195908201906001016145bf565b81835260006001600160fb1b038311156145fc578081fd5b6020830280836020870137939093016020019283525090919050565b6000815180845260208085019450808401835b838110156145a15781518752958201959082019060010161462b565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b6002811061467b57fe5b9052565b6003811061467b57fe5b61469382826146f2565b6101006146a48184018284016146f2565b506102006146b68184018284016146f2565b506103006125268184018284016146f2565b80356146d381615229565b1515825260208101356146e581615229565b8015156020840152505050565b6146fc8282614730565b61470c6040830160408301614730565b61471c6080830160808301614730565b61472c60c0830160c08301614730565b5050565b80358252602090810135910152565b600082516147518184602087016151e8565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0386168152602081018590526040810184905260c081016008841061482157fe5b83606083015282516080830152602083015160a08301529695505050505050565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b03871681526104c06020820181905260009061488f8880615187565b610140838601526148a561060086018284614647565b925050506148b66020890189615187565b6104bf1980868503016104e08701526148d0848385614647565b93506148df60408c018c615140565b9350915080868503016105008701526148f9848484614564565b935061490860608c018c615140565b9350915080868503016105208701526149228484846145e4565b935061493160808c018c615140565b9350915080868503016105408701525061494c8383836145e4565b9250505060a088013561056084015260c088013561058084015260e08801356105a08401526101008801356105c084015261498b6101208901896151cb565b6149996105e0850182614671565b506149a760408401886146c8565b6149b46080840187614689565b8281036104808401526149c781866145ac565b90508281036104a0840152612e1d8185614618565b6001600160a01b039390931683526020830191909152604082015260600190565b600060408252614a1060408301856145ac565b8281036020840152612d3e8185614618565b600060408252614a356040830185614618565b8281036020840152612d3e81856145ac565b901515815260200190565b600f94850b81529290930b60208301526040820152606081019190915260800190565b6000602082528251806020840152614a948160408501602087016151e8565b601f01601f19169190910160400192915050565b60208082526009908201526808aa4a49ea4be8aa8960bb1b604082015260600190565b60208082526013908201527208aa4a4be988a9c8ea890be9a92a69a82a8869606b1b604082015260600190565b6020808252601b908201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604082015260600190565b60208082526018908201527708aa4a4bea89e968a9c988a9c8ea890be9a92a69a82a886960431b604082015260600190565b60208082526019908201527811549497d513d2d15397d393d517d5d2125511531254d51151603a1b604082015260600190565b6020808252818101527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604082015260600190565b6020808252600e908201526d1353d115531157d253131151d05360921b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601590820152744552525f494e56414c49445f535741505f5459504560581b604082015260600190565b60208082526010908201526f11549497d1125597d25395115493905360821b604082015260600190565b6020808252600b908201526a4552525f5245454e54525960a81b604082015260600190565b6020808252600e908201526d1493d555115497d253131151d05360921b604082015260600190565b60208082526019908201527811549497d4d210549157d05353d5539517d513d7d4d3505313603a1b604082015260600190565b60208082526010908201526f4552525f4d554c5f4f564552464c4f5760801b604082015260600190565b6020808252600c908201526b4552525f4449565f5a45524f60a01b604082015260600190565b60208082526013908201527211549497d514905394d1915497d19052531151606a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252601b908201527a11549497d49150d152559157d05353d5539517d513d7d4d3505313602a1b604082015260600190565b6020808252601190820152704552525f5355425f554e444552464c4f5760781b604082015260600190565b60208082526010908201526f4552525f4144445f4f564552464c4f5760801b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b6020808252601f908201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604082015260600190565b6000602082528235614f3481615214565b6001600160a01b0390811660208481019190915284013590614f5582615214565b808216604085015260408501359150614f6d82615214565b80821660608501525050614f846060840184615133565b614f916080840182614557565b50614f9f60808401846151d8565b614fac60a084018261467f565b5060a083013560c0830152614fc460c0840184615187565b60e080850152612d3e61010085018284614647565b90815260200190565b600084825260606020830152614ffb6060830185614618565b905060018060a01b0383166040830152949350505050565b60008582526080602083015261502c6080830186614618565b6001600160a01b039485166040840152929093166060909101529392505050565b600086825285602083015260a0604083015261506c60a08301866145ac565b6001600160a01b0394909416606083015250608001529392505050565b600084825283602083015260606040830152612d3e6060830184614618565b6000808335601e198436030181126150be578283fd5b8301803591506001600160401b038211156150d7578283fd5b602090810192508102360382131561386057600080fd5b6040518181016001600160401b038111828210171561510c57600080fd5b604052919050565b60006001600160401b03821115615129578081fd5b5060209081020190565b600082356131ff81615214565b6000808335601e19843603018112615156578283fd5b83016020810192503590506001600160401b0381111561517557600080fd5b60208102360383131561386057600080fd5b6000808335601e1984360301811261519d578283fd5b83016020810192503590506001600160401b038111156151bc57600080fd5b80360383131561386057600080fd5b600082356131ff81615237565b60008235600381106131ff578182fd5b60005b838110156152035781810151838201526020016151eb565b838111156117595750506000910152565b6001600160a01b0381168114610bf457600080fd5b8015158114610bf457600080fd5b60028110610bf457600080fd5b80600f0b8114610bf457600080fdfe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220ceb17fa56d4af0bb0810873ecc72aecc3ee88a00c5774ca340838706e9f729cd64736f6c634300060c0033
Deployed Bytecode
0x60806040526004361061011f5760003560e01c806307f4e3471461012b5780630ebb327114610161578063135b968d146101835780631eccc185146101a3578063271b7895146101c35780632dd31000146101e3578063333fbeef146101f857806339f8a39f146102185780633e67f1571461022d57806349f77d551461024d5780634ef39b751461026d5780635135aafb1461028d578063555e129d146102ad57806363ced092146102c05780636936674d146102e05780637b7d6c681461030057806380ad2cf3146103205780638a5c57df146103405780639589da7614610360578063a7f28da714610380578063a92f00ff146103a0578063d2536ec0146103c0578063e221e73a146103d3578063fb411265146103f357610126565b3661012657005b600080fd5b34801561013757600080fd5b5061014b610146366004613eab565b610413565b604051610158919061475b565b60405180910390f35b34801561016d57600080fd5b5061018161017c366004613c81565b610780565b005b34801561018f57600080fd5b5061018161019e3660046140c8565b6107d6565b3480156101af57600080fd5b506101816101be366004613dc3565b610908565b3480156101cf57600080fd5b506101816101de366004613c81565b610962565b3480156101ef57600080fd5b5061014b61099d565b34801561020457600080fd5b50610181610213366004613d3f565b6109b5565b34801561022457600080fd5b5061014b6109e1565b34801561023957600080fd5b506101816102483660046142e1565b6109f9565b34801561025957600080fd5b5061018161026836600461427e565b610a25565b34801561027957600080fd5b50610181610288366004613c81565b610a90565b34801561029957600080fd5b506101816102a8366004613d51565b610bf7565b6101816102bb366004613f9c565b610c65565b3480156102cc57600080fd5b506101816102db366004614139565b611662565b3480156102ec57600080fd5b506101816102fb366004613c81565b61175f565b34801561030c57600080fd5b5061018161031b366004613d3f565b611799565b34801561032c57600080fd5b5061018161033b36600461409d565b6117ce565b34801561034c57600080fd5b5061018161035b366004614225565b6117fa565b34801561036c57600080fd5b5061018161037b366004614035565b6118b4565b34801561038c57600080fd5b5061018161039b366004613d3f565b6118e2565b3480156103ac57600080fd5b5061014b6103bb366004613df0565b61190e565b6101816103ce366004614185565b611cb8565b3480156103df57600080fd5b506101816103ee366004613cb9565b6123a4565b3480156103ff57600080fd5b5061018161040e366004613c81565b6123d0565b600061042260608901896150a8565b905061043160408a018a6150a8565b9050146104595760405162461bcd60e51b815260040161045090614acb565b60405180910390fd5b61046660808901896150a8565b905061047560408a018a6150a8565b9050146104945760405162461bcd60e51b815260040161045090614acb565b604051632c60e63560e01b81526001600160a01b038b1690632c60e635906104ca908c908c908b908b908b908b9060040161486c565b602060405180830381600087803b1580156104e457600080fd5b505af11580156104f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051c9190613c9d565b905060005b61052e60408a018a6150a8565b90508110156105fd57600061054660408b018b6150a8565b8381811061055057fe5b90506020020160208101906105659190613c81565b90506105a4333061057960608e018e6150a8565b8681811061058357fe5b90506020020135846001600160a01b031661240b909392919063ffffffff16565b6105b96001600160a01b038216846000612463565b6105f4836105ca60608d018d6150a8565b858181106105d457fe5b90506020020135836001600160a01b03166124639092919063ffffffff16565b50600101610521565b506001600160a01b03811663eff4955733893560208b013561062560608d0160408e01614345565b876040518663ffffffff1660e01b81526004016106469594939291906147f9565b600060405180830381600087803b15801561066057600080fd5b505af1158015610674573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038416925063a9059cbb91506106a79033908b35906004016147e0565b602060405180830381600087803b1580156106c157600080fd5b505af11580156106d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f99190613d23565b6107155760405162461bcd60e51b815260040161045090614d5e565b6040516392eefe9b60e01b81526001600160a01b038216906392eefe9b9061074190339060040161475b565b600060405180830381600087803b15801561075b57600080fd5b505af115801561076f573d6000803e3d6000fd5b505050509998505050505050505050565b806001600160a01b03166343774a6b6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107bb57600080fd5b505af11580156107cf573d6000803e3d6000fd5b5050505050565b6060856001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561081157600080fd5b505afa158015610825573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108499190613c9d565b6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561088157600080fd5b505afa158015610895573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108bd9190810190613cf1565b905061090086828787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525089925061252b915050565b505050505050565b6040516324dacaa960e11b81526001600160a01b038316906349b5955290610934908490600401614a47565b600060405180830381600087803b15801561094e57600080fd5b505af1158015610900573d6000803e3d6000fd5b806001600160a01b0316631296548f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107bb57600080fd5b73f49a0cab1f8b3c08d98bcf77b0b4216d24be49f281565b60405163c83a1c2d60e01b81526001600160a01b0383169063c83a1c2d9061093490849060040161475b565b73530824da86689c9c17cdc2871ff29b058345b44a81565b604051637051b85760e11b81526001600160a01b0383169063e0a370ae90610934908490600401614f23565b60405163167ae91560e21b81526001600160a01b038616906359eba45490610a57908790879087908790600401614842565b600060405180830381600087803b158015610a7157600080fd5b505af1158015610a85573d6000803e3d6000fd5b505050505050505050565b806001600160a01b0316634bb278f36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610acb57600080fd5b505af1158015610adf573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038416925063a9059cbb9150339083906370a0823190610b1990309060040161475b565b60206040518083038186803b158015610b3157600080fd5b505afa158015610b45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b699190614460565b6040518363ffffffff1660e01b8152600401610b869291906147e0565b602060405180830381600087803b158015610ba057600080fd5b505af1158015610bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd89190613d23565b610bf45760405162461bcd60e51b815260040161045090614d5e565b50565b610c008361284a565b6040516303c153ef60e61b81526001600160a01b0384169063f054fbc090610c2e90859085906004016149fd565b600060405180830381600087803b158015610c4857600080fd5b505af1158015610c5c573d6000803e3d6000fd5b50505050505050565b60026000541415610c885760405162461bcd60e51b815260040161045090614c8e565b600260005560405163db7ca46b60e01b815273f49a0cab1f8b3c08d98bcf77b0b4216d24be49f29063db7ca46b90610cc490869060040161475b565b60206040518083038186803b158015610cdc57600080fd5b505afa158015610cf0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d149190613d23565b610d305760405162461bcd60e51b815260040161045090614b5f565b6060876001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6b57600080fd5b505afa158015610d7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da39190613c9d565b6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b158015610ddb57600080fd5b505afa158015610def573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e179190810190613cf1565b90508151815114610e3a5760405162461bcd60e51b815260040161045090614b2d565b606081516001600160401b0381118015610e5357600080fd5b50604051908082528060200260200182016040528015610e7d578160200160208202803683370190505b5090503360006001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610f5757600034118015610eb757508834145b610ed35760405162461bcd60e51b815260040161045090614aa8565b73ca0e11e5576ff113ff3028b940a5498dd216d18c6001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f2257600080fd5b505af1158015610f36573d6000803e3d6000fd5b505050505073ca0e11e5576ff113ff3028b940a5498dd216d18c9050610f6e565b5085610f6e6001600160a01b03821683308c61240b565b610f90610f7e6020880188613c81565b6001600160a01b038316906000612463565b610fb1610fa06020880188613c81565b6001600160a01b038316908b612463565b610fb961392b565b604051806080016040528060001981526020018d6001600160a01b0316637228c87b6040518163ffffffff1660e01b815260040161016060405180830381600087803b15801561100857600080fd5b505af115801561101c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104091906143ca565b610100015181526020018d6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561108357600080fd5b505afa158015611097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110bb9190614460565b81526020018d6001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156110f957600080fd5b505afa15801561110d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111319190613c9d565b6001600160a01b03169052905060005b855181101561129d5761115261395c565b87828151811061115e57fe5b60200260200101519050836001600160a01b031687838151811061117e57fe5b60200260200101516001600160a01b0316146111ce576111b289828985815181106111a557fe5b602002602001015161285c565b8683815181106111be57fe5b60200260200101818152506111eb565b80600001518683815181106111df57fe5b60200260200101818152505b50600061122d8460600151856040015186602001518b878151811061120c57fe5b60200260200101518b888151811061122057fe5b6020026020010151612d47565b845190915081101561123d578084525b61126f8f60008a868151811061124f57fe5b60200260200101516001600160a01b03166124639092919063ffffffff16565b6112938f88858151811061127f57fe5b60200260200101518a868151811061124f57fe5b5050600101611141565b5080518911156112bf5760405162461bcd60e51b815260040161045090614cdb565b8b6001600160a01b031663276990f68260000151868e876040518563ffffffff1660e01b81526004016112f59493929190615013565b600060405180830381600087803b15801561130f57600080fd5b505af1158015611323573d6000803e3d6000fd5b5050505060005b855181101561146957600086828151811061134157fe5b602002602001015190506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611379919061475b565b60206040518083038186803b15801561139157600080fd5b505afa1580156113a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c99190614460565b11156114605761146085826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016113ff919061475b565b60206040518083038186803b15801561141757600080fd5b505afa15801561142b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144f9190614460565b6001600160a01b0384169190612e2a565b5060010161132a565b506114fb83836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161149a919061475b565b60206040518083038186803b1580156114b257600080fd5b505afa1580156114c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ea9190614460565b6001600160a01b0385169190612e2a565b6040516370a0823160e01b81526001600160a01b038d169063a9059cbb90859083906370a082319061153190309060040161475b565b60206040518083038186803b15801561154957600080fd5b505afa15801561155d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115819190614460565b6040518363ffffffff1660e01b815260040161159e9291906147e0565b602060405180830381600087803b1580156115b857600080fd5b505af11580156115cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f09190613d23565b61160c5760405162461bcd60e51b815260040161045090614d5e565b7fa1906a9ec8b18f0b22525421de8e6d162eac414db71d7a6a26ee6a349579139933898c8f85600001516040516116479594939291906147ad565b60405180910390a15050600160005550505050505050505050565b6060836001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561169d57600080fd5b505afa1580156116b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d59190613c9d565b6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561170d57600080fd5b505afa158015611721573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117499190810190613cf1565b9050611759848484846000612e49565b50505050565b600061176a82613135565b60405163325a48a760e21b81529091506001600160a01b0382169063c969229c9061093490859060040161475b565b6117a28261284a565b6040516392eefe9b60e01b81526001600160a01b038316906392eefe9b9061093490849060040161475b565b6040516347786d3760e01b81526001600160a01b038316906347786d3790610934908490600401614fd9565b6060846001600160a01b031663be3bbd2e6040518163ffffffff1660e01b815260040160006040518083038186803b15801561183557600080fd5b505afa158015611849573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118719190810190613cf1565b90506107cf85828686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525033925061252b915050565b6040516329b0917160e21b81526001600160a01b0384169063a6c245c490610c2e9085908590600401614a22565b60405163e2762d4b60e01b81526001600160a01b0383169063e2762d4b9061093490849060040161475b565b600086851461192f5760405162461bcd60e51b815260040161045090614acb565b86831461194e5760405162461bcd60e51b815260040161045090614acb565b886001600160a01b03166391cefde46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561198957600080fd5b505af115801561199d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c19190613c9d565b905060005b87811015611adc5760008989838181106119dc57fe5b90506020020160208101906119f19190613c81565b9050611a0433308a8a8681811061058357fe5b611a196001600160a01b038216846000612463565b611a29838989858181106105d457fe5b826001600160a01b031663e4e1e5388b8b85818110611a4457fe5b9050602002016020810190611a599190613c81565b8a8a86818110611a6557fe5b90506020020135898987818110611a7857fe5b905060200201356040518463ffffffff1660e01b8152600401611a9d939291906149dc565b600060405180830381600087803b158015611ab757600080fd5b505af1158015611acb573d6000803e3d6000fd5b5050600190930192506119c6915050565b508115611c4c57806001600160a01b0316634bb278f36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611b1e57600080fd5b505af1158015611b32573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038416925063a9059cbb9150339083906370a0823190611b6c90309060040161475b565b60206040518083038186803b158015611b8457600080fd5b505afa158015611b98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bbc9190614460565b6040518363ffffffff1660e01b8152600401611bd99291906147e0565b602060405180830381600087803b158015611bf357600080fd5b505af1158015611c07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2b9190613d23565b611c475760405162461bcd60e51b815260040161045090614d5e565b611cac565b6040516324dacaa960e11b81526001600160a01b038216906349b5955290611c7990600190600401614a47565b600060405180830381600087803b158015611c9357600080fd5b505af1158015611ca7573d6000803e3d6000fd5b505050505b98975050505050505050565b60026000541415611cdb5760405162461bcd60e51b815260040161045090614c8e565b60026000819055506060876001600160a01b031663b64ef17b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d1e57600080fd5b505afa158015611d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d569190613c9d565b6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b158015611d8e57600080fd5b505afa158015611da2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611dca9190810190613cf1565b825160405163db7ca46b60e01b81529192509073f49a0cab1f8b3c08d98bcf77b0b4216d24be49f29063db7ca46b90611e0790889060040161475b565b60206040518083038186803b158015611e1f57600080fd5b505afa158015611e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190613d23565b611e735760405162461bcd60e51b815260040161045090614b5f565b8251825114611e945760405162461bcd60e51b815260040161045090614b2d565b8651825114611eb55760405162461bcd60e51b815260040161045090614b2d565b846001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415611ef2575073ca0e11e5576ff113ff3028b940a5498dd216d18c5b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190611f2190309060040161475b565b60206040518083038186803b158015611f3957600080fd5b505afa158015611f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f719190614460565b90506060836001600160401b0381118015611f8b57600080fd5b50604051908082528060200260200182016040528015611fb5578160200160208202803683370190505b50905060005b8481101561207157858181518110611fcf57fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612002919061475b565b60206040518083038186803b15801561201a57600080fd5b505afa15801561202e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120529190614460565b82828151811061205e57fe5b6020908102919091010152600101611fbb565b506120808c8c8c886001612e49565b60005b848110156121d25761209361395c565b87828151811061209f57fe5b6020026020010151905060008783815181106120b757fe5b60200260200101519050856001600160a01b03168884815181106120d757fe5b60200260200101516001600160a01b0316146121c8576040516370a0823160e01b8152612186906001600160a01b038316906370a082319061211d90309060040161475b565b60206040518083038186803b15801561213557600080fd5b505afa158015612149573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216d9190614460565b85858151811061217957fe5b60200260200101516131bd565b8252612198610f7e60208c018c613c81565b6121bb6121a860208c018c613c81565b83516001600160a01b0384169190612463565b6121c68a838861285c565b505b5050600101612083565b50600061225a846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612204919061475b565b60206040518083038186803b15801561221c57600080fd5b505afa158015612230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122549190614460565b846131bd565b9050808a111561227c5760405162461bcd60e51b815260040161045090614dc2565b6001600160a01b03891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561233d57604051632e1a7d4d60e01b815273ca0e11e5576ff113ff3028b940a5498dd216d18c90632e1a7d4d906122d8908490600401614fd9565b600060405180830381600087803b1580156122f257600080fd5b505af1158015612306573d6000803e3d6000fd5b505060405133925083156108fc02915083906000818181858888f19350505050158015612337573d6000803e3d6000fd5b50612351565b6123516001600160a01b0385163383612e2a565b7f2390bb834dbab89c25583d7e45b1f1b35709ffb807ccc79cd1e028c4d1d1dd89338e8e8c856040516123889594939291906147ad565b60405180910390a1505060016000555050505050505050505050565b60405163edb12adf60e01b81526001600160a01b0383169063edb12adf9061093490849060040161475b565b806001600160a01b031663d2fed42e6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107bb57600080fd5b611759846323b872dd60e01b85858560405160240161242c93929190614789565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613208565b8015806124eb5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90612499903090869060040161476f565b60206040518083038186803b1580156124b157600080fd5b505afa1580156124c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124e99190614460565b155b6125075760405162461bcd60e51b815260040161045090614e96565b6125268363095ea7b360e01b848460405160240161242c9291906147e0565b505050565b835182511461254c5760405162461bcd60e51b815260040161045090614acb565b60005b84518110156125f257600085828151811061256657fe5b602002602001015190506125a3333086858151811061258157fe5b6020026020010151846001600160a01b031661240b909392919063ffffffff16565b6125b86001600160a01b038216886000612463565b6125e9878584815181106125c857fe5b6020026020010151836001600160a01b03166124639092919063ffffffff16565b5060010161254f565b506040516313b4c87b60e11b81526001600160a01b0386169063276990f690612625908690869086903390600401615013565b600060405180830381600087803b15801561263f57600080fd5b505af1158015612653573d6000803e3d6000fd5b5050505060005b845181101561273857600085828151811061267157fe5b602002602001015190506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016126a9919061475b565b60206040518083038186803b1580156126c157600080fd5b505afa1580156126d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f99190614460565b111561272f5761272f33826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016113ff919061475b565b5060010161265a565b506040516370a0823160e01b81526001600160a01b0386169063a9059cbb90339083906370a082319061276f90309060040161475b565b60206040518083038186803b15801561278757600080fd5b505afa15801561279b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127bf9190614460565b6040518363ffffffff1660e01b81526004016127dc9291906147e0565b602060405180830381600087803b1580156127f657600080fd5b505af115801561280a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061282e9190613d23565b6107cf5760405162461bcd60e51b815260040161045090614d5e565b612853816123d0565b610bf4816132ed565b600073f49a0cab1f8b3c08d98bcf77b0b4216d24be49f26338f0d245826128896040880160208901613c81565b6040518363ffffffff1660e01b81526004016128a692919061476f565b60206040518083038186803b1580156128be57600080fd5b505afa1580156128d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f69190613d23565b6129125760405162461bcd60e51b815260040161045090614bc7565b6129226040850160208601613c81565b6001600160a01b03166337f6213861293d6020870187613c81565b6040518263ffffffff1660e01b8152600401612959919061475b565b602060405180830381600087803b15801561297357600080fd5b505af1158015612987573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ab9190613d23565b6129c75760405162461bcd60e51b815260040161045090614cb3565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906129f690309060040161475b565b60206040518083038186803b158015612a0e57600080fd5b505afa158015612a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a469190614460565b90506001612a5a6060870160408801614364565b6003811115612a6557fe5b1415612b0457600060608560200151806020019051810190612a8791906144bc565b9092509050612a996020880188613c81565b8651604051637224811760e11b81526001600160a01b03929092169163e449022e91612acb9186908690600401615089565b600060405180830381600087803b158015612ae557600080fd5b505af1158015612af9573d6000803e3d6000fd5b505050505050612cb8565b6000612b166060870160408801614364565b6003811115612b2157fe5b1415612b9757600060608560200151806020019051810190612b439190614478565b9092509050612b556020880188613c81565b6001600160a01b03166338ed17398760000151848430612b774261070861357d565b6040518663ffffffff1660e01b8152600401612acb95949392919061504d565b6002612ba96060870160408801614364565b6003811115612bb457fe5b1415612bdc57612bd6612bca6020870187613c81565b856020015160006135a2565b50612cb8565b6003612bee6060870160408801614364565b6003811115612bf957fe5b1415612ca0576000806000808760200151806020019051810190612c1d9190614383565b92965090945092509050612c3460208a018a613c81565b6001600160a01b031663a6417ed6858585856040518563ffffffff1660e01b8152600401612c659493929190614a52565b600060405180830381600087803b158015612c7f57600080fd5b505af1158015612c93573d6000803e3d6000fd5b5050505050505050612cb8565b60405162461bcd60e51b815260040161045090614c35565b6040516370a0823160e01b8152612d3e906001600160a01b038516906370a0823190612ce890309060040161475b565b60206040518083038186803b158015612d0057600080fd5b505afa158015612d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d389190614460565b826131bd565b95945050505050565b600080866001600160a01b031663f8b2cb4f856040518263ffffffff1660e01b8152600401612d76919061475b565b60206040518083038186803b158015612d8e57600080fd5b505afa158015612da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc69190614460565b90506000612dd6866103e86135d0565b90506000612e1d612de884600161364d565b6103e802612e01846103e861367290919063ffffffff16565b612e1688612e108d6001613672565b906135d0565b02906136ab565b9998505050505050505050565b6125268363a9059cbb60e01b848460405160240161242c9291906147e0565b836001866001600160a01b03166373a9855c6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e8757600080fd5b505af1158015612e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebf9190614329565b6001811115612eca57fe5b1415612f4f576040516370a0823160e01b81526001600160a01b038716906370a0823190612efc90339060040161475b565b60206040518083038186803b158015612f1457600080fd5b505afa158015612f28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f4c9190614460565b90505b6040516323b872dd60e01b81526001600160a01b038716906323b872dd90612f7f90339030908690600401614789565b602060405180830381600087803b158015612f9957600080fd5b505af1158015612fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd19190613d23565b612fed5760405162461bcd60e51b815260040161045090614d5e565b6040516305369ecb60e11b81526001600160a01b03871690630a6d3d969061301d90849088903390600401614fe2565b600060405180830381600087803b15801561303757600080fd5b505af115801561304b573d6000803e3d6000fd5b50505050816109005760005b8351811015610c5c57600084828151811061306e57fe5b602002602001015190506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016130a6919061475b565b60206040518083038186803b1580156130be57600080fd5b505afa1580156130d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f69190614460565b111561312c5761312c33826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016113ff919061475b565b50600101613057565b6000806131418361373c565b9050806001600160a01b0316639daafec76040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561317e57600080fd5b505af1158015613192573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131b69190613c9d565b9392505050565b60006131ff83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506137af565b90505b92915050565b61321a826001600160a01b03166137db565b6132365760405162461bcd60e51b815260040161045090614eec565b60006060836001600160a01b031683604051613252919061473f565b6000604051808303816000865af19150503d806000811461328f576040519150601f19603f3d011682016040523d82523d6000602084013e613294565b606091505b5091509150816132b65760405162461bcd60e51b815260040161045090614b92565b80511561175957808060200190518101906132d19190613d23565b6117595760405162461bcd60e51b815260040161045090614e4c565b60006132f88261373c565b9050600061330583613135565b90506000826001600160a01b031663c0fcb166856040518263ffffffff1660e01b8152600401613335919061475b565b60206040518083038186803b15801561334d57600080fd5b505afa158015613361573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133859190613d23565b90506000826001600160a01b031663c0fcb166866040518263ffffffff1660e01b81526004016133b5919061475b565b60206040518083038186803b1580156133cd57600080fd5b505afa1580156133e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134059190613d23565b90506000856001600160a01b03166373a9855c6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561344457600080fd5b505af1158015613458573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347c9190614329565b9050600081600181111561348c57fe5b1480156134965750825b156134fa5760405163edb12adf60e01b81526001600160a01b0386169063edb12adf906134c790899060040161475b565b600060405180830381600087803b1580156134e157600080fd5b505af11580156134f5573d6000803e3d6000fd5b505050505b600181600181111561350857fe5b1480156135125750815b156109005760405163edb12adf60e01b81526001600160a01b0385169063edb12adf9061354390899060040161475b565b600060405180830381600087803b15801561355d57600080fd5b505af1158015613571573d6000803e3d6000fd5b50505050505050505050565b6000828201838110156131ff5760405162461bcd60e51b815260040161045090614af8565b60606135c884848460405180606001604052806029815260200161525460299139613814565b949350505050565b6000826135df57506000613202565b828202828482816135ec57fe5b041461360a5760405162461bcd60e51b815260040161045090614d0e565b6706f05b59d3b200008101818110156136355760405162461bcd60e51b815260040161045090614d0e565b6000670de0b6b3a7640000825b049695505050505050565b6000828201838110156131ff5760405162461bcd60e51b815260040161045090614e22565b60008060006136818585613842565b9150915080156136a35760405162461bcd60e51b815260040161045090614df7565b509392505050565b6000816136ca5760405162461bcd60e51b815260040161045090614d38565b826136d757506000613202565b670de0b6b3a7640000838102908482816136ed57fe5b041461370b5760405162461bcd60e51b815260040161045090614c64565b600283048101818110156137315760405162461bcd60e51b815260040161045090614c64565b600084828161364257fe5b6000816001600160a01b031663430bf08a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561377757600080fd5b505afa15801561378b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132029190613c9d565b600081848411156137d35760405162461bcd60e51b81526004016104509190614a75565b505050900390565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906135c8575050151592915050565b6060824710156138365760405162461bcd60e51b815260040161045090614bef565b612d3e85858585613867565b6000808383116138585750508082036000613860565b505081810360015b9250929050565b6060613872856137db565b61388e5760405162461bcd60e51b815260040161045090614d8b565b60006060866001600160a01b031685876040516138ab919061473f565b60006040518083038185875af1925050503d80600081146138e8576040519150601f19603f3d011682016040523d82523d6000602084013e6138ed565b606091505b509150915081156139015791506135c89050565b8051156139115780518082602001fd5b8360405162461bcd60e51b81526004016104509190614a75565b604051806080016040528060008152602001600081526020016000815260200160006001600160a01b031681525090565b604051806040016040528060008152602001606081525090565b803561320281615214565b60008083601f840112613992578182fd5b5081356001600160401b038111156139a8578182fd5b602083019150836020808302850101111561386057600080fd5b600082601f8301126139d2578081fd5b81356139e56139e082615114565b6150ee565b818152915060208083019084810181840286018201871015613a0657600080fd5b60005b84811015613a2e578135613a1c81615214565b84529282019290820190600101613a09565b505050505092915050565b600082601f830112613a49578081fd5b8151613a576139e082615114565b818152915060208083019084810181840286018201871015613a7857600080fd5b60005b84811015613a2e578151613a8e81615214565b84529282019290820190600101613a7b565b600082601f830112613ab0578081fd5b8135613abe6139e082615114565b818152915060208083019084810160005b84811015613a2e5781358701604080601f19838c03011215613af057600080fd5b613af9816150ee565b82860135815290820135906001600160401b03821115613b1857600080fd5b613b268b8784860101613b9c565b81870152865250509282019290820190600101613acf565b600082601f830112613b4e578081fd5b8135613b5c6139e082615114565b818152915060208083019084810181840286018201871015613b7d57600080fd5b60005b84811015613a2e57813584529282019290820190600101613b80565b600082601f830112613bac578081fd5b81356001600160401b03811115613bc1578182fd5b613bd4601f8201601f19166020016150ee565b9150808252836020828501011115613beb57600080fd5b8060208401602084013760009082016020015292915050565b600060608284031215613c15578081fd5b50919050565b60006104008284031215613c15578081fd5b60006101408284031215613c15578081fd5b600060408284031215613c50578081fd5b613c5a60406150ee565b9050813581526020820135602082015292915050565b600060408284031215613c15578081fd5b600060208284031215613c92578081fd5b81356131ff81615214565b600060208284031215613cae578081fd5b81516131ff81615214565b60008060408385031215613ccb578081fd5b8235613cd681615214565b91506020830135613ce681615214565b809150509250929050565b600060208284031215613d02578081fd5b81516001600160401b03811115613d17578182fd5b6135c884828501613a39565b600060208284031215613d34578081fd5b81516131ff81615229565b60008060408385031215613ccb578182fd5b600080600060608486031215613d65578081fd5b8335613d7081615214565b925060208401356001600160401b0380821115613d8b578283fd5b613d97878388016139c2565b93506040860135915080821115613dac578283fd5b50613db986828701613b3e565b9150509250925092565b60008060408385031215613dd5578182fd5b8235613de081615214565b91506020830135613ce681615229565b60008060008060008060008060a0898b031215613e0b578586fd5b8835613e1681615214565b975060208901356001600160401b0380821115613e31578788fd5b613e3d8c838d01613981565b909950975060408b0135915080821115613e55578586fd5b613e618c838d01613981565b909750955060608b0135915080821115613e79578485fd5b50613e868b828c01613981565b9094509250506080890135613e9a81615229565b809150509295985092959890939650565b60008060008060008060008060006105808a8c031215613ec9578283fd5b613ed38b8b613976565b9850613ee28b60208c01613976565b975060408a01356001600160401b0380821115613efd578485fd5b613f098d838e01613c2d565b9850613f188d60608e01613c04565b9750613f278d60c08e01613c70565b9650613f378d6101008e01613c1b565b95506105008c0135915080821115613f4d578485fd5b613f598d838e016139c2565b94506105208c0135915080821115613f6f578283fd5b50613f7c8c828d01613b3e565b925050613f8d8b6105408c01613c3f565b90509295985092959850929598565b6000806000806000806000610120888a031215613fb7578081fd5b8735613fc281615214565b96506020880135613fd281615214565b955060408801359450606088013593506080880135613ff081615214565b9250613fff8960a08a01613c04565b91506101008801356001600160401b0381111561401a578182fd5b6140268a828b01613aa0565b91505092959891949750929550565b600080600060608486031215614049578081fd5b833561405481615214565b925060208401356001600160401b038082111561406f578283fd5b61407b87838801613b3e565b93506040860135915080821115614090578283fd5b50613db9868287016139c2565b600080604083850312156140af578182fd5b82356140ba81615214565b946020939093013593505050565b6000806000806000608086880312156140df578283fd5b85356140ea81615214565b94506020860135935060408601356001600160401b0381111561410b578384fd5b61411788828901613981565b909450925050606086013561412b81615214565b809150509295509295909350565b60008060006060848603121561414d578081fd5b833561415881615214565b92506020840135915060408401356001600160401b03811115614179578182fd5b613db986828701613b3e565b6000806000806000806000610120888a0312156141a0578081fd5b87356141ab81615214565b96506020880135955060408801356001600160401b03808211156141cd578283fd5b6141d98b838c01613b3e565b965060608a0135955060808a013591506141f282615214565b8194506142028b60a08c01613c04565b93506101008a0135915080821115614218578283fd5b506140268a828b01613aa0565b6000806000806060858703121561423a578182fd5b843561424581615214565b93506020850135925060408501356001600160401b03811115614266578283fd5b61427287828801613981565b95989497509550505050565b600080600080600060a08688031215614295578283fd5b85356142a081615214565b945060208601356142b081615214565b935060408601356142c081615214565b925060608601356142d081615214565b949793965091946080013592915050565b600080604083850312156142f3578182fd5b82356142fe81615214565b915060208301356001600160401b03811115614318578182fd5b830160e08186031215613ce6578182fd5b60006020828403121561433a578081fd5b81516131ff81615237565b600060208284031215614356578081fd5b8135600881106131ff578182fd5b600060208284031215614375578081fd5b8135600481106131ff578182fd5b60008060008060808587031215614398578182fd5b84516143a381615244565b60208601519094506143b481615244565b6040860151606090960151949790965092505050565b60006101608083850312156143dd578182fd5b6143e6816150ee565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152508091505092915050565b600060208284031215614471578081fd5b5051919050565b6000806040838503121561448a578182fd5b8251915060208301516001600160401b038111156144a6578182fd5b6144b285828601613a39565b9150509250929050565b600080604083850312156144ce578182fd5b825191506020808401516001600160401b038111156144eb578283fd5b8401601f810186136144fb578283fd5b80516145096139e082615114565b81815283810190838501858402850186018a1015614525578687fd5b8694505b83851015614547578051835260019490940193918501918501614529565b5080955050505050509250929050565b6001600160a01b03169052565b60008284526020808501945082825b858110156145a157813561458681615214565b6001600160a01b031687529582019590820190600101614573565b509495945050505050565b6000815180845260208085019450808401835b838110156145a15781516001600160a01b0316875295820195908201906001016145bf565b81835260006001600160fb1b038311156145fc578081fd5b6020830280836020870137939093016020019283525090919050565b6000815180845260208085019450808401835b838110156145a15781518752958201959082019060010161462b565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b6002811061467b57fe5b9052565b6003811061467b57fe5b61469382826146f2565b6101006146a48184018284016146f2565b506102006146b68184018284016146f2565b506103006125268184018284016146f2565b80356146d381615229565b1515825260208101356146e581615229565b8015156020840152505050565b6146fc8282614730565b61470c6040830160408301614730565b61471c6080830160808301614730565b61472c60c0830160c08301614730565b5050565b80358252602090810135910152565b600082516147518184602087016151e8565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0386168152602081018590526040810184905260c081016008841061482157fe5b83606083015282516080830152602083015160a08301529695505050505050565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b03871681526104c06020820181905260009061488f8880615187565b610140838601526148a561060086018284614647565b925050506148b66020890189615187565b6104bf1980868503016104e08701526148d0848385614647565b93506148df60408c018c615140565b9350915080868503016105008701526148f9848484614564565b935061490860608c018c615140565b9350915080868503016105208701526149228484846145e4565b935061493160808c018c615140565b9350915080868503016105408701525061494c8383836145e4565b9250505060a088013561056084015260c088013561058084015260e08801356105a08401526101008801356105c084015261498b6101208901896151cb565b6149996105e0850182614671565b506149a760408401886146c8565b6149b46080840187614689565b8281036104808401526149c781866145ac565b90508281036104a0840152612e1d8185614618565b6001600160a01b039390931683526020830191909152604082015260600190565b600060408252614a1060408301856145ac565b8281036020840152612d3e8185614618565b600060408252614a356040830185614618565b8281036020840152612d3e81856145ac565b901515815260200190565b600f94850b81529290930b60208301526040820152606081019190915260800190565b6000602082528251806020840152614a948160408501602087016151e8565b601f01601f19169190910160400192915050565b60208082526009908201526808aa4a49ea4be8aa8960bb1b604082015260600190565b60208082526013908201527208aa4a4be988a9c8ea890be9a92a69a82a8869606b1b604082015260600190565b6020808252601b908201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604082015260600190565b60208082526018908201527708aa4a4bea89e968a9c988a9c8ea890be9a92a69a82a886960431b604082015260600190565b60208082526019908201527811549497d513d2d15397d393d517d5d2125511531254d51151603a1b604082015260600190565b6020808252818101527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604082015260600190565b6020808252600e908201526d1353d115531157d253131151d05360921b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601590820152744552525f494e56414c49445f535741505f5459504560581b604082015260600190565b60208082526010908201526f11549497d1125597d25395115493905360821b604082015260600190565b6020808252600b908201526a4552525f5245454e54525960a81b604082015260600190565b6020808252600e908201526d1493d555115497d253131151d05360921b604082015260600190565b60208082526019908201527811549497d4d210549157d05353d5539517d513d7d4d3505313603a1b604082015260600190565b60208082526010908201526f4552525f4d554c5f4f564552464c4f5760801b604082015260600190565b6020808252600c908201526b4552525f4449565f5a45524f60a01b604082015260600190565b60208082526013908201527211549497d514905394d1915497d19052531151606a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252601b908201527a11549497d49150d152559157d05353d5539517d513d7d4d3505313602a1b604082015260600190565b6020808252601190820152704552525f5355425f554e444552464c4f5760781b604082015260600190565b60208082526010908201526f4552525f4144445f4f564552464c4f5760801b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b6020808252601f908201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604082015260600190565b6000602082528235614f3481615214565b6001600160a01b0390811660208481019190915284013590614f5582615214565b808216604085015260408501359150614f6d82615214565b80821660608501525050614f846060840184615133565b614f916080840182614557565b50614f9f60808401846151d8565b614fac60a084018261467f565b5060a083013560c0830152614fc460c0840184615187565b60e080850152612d3e61010085018284614647565b90815260200190565b600084825260606020830152614ffb6060830185614618565b905060018060a01b0383166040830152949350505050565b60008582526080602083015261502c6080830186614618565b6001600160a01b039485166040840152929093166060909101529392505050565b600086825285602083015260a0604083015261506c60a08301866145ac565b6001600160a01b0394909416606083015250608001529392505050565b600084825283602083015260606040830152612d3e6060830184614618565b6000808335601e198436030181126150be578283fd5b8301803591506001600160401b038211156150d7578283fd5b602090810192508102360382131561386057600080fd5b6040518181016001600160401b038111828210171561510c57600080fd5b604052919050565b60006001600160401b03821115615129578081fd5b5060209081020190565b600082356131ff81615214565b6000808335601e19843603018112615156578283fd5b83016020810192503590506001600160401b0381111561517557600080fd5b60208102360383131561386057600080fd5b6000808335601e1984360301811261519d578283fd5b83016020810192503590506001600160401b038111156151bc57600080fd5b80360383131561386057600080fd5b600082356131ff81615237565b60008235600381106131ff578182fd5b60005b838110156152035781810151838201526020016151eb565b838111156117595750506000910152565b6001600160a01b0381168114610bf457600080fd5b8015158114610bf457600080fd5b60028110610bf457600080fd5b80600f0b8114610bf457600080fdfe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220ceb17fa56d4af0bb0810873ecc72aecc3ee88a00c5774ca340838706e9f729cd64736f6c634300060c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.