More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 3,451 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Sell NXM | 20451915 | 106 days ago | IN | 0 ETH | 0.00011793 | ||||
Sell NXM Tokens | 12837914 | 1220 days ago | IN | 0 ETH | 0.00454049 | ||||
Sell NXM Tokens | 12823677 | 1223 days ago | IN | 0 ETH | 0 | ||||
Make Cover Begin | 12508674 | 1272 days ago | IN | 3.12640657 ETH | 0.01683492 | ||||
Make Cover Begin | 12508541 | 1272 days ago | IN | 0.02562628 ETH | 0.01574038 | ||||
Buy NXM | 12507941 | 1272 days ago | IN | 1.48 ETH | 0.00607857 | ||||
Make Cover Begin | 12507525 | 1272 days ago | IN | 3.20328542 ETH | 0.02492238 | ||||
Make Cover Begin | 12506852 | 1272 days ago | IN | 0.09467488 ETH | 0.00192884 | ||||
Make Cover Using... | 12506581 | 1272 days ago | IN | 0 ETH | 0.01881583 | ||||
Make Cover Using... | 12506575 | 1272 days ago | IN | 0 ETH | 0.01825763 | ||||
Make Cover Using... | 12506471 | 1272 days ago | IN | 0 ETH | 0.01936966 | ||||
Buy NXM | 12506234 | 1272 days ago | IN | 0.5 ETH | 0.00564392 | ||||
Make Cover Begin | 12506216 | 1272 days ago | IN | 0.34221072 ETH | 0.02996216 | ||||
Make Cover Using... | 12505753 | 1272 days ago | IN | 0 ETH | 0.02147911 | ||||
Make Cover Begin | 12505668 | 1272 days ago | IN | 0.07830253 ETH | 0.01850934 | ||||
Make Cover Begin | 12505653 | 1272 days ago | IN | 0.12813141 ETH | 0.01899072 | ||||
Buy NXM | 12505384 | 1272 days ago | IN | 2 ETH | 0.00679677 | ||||
Make Cover Begin | 12504956 | 1272 days ago | IN | 0.12813141 ETH | 0.02876755 | ||||
Buy NXM | 12504871 | 1272 days ago | IN | 0.1 ETH | 0.0071199 | ||||
Make Cover Using... | 12504727 | 1272 days ago | IN | 0 ETH | 0.03307827 | ||||
Make Cover Using... | 12504311 | 1272 days ago | IN | 0 ETH | 0.03272392 | ||||
Make Cover Using... | 12504136 | 1272 days ago | IN | 0 ETH | 0.02520849 | ||||
Make Cover Begin | 12503870 | 1272 days ago | IN | 0.1089117 ETH | 0.01729226 | ||||
Make Cover Begin | 12503616 | 1272 days ago | IN | 0.03843942 ETH | 0.01629446 | ||||
Make Cover Using... | 12503597 | 1272 days ago | IN | 0 ETH | 0.01714854 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
12509963 | 1271 days ago | 161,873.19324096 ETH | ||||
12507931 | 1272 days ago | 0.07687885 ETH | ||||
12491733 | 1274 days ago | 5.67372791 ETH | ||||
12491702 | 1274 days ago | 5.71105506 ETH | ||||
12491667 | 1274 days ago | 5.37511065 ETH | ||||
12491661 | 1274 days ago | 0.30489021 ETH | ||||
12491660 | 1274 days ago | 5.22580202 ETH | ||||
12491609 | 1274 days ago | 0.36575173 ETH | ||||
12491604 | 1274 days ago | 6.94285126 ETH | ||||
12491575 | 1274 days ago | 5.44976496 ETH | ||||
12491568 | 1274 days ago | 0.34909666 ETH | ||||
12491567 | 1274 days ago | 6.56957968 ETH | ||||
12490716 | 1274 days ago | 0.31873057 ETH | ||||
12490715 | 1274 days ago | 5.78570938 ETH | ||||
12490700 | 1274 days ago | 5.23204182 ETH | ||||
12490642 | 1274 days ago | 4.68776275 ETH | ||||
12490606 | 1274 days ago | 0.30927431 ETH | ||||
12490601 | 1274 days ago | 5.41243781 ETH | ||||
12490597 | 1274 days ago | 5.07135064 ETH | ||||
12490590 | 1274 days ago | 0.31960621 ETH | ||||
12490589 | 1274 days ago | 5.56174643 ETH | ||||
12490574 | 1274 days ago | 0.90070633 ETH | ||||
12489698 | 1275 days ago | 0.4597753 ETH | ||||
12489633 | 1275 days ago | 5.83713533 ETH | ||||
12489606 | 1275 days ago | 0.33379222 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Pool
Compiler Version
v0.5.17+commit.d19bba13
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "../../abstract/MasterAware.sol"; import "../cover/Quotation.sol"; import "../oracles/PriceFeedOracle.sol"; import "../token/NXMToken.sol"; import "../token/TokenController.sol"; import "./MCR.sol"; import "./SwapAgent.sol"; contract Pool is MasterAware, ReentrancyGuard { using Address for address; using SafeMath for uint; using SafeERC20 for IERC20; /* storage */ address[] public assets; mapping(address => SwapAgent.AssetData) public assetData; // contracts Quotation public quotation; NXMToken public nxmToken; TokenController public tokenController; MCR public mcr; // parameters address public twapOracle; address public swapController; uint public minPoolEth; PriceFeedOracle public priceFeedOracle; /* constants */ address constant public ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; uint public constant MCR_RATIO_DECIMALS = 4; uint public constant MAX_MCR_RATIO = 40000; // 400% uint public constant MAX_BUY_SELL_MCR_ETH_FRACTION = 500; // 5%. 4 decimal points uint internal constant CONSTANT_C = 5800000; uint internal constant CONSTANT_A = 1028 * 1e13; uint internal constant TOKEN_EXPONENT = 4; /* events */ event Payout(address indexed to, address indexed asset, uint amount); event NXMSold (address indexed member, uint nxmIn, uint ethOut); event NXMBought (address indexed member, uint ethIn, uint nxmOut); event Swapped(address indexed fromAsset, address indexed toAsset, uint amountIn, uint amountOut); /* logic */ modifier onlySwapController { require(msg.sender == swapController, "Pool: not swapController"); _; } constructor ( address[] memory _assets, uint112[] memory _minAmounts, uint112[] memory _maxAmounts, uint[] memory _maxSlippageRatios, address _master, address _priceOracle, address _twapOracle, address _swapController ) public { require(_assets.length == _minAmounts.length, "Pool: length mismatch"); require(_assets.length == _maxAmounts.length, "Pool: length mismatch"); require(_assets.length == _maxSlippageRatios.length, "Pool: length mismatch"); for (uint i = 0; i < _assets.length; i++) { address asset = _assets[i]; require(asset != address(0), "Pool: asset is zero address"); require(_maxAmounts[i] >= _minAmounts[i], "Pool: max < min"); require(_maxSlippageRatios[i] <= 1 ether, "Pool: max < min"); assets.push(asset); assetData[asset].minAmount = _minAmounts[i]; assetData[asset].maxAmount = _maxAmounts[i]; assetData[asset].maxSlippageRatio = _maxSlippageRatios[i]; } master = INXMMaster(_master); priceFeedOracle = PriceFeedOracle(_priceOracle); twapOracle = _twapOracle; swapController = _swapController; } // fallback function function() external payable {} // for legacy Pool1 upgrade compatibility function sendEther() external payable {} /** * @dev Calculates total value of all pool assets in ether */ function getPoolValueInEth() public view returns (uint) { uint total = address(this).balance; for (uint i = 0; i < assets.length; i++) { address assetAddress = assets[i]; IERC20 token = IERC20(assetAddress); uint rate = priceFeedOracle.getAssetToEthRate(assetAddress); require(rate > 0, "Pool: zero rate"); uint assetBalance = token.balanceOf(address(this)); uint assetValue = assetBalance.mul(rate).div(1e18); total = total.add(assetValue); } return total; } /* asset related functions */ function getAssets() external view returns (address[] memory) { return assets; } function getAssetDetails(address _asset) external view returns ( uint balance, uint112 min, uint112 max, uint32 lastAssetSwapTime, uint maxSlippageRatio ) { IERC20 token = IERC20(_asset); balance = token.balanceOf(address(this)); SwapAgent.AssetData memory data = assetData[_asset]; return (balance, data.minAmount, data.maxAmount, data.lastSwapTime, data.maxSlippageRatio); } function addAsset( address _asset, uint112 _min, uint112 _max, uint _maxSlippageRatio ) external onlyGovernance { require(_asset != address(0), "Pool: asset is zero address"); require(_max >= _min, "Pool: max < min"); require(_maxSlippageRatio <= 1 ether, "Pool: max slippage ratio > 1"); for (uint i = 0; i < assets.length; i++) { require(_asset != assets[i], "Pool: asset exists"); } assets.push(_asset); assetData[_asset] = SwapAgent.AssetData(_min, _max, 0, _maxSlippageRatio); } function removeAsset(address _asset) external onlyGovernance { for (uint i = 0; i < assets.length; i++) { if (_asset != assets[i]) { continue; } delete assetData[_asset]; assets[i] = assets[assets.length - 1]; assets.pop(); return; } revert("Pool: asset not found"); } function setAssetDetails( address _asset, uint112 _min, uint112 _max, uint _maxSlippageRatio ) external onlyGovernance { require(_min <= _max, "Pool: min > max"); require(_maxSlippageRatio <= 1 ether, "Pool: max slippage ratio > 1"); for (uint i = 0; i < assets.length; i++) { if (_asset != assets[i]) { continue; } assetData[_asset].minAmount = _min; assetData[_asset].maxAmount = _max; assetData[_asset].maxSlippageRatio = _maxSlippageRatio; return; } revert("Pool: asset not found"); } /* swap functions */ function getSwapQuote( uint tokenAmountIn, IERC20 fromToken, IERC20 toToken ) public view returns (uint tokenAmountOut) { return SwapAgent.getSwapQuote( tokenAmountIn, fromToken, toToken ); } function swapETHForAsset( address toTokenAddress, uint amountIn, uint amountOutMin ) external whenNotPaused onlySwapController nonReentrant { SwapAgent.AssetData storage assetDetails = assetData[toTokenAddress]; uint amountOut = SwapAgent.swapETHForAsset( twapOracle, assetDetails, toTokenAddress, amountIn, amountOutMin, minPoolEth ); emit Swapped(ETH, toTokenAddress, amountIn, amountOut); } function swapAssetForETH( address fromTokenAddress, uint amountIn, uint amountOutMin ) external whenNotPaused onlySwapController nonReentrant { uint amountOut = SwapAgent.swapAssetForETH( twapOracle, assetData[fromTokenAddress], fromTokenAddress, amountIn, amountOutMin ); emit Swapped(fromTokenAddress, ETH, amountIn, amountOut); } /* claim related functions */ /** * @dev Execute the payout in case a claim is accepted * @param asset token address or 0xEee...EEeE for ether * @param payoutAddress send funds to this address * @param amount amount to send */ function sendClaimPayout ( address asset, address payable payoutAddress, uint amount ) external onlyInternal nonReentrant returns (bool success) { bool ok; if (asset == ETH) { // solhint-disable-next-line avoid-low-level-calls (ok, /* data */) = payoutAddress.call.value(amount)(""); } else { ok = _safeTokenTransfer(asset, payoutAddress, amount); } if (ok) { emit Payout(payoutAddress, asset, amount); } return ok; } /** * @dev safeTransfer implementation that does not revert * @param tokenAddress ERC20 address * @param to destination * @param value amount to send * @return success true if the transfer was successfull */ function _safeTokenTransfer ( address tokenAddress, address to, uint256 value ) internal returns (bool) { // token address is not a contract if (!tokenAddress.isContract()) { return false; } IERC20 token = IERC20(tokenAddress); bytes memory data = abi.encodeWithSelector(token.transfer.selector, to, value); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = tokenAddress.call(data); // low-level call failed/reverted if (!success) { return false; } // tokens that don't have return data if (returndata.length == 0) { return true; } // tokens that have return data will return a bool return abi.decode(returndata, (bool)); } /* pool lifecycle functions */ function transferAsset( address asset, address payable destination, uint amount ) external onlyGovernance nonReentrant { require(assetData[asset].maxAmount == 0, "Pool: max not zero"); require(destination != address(0), "Pool: dest zero"); IERC20 token = IERC20(asset); uint balance = token.balanceOf(address(this)); uint transferableAmount = amount > balance ? balance : amount; token.safeTransfer(destination, transferableAmount); } function upgradeCapitalPool(address payable newPoolAddress) external onlyMaster nonReentrant { // transfer ether uint ethBalance = address(this).balance; (bool ok, /* data */) = newPoolAddress.call.value(ethBalance)(""); require(ok, "Pool: transfer failed"); // transfer assets for (uint i = 0; i < assets.length; i++) { IERC20 token = IERC20(assets[i]); uint tokenBalance = token.balanceOf(address(this)); token.safeTransfer(newPoolAddress, tokenBalance); } } /** * @dev Update dependent contract address * @dev Implements MasterAware interface function */ function changeDependentContractAddress() public { nxmToken = NXMToken(master.tokenAddress()); tokenController = TokenController(master.getLatestAddress("TC")); quotation = Quotation(master.getLatestAddress("QT")); mcr = MCR(master.getLatestAddress("MC")); } /* cover purchase functions */ /// @dev Enables user to purchase cover with funding in ETH. /// @param smartCAdd Smart Contract Address function makeCoverBegin( address smartCAdd, bytes4 coverCurr, uint[] memory coverDetails, uint16 coverPeriod, uint8 _v, bytes32 _r, bytes32 _s ) public payable onlyMember whenNotPaused { require(coverCurr == "ETH", "Pool: Unexpected asset type"); require(msg.value == coverDetails[1], "Pool: ETH amount does not match premium"); quotation.verifyCoverDetails(msg.sender, smartCAdd, coverCurr, coverDetails, coverPeriod, _v, _r, _s); } /** * @dev Enables user to purchase cover via currency asset eg DAI */ function makeCoverUsingCA( address smartCAdd, bytes4 coverCurr, uint[] memory coverDetails, uint16 coverPeriod, uint8 _v, bytes32 _r, bytes32 _s ) public onlyMember whenNotPaused { require(coverCurr != "ETH", "Pool: Unexpected asset type"); quotation.verifyCoverDetails(msg.sender, smartCAdd, coverCurr, coverDetails, coverPeriod, _v, _r, _s); } function transferAssetFrom (address asset, address from, uint amount) public onlyInternal whenNotPaused { IERC20 token = IERC20(asset); token.safeTransferFrom(from, address(this), amount); } /* token sale functions */ /** * @dev (DEPRECATED, use sellTokens function instead) Allows selling of NXM for ether. * Seller first needs to give this contract allowance to * transfer/burn tokens in the NXMToken contract * @param _amount Amount of NXM to sell * @return success returns true on successfull sale */ function sellNXMTokens(uint _amount) public onlyMember whenNotPaused returns (bool success) { sellNXM(_amount, 0); return true; } /** * @dev (DEPRECATED, use calculateNXMForEth function instead) Returns the amount of wei a seller will get for selling NXM * @param amount Amount of NXM to sell * @return weiToPay Amount of wei the seller will get */ function getWei(uint amount) external view returns (uint weiToPay) { return getEthForNXM(amount); } /** * @dev Buys NXM tokens with ETH. * @param minTokensOut Minimum amount of tokens to be bought. Revert if boughtTokens falls below this number. * @return boughtTokens number of bought tokens. */ function buyNXM(uint minTokensOut) public payable onlyMember whenNotPaused { uint ethIn = msg.value; require(ethIn > 0, "Pool: ethIn > 0"); uint totalAssetValue = getPoolValueInEth().sub(ethIn); uint mcrEth = mcr.getLastMCREther(); uint mcrRatio = calculateMCRRatio(totalAssetValue, mcrEth); require(mcrRatio <= MAX_MCR_RATIO, "Pool: Cannot purchase if MCR% > 400%"); uint tokensOut = calculateNXMForEth(ethIn, totalAssetValue, mcrEth); require(tokensOut >= minTokensOut, "Pool: tokensOut is less than minTokensOut"); tokenController.mint(msg.sender, tokensOut); emit NXMBought(msg.sender, ethIn, tokensOut); } /** * @dev Sell NXM tokens and receive ETH. * @param tokenAmount Amount of tokens to sell. * @param minEthOut Minimum amount of ETH to be received. Revert if ethOut falls below this number. * @return ethOut amount of ETH received in exchange for the tokens. */ function sellNXM(uint tokenAmount, uint minEthOut) public onlyMember nonReentrant whenNotPaused { require(nxmToken.balanceOf(msg.sender) >= tokenAmount, "Pool: Not enough balance"); require(nxmToken.isLockedForMV(msg.sender) <= now, "Pool: NXM tokens are locked for voting"); uint currentTotalAssetValue = getPoolValueInEth(); uint mcrEth = mcr.getLastMCREther(); uint ethOut = calculateEthForNXM(tokenAmount, currentTotalAssetValue, mcrEth); require(currentTotalAssetValue.sub(ethOut) >= mcrEth, "Pool: MCR% cannot fall below 100%"); require(ethOut >= minEthOut, "Pool: ethOut < minEthOut"); tokenController.burnFrom(msg.sender, tokenAmount); (bool ok, /* data */) = msg.sender.call.value(ethOut)(""); require(ok, "Pool: Sell transfer failed"); emit NXMSold(msg.sender, tokenAmount, ethOut); } /** * @dev Get value in tokens for an ethAmount purchase. * @param ethAmount amount of ETH used for buying. * @return tokenValue tokens obtained by buying worth of ethAmount */ function getNXMForEth( uint ethAmount ) public view returns (uint) { uint totalAssetValue = getPoolValueInEth(); uint mcrEth = mcr.getLastMCREther(); return calculateNXMForEth(ethAmount, totalAssetValue, mcrEth); } function calculateNXMForEth( uint ethAmount, uint currentTotalAssetValue, uint mcrEth ) public pure returns (uint) { require( ethAmount <= mcrEth.mul(MAX_BUY_SELL_MCR_ETH_FRACTION).div(10 ** MCR_RATIO_DECIMALS), "Pool: Purchases worth higher than 5% of MCReth are not allowed" ); /* The price formula is: P(V) = A + MCReth / C * MCR% ^ 4 where MCR% = V / MCReth P(V) = A + 1 / (C * MCReth ^ 3) * V ^ 4 To compute the number of tokens issued we can integrate with respect to V the following: ΔT = ΔV / P(V) which assumes that for an infinitesimally small change in locked value V price is constant and we get an infinitesimally change in token supply ΔT. This is not computable on-chain, below we use an approximation that works well assuming * MCR% stays within [100%, 400%] * ethAmount <= 5% * MCReth Use a simplified formula excluding the constant A price offset to compute the amount of tokens to be minted. AdjustedP(V) = 1 / (C * MCReth ^ 3) * V ^ 4 AdjustedP(V) = 1 / (C * MCReth ^ 3) * V ^ 4 For a very small variation in tokens ΔT, we have, ΔT = ΔV / P(V), to get total T we integrate with respect to V. adjustedTokenAmount = ∫ (dV / AdjustedP(V)) from V0 (currentTotalAssetValue) to V1 (nextTotalAssetValue) adjustedTokenAmount = ∫ ((C * MCReth ^ 3) / V ^ 4 * dV) from V0 to V1 Evaluating the above using the antiderivative of the function we get: adjustedTokenAmount = - MCReth ^ 3 * C / (3 * V1 ^3) + MCReth * C /(3 * V0 ^ 3) */ if (currentTotalAssetValue == 0 || mcrEth.div(currentTotalAssetValue) > 1e12) { /* If the currentTotalAssetValue = 0, adjustedTokenPrice approaches 0. Therefore we can assume the price is A. If currentTotalAssetValue is far smaller than mcrEth, MCR% approaches 0, let the price be A (baseline price). This avoids overflow in the calculateIntegralAtPoint computation. This approximation is safe from arbitrage since at MCR% < 100% no sells are possible. */ uint tokenPrice = CONSTANT_A; return ethAmount.mul(1e18).div(tokenPrice); } // MCReth * C /(3 * V0 ^ 3) uint point0 = calculateIntegralAtPoint(currentTotalAssetValue, mcrEth); // MCReth * C / (3 * V1 ^3) uint nextTotalAssetValue = currentTotalAssetValue.add(ethAmount); uint point1 = calculateIntegralAtPoint(nextTotalAssetValue, mcrEth); uint adjustedTokenAmount = point0.sub(point1); /* Compute a preliminary adjustedTokenPrice for the minted tokens based on the adjustedTokenAmount above, and to that add the A constant (the price offset previously removed in the adjusted Price formula) to obtain the finalPrice and ultimately the tokenValue based on the finalPrice. adjustedPrice = ethAmount / adjustedTokenAmount finalPrice = adjustedPrice + A tokenValue = ethAmount / finalPrice */ // ethAmount is multiplied by 1e18 to cancel out the multiplication factor of 1e18 of the adjustedTokenAmount uint adjustedTokenPrice = ethAmount.mul(1e18).div(adjustedTokenAmount); uint tokenPrice = adjustedTokenPrice.add(CONSTANT_A); return ethAmount.mul(1e18).div(tokenPrice); } /** * @dev integral(V) = MCReth ^ 3 * C / (3 * V ^ 3) * 1e18 * computation result is multiplied by 1e18 to allow for a precision of 18 decimals. * NOTE: omits the minus sign of the correct integral to use a uint result type for simplicity * WARNING: this low-level function should be called from a contract which checks that * mcrEth / assetValue < 1e17 (no overflow) and assetValue != 0 */ function calculateIntegralAtPoint( uint assetValue, uint mcrEth ) internal pure returns (uint) { return CONSTANT_C .mul(1e18) .div(3) .mul(mcrEth).div(assetValue) .mul(mcrEth).div(assetValue) .mul(mcrEth).div(assetValue); } function getEthForNXM(uint nxmAmount) public view returns (uint ethAmount) { uint currentTotalAssetValue = getPoolValueInEth(); uint mcrEth = mcr.getLastMCREther(); return calculateEthForNXM(nxmAmount, currentTotalAssetValue, mcrEth); } /** * @dev Computes token sell value for a tokenAmount in ETH with a sell spread of 2.5%. * for values in ETH of the sale <= 1% * MCReth the sell spread is very close to the exact value of 2.5%. * for values higher than that sell spread may exceed 2.5% * (The higher amount being sold at any given time the higher the spread) */ function calculateEthForNXM( uint nxmAmount, uint currentTotalAssetValue, uint mcrEth ) public pure returns (uint) { // Step 1. Calculate spot price at current values and amount of ETH if tokens are sold at that price uint spotPrice0 = calculateTokenSpotPrice(currentTotalAssetValue, mcrEth); uint spotEthAmount = nxmAmount.mul(spotPrice0).div(1e18); // Step 2. Calculate spot price using V = currentTotalAssetValue - spotEthAmount from step 1 uint totalValuePostSpotPriceSell = currentTotalAssetValue.sub(spotEthAmount); uint spotPrice1 = calculateTokenSpotPrice(totalValuePostSpotPriceSell, mcrEth); // Step 3. Min [average[Price(0), Price(1)] x ( 1 - Sell Spread), Price(1) ] // Sell Spread = 2.5% uint averagePriceWithSpread = spotPrice0.add(spotPrice1).div(2).mul(975).div(1000); uint finalPrice = averagePriceWithSpread < spotPrice1 ? averagePriceWithSpread : spotPrice1; uint ethAmount = finalPrice.mul(nxmAmount).div(1e18); require( ethAmount <= mcrEth.mul(MAX_BUY_SELL_MCR_ETH_FRACTION).div(10 ** MCR_RATIO_DECIMALS), "Pool: Sales worth more than 5% of MCReth are not allowed" ); return ethAmount; } function calculateMCRRatio(uint totalAssetValue, uint mcrEth) public pure returns (uint) { return totalAssetValue.mul(10 ** MCR_RATIO_DECIMALS).div(mcrEth); } /** * @dev Calculates token price in ETH 1 NXM token. TokenPrice = A + (MCReth / C) * MCR%^4 */ function calculateTokenSpotPrice(uint totalAssetValue, uint mcrEth) public pure returns (uint tokenPrice) { uint mcrRatio = calculateMCRRatio(totalAssetValue, mcrEth); uint precisionDecimals = 10 ** TOKEN_EXPONENT.mul(MCR_RATIO_DECIMALS); return mcrEth .mul(mcrRatio ** TOKEN_EXPONENT) .div(CONSTANT_C) .div(precisionDecimals) .add(CONSTANT_A); } /** * @dev Returns the NXM price in a given asset * @param asset Asset name. */ function getTokenPrice(address asset) public view returns (uint tokenPrice) { uint totalAssetValue = getPoolValueInEth(); uint mcrEth = mcr.getLastMCREther(); uint tokenSpotPriceEth = calculateTokenSpotPrice(totalAssetValue, mcrEth); return priceFeedOracle.getAssetForEth(asset, tokenSpotPriceEth); } function getMCRRatio() public view returns (uint) { uint totalAssetValue = getPoolValueInEth(); uint mcrEth = mcr.getLastMCREther(); return calculateMCRRatio(totalAssetValue, mcrEth); } function updateUintParameters(bytes8 code, uint value) external onlyGovernance { if (code == "MIN_ETH") { minPoolEth = value; return; } revert("Pool: unknown parameter"); } function updateAddressParameters(bytes8 code, address value) external onlyGovernance { if (code == "TWAP") { twapOracle = value; return; } if (code == "SWAP") { swapController = value; return; } if (code == "PRC_FEED") { priceFeedOracle = PriceFeedOracle(value); return; } revert("Pool: unknown parameter"); } }
pragma solidity ^0.5.0; /** * @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(uint256 a, uint256 b) internal pure returns (uint256) { uint256 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(uint256 a, uint256 b) internal pure returns (uint256) { 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. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 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(uint256 a, uint256 b) internal pure returns (uint256) { // 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; } uint256 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(uint256 a, uint256 b) internal pure returns (uint256) { 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. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 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(uint256 a, uint256 b) internal pure returns (uint256) { 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. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev 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, uint256 amount) external returns (bool); /** * @dev 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 (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev 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, uint256 amount) external returns (bool); /** * @dev 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, uint256 value); /** * @dev 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, uint256 value); }
pragma solidity ^0.5.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/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 ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length 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 safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length 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"); } } }
pragma solidity ^0.5.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} 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 `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. * * _Since v2.5.0:_ this module is now much more gas efficient, given net gas * metering changes introduced in the Istanbul hardfork. */ contract ReentrancyGuard { bool private _notEntered; constructor () internal { // Storing an initial 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 percetange 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. _notEntered = true; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_notEntered, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _notEntered = false; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _notEntered = true; } }
pragma solidity ^0.5.5; /** * @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 Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @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]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } }
pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "./INXMMaster.sol"; contract MasterAware { INXMMaster public master; modifier onlyMember { require(master.isMember(msg.sender), "Caller is not a member"); _; } modifier onlyInternal { require(master.isInternal(msg.sender), "Caller is not an internal contract"); _; } modifier onlyMaster { if (address(master) != address(0)) { require(address(master) == msg.sender, "Not master"); } _; } modifier onlyGovernance { require( master.checkIsAuthToGoverned(msg.sender), "Caller is not authorized to govern" ); _; } modifier whenPaused { require(master.isPause(), "System is not paused"); _; } modifier whenNotPaused { require(!master.isPause(), "System is paused"); _; } function changeMasterAddress(address masterAddress) public onlyMaster { master = INXMMaster(masterAddress); } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../capital/MCR.sol"; import "../capital/PoolData.sol"; import "../claims/ClaimsReward.sol"; import "../governance/MemberRoles.sol"; import "../token/TokenController.sol"; import "../token/TokenData.sol"; import "../token/TokenFunctions.sol"; import "./QuotationData.sol"; contract Quotation is Iupgradable { using SafeMath for uint; TokenFunctions public tf; TokenController public tc; TokenData public td; Pool public pool; PoolData public pd; QuotationData public qd; MCR public m1; MemberRoles public mr; ClaimsReward public cr; bool internal locked; event RefundEvent(address indexed user, bool indexed status, uint holdedCoverID, bytes32 reason); modifier noReentrancy() { require(!locked, "Reentrant call."); locked = true; _; locked = false; } /** * @dev Iupgradable Interface to update dependent contract address */ function changeDependentContractAddress() public onlyInternal { m1 = MCR(ms.getLatestAddress("MC")); tf = TokenFunctions(ms.getLatestAddress("TF")); tc = TokenController(ms.getLatestAddress("TC")); td = TokenData(ms.getLatestAddress("TD")); qd = QuotationData(ms.getLatestAddress("QD")); pd = PoolData(ms.getLatestAddress("PD")); mr = MemberRoles(ms.getLatestAddress("MR")); cr = ClaimsReward(ms.getLatestAddress("CR")); pool = Pool(ms.getLatestAddress("P1")); } function sendEther() public payable { } /** * @dev Expires a cover after a set period of time. * Changes the status of the Cover and reduces the current * sum assured of all areas in which the quotation lies * Unlocks the CN tokens of the cover. Updates the Total Sum Assured value. * @param _cid Cover Id. */ function expireCover(uint _cid) public { require(checkCoverExpired(_cid) && qd.getCoverStatusNo(_cid) != uint(QuotationData.CoverStatus.CoverExpired)); tf.unlockCN(_cid); bytes4 curr; address scAddress; uint sumAssured; (,, scAddress, curr, sumAssured,) = qd.getCoverDetailsByCoverID1(_cid); if (qd.getCoverStatusNo(_cid) != uint(QuotationData.CoverStatus.ClaimAccepted)) _removeSAFromCSA(_cid, sumAssured); qd.changeCoverStatusNo(_cid, uint8(QuotationData.CoverStatus.CoverExpired)); } /** * @dev Checks if a cover should get expired/closed or not. * @param _cid Cover Index. * @return expire true if the Cover's time has expired, false otherwise. */ function checkCoverExpired(uint _cid) public view returns (bool expire) { expire = qd.getValidityOfCover(_cid) < uint64(now); } /** * @dev Updates the Sum Assured Amount of all the quotation. * @param _cid Cover id * @param _amount that will get subtracted Current Sum Assured * amount that comes under a quotation. */ function removeSAFromCSA(uint _cid, uint _amount) public onlyInternal { _removeSAFromCSA(_cid, _amount); } /** * @dev Makes Cover funded via NXM tokens. * @param smartCAdd Smart Contract Address */ function makeCoverUsingNXMTokens( uint[] memory coverDetails, uint16 coverPeriod, bytes4 coverCurr, address smartCAdd, uint8 _v, bytes32 _r, bytes32 _s ) public isMemberAndcheckPause { tc.burnFrom(msg.sender, coverDetails[2]); // need burn allowance _verifyCoverDetails(msg.sender, smartCAdd, coverCurr, coverDetails, coverPeriod, _v, _r, _s, true); } /** * @dev Verifies cover details signed off chain. * @param from address of funder. * @param scAddress Smart Contract Address */ function verifyCoverDetails( address payable from, address scAddress, bytes4 coverCurr, uint[] memory coverDetails, uint16 coverPeriod, uint8 _v, bytes32 _r, bytes32 _s ) public onlyInternal { _verifyCoverDetails( from, scAddress, coverCurr, coverDetails, coverPeriod, _v, _r, _s, false ); } /** * @dev Verifies signature. * @param coverDetails details related to cover. * @param coverPeriod validity of cover. * @param smaratCA smarat contract address. * @param _v argument from vrs hash. * @param _r argument from vrs hash. * @param _s argument from vrs hash. */ function verifySign( uint[] memory coverDetails, uint16 coverPeriod, bytes4 curr, address smaratCA, uint8 _v, bytes32 _r, bytes32 _s ) public view returns (bool) { require(smaratCA != address(0)); require(pd.capReached() == 1, "Can not buy cover until cap reached for 1st time"); bytes32 hash = getOrderHash(coverDetails, coverPeriod, curr, smaratCA); return isValidSignature(hash, _v, _r, _s); } /** * @dev Gets order hash for given cover details. * @param coverDetails details realted to cover. * @param coverPeriod validity of cover. * @param smaratCA smarat contract address. */ function getOrderHash( uint[] memory coverDetails, uint16 coverPeriod, bytes4 curr, address smaratCA ) public view returns (bytes32) { return keccak256( abi.encodePacked( coverDetails[0], curr, coverPeriod, smaratCA, coverDetails[1], coverDetails[2], coverDetails[3], coverDetails[4], address(this) ) ); } /** * @dev Verifies signature. * @param hash order hash * @param v argument from vrs hash. * @param r argument from vrs hash. * @param s argument from vrs hash. */ function isValidSignature(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public view returns (bool) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, hash)); address a = ecrecover(prefixedHash, v, r, s); return (a == qd.getAuthQuoteEngine()); } /** * @dev to get the status of recently holded coverID * @param userAdd is the user address in concern * @return the status of the concerned coverId */ function getRecentHoldedCoverIdStatus(address userAdd) public view returns (int) { uint holdedCoverLen = qd.getUserHoldedCoverLength(userAdd); if (holdedCoverLen == 0) { return - 1; } else { uint holdedCoverID = qd.getUserHoldedCoverByIndex(userAdd, holdedCoverLen.sub(1)); return int(qd.holdedCoverIDStatus(holdedCoverID)); } } /** * @dev to get the verdict of kyc process * @param status is the kyc status * @param _add is the address of member */ function kycVerdict(address _add, bool status) public checkPause noReentrancy { require(msg.sender == qd.kycAuthAddress()); _kycTrigger(status, _add); } /** * @dev transfering Ethers to newly created quotation contract. */ function transferAssetsToNewContract(address newAdd) public onlyInternal noReentrancy { uint amount = address(this).balance; IERC20 erc20; if (amount > 0) { // newAdd.transfer(amount); Quotation newQT = Quotation(newAdd); newQT.sendEther.value(amount)(); } uint currAssetLen = pd.getAllCurrenciesLen(); for (uint64 i = 1; i < currAssetLen; i++) { bytes4 currName = pd.getCurrenciesByIndex(i); address currAddr = pd.getCurrencyAssetAddress(currName); erc20 = IERC20(currAddr); // solhint-disable-line if (erc20.balanceOf(address(this)) > 0) { require(erc20.transfer(newAdd, erc20.balanceOf(address(this)))); } } } /** * @dev Creates cover of the quotation, changes the status of the quotation , * updates the total sum assured and locks the tokens of the cover against a quote. * @param from Quote member Ethereum address. */ function _makeCover(//solhint-disable-line address payable from, address scAddress, bytes4 coverCurr, uint[] memory coverDetails, uint16 coverPeriod ) internal { uint cid = qd.getCoverLength(); qd.addCover( coverPeriod, coverDetails[0], from, coverCurr, scAddress, coverDetails[1], coverDetails[2] ); uint coverNoteAmount = (coverDetails[2].mul(qd.tokensRetained())).div(100); tc.mint(from, coverNoteAmount); tf.lockCN(coverNoteAmount, coverPeriod, cid, from); qd.addInTotalSumAssured(coverCurr, coverDetails[0]); qd.addInTotalSumAssuredSC(scAddress, coverCurr, coverDetails[0]); tf.pushStakerRewards(scAddress, coverDetails[2]); } /** * @dev Makes a cover. * @param from address of funder. * @param scAddress Smart Contract Address */ function _verifyCoverDetails( address payable from, address scAddress, bytes4 coverCurr, uint[] memory coverDetails, uint16 coverPeriod, uint8 _v, bytes32 _r, bytes32 _s, bool isNXM ) internal { require(coverDetails[3] > now); require(!qd.timestampRepeated(coverDetails[4])); qd.setTimestampRepeated(coverDetails[4]); require(coverPeriod >= 30 && coverPeriod <= 365, "Quotation: Cover period out of bounds"); address asset = cr.getCurrencyAssetAddress(coverCurr); if (coverCurr != "ETH" && !isNXM) { pool.transferAssetFrom(asset, from, coverDetails[1]); } require(verifySign(coverDetails, coverPeriod, coverCurr, scAddress, _v, _r, _s)); _makeCover(from, scAddress, coverCurr, coverDetails, coverPeriod); } /** * @dev Updates the Sum Assured Amount of all the quotation. * @param _cid Cover id * @param _amount that will get subtracted Current Sum Assured * amount that comes under a quotation. */ function _removeSAFromCSA(uint _cid, uint _amount) internal checkPause { address _add; bytes4 coverCurr; (,, _add, coverCurr,,) = qd.getCoverDetailsByCoverID1(_cid); qd.subFromTotalSumAssured(coverCurr, _amount); qd.subFromTotalSumAssuredSC(_add, coverCurr, _amount); } /** * @dev to trigger the kyc process * @param status is the kyc status * @param _add is the address of member */ function _kycTrigger(bool status, address _add) internal { uint holdedCoverLen = qd.getUserHoldedCoverLength(_add).sub(1); uint holdedCoverID = qd.getUserHoldedCoverByIndex(_add, holdedCoverLen); address payable userAdd; address scAddress; bytes4 coverCurr; uint16 coverPeriod; uint[] memory coverDetails = new uint[](4); IERC20 erc20; (, userAdd, coverDetails) = qd.getHoldedCoverDetailsByID2(holdedCoverID); (, scAddress, coverCurr, coverPeriod) = qd.getHoldedCoverDetailsByID1(holdedCoverID); require(qd.refundEligible(userAdd)); qd.setRefundEligible(userAdd, false); require(qd.holdedCoverIDStatus(holdedCoverID) == uint(QuotationData.HCIDStatus.kycPending)); uint joinFee = td.joiningFee(); if (status) { mr.payJoiningFee.value(joinFee)(userAdd); if (coverDetails[3] > now) { qd.setHoldedCoverIDStatus(holdedCoverID, uint(QuotationData.HCIDStatus.kycPass)); if (coverCurr == "ETH") { (bool ok,) = address(pool).call.value(coverDetails[1])(""); require(ok, "Quotation: ether transfer to pool failed"); } else { erc20 = IERC20(pd.getCurrencyAssetAddress(coverCurr)); // solhint-disable-line require(erc20.transfer(address(pool), coverDetails[1])); } emit RefundEvent(userAdd, status, holdedCoverID, "KYC Passed"); _makeCover(userAdd, scAddress, coverCurr, coverDetails, coverPeriod); } else { qd.setHoldedCoverIDStatus(holdedCoverID, uint(QuotationData.HCIDStatus.kycPassNoCover)); if (coverCurr == "ETH") { userAdd.transfer(coverDetails[1]); } else { erc20 = IERC20(pd.getCurrencyAssetAddress(coverCurr)); // solhint-disable-line require(erc20.transfer(userAdd, coverDetails[1])); } emit RefundEvent(userAdd, status, holdedCoverID, "Cover Failed"); } } else { qd.setHoldedCoverIDStatus(holdedCoverID, uint(QuotationData.HCIDStatus.kycFailedOrRefunded)); uint totalRefund = joinFee; if (coverCurr == "ETH") { totalRefund = coverDetails[1].add(joinFee); } else { erc20 = IERC20(pd.getCurrencyAssetAddress(coverCurr)); // solhint-disable-line require(erc20.transfer(userAdd, coverDetails[1])); } userAdd.transfer(totalRefund); emit RefundEvent(userAdd, status, holdedCoverID, "KYC Failed"); } } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; contract Aggregator { function latestAnswer() public view returns (int); } contract PriceFeedOracle { using SafeMath for uint; mapping (address => address) public aggregators; address public daiAddress; address constant public ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; constructor (address[] memory assets, address[] memory _aggregators, address _daiAddress) public { require(assets.length == _aggregators.length, "PriceFeedOracle: assets and _aggregators need to have same length"); for (uint i = 0; i < assets.length; i++) { aggregators[assets[i]] = _aggregators[i]; } daiAddress = _daiAddress; } /** * @dev Returns the amount of ether in wei that are equivalent to 1 unit (10 ** decimals) of asset * @param asset quoted currency * @return price in ether */ function getAssetToEthRate(address asset) public view returns (uint) { if (asset == ETH) { return 1 ether; } address aggregatorAddress = aggregators[asset]; if (aggregatorAddress == address(0)) { revert("PriceFeedOracle: Oracle asset not found"); } int rate = Aggregator(aggregatorAddress).latestAnswer(); require(rate > 0, "PriceFeedOracle: Rate must be > 0"); return uint(rate); } /** * @dev Returns the amount of currency that is equivalent to ethIn amount of ether. * @param asset quoted Supported values: ["DAI", "ETH"] * @param ethIn amount of ether to be converted to the currency * @return price in ether */ function getAssetForEth(address asset, uint ethIn) external view returns (uint) { if (asset == daiAddress) { return ethIn.mul(1e18).div(getAssetToEthRate(daiAddress)); } if (asset == ETH) { return ethIn; } revert("PriceFeedOracle: Unknown asset"); } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "./external/OZIERC20.sol"; import "./external/OZSafeMath.sol"; contract NXMToken is OZIERC20 { using OZSafeMath for uint256; event WhiteListed(address indexed member); event BlackListed(address indexed member); mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowed; mapping(address => bool) public whiteListed; mapping(address => uint) public isLockedForMV; uint256 private _totalSupply; string public name = "NXM"; string public symbol = "NXM"; uint8 public decimals = 18; address public operator; modifier canTransfer(address _to) { require(whiteListed[_to]); _; } modifier onlyOperator() { if (operator != address(0)) require(msg.sender == operator); _; } constructor(address _founderAddress, uint _initialSupply) public { _mint(_founderAddress, _initialSupply); } /** * @dev Total number of tokens in existence */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev Gets the balance of the specified address. * @param owner The address to query the balance of. * @return An uint256 representing the amount owned by the passed address. */ function balanceOf(address owner) public view returns (uint256) { return _balances[owner]; } /** * @dev Function to check the amount of tokens that an owner allowed to a spender. * @param owner address The address which owns the funds. * @param spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ function allowance( address owner, address spender ) public view returns (uint256) { return _allowed[owner][spender]; } /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. * Beware that changing an allowance with this method brings the risk that someone may use both the old * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. */ function approve(address spender, uint256 value) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * approve should be called when allowed_[_spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * @param spender The address which will spend the funds. * @param addedValue The amount of tokens to increase the allowance by. */ function increaseAllowance( address spender, uint256 addedValue ) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = ( _allowed[msg.sender][spender].add(addedValue)); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * approve should be called when allowed_[_spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * @param spender The address which will spend the funds. * @param subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseAllowance( address spender, uint256 subtractedValue ) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = ( _allowed[msg.sender][spender].sub(subtractedValue)); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Adds a user to whitelist * @param _member address to add to whitelist */ function addToWhiteList(address _member) public onlyOperator returns (bool) { whiteListed[_member] = true; emit WhiteListed(_member); return true; } /** * @dev removes a user from whitelist * @param _member address to remove from whitelist */ function removeFromWhiteList(address _member) public onlyOperator returns (bool) { whiteListed[_member] = false; emit BlackListed(_member); return true; } /** * @dev change operator address * @param _newOperator address of new operator */ function changeOperator(address _newOperator) public onlyOperator returns (bool) { operator = _newOperator; return true; } /** * @dev burns an amount of the tokens of the message sender * account. * @param amount The amount that will be burnt. */ function burn(uint256 amount) public returns (bool) { _burn(msg.sender, amount); return true; } /** * @dev Burns a specific amount of tokens from the target address and decrements allowance * @param from address The address which you want to send tokens from * @param value uint256 The amount of token to be burned */ function burnFrom(address from, uint256 value) public returns (bool) { _burnFrom(from, value); return true; } /** * @dev function that mints an amount of the token and assigns it to * an account. * @param account The account that will receive the created tokens. * @param amount The amount that will be created. */ function mint(address account, uint256 amount) public onlyOperator { _mint(account, amount); } /** * @dev Transfer token for a specified address * @param to The address to transfer to. * @param value The amount to be transferred. */ function transfer(address to, uint256 value) public canTransfer(to) returns (bool) { require(isLockedForMV[msg.sender] < now); // if not voted under governance require(value <= _balances[msg.sender]); _transfer(to, value); return true; } /** * @dev Transfer tokens to the operator from the specified address * @param from The address to transfer from. * @param value The amount to be transferred. */ function operatorTransfer(address from, uint256 value) public onlyOperator returns (bool) { require(value <= _balances[from]); _transferFrom(from, operator, value); return true; } /** * @dev Transfer tokens from one address to another * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to * @param value uint256 the amount of tokens to be transferred */ function transferFrom( address from, address to, uint256 value ) public canTransfer(to) returns (bool) { require(isLockedForMV[from] < now); // if not voted under governance require(value <= _balances[from]); require(value <= _allowed[from][msg.sender]); _transferFrom(from, to, value); return true; } /** * @dev Lock the user's tokens * @param _of user's address. */ function lockForMemberVote(address _of, uint _days) public onlyOperator { if (_days.add(now) > isLockedForMV[_of]) isLockedForMV[_of] = _days.add(now); } /** * @dev Transfer token for a specified address * @param to The address to transfer to. * @param value The amount to be transferred. */ function _transfer(address to, uint256 value) internal { _balances[msg.sender] = _balances[msg.sender].sub(value); _balances[to] = _balances[to].add(value); emit Transfer(msg.sender, to, value); } /** * @dev Transfer tokens from one address to another * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to * @param value uint256 the amount of tokens to be transferred */ function _transferFrom( address from, address to, uint256 value ) internal { _balances[from] = _balances[from].sub(value); _balances[to] = _balances[to].add(value); _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value); emit Transfer(from, to, value); } /** * @dev Internal function that mints an amount of the token and assigns it to * an account. This encapsulates the modification of balances such that the * proper events are emitted. * @param account The account that will receive the created tokens. * @param amount The amount that will be created. */ function _mint(address account, uint256 amount) internal { require(account != address(0)); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Internal function that burns an amount of the token of a given * account. * @param account The account whose tokens will be burnt. * @param amount The amount that will be burnt. */ function _burn(address account, uint256 amount) internal { require(amount <= _balances[account]); _totalSupply = _totalSupply.sub(amount); _balances[account] = _balances[account].sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Internal function that burns an amount of the token of a given * account, deducting from the sender's allowance for said account. Uses the * internal burn function. * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burnFrom(address account, uint256 value) internal { require(value <= _allowed[account][msg.sender]); // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted, // this function needs to emit an event with the updated approval. _allowed[account][msg.sender] = _allowed[account][msg.sender].sub( value); _burn(account, value); } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../abstract/Iupgradable.sol"; import "../../interfaces/IPooledStaking.sol"; import "./NXMToken.sol"; import "./external/IERC1132.sol"; contract TokenController is IERC1132, Iupgradable { using SafeMath for uint256; event Burned(address indexed member, bytes32 lockedUnder, uint256 amount); NXMToken public token; IPooledStaking public pooledStaking; uint public minCALockTime = uint(30).mul(1 days); bytes32 private constant CLA = bytes32("CLA"); /** * @dev Just for interface */ function changeDependentContractAddress() public { token = NXMToken(ms.tokenAddress()); pooledStaking = IPooledStaking(ms.getLatestAddress("PS")); } /** * @dev to change the operator address * @param _newOperator is the new address of operator */ function changeOperator(address _newOperator) public onlyInternal { token.changeOperator(_newOperator); } /** * @dev Proxies token transfer through this contract to allow staking when members are locked for voting * @param _from Source address * @param _to Destination address * @param _value Amount to transfer */ function operatorTransfer(address _from, address _to, uint _value) onlyInternal external returns (bool) { require(msg.sender == address(pooledStaking), "Call is only allowed from PooledStaking address"); require(token.operatorTransfer(_from, _value), "Operator transfer failed"); require(token.transfer(_to, _value), "Internal transfer failed"); return true; } /** * @dev Locks a specified amount of tokens, * for CLA reason and for a specified time * @param _reason The reason to lock tokens, currently restricted to CLA * @param _amount Number of tokens to be locked * @param _time Lock time in seconds */ function lock(bytes32 _reason, uint256 _amount, uint256 _time) public checkPause returns (bool) { require(_reason == CLA, "Restricted to reason CLA"); require(minCALockTime <= _time, "Should lock for minimum time"); // If tokens are already locked, then functions extendLock or // increaseLockAmount should be used to make any changes _lock(msg.sender, _reason, _amount, _time); return true; } /** * @dev Locks a specified amount of tokens against an address, * for a specified reason and time * @param _reason The reason to lock tokens * @param _amount Number of tokens to be locked * @param _time Lock time in seconds * @param _of address whose tokens are to be locked */ function lockOf(address _of, bytes32 _reason, uint256 _amount, uint256 _time) public onlyInternal returns (bool) { // If tokens are already locked, then functions extendLock or // increaseLockAmount should be used to make any changes _lock(_of, _reason, _amount, _time); return true; } /** * @dev Extends lock for reason CLA for a specified time * @param _reason The reason to lock tokens, currently restricted to CLA * @param _time Lock extension time in seconds */ function extendLock(bytes32 _reason, uint256 _time) public checkPause returns (bool) { require(_reason == CLA, "Restricted to reason CLA"); _extendLock(msg.sender, _reason, _time); return true; } /** * @dev Extends lock for a specified reason and time * @param _reason The reason to lock tokens * @param _time Lock extension time in seconds */ function extendLockOf(address _of, bytes32 _reason, uint256 _time) public onlyInternal returns (bool) { _extendLock(_of, _reason, _time); return true; } /** * @dev Increase number of tokens locked for a CLA reason * @param _reason The reason to lock tokens, currently restricted to CLA * @param _amount Number of tokens to be increased */ function increaseLockAmount(bytes32 _reason, uint256 _amount) public checkPause returns (bool) { require(_reason == CLA, "Restricted to reason CLA"); require(_tokensLocked(msg.sender, _reason) > 0); token.operatorTransfer(msg.sender, _amount); locked[msg.sender][_reason].amount = locked[msg.sender][_reason].amount.add(_amount); emit Locked(msg.sender, _reason, _amount, locked[msg.sender][_reason].validity); return true; } /** * @dev burns tokens of an address * @param _of is the address to burn tokens of * @param amount is the amount to burn * @return the boolean status of the burning process */ function burnFrom(address _of, uint amount) public onlyInternal returns (bool) { return token.burnFrom(_of, amount); } /** * @dev Burns locked tokens of a user * @param _of address whose tokens are to be burned * @param _reason lock reason for which tokens are to be burned * @param _amount amount of tokens to burn */ function burnLockedTokens(address _of, bytes32 _reason, uint256 _amount) public onlyInternal { _burnLockedTokens(_of, _reason, _amount); } /** * @dev reduce lock duration for a specified reason and time * @param _of The address whose tokens are locked * @param _reason The reason to lock tokens * @param _time Lock reduction time in seconds */ function reduceLock(address _of, bytes32 _reason, uint256 _time) public onlyInternal { _reduceLock(_of, _reason, _time); } /** * @dev Released locked tokens of an address locked for a specific reason * @param _of address whose tokens are to be released from lock * @param _reason reason of the lock * @param _amount amount of tokens to release */ function releaseLockedTokens(address _of, bytes32 _reason, uint256 _amount) public onlyInternal { _releaseLockedTokens(_of, _reason, _amount); } /** * @dev Adds an address to whitelist maintained in the contract * @param _member address to add to whitelist */ function addToWhitelist(address _member) public onlyInternal { token.addToWhiteList(_member); } /** * @dev Removes an address from the whitelist in the token * @param _member address to remove */ function removeFromWhitelist(address _member) public onlyInternal { token.removeFromWhiteList(_member); } /** * @dev Mints new token for an address * @param _member address to reward the minted tokens * @param _amount number of tokens to mint */ function mint(address _member, uint _amount) public onlyInternal { token.mint(_member, _amount); } /** * @dev Lock the user's tokens * @param _of user's address. */ function lockForMemberVote(address _of, uint _days) public onlyInternal { token.lockForMemberVote(_of, _days); } /** * @dev Unlocks the unlockable tokens against CLA of a specified address * @param _of Address of user, claiming back unlockable tokens against CLA */ function unlock(address _of) public checkPause returns (uint256 unlockableTokens) { unlockableTokens = _tokensUnlockable(_of, CLA); if (unlockableTokens > 0) { locked[_of][CLA].claimed = true; emit Unlocked(_of, CLA, unlockableTokens); require(token.transfer(_of, unlockableTokens)); } } /** * @dev Updates Uint Parameters of a code * @param code whose details we want to update * @param val value to set */ function updateUintParameters(bytes8 code, uint val) public { require(ms.checkIsAuthToGoverned(msg.sender)); if (code == "MNCLT") { minCALockTime = val.mul(1 days); } else { revert("Invalid param code"); } } /** * @dev Gets the validity of locked tokens of a specified address * @param _of The address to query the validity * @param reason reason for which tokens were locked */ function getLockedTokensValidity(address _of, bytes32 reason) public view returns (uint256 validity) { validity = locked[_of][reason].validity; } /** * @dev Gets the unlockable tokens of a specified address * @param _of The address to query the the unlockable token count of */ function getUnlockableTokens(address _of) public view returns (uint256 unlockableTokens) { for (uint256 i = 0; i < lockReason[_of].length; i++) { unlockableTokens = unlockableTokens.add(_tokensUnlockable(_of, lockReason[_of][i])); } } /** * @dev Returns tokens locked for a specified address for a * specified reason * * @param _of The address whose tokens are locked * @param _reason The reason to query the lock tokens for */ function tokensLocked(address _of, bytes32 _reason) public view returns (uint256 amount) { return _tokensLocked(_of, _reason); } /** * @dev Returns unlockable tokens for a specified address for a specified reason * @param _of The address to query the the unlockable token count of * @param _reason The reason to query the unlockable tokens for */ function tokensUnlockable(address _of, bytes32 _reason) public view returns (uint256 amount) { return _tokensUnlockable(_of, _reason); } function totalSupply() public view returns (uint256) { return token.totalSupply(); } /** * @dev Returns tokens locked for a specified address for a * specified reason at a specific time * * @param _of The address whose tokens are locked * @param _reason The reason to query the lock tokens for * @param _time The timestamp to query the lock tokens for */ function tokensLockedAtTime(address _of, bytes32 _reason, uint256 _time) public view returns (uint256 amount) { return _tokensLockedAtTime(_of, _reason, _time); } /** * @dev Returns the total amount of tokens held by an address: * transferable + locked + staked for pooled staking - pending burns. * Used by Claims and Governance in member voting to calculate the user's vote weight. * * @param _of The address to query the total balance of * @param _of The address to query the total balance of */ function totalBalanceOf(address _of) public view returns (uint256 amount) { amount = token.balanceOf(_of); for (uint256 i = 0; i < lockReason[_of].length; i++) { amount = amount.add(_tokensLocked(_of, lockReason[_of][i])); } uint stakerReward = pooledStaking.stakerReward(_of); uint stakerDeposit = pooledStaking.stakerDeposit(_of); amount = amount.add(stakerDeposit).add(stakerReward); } /** * @dev Returns the total locked tokens at time * Returns the total amount of locked and staked tokens at a given time. Used by MemberRoles to check eligibility * for withdraw / switch membership. Includes tokens locked for Claim Assessment and staked for Risk Assessment. * Does not take into account pending burns. * * @param _of member whose locked tokens are to be calculate * @param _time timestamp when the tokens should be locked */ function totalLockedBalance(address _of, uint256 _time) public view returns (uint256 amount) { for (uint256 i = 0; i < lockReason[_of].length; i++) { amount = amount.add(_tokensLockedAtTime(_of, lockReason[_of][i], _time)); } amount = amount.add(pooledStaking.stakerDeposit(_of)); } /** * @dev Locks a specified amount of tokens against an address, * for a specified reason and time * @param _of address whose tokens are to be locked * @param _reason The reason to lock tokens * @param _amount Number of tokens to be locked * @param _time Lock time in seconds */ function _lock(address _of, bytes32 _reason, uint256 _amount, uint256 _time) internal { require(_tokensLocked(_of, _reason) == 0); require(_amount != 0); if (locked[_of][_reason].amount == 0) { lockReason[_of].push(_reason); } require(token.operatorTransfer(_of, _amount)); uint256 validUntil = now.add(_time); // solhint-disable-line locked[_of][_reason] = LockToken(_amount, validUntil, false); emit Locked(_of, _reason, _amount, validUntil); } /** * @dev Returns tokens locked for a specified address for a * specified reason * * @param _of The address whose tokens are locked * @param _reason The reason to query the lock tokens for */ function _tokensLocked(address _of, bytes32 _reason) internal view returns (uint256 amount) { if (!locked[_of][_reason].claimed) { amount = locked[_of][_reason].amount; } } /** * @dev Returns tokens locked for a specified address for a * specified reason at a specific time * * @param _of The address whose tokens are locked * @param _reason The reason to query the lock tokens for * @param _time The timestamp to query the lock tokens for */ function _tokensLockedAtTime(address _of, bytes32 _reason, uint256 _time) internal view returns (uint256 amount) { if (locked[_of][_reason].validity > _time) { amount = locked[_of][_reason].amount; } } /** * @dev Extends lock for a specified reason and time * @param _of The address whose tokens are locked * @param _reason The reason to lock tokens * @param _time Lock extension time in seconds */ function _extendLock(address _of, bytes32 _reason, uint256 _time) internal { require(_tokensLocked(_of, _reason) > 0); emit Unlocked(_of, _reason, locked[_of][_reason].amount); locked[_of][_reason].validity = locked[_of][_reason].validity.add(_time); emit Locked(_of, _reason, locked[_of][_reason].amount, locked[_of][_reason].validity); } /** * @dev reduce lock duration for a specified reason and time * @param _of The address whose tokens are locked * @param _reason The reason to lock tokens * @param _time Lock reduction time in seconds */ function _reduceLock(address _of, bytes32 _reason, uint256 _time) internal { require(_tokensLocked(_of, _reason) > 0); emit Unlocked(_of, _reason, locked[_of][_reason].amount); locked[_of][_reason].validity = locked[_of][_reason].validity.sub(_time); emit Locked(_of, _reason, locked[_of][_reason].amount, locked[_of][_reason].validity); } /** * @dev Returns unlockable tokens for a specified address for a specified reason * @param _of The address to query the the unlockable token count of * @param _reason The reason to query the unlockable tokens for */ function _tokensUnlockable(address _of, bytes32 _reason) internal view returns (uint256 amount) { if (locked[_of][_reason].validity <= now && !locked[_of][_reason].claimed) { amount = locked[_of][_reason].amount; } } /** * @dev Burns locked tokens of a user * @param _of address whose tokens are to be burned * @param _reason lock reason for which tokens are to be burned * @param _amount amount of tokens to burn */ function _burnLockedTokens(address _of, bytes32 _reason, uint256 _amount) internal { uint256 amount = _tokensLocked(_of, _reason); require(amount >= _amount); if (amount == _amount) { locked[_of][_reason].claimed = true; } locked[_of][_reason].amount = locked[_of][_reason].amount.sub(_amount); if (locked[_of][_reason].amount == 0) { _removeReason(_of, _reason); } token.burn(_amount); emit Burned(_of, _reason, _amount); } /** * @dev Released locked tokens of an address locked for a specific reason * @param _of address whose tokens are to be released from lock * @param _reason reason of the lock * @param _amount amount of tokens to release */ function _releaseLockedTokens(address _of, bytes32 _reason, uint256 _amount) internal { uint256 amount = _tokensLocked(_of, _reason); require(amount >= _amount); if (amount == _amount) { locked[_of][_reason].claimed = true; } locked[_of][_reason].amount = locked[_of][_reason].amount.sub(_amount); if (locked[_of][_reason].amount == 0) { _removeReason(_of, _reason); } require(token.transfer(_of, _amount)); emit Unlocked(_of, _reason, _amount); } function _removeReason(address _of, bytes32 _reason) internal { uint len = lockReason[_of].length; for (uint i = 0; i < len; i++) { if (lockReason[_of][i] == _reason) { lockReason[_of][i] = lockReason[_of][len.sub(1)]; lockReason[_of].pop(); break; } } } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../capital/Pool.sol"; import "../cover/QuotationData.sol"; import "../governance/MemberRoles.sol"; import "../governance/ProposalCategory.sol"; import "../oracles/PriceFeedOracle.sol"; import "../token/NXMToken.sol"; import "../token/TokenData.sol"; import "./PoolData.sol"; contract MCR is Iupgradable { using SafeMath for uint; Pool public pool; PoolData public pd; NXMToken public tk; QuotationData public qd; MemberRoles public mr; TokenData public td; ProposalCategory public proposalCategory; uint private constant minCapFactor = uint(10) ** 21; uint public variableMincap; uint public dynamicMincapThresholdx100 = 13000; uint public dynamicMincapIncrementx100 = 100; event MCREvent( uint indexed date, uint blockNumber, bytes4[] allCurr, uint[] allCurrRates, uint mcrEtherx100, uint mcrPercx100, uint vFull ); constructor (address masterAddress) public { changeMasterAddress(masterAddress); // we'll pass the zero address on the first deploy // due to missing previous MCR contract if (masterAddress == address(0)) { return; } address mcrAddress = ms.getLatestAddress("MC"); MCR previousMCR = MCR(mcrAddress); // fetch MCR parameters from previous contract variableMincap = previousMCR.variableMincap(); dynamicMincapThresholdx100 = previousMCR.dynamicMincapThresholdx100(); dynamicMincapIncrementx100 = previousMCR.dynamicMincapIncrementx100(); } /** * @dev Adds new MCR data. * @param mcrP Minimum Capital Requirement in percentage. * @param vF Pool fund value in Ether used in the last full daily calculation of the Capital model. * @param onlyDate Date(yyyymmdd) at which MCR details are getting added. */ function addMCRData( uint mcrP, uint mcrE, uint vF, bytes4[] calldata curr, uint[] calldata _threeDayAvg, uint64 onlyDate ) external checkPause { require(proposalCategory.constructorCheck()); require(pd.isnotarise(msg.sender)); if (mr.launched() && pd.capReached() != 1) { if (mcrP >= 10000) pd.setCapReached(1); } uint len = pd.getMCRDataLength(); _addMCRData(len, onlyDate, curr, mcrE, mcrP, vF, _threeDayAvg); } // proxying this call through mcr contract to get rid of pd from pool function getLastMCREther() external view returns (uint) { return pd.getLastMCREther(); } /** * @dev Iupgradable Interface to update dependent contract address */ function changeDependentContractAddress() public { qd = QuotationData(ms.getLatestAddress("QD")); pool = Pool(ms.getLatestAddress("P1")); pd = PoolData(ms.getLatestAddress("PD")); tk = NXMToken(ms.tokenAddress()); mr = MemberRoles(ms.getLatestAddress("MR")); td = TokenData(ms.getLatestAddress("TD")); proposalCategory = ProposalCategory(ms.getLatestAddress("PC")); } /** * @dev Gets total sum assured (in ETH). * @return amount of sum assured */ function getAllSumAssurance() public view returns (uint) { PriceFeedOracle priceFeed = pool.priceFeedOracle(); address daiAddress = priceFeed.daiAddress(); uint ethAmount = qd.getTotalSumAssured("ETH").mul(1e18); uint daiAmount = qd.getTotalSumAssured("DAI").mul(1e18); uint daiRate = priceFeed.getAssetToEthRate(daiAddress); uint daiAmountInEth = daiAmount.mul(daiRate).div(1e18); return ethAmount.add(daiAmountInEth); } function getThresholdValues(uint vtp, uint vF, uint totalSA, uint minCap) public view returns (uint lowerThreshold, uint upperThreshold) { minCap = (minCap.mul(minCapFactor)).add(variableMincap); uint lower = 0; if (vtp >= vF) { // Max Threshold = [MAX(Vtp, Vfull) x 120] / mcrMinCap upperThreshold = vtp.mul(120).mul(100).div((minCap)); } else { upperThreshold = vF.mul(120).mul(100).div((minCap)); } if (vtp > 0) { lower = totalSA.mul(pd.shockParameter()).div(100); if (lower < minCap.mul(11).div(10)) lower = minCap.mul(11).div(10); } if (lower > 0) { // Min Threshold = [Vtp / MAX(TotalActiveSA x ShockParameter, mcrMinCap x 1.1)] x 100 lowerThreshold = vtp.mul(100).mul(100).div(lower); } } /** * @dev Gets Uint Parameters of a code * @param code whose details we want * @return string value of the code * @return associated amount (time or perc or value) to the code */ function getUintParameters(bytes8 code) external view returns (bytes8 codeVal, uint val) { codeVal = code; if (code == "DMCT") { val = dynamicMincapThresholdx100; } else if (code == "DMCI") { val = dynamicMincapIncrementx100; } } /** * @dev Updates Uint Parameters of a code * @param code whose details we want to update * @param val value to set */ function updateUintParameters(bytes8 code, uint val) public { require(ms.checkIsAuthToGoverned(msg.sender)); if (code == "DMCT") { dynamicMincapThresholdx100 = val; } else if (code == "DMCI") { dynamicMincapIncrementx100 = val; } else { revert("Invalid param code"); } } /** * @dev Adds MCR Data. Checks if MCR is within valid * thresholds in order to rule out any incorrect calculations */ function _addMCRData( uint len, uint64 newMCRDate, bytes4[] memory curr, uint mcrE, uint mcrP, uint vF, uint[] memory _threeDayAvg ) internal { uint lowerThreshold = 0; uint upperThreshold = 0; if (len > 1) { uint vtp = pool.getPoolValueInEth(); (lowerThreshold, upperThreshold) = getThresholdValues(vtp, vF, getAllSumAssurance(), pd.minCap()); } if (mcrP > dynamicMincapThresholdx100) { variableMincap = (variableMincap.mul(dynamicMincapIncrementx100.add(10000)).add(minCapFactor.mul(pd.minCap().mul(dynamicMincapIncrementx100)))).div(10000); } // Explanation for above formula :- // actual formula -> variableMinCap = variableMinCap + (variableMinCap+minCap)*dynamicMincapIncrement/100 // Implemented formula is simplified form of actual formula. // Let consider above formula as b = b + (a+b)*c/100 // here, dynamicMincapIncrement is in x100 format. // so b+(a+b)*cx100/10000 can be written as => (10000.b + b.cx100 + a.cx100)/10000. // It can further simplify to (b.(10000+cx100) + a.cx100)/10000. if (len == 1 || (mcrP) >= lowerThreshold && (mcrP) <= upperThreshold) { pd.pushMCRData(mcrP, mcrE, vF, newMCRDate); for (uint i = 0; i < curr.length; i++) { pd.updateCAAvgRate(curr[i], _threeDayAvg[i]); } emit MCREvent(newMCRDate, block.number, curr, _threeDayAvg, mcrE, mcrP, vF); return; } revert("MCR: Failed"); } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "../../external/uniswap/IUniswapV2Router02.sol"; import "../oracles/TwapOracle.sol"; library SwapAgent { using SafeMath for uint; struct AssetData { uint112 minAmount; uint112 maxAmount; uint32 lastSwapTime; // 18 decimals of precision. 0.01% -> 0.0001 -> 1e14 uint maxSlippageRatio; } IUniswapV2Router02 constant public router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); uint constant public MAX_LIQUIDITY_RATIO = 3 * 1e15; function getSwapQuote( uint tokenAmountIn, IERC20 fromToken, IERC20 toToken ) public view returns (uint tokenAmountOut) { address[] memory path = new address[](2); path[0] = address(fromToken); path[1] = address(toToken); uint[] memory amountsOut = router.getAmountsOut(tokenAmountIn, path); return amountsOut[1]; } function swapETHForAsset( address _oracle, AssetData storage assetData, address toTokenAddress, uint amountIn, uint amountOutMin, uint minLeftETH ) external returns (uint) { uint balanceBefore = IERC20(toTokenAddress).balanceOf(address(this)); address WETH = router.WETH(); { // scope for swap frequency check uint timeSinceLastTrade = block.timestamp.sub(uint(assetData.lastSwapTime)); require(timeSinceLastTrade > TwapOracle(_oracle).periodSize(), "SwapAgent: too fast"); } { // scope for liquidity check address pairAddress = TwapOracle(_oracle).pairFor(WETH, toTokenAddress); IUniswapV2Pair pair = IUniswapV2Pair(pairAddress); (uint112 reserve0, uint112 reserve1, /* time */) = pair.getReserves(); uint ethReserve = WETH < toTokenAddress ? reserve0 : reserve1; uint maxTradable = ethReserve.mul(MAX_LIQUIDITY_RATIO).div(1e18); require(amountIn <= maxTradable, "SwapAgent: exceeds max tradable amount"); } { // scope for ether checks uint ethBalanceBefore = address(this).balance; uint ethBalanceAfter = ethBalanceBefore.sub(amountIn); require(ethBalanceAfter >= minLeftETH, "SwapAgent: insufficient ether left"); } { // scope for token checks uint avgAmountOut = TwapOracle(_oracle).consult(WETH, amountIn, toTokenAddress); uint maxSlippageAmount = avgAmountOut.mul(assetData.maxSlippageRatio).div(1e18); uint minOutOnMaxSlippage = avgAmountOut.sub(maxSlippageAmount); // gas optimisation: reads both values using a single SLOAD (uint minAssetAmount, uint maxAssetAmount) = (assetData.minAmount, assetData.maxAmount); require(amountOutMin >= minOutOnMaxSlippage, "SwapAgent: amountOutMin < minOutOnMaxSlippage"); require(balanceBefore < minAssetAmount, "SwapAgent: balanceBefore >= min"); require(balanceBefore.add(amountOutMin) <= maxAssetAmount, "SwapAgent: balanceAfter > max"); } address[] memory path = new address[](2); path[0] = WETH; path[1] = toTokenAddress; router.swapExactETHForTokens.value(amountIn)(amountOutMin, path, address(this), block.timestamp); assetData.lastSwapTime = uint32(block.timestamp); uint balanceAfter = IERC20(toTokenAddress).balanceOf(address(this)); uint amountOut = balanceAfter.sub(balanceBefore); return amountOut; } function swapAssetForETH( address _oracle, AssetData storage assetData, address fromTokenAddress, uint amountIn, uint amountOutMin ) external returns (uint) { uint tokenBalanceBefore = IERC20(fromTokenAddress).balanceOf(address(this)); uint balanceBefore = address(this).balance; address WETH = router.WETH(); { // scope for swap frequency check uint timeSinceLastTrade = block.timestamp.sub(uint(assetData.lastSwapTime)); require(timeSinceLastTrade > TwapOracle(_oracle).periodSize(), "SwapAgent: too fast"); } { // scope for liquidity check address pairAddress = TwapOracle(_oracle).pairFor(fromTokenAddress, WETH); IUniswapV2Pair pair = IUniswapV2Pair(pairAddress); (uint112 reserve0, uint112 reserve1, /* time */) = pair.getReserves(); uint tokenReserve = fromTokenAddress < WETH ? reserve0 : reserve1; uint maxTradable = tokenReserve.mul(MAX_LIQUIDITY_RATIO).div(1e18); require(amountIn <= maxTradable, "SwapAgent: exceeds max tradable amount"); } { // scope for token checks uint avgAmountOut = TwapOracle(_oracle).consult(fromTokenAddress, amountIn, WETH); uint maxSlippageAmount = avgAmountOut.mul(assetData.maxSlippageRatio).div(1e18); uint minOutOnMaxSlippage = avgAmountOut.sub(maxSlippageAmount); // gas optimisation: reads both values using a single SLOAD (uint minAssetAmount, uint maxAssetAmount) = (assetData.minAmount, assetData.maxAmount); require(amountOutMin >= minOutOnMaxSlippage, "SwapAgent: amountOutMin < minOutOnMaxSlippage"); require(tokenBalanceBefore > maxAssetAmount, "SwapAgent: tokenBalanceBefore <= max"); require(tokenBalanceBefore.sub(amountIn) >= minAssetAmount, "SwapAgent: tokenBalanceAfter < min"); } address[] memory path = new address[](2); path[0] = fromTokenAddress; path[1] = router.WETH(); IERC20(fromTokenAddress).approve(address(router), amountIn); router.swapExactTokensForETH(amountIn, amountOutMin, path, address(this), block.timestamp); assetData.lastSwapTime = uint32(block.timestamp); uint balanceAfter = address(this).balance; uint amountOut = balanceAfter.sub(balanceBefore); return amountOut; } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; contract INXMMaster { address public tokenAddress; address public owner; uint public pauseTime; function delegateCallBack(bytes32 myid) external; function masterInitialized() public view returns (bool); function isInternal(address _add) public view returns (bool); function isPause() public view returns (bool check); function isOwner(address _add) public view returns (bool); function isMember(address _add) public view returns (bool); function checkIsAuthToGoverned(address _add) public view returns (bool); function updatePauseTime(uint _time) public; function dAppLocker() public view returns (address _add); function dAppToken() public view returns (address _add); function getLatestAddress(bytes2 _contractName) public view returns (address payable contractAddress); }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../abstract/Iupgradable.sol"; contract DSValue { function peek() public view returns (bytes32, bool); function read() public view returns (bytes32); } contract PoolData is Iupgradable { using SafeMath for uint; struct ApiId { bytes4 typeOf; bytes4 currency; uint id; uint64 dateAdd; uint64 dateUpd; } struct CurrencyAssets { address currAddress; uint baseMin; uint varMin; } struct InvestmentAssets { address currAddress; bool status; uint64 minHoldingPercX100; uint64 maxHoldingPercX100; uint8 decimals; } struct IARankDetails { bytes4 maxIACurr; uint64 maxRate; bytes4 minIACurr; uint64 minRate; } struct McrData { uint mcrPercx100; uint mcrEther; uint vFull; //Pool funds uint64 date; } IARankDetails[] internal allIARankDetails; McrData[] public allMCRData; bytes4[] internal allInvestmentCurrencies; bytes4[] internal allCurrencies; bytes32[] public allAPIcall; mapping(bytes32 => ApiId) public allAPIid; mapping(uint64 => uint) internal datewiseId; mapping(bytes16 => uint) internal currencyLastIndex; mapping(bytes4 => CurrencyAssets) internal allCurrencyAssets; mapping(bytes4 => InvestmentAssets) internal allInvestmentAssets; mapping(bytes4 => uint) internal caAvgRate; mapping(bytes4 => uint) internal iaAvgRate; address public notariseMCR; address public daiFeedAddress; uint private constant DECIMAL1E18 = uint(10) ** 18; uint public uniswapDeadline; uint public liquidityTradeCallbackTime; uint public lastLiquidityTradeTrigger; uint64 internal lastDate; uint public variationPercX100; uint public iaRatesTime; uint public minCap; uint public mcrTime; uint public a; uint public shockParameter; uint public c; uint public mcrFailTime; uint public ethVolumeLimit; uint public capReached; uint public capacityLimit; constructor(address _notariseAdd, address _daiFeedAdd, address _daiAdd) public { notariseMCR = _notariseAdd; daiFeedAddress = _daiFeedAdd; c = 5800000; a = 1028; mcrTime = 24 hours; mcrFailTime = 6 hours; allMCRData.push(McrData(0, 0, 0, 0)); minCap = 12000 * DECIMAL1E18; shockParameter = 50; variationPercX100 = 100; // 1% iaRatesTime = 24 hours; // 24 hours in seconds uniswapDeadline = 20 minutes; liquidityTradeCallbackTime = 4 hours; ethVolumeLimit = 4; capacityLimit = 10; allCurrencies.push("ETH"); allCurrencyAssets["ETH"] = CurrencyAssets(address(0), 1000 * DECIMAL1E18, 0); allCurrencies.push("DAI"); allCurrencyAssets["DAI"] = CurrencyAssets(_daiAdd, 50000 * DECIMAL1E18, 0); allInvestmentCurrencies.push("ETH"); allInvestmentAssets["ETH"] = InvestmentAssets(address(0), true, 2500, 10000, 18); allInvestmentCurrencies.push("DAI"); allInvestmentAssets["DAI"] = InvestmentAssets(_daiAdd, true, 250, 1500, 18); } /** * @dev to set the maximum cap allowed * @param val is the new value */ function setCapReached(uint val) external onlyInternal { capReached = val; } /// @dev Updates the 3 day average rate of a IA currency. /// To be replaced by MakerDao's on chain rates /// @param curr IA Currency Name. /// @param rate Average exchange rate X 100 (of last 3 days). function updateIAAvgRate(bytes4 curr, uint rate) external onlyInternal { iaAvgRate[curr] = rate; } /// @dev Updates the 3 day average rate of a CA currency. /// To be replaced by MakerDao's on chain rates /// @param curr Currency Name. /// @param rate Average exchange rate X 100 (of last 3 days). function updateCAAvgRate(bytes4 curr, uint rate) external onlyInternal { caAvgRate[curr] = rate; } /// @dev Adds details of (Minimum Capital Requirement)MCR. /// @param mcrp Minimum Capital Requirement percentage (MCR% * 100 ,Ex:for 54.56% ,given 5456) /// @param vf Pool fund value in Ether used in the last full daily calculation from the Capital model. function pushMCRData(uint mcrp, uint mcre, uint vf, uint64 time) external onlyInternal { allMCRData.push(McrData(mcrp, mcre, vf, time)); } /** * @dev Updates the Timestamp at which result of oracalize call is received. */ function updateDateUpdOfAPI(bytes32 myid) external onlyInternal { allAPIid[myid].dateUpd = uint64(now); } /** * @dev Saves the details of the Oraclize API. * @param myid Id return by the oraclize query. * @param _typeof type of the query for which oraclize call is made. * @param id ID of the proposal,quote,cover etc. for which oraclize call is made */ function saveApiDetails(bytes32 myid, bytes4 _typeof, uint id) external onlyInternal { allAPIid[myid] = ApiId(_typeof, "", id, uint64(now), uint64(now)); } /** * @dev Stores the id return by the oraclize query. * Maintains record of all the Ids return by oraclize query. * @param myid Id return by the oraclize query. */ function addInAllApiCall(bytes32 myid) external onlyInternal { allAPIcall.push(myid); } /** * @dev Saves investment asset rank details. * @param maxIACurr Maximum ranked investment asset currency. * @param maxRate Maximum ranked investment asset rate. * @param minIACurr Minimum ranked investment asset currency. * @param minRate Minimum ranked investment asset rate. * @param date in yyyymmdd. */ function saveIARankDetails( bytes4 maxIACurr, uint64 maxRate, bytes4 minIACurr, uint64 minRate, uint64 date ) external onlyInternal { allIARankDetails.push(IARankDetails(maxIACurr, maxRate, minIACurr, minRate)); datewiseId[date] = allIARankDetails.length.sub(1); } /** * @dev to get the time for the laste liquidity trade trigger */ function setLastLiquidityTradeTrigger() external onlyInternal { lastLiquidityTradeTrigger = now; } /** * @dev Updates Last Date. */ function updatelastDate(uint64 newDate) external onlyInternal { lastDate = newDate; } /** * @dev Adds currency asset currency. * @param curr currency of the asset * @param currAddress address of the currency * @param baseMin base minimum in 10^18. */ function addCurrencyAssetCurrency( bytes4 curr, address currAddress, uint baseMin ) external { require(ms.checkIsAuthToGoverned(msg.sender)); allCurrencies.push(curr); allCurrencyAssets[curr] = CurrencyAssets(currAddress, baseMin, 0); } /** * @dev Adds investment asset. */ function addInvestmentAssetCurrency( bytes4 curr, address currAddress, bool status, uint64 minHoldingPercX100, uint64 maxHoldingPercX100, uint8 decimals ) external { require(ms.checkIsAuthToGoverned(msg.sender)); allInvestmentCurrencies.push(curr); allInvestmentAssets[curr] = InvestmentAssets(currAddress, status, minHoldingPercX100, maxHoldingPercX100, decimals); } /** * @dev Changes base minimum of a given currency asset. */ function changeCurrencyAssetBaseMin(bytes4 curr, uint baseMin) external { require(ms.checkIsAuthToGoverned(msg.sender)); allCurrencyAssets[curr].baseMin = baseMin; } /** * @dev changes variable minimum of a given currency asset. */ function changeCurrencyAssetVarMin(bytes4 curr, uint varMin) external onlyInternal { allCurrencyAssets[curr].varMin = varMin; } /** * @dev Changes the investment asset status. */ function changeInvestmentAssetStatus(bytes4 curr, bool status) external { require(ms.checkIsAuthToGoverned(msg.sender)); allInvestmentAssets[curr].status = status; } /** * @dev Changes the investment asset Holding percentage of a given currency. */ function changeInvestmentAssetHoldingPerc( bytes4 curr, uint64 minPercX100, uint64 maxPercX100 ) external { require(ms.checkIsAuthToGoverned(msg.sender)); allInvestmentAssets[curr].minHoldingPercX100 = minPercX100; allInvestmentAssets[curr].maxHoldingPercX100 = maxPercX100; } /** * @dev Gets Currency asset token address. */ function changeCurrencyAssetAddress(bytes4 curr, address currAdd) external { require(ms.checkIsAuthToGoverned(msg.sender)); allCurrencyAssets[curr].currAddress = currAdd; } /** * @dev Changes Investment asset token address. */ function changeInvestmentAssetAddressAndDecimal( bytes4 curr, address currAdd, uint8 newDecimal ) external { require(ms.checkIsAuthToGoverned(msg.sender)); allInvestmentAssets[curr].currAddress = currAdd; allInvestmentAssets[curr].decimals = newDecimal; } /// @dev Changes address allowed to post MCR. function changeNotariseAddress(address _add) external onlyInternal { notariseMCR = _add; } /// @dev updates daiFeedAddress address. /// @param _add address of DAI feed. function changeDAIfeedAddress(address _add) external onlyInternal { daiFeedAddress = _add; } /** * @dev Gets Uint Parameters of a code * @param code whose details we want * @return string value of the code * @return associated amount (time or perc or value) to the code */ function getUintParameters(bytes8 code) external view returns (bytes8 codeVal, uint val) { codeVal = code; if (code == "MCRTIM") { val = mcrTime / (1 hours); } else if (code == "MCRFTIM") { val = mcrFailTime / (1 hours); } else if (code == "MCRMIN") { val = minCap; } else if (code == "MCRSHOCK") { val = shockParameter; } else if (code == "MCRCAPL") { val = capacityLimit; } else if (code == "IMZ") { val = variationPercX100; } else if (code == "IMRATET") { val = iaRatesTime / (1 hours); } else if (code == "IMUNIDL") { val = uniswapDeadline / (1 minutes); } else if (code == "IMLIQT") { val = liquidityTradeCallbackTime / (1 hours); } else if (code == "IMETHVL") { val = ethVolumeLimit; } else if (code == "C") { val = c; } else if (code == "A") { val = a; } } /// @dev Checks whether a given address can notaise MCR data or not. /// @param _add Address. /// @return res Returns 0 if address is not authorized, else 1. function isnotarise(address _add) external view returns (bool res) { res = false; if (_add == notariseMCR) res = true; } /// @dev Gets the details of last added MCR. /// @return mcrPercx100 Total Minimum Capital Requirement percentage of that month of year(multiplied by 100). /// @return vFull Total Pool fund value in Ether used in the last full daily calculation. function getLastMCR() external view returns (uint mcrPercx100, uint mcrEtherx1E18, uint vFull, uint64 date) { uint index = allMCRData.length.sub(1); return ( allMCRData[index].mcrPercx100, allMCRData[index].mcrEther, allMCRData[index].vFull, allMCRData[index].date ); } /// @dev Gets last Minimum Capital Requirement percentage of Capital Model /// @return val MCR% value,multiplied by 100. function getLastMCRPerc() external view returns (uint) { return allMCRData[allMCRData.length.sub(1)].mcrPercx100; } /// @dev Gets last Ether price of Capital Model /// @return val ether value,multiplied by 100. function getLastMCREther() external view returns (uint) { return allMCRData[allMCRData.length.sub(1)].mcrEther; } /// @dev Gets Pool fund value in Ether used in the last full daily calculation from the Capital model. function getLastVfull() external view returns (uint) { return allMCRData[allMCRData.length.sub(1)].vFull; } /// @dev Gets last Minimum Capital Requirement in Ether. /// @return date of MCR. function getLastMCRDate() external view returns (uint64 date) { date = allMCRData[allMCRData.length.sub(1)].date; } /// @dev Gets details for token price calculation. function getTokenPriceDetails(bytes4 curr) external view returns (uint _a, uint _c, uint rate) { _a = a; _c = c; rate = _getAvgRate(curr, false); } /// @dev Gets the total number of times MCR calculation has been made. function getMCRDataLength() external view returns (uint len) { len = allMCRData.length; } /** * @dev Gets investment asset rank details by given date. */ function getIARankDetailsByDate( uint64 date ) external view returns ( bytes4 maxIACurr, uint64 maxRate, bytes4 minIACurr, uint64 minRate ) { uint index = datewiseId[date]; return ( allIARankDetails[index].maxIACurr, allIARankDetails[index].maxRate, allIARankDetails[index].minIACurr, allIARankDetails[index].minRate ); } /** * @dev Gets Last Date. */ function getLastDate() external view returns (uint64 date) { return lastDate; } /** * @dev Gets investment currency for a given index. */ function getInvestmentCurrencyByIndex(uint index) external view returns (bytes4 currName) { return allInvestmentCurrencies[index]; } /** * @dev Gets count of investment currency. */ function getInvestmentCurrencyLen() external view returns (uint len) { return allInvestmentCurrencies.length; } /** * @dev Gets all the investment currencies. */ function getAllInvestmentCurrencies() external view returns (bytes4[] memory currencies) { return allInvestmentCurrencies; } /** * @dev Gets All currency for a given index. */ function getCurrenciesByIndex(uint index) external view returns (bytes4 currName) { return allCurrencies[index]; } /** * @dev Gets count of All currency. */ function getAllCurrenciesLen() external view returns (uint len) { return allCurrencies.length; } /** * @dev Gets all currencies */ function getAllCurrencies() external view returns (bytes4[] memory currencies) { return allCurrencies; } /** * @dev Gets currency asset details for a given currency. */ function getCurrencyAssetVarBase( bytes4 curr ) external view returns ( bytes4 currency, uint baseMin, uint varMin ) { return ( curr, allCurrencyAssets[curr].baseMin, allCurrencyAssets[curr].varMin ); } /** * @dev Gets minimum variable value for currency asset. */ function getCurrencyAssetVarMin(bytes4 curr) external view returns (uint varMin) { return allCurrencyAssets[curr].varMin; } /** * @dev Gets base minimum of a given currency asset. */ function getCurrencyAssetBaseMin(bytes4 curr) external view returns (uint baseMin) { return allCurrencyAssets[curr].baseMin; } /** * @dev Gets investment asset maximum and minimum holding percentage of a given currency. */ function getInvestmentAssetHoldingPerc( bytes4 curr ) external view returns ( uint64 minHoldingPercX100, uint64 maxHoldingPercX100 ) { return ( allInvestmentAssets[curr].minHoldingPercX100, allInvestmentAssets[curr].maxHoldingPercX100 ); } /** * @dev Gets investment asset decimals. */ function getInvestmentAssetDecimals(bytes4 curr) external view returns (uint8 decimal) { return allInvestmentAssets[curr].decimals; } /** * @dev Gets investment asset maximum holding percentage of a given currency. */ function getInvestmentAssetMaxHoldingPerc(bytes4 curr) external view returns (uint64 maxHoldingPercX100) { return allInvestmentAssets[curr].maxHoldingPercX100; } /** * @dev Gets investment asset minimum holding percentage of a given currency. */ function getInvestmentAssetMinHoldingPerc(bytes4 curr) external view returns (uint64 minHoldingPercX100) { return allInvestmentAssets[curr].minHoldingPercX100; } /** * @dev Gets investment asset details of a given currency */ function getInvestmentAssetDetails( bytes4 curr ) external view returns ( bytes4 currency, address currAddress, bool status, uint64 minHoldingPerc, uint64 maxHoldingPerc, uint8 decimals ) { return ( curr, allInvestmentAssets[curr].currAddress, allInvestmentAssets[curr].status, allInvestmentAssets[curr].minHoldingPercX100, allInvestmentAssets[curr].maxHoldingPercX100, allInvestmentAssets[curr].decimals ); } /** * @dev Gets Currency asset token address. */ function getCurrencyAssetAddress(bytes4 curr) external view returns (address) { return allCurrencyAssets[curr].currAddress; } /** * @dev Gets investment asset token address. */ function getInvestmentAssetAddress(bytes4 curr) external view returns (address) { return allInvestmentAssets[curr].currAddress; } /** * @dev Gets investment asset active Status of a given currency. */ function getInvestmentAssetStatus(bytes4 curr) external view returns (bool status) { return allInvestmentAssets[curr].status; } /** * @dev Gets type of oraclize query for a given Oraclize Query ID. * @param myid Oraclize Query ID identifying the query for which the result is being received. * @return _typeof It could be of type "quote","quotation","cover","claim" etc. */ function getApiIdTypeOf(bytes32 myid) external view returns (bytes4) { return allAPIid[myid].typeOf; } /** * @dev Gets ID associated to oraclize query for a given Oraclize Query ID. * @param myid Oraclize Query ID identifying the query for which the result is being received. * @return id1 It could be the ID of "proposal","quotation","cover","claim" etc. */ function getIdOfApiId(bytes32 myid) external view returns (uint) { return allAPIid[myid].id; } /** * @dev Gets the Timestamp of a oracalize call. */ function getDateAddOfAPI(bytes32 myid) external view returns (uint64) { return allAPIid[myid].dateAdd; } /** * @dev Gets the Timestamp at which result of oracalize call is received. */ function getDateUpdOfAPI(bytes32 myid) external view returns (uint64) { return allAPIid[myid].dateUpd; } /** * @dev Gets currency by oracalize id. */ function getCurrOfApiId(bytes32 myid) external view returns (bytes4) { return allAPIid[myid].currency; } /** * @dev Gets ID return by the oraclize query of a given index. * @param index Index. * @return myid ID return by the oraclize query. */ function getApiCallIndex(uint index) external view returns (bytes32 myid) { myid = allAPIcall[index]; } /** * @dev Gets Length of API call. */ function getApilCallLength() external view returns (uint) { return allAPIcall.length; } /** * @dev Get Details of Oraclize API when given Oraclize Id. * @param myid ID return by the oraclize query. * @return _typeof ype of the query for which oraclize * call is made.("proposal","quote","quotation" etc.) */ function getApiCallDetails( bytes32 myid ) external view returns ( bytes4 _typeof, bytes4 curr, uint id, uint64 dateAdd, uint64 dateUpd ) { return ( allAPIid[myid].typeOf, allAPIid[myid].currency, allAPIid[myid].id, allAPIid[myid].dateAdd, allAPIid[myid].dateUpd ); } /** * @dev Updates Uint Parameters of a code * @param code whose details we want to update * @param val value to set */ function updateUintParameters(bytes8 code, uint val) public { require(ms.checkIsAuthToGoverned(msg.sender)); if (code == "MCRTIM") { _changeMCRTime(val * 1 hours); } else if (code == "MCRFTIM") { _changeMCRFailTime(val * 1 hours); } else if (code == "MCRMIN") { _changeMinCap(val); } else if (code == "MCRSHOCK") { _changeShockParameter(val); } else if (code == "MCRCAPL") { _changeCapacityLimit(val); } else if (code == "IMZ") { _changeVariationPercX100(val); } else if (code == "IMRATET") { _changeIARatesTime(val * 1 hours); } else if (code == "IMUNIDL") { _changeUniswapDeadlineTime(val * 1 minutes); } else if (code == "IMLIQT") { _changeliquidityTradeCallbackTime(val * 1 hours); } else if (code == "IMETHVL") { _setEthVolumeLimit(val); } else if (code == "C") { _changeC(val); } else if (code == "A") { _changeA(val); } else { revert("Invalid param code"); } } /** * @dev to get the average rate of currency rate * @param curr is the currency in concern * @return required rate */ function getCAAvgRate(bytes4 curr) public view returns (uint rate) { return _getAvgRate(curr, false); } /** * @dev to get the average rate of investment rate * @param curr is the investment in concern * @return required rate */ function getIAAvgRate(bytes4 curr) public view returns (uint rate) { return _getAvgRate(curr, true); } function changeDependentContractAddress() public onlyInternal {} /// @dev Gets the average rate of a CA currency. /// @param curr Currency Name. /// @return rate Average rate X 100(of last 3 days). function _getAvgRate(bytes4 curr, bool isIA) internal view returns (uint rate) { if (curr == "DAI") { DSValue ds = DSValue(daiFeedAddress); rate = uint(ds.read()).div(uint(10) ** 16); } else if (isIA) { rate = iaAvgRate[curr]; } else { rate = caAvgRate[curr]; } } /** * @dev to set the ethereum volume limit * @param val is the new limit value */ function _setEthVolumeLimit(uint val) internal { ethVolumeLimit = val; } /// @dev Sets minimum Cap. function _changeMinCap(uint newCap) internal { minCap = newCap; } /// @dev Sets Shock Parameter. function _changeShockParameter(uint newParam) internal { shockParameter = newParam; } /// @dev Changes time period for obtaining new MCR data from external oracle query. function _changeMCRTime(uint _time) internal { mcrTime = _time; } /// @dev Sets MCR Fail time. function _changeMCRFailTime(uint _time) internal { mcrFailTime = _time; } /** * @dev to change the uniswap deadline time * @param newDeadline is the value */ function _changeUniswapDeadlineTime(uint newDeadline) internal { uniswapDeadline = newDeadline; } /** * @dev to change the liquidity trade call back time * @param newTime is the new value to be set */ function _changeliquidityTradeCallbackTime(uint newTime) internal { liquidityTradeCallbackTime = newTime; } /** * @dev Changes time after which investment asset rates need to be fed. */ function _changeIARatesTime(uint _newTime) internal { iaRatesTime = _newTime; } /** * @dev Changes the variation range percentage. */ function _changeVariationPercX100(uint newPercX100) internal { variationPercX100 = newPercX100; } /// @dev Changes Growth Step function _changeC(uint newC) internal { c = newC; } /// @dev Changes scaling factor. function _changeA(uint val) internal { a = val; } /** * @dev to change the capacity limit * @param val is the new value */ function _changeCapacityLimit(uint val) internal { capacityLimit = val; } }
/* Copyright (C) 2020 NexusMutual.io 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/ */ //Claims Reward Contract contains the functions for calculating number of tokens // that will get rewarded, unlocked or burned depending upon the status of claim. pragma solidity ^0.5.0; import "../../interfaces/IPooledStaking.sol"; import "../capital/Pool.sol"; import "../cover/QuotationData.sol"; import "../governance/Governance.sol"; import "../token/TokenData.sol"; import "../token/TokenFunctions.sol"; import "./Claims.sol"; import "./ClaimsData.sol"; contract ClaimsReward is Iupgradable { using SafeMath for uint; NXMToken internal tk; TokenController internal tc; TokenFunctions internal tf; TokenData internal td; QuotationData internal qd; Claims internal c1; ClaimsData internal cd; Pool internal pool; Governance internal gv; IPooledStaking internal pooledStaking; MemberRoles internal memberRoles; // assigned in constructor address public DAI; // constants address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; uint private constant DECIMAL1E18 = uint(10) ** 18; constructor (address masterAddress, address _daiAddress) public { changeMasterAddress(masterAddress); DAI = _daiAddress; } function changeDependentContractAddress() public onlyInternal { c1 = Claims(ms.getLatestAddress("CL")); cd = ClaimsData(ms.getLatestAddress("CD")); tk = NXMToken(ms.tokenAddress()); tc = TokenController(ms.getLatestAddress("TC")); td = TokenData(ms.getLatestAddress("TD")); tf = TokenFunctions(ms.getLatestAddress("TF")); qd = QuotationData(ms.getLatestAddress("QD")); gv = Governance(ms.getLatestAddress("GV")); pooledStaking = IPooledStaking(ms.getLatestAddress("PS")); memberRoles = MemberRoles(ms.getLatestAddress("MR")); pool = Pool(ms.getLatestAddress("P1")); } /// @dev Decides the next course of action for a given claim. function changeClaimStatus(uint claimid) public checkPause onlyInternal { (, uint coverid) = cd.getClaimCoverId(claimid); (, uint status) = cd.getClaimStatusNumber(claimid); // when current status is "Pending-Claim Assessor Vote" if (status == 0) { _changeClaimStatusCA(claimid, coverid, status); } else if (status >= 1 && status <= 5) { _changeClaimStatusMV(claimid, coverid, status); } else if (status == 12) {// when current status is "Claim Accepted Payout Pending" bool payoutSucceeded = attemptClaimPayout(coverid); if (payoutSucceeded) { c1.setClaimStatus(claimid, 14); } else { c1.setClaimStatus(claimid, 12); } } c1.changePendingClaimStart(); } function getCurrencyAssetAddress(bytes4 currency) public view returns (address) { if (currency == "ETH") { return ETH; } if (currency == "DAI") { return DAI; } revert("ClaimsReward: unknown asset"); } function attemptClaimPayout(uint coverId) internal returns (bool success) { uint sumAssured = qd.getCoverSumAssured(coverId); // TODO: when adding new cover currencies, fetch the correct decimals for this multiplication uint sumAssuredWei = sumAssured.mul(1e18); // get asset address bytes4 coverCurrency = qd.getCurrencyOfCover(coverId); address asset = getCurrencyAssetAddress(coverCurrency); // get payout address address payable coverHolder = qd.getCoverMemberAddress(coverId); address payable payoutAddress = memberRoles.getClaimPayoutAddress(coverHolder); // execute the payout bool payoutSucceeded = pool.sendClaimPayout(asset, payoutAddress, sumAssuredWei); if (payoutSucceeded) { // burn staked tokens (, address scAddress) = qd.getscAddressOfCover(coverId); uint tokenPrice = pool.getTokenPrice(asset); // note: for new assets "18" needs to be replaced with target asset decimals uint burnNXMAmount = sumAssuredWei.mul(1e18).div(tokenPrice); pooledStaking.pushBurn(scAddress, burnNXMAmount); // adjust total sum assured (, address coverContract) = qd.getscAddressOfCover(coverId); qd.subFromTotalSumAssured(coverCurrency, sumAssured); qd.subFromTotalSumAssuredSC(coverContract, coverCurrency, sumAssured); return true; } return false; } /// @dev Amount of tokens to be rewarded to a user for a particular vote id. /// @param check 1 -> CA vote, else member vote /// @param voteid vote id for which reward has to be Calculated /// @param flag if 1 calculate even if claimed,else don't calculate if already claimed /// @return tokenCalculated reward to be given for vote id /// @return lastClaimedCheck true if final verdict is still pending for that voteid /// @return tokens number of tokens locked under that voteid /// @return perc percentage of reward to be given. function getRewardToBeGiven( uint check, uint voteid, uint flag ) public view returns ( uint tokenCalculated, bool lastClaimedCheck, uint tokens, uint perc ) { uint claimId; int8 verdict; bool claimed; uint tokensToBeDist; uint totalTokens; (tokens, claimId, verdict, claimed) = cd.getVoteDetails(voteid); lastClaimedCheck = false; int8 claimVerdict = cd.getFinalVerdict(claimId); if (claimVerdict == 0) { lastClaimedCheck = true; } if (claimVerdict == verdict && (claimed == false || flag == 1)) { if (check == 1) { (perc, , tokensToBeDist) = cd.getClaimRewardDetail(claimId); } else { (, perc, tokensToBeDist) = cd.getClaimRewardDetail(claimId); } if (perc > 0) { if (check == 1) { if (verdict == 1) { (, totalTokens,) = cd.getClaimsTokenCA(claimId); } else { (,, totalTokens) = cd.getClaimsTokenCA(claimId); } } else { if (verdict == 1) { (, totalTokens,) = cd.getClaimsTokenMV(claimId); } else { (,, totalTokens) = cd.getClaimsTokenMV(claimId); } } tokenCalculated = (perc.mul(tokens).mul(tokensToBeDist)).div(totalTokens.mul(100)); } } } /// @dev Transfers all tokens held by contract to a new contract in case of upgrade. function upgrade(address _newAdd) public onlyInternal { uint amount = tk.balanceOf(address(this)); if (amount > 0) { require(tk.transfer(_newAdd, amount)); } } /// @dev Total reward in token due for claim by a user. /// @return total total number of tokens function getRewardToBeDistributedByUser(address _add) public view returns (uint total) { uint lengthVote = cd.getVoteAddressCALength(_add); uint lastIndexCA; uint lastIndexMV; uint tokenForVoteId; uint voteId; (lastIndexCA, lastIndexMV) = cd.getRewardDistributedIndex(_add); for (uint i = lastIndexCA; i < lengthVote; i++) { voteId = cd.getVoteAddressCA(_add, i); (tokenForVoteId,,,) = getRewardToBeGiven(1, voteId, 0); total = total.add(tokenForVoteId); } lengthVote = cd.getVoteAddressMemberLength(_add); for (uint j = lastIndexMV; j < lengthVote; j++) { voteId = cd.getVoteAddressMember(_add, j); (tokenForVoteId,,,) = getRewardToBeGiven(0, voteId, 0); total = total.add(tokenForVoteId); } return (total); } /// @dev Gets reward amount and claiming status for a given claim id. /// @return reward amount of tokens to user. /// @return claimed true if already claimed false if yet to be claimed. function getRewardAndClaimedStatus(uint check, uint claimId) public view returns (uint reward, bool claimed) { uint voteId; uint claimid; uint lengthVote; if (check == 1) { lengthVote = cd.getVoteAddressCALength(msg.sender); for (uint i = 0; i < lengthVote; i++) { voteId = cd.getVoteAddressCA(msg.sender, i); (, claimid, , claimed) = cd.getVoteDetails(voteId); if (claimid == claimId) {break;} } } else { lengthVote = cd.getVoteAddressMemberLength(msg.sender); for (uint j = 0; j < lengthVote; j++) { voteId = cd.getVoteAddressMember(msg.sender, j); (, claimid, , claimed) = cd.getVoteDetails(voteId); if (claimid == claimId) {break;} } } (reward,,,) = getRewardToBeGiven(check, voteId, 1); } /** * @dev Function used to claim all pending rewards : Claims Assessment + Risk Assessment + Governance * Claim assesment, Risk assesment, Governance rewards */ function claimAllPendingReward(uint records) public isMemberAndcheckPause { _claimRewardToBeDistributed(records); pooledStaking.withdrawReward(msg.sender); uint governanceRewards = gv.claimReward(msg.sender, records); if (governanceRewards > 0) { require(tk.transfer(msg.sender, governanceRewards)); } } /** * @dev Function used to get pending rewards of a particular user address. * @param _add user address. * @return total reward amount of the user */ function getAllPendingRewardOfUser(address _add) public view returns (uint) { uint caReward = getRewardToBeDistributedByUser(_add); uint pooledStakingReward = pooledStaking.stakerReward(_add); uint governanceReward = gv.getPendingReward(_add); return caReward.add(pooledStakingReward).add(governanceReward); } /// @dev Rewards/Punishes users who participated in Claims assessment. // Unlocking and burning of the tokens will also depend upon the status of claim. /// @param claimid Claim Id. function _rewardAgainstClaim(uint claimid, uint coverid, uint status) internal { uint premiumNXM = qd.getCoverPremiumNXM(coverid); uint distributableTokens = premiumNXM.mul(cd.claimRewardPerc()).div(100); // 20% of premium uint percCA; uint percMV; (percCA, percMV) = cd.getRewardStatus(status); cd.setClaimRewardDetail(claimid, percCA, percMV, distributableTokens); if (percCA > 0 || percMV > 0) { tc.mint(address(this), distributableTokens); } // denied if (status == 6 || status == 9 || status == 11) { cd.changeFinalVerdict(claimid, - 1); td.setDepositCN(coverid, false); // Unset flag tf.burnDepositCN(coverid); // burn Deposited CN // accepted } else if (status == 7 || status == 8 || status == 10) { cd.changeFinalVerdict(claimid, 1); td.setDepositCN(coverid, false); // Unset flag tf.unlockCN(coverid); bool payoutSucceeded = attemptClaimPayout(coverid); // 12 = payout pending, 14 = payout succeeded uint nextStatus = payoutSucceeded ? 14 : 12; c1.setClaimStatus(claimid, nextStatus); } } /// @dev Computes the result of Claim Assessors Voting for a given claim id. function _changeClaimStatusCA(uint claimid, uint coverid, uint status) internal { // Check if voting should be closed or not if (c1.checkVoteClosing(claimid) == 1) { uint caTokens = c1.getCATokens(claimid, 0); // converted in cover currency. uint accept; uint deny; uint acceptAndDeny; bool rewardOrPunish; uint sumAssured; (, accept) = cd.getClaimVote(claimid, 1); (, deny) = cd.getClaimVote(claimid, - 1); acceptAndDeny = accept.add(deny); accept = accept.mul(100); deny = deny.mul(100); if (caTokens == 0) { status = 3; } else { sumAssured = qd.getCoverSumAssured(coverid).mul(DECIMAL1E18); // Min threshold reached tokens used for voting > 5* sum assured if (caTokens > sumAssured.mul(5)) { if (accept.div(acceptAndDeny) > 70) { status = 7; qd.changeCoverStatusNo(coverid, uint8(QuotationData.CoverStatus.ClaimAccepted)); rewardOrPunish = true; } else if (deny.div(acceptAndDeny) > 70) { status = 6; qd.changeCoverStatusNo(coverid, uint8(QuotationData.CoverStatus.ClaimDenied)); rewardOrPunish = true; } else if (accept.div(acceptAndDeny) > deny.div(acceptAndDeny)) { status = 4; } else { status = 5; } } else { if (accept.div(acceptAndDeny) > deny.div(acceptAndDeny)) { status = 2; } else { status = 3; } } } c1.setClaimStatus(claimid, status); if (rewardOrPunish) { _rewardAgainstClaim(claimid, coverid, status); } } } /// @dev Computes the result of Member Voting for a given claim id. function _changeClaimStatusMV(uint claimid, uint coverid, uint status) internal { // Check if voting should be closed or not if (c1.checkVoteClosing(claimid) == 1) { uint8 coverStatus; uint statusOrig = status; uint mvTokens = c1.getCATokens(claimid, 1); // converted in cover currency. // If tokens used for acceptance >50%, claim is accepted uint sumAssured = qd.getCoverSumAssured(coverid).mul(DECIMAL1E18); uint thresholdUnreached = 0; // Minimum threshold for member voting is reached only when // value of tokens used for voting > 5* sum assured of claim id if (mvTokens < sumAssured.mul(5)) { thresholdUnreached = 1; } uint accept; (, accept) = cd.getClaimMVote(claimid, 1); uint deny; (, deny) = cd.getClaimMVote(claimid, - 1); if (accept.add(deny) > 0) { if (accept.mul(100).div(accept.add(deny)) >= 50 && statusOrig > 1 && statusOrig <= 5 && thresholdUnreached == 0) { status = 8; coverStatus = uint8(QuotationData.CoverStatus.ClaimAccepted); } else if (deny.mul(100).div(accept.add(deny)) >= 50 && statusOrig > 1 && statusOrig <= 5 && thresholdUnreached == 0) { status = 9; coverStatus = uint8(QuotationData.CoverStatus.ClaimDenied); } } if (thresholdUnreached == 1 && (statusOrig == 2 || statusOrig == 4)) { status = 10; coverStatus = uint8(QuotationData.CoverStatus.ClaimAccepted); } else if (thresholdUnreached == 1 && (statusOrig == 5 || statusOrig == 3 || statusOrig == 1)) { status = 11; coverStatus = uint8(QuotationData.CoverStatus.ClaimDenied); } c1.setClaimStatus(claimid, status); qd.changeCoverStatusNo(coverid, uint8(coverStatus)); // Reward/Punish Claim Assessors and Members who participated in Claims assessment _rewardAgainstClaim(claimid, coverid, status); } } /// @dev Allows a user to claim all pending Claims assessment rewards. function _claimRewardToBeDistributed(uint _records) internal { uint lengthVote = cd.getVoteAddressCALength(msg.sender); uint voteid; uint lastIndex; (lastIndex,) = cd.getRewardDistributedIndex(msg.sender); uint total = 0; uint tokenForVoteId = 0; bool lastClaimedCheck; uint _days = td.lockCADays(); bool claimed; uint counter = 0; uint claimId; uint perc; uint i; uint lastClaimed = lengthVote; for (i = lastIndex; i < lengthVote && counter < _records; i++) { voteid = cd.getVoteAddressCA(msg.sender, i); (tokenForVoteId, lastClaimedCheck, , perc) = getRewardToBeGiven(1, voteid, 0); if (lastClaimed == lengthVote && lastClaimedCheck == true) { lastClaimed = i; } (, claimId, , claimed) = cd.getVoteDetails(voteid); if (perc > 0 && !claimed) { counter++; cd.setRewardClaimed(voteid, true); } else if (perc == 0 && cd.getFinalVerdict(claimId) != 0 && !claimed) { (perc,,) = cd.getClaimRewardDetail(claimId); if (perc == 0) { counter++; } cd.setRewardClaimed(voteid, true); } if (tokenForVoteId > 0) { total = tokenForVoteId.add(total); } } if (lastClaimed == lengthVote) { cd.setRewardDistributedIndexCA(msg.sender, i); } else { cd.setRewardDistributedIndexCA(msg.sender, lastClaimed); } lengthVote = cd.getVoteAddressMemberLength(msg.sender); lastClaimed = lengthVote; _days = _days.mul(counter); if (tc.tokensLockedAtTime(msg.sender, "CLA", now) > 0) { tc.reduceLock(msg.sender, "CLA", _days); } (, lastIndex) = cd.getRewardDistributedIndex(msg.sender); lastClaimed = lengthVote; counter = 0; for (i = lastIndex; i < lengthVote && counter < _records; i++) { voteid = cd.getVoteAddressMember(msg.sender, i); (tokenForVoteId, lastClaimedCheck,,) = getRewardToBeGiven(0, voteid, 0); if (lastClaimed == lengthVote && lastClaimedCheck == true) { lastClaimed = i; } (, claimId, , claimed) = cd.getVoteDetails(voteid); if (claimed == false && cd.getFinalVerdict(claimId) != 0) { cd.setRewardClaimed(voteid, true); counter++; } if (tokenForVoteId > 0) { total = tokenForVoteId.add(total); } } if (total > 0) { require(tk.transfer(msg.sender, total)); } if (lastClaimed == lengthVote) { cd.setRewardDistributedIndexMV(msg.sender, i); } else { cd.setRewardDistributedIndexMV(msg.sender, lastClaimed); } } /** * @dev Function used to claim the commission earned by the staker. */ function _claimStakeCommission(uint _records, address _user) external onlyInternal { uint total = 0; uint len = td.getStakerStakedContractLength(_user); uint lastCompletedStakeCommission = td.lastCompletedStakeCommission(_user); uint commissionEarned; uint commissionRedeemed; uint maxCommission; uint lastCommisionRedeemed = len; uint counter; uint i; for (i = lastCompletedStakeCommission; i < len && counter < _records; i++) { commissionRedeemed = td.getStakerRedeemedStakeCommission(_user, i); commissionEarned = td.getStakerEarnedStakeCommission(_user, i); maxCommission = td.getStakerInitialStakedAmountOnContract( _user, i).mul(td.stakerMaxCommissionPer()).div(100); if (lastCommisionRedeemed == len && maxCommission != commissionEarned) lastCommisionRedeemed = i; td.pushRedeemedStakeCommissions(_user, i, commissionEarned.sub(commissionRedeemed)); total = total.add(commissionEarned.sub(commissionRedeemed)); counter++; } if (lastCommisionRedeemed == len) { td.setLastCompletedStakeCommissionIndex(_user, i); } else { td.setLastCompletedStakeCommissionIndex(_user, lastCommisionRedeemed); } if (total > 0) require(tk.transfer(_user, total)); // solhint-disable-line } }
/* Copyright (C) 2017 GovBlocks.io 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.5.0; import "../claims/ClaimsReward.sol"; import "../cover/QuotationData.sol"; import "../token/TokenController.sol"; import "../token/TokenData.sol"; import "../token/TokenFunctions.sol"; import "./Governance.sol"; import "./external/Governed.sol"; contract MemberRoles is Governed, Iupgradable { TokenController public dAppToken; TokenData internal td; QuotationData internal qd; ClaimsReward internal cr; Governance internal gv; TokenFunctions internal tf; NXMToken public tk; struct MemberRoleDetails { uint memberCounter; mapping(address => bool) memberActive; address[] memberAddress; address authorized; } enum Role {UnAssigned, AdvisoryBoard, Member, Owner} event MemberRole(uint256 indexed roleId, bytes32 roleName, string roleDescription); event switchedMembership(address indexed previousMember, address indexed newMember, uint timeStamp); event ClaimPayoutAddressSet(address indexed member, address indexed payoutAddress); MemberRoleDetails[] internal memberRoleData; bool internal constructorCheck; uint public maxABCount; bool public launched; uint public launchedOn; mapping (address => address payable) internal claimPayoutAddress; modifier checkRoleAuthority(uint _memberRoleId) { if (memberRoleData[_memberRoleId].authorized != address(0)) require(msg.sender == memberRoleData[_memberRoleId].authorized); else require(isAuthorizedToGovern(msg.sender), "Not Authorized"); _; } /** * @dev to swap advisory board member * @param _newABAddress is address of new AB member * @param _removeAB is advisory board member to be removed */ function swapABMember( address _newABAddress, address _removeAB ) external checkRoleAuthority(uint(Role.AdvisoryBoard)) { _updateRole(_newABAddress, uint(Role.AdvisoryBoard), true); _updateRole(_removeAB, uint(Role.AdvisoryBoard), false); } /** * @dev to swap the owner address * @param _newOwnerAddress is the new owner address */ function swapOwner( address _newOwnerAddress ) external { require(msg.sender == address(ms)); _updateRole(ms.owner(), uint(Role.Owner), false); _updateRole(_newOwnerAddress, uint(Role.Owner), true); } /** * @dev is used to add initital advisory board members * @param abArray is the list of initial advisory board members */ function addInitialABMembers(address[] calldata abArray) external onlyOwner { //Ensure that NXMaster has initialized. require(ms.masterInitialized()); require(maxABCount >= SafeMath.add(numberOfMembers(uint(Role.AdvisoryBoard)), abArray.length) ); //AB count can't exceed maxABCount for (uint i = 0; i < abArray.length; i++) { require(checkRole(abArray[i], uint(MemberRoles.Role.Member))); _updateRole(abArray[i], uint(Role.AdvisoryBoard), true); } } /** * @dev to change max number of AB members allowed * @param _val is the new value to be set */ function changeMaxABCount(uint _val) external onlyInternal { maxABCount = _val; } /** * @dev Iupgradable Interface to update dependent contract address */ function changeDependentContractAddress() public { td = TokenData(ms.getLatestAddress("TD")); cr = ClaimsReward(ms.getLatestAddress("CR")); qd = QuotationData(ms.getLatestAddress("QD")); gv = Governance(ms.getLatestAddress("GV")); tf = TokenFunctions(ms.getLatestAddress("TF")); tk = NXMToken(ms.tokenAddress()); dAppToken = TokenController(ms.getLatestAddress("TC")); } /** * @dev to change the master address * @param _masterAddress is the new master address */ function changeMasterAddress(address _masterAddress) public { if (masterAddress != address(0)) require(masterAddress == msg.sender); masterAddress = _masterAddress; ms = INXMMaster(_masterAddress); nxMasterAddress = _masterAddress; } /** * @dev to initiate the member roles * @param _firstAB is the address of the first AB member * @param memberAuthority is the authority (role) of the member */ function memberRolesInitiate(address _firstAB, address memberAuthority) public { require(!constructorCheck); _addInitialMemberRoles(_firstAB, memberAuthority); constructorCheck = true; } /// @dev Adds new member role /// @param _roleName New role name /// @param _roleDescription New description hash /// @param _authorized Authorized member against every role id function addRole(//solhint-disable-line bytes32 _roleName, string memory _roleDescription, address _authorized ) public onlyAuthorizedToGovern { _addRole(_roleName, _roleDescription, _authorized); } /// @dev Assign or Delete a member from specific role. /// @param _memberAddress Address of Member /// @param _roleId RoleId to update /// @param _active active is set to be True if we want to assign this role to member, False otherwise! function updateRole(//solhint-disable-line address _memberAddress, uint _roleId, bool _active ) public checkRoleAuthority(_roleId) { _updateRole(_memberAddress, _roleId, _active); } /** * @dev to add members before launch * @param userArray is list of addresses of members * @param tokens is list of tokens minted for each array element */ function addMembersBeforeLaunch(address[] memory userArray, uint[] memory tokens) public onlyOwner { require(!launched); for (uint i = 0; i < userArray.length; i++) { require(!ms.isMember(userArray[i])); dAppToken.addToWhitelist(userArray[i]); _updateRole(userArray[i], uint(Role.Member), true); dAppToken.mint(userArray[i], tokens[i]); } launched = true; launchedOn = now; } /** * @dev Called by user to pay joining membership fee */ function payJoiningFee(address _userAddress) public payable { require(_userAddress != address(0)); require(!ms.isPause(), "Emergency Pause Applied"); if (msg.sender == address(ms.getLatestAddress("QT"))) { require(td.walletAddress() != address(0), "No walletAddress present"); dAppToken.addToWhitelist(_userAddress); _updateRole(_userAddress, uint(Role.Member), true); td.walletAddress().transfer(msg.value); } else { require(!qd.refundEligible(_userAddress)); require(!ms.isMember(_userAddress)); require(msg.value == td.joiningFee()); qd.setRefundEligible(_userAddress, true); } } /** * @dev to perform kyc verdict * @param _userAddress whose kyc is being performed * @param verdict of kyc process */ function kycVerdict(address payable _userAddress, bool verdict) public { require(msg.sender == qd.kycAuthAddress()); require(!ms.isPause()); require(_userAddress != address(0)); require(!ms.isMember(_userAddress)); require(qd.refundEligible(_userAddress)); if (verdict) { qd.setRefundEligible(_userAddress, false); uint fee = td.joiningFee(); dAppToken.addToWhitelist(_userAddress); _updateRole(_userAddress, uint(Role.Member), true); td.walletAddress().transfer(fee); // solhint-disable-line } else { qd.setRefundEligible(_userAddress, false); _userAddress.transfer(td.joiningFee()); // solhint-disable-line } } /** * @dev Called by existed member if wish to Withdraw membership. */ function withdrawMembership() public { require(!ms.isPause() && ms.isMember(msg.sender)); require(dAppToken.totalLockedBalance(msg.sender, now) == 0); // solhint-disable-line require(!tf.isLockedForMemberVote(msg.sender)); // No locked tokens for Member/Governance voting require(cr.getAllPendingRewardOfUser(msg.sender) == 0); // No pending reward to be claimed(claim assesment). require(dAppToken.tokensUnlockable(msg.sender, "CLA") == 0, "Member should have no CLA unlockable tokens"); gv.removeDelegation(msg.sender); dAppToken.burnFrom(msg.sender, tk.balanceOf(msg.sender)); _updateRole(msg.sender, uint(Role.Member), false); dAppToken.removeFromWhitelist(msg.sender); // need clarification on whitelist if (claimPayoutAddress[msg.sender] != address(0)) { claimPayoutAddress[msg.sender] = address(0); emit ClaimPayoutAddressSet(msg.sender, address(0)); } } /** * @dev Called by existed member if wish to switch membership to other address. * @param _add address of user to forward membership. */ function switchMembership(address _add) external { require(!ms.isPause() && ms.isMember(msg.sender) && !ms.isMember(_add)); require(dAppToken.totalLockedBalance(msg.sender, now) == 0); // solhint-disable-line require(!tf.isLockedForMemberVote(msg.sender)); // No locked tokens for Member/Governance voting require(cr.getAllPendingRewardOfUser(msg.sender) == 0); // No pending reward to be claimed(claim assesment). require(dAppToken.tokensUnlockable(msg.sender, "CLA") == 0, "Member should have no CLA unlockable tokens"); gv.removeDelegation(msg.sender); dAppToken.addToWhitelist(_add); _updateRole(_add, uint(Role.Member), true); tk.transferFrom(msg.sender, _add, tk.balanceOf(msg.sender)); _updateRole(msg.sender, uint(Role.Member), false); dAppToken.removeFromWhitelist(msg.sender); address payable previousPayoutAddress = claimPayoutAddress[msg.sender]; if (previousPayoutAddress != address(0)) { address payable storedAddress = previousPayoutAddress == _add ? address(0) : previousPayoutAddress; claimPayoutAddress[msg.sender] = address(0); claimPayoutAddress[_add] = storedAddress; // emit event for old address reset emit ClaimPayoutAddressSet(msg.sender, address(0)); if (storedAddress != address(0)) { // emit event for setting the payout address on the new member address if it's non zero emit ClaimPayoutAddressSet(_add, storedAddress); } } emit switchedMembership(msg.sender, _add, now); } function getClaimPayoutAddress(address payable _member) external view returns (address payable) { address payable payoutAddress = claimPayoutAddress[_member]; return payoutAddress != address(0) ? payoutAddress : _member; } function setClaimPayoutAddress(address payable _address) external { require(!ms.isPause(), "system is paused"); require(ms.isMember(msg.sender), "sender is not a member"); require(_address != msg.sender, "should be different than the member address"); claimPayoutAddress[msg.sender] = _address; emit ClaimPayoutAddressSet(msg.sender, _address); } /// @dev Return number of member roles function totalRoles() public view returns (uint256) {//solhint-disable-line return memberRoleData.length; } /// @dev Change Member Address who holds the authority to Add/Delete any member from specific role. /// @param _roleId roleId to update its Authorized Address /// @param _newAuthorized New authorized address against role id function changeAuthorized(uint _roleId, address _newAuthorized) public checkRoleAuthority(_roleId) {//solhint-disable-line memberRoleData[_roleId].authorized = _newAuthorized; } /// @dev Gets the member addresses assigned by a specific role /// @param _memberRoleId Member role id /// @return roleId Role id /// @return allMemberAddress Member addresses of specified role id function members(uint _memberRoleId) public view returns (uint, address[] memory memberArray) {//solhint-disable-line uint length = memberRoleData[_memberRoleId].memberAddress.length; uint i; uint j = 0; memberArray = new address[](memberRoleData[_memberRoleId].memberCounter); for (i = 0; i < length; i++) { address member = memberRoleData[_memberRoleId].memberAddress[i]; if (memberRoleData[_memberRoleId].memberActive[member] && !_checkMemberInArray(member, memberArray)) {//solhint-disable-line memberArray[j] = member; j++; } } return (_memberRoleId, memberArray); } /// @dev Gets all members' length /// @param _memberRoleId Member role id /// @return memberRoleData[_memberRoleId].memberCounter Member length function numberOfMembers(uint _memberRoleId) public view returns (uint) {//solhint-disable-line return memberRoleData[_memberRoleId].memberCounter; } /// @dev Return member address who holds the right to add/remove any member from specific role. function authorized(uint _memberRoleId) public view returns (address) {//solhint-disable-line return memberRoleData[_memberRoleId].authorized; } /// @dev Get All role ids array that has been assigned to a member so far. function roles(address _memberAddress) public view returns (uint[] memory) {//solhint-disable-line uint length = memberRoleData.length; uint[] memory assignedRoles = new uint[](length); uint counter = 0; for (uint i = 1; i < length; i++) { if (memberRoleData[i].memberActive[_memberAddress]) { assignedRoles[counter] = i; counter++; } } return assignedRoles; } /// @dev Returns true if the given role id is assigned to a member. /// @param _memberAddress Address of member /// @param _roleId Checks member's authenticity with the roleId. /// i.e. Returns true if this roleId is assigned to member function checkRole(address _memberAddress, uint _roleId) public view returns (bool) {//solhint-disable-line if (_roleId == uint(Role.UnAssigned)) return true; else if (memberRoleData[_roleId].memberActive[_memberAddress]) //solhint-disable-line return true; else return false; } /// @dev Return total number of members assigned against each role id. /// @return totalMembers Total members in particular role id function getMemberLengthForAllRoles() public view returns (uint[] memory totalMembers) {//solhint-disable-line totalMembers = new uint[](memberRoleData.length); for (uint i = 0; i < memberRoleData.length; i++) { totalMembers[i] = numberOfMembers(i); } } /** * @dev to update the member roles * @param _memberAddress in concern * @param _roleId the id of role * @param _active if active is true, add the member, else remove it */ function _updateRole(address _memberAddress, uint _roleId, bool _active) internal { // require(_roleId != uint(Role.TokenHolder), "Membership to Token holder is detected automatically"); if (_active) { require(!memberRoleData[_roleId].memberActive[_memberAddress]); memberRoleData[_roleId].memberCounter = SafeMath.add(memberRoleData[_roleId].memberCounter, 1); memberRoleData[_roleId].memberActive[_memberAddress] = true; memberRoleData[_roleId].memberAddress.push(_memberAddress); } else { require(memberRoleData[_roleId].memberActive[_memberAddress]); memberRoleData[_roleId].memberCounter = SafeMath.sub(memberRoleData[_roleId].memberCounter, 1); delete memberRoleData[_roleId].memberActive[_memberAddress]; } } /// @dev Adds new member role /// @param _roleName New role name /// @param _roleDescription New description hash /// @param _authorized Authorized member against every role id function _addRole( bytes32 _roleName, string memory _roleDescription, address _authorized ) internal { emit MemberRole(memberRoleData.length, _roleName, _roleDescription); memberRoleData.push(MemberRoleDetails(0, new address[](0), _authorized)); } /** * @dev to check if member is in the given member array * @param _memberAddress in concern * @param memberArray in concern * @return boolean to represent the presence */ function _checkMemberInArray( address _memberAddress, address[] memory memberArray ) internal pure returns (bool memberExists) { uint i; for (i = 0; i < memberArray.length; i++) { if (memberArray[i] == _memberAddress) { memberExists = true; break; } } } /** * @dev to add initial member roles * @param _firstAB is the member address to be added * @param memberAuthority is the member authority(role) to be added for */ function _addInitialMemberRoles(address _firstAB, address memberAuthority) internal { maxABCount = 5; _addRole("Unassigned", "Unassigned", address(0)); _addRole( "Advisory Board", "Selected few members that are deeply entrusted by the dApp. An ideal advisory board should be a mix of skills of domain, governance, research, technology, consulting etc to improve the performance of the dApp.", //solhint-disable-line address(0) ); _addRole( "Member", "Represents all users of Mutual.", //solhint-disable-line memberAuthority ); _addRole( "Owner", "Represents Owner of Mutual.", //solhint-disable-line address(0) ); // _updateRole(_firstAB, uint(Role.AdvisoryBoard), true); _updateRole(_firstAB, uint(Role.Owner), true); // _updateRole(_firstAB, uint(Role.Member), true); launchedOn = 0; } function memberAtIndex(uint _memberRoleId, uint index) external view returns (address, bool) { address memberAddress = memberRoleData[_memberRoleId].memberAddress[index]; return (memberAddress, memberRoleData[_memberRoleId].memberActive[memberAddress]); } function membersLength(uint _memberRoleId) external view returns (uint) { return memberRoleData[_memberRoleId].memberAddress.length; } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../abstract/Iupgradable.sol"; contract TokenData is Iupgradable { using SafeMath for uint; address payable public walletAddress; uint public lockTokenTimeAfterCoverExp; uint public bookTime; uint public lockCADays; uint public lockMVDays; uint public scValidDays; uint public joiningFee; uint public stakerCommissionPer; uint public stakerMaxCommissionPer; uint public tokenExponent; uint public priceStep; struct StakeCommission { uint commissionEarned; uint commissionRedeemed; } struct Stake { address stakedContractAddress; uint stakedContractIndex; uint dateAdd; uint stakeAmount; uint unlockedAmount; uint burnedAmount; uint unLockableBeforeLastBurn; } struct Staker { address stakerAddress; uint stakerIndex; } struct CoverNote { uint amount; bool isDeposited; } /** * @dev mapping of uw address to array of sc address to fetch * all staked contract address of underwriter, pushing * data into this array of Stake returns stakerIndex */ mapping(address => Stake[]) public stakerStakedContracts; /** * @dev mapping of sc address to array of UW address to fetch * all underwritters of the staked smart contract * pushing data into this mapped array returns scIndex */ mapping(address => Staker[]) public stakedContractStakers; /** * @dev mapping of staked contract Address to the array of StakeCommission * here index of this array is stakedContractIndex */ mapping(address => mapping(uint => StakeCommission)) public stakedContractStakeCommission; mapping(address => uint) public lastCompletedStakeCommission; /** * @dev mapping of the staked contract address to the current * staker index who will receive commission. */ mapping(address => uint) public stakedContractCurrentCommissionIndex; /** * @dev mapping of the staked contract address to the * current staker index to burn token from. */ mapping(address => uint) public stakedContractCurrentBurnIndex; /** * @dev mapping to return true if Cover Note deposited against coverId */ mapping(uint => CoverNote) public depositedCN; mapping(address => uint) internal isBookedTokens; event Commission( address indexed stakedContractAddress, address indexed stakerAddress, uint indexed scIndex, uint commissionAmount ); constructor(address payable _walletAdd) public { walletAddress = _walletAdd; bookTime = 12 hours; joiningFee = 2000000000000000; // 0.002 Ether lockTokenTimeAfterCoverExp = 35 days; scValidDays = 250; lockCADays = 7 days; lockMVDays = 2 days; stakerCommissionPer = 20; stakerMaxCommissionPer = 50; tokenExponent = 4; priceStep = 1000; } /** * @dev Change the wallet address which receive Joining Fee */ function changeWalletAddress(address payable _address) external onlyInternal { walletAddress = _address; } /** * @dev Gets Uint Parameters of a code * @param code whose details we want * @return string value of the code * @return associated amount (time or perc or value) to the code */ function getUintParameters(bytes8 code) external view returns (bytes8 codeVal, uint val) { codeVal = code; if (code == "TOKEXP") { val = tokenExponent; } else if (code == "TOKSTEP") { val = priceStep; } else if (code == "RALOCKT") { val = scValidDays; } else if (code == "RACOMM") { val = stakerCommissionPer; } else if (code == "RAMAXC") { val = stakerMaxCommissionPer; } else if (code == "CABOOKT") { val = bookTime / (1 hours); } else if (code == "CALOCKT") { val = lockCADays / (1 days); } else if (code == "MVLOCKT") { val = lockMVDays / (1 days); } else if (code == "QUOLOCKT") { val = lockTokenTimeAfterCoverExp / (1 days); } else if (code == "JOINFEE") { val = joiningFee; } } /** * @dev Just for interface */ function changeDependentContractAddress() public {//solhint-disable-line } /** * @dev to get the contract staked by a staker * @param _stakerAddress is the address of the staker * @param _stakerIndex is the index of staker * @return the address of staked contract */ function getStakerStakedContractByIndex( address _stakerAddress, uint _stakerIndex ) public view returns (address stakedContractAddress) { stakedContractAddress = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakedContractAddress; } /** * @dev to get the staker's staked burned * @param _stakerAddress is the address of the staker * @param _stakerIndex is the index of staker * @return amount burned */ function getStakerStakedBurnedByIndex( address _stakerAddress, uint _stakerIndex ) public view returns (uint burnedAmount) { burnedAmount = stakerStakedContracts[ _stakerAddress][_stakerIndex].burnedAmount; } /** * @dev to get the staker's staked unlockable before the last burn * @param _stakerAddress is the address of the staker * @param _stakerIndex is the index of staker * @return unlockable staked tokens */ function getStakerStakedUnlockableBeforeLastBurnByIndex( address _stakerAddress, uint _stakerIndex ) public view returns (uint unlockable) { unlockable = stakerStakedContracts[ _stakerAddress][_stakerIndex].unLockableBeforeLastBurn; } /** * @dev to get the staker's staked contract index * @param _stakerAddress is the address of the staker * @param _stakerIndex is the index of staker * @return is the index of the smart contract address */ function getStakerStakedContractIndex( address _stakerAddress, uint _stakerIndex ) public view returns (uint scIndex) { scIndex = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakedContractIndex; } /** * @dev to get the staker index of the staked contract * @param _stakedContractAddress is the address of the staked contract * @param _stakedContractIndex is the index of staked contract * @return is the index of the staker */ function getStakedContractStakerIndex( address _stakedContractAddress, uint _stakedContractIndex ) public view returns (uint sIndex) { sIndex = stakedContractStakers[ _stakedContractAddress][_stakedContractIndex].stakerIndex; } /** * @dev to get the staker's initial staked amount on the contract * @param _stakerAddress is the address of the staker * @param _stakerIndex is the index of staker * @return staked amount */ function getStakerInitialStakedAmountOnContract( address _stakerAddress, uint _stakerIndex ) public view returns (uint amount) { amount = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakeAmount; } /** * @dev to get the staker's staked contract length * @param _stakerAddress is the address of the staker * @return length of staked contract */ function getStakerStakedContractLength( address _stakerAddress ) public view returns (uint length) { length = stakerStakedContracts[_stakerAddress].length; } /** * @dev to get the staker's unlocked tokens which were staked * @param _stakerAddress is the address of the staker * @param _stakerIndex is the index of staker * @return amount */ function getStakerUnlockedStakedTokens( address _stakerAddress, uint _stakerIndex ) public view returns (uint amount) { amount = stakerStakedContracts[ _stakerAddress][_stakerIndex].unlockedAmount; } /** * @dev pushes the unlocked staked tokens by a staker. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker to distribute commission. * @param _amount amount to be given as commission. */ function pushUnlockedStakedTokens( address _stakerAddress, uint _stakerIndex, uint _amount ) public onlyInternal { stakerStakedContracts[_stakerAddress][ _stakerIndex].unlockedAmount = stakerStakedContracts[_stakerAddress][ _stakerIndex].unlockedAmount.add(_amount); } /** * @dev pushes the Burned tokens for a staker. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker. * @param _amount amount to be burned. */ function pushBurnedTokens( address _stakerAddress, uint _stakerIndex, uint _amount ) public onlyInternal { stakerStakedContracts[_stakerAddress][ _stakerIndex].burnedAmount = stakerStakedContracts[_stakerAddress][ _stakerIndex].burnedAmount.add(_amount); } /** * @dev pushes the unLockable tokens for a staker before last burn. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker. * @param _amount amount to be added to unlockable. */ function pushUnlockableBeforeLastBurnTokens( address _stakerAddress, uint _stakerIndex, uint _amount ) public onlyInternal { stakerStakedContracts[_stakerAddress][ _stakerIndex].unLockableBeforeLastBurn = stakerStakedContracts[_stakerAddress][ _stakerIndex].unLockableBeforeLastBurn.add(_amount); } /** * @dev sets the unLockable tokens for a staker before last burn. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker. * @param _amount amount to be added to unlockable. */ function setUnlockableBeforeLastBurnTokens( address _stakerAddress, uint _stakerIndex, uint _amount ) public onlyInternal { stakerStakedContracts[_stakerAddress][ _stakerIndex].unLockableBeforeLastBurn = _amount; } /** * @dev pushes the earned commission earned by a staker. * @param _stakerAddress address of staker. * @param _stakedContractAddress address of smart contract. * @param _stakedContractIndex index of the staker to distribute commission. * @param _commissionAmount amount to be given as commission. */ function pushEarnedStakeCommissions( address _stakerAddress, address _stakedContractAddress, uint _stakedContractIndex, uint _commissionAmount ) public onlyInternal { stakedContractStakeCommission[_stakedContractAddress][_stakedContractIndex]. commissionEarned = stakedContractStakeCommission[_stakedContractAddress][ _stakedContractIndex].commissionEarned.add(_commissionAmount); emit Commission( _stakerAddress, _stakedContractAddress, _stakedContractIndex, _commissionAmount ); } /** * @dev pushes the redeemed commission redeemed by a staker. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker to distribute commission. * @param _amount amount to be given as commission. */ function pushRedeemedStakeCommissions( address _stakerAddress, uint _stakerIndex, uint _amount ) public onlyInternal { uint stakedContractIndex = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakedContractIndex; address stakedContractAddress = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakedContractAddress; stakedContractStakeCommission[stakedContractAddress][stakedContractIndex]. commissionRedeemed = stakedContractStakeCommission[ stakedContractAddress][stakedContractIndex].commissionRedeemed.add(_amount); } /** * @dev Gets stake commission given to an underwriter * for particular stakedcontract on given index. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker commission. */ function getStakerEarnedStakeCommission( address _stakerAddress, uint _stakerIndex ) public view returns (uint) { return _getStakerEarnedStakeCommission(_stakerAddress, _stakerIndex); } /** * @dev Gets stake commission redeemed by an underwriter * for particular staked contract on given index. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker commission. * @return commissionEarned total amount given to staker. */ function getStakerRedeemedStakeCommission( address _stakerAddress, uint _stakerIndex ) public view returns (uint) { return _getStakerRedeemedStakeCommission(_stakerAddress, _stakerIndex); } /** * @dev Gets total stake commission given to an underwriter * @param _stakerAddress address of staker. * @return totalCommissionEarned total commission earned by staker. */ function getStakerTotalEarnedStakeCommission( address _stakerAddress ) public view returns (uint totalCommissionEarned) { totalCommissionEarned = 0; for (uint i = 0; i < stakerStakedContracts[_stakerAddress].length; i++) { totalCommissionEarned = totalCommissionEarned. add(_getStakerEarnedStakeCommission(_stakerAddress, i)); } } /** * @dev Gets total stake commission given to an underwriter * @param _stakerAddress address of staker. * @return totalCommissionEarned total commission earned by staker. */ function getStakerTotalReedmedStakeCommission( address _stakerAddress ) public view returns (uint totalCommissionRedeemed) { totalCommissionRedeemed = 0; for (uint i = 0; i < stakerStakedContracts[_stakerAddress].length; i++) { totalCommissionRedeemed = totalCommissionRedeemed.add( _getStakerRedeemedStakeCommission(_stakerAddress, i)); } } /** * @dev set flag to deposit/ undeposit cover note * against a cover Id * @param coverId coverId of Cover * @param flag true/false for deposit/undeposit */ function setDepositCN(uint coverId, bool flag) public onlyInternal { if (flag == true) { require(!depositedCN[coverId].isDeposited, "Cover note already deposited"); } depositedCN[coverId].isDeposited = flag; } /** * @dev set locked cover note amount * against a cover Id * @param coverId coverId of Cover * @param amount amount of nxm to be locked */ function setDepositCNAmount(uint coverId, uint amount) public onlyInternal { depositedCN[coverId].amount = amount; } /** * @dev to get the staker address on a staked contract * @param _stakedContractAddress is the address of the staked contract in concern * @param _stakedContractIndex is the index of staked contract's index * @return address of staker */ function getStakedContractStakerByIndex( address _stakedContractAddress, uint _stakedContractIndex ) public view returns (address stakerAddress) { stakerAddress = stakedContractStakers[ _stakedContractAddress][_stakedContractIndex].stakerAddress; } /** * @dev to get the length of stakers on a staked contract * @param _stakedContractAddress is the address of the staked contract in concern * @return length in concern */ function getStakedContractStakersLength( address _stakedContractAddress ) public view returns (uint length) { length = stakedContractStakers[_stakedContractAddress].length; } /** * @dev Adds a new stake record. * @param _stakerAddress staker address. * @param _stakedContractAddress smart contract address. * @param _amount amountof NXM to be staked. */ function addStake( address _stakerAddress, address _stakedContractAddress, uint _amount ) public onlyInternal returns (uint scIndex) { scIndex = (stakedContractStakers[_stakedContractAddress].push( Staker(_stakerAddress, stakerStakedContracts[_stakerAddress].length))).sub(1); stakerStakedContracts[_stakerAddress].push( Stake(_stakedContractAddress, scIndex, now, _amount, 0, 0, 0)); } /** * @dev books the user's tokens for maintaining Assessor Velocity, * i.e. once a token is used to cast a vote as a Claims assessor, * @param _of user's address. */ function bookCATokens(address _of) public onlyInternal { require(!isCATokensBooked(_of), "Tokens already booked"); isBookedTokens[_of] = now.add(bookTime); } /** * @dev to know if claim assessor's tokens are booked or not * @param _of is the claim assessor's address in concern * @return boolean representing the status of tokens booked */ function isCATokensBooked(address _of) public view returns (bool res) { if (now < isBookedTokens[_of]) res = true; } /** * @dev Sets the index which will receive commission. * @param _stakedContractAddress smart contract address. * @param _index current index. */ function setStakedContractCurrentCommissionIndex( address _stakedContractAddress, uint _index ) public onlyInternal { stakedContractCurrentCommissionIndex[_stakedContractAddress] = _index; } /** * @dev Sets the last complete commission index * @param _stakerAddress smart contract address. * @param _index current index. */ function setLastCompletedStakeCommissionIndex( address _stakerAddress, uint _index ) public onlyInternal { lastCompletedStakeCommission[_stakerAddress] = _index; } /** * @dev Sets the index till which commission is distrubuted. * @param _stakedContractAddress smart contract address. * @param _index current index. */ function setStakedContractCurrentBurnIndex( address _stakedContractAddress, uint _index ) public onlyInternal { stakedContractCurrentBurnIndex[_stakedContractAddress] = _index; } /** * @dev Updates Uint Parameters of a code * @param code whose details we want to update * @param val value to set */ function updateUintParameters(bytes8 code, uint val) public { require(ms.checkIsAuthToGoverned(msg.sender)); if (code == "TOKEXP") { _setTokenExponent(val); } else if (code == "TOKSTEP") { _setPriceStep(val); } else if (code == "RALOCKT") { _changeSCValidDays(val); } else if (code == "RACOMM") { _setStakerCommissionPer(val); } else if (code == "RAMAXC") { _setStakerMaxCommissionPer(val); } else if (code == "CABOOKT") { _changeBookTime(val * 1 hours); } else if (code == "CALOCKT") { _changelockCADays(val * 1 days); } else if (code == "MVLOCKT") { _changelockMVDays(val * 1 days); } else if (code == "QUOLOCKT") { _setLockTokenTimeAfterCoverExp(val * 1 days); } else if (code == "JOINFEE") { _setJoiningFee(val); } else { revert("Invalid param code"); } } /** * @dev Internal function to get stake commission given to an * underwriter for particular stakedcontract on given index. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker commission. */ function _getStakerEarnedStakeCommission( address _stakerAddress, uint _stakerIndex ) internal view returns (uint amount) { uint _stakedContractIndex; address _stakedContractAddress; _stakedContractAddress = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakedContractAddress; _stakedContractIndex = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakedContractIndex; amount = stakedContractStakeCommission[ _stakedContractAddress][_stakedContractIndex].commissionEarned; } /** * @dev Internal function to get stake commission redeemed by an * underwriter for particular stakedcontract on given index. * @param _stakerAddress address of staker. * @param _stakerIndex index of the staker commission. */ function _getStakerRedeemedStakeCommission( address _stakerAddress, uint _stakerIndex ) internal view returns (uint amount) { uint _stakedContractIndex; address _stakedContractAddress; _stakedContractAddress = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakedContractAddress; _stakedContractIndex = stakerStakedContracts[ _stakerAddress][_stakerIndex].stakedContractIndex; amount = stakedContractStakeCommission[ _stakedContractAddress][_stakedContractIndex].commissionRedeemed; } /** * @dev to set the percentage of staker commission * @param _val is new percentage value */ function _setStakerCommissionPer(uint _val) internal { stakerCommissionPer = _val; } /** * @dev to set the max percentage of staker commission * @param _val is new percentage value */ function _setStakerMaxCommissionPer(uint _val) internal { stakerMaxCommissionPer = _val; } /** * @dev to set the token exponent value * @param _val is new value */ function _setTokenExponent(uint _val) internal { tokenExponent = _val; } /** * @dev to set the price step * @param _val is new value */ function _setPriceStep(uint _val) internal { priceStep = _val; } /** * @dev Changes number of days for which NXM needs to staked in case of underwriting */ function _changeSCValidDays(uint _days) internal { scValidDays = _days; } /** * @dev Changes the time period up to which tokens will be locked. * Used to generate the validity period of tokens booked by * a user for participating in claim's assessment/claim's voting. */ function _changeBookTime(uint _time) internal { bookTime = _time; } /** * @dev Changes lock CA days - number of days for which tokens * are locked while submitting a vote. */ function _changelockCADays(uint _val) internal { lockCADays = _val; } /** * @dev Changes lock MV days - number of days for which tokens are locked * while submitting a vote. */ function _changelockMVDays(uint _val) internal { lockMVDays = _val; } /** * @dev Changes extra lock period for a cover, post its expiry. */ function _setLockTokenTimeAfterCoverExp(uint time) internal { lockTokenTimeAfterCoverExp = time; } /** * @dev Set the joining fee for membership */ function _setJoiningFee(uint _amount) internal { joiningFee = _amount; } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../interfaces/IPooledStaking.sol"; import "../cover/QuotationData.sol"; import "./NXMToken.sol"; import "./TokenController.sol"; import "./TokenData.sol"; contract TokenFunctions is Iupgradable { using SafeMath for uint; NXMToken public tk; TokenController public tc; TokenData public td; QuotationData public qd; IPooledStaking public pooledStaking; event BurnCATokens(uint claimId, address addr, uint amount); /** * @dev Rewards stakers on purchase of cover on smart contract. * @param _contractAddress smart contract address. * @param _coverPriceNXM cover price in NXM. */ function pushStakerRewards(address _contractAddress, uint _coverPriceNXM) external onlyInternal { uint rewardValue = _coverPriceNXM.mul(td.stakerCommissionPer()).div(100); pooledStaking.accumulateReward(_contractAddress, rewardValue); } /** * @dev Returns amount of NXM Tokens locked as Cover Note for given coverId. * @param _of address of the coverHolder. * @param _coverId coverId of the cover. */ function getUserLockedCNTokens(address _of, uint _coverId) external view returns (uint) { return _getUserLockedCNTokens(_of, _coverId); } /** * @dev to get the all the cover locked tokens of a user * @param _of is the user address in concern * @return amount locked */ function getUserAllLockedCNTokens(address _of) external view returns (uint amount) { for (uint i = 0; i < qd.getUserCoverLength(_of); i++) { amount = amount.add(_getUserLockedCNTokens(_of, qd.getAllCoversOfUser(_of)[i])); } } /** * @dev Returns amount of NXM Tokens locked as Cover Note against given coverId. * @param _coverId coverId of the cover. */ function getLockedCNAgainstCover(uint _coverId) external view returns (uint) { return _getLockedCNAgainstCover(_coverId); } /** * @dev Change Dependent Contract Address */ function changeDependentContractAddress() public { tk = NXMToken(ms.tokenAddress()); td = TokenData(ms.getLatestAddress("TD")); tc = TokenController(ms.getLatestAddress("TC")); qd = QuotationData(ms.getLatestAddress("QD")); pooledStaking = IPooledStaking(ms.getLatestAddress("PS")); } /** * @dev Set the flag to check if cover note is deposited against the cover id * @param coverId Cover Id. */ function depositCN(uint coverId) public onlyInternal returns (bool success) { require(_getLockedCNAgainstCover(coverId) > 0, "No cover note available"); td.setDepositCN(coverId, true); success = true; } /** * @param _of address of Member * @param _coverId Cover Id * @param _lockTime Pending Time + Cover Period 7*1 days */ function extendCNEPOff(address _of, uint _coverId, uint _lockTime) public onlyInternal { uint timeStamp = now.add(_lockTime); uint coverValidUntil = qd.getValidityOfCover(_coverId); if (timeStamp >= coverValidUntil) { bytes32 reason = keccak256(abi.encodePacked("CN", _of, _coverId)); tc.extendLockOf(_of, reason, timeStamp); } } /** * @dev to burn the deposited cover tokens * @param coverId is id of cover whose tokens have to be burned * @return the status of the successful burning */ function burnDepositCN(uint coverId) public onlyInternal returns (bool success) { address _of = qd.getCoverMemberAddress(coverId); uint amount; (amount,) = td.depositedCN(coverId); amount = (amount.mul(50)).div(100); bytes32 reason = keccak256(abi.encodePacked("CN", _of, coverId)); tc.burnLockedTokens(_of, reason, amount); success = true; } /** * @dev Unlocks covernote locked against a given cover * @param coverId id of cover */ function unlockCN(uint coverId) public onlyInternal { (, bool isDeposited) = td.depositedCN(coverId); require(!isDeposited, "Cover note is deposited and can not be released"); uint lockedCN = _getLockedCNAgainstCover(coverId); if (lockedCN != 0) { address coverHolder = qd.getCoverMemberAddress(coverId); bytes32 reason = keccak256(abi.encodePacked("CN", coverHolder, coverId)); tc.releaseLockedTokens(coverHolder, reason, lockedCN); } } /** * @dev Burns tokens used for fraudulent voting against a claim * @param claimid Claim Id. * @param _value number of tokens to be burned * @param _of Claim Assessor's address. */ function burnCAToken(uint claimid, uint _value, address _of) public { require(ms.checkIsAuthToGoverned(msg.sender)); tc.burnLockedTokens(_of, "CLA", _value); emit BurnCATokens(claimid, _of, _value); } /** * @dev to lock cover note tokens * @param coverNoteAmount is number of tokens to be locked * @param coverPeriod is cover period in concern * @param coverId is the cover id of cover in concern * @param _of address whose tokens are to be locked */ function lockCN( uint coverNoteAmount, uint coverPeriod, uint coverId, address _of ) public onlyInternal { uint validity = (coverPeriod * 1 days).add(td.lockTokenTimeAfterCoverExp()); bytes32 reason = keccak256(abi.encodePacked("CN", _of, coverId)); td.setDepositCNAmount(coverId, coverNoteAmount); tc.lockOf(_of, reason, coverNoteAmount, validity); } /** * @dev to check if a member is locked for member vote * @param _of is the member address in concern * @return the boolean status */ function isLockedForMemberVote(address _of) public view returns (bool) { return now < tk.isLockedForMV(_of); } /** * @dev Returns amount of NXM Tokens locked as Cover Note for given coverId. * @param _coverId coverId of the cover. */ function _getLockedCNAgainstCover(uint _coverId) internal view returns (uint) { address coverHolder = qd.getCoverMemberAddress(_coverId); bytes32 reason = keccak256(abi.encodePacked("CN", coverHolder, _coverId)); return tc.tokensLockedAtTime(coverHolder, reason, now); } /** * @dev Returns amount of NXM Tokens locked as Cover Note for given coverId. * @param _of address of the coverHolder. * @param _coverId coverId of the cover. */ function _getUserLockedCNTokens(address _of, uint _coverId) internal view returns (uint) { bytes32 reason = keccak256(abi.encodePacked("CN", _of, _coverId)); return tc.tokensLockedAtTime(_of, reason, now); } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../abstract/Iupgradable.sol"; contract QuotationData is Iupgradable { using SafeMath for uint; enum HCIDStatus {NA, kycPending, kycPass, kycFailedOrRefunded, kycPassNoCover} enum CoverStatus {Active, ClaimAccepted, ClaimDenied, CoverExpired, ClaimSubmitted, Requested} struct Cover { address payable memberAddress; bytes4 currencyCode; uint sumAssured; uint16 coverPeriod; uint validUntil; address scAddress; uint premiumNXM; } struct HoldCover { uint holdCoverId; address payable userAddress; address scAddress; bytes4 coverCurr; uint[] coverDetails; uint16 coverPeriod; } address public authQuoteEngine; mapping(bytes4 => uint) internal currencyCSA; mapping(address => uint[]) internal userCover; mapping(address => uint[]) public userHoldedCover; mapping(address => bool) public refundEligible; mapping(address => mapping(bytes4 => uint)) internal currencyCSAOfSCAdd; mapping(uint => uint8) public coverStatus; mapping(uint => uint) public holdedCoverIDStatus; mapping(uint => bool) public timestampRepeated; Cover[] internal allCovers; HoldCover[] internal allCoverHolded; uint public stlp; uint public stl; uint public pm; uint public minDays; uint public tokensRetained; address public kycAuthAddress; event CoverDetailsEvent( uint indexed cid, address scAdd, uint sumAssured, uint expiry, uint premium, uint premiumNXM, bytes4 curr ); event CoverStatusEvent(uint indexed cid, uint8 statusNum); constructor(address _authQuoteAdd, address _kycAuthAdd) public { authQuoteEngine = _authQuoteAdd; kycAuthAddress = _kycAuthAdd; stlp = 90; stl = 100; pm = 30; minDays = 30; tokensRetained = 10; allCovers.push(Cover(address(0), "0x00", 0, 0, 0, address(0), 0)); uint[] memory arr = new uint[](1); allCoverHolded.push(HoldCover(0, address(0), address(0), 0x00, arr, 0)); } /// @dev Adds the amount in Total Sum Assured of a given currency of a given smart contract address. /// @param _add Smart Contract Address. /// @param _amount Amount to be added. function addInTotalSumAssuredSC(address _add, bytes4 _curr, uint _amount) external onlyInternal { currencyCSAOfSCAdd[_add][_curr] = currencyCSAOfSCAdd[_add][_curr].add(_amount); } /// @dev Subtracts the amount from Total Sum Assured of a given currency and smart contract address. /// @param _add Smart Contract Address. /// @param _amount Amount to be subtracted. function subFromTotalSumAssuredSC(address _add, bytes4 _curr, uint _amount) external onlyInternal { currencyCSAOfSCAdd[_add][_curr] = currencyCSAOfSCAdd[_add][_curr].sub(_amount); } /// @dev Subtracts the amount from Total Sum Assured of a given currency. /// @param _curr Currency Name. /// @param _amount Amount to be subtracted. function subFromTotalSumAssured(bytes4 _curr, uint _amount) external onlyInternal { currencyCSA[_curr] = currencyCSA[_curr].sub(_amount); } /// @dev Adds the amount in Total Sum Assured of a given currency. /// @param _curr Currency Name. /// @param _amount Amount to be added. function addInTotalSumAssured(bytes4 _curr, uint _amount) external onlyInternal { currencyCSA[_curr] = currencyCSA[_curr].add(_amount); } /// @dev sets bit for timestamp to avoid replay attacks. function setTimestampRepeated(uint _timestamp) external onlyInternal { timestampRepeated[_timestamp] = true; } /// @dev Creates a blank new cover. function addCover( uint16 _coverPeriod, uint _sumAssured, address payable _userAddress, bytes4 _currencyCode, address _scAddress, uint premium, uint premiumNXM ) external onlyInternal { uint expiryDate = now.add(uint(_coverPeriod).mul(1 days)); allCovers.push(Cover(_userAddress, _currencyCode, _sumAssured, _coverPeriod, expiryDate, _scAddress, premiumNXM)); uint cid = allCovers.length.sub(1); userCover[_userAddress].push(cid); emit CoverDetailsEvent(cid, _scAddress, _sumAssured, expiryDate, premium, premiumNXM, _currencyCode); } /// @dev create holded cover which will process after verdict of KYC. function addHoldCover( address payable from, address scAddress, bytes4 coverCurr, uint[] calldata coverDetails, uint16 coverPeriod ) external onlyInternal { uint holdedCoverLen = allCoverHolded.length; holdedCoverIDStatus[holdedCoverLen] = uint(HCIDStatus.kycPending); allCoverHolded.push(HoldCover(holdedCoverLen, from, scAddress, coverCurr, coverDetails, coverPeriod)); userHoldedCover[from].push(allCoverHolded.length.sub(1)); } ///@dev sets refund eligible bit. ///@param _add user address. ///@param status indicates if user have pending kyc. function setRefundEligible(address _add, bool status) external onlyInternal { refundEligible[_add] = status; } /// @dev to set current status of particular holded coverID (1 for not completed KYC, /// 2 for KYC passed, 3 for failed KYC or full refunded, /// 4 for KYC completed but cover not processed) function setHoldedCoverIDStatus(uint holdedCoverID, uint status) external onlyInternal { holdedCoverIDStatus[holdedCoverID] = status; } /** * @dev to set address of kyc authentication * @param _add is the new address */ function setKycAuthAddress(address _add) external onlyInternal { kycAuthAddress = _add; } /// @dev Changes authorised address for generating quote off chain. function changeAuthQuoteEngine(address _add) external onlyInternal { authQuoteEngine = _add; } /** * @dev Gets Uint Parameters of a code * @param code whose details we want * @return string value of the code * @return associated amount (time or perc or value) to the code */ function getUintParameters(bytes8 code) external view returns (bytes8 codeVal, uint val) { codeVal = code; if (code == "STLP") { val = stlp; } else if (code == "STL") { val = stl; } else if (code == "PM") { val = pm; } else if (code == "QUOMIND") { val = minDays; } else if (code == "QUOTOK") { val = tokensRetained; } } /// @dev Gets Product details. /// @return _minDays minimum cover period. /// @return _PM Profit margin. /// @return _STL short term Load. /// @return _STLP short term load period. function getProductDetails() external view returns ( uint _minDays, uint _pm, uint _stl, uint _stlp ) { _minDays = minDays; _pm = pm; _stl = stl; _stlp = stlp; } /// @dev Gets total number covers created till date. function getCoverLength() external view returns (uint len) { return (allCovers.length); } /// @dev Gets Authorised Engine address. function getAuthQuoteEngine() external view returns (address _add) { _add = authQuoteEngine; } /// @dev Gets the Total Sum Assured amount of a given currency. function getTotalSumAssured(bytes4 _curr) external view returns (uint amount) { amount = currencyCSA[_curr]; } /// @dev Gets all the Cover ids generated by a given address. /// @param _add User's address. /// @return allCover array of covers. function getAllCoversOfUser(address _add) external view returns (uint[] memory allCover) { return (userCover[_add]); } /// @dev Gets total number of covers generated by a given address function getUserCoverLength(address _add) external view returns (uint len) { len = userCover[_add].length; } /// @dev Gets the status of a given cover. function getCoverStatusNo(uint _cid) external view returns (uint8) { return coverStatus[_cid]; } /// @dev Gets the Cover Period (in days) of a given cover. function getCoverPeriod(uint _cid) external view returns (uint32 cp) { cp = allCovers[_cid].coverPeriod; } /// @dev Gets the Sum Assured Amount of a given cover. function getCoverSumAssured(uint _cid) external view returns (uint sa) { sa = allCovers[_cid].sumAssured; } /// @dev Gets the Currency Name in which a given cover is assured. function getCurrencyOfCover(uint _cid) external view returns (bytes4 curr) { curr = allCovers[_cid].currencyCode; } /// @dev Gets the validity date (timestamp) of a given cover. function getValidityOfCover(uint _cid) external view returns (uint date) { date = allCovers[_cid].validUntil; } /// @dev Gets Smart contract address of cover. function getscAddressOfCover(uint _cid) external view returns (uint, address) { return (_cid, allCovers[_cid].scAddress); } /// @dev Gets the owner address of a given cover. function getCoverMemberAddress(uint _cid) external view returns (address payable _add) { _add = allCovers[_cid].memberAddress; } /// @dev Gets the premium amount of a given cover in NXM. function getCoverPremiumNXM(uint _cid) external view returns (uint _premiumNXM) { _premiumNXM = allCovers[_cid].premiumNXM; } /// @dev Provides the details of a cover Id /// @param _cid cover Id /// @return memberAddress cover user address. /// @return scAddress smart contract Address /// @return currencyCode currency of cover /// @return sumAssured sum assured of cover /// @return premiumNXM premium in NXM function getCoverDetailsByCoverID1( uint _cid ) external view returns ( uint cid, address _memberAddress, address _scAddress, bytes4 _currencyCode, uint _sumAssured, uint premiumNXM ) { return ( _cid, allCovers[_cid].memberAddress, allCovers[_cid].scAddress, allCovers[_cid].currencyCode, allCovers[_cid].sumAssured, allCovers[_cid].premiumNXM ); } /// @dev Provides details of a cover Id /// @param _cid cover Id /// @return status status of cover. /// @return sumAssured Sum assurance of cover. /// @return coverPeriod Cover Period of cover (in days). /// @return validUntil is validity of cover. function getCoverDetailsByCoverID2( uint _cid ) external view returns ( uint cid, uint8 status, uint sumAssured, uint16 coverPeriod, uint validUntil ) { return ( _cid, coverStatus[_cid], allCovers[_cid].sumAssured, allCovers[_cid].coverPeriod, allCovers[_cid].validUntil ); } /// @dev Provides details of a holded cover Id /// @param _hcid holded cover Id /// @return scAddress SmartCover address of cover. /// @return coverCurr currency of cover. /// @return coverPeriod Cover Period of cover (in days). function getHoldedCoverDetailsByID1( uint _hcid ) external view returns ( uint hcid, address scAddress, bytes4 coverCurr, uint16 coverPeriod ) { return ( _hcid, allCoverHolded[_hcid].scAddress, allCoverHolded[_hcid].coverCurr, allCoverHolded[_hcid].coverPeriod ); } /// @dev Gets total number holded covers created till date. function getUserHoldedCoverLength(address _add) external view returns (uint) { return userHoldedCover[_add].length; } /// @dev Gets holded cover index by index of user holded covers. function getUserHoldedCoverByIndex(address _add, uint index) external view returns (uint) { return userHoldedCover[_add][index]; } /// @dev Provides the details of a holded cover Id /// @param _hcid holded cover Id /// @return memberAddress holded cover user address. /// @return coverDetails array contains SA, Cover Currency Price,Price in NXM, Expiration time of Qoute. function getHoldedCoverDetailsByID2( uint _hcid ) external view returns ( uint hcid, address payable memberAddress, uint[] memory coverDetails ) { return ( _hcid, allCoverHolded[_hcid].userAddress, allCoverHolded[_hcid].coverDetails ); } /// @dev Gets the Total Sum Assured amount of a given currency and smart contract address. function getTotalSumAssuredSC(address _add, bytes4 _curr) external view returns (uint amount) { amount = currencyCSAOfSCAdd[_add][_curr]; } //solhint-disable-next-line function changeDependentContractAddress() public {} /// @dev Changes the status of a given cover. /// @param _cid cover Id. /// @param _stat New status. function changeCoverStatusNo(uint _cid, uint8 _stat) public onlyInternal { coverStatus[_cid] = _stat; emit CoverStatusEvent(_cid, _stat); } /** * @dev Updates Uint Parameters of a code * @param code whose details we want to update * @param val value to set */ function updateUintParameters(bytes8 code, uint val) public { require(ms.checkIsAuthToGoverned(msg.sender)); if (code == "STLP") { _changeSTLP(val); } else if (code == "STL") { _changeSTL(val); } else if (code == "PM") { _changePM(val); } else if (code == "QUOMIND") { _changeMinDays(val); } else if (code == "QUOTOK") { _setTokensRetained(val); } else { revert("Invalid param code"); } } /// @dev Changes the existing Profit Margin value function _changePM(uint _pm) internal { pm = _pm; } /// @dev Changes the existing Short Term Load Period (STLP) value. function _changeSTLP(uint _stlp) internal { stlp = _stlp; } /// @dev Changes the existing Short Term Load (STL) value. function _changeSTL(uint _stl) internal { stl = _stl; } /// @dev Changes the existing Minimum cover period (in days) function _changeMinDays(uint _days) internal { minDays = _days; } /** * @dev to set the the amount of tokens retained * @param val is the amount retained */ function _setTokensRetained(uint val) internal { tokensRetained = val; } }
/* Copyright (C) 2017 GovBlocks.io 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.5.0; import "../../abstract/Iupgradable.sol"; import "./MemberRoles.sol"; import "./external/Governed.sol"; import "./external/IProposalCategory.sol"; contract ProposalCategory is Governed, IProposalCategory, Iupgradable { bool public constructorCheck; MemberRoles internal mr; struct CategoryStruct { uint memberRoleToVote; uint majorityVotePerc; uint quorumPerc; uint[] allowedToCreateProposal; uint closingTime; uint minStake; } struct CategoryAction { uint defaultIncentive; address contractAddress; bytes2 contractName; } CategoryStruct[] internal allCategory; mapping(uint => CategoryAction) internal categoryActionData; mapping(uint => uint) public categoryABReq; mapping(uint => uint) public isSpecialResolution; mapping(uint => bytes) public categoryActionHashes; bool public categoryActionHashUpdated; /** * @dev Adds new category (Discontinued, moved functionality to newCategory) * @param _name Category name * @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. * @param _majorityVotePerc Majority Vote threshold for Each voting layer * @param _quorumPerc minimum threshold percentage required in voting to calculate result * @param _allowedToCreateProposal Member roles allowed to create the proposal * @param _closingTime Vote closing time for Each voting layer * @param _actionHash hash of details containing the action that has to be performed after proposal is accepted * @param _contractAddress address of contract to call after proposal is accepted * @param _contractName name of contract to be called after proposal is accepted * @param _incentives rewards to distributed after proposal is accepted */ function addCategory( string calldata _name, uint _memberRoleToVote, uint _majorityVotePerc, uint _quorumPerc, uint[] calldata _allowedToCreateProposal, uint _closingTime, string calldata _actionHash, address _contractAddress, bytes2 _contractName, uint[] calldata _incentives ) external {} /** * @dev Initiates Default settings for Proposal Category contract (Adding default categories) */ function proposalCategoryInitiate() external {} /** * @dev Initiates Default action function hashes for existing categories * To be called after the contract has been upgraded by governance */ function updateCategoryActionHashes() external onlyOwner { require(!categoryActionHashUpdated, "Category action hashes already updated"); categoryActionHashUpdated = true; categoryActionHashes[1] = abi.encodeWithSignature("addRole(bytes32,string,address)"); categoryActionHashes[2] = abi.encodeWithSignature("updateRole(address,uint256,bool)"); categoryActionHashes[3] = abi.encodeWithSignature("newCategory(string,uint256,uint256,uint256,uint256[],uint256,string,address,bytes2,uint256[],string)"); // solhint-disable-line categoryActionHashes[4] = abi.encodeWithSignature("editCategory(uint256,string,uint256,uint256,uint256,uint256[],uint256,string,address,bytes2,uint256[],string)"); // solhint-disable-line categoryActionHashes[5] = abi.encodeWithSignature("upgradeContractImplementation(bytes2,address)"); categoryActionHashes[6] = abi.encodeWithSignature("startEmergencyPause()"); categoryActionHashes[7] = abi.encodeWithSignature("addEmergencyPause(bool,bytes4)"); categoryActionHashes[8] = abi.encodeWithSignature("burnCAToken(uint256,uint256,address)"); categoryActionHashes[9] = abi.encodeWithSignature("setUserClaimVotePausedOn(address)"); categoryActionHashes[12] = abi.encodeWithSignature("transferEther(uint256,address)"); categoryActionHashes[13] = abi.encodeWithSignature("addInvestmentAssetCurrency(bytes4,address,bool,uint64,uint64,uint8)"); // solhint-disable-line categoryActionHashes[14] = abi.encodeWithSignature("changeInvestmentAssetHoldingPerc(bytes4,uint64,uint64)"); categoryActionHashes[15] = abi.encodeWithSignature("changeInvestmentAssetStatus(bytes4,bool)"); categoryActionHashes[16] = abi.encodeWithSignature("swapABMember(address,address)"); categoryActionHashes[17] = abi.encodeWithSignature("addCurrencyAssetCurrency(bytes4,address,uint256)"); categoryActionHashes[20] = abi.encodeWithSignature("updateUintParameters(bytes8,uint256)"); categoryActionHashes[21] = abi.encodeWithSignature("updateUintParameters(bytes8,uint256)"); categoryActionHashes[22] = abi.encodeWithSignature("updateUintParameters(bytes8,uint256)"); categoryActionHashes[23] = abi.encodeWithSignature("updateUintParameters(bytes8,uint256)"); categoryActionHashes[24] = abi.encodeWithSignature("updateUintParameters(bytes8,uint256)"); categoryActionHashes[25] = abi.encodeWithSignature("updateUintParameters(bytes8,uint256)"); categoryActionHashes[26] = abi.encodeWithSignature("updateUintParameters(bytes8,uint256)"); categoryActionHashes[27] = abi.encodeWithSignature("updateAddressParameters(bytes8,address)"); categoryActionHashes[28] = abi.encodeWithSignature("updateOwnerParameters(bytes8,address)"); categoryActionHashes[29] = abi.encodeWithSignature("upgradeMultipleContracts(bytes2[],address[])"); categoryActionHashes[30] = abi.encodeWithSignature("changeCurrencyAssetAddress(bytes4,address)"); categoryActionHashes[31] = abi.encodeWithSignature("changeCurrencyAssetBaseMin(bytes4,uint256)"); categoryActionHashes[32] = abi.encodeWithSignature("changeInvestmentAssetAddressAndDecimal(bytes4,address,uint8)"); // solhint-disable-line categoryActionHashes[33] = abi.encodeWithSignature("externalLiquidityTrade()"); } /** * @dev Gets Total number of categories added till now */ function totalCategories() external view returns (uint) { return allCategory.length; } /** * @dev Gets category details */ function category(uint _categoryId) external view returns (uint, uint, uint, uint, uint[] memory, uint, uint) { return ( _categoryId, allCategory[_categoryId].memberRoleToVote, allCategory[_categoryId].majorityVotePerc, allCategory[_categoryId].quorumPerc, allCategory[_categoryId].allowedToCreateProposal, allCategory[_categoryId].closingTime, allCategory[_categoryId].minStake ); } /** * @dev Gets category ab required and isSpecialResolution * @return the category id * @return if AB voting is required * @return is category a special resolution */ function categoryExtendedData(uint _categoryId) external view returns (uint, uint, uint) { return ( _categoryId, categoryABReq[_categoryId], isSpecialResolution[_categoryId] ); } /** * @dev Gets the category acion details * @param _categoryId is the category id in concern * @return the category id * @return the contract address * @return the contract name * @return the default incentive */ function categoryAction(uint _categoryId) external view returns (uint, address, bytes2, uint) { return ( _categoryId, categoryActionData[_categoryId].contractAddress, categoryActionData[_categoryId].contractName, categoryActionData[_categoryId].defaultIncentive ); } /** * @dev Gets the category acion details of a category id * @param _categoryId is the category id in concern * @return the category id * @return the contract address * @return the contract name * @return the default incentive * @return action function hash */ function categoryActionDetails(uint _categoryId) external view returns (uint, address, bytes2, uint, bytes memory) { return ( _categoryId, categoryActionData[_categoryId].contractAddress, categoryActionData[_categoryId].contractName, categoryActionData[_categoryId].defaultIncentive, categoryActionHashes[_categoryId] ); } /** * @dev Updates dependant contract addresses */ function changeDependentContractAddress() public { mr = MemberRoles(ms.getLatestAddress("MR")); } /** * @dev Adds new category * @param _name Category name * @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. * @param _majorityVotePerc Majority Vote threshold for Each voting layer * @param _quorumPerc minimum threshold percentage required in voting to calculate result * @param _allowedToCreateProposal Member roles allowed to create the proposal * @param _closingTime Vote closing time for Each voting layer * @param _actionHash hash of details containing the action that has to be performed after proposal is accepted * @param _contractAddress address of contract to call after proposal is accepted * @param _contractName name of contract to be called after proposal is accepted * @param _incentives rewards to distributed after proposal is accepted * @param _functionHash function signature to be executed */ function newCategory( string memory _name, uint _memberRoleToVote, uint _majorityVotePerc, uint _quorumPerc, uint[] memory _allowedToCreateProposal, uint _closingTime, string memory _actionHash, address _contractAddress, bytes2 _contractName, uint[] memory _incentives, string memory _functionHash ) public onlyAuthorizedToGovern { require(_quorumPerc <= 100 && _majorityVotePerc <= 100, "Invalid percentage"); require((_contractName == "EX" && _contractAddress == address(0)) || bytes(_functionHash).length > 0); require(_incentives[3] <= 1, "Invalid special resolution flag"); //If category is special resolution role authorized should be member if (_incentives[3] == 1) { require(_memberRoleToVote == uint(MemberRoles.Role.Member)); _majorityVotePerc = 0; _quorumPerc = 0; } _addCategory( _name, _memberRoleToVote, _majorityVotePerc, _quorumPerc, _allowedToCreateProposal, _closingTime, _actionHash, _contractAddress, _contractName, _incentives ); if (bytes(_functionHash).length > 0 && abi.encodeWithSignature(_functionHash).length == 4) { categoryActionHashes[allCategory.length - 1] = abi.encodeWithSignature(_functionHash); } } /** * @dev Changes the master address and update it's instance * @param _masterAddress is the new master address */ function changeMasterAddress(address _masterAddress) public { if (masterAddress != address(0)) require(masterAddress == msg.sender); masterAddress = _masterAddress; ms = INXMMaster(_masterAddress); nxMasterAddress = _masterAddress; } /** * @dev Updates category details (Discontinued, moved functionality to editCategory) * @param _categoryId Category id that needs to be updated * @param _name Category name * @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. * @param _allowedToCreateProposal Member roles allowed to create the proposal * @param _majorityVotePerc Majority Vote threshold for Each voting layer * @param _quorumPerc minimum threshold percentage required in voting to calculate result * @param _closingTime Vote closing time for Each voting layer * @param _actionHash hash of details containing the action that has to be performed after proposal is accepted * @param _contractAddress address of contract to call after proposal is accepted * @param _contractName name of contract to be called after proposal is accepted * @param _incentives rewards to distributed after proposal is accepted */ function updateCategory( uint _categoryId, string memory _name, uint _memberRoleToVote, uint _majorityVotePerc, uint _quorumPerc, uint[] memory _allowedToCreateProposal, uint _closingTime, string memory _actionHash, address _contractAddress, bytes2 _contractName, uint[] memory _incentives ) public {} /** * @dev Updates category details * @param _categoryId Category id that needs to be updated * @param _name Category name * @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. * @param _allowedToCreateProposal Member roles allowed to create the proposal * @param _majorityVotePerc Majority Vote threshold for Each voting layer * @param _quorumPerc minimum threshold percentage required in voting to calculate result * @param _closingTime Vote closing time for Each voting layer * @param _actionHash hash of details containing the action that has to be performed after proposal is accepted * @param _contractAddress address of contract to call after proposal is accepted * @param _contractName name of contract to be called after proposal is accepted * @param _incentives rewards to distributed after proposal is accepted * @param _functionHash function signature to be executed */ function editCategory( uint _categoryId, string memory _name, uint _memberRoleToVote, uint _majorityVotePerc, uint _quorumPerc, uint[] memory _allowedToCreateProposal, uint _closingTime, string memory _actionHash, address _contractAddress, bytes2 _contractName, uint[] memory _incentives, string memory _functionHash ) public onlyAuthorizedToGovern { require(_verifyMemberRoles(_memberRoleToVote, _allowedToCreateProposal) == 1, "Invalid Role"); require(_quorumPerc <= 100 && _majorityVotePerc <= 100, "Invalid percentage"); require((_contractName == "EX" && _contractAddress == address(0)) || bytes(_functionHash).length > 0); require(_incentives[3] <= 1, "Invalid special resolution flag"); //If category is special resolution role authorized should be member if (_incentives[3] == 1) { require(_memberRoleToVote == uint(MemberRoles.Role.Member)); _majorityVotePerc = 0; _quorumPerc = 0; } delete categoryActionHashes[_categoryId]; if (bytes(_functionHash).length > 0 && abi.encodeWithSignature(_functionHash).length == 4) { categoryActionHashes[_categoryId] = abi.encodeWithSignature(_functionHash); } allCategory[_categoryId].memberRoleToVote = _memberRoleToVote; allCategory[_categoryId].majorityVotePerc = _majorityVotePerc; allCategory[_categoryId].closingTime = _closingTime; allCategory[_categoryId].allowedToCreateProposal = _allowedToCreateProposal; allCategory[_categoryId].minStake = _incentives[0]; allCategory[_categoryId].quorumPerc = _quorumPerc; categoryActionData[_categoryId].defaultIncentive = _incentives[1]; categoryActionData[_categoryId].contractName = _contractName; categoryActionData[_categoryId].contractAddress = _contractAddress; categoryABReq[_categoryId] = _incentives[2]; isSpecialResolution[_categoryId] = _incentives[3]; emit Category(_categoryId, _name, _actionHash); } /** * @dev Internal call to add new category * @param _name Category name * @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. * @param _majorityVotePerc Majority Vote threshold for Each voting layer * @param _quorumPerc minimum threshold percentage required in voting to calculate result * @param _allowedToCreateProposal Member roles allowed to create the proposal * @param _closingTime Vote closing time for Each voting layer * @param _actionHash hash of details containing the action that has to be performed after proposal is accepted * @param _contractAddress address of contract to call after proposal is accepted * @param _contractName name of contract to be called after proposal is accepted * @param _incentives rewards to distributed after proposal is accepted */ function _addCategory( string memory _name, uint _memberRoleToVote, uint _majorityVotePerc, uint _quorumPerc, uint[] memory _allowedToCreateProposal, uint _closingTime, string memory _actionHash, address _contractAddress, bytes2 _contractName, uint[] memory _incentives ) internal { require(_verifyMemberRoles(_memberRoleToVote, _allowedToCreateProposal) == 1, "Invalid Role"); allCategory.push( CategoryStruct( _memberRoleToVote, _majorityVotePerc, _quorumPerc, _allowedToCreateProposal, _closingTime, _incentives[0] ) ); uint categoryId = allCategory.length - 1; categoryActionData[categoryId] = CategoryAction(_incentives[1], _contractAddress, _contractName); categoryABReq[categoryId] = _incentives[2]; isSpecialResolution[categoryId] = _incentives[3]; emit Category(categoryId, _name, _actionHash); } /** * @dev Internal call to check if given roles are valid or not */ function _verifyMemberRoles(uint _memberRoleToVote, uint[] memory _allowedToCreateProposal) internal view returns (uint) { uint totalRoles = mr.totalRoles(); if (_memberRoleToVote >= totalRoles) { return 0; } for (uint i = 0; i < _allowedToCreateProposal.length; i++) { if (_allowedToCreateProposal[i] >= totalRoles) { return 0; } } return 1; } }
pragma solidity ^0.5.0; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ interface OZIERC20 { function transfer(address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); function totalSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); event Transfer( address indexed from, address indexed to, uint256 value ); event Approval( address indexed owner, address indexed spender, uint256 value ); }
pragma solidity ^0.5.0; /** * @title SafeMath * @dev Math operations with safety checks that revert on error */ library OZSafeMath { /** * @dev Multiplies two numbers, reverts on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // 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-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two numbers truncating the quotient, reverts on division by zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0); // Solidity only automatically asserts when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Adds two numbers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Divides two numbers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } }
pragma solidity ^0.5.0; import "./INXMMaster.sol"; contract Iupgradable { INXMMaster public ms; address public nxMasterAddress; modifier onlyInternal { require(ms.isInternal(msg.sender)); _; } modifier isMemberAndcheckPause { require(ms.isPause() == false && ms.isMember(msg.sender) == true); _; } modifier onlyOwner { require(ms.isOwner(msg.sender)); _; } modifier checkPause { require(ms.isPause() == false); _; } modifier isMember { require(ms.isMember(msg.sender), "Not member"); _; } /** * @dev Iupgradable Interface to update dependent contract address */ function changeDependentContractAddress() public; /** * @dev change master address * @param _masterAddress is the new address */ function changeMasterAddress(address _masterAddress) public { if (address(ms) != address(0)) { require(address(ms) == msg.sender, "Not master"); } ms = INXMMaster(_masterAddress); nxMasterAddress = _masterAddress; } }
pragma solidity ^0.5.0; interface IPooledStaking { function accumulateReward(address contractAddress, uint amount) external; function pushBurn(address contractAddress, uint amount) external; function hasPendingActions() external view returns (bool); function contractStake(address contractAddress) external view returns (uint); function stakerReward(address staker) external view returns (uint); function stakerDeposit(address staker) external view returns (uint); function stakerContractStake(address staker, address contractAddress) external view returns (uint); function withdraw(uint amount) external; function stakerMaxWithdrawable(address stakerAddress) external view returns (uint); function withdrawReward(address stakerAddress) external; }
pragma solidity ^0.5.0; /** * @title ERC1132 interface * @dev see https://github.com/ethereum/EIPs/issues/1132 */ contract IERC1132 { /** * @dev Reasons why a user's tokens have been locked */ mapping(address => bytes32[]) public lockReason; /** * @dev locked token structure */ struct LockToken { uint256 amount; uint256 validity; bool claimed; } /** * @dev Holds number & validity of tokens locked for a given reason for * a specified address */ mapping(address => mapping(bytes32 => LockToken)) public locked; /** * @dev Records data of all the tokens Locked */ event Locked( address indexed _of, bytes32 indexed _reason, uint256 _amount, uint256 _validity ); /** * @dev Records data of all the tokens unlocked */ event Unlocked( address indexed _of, bytes32 indexed _reason, uint256 _amount ); /** * @dev Locks a specified amount of tokens against an address, * for a specified reason and time * @param _reason The reason to lock tokens * @param _amount Number of tokens to be locked * @param _time Lock time in seconds */ function lock(bytes32 _reason, uint256 _amount, uint256 _time) public returns (bool); /** * @dev Returns tokens locked for a specified address for a * specified reason * * @param _of The address whose tokens are locked * @param _reason The reason to query the lock tokens for */ function tokensLocked(address _of, bytes32 _reason) public view returns (uint256 amount); /** * @dev Returns tokens locked for a specified address for a * specified reason at a specific time * * @param _of The address whose tokens are locked * @param _reason The reason to query the lock tokens for * @param _time The timestamp to query the lock tokens for */ function tokensLockedAtTime(address _of, bytes32 _reason, uint256 _time) public view returns (uint256 amount); /** * @dev Returns total tokens held by an address (locked + transferable) * @param _of The address to query the total balance of */ function totalBalanceOf(address _of) public view returns (uint256 amount); /** * @dev Extends lock for a specified reason and time * @param _reason The reason to lock tokens * @param _time Lock extension time in seconds */ function extendLock(bytes32 _reason, uint256 _time) public returns (bool); /** * @dev Increase number of tokens locked for a specified reason * @param _reason The reason to lock tokens * @param _amount Number of tokens to be increased */ function increaseLockAmount(bytes32 _reason, uint256 _amount) public returns (bool); /** * @dev Returns unlockable tokens for a specified address for a specified reason * @param _of The address to query the the unlockable token count of * @param _reason The reason to query the unlockable tokens for */ function tokensUnlockable(address _of, bytes32 _reason) public view returns (uint256 amount); /** * @dev Unlocks the unlockable tokens of a specified address * @param _of Address of user, claiming back unlockable tokens */ function unlock(address _of) public returns (uint256 unlockableTokens); /** * @dev Gets the unlockable tokens of a specified address * @param _of The address to query the the unlockable token count of */ function getUnlockableTokens(address _of) public view returns (uint256 unlockableTokens); }
// /* Copyright (C) 2017 GovBlocks.io // 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../token/TokenController.sol"; import "./MemberRoles.sol"; import "./ProposalCategory.sol"; import "./external/IGovernance.sol"; contract Governance is IGovernance, Iupgradable { using SafeMath for uint; enum ProposalStatus { Draft, AwaitingSolution, VotingStarted, Accepted, Rejected, Majority_Not_Reached_But_Accepted, Denied } struct ProposalData { uint propStatus; uint finalVerdict; uint category; uint commonIncentive; uint dateUpd; address owner; } struct ProposalVote { address voter; uint proposalId; uint dateAdd; } struct VoteTally { mapping(uint => uint) memberVoteValue; mapping(uint => uint) abVoteValue; uint voters; } struct DelegateVote { address follower; address leader; uint lastUpd; } ProposalVote[] internal allVotes; DelegateVote[] public allDelegation; mapping(uint => ProposalData) internal allProposalData; mapping(uint => bytes[]) internal allProposalSolutions; mapping(address => uint[]) internal allVotesByMember; mapping(uint => mapping(address => bool)) public rewardClaimed; mapping(address => mapping(uint => uint)) public memberProposalVote; mapping(address => uint) public followerDelegation; mapping(address => uint) internal followerCount; mapping(address => uint[]) internal leaderDelegation; mapping(uint => VoteTally) public proposalVoteTally; mapping(address => bool) public isOpenForDelegation; mapping(address => uint) public lastRewardClaimed; bool internal constructorCheck; uint public tokenHoldingTime; uint internal roleIdAllowedToCatgorize; uint internal maxVoteWeigthPer; uint internal specialResolutionMajPerc; uint internal maxFollowers; uint internal totalProposals; uint internal maxDraftTime; MemberRoles internal memberRole; ProposalCategory internal proposalCategory; TokenController internal tokenInstance; mapping(uint => uint) public proposalActionStatus; mapping(uint => uint) internal proposalExecutionTime; mapping(uint => mapping(address => bool)) public proposalRejectedByAB; mapping(uint => uint) internal actionRejectedCount; bool internal actionParamsInitialised; uint internal actionWaitingTime; uint constant internal AB_MAJ_TO_REJECT_ACTION = 3; enum ActionStatus { Pending, Accepted, Rejected, Executed, NoAction } /** * @dev Called whenever an action execution is failed. */ event ActionFailed ( uint256 proposalId ); /** * @dev Called whenever an AB member rejects the action execution. */ event ActionRejected ( uint256 indexed proposalId, address rejectedBy ); /** * @dev Checks if msg.sender is proposal owner */ modifier onlyProposalOwner(uint _proposalId) { require(msg.sender == allProposalData[_proposalId].owner, "Not allowed"); _; } /** * @dev Checks if proposal is opened for voting */ modifier voteNotStarted(uint _proposalId) { require(allProposalData[_proposalId].propStatus < uint(ProposalStatus.VotingStarted)); _; } /** * @dev Checks if msg.sender is allowed to create proposal under given category */ modifier isAllowed(uint _categoryId) { require(allowedToCreateProposal(_categoryId), "Not allowed"); _; } /** * @dev Checks if msg.sender is allowed categorize proposal under given category */ modifier isAllowedToCategorize() { require(memberRole.checkRole(msg.sender, roleIdAllowedToCatgorize), "Not allowed"); _; } /** * @dev Checks if msg.sender had any pending rewards to be claimed */ modifier checkPendingRewards { require(getPendingReward(msg.sender) == 0, "Claim reward"); _; } /** * @dev Event emitted whenever a proposal is categorized */ event ProposalCategorized( uint indexed proposalId, address indexed categorizedBy, uint categoryId ); /** * @dev Removes delegation of an address. * @param _add address to undelegate. */ function removeDelegation(address _add) external onlyInternal { _unDelegate(_add); } /** * @dev Creates a new proposal * @param _proposalDescHash Proposal description hash through IPFS having Short and long description of proposal * @param _categoryId This id tells under which the proposal is categorized i.e. Proposal's Objective */ function createProposal( string calldata _proposalTitle, string calldata _proposalSD, string calldata _proposalDescHash, uint _categoryId ) external isAllowed(_categoryId) { require(ms.isMember(msg.sender), "Not Member"); _createProposal(_proposalTitle, _proposalSD, _proposalDescHash, _categoryId); } /** * @dev Edits the details of an existing proposal * @param _proposalId Proposal id that details needs to be updated * @param _proposalDescHash Proposal description hash having long and short description of proposal. */ function updateProposal( uint _proposalId, string calldata _proposalTitle, string calldata _proposalSD, string calldata _proposalDescHash ) external onlyProposalOwner(_proposalId) { require( allProposalSolutions[_proposalId].length < 2, "Not allowed" ); allProposalData[_proposalId].propStatus = uint(ProposalStatus.Draft); allProposalData[_proposalId].category = 0; allProposalData[_proposalId].commonIncentive = 0; emit Proposal( allProposalData[_proposalId].owner, _proposalId, now, _proposalTitle, _proposalSD, _proposalDescHash ); } /** * @dev Categorizes proposal to proceed further. Categories shows the proposal objective. */ function categorizeProposal( uint _proposalId, uint _categoryId, uint _incentive ) external voteNotStarted(_proposalId) isAllowedToCategorize { _categorizeProposal(_proposalId, _categoryId, _incentive); } /** * @dev Submit proposal with solution * @param _proposalId Proposal id * @param _solutionHash Solution hash contains parameters, values and description needed according to proposal */ function submitProposalWithSolution( uint _proposalId, string calldata _solutionHash, bytes calldata _action ) external onlyProposalOwner(_proposalId) { require(allProposalData[_proposalId].propStatus == uint(ProposalStatus.AwaitingSolution)); _proposalSubmission(_proposalId, _solutionHash, _action); } /** * @dev Creates a new proposal with solution * @param _proposalDescHash Proposal description hash through IPFS having Short and long description of proposal * @param _categoryId This id tells under which the proposal is categorized i.e. Proposal's Objective * @param _solutionHash Solution hash contains parameters, values and description needed according to proposal */ function createProposalwithSolution( string calldata _proposalTitle, string calldata _proposalSD, string calldata _proposalDescHash, uint _categoryId, string calldata _solutionHash, bytes calldata _action ) external isAllowed(_categoryId) { uint proposalId = totalProposals; _createProposal(_proposalTitle, _proposalSD, _proposalDescHash, _categoryId); require(_categoryId > 0); _proposalSubmission( proposalId, _solutionHash, _action ); } /** * @dev Submit a vote on the proposal. * @param _proposalId to vote upon. * @param _solutionChosen is the chosen vote. */ function submitVote(uint _proposalId, uint _solutionChosen) external { require(allProposalData[_proposalId].propStatus == uint(Governance.ProposalStatus.VotingStarted), "Not allowed"); require(_solutionChosen < allProposalSolutions[_proposalId].length); _submitVote(_proposalId, _solutionChosen); } /** * @dev Closes the proposal. * @param _proposalId of proposal to be closed. */ function closeProposal(uint _proposalId) external { uint category = allProposalData[_proposalId].category; uint _memberRole; if (allProposalData[_proposalId].dateUpd.add(maxDraftTime) <= now && allProposalData[_proposalId].propStatus < uint(ProposalStatus.VotingStarted)) { _updateProposalStatus(_proposalId, uint(ProposalStatus.Denied)); } else { require(canCloseProposal(_proposalId) == 1); (, _memberRole,,,,,) = proposalCategory.category(allProposalData[_proposalId].category); if (_memberRole == uint(MemberRoles.Role.AdvisoryBoard)) { _closeAdvisoryBoardVote(_proposalId, category); } else { _closeMemberVote(_proposalId, category); } } } /** * @dev Claims reward for member. * @param _memberAddress to claim reward of. * @param _maxRecords maximum number of records to claim reward for. _proposals list of proposals of which reward will be claimed. * @return amount of pending reward. */ function claimReward(address _memberAddress, uint _maxRecords) external returns (uint pendingDAppReward) { uint voteId; address leader; uint lastUpd; require(msg.sender == ms.getLatestAddress("CR")); uint delegationId = followerDelegation[_memberAddress]; DelegateVote memory delegationData = allDelegation[delegationId]; if (delegationId > 0 && delegationData.leader != address(0)) { leader = delegationData.leader; lastUpd = delegationData.lastUpd; } else leader = _memberAddress; uint proposalId; uint totalVotes = allVotesByMember[leader].length; uint lastClaimed = totalVotes; uint j; uint i; for (i = lastRewardClaimed[_memberAddress]; i < totalVotes && j < _maxRecords; i++) { voteId = allVotesByMember[leader][i]; proposalId = allVotes[voteId].proposalId; if (proposalVoteTally[proposalId].voters > 0 && (allVotes[voteId].dateAdd > ( lastUpd.add(tokenHoldingTime)) || leader == _memberAddress)) { if (allProposalData[proposalId].propStatus > uint(ProposalStatus.VotingStarted)) { if (!rewardClaimed[voteId][_memberAddress]) { pendingDAppReward = pendingDAppReward.add( allProposalData[proposalId].commonIncentive.div( proposalVoteTally[proposalId].voters ) ); rewardClaimed[voteId][_memberAddress] = true; j++; } } else { if (lastClaimed == totalVotes) { lastClaimed = i; } } } } if (lastClaimed == totalVotes) { lastRewardClaimed[_memberAddress] = i; } else { lastRewardClaimed[_memberAddress] = lastClaimed; } if (j > 0) { emit RewardClaimed( _memberAddress, pendingDAppReward ); } } /** * @dev Sets delegation acceptance status of individual user * @param _status delegation acceptance status */ function setDelegationStatus(bool _status) external isMemberAndcheckPause checkPendingRewards { isOpenForDelegation[msg.sender] = _status; } /** * @dev Delegates vote to an address. * @param _add is the address to delegate vote to. */ function delegateVote(address _add) external isMemberAndcheckPause checkPendingRewards { require(ms.masterInitialized()); require(allDelegation[followerDelegation[_add]].leader == address(0)); if (followerDelegation[msg.sender] > 0) { require((allDelegation[followerDelegation[msg.sender]].lastUpd).add(tokenHoldingTime) < now); } require(!alreadyDelegated(msg.sender)); require(!memberRole.checkRole(msg.sender, uint(MemberRoles.Role.Owner))); require(!memberRole.checkRole(msg.sender, uint(MemberRoles.Role.AdvisoryBoard))); require(followerCount[_add] < maxFollowers); if (allVotesByMember[msg.sender].length > 0) { require((allVotes[allVotesByMember[msg.sender][allVotesByMember[msg.sender].length - 1]].dateAdd).add(tokenHoldingTime) < now); } require(ms.isMember(_add)); require(isOpenForDelegation[_add]); allDelegation.push(DelegateVote(msg.sender, _add, now)); followerDelegation[msg.sender] = allDelegation.length - 1; leaderDelegation[_add].push(allDelegation.length - 1); followerCount[_add]++; lastRewardClaimed[msg.sender] = allVotesByMember[_add].length; } /** * @dev Undelegates the sender */ function unDelegate() external isMemberAndcheckPause checkPendingRewards { _unDelegate(msg.sender); } /** * @dev Triggers action of accepted proposal after waiting time is finished */ function triggerAction(uint _proposalId) external { require(proposalActionStatus[_proposalId] == uint(ActionStatus.Accepted) && proposalExecutionTime[_proposalId] <= now, "Cannot trigger"); _triggerAction(_proposalId, allProposalData[_proposalId].category); } /** * @dev Provides option to Advisory board member to reject proposal action execution within actionWaitingTime, if found suspicious */ function rejectAction(uint _proposalId) external { require(memberRole.checkRole(msg.sender, uint(MemberRoles.Role.AdvisoryBoard)) && proposalExecutionTime[_proposalId] > now); require(proposalActionStatus[_proposalId] == uint(ActionStatus.Accepted)); require(!proposalRejectedByAB[_proposalId][msg.sender]); require( keccak256(proposalCategory.categoryActionHashes(allProposalData[_proposalId].category)) != keccak256(abi.encodeWithSignature("swapABMember(address,address)")) ); proposalRejectedByAB[_proposalId][msg.sender] = true; actionRejectedCount[_proposalId]++; emit ActionRejected(_proposalId, msg.sender); if (actionRejectedCount[_proposalId] == AB_MAJ_TO_REJECT_ACTION) { proposalActionStatus[_proposalId] = uint(ActionStatus.Rejected); } } /** * @dev Sets intial actionWaitingTime value * To be called after governance implementation has been updated */ function setInitialActionParameters() external onlyOwner { require(!actionParamsInitialised); actionParamsInitialised = true; actionWaitingTime = 24 * 1 hours; } /** * @dev Gets Uint Parameters of a code * @param code whose details we want * @return string value of the code * @return associated amount (time or perc or value) to the code */ function getUintParameters(bytes8 code) external view returns (bytes8 codeVal, uint val) { codeVal = code; if (code == "GOVHOLD") { val = tokenHoldingTime / (1 days); } else if (code == "MAXFOL") { val = maxFollowers; } else if (code == "MAXDRFT") { val = maxDraftTime / (1 days); } else if (code == "EPTIME") { val = ms.pauseTime() / (1 days); } else if (code == "ACWT") { val = actionWaitingTime / (1 hours); } } /** * @dev Gets all details of a propsal * @param _proposalId whose details we want * @return proposalId * @return category * @return status * @return finalVerdict * @return totalReward */ function proposal(uint _proposalId) external view returns ( uint proposalId, uint category, uint status, uint finalVerdict, uint totalRewar ) { return ( _proposalId, allProposalData[_proposalId].category, allProposalData[_proposalId].propStatus, allProposalData[_proposalId].finalVerdict, allProposalData[_proposalId].commonIncentive ); } /** * @dev Gets some details of a propsal * @param _proposalId whose details we want * @return proposalId * @return number of all proposal solutions * @return amount of votes */ function proposalDetails(uint _proposalId) external view returns (uint, uint, uint) { return ( _proposalId, allProposalSolutions[_proposalId].length, proposalVoteTally[_proposalId].voters ); } /** * @dev Gets solution action on a proposal * @param _proposalId whose details we want * @param _solution whose details we want * @return action of a solution on a proposal */ function getSolutionAction(uint _proposalId, uint _solution) external view returns (uint, bytes memory) { return ( _solution, allProposalSolutions[_proposalId][_solution] ); } /** * @dev Gets length of propsal * @return length of propsal */ function getProposalLength() external view returns (uint) { return totalProposals; } /** * @dev Get followers of an address * @return get followers of an address */ function getFollowers(address _add) external view returns (uint[] memory) { return leaderDelegation[_add]; } /** * @dev Gets pending rewards of a member * @param _memberAddress in concern * @return amount of pending reward */ function getPendingReward(address _memberAddress) public view returns (uint pendingDAppReward) { uint delegationId = followerDelegation[_memberAddress]; address leader; uint lastUpd; DelegateVote memory delegationData = allDelegation[delegationId]; if (delegationId > 0 && delegationData.leader != address(0)) { leader = delegationData.leader; lastUpd = delegationData.lastUpd; } else leader = _memberAddress; uint proposalId; for (uint i = lastRewardClaimed[_memberAddress]; i < allVotesByMember[leader].length; i++) { if (allVotes[allVotesByMember[leader][i]].dateAdd > ( lastUpd.add(tokenHoldingTime)) || leader == _memberAddress) { if (!rewardClaimed[allVotesByMember[leader][i]][_memberAddress]) { proposalId = allVotes[allVotesByMember[leader][i]].proposalId; if (proposalVoteTally[proposalId].voters > 0 && allProposalData[proposalId].propStatus > uint(ProposalStatus.VotingStarted)) { pendingDAppReward = pendingDAppReward.add( allProposalData[proposalId].commonIncentive.div( proposalVoteTally[proposalId].voters ) ); } } } } } /** * @dev Updates Uint Parameters of a code * @param code whose details we want to update * @param val value to set */ function updateUintParameters(bytes8 code, uint val) public { require(ms.checkIsAuthToGoverned(msg.sender)); if (code == "GOVHOLD") { tokenHoldingTime = val * 1 days; } else if (code == "MAXFOL") { maxFollowers = val; } else if (code == "MAXDRFT") { maxDraftTime = val * 1 days; } else if (code == "EPTIME") { ms.updatePauseTime(val * 1 days); } else if (code == "ACWT") { actionWaitingTime = val * 1 hours; } else { revert("Invalid code"); } } /** * @dev Updates all dependency addresses to latest ones from Master */ function changeDependentContractAddress() public { tokenInstance = TokenController(ms.dAppLocker()); memberRole = MemberRoles(ms.getLatestAddress("MR")); proposalCategory = ProposalCategory(ms.getLatestAddress("PC")); } /** * @dev Checks if msg.sender is allowed to create a proposal under given category */ function allowedToCreateProposal(uint category) public view returns (bool check) { if (category == 0) return true; uint[] memory mrAllowed; (,,,, mrAllowed,,) = proposalCategory.category(category); for (uint i = 0; i < mrAllowed.length; i++) { if (mrAllowed[i] == 0 || memberRole.checkRole(msg.sender, mrAllowed[i])) return true; } } /** * @dev Checks if an address is already delegated * @param _add in concern * @return bool value if the address is delegated or not */ function alreadyDelegated(address _add) public view returns (bool delegated) { for (uint i = 0; i < leaderDelegation[_add].length; i++) { if (allDelegation[leaderDelegation[_add][i]].leader == _add) { return true; } } } /** * @dev Checks If the proposal voting time is up and it's ready to close * i.e. Closevalue is 1 if proposal is ready to be closed, 2 if already closed, 0 otherwise! * @param _proposalId Proposal id to which closing value is being checked */ function canCloseProposal(uint _proposalId) public view returns (uint) { uint dateUpdate; uint pStatus; uint _closingTime; uint _roleId; uint majority; pStatus = allProposalData[_proposalId].propStatus; dateUpdate = allProposalData[_proposalId].dateUpd; (, _roleId, majority, , , _closingTime,) = proposalCategory.category(allProposalData[_proposalId].category); if ( pStatus == uint(ProposalStatus.VotingStarted) ) { uint numberOfMembers = memberRole.numberOfMembers(_roleId); if (_roleId == uint(MemberRoles.Role.AdvisoryBoard)) { if (proposalVoteTally[_proposalId].abVoteValue[1].mul(100).div(numberOfMembers) >= majority || proposalVoteTally[_proposalId].abVoteValue[1].add(proposalVoteTally[_proposalId].abVoteValue[0]) == numberOfMembers || dateUpdate.add(_closingTime) <= now) { return 1; } } else { if (numberOfMembers == proposalVoteTally[_proposalId].voters || dateUpdate.add(_closingTime) <= now) return 1; } } else if (pStatus > uint(ProposalStatus.VotingStarted)) { return 2; } else { return 0; } } /** * @dev Gets Id of member role allowed to categorize the proposal * @return roleId allowed to categorize the proposal */ function allowedToCatgorize() public view returns (uint roleId) { return roleIdAllowedToCatgorize; } /** * @dev Gets vote tally data * @param _proposalId in concern * @param _solution of a proposal id * @return member vote value * @return advisory board vote value * @return amount of votes */ function voteTallyData(uint _proposalId, uint _solution) public view returns (uint, uint, uint) { return (proposalVoteTally[_proposalId].memberVoteValue[_solution], proposalVoteTally[_proposalId].abVoteValue[_solution], proposalVoteTally[_proposalId].voters); } /** * @dev Internal call to create proposal * @param _proposalTitle of proposal * @param _proposalSD is short description of proposal * @param _proposalDescHash IPFS hash value of propsal * @param _categoryId of proposal */ function _createProposal( string memory _proposalTitle, string memory _proposalSD, string memory _proposalDescHash, uint _categoryId ) internal { require(proposalCategory.categoryABReq(_categoryId) == 0 || _categoryId == 0); uint _proposalId = totalProposals; allProposalData[_proposalId].owner = msg.sender; allProposalData[_proposalId].dateUpd = now; allProposalSolutions[_proposalId].push(""); totalProposals++; emit Proposal( msg.sender, _proposalId, now, _proposalTitle, _proposalSD, _proposalDescHash ); if (_categoryId > 0) _categorizeProposal(_proposalId, _categoryId, 0); } /** * @dev Internal call to categorize a proposal * @param _proposalId of proposal * @param _categoryId of proposal * @param _incentive is commonIncentive */ function _categorizeProposal( uint _proposalId, uint _categoryId, uint _incentive ) internal { require( _categoryId > 0 && _categoryId < proposalCategory.totalCategories(), "Invalid category" ); allProposalData[_proposalId].category = _categoryId; allProposalData[_proposalId].commonIncentive = _incentive; allProposalData[_proposalId].propStatus = uint(ProposalStatus.AwaitingSolution); emit ProposalCategorized(_proposalId, msg.sender, _categoryId); } /** * @dev Internal call to add solution to a proposal * @param _proposalId in concern * @param _action on that solution * @param _solutionHash string value */ function _addSolution(uint _proposalId, bytes memory _action, string memory _solutionHash) internal { allProposalSolutions[_proposalId].push(_action); emit Solution(_proposalId, msg.sender, allProposalSolutions[_proposalId].length - 1, _solutionHash, now); } /** * @dev Internal call to add solution and open proposal for voting */ function _proposalSubmission( uint _proposalId, string memory _solutionHash, bytes memory _action ) internal { uint _categoryId = allProposalData[_proposalId].category; if (proposalCategory.categoryActionHashes(_categoryId).length == 0) { require(keccak256(_action) == keccak256("")); proposalActionStatus[_proposalId] = uint(ActionStatus.NoAction); } _addSolution( _proposalId, _action, _solutionHash ); _updateProposalStatus(_proposalId, uint(ProposalStatus.VotingStarted)); (, , , , , uint closingTime,) = proposalCategory.category(_categoryId); emit CloseProposalOnTime(_proposalId, closingTime.add(now)); } /** * @dev Internal call to submit vote * @param _proposalId of proposal in concern * @param _solution for that proposal */ function _submitVote(uint _proposalId, uint _solution) internal { uint delegationId = followerDelegation[msg.sender]; uint mrSequence; uint majority; uint closingTime; (, mrSequence, majority, , , closingTime,) = proposalCategory.category(allProposalData[_proposalId].category); require(allProposalData[_proposalId].dateUpd.add(closingTime) > now, "Closed"); require(memberProposalVote[msg.sender][_proposalId] == 0, "Not allowed"); require((delegationId == 0) || (delegationId > 0 && allDelegation[delegationId].leader == address(0) && _checkLastUpd(allDelegation[delegationId].lastUpd))); require(memberRole.checkRole(msg.sender, mrSequence), "Not Authorized"); uint totalVotes = allVotes.length; allVotesByMember[msg.sender].push(totalVotes); memberProposalVote[msg.sender][_proposalId] = totalVotes; allVotes.push(ProposalVote(msg.sender, _proposalId, now)); emit Vote(msg.sender, _proposalId, totalVotes, now, _solution); if (mrSequence == uint(MemberRoles.Role.Owner)) { if (_solution == 1) _callIfMajReached(_proposalId, uint(ProposalStatus.Accepted), allProposalData[_proposalId].category, 1, MemberRoles.Role.Owner); else _updateProposalStatus(_proposalId, uint(ProposalStatus.Rejected)); } else { uint numberOfMembers = memberRole.numberOfMembers(mrSequence); _setVoteTally(_proposalId, _solution, mrSequence); if (mrSequence == uint(MemberRoles.Role.AdvisoryBoard)) { if (proposalVoteTally[_proposalId].abVoteValue[1].mul(100).div(numberOfMembers) >= majority || (proposalVoteTally[_proposalId].abVoteValue[1].add(proposalVoteTally[_proposalId].abVoteValue[0])) == numberOfMembers) { emit VoteCast(_proposalId); } } else { if (numberOfMembers == proposalVoteTally[_proposalId].voters) emit VoteCast(_proposalId); } } } /** * @dev Internal call to set vote tally of a proposal * @param _proposalId of proposal in concern * @param _solution of proposal in concern * @param mrSequence number of members for a role */ function _setVoteTally(uint _proposalId, uint _solution, uint mrSequence) internal { uint categoryABReq; uint isSpecialResolution; (, categoryABReq, isSpecialResolution) = proposalCategory.categoryExtendedData(allProposalData[_proposalId].category); if (memberRole.checkRole(msg.sender, uint(MemberRoles.Role.AdvisoryBoard)) && (categoryABReq > 0) || mrSequence == uint(MemberRoles.Role.AdvisoryBoard)) { proposalVoteTally[_proposalId].abVoteValue[_solution]++; } tokenInstance.lockForMemberVote(msg.sender, tokenHoldingTime); if (mrSequence != uint(MemberRoles.Role.AdvisoryBoard)) { uint voteWeight; uint voters = 1; uint tokenBalance = tokenInstance.totalBalanceOf(msg.sender); uint totalSupply = tokenInstance.totalSupply(); if (isSpecialResolution == 1) { voteWeight = tokenBalance.add(10 ** 18); } else { voteWeight = (_minOf(tokenBalance, maxVoteWeigthPer.mul(totalSupply).div(100))).add(10 ** 18); } DelegateVote memory delegationData; for (uint i = 0; i < leaderDelegation[msg.sender].length; i++) { delegationData = allDelegation[leaderDelegation[msg.sender][i]]; if (delegationData.leader == msg.sender && _checkLastUpd(delegationData.lastUpd)) { if (memberRole.checkRole(delegationData.follower, mrSequence)) { tokenBalance = tokenInstance.totalBalanceOf(delegationData.follower); tokenInstance.lockForMemberVote(delegationData.follower, tokenHoldingTime); voters++; if (isSpecialResolution == 1) { voteWeight = voteWeight.add(tokenBalance.add(10 ** 18)); } else { voteWeight = voteWeight.add((_minOf(tokenBalance, maxVoteWeigthPer.mul(totalSupply).div(100))).add(10 ** 18)); } } } } proposalVoteTally[_proposalId].memberVoteValue[_solution] = proposalVoteTally[_proposalId].memberVoteValue[_solution].add(voteWeight); proposalVoteTally[_proposalId].voters = proposalVoteTally[_proposalId].voters + voters; } } /** * @dev Gets minimum of two numbers * @param a one of the two numbers * @param b one of the two numbers * @return minimum number out of the two */ function _minOf(uint a, uint b) internal pure returns (uint res) { res = a; if (res > b) res = b; } /** * @dev Check the time since last update has exceeded token holding time or not * @param _lastUpd is last update time * @return the bool which tells if the time since last update has exceeded token holding time or not */ function _checkLastUpd(uint _lastUpd) internal view returns (bool) { return (now - _lastUpd) > tokenHoldingTime; } /** * @dev Checks if the vote count against any solution passes the threshold value or not. */ function _checkForThreshold(uint _proposalId, uint _category) internal view returns (bool check) { uint categoryQuorumPerc; uint roleAuthorized; (, roleAuthorized, , categoryQuorumPerc, , ,) = proposalCategory.category(_category); check = ((proposalVoteTally[_proposalId].memberVoteValue[0] .add(proposalVoteTally[_proposalId].memberVoteValue[1])) .mul(100)) .div( tokenInstance.totalSupply().add( memberRole.numberOfMembers(roleAuthorized).mul(10 ** 18) ) ) >= categoryQuorumPerc; } /** * @dev Called when vote majority is reached * @param _proposalId of proposal in concern * @param _status of proposal in concern * @param category of proposal in concern * @param max vote value of proposal in concern */ function _callIfMajReached(uint _proposalId, uint _status, uint category, uint max, MemberRoles.Role role) internal { allProposalData[_proposalId].finalVerdict = max; _updateProposalStatus(_proposalId, _status); emit ProposalAccepted(_proposalId); if (proposalActionStatus[_proposalId] != uint(ActionStatus.NoAction)) { if (role == MemberRoles.Role.AdvisoryBoard) { _triggerAction(_proposalId, category); } else { proposalActionStatus[_proposalId] = uint(ActionStatus.Accepted); proposalExecutionTime[_proposalId] = actionWaitingTime.add(now); } } } /** * @dev Internal function to trigger action of accepted proposal */ function _triggerAction(uint _proposalId, uint _categoryId) internal { proposalActionStatus[_proposalId] = uint(ActionStatus.Executed); bytes2 contractName; address actionAddress; bytes memory _functionHash; (, actionAddress, contractName, , _functionHash) = proposalCategory.categoryActionDetails(_categoryId); if (contractName == "MS") { actionAddress = address(ms); } else if (contractName != "EX") { actionAddress = ms.getLatestAddress(contractName); } // solhint-disable-next-line avoid-low-level-calls (bool actionStatus,) = actionAddress.call(abi.encodePacked(_functionHash, allProposalSolutions[_proposalId][1])); if (actionStatus) { emit ActionSuccess(_proposalId); } else { proposalActionStatus[_proposalId] = uint(ActionStatus.Accepted); emit ActionFailed(_proposalId); } } /** * @dev Internal call to update proposal status * @param _proposalId of proposal in concern * @param _status of proposal to set */ function _updateProposalStatus(uint _proposalId, uint _status) internal { if (_status == uint(ProposalStatus.Rejected) || _status == uint(ProposalStatus.Denied)) { proposalActionStatus[_proposalId] = uint(ActionStatus.NoAction); } allProposalData[_proposalId].dateUpd = now; allProposalData[_proposalId].propStatus = _status; } /** * @dev Internal call to undelegate a follower * @param _follower is address of follower to undelegate */ function _unDelegate(address _follower) internal { uint followerId = followerDelegation[_follower]; if (followerId > 0) { followerCount[allDelegation[followerId].leader] = followerCount[allDelegation[followerId].leader].sub(1); allDelegation[followerId].leader = address(0); allDelegation[followerId].lastUpd = now; lastRewardClaimed[_follower] = allVotesByMember[_follower].length; } } /** * @dev Internal call to close member voting * @param _proposalId of proposal in concern * @param category of proposal in concern */ function _closeMemberVote(uint _proposalId, uint category) internal { uint isSpecialResolution; uint abMaj; (, abMaj, isSpecialResolution) = proposalCategory.categoryExtendedData(category); if (isSpecialResolution == 1) { uint acceptedVotePerc = proposalVoteTally[_proposalId].memberVoteValue[1].mul(100) .div( tokenInstance.totalSupply().add( memberRole.numberOfMembers(uint(MemberRoles.Role.Member)).mul(10 ** 18) )); if (acceptedVotePerc >= specialResolutionMajPerc) { _callIfMajReached(_proposalId, uint(ProposalStatus.Accepted), category, 1, MemberRoles.Role.Member); } else { _updateProposalStatus(_proposalId, uint(ProposalStatus.Denied)); } } else { if (_checkForThreshold(_proposalId, category)) { uint majorityVote; (,, majorityVote,,,,) = proposalCategory.category(category); if ( ((proposalVoteTally[_proposalId].memberVoteValue[1].mul(100)) .div(proposalVoteTally[_proposalId].memberVoteValue[0] .add(proposalVoteTally[_proposalId].memberVoteValue[1]) )) >= majorityVote ) { _callIfMajReached(_proposalId, uint(ProposalStatus.Accepted), category, 1, MemberRoles.Role.Member); } else { _updateProposalStatus(_proposalId, uint(ProposalStatus.Rejected)); } } else { if (abMaj > 0 && proposalVoteTally[_proposalId].abVoteValue[1].mul(100) .div(memberRole.numberOfMembers(uint(MemberRoles.Role.AdvisoryBoard))) >= abMaj) { _callIfMajReached(_proposalId, uint(ProposalStatus.Accepted), category, 1, MemberRoles.Role.Member); } else { _updateProposalStatus(_proposalId, uint(ProposalStatus.Denied)); } } } if (proposalVoteTally[_proposalId].voters > 0) { tokenInstance.mint(ms.getLatestAddress("CR"), allProposalData[_proposalId].commonIncentive); } } /** * @dev Internal call to close advisory board voting * @param _proposalId of proposal in concern * @param category of proposal in concern */ function _closeAdvisoryBoardVote(uint _proposalId, uint category) internal { uint _majorityVote; MemberRoles.Role _roleId = MemberRoles.Role.AdvisoryBoard; (,, _majorityVote,,,,) = proposalCategory.category(category); if (proposalVoteTally[_proposalId].abVoteValue[1].mul(100) .div(memberRole.numberOfMembers(uint(_roleId))) >= _majorityVote) { _callIfMajReached(_proposalId, uint(ProposalStatus.Accepted), category, 1, _roleId); } else { _updateProposalStatus(_proposalId, uint(ProposalStatus.Denied)); } } }
/* Copyright (C) 2017 GovBlocks.io 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.5.0; interface IMaster { function getLatestAddress(bytes2 _module) external view returns (address); } contract Governed { address public masterAddress; // Name of the dApp, needs to be set by contracts inheriting this contract /// @dev modifier that allows only the authorized addresses to execute the function modifier onlyAuthorizedToGovern() { IMaster ms = IMaster(masterAddress); require(ms.getLatestAddress("GV") == msg.sender, "Not authorized"); _; } /// @dev checks if an address is authorized to govern function isAuthorizedToGovern(address _toCheck) public view returns (bool) { IMaster ms = IMaster(masterAddress); return (ms.getLatestAddress("GV") == _toCheck); } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "../capital/Pool.sol"; import "../claims/ClaimsReward.sol"; import "../token/NXMToken.sol"; import "../token/TokenController.sol"; import "../token/TokenFunctions.sol"; import "./ClaimsData.sol"; contract Claims is Iupgradable { using SafeMath for uint; TokenFunctions internal tf; NXMToken internal tk; TokenController internal tc; ClaimsReward internal cr; Pool internal p1; ClaimsData internal cd; TokenData internal td; QuotationData internal qd; uint private constant DECIMAL1E18 = uint(10) ** 18; /** * @dev Sets the status of claim using claim id. * @param claimId claim id. * @param stat status to be set. */ function setClaimStatus(uint claimId, uint stat) external onlyInternal { _setClaimStatus(claimId, stat); } /** * @dev Gets claim details of claim id = pending claim start + given index */ function getClaimFromNewStart( uint index ) external view returns ( uint coverId, uint claimId, int8 voteCA, int8 voteMV, uint statusnumber ) { (coverId, claimId, voteCA, voteMV, statusnumber) = cd.getClaimFromNewStart(index, msg.sender); } /** * @dev Gets details of a claim submitted by the calling user, at a given index */ function getUserClaimByIndex( uint index ) external view returns ( uint status, uint coverId, uint claimId ) { uint statusno; (statusno, coverId, claimId) = cd.getUserClaimByIndex(index, msg.sender); status = statusno; } /** * @dev Gets details of a given claim id. * @param _claimId Claim Id. * @return status Current status of claim id * @return finalVerdict Decision made on the claim, 1 -> acceptance, -1 -> denial * @return claimOwner Address through which claim is submitted * @return coverId Coverid associated with the claim id */ function getClaimbyIndex(uint _claimId) external view returns ( uint claimId, uint status, int8 finalVerdict, address claimOwner, uint coverId ) { uint stat; claimId = _claimId; (, coverId, finalVerdict, stat,,) = cd.getClaim(_claimId); claimOwner = qd.getCoverMemberAddress(coverId); status = stat; } /** * @dev Calculates total amount that has been used to assess a claim. * Computaion:Adds acceptCA(tokens used for voting in favor of a claim) * denyCA(tokens used for voting against a claim) * current token price. * @param claimId Claim Id. * @param member Member type 0 -> Claim Assessors, else members. * @return tokens Total Amount used in Claims assessment. */ function getCATokens(uint claimId, uint member) external view returns (uint tokens) { uint coverId; (, coverId) = cd.getClaimCoverId(claimId); bytes4 currency = qd.getCurrencyOfCover(coverId); address asset = cr.getCurrencyAssetAddress(currency); uint tokenx1e18 = p1.getTokenPrice(asset); uint accept; uint deny; if (member == 0) { (, accept, deny) = cd.getClaimsTokenCA(claimId); } else { (, accept, deny) = cd.getClaimsTokenMV(claimId); } tokens = ((accept.add(deny)).mul(tokenx1e18)).div(DECIMAL1E18); // amount (not in tokens) } /** * Iupgradable Interface to update dependent contract address */ function changeDependentContractAddress() public onlyInternal { tk = NXMToken(ms.tokenAddress()); td = TokenData(ms.getLatestAddress("TD")); tf = TokenFunctions(ms.getLatestAddress("TF")); tc = TokenController(ms.getLatestAddress("TC")); p1 = Pool(ms.getLatestAddress("P1")); cr = ClaimsReward(ms.getLatestAddress("CR")); cd = ClaimsData(ms.getLatestAddress("CD")); qd = QuotationData(ms.getLatestAddress("QD")); } /** * @dev Updates the pending claim start variable, * the lowest claim id with a pending decision/payout. */ function changePendingClaimStart() public onlyInternal { uint origstat; uint state12Count; uint pendingClaimStart = cd.pendingClaimStart(); uint actualClaimLength = cd.actualClaimLength(); for (uint i = pendingClaimStart; i < actualClaimLength; i++) { (, , , origstat, , state12Count) = cd.getClaim(i); if (origstat > 5 && ((origstat != 12) || (origstat == 12 && state12Count >= 60))) { cd.setpendingClaimStart(i); } else { break; } } } /** * @dev Submits a claim for a given cover note. * Adds claim to queue incase of emergency pause else directly submits the claim. * @param coverId Cover Id. */ function submitClaim(uint coverId) public { address qadd = qd.getCoverMemberAddress(coverId); require(qadd == msg.sender); uint8 cStatus; (, cStatus,,,) = qd.getCoverDetailsByCoverID2(coverId); require(cStatus != uint8(QuotationData.CoverStatus.ClaimSubmitted), "Claim already submitted"); require(cStatus != uint8(QuotationData.CoverStatus.CoverExpired), "Cover already expired"); if (ms.isPause() == false) { _addClaim(coverId, now, qadd); } else { cd.setClaimAtEmergencyPause(coverId, now, false); qd.changeCoverStatusNo(coverId, uint8(QuotationData.CoverStatus.Requested)); } } /** * @dev Submits the Claims queued once the emergency pause is switched off. */ function submitClaimAfterEPOff() public onlyInternal { uint lengthOfClaimSubmittedAtEP = cd.getLengthOfClaimSubmittedAtEP(); uint firstClaimIndexToSubmitAfterEP = cd.getFirstClaimIndexToSubmitAfterEP(); uint coverId; uint dateUpd; bool submit; address qadd; for (uint i = firstClaimIndexToSubmitAfterEP; i < lengthOfClaimSubmittedAtEP; i++) { (coverId, dateUpd, submit) = cd.getClaimOfEmergencyPauseByIndex(i); require(submit == false); qadd = qd.getCoverMemberAddress(coverId); _addClaim(coverId, dateUpd, qadd); cd.setClaimSubmittedAtEPTrue(i, true); } cd.setFirstClaimIndexToSubmitAfterEP(lengthOfClaimSubmittedAtEP); } /** * @dev Castes vote for members who have tokens locked under Claims Assessment * @param claimId claim id. * @param verdict 1 for Accept,-1 for Deny. */ function submitCAVote(uint claimId, int8 verdict) public isMemberAndcheckPause { require(checkVoteClosing(claimId) != 1); require(cd.userClaimVotePausedOn(msg.sender).add(cd.pauseDaysCA()) < now); uint tokens = tc.tokensLockedAtTime(msg.sender, "CLA", now.add(cd.claimDepositTime())); require(tokens > 0); uint stat; (, stat) = cd.getClaimStatusNumber(claimId); require(stat == 0); require(cd.getUserClaimVoteCA(msg.sender, claimId) == 0); td.bookCATokens(msg.sender); cd.addVote(msg.sender, tokens, claimId, verdict); cd.callVoteEvent(msg.sender, claimId, "CAV", tokens, now, verdict); uint voteLength = cd.getAllVoteLength(); cd.addClaimVoteCA(claimId, voteLength); cd.setUserClaimVoteCA(msg.sender, claimId, voteLength); cd.setClaimTokensCA(claimId, verdict, tokens); tc.extendLockOf(msg.sender, "CLA", td.lockCADays()); int close = checkVoteClosing(claimId); if (close == 1) { cr.changeClaimStatus(claimId); } } /** * @dev Submits a member vote for assessing a claim. * Tokens other than those locked under Claims * Assessment can be used to cast a vote for a given claim id. * @param claimId Selected claim id. * @param verdict 1 for Accept,-1 for Deny. */ function submitMemberVote(uint claimId, int8 verdict) public isMemberAndcheckPause { require(checkVoteClosing(claimId) != 1); uint stat; uint tokens = tc.totalBalanceOf(msg.sender); (, stat) = cd.getClaimStatusNumber(claimId); require(stat >= 1 && stat <= 5); require(cd.getUserClaimVoteMember(msg.sender, claimId) == 0); cd.addVote(msg.sender, tokens, claimId, verdict); cd.callVoteEvent(msg.sender, claimId, "MV", tokens, now, verdict); tc.lockForMemberVote(msg.sender, td.lockMVDays()); uint voteLength = cd.getAllVoteLength(); cd.addClaimVotemember(claimId, voteLength); cd.setUserClaimVoteMember(msg.sender, claimId, voteLength); cd.setClaimTokensMV(claimId, verdict, tokens); int close = checkVoteClosing(claimId); if (close == 1) { cr.changeClaimStatus(claimId); } } /** * @dev Pause Voting of All Pending Claims when Emergency Pause Start. */ function pauseAllPendingClaimsVoting() public onlyInternal { uint firstIndex = cd.pendingClaimStart(); uint actualClaimLength = cd.actualClaimLength(); for (uint i = firstIndex; i < actualClaimLength; i++) { if (checkVoteClosing(i) == 0) { uint dateUpd = cd.getClaimDateUpd(i); cd.setPendingClaimDetails(i, (dateUpd.add(cd.maxVotingTime())).sub(now), false); } } } /** * @dev Resume the voting phase of all Claims paused due to an emergency pause. */ function startAllPendingClaimsVoting() public onlyInternal { uint firstIndx = cd.getFirstClaimIndexToStartVotingAfterEP(); uint i; uint lengthOfClaimVotingPause = cd.getLengthOfClaimVotingPause(); for (i = firstIndx; i < lengthOfClaimVotingPause; i++) { uint pendingTime; uint claimID; (claimID, pendingTime,) = cd.getPendingClaimDetailsByIndex(i); uint pTime = (now.sub(cd.maxVotingTime())).add(pendingTime); cd.setClaimdateUpd(claimID, pTime); cd.setPendingClaimVoteStatus(i, true); uint coverid; (, coverid) = cd.getClaimCoverId(claimID); address qadd = qd.getCoverMemberAddress(coverid); tf.extendCNEPOff(qadd, coverid, pendingTime.add(cd.claimDepositTime())); } cd.setFirstClaimIndexToStartVotingAfterEP(i); } /** * @dev Checks if voting of a claim should be closed or not. * @param claimId Claim Id. * @return close 1 -> voting should be closed, 0 -> if voting should not be closed, * -1 -> voting has already been closed. */ function checkVoteClosing(uint claimId) public view returns (int8 close) { close = 0; uint status; (, status) = cd.getClaimStatusNumber(claimId); uint dateUpd = cd.getClaimDateUpd(claimId); if (status == 12 && dateUpd.add(cd.payoutRetryTime()) < now) { if (cd.getClaimState12Count(claimId) < 60) close = 1; } if (status > 5 && status != 12) { close = - 1; } else if (status != 12 && dateUpd.add(cd.maxVotingTime()) <= now) { close = 1; } else if (status != 12 && dateUpd.add(cd.minVotingTime()) >= now) { close = 0; } else if (status == 0 || (status >= 1 && status <= 5)) { close = _checkVoteClosingFinal(claimId, status); } } /** * @dev Checks if voting of a claim should be closed or not. * Internally called by checkVoteClosing method * for Claims whose status number is 0 or status number lie between 2 and 6. * @param claimId Claim Id. * @param status Current status of claim. * @return close 1 if voting should be closed,0 in case voting should not be closed, * -1 if voting has already been closed. */ function _checkVoteClosingFinal(uint claimId, uint status) internal view returns (int8 close) { close = 0; uint coverId; (, coverId) = cd.getClaimCoverId(claimId); bytes4 currency = qd.getCurrencyOfCover(coverId); address asset = cr.getCurrencyAssetAddress(currency); uint tokenx1e18 = p1.getTokenPrice(asset); uint accept; uint deny; (, accept, deny) = cd.getClaimsTokenCA(claimId); uint caTokens = ((accept.add(deny)).mul(tokenx1e18)).div(DECIMAL1E18); (, accept, deny) = cd.getClaimsTokenMV(claimId); uint mvTokens = ((accept.add(deny)).mul(tokenx1e18)).div(DECIMAL1E18); uint sumassured = qd.getCoverSumAssured(coverId).mul(DECIMAL1E18); if (status == 0 && caTokens >= sumassured.mul(10)) { close = 1; } else if (status >= 1 && status <= 5 && mvTokens >= sumassured.mul(10)) { close = 1; } } /** * @dev Changes the status of an existing claim id, based on current * status and current conditions of the system * @param claimId Claim Id. * @param stat status number. */ function _setClaimStatus(uint claimId, uint stat) internal { uint origstat; uint state12Count; uint dateUpd; uint coverId; (, coverId, , origstat, dateUpd, state12Count) = cd.getClaim(claimId); (, origstat) = cd.getClaimStatusNumber(claimId); if (stat == 12 && origstat == 12) { cd.updateState12Count(claimId, 1); } cd.setClaimStatus(claimId, stat); if (state12Count >= 60 && stat == 12) { cd.setClaimStatus(claimId, 13); qd.changeCoverStatusNo(coverId, uint8(QuotationData.CoverStatus.ClaimDenied)); } cd.setClaimdateUpd(claimId, now); } /** * @dev Submits a claim for a given cover note. * Set deposits flag against cover. */ function _addClaim(uint coverId, uint time, address add) internal { tf.depositCN(coverId); uint len = cd.actualClaimLength(); cd.addClaim(len, coverId, add, now); cd.callClaimEvent(coverId, add, len, time); qd.changeCoverStatusNo(coverId, uint8(QuotationData.CoverStatus.ClaimSubmitted)); } }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../abstract/Iupgradable.sol"; contract ClaimsData is Iupgradable { using SafeMath for uint; struct Claim { uint coverId; uint dateUpd; } struct Vote { address voter; uint tokens; uint claimId; int8 verdict; bool rewardClaimed; } struct ClaimsPause { uint coverid; uint dateUpd; bool submit; } struct ClaimPauseVoting { uint claimid; uint pendingTime; bool voting; } struct RewardDistributed { uint lastCAvoteIndex; uint lastMVvoteIndex; } struct ClaimRewardDetails { uint percCA; uint percMV; uint tokenToBeDist; } struct ClaimTotalTokens { uint accept; uint deny; } struct ClaimRewardStatus { uint percCA; uint percMV; } ClaimRewardStatus[] internal rewardStatus; Claim[] internal allClaims; Vote[] internal allvotes; ClaimsPause[] internal claimPause; ClaimPauseVoting[] internal claimPauseVotingEP; mapping(address => RewardDistributed) internal voterVoteRewardReceived; mapping(uint => ClaimRewardDetails) internal claimRewardDetail; mapping(uint => ClaimTotalTokens) internal claimTokensCA; mapping(uint => ClaimTotalTokens) internal claimTokensMV; mapping(uint => int8) internal claimVote; mapping(uint => uint) internal claimsStatus; mapping(uint => uint) internal claimState12Count; mapping(uint => uint[]) internal claimVoteCA; mapping(uint => uint[]) internal claimVoteMember; mapping(address => uint[]) internal voteAddressCA; mapping(address => uint[]) internal voteAddressMember; mapping(address => uint[]) internal allClaimsByAddress; mapping(address => mapping(uint => uint)) internal userClaimVoteCA; mapping(address => mapping(uint => uint)) internal userClaimVoteMember; mapping(address => uint) public userClaimVotePausedOn; uint internal claimPauseLastsubmit; uint internal claimStartVotingFirstIndex; uint public pendingClaimStart; uint public claimDepositTime; uint public maxVotingTime; uint public minVotingTime; uint public payoutRetryTime; uint public claimRewardPerc; uint public minVoteThreshold; uint public maxVoteThreshold; uint public majorityConsensus; uint public pauseDaysCA; event ClaimRaise( uint indexed coverId, address indexed userAddress, uint claimId, uint dateSubmit ); event VoteCast( address indexed userAddress, uint indexed claimId, bytes4 indexed typeOf, uint tokens, uint submitDate, int8 verdict ); constructor() public { pendingClaimStart = 1; maxVotingTime = 48 * 1 hours; minVotingTime = 12 * 1 hours; payoutRetryTime = 24 * 1 hours; allvotes.push(Vote(address(0), 0, 0, 0, false)); allClaims.push(Claim(0, 0)); claimDepositTime = 7 days; claimRewardPerc = 20; minVoteThreshold = 5; maxVoteThreshold = 10; majorityConsensus = 70; pauseDaysCA = 3 days; _addRewardIncentive(); } /** * @dev Updates the pending claim start variable, * the lowest claim id with a pending decision/payout. */ function setpendingClaimStart(uint _start) external onlyInternal { require(pendingClaimStart <= _start); pendingClaimStart = _start; } /** * @dev Updates the max vote index for which claim assessor has received reward * @param _voter address of the voter. * @param caIndex last index till which reward was distributed for CA */ function setRewardDistributedIndexCA(address _voter, uint caIndex) external onlyInternal { voterVoteRewardReceived[_voter].lastCAvoteIndex = caIndex; } /** * @dev Used to pause claim assessor activity for 3 days * @param user Member address whose claim voting ability needs to be paused */ function setUserClaimVotePausedOn(address user) external { require(ms.checkIsAuthToGoverned(msg.sender)); userClaimVotePausedOn[user] = now; } /** * @dev Updates the max vote index for which member has received reward * @param _voter address of the voter. * @param mvIndex last index till which reward was distributed for member */ function setRewardDistributedIndexMV(address _voter, uint mvIndex) external onlyInternal { voterVoteRewardReceived[_voter].lastMVvoteIndex = mvIndex; } /** * @param claimid claim id. * @param percCA reward Percentage reward for claim assessor * @param percMV reward Percentage reward for members * @param tokens total tokens to be rewarded */ function setClaimRewardDetail( uint claimid, uint percCA, uint percMV, uint tokens ) external onlyInternal { claimRewardDetail[claimid].percCA = percCA; claimRewardDetail[claimid].percMV = percMV; claimRewardDetail[claimid].tokenToBeDist = tokens; } /** * @dev Sets the reward claim status against a vote id. * @param _voteid vote Id. * @param claimed true if reward for vote is claimed, else false. */ function setRewardClaimed(uint _voteid, bool claimed) external onlyInternal { allvotes[_voteid].rewardClaimed = claimed; } /** * @dev Sets the final vote's result(either accepted or declined)of a claim. * @param _claimId Claim Id. * @param _verdict 1 if claim is accepted,-1 if declined. */ function changeFinalVerdict(uint _claimId, int8 _verdict) external onlyInternal { claimVote[_claimId] = _verdict; } /** * @dev Creates a new claim. */ function addClaim( uint _claimId, uint _coverId, address _from, uint _nowtime ) external onlyInternal { allClaims.push(Claim(_coverId, _nowtime)); allClaimsByAddress[_from].push(_claimId); } /** * @dev Add Vote's details of a given claim. */ function addVote( address _voter, uint _tokens, uint claimId, int8 _verdict ) external onlyInternal { allvotes.push(Vote(_voter, _tokens, claimId, _verdict, false)); } /** * @dev Stores the id of the claim assessor vote given to a claim. * Maintains record of all votes given by all the CA to a claim. * @param _claimId Claim Id to which vote has given by the CA. * @param _voteid Vote Id. */ function addClaimVoteCA(uint _claimId, uint _voteid) external onlyInternal { claimVoteCA[_claimId].push(_voteid); } /** * @dev Sets the id of the vote. * @param _from Claim assessor's address who has given the vote. * @param _claimId Claim Id for which vote has been given by the CA. * @param _voteid Vote Id which will be stored against the given _from and claimid. */ function setUserClaimVoteCA( address _from, uint _claimId, uint _voteid ) external onlyInternal { userClaimVoteCA[_from][_claimId] = _voteid; voteAddressCA[_from].push(_voteid); } /** * @dev Stores the tokens locked by the Claim Assessors during voting of a given claim. * @param _claimId Claim Id. * @param _vote 1 for accept and increases the tokens of claim as accept, * -1 for deny and increases the tokens of claim as deny. * @param _tokens Number of tokens. */ function setClaimTokensCA(uint _claimId, int8 _vote, uint _tokens) external onlyInternal { if (_vote == 1) claimTokensCA[_claimId].accept = claimTokensCA[_claimId].accept.add(_tokens); if (_vote == - 1) claimTokensCA[_claimId].deny = claimTokensCA[_claimId].deny.add(_tokens); } /** * @dev Stores the tokens locked by the Members during voting of a given claim. * @param _claimId Claim Id. * @param _vote 1 for accept and increases the tokens of claim as accept, * -1 for deny and increases the tokens of claim as deny. * @param _tokens Number of tokens. */ function setClaimTokensMV(uint _claimId, int8 _vote, uint _tokens) external onlyInternal { if (_vote == 1) claimTokensMV[_claimId].accept = claimTokensMV[_claimId].accept.add(_tokens); if (_vote == - 1) claimTokensMV[_claimId].deny = claimTokensMV[_claimId].deny.add(_tokens); } /** * @dev Stores the id of the member vote given to a claim. * Maintains record of all votes given by all the Members to a claim. * @param _claimId Claim Id to which vote has been given by the Member. * @param _voteid Vote Id. */ function addClaimVotemember(uint _claimId, uint _voteid) external onlyInternal { claimVoteMember[_claimId].push(_voteid); } /** * @dev Sets the id of the vote. * @param _from Member's address who has given the vote. * @param _claimId Claim Id for which vote has been given by the Member. * @param _voteid Vote Id which will be stored against the given _from and claimid. */ function setUserClaimVoteMember( address _from, uint _claimId, uint _voteid ) external onlyInternal { userClaimVoteMember[_from][_claimId] = _voteid; voteAddressMember[_from].push(_voteid); } /** * @dev Increases the count of failure until payout of a claim is successful. */ function updateState12Count(uint _claimId, uint _cnt) external onlyInternal { claimState12Count[_claimId] = claimState12Count[_claimId].add(_cnt); } /** * @dev Sets status of a claim. * @param _claimId Claim Id. * @param _stat Status number. */ function setClaimStatus(uint _claimId, uint _stat) external onlyInternal { claimsStatus[_claimId] = _stat; } /** * @dev Sets the timestamp of a given claim at which the Claim's details has been updated. * @param _claimId Claim Id of claim which has been changed. * @param _dateUpd timestamp at which claim is updated. */ function setClaimdateUpd(uint _claimId, uint _dateUpd) external onlyInternal { allClaims[_claimId].dateUpd = _dateUpd; } /** @dev Queues Claims during Emergency Pause. */ function setClaimAtEmergencyPause( uint _coverId, uint _dateUpd, bool _submit ) external onlyInternal { claimPause.push(ClaimsPause(_coverId, _dateUpd, _submit)); } /** * @dev Set submission flag for Claims queued during emergency pause. * Set to true after EP is turned off and the claim is submitted . */ function setClaimSubmittedAtEPTrue(uint _index, bool _submit) external onlyInternal { claimPause[_index].submit = _submit; } /** * @dev Sets the index from which claim needs to be * submitted when emergency pause is swithched off. */ function setFirstClaimIndexToSubmitAfterEP( uint _firstClaimIndexToSubmit ) external onlyInternal { claimPauseLastsubmit = _firstClaimIndexToSubmit; } /** * @dev Sets the pending vote duration for a claim in case of emergency pause. */ function setPendingClaimDetails( uint _claimId, uint _pendingTime, bool _voting ) external onlyInternal { claimPauseVotingEP.push(ClaimPauseVoting(_claimId, _pendingTime, _voting)); } /** * @dev Sets voting flag true after claim is reopened for voting after emergency pause. */ function setPendingClaimVoteStatus(uint _claimId, bool _vote) external onlyInternal { claimPauseVotingEP[_claimId].voting = _vote; } /** * @dev Sets the index from which claim needs to be * reopened when emergency pause is swithched off. */ function setFirstClaimIndexToStartVotingAfterEP( uint _claimStartVotingFirstIndex ) external onlyInternal { claimStartVotingFirstIndex = _claimStartVotingFirstIndex; } /** * @dev Calls Vote Event. */ function callVoteEvent( address _userAddress, uint _claimId, bytes4 _typeOf, uint _tokens, uint _submitDate, int8 _verdict ) external onlyInternal { emit VoteCast( _userAddress, _claimId, _typeOf, _tokens, _submitDate, _verdict ); } /** * @dev Calls Claim Event. */ function callClaimEvent( uint _coverId, address _userAddress, uint _claimId, uint _datesubmit ) external onlyInternal { emit ClaimRaise(_coverId, _userAddress, _claimId, _datesubmit); } /** * @dev Gets Uint Parameters by parameter code * @param code whose details we want * @return string value of the parameter * @return associated amount (time or perc or value) to the code */ function getUintParameters(bytes8 code) external view returns (bytes8 codeVal, uint val) { codeVal = code; if (code == "CAMAXVT") { val = maxVotingTime / (1 hours); } else if (code == "CAMINVT") { val = minVotingTime / (1 hours); } else if (code == "CAPRETRY") { val = payoutRetryTime / (1 hours); } else if (code == "CADEPT") { val = claimDepositTime / (1 days); } else if (code == "CAREWPER") { val = claimRewardPerc; } else if (code == "CAMINTH") { val = minVoteThreshold; } else if (code == "CAMAXTH") { val = maxVoteThreshold; } else if (code == "CACONPER") { val = majorityConsensus; } else if (code == "CAPAUSET") { val = pauseDaysCA / (1 days); } } /** * @dev Get claim queued during emergency pause by index. */ function getClaimOfEmergencyPauseByIndex( uint _index ) external view returns ( uint coverId, uint dateUpd, bool submit ) { coverId = claimPause[_index].coverid; dateUpd = claimPause[_index].dateUpd; submit = claimPause[_index].submit; } /** * @dev Gets the Claim's details of given claimid. */ function getAllClaimsByIndex( uint _claimId ) external view returns ( uint coverId, int8 vote, uint status, uint dateUpd, uint state12Count ) { return ( allClaims[_claimId].coverId, claimVote[_claimId], claimsStatus[_claimId], allClaims[_claimId].dateUpd, claimState12Count[_claimId] ); } /** * @dev Gets the vote id of a given claim of a given Claim Assessor. */ function getUserClaimVoteCA( address _add, uint _claimId ) external view returns (uint idVote) { return userClaimVoteCA[_add][_claimId]; } /** * @dev Gets the vote id of a given claim of a given member. */ function getUserClaimVoteMember( address _add, uint _claimId ) external view returns (uint idVote) { return userClaimVoteMember[_add][_claimId]; } /** * @dev Gets the count of all votes. */ function getAllVoteLength() external view returns (uint voteCount) { return allvotes.length.sub(1); // Start Index always from 1. } /** * @dev Gets the status number of a given claim. * @param _claimId Claim id. * @return statno Status Number. */ function getClaimStatusNumber(uint _claimId) external view returns (uint claimId, uint statno) { return (_claimId, claimsStatus[_claimId]); } /** * @dev Gets the reward percentage to be distributed for a given status id * @param statusNumber the number of type of status * @return percCA reward Percentage for claim assessor * @return percMV reward Percentage for members */ function getRewardStatus(uint statusNumber) external view returns (uint percCA, uint percMV) { return (rewardStatus[statusNumber].percCA, rewardStatus[statusNumber].percMV); } /** * @dev Gets the number of tries that have been made for a successful payout of a Claim. */ function getClaimState12Count(uint _claimId) external view returns (uint num) { num = claimState12Count[_claimId]; } /** * @dev Gets the last update date of a claim. */ function getClaimDateUpd(uint _claimId) external view returns (uint dateupd) { dateupd = allClaims[_claimId].dateUpd; } /** * @dev Gets all Claims created by a user till date. * @param _member user's address. * @return claimarr List of Claims id. */ function getAllClaimsByAddress(address _member) external view returns (uint[] memory claimarr) { return allClaimsByAddress[_member]; } /** * @dev Gets the number of tokens that has been locked * while giving vote to a claim by Claim Assessors. * @param _claimId Claim Id. * @return accept Total number of tokens when CA accepts the claim. * @return deny Total number of tokens when CA declines the claim. */ function getClaimsTokenCA( uint _claimId ) external view returns ( uint claimId, uint accept, uint deny ) { return ( _claimId, claimTokensCA[_claimId].accept, claimTokensCA[_claimId].deny ); } /** * @dev Gets the number of tokens that have been * locked while assessing a claim as a member. * @param _claimId Claim Id. * @return accept Total number of tokens in acceptance of the claim. * @return deny Total number of tokens against the claim. */ function getClaimsTokenMV( uint _claimId ) external view returns ( uint claimId, uint accept, uint deny ) { return ( _claimId, claimTokensMV[_claimId].accept, claimTokensMV[_claimId].deny ); } /** * @dev Gets the total number of votes cast as Claims assessor for/against a given claim */ function getCaClaimVotesToken(uint _claimId) external view returns (uint claimId, uint cnt) { claimId = _claimId; cnt = 0; for (uint i = 0; i < claimVoteCA[_claimId].length; i++) { cnt = cnt.add(allvotes[claimVoteCA[_claimId][i]].tokens); } } /** * @dev Gets the total number of tokens cast as a member for/against a given claim */ function getMemberClaimVotesToken( uint _claimId ) external view returns (uint claimId, uint cnt) { claimId = _claimId; cnt = 0; for (uint i = 0; i < claimVoteMember[_claimId].length; i++) { cnt = cnt.add(allvotes[claimVoteMember[_claimId][i]].tokens); } } /** * @dev Provides information of a vote when given its vote id. * @param _voteid Vote Id. */ function getVoteDetails(uint _voteid) external view returns ( uint tokens, uint claimId, int8 verdict, bool rewardClaimed ) { return ( allvotes[_voteid].tokens, allvotes[_voteid].claimId, allvotes[_voteid].verdict, allvotes[_voteid].rewardClaimed ); } /** * @dev Gets the voter's address of a given vote id. */ function getVoterVote(uint _voteid) external view returns (address voter) { return allvotes[_voteid].voter; } /** * @dev Provides information of a Claim when given its claim id. * @param _claimId Claim Id. */ function getClaim( uint _claimId ) external view returns ( uint claimId, uint coverId, int8 vote, uint status, uint dateUpd, uint state12Count ) { return ( _claimId, allClaims[_claimId].coverId, claimVote[_claimId], claimsStatus[_claimId], allClaims[_claimId].dateUpd, claimState12Count[_claimId] ); } /** * @dev Gets the total number of votes of a given claim. * @param _claimId Claim Id. * @param _ca if 1: votes given by Claim Assessors to a claim, * else returns the number of votes of given by Members to a claim. * @return len total number of votes for/against a given claim. */ function getClaimVoteLength( uint _claimId, uint8 _ca ) external view returns (uint claimId, uint len) { claimId = _claimId; if (_ca == 1) len = claimVoteCA[_claimId].length; else len = claimVoteMember[_claimId].length; } /** * @dev Gets the verdict of a vote using claim id and index. * @param _ca 1 for vote given as a CA, else for vote given as a member. * @return ver 1 if vote was given in favour,-1 if given in against. */ function getVoteVerdict( uint _claimId, uint _index, uint8 _ca ) external view returns (int8 ver) { if (_ca == 1) ver = allvotes[claimVoteCA[_claimId][_index]].verdict; else ver = allvotes[claimVoteMember[_claimId][_index]].verdict; } /** * @dev Gets the Number of tokens of a vote using claim id and index. * @param _ca 1 for vote given as a CA, else for vote given as a member. * @return tok Number of tokens. */ function getVoteToken( uint _claimId, uint _index, uint8 _ca ) external view returns (uint tok) { if (_ca == 1) tok = allvotes[claimVoteCA[_claimId][_index]].tokens; else tok = allvotes[claimVoteMember[_claimId][_index]].tokens; } /** * @dev Gets the Voter's address of a vote using claim id and index. * @param _ca 1 for vote given as a CA, else for vote given as a member. * @return voter Voter's address. */ function getVoteVoter( uint _claimId, uint _index, uint8 _ca ) external view returns (address voter) { if (_ca == 1) voter = allvotes[claimVoteCA[_claimId][_index]].voter; else voter = allvotes[claimVoteMember[_claimId][_index]].voter; } /** * @dev Gets total number of Claims created by a user till date. * @param _add User's address. */ function getUserClaimCount(address _add) external view returns (uint len) { len = allClaimsByAddress[_add].length; } /** * @dev Calculates number of Claims that are in pending state. */ function getClaimLength() external view returns (uint len) { len = allClaims.length.sub(pendingClaimStart); } /** * @dev Gets the Number of all the Claims created till date. */ function actualClaimLength() external view returns (uint len) { len = allClaims.length; } /** * @dev Gets details of a claim. * @param _index claim id = pending claim start + given index * @param _add User's address. * @return coverid cover against which claim has been submitted. * @return claimId Claim Id. * @return voteCA verdict of vote given as a Claim Assessor. * @return voteMV verdict of vote given as a Member. * @return statusnumber Status of claim. */ function getClaimFromNewStart( uint _index, address _add ) external view returns ( uint coverid, uint claimId, int8 voteCA, int8 voteMV, uint statusnumber ) { uint i = pendingClaimStart.add(_index); coverid = allClaims[i].coverId; claimId = i; if (userClaimVoteCA[_add][i] > 0) voteCA = allvotes[userClaimVoteCA[_add][i]].verdict; else voteCA = 0; if (userClaimVoteMember[_add][i] > 0) voteMV = allvotes[userClaimVoteMember[_add][i]].verdict; else voteMV = 0; statusnumber = claimsStatus[i]; } /** * @dev Gets details of a claim of a user at a given index. */ function getUserClaimByIndex( uint _index, address _add ) external view returns ( uint status, uint coverid, uint claimId ) { claimId = allClaimsByAddress[_add][_index]; status = claimsStatus[claimId]; coverid = allClaims[claimId].coverId; } /** * @dev Gets Id of all the votes given to a claim. * @param _claimId Claim Id. * @return ca id of all the votes given by Claim assessors to a claim. * @return mv id of all the votes given by members to a claim. */ function getAllVotesForClaim( uint _claimId ) external view returns ( uint claimId, uint[] memory ca, uint[] memory mv ) { return (_claimId, claimVoteCA[_claimId], claimVoteMember[_claimId]); } /** * @dev Gets Number of tokens deposit in a vote using * Claim assessor's address and claim id. * @return tokens Number of deposited tokens. */ function getTokensClaim( address _of, uint _claimId ) external view returns ( uint claimId, uint tokens ) { return (_claimId, allvotes[userClaimVoteCA[_of][_claimId]].tokens); } /** * @param _voter address of the voter. * @return lastCAvoteIndex last index till which reward was distributed for CA * @return lastMVvoteIndex last index till which reward was distributed for member */ function getRewardDistributedIndex( address _voter ) external view returns ( uint lastCAvoteIndex, uint lastMVvoteIndex ) { return ( voterVoteRewardReceived[_voter].lastCAvoteIndex, voterVoteRewardReceived[_voter].lastMVvoteIndex ); } /** * @param claimid claim id. * @return perc_CA reward Percentage for claim assessor * @return perc_MV reward Percentage for members * @return tokens total tokens to be rewarded */ function getClaimRewardDetail( uint claimid ) external view returns ( uint percCA, uint percMV, uint tokens ) { return ( claimRewardDetail[claimid].percCA, claimRewardDetail[claimid].percMV, claimRewardDetail[claimid].tokenToBeDist ); } /** * @dev Gets cover id of a claim. */ function getClaimCoverId(uint _claimId) external view returns (uint claimId, uint coverid) { return (_claimId, allClaims[_claimId].coverId); } /** * @dev Gets total number of tokens staked during voting by Claim Assessors. * @param _claimId Claim Id. * @param _verdict 1 to get total number of accept tokens, -1 to get total number of deny tokens. * @return token token Number of tokens(either accept or deny on the basis of verdict given as parameter). */ function getClaimVote(uint _claimId, int8 _verdict) external view returns (uint claimId, uint token) { claimId = _claimId; token = 0; for (uint i = 0; i < claimVoteCA[_claimId].length; i++) { if (allvotes[claimVoteCA[_claimId][i]].verdict == _verdict) token = token.add(allvotes[claimVoteCA[_claimId][i]].tokens); } } /** * @dev Gets total number of tokens staked during voting by Members. * @param _claimId Claim Id. * @param _verdict 1 to get total number of accept tokens, * -1 to get total number of deny tokens. * @return token token Number of tokens(either accept or * deny on the basis of verdict given as parameter). */ function getClaimMVote(uint _claimId, int8 _verdict) external view returns (uint claimId, uint token) { claimId = _claimId; token = 0; for (uint i = 0; i < claimVoteMember[_claimId].length; i++) { if (allvotes[claimVoteMember[_claimId][i]].verdict == _verdict) token = token.add(allvotes[claimVoteMember[_claimId][i]].tokens); } } /** * @param _voter address of voteid * @param index index to get voteid in CA */ function getVoteAddressCA(address _voter, uint index) external view returns (uint) { return voteAddressCA[_voter][index]; } /** * @param _voter address of voter * @param index index to get voteid in member vote */ function getVoteAddressMember(address _voter, uint index) external view returns (uint) { return voteAddressMember[_voter][index]; } /** * @param _voter address of voter */ function getVoteAddressCALength(address _voter) external view returns (uint) { return voteAddressCA[_voter].length; } /** * @param _voter address of voter */ function getVoteAddressMemberLength(address _voter) external view returns (uint) { return voteAddressMember[_voter].length; } /** * @dev Gets the Final result of voting of a claim. * @param _claimId Claim id. * @return verdict 1 if claim is accepted, -1 if declined. */ function getFinalVerdict(uint _claimId) external view returns (int8 verdict) { return claimVote[_claimId]; } /** * @dev Get number of Claims queued for submission during emergency pause. */ function getLengthOfClaimSubmittedAtEP() external view returns (uint len) { len = claimPause.length; } /** * @dev Gets the index from which claim needs to be * submitted when emergency pause is swithched off. */ function getFirstClaimIndexToSubmitAfterEP() external view returns (uint indexToSubmit) { indexToSubmit = claimPauseLastsubmit; } /** * @dev Gets number of Claims to be reopened for voting post emergency pause period. */ function getLengthOfClaimVotingPause() external view returns (uint len) { len = claimPauseVotingEP.length; } /** * @dev Gets claim details to be reopened for voting after emergency pause. */ function getPendingClaimDetailsByIndex( uint _index ) external view returns ( uint claimId, uint pendingTime, bool voting ) { claimId = claimPauseVotingEP[_index].claimid; pendingTime = claimPauseVotingEP[_index].pendingTime; voting = claimPauseVotingEP[_index].voting; } /** * @dev Gets the index from which claim needs to be reopened when emergency pause is swithched off. */ function getFirstClaimIndexToStartVotingAfterEP() external view returns (uint firstindex) { firstindex = claimStartVotingFirstIndex; } /** * @dev Updates Uint Parameters of a code * @param code whose details we want to update * @param val value to set */ function updateUintParameters(bytes8 code, uint val) public { require(ms.checkIsAuthToGoverned(msg.sender)); if (code == "CAMAXVT") { _setMaxVotingTime(val * 1 hours); } else if (code == "CAMINVT") { _setMinVotingTime(val * 1 hours); } else if (code == "CAPRETRY") { _setPayoutRetryTime(val * 1 hours); } else if (code == "CADEPT") { _setClaimDepositTime(val * 1 days); } else if (code == "CAREWPER") { _setClaimRewardPerc(val); } else if (code == "CAMINTH") { _setMinVoteThreshold(val); } else if (code == "CAMAXTH") { _setMaxVoteThreshold(val); } else if (code == "CACONPER") { _setMajorityConsensus(val); } else if (code == "CAPAUSET") { _setPauseDaysCA(val * 1 days); } else { revert("Invalid param code"); } } /** * @dev Iupgradable Interface to update dependent contract address */ function changeDependentContractAddress() public onlyInternal {} /** * @dev Adds status under which a claim can lie. * @param percCA reward percentage for claim assessor * @param percMV reward percentage for members */ function _pushStatus(uint percCA, uint percMV) internal { rewardStatus.push(ClaimRewardStatus(percCA, percMV)); } /** * @dev adds reward incentive for all possible claim status for Claim assessors and members */ function _addRewardIncentive() internal { _pushStatus(0, 0); // 0 Pending-Claim Assessor Vote _pushStatus(0, 0); // 1 Pending-Claim Assessor Vote Denied, Pending Member Vote _pushStatus(0, 0); // 2 Pending-CA Vote Threshold not Reached Accept, Pending Member Vote _pushStatus(0, 0); // 3 Pending-CA Vote Threshold not Reached Deny, Pending Member Vote _pushStatus(0, 0); // 4 Pending-CA Consensus not reached Accept, Pending Member Vote _pushStatus(0, 0); // 5 Pending-CA Consensus not reached Deny, Pending Member Vote _pushStatus(100, 0); // 6 Final-Claim Assessor Vote Denied _pushStatus(100, 0); // 7 Final-Claim Assessor Vote Accepted _pushStatus(0, 100); // 8 Final-Claim Assessor Vote Denied, MV Accepted _pushStatus(0, 100); // 9 Final-Claim Assessor Vote Denied, MV Denied _pushStatus(0, 0); // 10 Final-Claim Assessor Vote Accept, MV Nodecision _pushStatus(0, 0); // 11 Final-Claim Assessor Vote Denied, MV Nodecision _pushStatus(0, 0); // 12 Claim Accepted Payout Pending _pushStatus(0, 0); // 13 Claim Accepted No Payout _pushStatus(0, 0); // 14 Claim Accepted Payout Done } /** * @dev Sets Maximum time(in seconds) for which claim assessment voting is open */ function _setMaxVotingTime(uint _time) internal { maxVotingTime = _time; } /** * @dev Sets Minimum time(in seconds) for which claim assessment voting is open */ function _setMinVotingTime(uint _time) internal { minVotingTime = _time; } /** * @dev Sets Minimum vote threshold required */ function _setMinVoteThreshold(uint val) internal { minVoteThreshold = val; } /** * @dev Sets Maximum vote threshold required */ function _setMaxVoteThreshold(uint val) internal { maxVoteThreshold = val; } /** * @dev Sets the value considered as Majority Consenus in voting */ function _setMajorityConsensus(uint val) internal { majorityConsensus = val; } /** * @dev Sets the payout retry time */ function _setPayoutRetryTime(uint _time) internal { payoutRetryTime = _time; } /** * @dev Sets percentage of reward given for claim assessment */ function _setClaimRewardPerc(uint _val) internal { claimRewardPerc = _val; } /** * @dev Sets the time for which claim is deposited. */ function _setClaimDepositTime(uint _time) internal { claimDepositTime = _time; } /** * @dev Sets number of days claim assessment will be paused */ function _setPauseDaysCA(uint val) internal { pauseDaysCA = val; } }
pragma solidity ^0.5.0; import './IUniswapV2Router01.sol'; contract IUniswapV2Router02 is IUniswapV2Router01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; }
/* Copyright (C) 2020 NexusMutual.io 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.5.0; import "@uniswap/lib/contracts/libraries/FixedPoint.sol"; import "@uniswap/v2-periphery/contracts/libraries/UniswapV2OracleLibrary.sol"; contract TwapOracle { using FixedPoint for *; struct Bucket { uint timestamp; uint price0Cumulative; uint price1Cumulative; } event Updated(address indexed pair, uint timestamp, uint price0Cumulative, uint price1Cumulative); uint constant public periodSize = 1800; uint constant public periodsPerWindow = 8; uint constant public windowSize = periodSize * periodsPerWindow; address public factory; // token pair => Bucket[8] mapping(address => Bucket[8]) public buckets; constructor (address _factory) public { factory = _factory; } /* utils */ // https://uniswap.org/docs/v2/smart-contract-integration/getting-pair-addresses/ function _pairFor(address _factory, address tokenA, address tokenB) internal pure returns (address pair) { // sort tokens (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != token1, "TWAP: identical addresses"); require(token0 != address(0), "TWAP: zero address"); pair = address(uint(keccak256(abi.encodePacked( hex'ff', _factory, keccak256(abi.encodePacked(token0, token1)), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' )))); } function timestampToIndex(uint timestamp) internal pure returns (uint index) { uint epochPeriod = timestamp / periodSize; return epochPeriod % periodsPerWindow; } function pairFor(address tokenA, address tokenB) external view returns (address pair) { return _pairFor(factory, tokenA, tokenB); } function currentBucketIndex() external view returns (uint index) { return timestampToIndex(block.timestamp); } /* update */ function update(address[] calldata pairs) external { for (uint i = 0; i < pairs.length; i++) { // note: not reusing canUpdate() because we need the bucket variable address pair = pairs[i]; uint index = timestampToIndex(block.timestamp); Bucket storage bucket = buckets[pair][index]; if (block.timestamp - bucket.timestamp < periodSize) { continue; } (uint price0Cumulative, uint price1Cumulative,) = UniswapV2OracleLibrary.currentCumulativePrices(pair); bucket.timestamp = block.timestamp; bucket.price0Cumulative = price0Cumulative; bucket.price1Cumulative = price1Cumulative; emit Updated(pair, block.timestamp, price0Cumulative, price1Cumulative); } } function canUpdate(address pair) external view returns (bool) { uint index = timestampToIndex(block.timestamp); Bucket storage bucket = buckets[pair][index]; uint timeElapsed = block.timestamp - bucket.timestamp; return timeElapsed > periodSize; } /* consult */ function _getCumulativePrices( address tokenIn, address tokenOut ) internal view returns (uint priceCumulativeStart, uint priceCumulativeEnd, uint timeElapsed) { uint currentIndex = timestampToIndex(block.timestamp); uint firstBucketIndex = (currentIndex + 1) % periodsPerWindow; address pair = _pairFor(factory, tokenIn, tokenOut); Bucket storage firstBucket = buckets[pair][firstBucketIndex]; timeElapsed = block.timestamp - firstBucket.timestamp; require(timeElapsed <= windowSize, "TWAP: missing historical reading"); require(timeElapsed >= windowSize - periodSize * 2, "TWAP: unexpected time elapsed"); (uint price0Cumulative, uint price1Cumulative,) = UniswapV2OracleLibrary.currentCumulativePrices(pair); if (tokenIn < tokenOut) { return (firstBucket.price0Cumulative, price0Cumulative, timeElapsed); } return (firstBucket.price1Cumulative, price1Cumulative, timeElapsed); } function _computeAmountOut( uint priceCumulativeStart, uint priceCumulativeEnd, uint timeElapsed, uint amountIn ) internal pure returns (uint amountOut) { // overflow is desired. FixedPoint.uq112x112 memory priceAverage = FixedPoint.uq112x112( uint224((priceCumulativeEnd - priceCumulativeStart) / timeElapsed) ); return priceAverage.mul(amountIn).decode144(); } /** * @dev Returns the amount out corresponding to the amount in for a given token using the * @dev moving average over the time range [now - [windowSize, windowSize - periodSize * 2], now] * @dev update must have been called for the bucket corresponding to timestamp `now - windowSize` */ function consult(address tokenIn, uint amountIn, address tokenOut) external view returns (uint amountOut) { uint pastPriceCumulative; uint currentPriceCumulative; uint timeElapsed; (pastPriceCumulative, currentPriceCumulative, timeElapsed) = _getCumulativePrices(tokenIn, tokenOut); return _computeAmountOut( pastPriceCumulative, currentPriceCumulative, timeElapsed, amountIn ); } }
pragma solidity ^0.5.0; interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); }
pragma solidity >=0.4.0; // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) library FixedPoint { // range: [0, 2**112 - 1] // resolution: 1 / 2**112 struct uq112x112 { uint224 _x; } // range: [0, 2**144 - 1] // resolution: 1 / 2**112 struct uq144x112 { uint _x; } uint8 private constant RESOLUTION = 112; // encode a uint112 as a UQ112x112 function encode(uint112 x) internal pure returns (uq112x112 memory) { return uq112x112(uint224(x) << RESOLUTION); } // encodes a uint144 as a UQ144x112 function encode144(uint144 x) internal pure returns (uq144x112 memory) { return uq144x112(uint256(x) << RESOLUTION); } // divide a UQ112x112 by a uint112, returning a UQ112x112 function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) { require(x != 0, 'FixedPoint: DIV_BY_ZERO'); return uq112x112(self._x / uint224(x)); } // multiply a UQ112x112 by a uint, returning a UQ144x112 // reverts on overflow function mul(uq112x112 memory self, uint y) internal pure returns (uq144x112 memory) { uint z; require(y == 0 || (z = uint(self._x) * y) / y == uint(self._x), "FixedPoint: MULTIPLICATION_OVERFLOW"); return uq144x112(z); } // returns a UQ112x112 which represents the ratio of the numerator to the denominator // equivalent to encode(numerator).div(denominator) function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) { require(denominator > 0, "FixedPoint: DIV_BY_ZERO"); return uq112x112((uint224(numerator) << RESOLUTION) / denominator); } // decode a UQ112x112 into a uint112 by truncating after the radix point function decode(uq112x112 memory self) internal pure returns (uint112) { return uint112(self._x >> RESOLUTION); } // decode a UQ144x112 into a uint144 by truncating after the radix point function decode144(uq144x112 memory self) internal pure returns (uint144) { return uint144(self._x >> RESOLUTION); } }
pragma solidity >=0.5.0; import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; import '@uniswap/lib/contracts/libraries/FixedPoint.sol'; // library with helper methods for oracles that are concerned with computing average prices library UniswapV2OracleLibrary { using FixedPoint for *; // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1] function currentBlockTimestamp() internal view returns (uint32) { return uint32(block.timestamp % 2 ** 32); } // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. function currentCumulativePrices( address pair ) internal view returns (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) { blockTimestamp = currentBlockTimestamp(); price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast(); price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast(); // if time has elapsed since the last update on the pair, mock the accumulated price values (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves(); if (blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price0Cumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; // counterfactual price1Cumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed; } } }
/* Copyright (C) 2017 GovBlocks.io 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.5.0; contract IGovernance { event Proposal( address indexed proposalOwner, uint256 indexed proposalId, uint256 dateAdd, string proposalTitle, string proposalSD, string proposalDescHash ); event Solution( uint256 indexed proposalId, address indexed solutionOwner, uint256 indexed solutionId, string solutionDescHash, uint256 dateAdd ); event Vote( address indexed from, uint256 indexed proposalId, uint256 indexed voteId, uint256 dateAdd, uint256 solutionChosen ); event RewardClaimed( address indexed member, uint gbtReward ); /// @dev VoteCast event is called whenever a vote is cast that can potentially close the proposal. event VoteCast (uint256 proposalId); /// @dev ProposalAccepted event is called when a proposal is accepted so that a server can listen that can /// call any offchain actions event ProposalAccepted (uint256 proposalId); /// @dev CloseProposalOnTime event is called whenever a proposal is created or updated to close it on time. event CloseProposalOnTime ( uint256 indexed proposalId, uint256 time ); /// @dev ActionSuccess event is called whenever an onchain action is executed. event ActionSuccess ( uint256 proposalId ); /// @dev Creates a new proposal /// @param _proposalDescHash Proposal description hash through IPFS having Short and long description of proposal /// @param _categoryId This id tells under which the proposal is categorized i.e. Proposal's Objective function createProposal( string calldata _proposalTitle, string calldata _proposalSD, string calldata _proposalDescHash, uint _categoryId ) external; /// @dev Edits the details of an existing proposal and creates new version /// @param _proposalId Proposal id that details needs to be updated /// @param _proposalDescHash Proposal description hash having long and short description of proposal. function updateProposal( uint _proposalId, string calldata _proposalTitle, string calldata _proposalSD, string calldata _proposalDescHash ) external; /// @dev Categorizes proposal to proceed further. Categories shows the proposal objective. function categorizeProposal( uint _proposalId, uint _categoryId, uint _incentives ) external; /// @dev Submit proposal with solution /// @param _proposalId Proposal id /// @param _solutionHash Solution hash contains parameters, values and description needed according to proposal function submitProposalWithSolution( uint _proposalId, string calldata _solutionHash, bytes calldata _action ) external; /// @dev Creates a new proposal with solution and votes for the solution /// @param _proposalDescHash Proposal description hash through IPFS having Short and long description of proposal /// @param _categoryId This id tells under which the proposal is categorized i.e. Proposal's Objective /// @param _solutionHash Solution hash contains parameters, values and description needed according to proposal function createProposalwithSolution( string calldata _proposalTitle, string calldata _proposalSD, string calldata _proposalDescHash, uint _categoryId, string calldata _solutionHash, bytes calldata _action ) external; /// @dev Casts vote /// @param _proposalId Proposal id /// @param _solutionChosen solution chosen while voting. _solutionChosen[0] is the chosen solution function submitVote(uint _proposalId, uint _solutionChosen) external; function closeProposal(uint _proposalId) external; function claimReward(address _memberAddress, uint _maxRecords) external returns (uint pendingDAppReward); function proposal(uint _proposalId) external view returns ( uint proposalId, uint category, uint status, uint finalVerdict, uint totalReward ); function canCloseProposal(uint _proposalId) public view returns (uint closeValue); function allowedToCatgorize() public view returns (uint roleId); }
/* Copyright (C) 2017 GovBlocks.io 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.5.0; contract IProposalCategory { event Category( uint indexed categoryId, string categoryName, string actionHash ); /// @dev Adds new category /// @param _name Category name /// @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. /// @param _allowedToCreateProposal Member roles allowed to create the proposal /// @param _majorityVotePerc Majority Vote threshold for Each voting layer /// @param _quorumPerc minimum threshold percentage required in voting to calculate result /// @param _closingTime Vote closing time for Each voting layer /// @param _actionHash hash of details containing the action that has to be performed after proposal is accepted /// @param _contractAddress address of contract to call after proposal is accepted /// @param _contractName name of contract to be called after proposal is accepted /// @param _incentives rewards to distributed after proposal is accepted function addCategory( string calldata _name, uint _memberRoleToVote, uint _majorityVotePerc, uint _quorumPerc, uint[] calldata _allowedToCreateProposal, uint _closingTime, string calldata _actionHash, address _contractAddress, bytes2 _contractName, uint[] calldata _incentives ) external; /// @dev gets category details function category(uint _categoryId) external view returns ( uint categoryId, uint memberRoleToVote, uint majorityVotePerc, uint quorumPerc, uint[] memory allowedToCreateProposal, uint closingTime, uint minStake ); ///@dev gets category action details function categoryAction(uint _categoryId) external view returns ( uint categoryId, address contractAddress, bytes2 contractName, uint defaultIncentive ); /// @dev Gets Total number of categories added till now function totalCategories() external view returns (uint numberOfCategories); /// @dev Updates category details /// @param _categoryId Category id that needs to be updated /// @param _name Category name /// @param _memberRoleToVote Voting Layer sequence in which the voting has to be performed. /// @param _allowedToCreateProposal Member roles allowed to create the proposal /// @param _majorityVotePerc Majority Vote threshold for Each voting layer /// @param _quorumPerc minimum threshold percentage required in voting to calculate result /// @param _closingTime Vote closing time for Each voting layer /// @param _actionHash hash of details containing the action that has to be performed after proposal is accepted /// @param _contractAddress address of contract to call after proposal is accepted /// @param _contractName name of contract to be called after proposal is accepted /// @param _incentives rewards to distributed after proposal is accepted function updateCategory( uint _categoryId, string memory _name, uint _memberRoleToVote, uint _majorityVotePerc, uint _quorumPerc, uint[] memory _allowedToCreateProposal, uint _closingTime, string memory _actionHash, address _contractAddress, bytes2 _contractName, uint[] memory _incentives ) public; }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": { "contracts/modules/capital/SwapAgent.sol": { "SwapAgent": "0xcafea6a946406b0b48a77348a4f70dfeed0f4664" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"},{"internalType":"uint112[]","name":"_minAmounts","type":"uint112[]"},{"internalType":"uint112[]","name":"_maxAmounts","type":"uint112[]"},{"internalType":"uint256[]","name":"_maxSlippageRatios","type":"uint256[]"},{"internalType":"address","name":"_master","type":"address"},{"internalType":"address","name":"_priceOracle","type":"address"},{"internalType":"address","name":"_twapOracle","type":"address"},{"internalType":"address","name":"_swapController","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"},{"indexed":false,"internalType":"uint256","name":"ethIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nxmOut","type":"uint256"}],"name":"NXMBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"},{"indexed":false,"internalType":"uint256","name":"nxmIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethOut","type":"uint256"}],"name":"NXMSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Payout","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromAsset","type":"address"},{"indexed":true,"internalType":"address","name":"toAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swapped","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"ETH","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_BUY_SELL_MCR_ETH_FRACTION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_MCR_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MCR_RATIO_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint112","name":"_min","type":"uint112"},{"internalType":"uint112","name":"_max","type":"uint112"},{"internalType":"uint256","name":"_maxSlippageRatio","type":"uint256"}],"name":"addAsset","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetData","outputs":[{"internalType":"uint112","name":"minAmount","type":"uint112"},{"internalType":"uint112","name":"maxAmount","type":"uint112"},{"internalType":"uint32","name":"lastSwapTime","type":"uint32"},{"internalType":"uint256","name":"maxSlippageRatio","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"assets","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"minTokensOut","type":"uint256"}],"name":"buyNXM","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"nxmAmount","type":"uint256"},{"internalType":"uint256","name":"currentTotalAssetValue","type":"uint256"},{"internalType":"uint256","name":"mcrEth","type":"uint256"}],"name":"calculateEthForNXM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"totalAssetValue","type":"uint256"},{"internalType":"uint256","name":"mcrEth","type":"uint256"}],"name":"calculateMCRRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"currentTotalAssetValue","type":"uint256"},{"internalType":"uint256","name":"mcrEth","type":"uint256"}],"name":"calculateNXMForEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"totalAssetValue","type":"uint256"},{"internalType":"uint256","name":"mcrEth","type":"uint256"}],"name":"calculateTokenSpotPrice","outputs":[{"internalType":"uint256","name":"tokenPrice","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"changeDependentContractAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"masterAddress","type":"address"}],"name":"changeMasterAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAssetDetails","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint112","name":"min","type":"uint112"},{"internalType":"uint112","name":"max","type":"uint112"},{"internalType":"uint32","name":"lastAssetSwapTime","type":"uint32"},{"internalType":"uint256","name":"maxSlippageRatio","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAssets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"nxmAmount","type":"uint256"}],"name":"getEthForNXM","outputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMCRRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"}],"name":"getNXMForEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getPoolValueInEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"toToken","type":"address"}],"name":"getSwapQuote","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getTokenPrice","outputs":[{"internalType":"uint256","name":"tokenPrice","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getWei","outputs":[{"internalType":"uint256","name":"weiToPay","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"smartCAdd","type":"address"},{"internalType":"bytes4","name":"coverCurr","type":"bytes4"},{"internalType":"uint256[]","name":"coverDetails","type":"uint256[]"},{"internalType":"uint16","name":"coverPeriod","type":"uint16"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"makeCoverBegin","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"smartCAdd","type":"address"},{"internalType":"bytes4","name":"coverCurr","type":"bytes4"},{"internalType":"uint256[]","name":"coverDetails","type":"uint256[]"},{"internalType":"uint16","name":"coverPeriod","type":"uint16"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"makeCoverUsingCA","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"master","outputs":[{"internalType":"contract INXMMaster","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mcr","outputs":[{"internalType":"contract MCR","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minPoolEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nxmToken","outputs":[{"internalType":"contract NXMToken","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"priceFeedOracle","outputs":[{"internalType":"contract PriceFeedOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"quotation","outputs":[{"internalType":"contract Quotation","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"removeAsset","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"minEthOut","type":"uint256"}],"name":"sellNXM","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sellNXMTokens","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address payable","name":"payoutAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendClaimPayout","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"sendEther","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint112","name":"_min","type":"uint112"},{"internalType":"uint112","name":"_max","type":"uint112"},{"internalType":"uint256","name":"_maxSlippageRatio","type":"uint256"}],"name":"setAssetDetails","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"fromTokenAddress","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapAssetForETH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"swapController","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"toTokenAddress","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapETHForAsset","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"tokenController","outputs":[{"internalType":"contract TokenController","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address payable","name":"destination","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferAsset","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferAssetFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"twapOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes8","name":"code","type":"bytes8"},{"internalType":"address","name":"value","type":"address"}],"name":"updateAddressParameters","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes8","name":"code","type":"bytes8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"updateUintParameters","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"newPoolAddress","type":"address"}],"name":"upgradeCapitalPool","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620050d9380380620050d983398181016040526101008110156200003857600080fd5b81019080805160405193929190846401000000008211156200005957600080fd5b9083019060208201858111156200006f57600080fd5b82518660208202830111640100000000821117156200008d57600080fd5b82525081516020918201928201910280838360005b83811015620000bc578181015183820152602001620000a2565b5050505090500160405260200180516040519392919084640100000000821115620000e657600080fd5b908301906020820185811115620000fc57600080fd5b82518660208202830111640100000000821117156200011a57600080fd5b82525081516020918201928201910280838360005b83811015620001495781810151838201526020016200012f565b50505050905001604052602001805160405193929190846401000000008211156200017357600080fd5b9083019060208201858111156200018957600080fd5b8251866020820283011164010000000082111715620001a757600080fd5b82525081516020918201928201910280838360005b83811015620001d6578181015183820152602001620001bc565b50505050905001604052602001805160405193929190846401000000008211156200020057600080fd5b9083019060208201858111156200021657600080fd5b82518660208202830111640100000000821117156200023457600080fd5b82525081516020918201928201910280838360005b838110156200026357818101518382015260200162000249565b5050505091909101604090815260208301519083015160608401516080909401516000805460ff60a01b1916600160a01b17905589518b51939750919550925014620002e5576040805162461bcd60e51b81526020600482015260156024820152600080516020620050b9833981519152604482015290519081900360640190fd5b85518851146200032b576040805162461bcd60e51b81526020600482015260156024820152600080516020620050b9833981519152604482015290519081900360640190fd5b845188511462000371576040805162461bcd60e51b81526020600482015260156024820152600080516020620050b9833981519152604482015290519081900360640190fd5b60005b8851811015620006265760008982815181106200038d57fe5b6020026020010151905060006001600160a01b0316816001600160a01b0316141562000400576040805162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a206173736574206973207a65726f20616464726573730000000000604482015290519081900360640190fd5b8882815181106200040d57fe5b60200260200101516001600160701b03168883815181106200042b57fe5b60200260200101516001600160701b0316101562000482576040805162461bcd60e51b815260206004820152600f60248201526e2837b7b61d1036b0bc101e1036b4b760891b604482015290519081900360640190fd5b670de0b6b3a76400008783815181106200049857fe5b60200260200101511115620004e6576040805162461bcd60e51b815260206004820152600f60248201526e2837b7b61d1036b0bc101e1036b4b760891b604482015290519081900360640190fd5b6001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b03831617905588518990839081106200053f57fe5b6020908102919091018101516001600160a01b03831660009081526002909252604090912080546001600160701b0319166001600160701b0390921691909117905587518890839081106200059057fe5b602002602001015160026000836001600160a01b03166001600160a01b03168152602001908152602001600020600001600e6101000a8154816001600160701b0302191690836001600160701b03160217905550868281518110620005f157fe5b6020908102919091018101516001600160a01b0390921660009081526002909152604090206001908101919091550162000374565b50600080546001600160a01b039586166001600160a01b031991821617909155600a80549486169482169490941790935560078054928516928416929092179091556008805491909316911617905550505050614a3080620006896000396000f3fe6080604052600436106102885760003560e01c806374bd0ace1161015a578063b8caedc4116100c1578063ddf403aa1161007a578063ddf403aa14610bc7578063e942c56414610bdc578063e967eb1a14610c06578063eddd9d8214610c1b578063ee97f7f314610c30578063ffa6de3a14610c4557610288565b8063b8caedc414610aca578063b9ab992714610adf578063cf35bdd014610af4578063d02641a014610b1e578063d311afb414610b51578063d46655f414610b9457610288565b80639c9b6451116101135780639c9b6451146109245780639dd86e0f14610994578063a52f930f146109ce578063aafa936d14610a20578063ad4cc43e14610a72578063b222a4d314610ab557610288565b806374bd0ace1461077557806375466b9b146107b35780638076083d146107f65780638322fff2146108dd5780639043292a146108f2578063963bbc601461090757610288565b806343400ed7116101fe57806365a21992116101b757806365a219921461058857806366fd551d146105be57806367e4ac2c146105f157806368da80af1461065657806369f36c321461073057806370310cb71461074557610288565b806343400ed714610455578063439e2e451461048b578063441da1ba146104ce5780634779be08146104ff57806349386d87146105145780634a5e42b11461055557610288565b80631f50c989116102505780631f50c9891461033d5780632892b29c1461035257806328dd37731461037c5780632f04d798146103ac5780633f494325146103c157806341fee44a146103eb57610288565b806304e8266f1461028a5780630bb76fff146102cc5780630e29df22146102e15780630ea9c984146102e957806311267784146102fe575b005b34801561029657600080fd5b506102ba600480360360408110156102ad57600080fd5b5080359060200135610c84565b60408051918252519081900360200190f35b3480156102d857600080fd5b506102ba610cf5565b610288610cfb565b3480156102f557600080fd5b50610288610cfd565b34801561030a57600080fd5b506102886004803603606081101561032157600080fd5b506001600160a01b038135169060208101359060400135610f44565b34801561034957600080fd5b506102ba6111df565b34801561035e57600080fd5b506102ba6004803603602081101561037557600080fd5b50356111e5565b34801561038857600080fd5b506102886004803603604081101561039f57600080fd5b5080359060200135611283565b3480156103b857600080fd5b506102ba611887565b3480156103cd57600080fd5b506102ba600480360360208110156103e457600080fd5b5035611a38565b3480156103f757600080fd5b5061041e6004803603602081101561040e57600080fd5b50356001600160a01b0316611ace565b604080516001600160701b03958616815293909416602084015263ffffffff90911682840152606082015290519081900360800190f35b34801561046157600080fd5b506102ba6004803603606081101561047857600080fd5b5080359060208101359060400135611b0d565b34801561049757600080fd5b50610288600480360360608110156104ae57600080fd5b506001600160a01b03813581169160208101359091169060400135611c26565b3480156104da57600080fd5b506104e3611eac565b604080516001600160a01b039092168252519081900360200190f35b34801561050b57600080fd5b506102ba611ebb565b34801561052057600080fd5b506102ba6004803603606081101561053757600080fd5b508035906001600160a01b0360208201358116916040013516611ec0565b34801561056157600080fd5b506102886004803603602081101561057857600080fd5b50356001600160a01b0316611f61565b34801561059457600080fd5b506102ba600480360360608110156105ab57600080fd5b508035906020810135906040013561215c565b3480156105ca57600080fd5b50610288600480360360208110156105e157600080fd5b50356001600160a01b03166122a0565b3480156105fd57600080fd5b506106066124ce565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561064257818101518382015260200161062a565b505050509050019250505060405180910390f35b610288600480360360e081101561066c57600080fd5b6001600160a01b03823516916001600160e01b0319602082013516918101906060810160408201356401000000008111156106a657600080fd5b8201836020820111156106b857600080fd5b803590602001918460208302840111640100000000831117156106da57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505061ffff83351693505060ff602083013516916040810135915060600135612530565b34801561073c57600080fd5b506102ba612864565b34801561075157600080fd5b506102ba6004803603604081101561076857600080fd5b5080359060200135612900565b34801561078157600080fd5b5061079f6004803603602081101561079857600080fd5b5035612918565b604080519115158252519081900360200190f35b3480156107bf57600080fd5b5061079f600480360360608110156107d657600080fd5b506001600160a01b03813581169160208101359091169060400135612aab565b34801561080257600080fd5b50610288600480360360e081101561081957600080fd5b6001600160a01b03823516916001600160e01b03196020820135169181019060608101604082013564010000000081111561085357600080fd5b82018360208201111561086557600080fd5b8035906020019184602083028401116401000000008311171561088757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505061ffff83351693505060ff602083013516916040810135915060600135612cb1565b3480156108e957600080fd5b506104e3612e95565b3480156108fe57600080fd5b506104e3612ead565b6102886004803603602081101561091d57600080fd5b5035612ebc565b34801561093057600080fd5b506109576004803603602081101561094757600080fd5b50356001600160a01b0316613267565b604080519586526001600160701b039485166020870152929093168483015263ffffffff1660608401526080830191909152519081900360a00190f35b3480156109a057600080fd5b50610288600480360360408110156109b757600080fd5b506001600160c01b03198135169060200135613377565b3480156109da57600080fd5b50610288600480360360808110156109f157600080fd5b506001600160a01b03813516906001600160701b036020820135811691604081013590911690606001356134a0565b348015610a2c57600080fd5b5061028860048036036080811015610a4357600080fd5b506001600160a01b03813516906001600160701b036020820135811691604081013590911690606001356137c7565b348015610a7e57600080fd5b5061028860048036036040811015610a9557600080fd5b5080356001600160c01b03191690602001356001600160a01b03166139d4565b348015610ac157600080fd5b506102ba613b35565b348015610ad657600080fd5b506104e3613b3b565b348015610aeb57600080fd5b506104e3613b4a565b348015610b0057600080fd5b506104e360048036036020811015610b1757600080fd5b5035613b59565b348015610b2a57600080fd5b506102ba60048036036020811015610b4157600080fd5b50356001600160a01b0316613b80565b348015610b5d57600080fd5b5061028860048036036060811015610b7457600080fd5b506001600160a01b03813581169160208101359091169060400135613ca2565b348015610ba057600080fd5b5061028860048036036020811015610bb757600080fd5b50356001600160a01b0316613e2e565b348015610bd357600080fd5b506104e3613ead565b348015610be857600080fd5b506102ba60048036036020811015610bff57600080fd5b5035613ebc565b348015610c1257600080fd5b506104e3613ec7565b348015610c2757600080fd5b506104e3613ed6565b348015610c3c57600080fd5b506104e3613ee5565b348015610c5157600080fd5b5061028860048036036060811015610c6857600080fd5b506001600160a01b038135169060208101359060400135613ef4565b600080610c918484612900565b90506000610ca660048063ffffffff61419d16565b600a0a9050610cea6624859b044a8000610cde83610cd262588040818a60048a0a63ffffffff61419d16565b9063ffffffff6141f616565b9063ffffffff61423816565b925050505b92915050565b60095481565b565b6000809054906101000a90046001600160a01b03166001600160a01b0316639d76ea586040518163ffffffff1660e01b815260040160206040518083038186803b158015610d4a57600080fd5b505afa158015610d5e573d6000803e3d6000fd5b505050506040513d6020811015610d7457600080fd5b5051600480546001600160a01b0319166001600160a01b03928316178155600054604080516227050b60e31b815261544360f01b9381019390935251921691630138285891602480820192602092909190829003018186803b158015610dd957600080fd5b505afa158015610ded573d6000803e3d6000fd5b505050506040513d6020811015610e0357600080fd5b5051600580546001600160a01b0319166001600160a01b03928316179055600054604080516227050b60e31b815261145560f21b6004820152905191909216916301382858916024808301926020929190829003018186803b158015610e6857600080fd5b505afa158015610e7c573d6000803e3d6000fd5b505050506040513d6020811015610e9257600080fd5b5051600380546001600160a01b0319166001600160a01b03928316179055600054604080516227050b60e31b8152614d4360f01b6004820152905191909216916301382858916024808301926020929190829003018186803b158015610ef757600080fd5b505afa158015610f0b573d6000803e3d6000fd5b505050506040513d6020811015610f2157600080fd5b5051600680546001600160a01b0319166001600160a01b03909216919091179055565b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015610f9157600080fd5b505afa158015610fa5573d6000803e3d6000fd5b505050506040513d6020811015610fbb57600080fd5b505115611002576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6008546001600160a01b0316331461105c576040805162461bcd60e51b81526020600482015260186024820152772837b7b61d103737ba1039bbb0b821b7b73a3937b63632b960411b604482015290519081900360640190fd5b600054600160a01b900460ff166110a8576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556007546001600160a01b038581168084526002602090815260408086208151631ab6b2b760e01b8152949095166004850152602484019490945260448301919091526064820186905260848201859052915173cafea6a946406b0b48a77348a4f70dfeed0f466492631ab6b2b79260a48082019391829003018186803b15801561113e57600080fd5b505af4158015611152573d6000803e3d6000fd5b505050506040513d602081101561116857600080fd5b50516040805185815260208101839052815192935073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee926001600160a01b038816927fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb928290030190a350506000805460ff60a01b1916600160a01b1790555050565b6101f481565b6000806111f0611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561124257600080fd5b505afa158015611256573d6000803e3d6000fd5b505050506040513d602081101561126c57600080fd5b5051905061127b848383611b0d565b949350505050565b6000546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b1580156112ce57600080fd5b505afa1580156112e2573d6000803e3d6000fd5b505050506040513d60208110156112f857600080fd5b5051611344576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b600054600160a01b900460ff16611390576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b19811690915560408051600162f6c75960e01b0319815290516001600160a01b039092169163ff0938a791600480820192602092909190829003018186803b1580156113e457600080fd5b505afa1580156113f8573d6000803e3d6000fd5b505050506040513d602081101561140e57600080fd5b505115611455576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b60048054604080516370a0823160e01b815233938101939093525184926001600160a01b03909216916370a08231916024808301926020929190829003018186803b1580156114a357600080fd5b505afa1580156114b7573d6000803e3d6000fd5b505050506040513d60208110156114cd57600080fd5b50511015611522576040805162461bcd60e51b815260206004820152601860248201527f506f6f6c3a204e6f7420656e6f7567682062616c616e63650000000000000000604482015290519081900360640190fd5b60048054604080516398fd371f60e01b815233938101939093525142926001600160a01b03909216916398fd371f916024808301926020929190829003018186803b15801561157057600080fd5b505afa158015611584573d6000803e3d6000fd5b505050506040513d602081101561159a57600080fd5b505111156115d95760405162461bcd60e51b81526004018080602001828103825260268152602001806149d66026913960400191505060405180910390fd5b60006115e3611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561163557600080fd5b505afa158015611649573d6000803e3d6000fd5b505050506040513d602081101561165f57600080fd5b505190506000611670858484611b0d565b905081611683848363ffffffff61429216565b10156116c05760405162461bcd60e51b815260040180806020018281038252602181526020018061487a6021913960400191505060405180910390fd5b83811015611715576040805162461bcd60e51b815260206004820152601860248201527f506f6f6c3a206574684f7574203c206d696e4574684f75740000000000000000604482015290519081900360640190fd5b6005546040805163079cc67960e41b81523360048201526024810188905290516001600160a01b03909216916379cc6790916044808201926020929091908290030181600087803b15801561176957600080fd5b505af115801561177d573d6000803e3d6000fd5b505050506040513d602081101561179357600080fd5b5050604051600090339083908381818185875af1925050503d80600081146117d7576040519150601f19603f3d011682016040523d82523d6000602084013e6117dc565b606091505b5050905080611832576040805162461bcd60e51b815260206004820152601a60248201527f506f6f6c3a2053656c6c207472616e73666572206661696c6564000000000000604482015290519081900360640190fd5b6040805187815260208101849052815133927f45ea3d587ef2c627bc7085da467e1df0748c42d3ee4074b2f6b942f6876636c5928290030190a250506000805460ff60a01b1916600160a01b17905550505050565b600047815b600154811015611a32576000600182815481106118a557fe5b6000918252602080832090910154600a546040805163696ae5e360e01b81526001600160a01b03938416600482018190529151919650869594929093169263696ae5e3926024808301939192829003018186803b15801561190557600080fd5b505afa158015611919573d6000803e3d6000fd5b505050506040513d602081101561192f57600080fd5b5051905080611977576040805162461bcd60e51b815260206004820152600f60248201526e506f6f6c3a207a65726f207261746560881b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038516916370a0823191602480820192602092909190829003018186803b1580156119c157600080fd5b505afa1580156119d5573d6000803e3d6000fd5b505050506040513d60208110156119eb57600080fd5b505190506000611a0d670de0b6b3a7640000610cd2848663ffffffff61419d16565b9050611a1f878263ffffffff61423816565b9650506001909401935061188c92505050565b50905090565b600080611a43611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a9557600080fd5b505afa158015611aa9573d6000803e3d6000fd5b505050506040513d6020811015611abf57600080fd5b5051905061127b84838361215c565b600260205260009081526040902080546001909101546001600160701b0380831692600160701b810490911691600160e01b90910463ffffffff169084565b600080611b1a8484610c84565b90506000611b3a670de0b6b3a7640000610cd2888563ffffffff61419d16565b90506000611b4e868363ffffffff61429216565b90506000611b5c8287610c84565b90506000611b8b6103e8610cd26103cf611b7f6002838b8963ffffffff61423816565b9063ffffffff61419d16565b90506000828210611b9c5782611b9e565b815b90506000611bbe670de0b6b3a7640000610cd2848e63ffffffff61419d16565b9050611bd8612710610cd28b6101f463ffffffff61419d16565b811115611c165760405162461bcd60e51b815260040180806020018281038252603881526020018061489b6038913960400191505060405180910390fd5b96505050505050505b9392505050565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b158015611c7157600080fd5b505afa158015611c85573d6000803e3d6000fd5b505050506040513d6020811015611c9b57600080fd5b5051611cd85760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b600054600160a01b900460ff16611d24576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556001600160a01b038416815260026020526040902054600160701b90046001600160701b031615611d9e576040805162461bcd60e51b8152602060048201526012602482015271506f6f6c3a206d6178206e6f74207a65726f60701b604482015290519081900360640190fd5b6001600160a01b038216611deb576040805162461bcd60e51b815260206004820152600f60248201526e506f6f6c3a2064657374207a65726f60881b604482015290519081900360640190fd5b604080516370a0823160e01b8152306004820152905184916000916001600160a01b038416916370a08231916024808301926020929190829003018186803b158015611e3657600080fd5b505afa158015611e4a573d6000803e3d6000fd5b505050506040513d6020811015611e6057600080fd5b505190506000818411611e735783611e75565b815b9050611e916001600160a01b038416868363ffffffff6142d416565b50506000805460ff60a01b1916600160a01b17905550505050565b6003546001600160a01b031681565b600481565b6040805163ca31d03f60e01b8152600481018590526001600160a01b03808516602483015283166044820152905160009173cafea6a946406b0b48a77348a4f70dfeed0f46649163ca31d03f91606480820192602092909190829003018186803b158015611f2d57600080fd5b505af4158015611f41573d6000803e3d6000fd5b505050506040513d6020811015611f5757600080fd5b5051949350505050565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b158015611fac57600080fd5b505afa158015611fc0573d6000803e3d6000fd5b505050506040513d6020811015611fd657600080fd5b50516120135760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b60005b600154811015612113576001818154811061202d57fe5b6000918252602090912001546001600160a01b038381169116146120505761210b565b6001600160a01b03821660009081526002602052604081208181556001908101919091558054600019810190811061208457fe5b600091825260209091200154600180546001600160a01b0390921691839081106120aa57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060018054806120e357fe5b600082815260209020810160001990810180546001600160a01b031916905501905550612159565b600101612016565b506040805162461bcd60e51b8152602060048201526015602482015274141bdbdb0e88185cdcd95d081b9bdd08199bdd5b99605a1b604482015290519081900360640190fd5b50565b6000612176612710610cd2846101f463ffffffff61419d16565b8411156121b45760405162461bcd60e51b815260040180806020018281038252603e81526020018061483c603e913960400191505060405180910390fd5b8215806121d4575064e8d4a510006121d2838563ffffffff6141f616565b115b15612205576624859b044a80006121fd81610cd287670de0b6b3a764000063ffffffff61419d16565b915050611c1f565b6000612211848461432b565b90506000612225858763ffffffff61423816565b90506000612233828661432b565b90506000612247848363ffffffff61429216565b9050600061226782610cd28b670de0b6b3a764000063ffffffff61419d16565b90506000612282826624859b044a800063ffffffff61423816565b9050611c1681610cd28c670de0b6b3a764000063ffffffff61419d16565b6000546001600160a01b0316156122fd576000546001600160a01b031633146122fd576040805162461bcd60e51b815260206004820152600a6024820152692737ba1036b0b9ba32b960b11b604482015290519081900360640190fd5b600054600160a01b900460ff16612349576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556040514791906001600160a01b0384169083908381818185875af1925050503d80600081146123a1576040519150601f19603f3d011682016040523d82523d6000602084013e6123a6565b606091505b50509050806123f4576040805162461bcd60e51b8152602060048201526015602482015274141bdbdb0e881d1c985b9cd9995c8819985a5b1959605a1b604482015290519081900360640190fd5b60005b6001548110156124b55760006001828154811061241057fe5b6000918252602080832090910154604080516370a0823160e01b815230600482015290516001600160a01b03909216945084926370a0823192602480840193829003018186803b15801561246357600080fd5b505afa158015612477573d6000803e3d6000fd5b505050506040513d602081101561248d57600080fd5b505190506124ab6001600160a01b038316878363ffffffff6142d416565b50506001016123f7565b50506000805460ff60a01b1916600160a01b1790555050565b6060600180548060200260200160405190810160405280929190818152602001828054801561252657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612508575b5050505050905090565b6000546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b15801561257b57600080fd5b505afa15801561258f573d6000803e3d6000fd5b505050506040513d60208110156125a557600080fd5b50516125f1576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561263e57600080fd5b505afa158015612652573d6000803e3d6000fd5b505050506040513d602081101561266857600080fd5b5051156126af576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6208aa8960eb1b6001600160e01b0319871614612713576040805162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a20556e657870656374656420617373657420747970650000000000604482015290519081900360640190fd5b8460018151811061272057fe5b602002602001015134146127655760405162461bcd60e51b81526004018080602001828103825260278152602001806149af6027913960400191505060405180910390fd5b60035460405163250bc23960e11b815233600482018181526001600160a01b038b811660248501526001600160e01b03198b16604485015261ffff8916608485015260ff881660a485015260c4840187905260e48401869052610100606485019081528a516101048601528a519190951694634a178472948d938d938d938d938d938d938d93919261012401906020808a01910280838360005b838110156128175781810151838201526020016127ff565b505050509050019950505050505050505050600060405180830381600087803b15801561284357600080fd5b505af1158015612857573d6000803e3d6000fd5b5050505050505050505050565b60008061286f611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128c157600080fd5b505afa1580156128d5573d6000803e3d6000fd5b505050506040513d60208110156128eb57600080fd5b505190506128f98282612900565b9250505090565b6000611c1f82610cd28561271063ffffffff61419d16565b600080546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b15801561296457600080fd5b505afa158015612978573d6000803e3d6000fd5b505050506040513d602081101561298e57600080fd5b50516129da576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015612a2757600080fd5b505afa158015612a3b573d6000803e3d6000fd5b505050506040513d6020811015612a5157600080fd5b505115612a98576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b612aa3826000611283565b506001919050565b60008054604080516323c5b10760e21b815233600482015290516001600160a01b0390921691638f16c41c91602480820192602092909190829003018186803b158015612af757600080fd5b505afa158015612b0b573d6000803e3d6000fd5b505050506040513d6020811015612b2157600080fd5b5051612b5e5760405162461bcd60e51b81526004018080602001828103825260228152602001806149636022913960400191505060405180910390fd5b600054600160a01b900460ff16612baa576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556001600160a01b03851673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415612c35576040516001600160a01b038516908490600081818185875af1925050503d8060008114612c25576040519150601f19603f3d011682016040523d82523d6000602084013e612c2a565b606091505b505080915050612c43565b612c4085858561435b565b90505b8015612c9557846001600160a01b0316846001600160a01b03167febe7adb4feddf2afa5de463169fdc706254a55c9cf2b930ac84bb49e28cfe6bb856040518082815260200191505060405180910390a35b90506000805460ff60a01b1916600160a01b1790559392505050565b6000546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b158015612cfc57600080fd5b505afa158015612d10573d6000803e3d6000fd5b505050506040513d6020811015612d2657600080fd5b5051612d72576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015612dbf57600080fd5b505afa158015612dd3573d6000803e3d6000fd5b505050506040513d6020811015612de957600080fd5b505115612e30576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6208aa8960eb1b6001600160e01b031987161415612765576040805162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a20556e657870656374656420617373657420747970650000000000604482015290519081900360640190fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6007546001600160a01b031681565b6000546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b158015612f0757600080fd5b505afa158015612f1b573d6000803e3d6000fd5b505050506040513d6020811015612f3157600080fd5b5051612f7d576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015612fca57600080fd5b505afa158015612fde573d6000803e3d6000fd5b505050506040513d6020811015612ff457600080fd5b50511561303b576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b3480613080576040805162461bcd60e51b815260206004820152600f60248201526e0506f6f6c3a20657468496e203e203608c1b604482015290519081900360640190fd5b600061309a8261308e611887565b9063ffffffff61429216565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156130ec57600080fd5b505afa158015613100573d6000803e3d6000fd5b505050506040513d602081101561311657600080fd5b5051905060006131268383612900565b9050619c408111156131695760405162461bcd60e51b81526004018080602001828103825260248152602001806148d36024913960400191505060405180910390fd5b600061317685858561215c565b9050858110156131b75760405162461bcd60e51b81526004018080602001828103825260298152602001806149186029913960400191505060405180910390fd5b600554604080516340c10f1960e01b81523360048201526024810184905290516001600160a01b03909216916340c10f199160448082019260009290919082900301818387803b15801561320a57600080fd5b505af115801561321e573d6000803e3d6000fd5b5050604080518881526020810185905281513394507fb4bf7fd11bc97d76c39ed13880388ee221d6971dd18f90e65179e0056d24671193509081900390910190a2505050505050565b600080600080600080869050806001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156132c957600080fd5b505afa1580156132dd573d6000803e3d6000fd5b505050506040513d60208110156132f357600080fd5b505195506132ff6147f4565b505050506001600160a01b0393909316600090815260026020908152604091829020825160808101845281546001600160701b03808216808452600160701b8304909116948301859052600160e01b90910463ffffffff16948201859052600190920154606090910181905294969095509093919250565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b1580156133c257600080fd5b505afa1580156133d6573d6000803e3d6000fd5b505050506040513d60208110156133ec57600080fd5b50516134295760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b6609a929cbe8aa8960cb1b6001600160c01b03198316141561344f57600981905561349c565b6040805162461bcd60e51b815260206004820152601760248201527f506f6f6c3a20756e6b6e6f776e20706172616d65746572000000000000000000604482015290519081900360640190fd5b5050565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b1580156134eb57600080fd5b505afa1580156134ff573d6000803e3d6000fd5b505050506040513d602081101561351557600080fd5b50516135525760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b6001600160a01b0384166135ad576040805162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a206173736574206973207a65726f20616464726573730000000000604482015290519081900360640190fd5b826001600160701b0316826001600160701b03161015613606576040805162461bcd60e51b815260206004820152600f60248201526e2837b7b61d1036b0bc101e1036b4b760891b604482015290519081900360640190fd5b670de0b6b3a7640000811115613663576040805162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a206d617820736c69707061676520726174696f203e203100000000604482015290519081900360640190fd5b60005b6001548110156136e6576001818154811061367d57fe5b6000918252602090912001546001600160a01b03868116911614156136de576040805162461bcd60e51b8152602060048201526012602482015271506f6f6c3a2061737365742065786973747360701b604482015290519081900360640190fd5b600101613666565b506001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b039096166001600160a01b031990961686179055604080516080810182526001600160701b0395861681529385166020858101918252600086840181815260608801968752988152600290915291909120935184549151965163ffffffff16600160e01b026001600160e01b03978716600160701b02600160701b600160e01b0319929097166001600160701b0319909316929092171694909417949094169290921781559051910155565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b15801561381257600080fd5b505afa158015613826573d6000803e3d6000fd5b505050506040513d602081101561383c57600080fd5b50516138795760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b816001600160701b0316836001600160701b031611156138d2576040805162461bcd60e51b815260206004820152600f60248201526e0a0deded87440dad2dc407c40dac2f608b1b604482015290519081900360640190fd5b670de0b6b3a764000081111561392f576040805162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a206d617820736c69707061676520726174696f203e203100000000604482015290519081900360640190fd5b60005b600154811015612113576001818154811061394957fe5b6000918252602090912001546001600160a01b0386811691161461396c576139c6565b506001600160a01b038416600090815260026020526040902080546001600160701b03848116600160701b02600160701b600160e01b03199187166001600160701b031990931692909217161781556001018190556139ce565b600101613932565b50505050565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b158015613a1f57600080fd5b505afa158015613a33573d6000803e3d6000fd5b505050506040513d6020811015613a4957600080fd5b5051613a865760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b630545741560e41b6001600160c01b031983161415613abf57600780546001600160a01b0319166001600160a01b03831617905561349c565b630535741560e41b6001600160c01b031983161415613af857600880546001600160a01b0319166001600160a01b03831617905561349c565b67141490d7d191515160c21b6001600160c01b03198316141561344f57600a80546001600160a01b0319166001600160a01b03831617905561349c565b619c4081565b6006546001600160a01b031681565b600a546001600160a01b031681565b60018181548110613b6657fe5b6000918252602090912001546001600160a01b0316905081565b600080613b8b611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613bdd57600080fd5b505afa158015613bf1573d6000803e3d6000fd5b505050506040513d6020811015613c0757600080fd5b505190506000613c178383610c84565b600a5460408051632ae2073360e11b81526001600160a01b0389811660048301526024820185905291519394509116916355c40e6691604480820192602092909190829003018186803b158015613c6d57600080fd5b505afa158015613c81573d6000803e3d6000fd5b505050506040513d6020811015613c9757600080fd5b505195945050505050565b600054604080516323c5b10760e21b815233600482015290516001600160a01b0390921691638f16c41c91602480820192602092909190829003018186803b158015613ced57600080fd5b505afa158015613d01573d6000803e3d6000fd5b505050506040513d6020811015613d1757600080fd5b5051613d545760405162461bcd60e51b81526004018080602001828103825260228152602001806149636022913960400191505060405180910390fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015613da157600080fd5b505afa158015613db5573d6000803e3d6000fd5b505050506040513d6020811015613dcb57600080fd5b505115613e12576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b826139ce6001600160a01b03821684308563ffffffff6144ad16565b6000546001600160a01b031615613e8b576000546001600160a01b03163314613e8b576040805162461bcd60e51b815260206004820152600a6024820152692737ba1036b0b9ba32b960b11b604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b031681565b6000610cef826111e5565b6004546001600160a01b031681565b6005546001600160a01b031681565b6000546001600160a01b031681565b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015613f4157600080fd5b505afa158015613f55573d6000803e3d6000fd5b505050506040513d6020811015613f6b57600080fd5b505115613fb2576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6008546001600160a01b0316331461400c576040805162461bcd60e51b81526020600482015260186024820152772837b7b61d103737ba1039bbb0b821b7b73a3937b63632b960411b604482015290519081900360640190fd5b600054600160a01b900460ff16614058576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556001600160a01b03808516808352600260209081526040808520600754600954835163d56b5b1560e01b8152919096166004820152602481018290526044810194909452606484018890526084840187905260a48401949094525192939273cafea6a946406b0b48a77348a4f70dfeed0f46649263d56b5b159260c4808301939192829003018186803b1580156140fb57600080fd5b505af415801561410f573d6000803e3d6000fd5b505050506040513d602081101561412557600080fd5b5051604080518681526020810183905281519293506001600160a01b0388169273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee927fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb928290030190a350506000805460ff60a01b1916600160a01b179055505050565b6000826141ac57506000610cef565b828202828482816141b957fe5b0414611c1f5760405162461bcd60e51b81526004018080602001828103825260218152602001806148f76021913960400191505060405180910390fd5b6000611c1f83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614507565b600082820183811015611c1f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611c1f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506145a9565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052614326908490614603565b505050565b6000611c1f83610cd284611b7f838383838383838360038362588040670de0b6b3a764000063ffffffff61419d16565b600061436f846001600160a01b03166147bb565b61437b57506000611c1f565b604080516001600160a01b038581166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17815292518251889460009360609390871692869282918083835b602083106143f95780518252601f1990920191602091820191016143da565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461445b576040519150601f19603f3d011682016040523d82523d6000602084013e614460565b606091505b509150915081614477576000945050505050611c1f565b805161448a576001945050505050611c1f565b80806020019051602081101561449f57600080fd5b505198975050505050505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526139ce908590614603565b600081836145935760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614558578181015183820152602001614540565b50505050905090810190601f1680156145855780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161459f57fe5b0495945050505050565b600081848411156145fb5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614558578181015183820152602001614540565b505050900390565b614615826001600160a01b03166147bb565b614666576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106146a45780518252601f199092019160209182019101614685565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614706576040519150601f19603f3d011682016040523d82523d6000602084013e61470b565b606091505b509150915081614762576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156139ce5780806020019051602081101561477e57600080fd5b50516139ce5760405162461bcd60e51b815260040180806020018281038252602a815260200180614985602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061127b575050151592915050565b6040805160808101825260008082526020820181905291810182905260608101919091529056fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c00506f6f6c3a2050757263686173657320776f72746820686967686572207468616e203525206f66204d435265746820617265206e6f7420616c6c6f776564506f6f6c3a204d4352252063616e6e6f742066616c6c2062656c6f772031303025506f6f6c3a2053616c657320776f727468206d6f7265207468616e203525206f66204d435265746820617265206e6f7420616c6c6f776564506f6f6c3a2043616e6e6f74207075726368617365206966204d435225203e2034303025536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77506f6f6c3a20746f6b656e734f7574206973206c657373207468616e206d696e546f6b656e734f757443616c6c6572206973206e6f7420617574686f72697a656420746f20676f7665726e43616c6c6572206973206e6f7420616e20696e7465726e616c20636f6e74726163745361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564506f6f6c3a2045544820616d6f756e7420646f6573206e6f74206d61746368207072656d69756d506f6f6c3a204e584d20746f6b656e7320617265206c6f636b656420666f7220766f74696e67a265627a7a72315820ac66113c020348db134b54bfcf79295308d58fff60cdd9c6bff72265dfed7dba64736f6c63430005110032506f6f6c3a206c656e677468206d69736d61746368000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000001bfd82675dbcc7762c84019ca518e701c0cd07e000000000000000000000000cafeae8bf47145bd573bfc436d1728cff224ca13000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000d3c21bcecceda1000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000001a784379d99db4200000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000058d15e17628000
Deployed Bytecode
0x6080604052600436106102885760003560e01c806374bd0ace1161015a578063b8caedc4116100c1578063ddf403aa1161007a578063ddf403aa14610bc7578063e942c56414610bdc578063e967eb1a14610c06578063eddd9d8214610c1b578063ee97f7f314610c30578063ffa6de3a14610c4557610288565b8063b8caedc414610aca578063b9ab992714610adf578063cf35bdd014610af4578063d02641a014610b1e578063d311afb414610b51578063d46655f414610b9457610288565b80639c9b6451116101135780639c9b6451146109245780639dd86e0f14610994578063a52f930f146109ce578063aafa936d14610a20578063ad4cc43e14610a72578063b222a4d314610ab557610288565b806374bd0ace1461077557806375466b9b146107b35780638076083d146107f65780638322fff2146108dd5780639043292a146108f2578063963bbc601461090757610288565b806343400ed7116101fe57806365a21992116101b757806365a219921461058857806366fd551d146105be57806367e4ac2c146105f157806368da80af1461065657806369f36c321461073057806370310cb71461074557610288565b806343400ed714610455578063439e2e451461048b578063441da1ba146104ce5780634779be08146104ff57806349386d87146105145780634a5e42b11461055557610288565b80631f50c989116102505780631f50c9891461033d5780632892b29c1461035257806328dd37731461037c5780632f04d798146103ac5780633f494325146103c157806341fee44a146103eb57610288565b806304e8266f1461028a5780630bb76fff146102cc5780630e29df22146102e15780630ea9c984146102e957806311267784146102fe575b005b34801561029657600080fd5b506102ba600480360360408110156102ad57600080fd5b5080359060200135610c84565b60408051918252519081900360200190f35b3480156102d857600080fd5b506102ba610cf5565b610288610cfb565b3480156102f557600080fd5b50610288610cfd565b34801561030a57600080fd5b506102886004803603606081101561032157600080fd5b506001600160a01b038135169060208101359060400135610f44565b34801561034957600080fd5b506102ba6111df565b34801561035e57600080fd5b506102ba6004803603602081101561037557600080fd5b50356111e5565b34801561038857600080fd5b506102886004803603604081101561039f57600080fd5b5080359060200135611283565b3480156103b857600080fd5b506102ba611887565b3480156103cd57600080fd5b506102ba600480360360208110156103e457600080fd5b5035611a38565b3480156103f757600080fd5b5061041e6004803603602081101561040e57600080fd5b50356001600160a01b0316611ace565b604080516001600160701b03958616815293909416602084015263ffffffff90911682840152606082015290519081900360800190f35b34801561046157600080fd5b506102ba6004803603606081101561047857600080fd5b5080359060208101359060400135611b0d565b34801561049757600080fd5b50610288600480360360608110156104ae57600080fd5b506001600160a01b03813581169160208101359091169060400135611c26565b3480156104da57600080fd5b506104e3611eac565b604080516001600160a01b039092168252519081900360200190f35b34801561050b57600080fd5b506102ba611ebb565b34801561052057600080fd5b506102ba6004803603606081101561053757600080fd5b508035906001600160a01b0360208201358116916040013516611ec0565b34801561056157600080fd5b506102886004803603602081101561057857600080fd5b50356001600160a01b0316611f61565b34801561059457600080fd5b506102ba600480360360608110156105ab57600080fd5b508035906020810135906040013561215c565b3480156105ca57600080fd5b50610288600480360360208110156105e157600080fd5b50356001600160a01b03166122a0565b3480156105fd57600080fd5b506106066124ce565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561064257818101518382015260200161062a565b505050509050019250505060405180910390f35b610288600480360360e081101561066c57600080fd5b6001600160a01b03823516916001600160e01b0319602082013516918101906060810160408201356401000000008111156106a657600080fd5b8201836020820111156106b857600080fd5b803590602001918460208302840111640100000000831117156106da57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505061ffff83351693505060ff602083013516916040810135915060600135612530565b34801561073c57600080fd5b506102ba612864565b34801561075157600080fd5b506102ba6004803603604081101561076857600080fd5b5080359060200135612900565b34801561078157600080fd5b5061079f6004803603602081101561079857600080fd5b5035612918565b604080519115158252519081900360200190f35b3480156107bf57600080fd5b5061079f600480360360608110156107d657600080fd5b506001600160a01b03813581169160208101359091169060400135612aab565b34801561080257600080fd5b50610288600480360360e081101561081957600080fd5b6001600160a01b03823516916001600160e01b03196020820135169181019060608101604082013564010000000081111561085357600080fd5b82018360208201111561086557600080fd5b8035906020019184602083028401116401000000008311171561088757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505061ffff83351693505060ff602083013516916040810135915060600135612cb1565b3480156108e957600080fd5b506104e3612e95565b3480156108fe57600080fd5b506104e3612ead565b6102886004803603602081101561091d57600080fd5b5035612ebc565b34801561093057600080fd5b506109576004803603602081101561094757600080fd5b50356001600160a01b0316613267565b604080519586526001600160701b039485166020870152929093168483015263ffffffff1660608401526080830191909152519081900360a00190f35b3480156109a057600080fd5b50610288600480360360408110156109b757600080fd5b506001600160c01b03198135169060200135613377565b3480156109da57600080fd5b50610288600480360360808110156109f157600080fd5b506001600160a01b03813516906001600160701b036020820135811691604081013590911690606001356134a0565b348015610a2c57600080fd5b5061028860048036036080811015610a4357600080fd5b506001600160a01b03813516906001600160701b036020820135811691604081013590911690606001356137c7565b348015610a7e57600080fd5b5061028860048036036040811015610a9557600080fd5b5080356001600160c01b03191690602001356001600160a01b03166139d4565b348015610ac157600080fd5b506102ba613b35565b348015610ad657600080fd5b506104e3613b3b565b348015610aeb57600080fd5b506104e3613b4a565b348015610b0057600080fd5b506104e360048036036020811015610b1757600080fd5b5035613b59565b348015610b2a57600080fd5b506102ba60048036036020811015610b4157600080fd5b50356001600160a01b0316613b80565b348015610b5d57600080fd5b5061028860048036036060811015610b7457600080fd5b506001600160a01b03813581169160208101359091169060400135613ca2565b348015610ba057600080fd5b5061028860048036036020811015610bb757600080fd5b50356001600160a01b0316613e2e565b348015610bd357600080fd5b506104e3613ead565b348015610be857600080fd5b506102ba60048036036020811015610bff57600080fd5b5035613ebc565b348015610c1257600080fd5b506104e3613ec7565b348015610c2757600080fd5b506104e3613ed6565b348015610c3c57600080fd5b506104e3613ee5565b348015610c5157600080fd5b5061028860048036036060811015610c6857600080fd5b506001600160a01b038135169060208101359060400135613ef4565b600080610c918484612900565b90506000610ca660048063ffffffff61419d16565b600a0a9050610cea6624859b044a8000610cde83610cd262588040818a60048a0a63ffffffff61419d16565b9063ffffffff6141f616565b9063ffffffff61423816565b925050505b92915050565b60095481565b565b6000809054906101000a90046001600160a01b03166001600160a01b0316639d76ea586040518163ffffffff1660e01b815260040160206040518083038186803b158015610d4a57600080fd5b505afa158015610d5e573d6000803e3d6000fd5b505050506040513d6020811015610d7457600080fd5b5051600480546001600160a01b0319166001600160a01b03928316178155600054604080516227050b60e31b815261544360f01b9381019390935251921691630138285891602480820192602092909190829003018186803b158015610dd957600080fd5b505afa158015610ded573d6000803e3d6000fd5b505050506040513d6020811015610e0357600080fd5b5051600580546001600160a01b0319166001600160a01b03928316179055600054604080516227050b60e31b815261145560f21b6004820152905191909216916301382858916024808301926020929190829003018186803b158015610e6857600080fd5b505afa158015610e7c573d6000803e3d6000fd5b505050506040513d6020811015610e9257600080fd5b5051600380546001600160a01b0319166001600160a01b03928316179055600054604080516227050b60e31b8152614d4360f01b6004820152905191909216916301382858916024808301926020929190829003018186803b158015610ef757600080fd5b505afa158015610f0b573d6000803e3d6000fd5b505050506040513d6020811015610f2157600080fd5b5051600680546001600160a01b0319166001600160a01b03909216919091179055565b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015610f9157600080fd5b505afa158015610fa5573d6000803e3d6000fd5b505050506040513d6020811015610fbb57600080fd5b505115611002576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6008546001600160a01b0316331461105c576040805162461bcd60e51b81526020600482015260186024820152772837b7b61d103737ba1039bbb0b821b7b73a3937b63632b960411b604482015290519081900360640190fd5b600054600160a01b900460ff166110a8576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556007546001600160a01b038581168084526002602090815260408086208151631ab6b2b760e01b8152949095166004850152602484019490945260448301919091526064820186905260848201859052915173cafea6a946406b0b48a77348a4f70dfeed0f466492631ab6b2b79260a48082019391829003018186803b15801561113e57600080fd5b505af4158015611152573d6000803e3d6000fd5b505050506040513d602081101561116857600080fd5b50516040805185815260208101839052815192935073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee926001600160a01b038816927fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb928290030190a350506000805460ff60a01b1916600160a01b1790555050565b6101f481565b6000806111f0611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561124257600080fd5b505afa158015611256573d6000803e3d6000fd5b505050506040513d602081101561126c57600080fd5b5051905061127b848383611b0d565b949350505050565b6000546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b1580156112ce57600080fd5b505afa1580156112e2573d6000803e3d6000fd5b505050506040513d60208110156112f857600080fd5b5051611344576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b600054600160a01b900460ff16611390576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b19811690915560408051600162f6c75960e01b0319815290516001600160a01b039092169163ff0938a791600480820192602092909190829003018186803b1580156113e457600080fd5b505afa1580156113f8573d6000803e3d6000fd5b505050506040513d602081101561140e57600080fd5b505115611455576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b60048054604080516370a0823160e01b815233938101939093525184926001600160a01b03909216916370a08231916024808301926020929190829003018186803b1580156114a357600080fd5b505afa1580156114b7573d6000803e3d6000fd5b505050506040513d60208110156114cd57600080fd5b50511015611522576040805162461bcd60e51b815260206004820152601860248201527f506f6f6c3a204e6f7420656e6f7567682062616c616e63650000000000000000604482015290519081900360640190fd5b60048054604080516398fd371f60e01b815233938101939093525142926001600160a01b03909216916398fd371f916024808301926020929190829003018186803b15801561157057600080fd5b505afa158015611584573d6000803e3d6000fd5b505050506040513d602081101561159a57600080fd5b505111156115d95760405162461bcd60e51b81526004018080602001828103825260268152602001806149d66026913960400191505060405180910390fd5b60006115e3611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561163557600080fd5b505afa158015611649573d6000803e3d6000fd5b505050506040513d602081101561165f57600080fd5b505190506000611670858484611b0d565b905081611683848363ffffffff61429216565b10156116c05760405162461bcd60e51b815260040180806020018281038252602181526020018061487a6021913960400191505060405180910390fd5b83811015611715576040805162461bcd60e51b815260206004820152601860248201527f506f6f6c3a206574684f7574203c206d696e4574684f75740000000000000000604482015290519081900360640190fd5b6005546040805163079cc67960e41b81523360048201526024810188905290516001600160a01b03909216916379cc6790916044808201926020929091908290030181600087803b15801561176957600080fd5b505af115801561177d573d6000803e3d6000fd5b505050506040513d602081101561179357600080fd5b5050604051600090339083908381818185875af1925050503d80600081146117d7576040519150601f19603f3d011682016040523d82523d6000602084013e6117dc565b606091505b5050905080611832576040805162461bcd60e51b815260206004820152601a60248201527f506f6f6c3a2053656c6c207472616e73666572206661696c6564000000000000604482015290519081900360640190fd5b6040805187815260208101849052815133927f45ea3d587ef2c627bc7085da467e1df0748c42d3ee4074b2f6b942f6876636c5928290030190a250506000805460ff60a01b1916600160a01b17905550505050565b600047815b600154811015611a32576000600182815481106118a557fe5b6000918252602080832090910154600a546040805163696ae5e360e01b81526001600160a01b03938416600482018190529151919650869594929093169263696ae5e3926024808301939192829003018186803b15801561190557600080fd5b505afa158015611919573d6000803e3d6000fd5b505050506040513d602081101561192f57600080fd5b5051905080611977576040805162461bcd60e51b815260206004820152600f60248201526e506f6f6c3a207a65726f207261746560881b604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038516916370a0823191602480820192602092909190829003018186803b1580156119c157600080fd5b505afa1580156119d5573d6000803e3d6000fd5b505050506040513d60208110156119eb57600080fd5b505190506000611a0d670de0b6b3a7640000610cd2848663ffffffff61419d16565b9050611a1f878263ffffffff61423816565b9650506001909401935061188c92505050565b50905090565b600080611a43611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a9557600080fd5b505afa158015611aa9573d6000803e3d6000fd5b505050506040513d6020811015611abf57600080fd5b5051905061127b84838361215c565b600260205260009081526040902080546001909101546001600160701b0380831692600160701b810490911691600160e01b90910463ffffffff169084565b600080611b1a8484610c84565b90506000611b3a670de0b6b3a7640000610cd2888563ffffffff61419d16565b90506000611b4e868363ffffffff61429216565b90506000611b5c8287610c84565b90506000611b8b6103e8610cd26103cf611b7f6002838b8963ffffffff61423816565b9063ffffffff61419d16565b90506000828210611b9c5782611b9e565b815b90506000611bbe670de0b6b3a7640000610cd2848e63ffffffff61419d16565b9050611bd8612710610cd28b6101f463ffffffff61419d16565b811115611c165760405162461bcd60e51b815260040180806020018281038252603881526020018061489b6038913960400191505060405180910390fd5b96505050505050505b9392505050565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b158015611c7157600080fd5b505afa158015611c85573d6000803e3d6000fd5b505050506040513d6020811015611c9b57600080fd5b5051611cd85760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b600054600160a01b900460ff16611d24576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556001600160a01b038416815260026020526040902054600160701b90046001600160701b031615611d9e576040805162461bcd60e51b8152602060048201526012602482015271506f6f6c3a206d6178206e6f74207a65726f60701b604482015290519081900360640190fd5b6001600160a01b038216611deb576040805162461bcd60e51b815260206004820152600f60248201526e506f6f6c3a2064657374207a65726f60881b604482015290519081900360640190fd5b604080516370a0823160e01b8152306004820152905184916000916001600160a01b038416916370a08231916024808301926020929190829003018186803b158015611e3657600080fd5b505afa158015611e4a573d6000803e3d6000fd5b505050506040513d6020811015611e6057600080fd5b505190506000818411611e735783611e75565b815b9050611e916001600160a01b038416868363ffffffff6142d416565b50506000805460ff60a01b1916600160a01b17905550505050565b6003546001600160a01b031681565b600481565b6040805163ca31d03f60e01b8152600481018590526001600160a01b03808516602483015283166044820152905160009173cafea6a946406b0b48a77348a4f70dfeed0f46649163ca31d03f91606480820192602092909190829003018186803b158015611f2d57600080fd5b505af4158015611f41573d6000803e3d6000fd5b505050506040513d6020811015611f5757600080fd5b5051949350505050565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b158015611fac57600080fd5b505afa158015611fc0573d6000803e3d6000fd5b505050506040513d6020811015611fd657600080fd5b50516120135760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b60005b600154811015612113576001818154811061202d57fe5b6000918252602090912001546001600160a01b038381169116146120505761210b565b6001600160a01b03821660009081526002602052604081208181556001908101919091558054600019810190811061208457fe5b600091825260209091200154600180546001600160a01b0390921691839081106120aa57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060018054806120e357fe5b600082815260209020810160001990810180546001600160a01b031916905501905550612159565b600101612016565b506040805162461bcd60e51b8152602060048201526015602482015274141bdbdb0e88185cdcd95d081b9bdd08199bdd5b99605a1b604482015290519081900360640190fd5b50565b6000612176612710610cd2846101f463ffffffff61419d16565b8411156121b45760405162461bcd60e51b815260040180806020018281038252603e81526020018061483c603e913960400191505060405180910390fd5b8215806121d4575064e8d4a510006121d2838563ffffffff6141f616565b115b15612205576624859b044a80006121fd81610cd287670de0b6b3a764000063ffffffff61419d16565b915050611c1f565b6000612211848461432b565b90506000612225858763ffffffff61423816565b90506000612233828661432b565b90506000612247848363ffffffff61429216565b9050600061226782610cd28b670de0b6b3a764000063ffffffff61419d16565b90506000612282826624859b044a800063ffffffff61423816565b9050611c1681610cd28c670de0b6b3a764000063ffffffff61419d16565b6000546001600160a01b0316156122fd576000546001600160a01b031633146122fd576040805162461bcd60e51b815260206004820152600a6024820152692737ba1036b0b9ba32b960b11b604482015290519081900360640190fd5b600054600160a01b900460ff16612349576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556040514791906001600160a01b0384169083908381818185875af1925050503d80600081146123a1576040519150601f19603f3d011682016040523d82523d6000602084013e6123a6565b606091505b50509050806123f4576040805162461bcd60e51b8152602060048201526015602482015274141bdbdb0e881d1c985b9cd9995c8819985a5b1959605a1b604482015290519081900360640190fd5b60005b6001548110156124b55760006001828154811061241057fe5b6000918252602080832090910154604080516370a0823160e01b815230600482015290516001600160a01b03909216945084926370a0823192602480840193829003018186803b15801561246357600080fd5b505afa158015612477573d6000803e3d6000fd5b505050506040513d602081101561248d57600080fd5b505190506124ab6001600160a01b038316878363ffffffff6142d416565b50506001016123f7565b50506000805460ff60a01b1916600160a01b1790555050565b6060600180548060200260200160405190810160405280929190818152602001828054801561252657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612508575b5050505050905090565b6000546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b15801561257b57600080fd5b505afa15801561258f573d6000803e3d6000fd5b505050506040513d60208110156125a557600080fd5b50516125f1576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561263e57600080fd5b505afa158015612652573d6000803e3d6000fd5b505050506040513d602081101561266857600080fd5b5051156126af576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6208aa8960eb1b6001600160e01b0319871614612713576040805162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a20556e657870656374656420617373657420747970650000000000604482015290519081900360640190fd5b8460018151811061272057fe5b602002602001015134146127655760405162461bcd60e51b81526004018080602001828103825260278152602001806149af6027913960400191505060405180910390fd5b60035460405163250bc23960e11b815233600482018181526001600160a01b038b811660248501526001600160e01b03198b16604485015261ffff8916608485015260ff881660a485015260c4840187905260e48401869052610100606485019081528a516101048601528a519190951694634a178472948d938d938d938d938d938d938d93919261012401906020808a01910280838360005b838110156128175781810151838201526020016127ff565b505050509050019950505050505050505050600060405180830381600087803b15801561284357600080fd5b505af1158015612857573d6000803e3d6000fd5b5050505050505050505050565b60008061286f611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128c157600080fd5b505afa1580156128d5573d6000803e3d6000fd5b505050506040513d60208110156128eb57600080fd5b505190506128f98282612900565b9250505090565b6000611c1f82610cd28561271063ffffffff61419d16565b600080546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b15801561296457600080fd5b505afa158015612978573d6000803e3d6000fd5b505050506040513d602081101561298e57600080fd5b50516129da576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015612a2757600080fd5b505afa158015612a3b573d6000803e3d6000fd5b505050506040513d6020811015612a5157600080fd5b505115612a98576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b612aa3826000611283565b506001919050565b60008054604080516323c5b10760e21b815233600482015290516001600160a01b0390921691638f16c41c91602480820192602092909190829003018186803b158015612af757600080fd5b505afa158015612b0b573d6000803e3d6000fd5b505050506040513d6020811015612b2157600080fd5b5051612b5e5760405162461bcd60e51b81526004018080602001828103825260228152602001806149636022913960400191505060405180910390fd5b600054600160a01b900460ff16612baa576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556001600160a01b03851673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415612c35576040516001600160a01b038516908490600081818185875af1925050503d8060008114612c25576040519150601f19603f3d011682016040523d82523d6000602084013e612c2a565b606091505b505080915050612c43565b612c4085858561435b565b90505b8015612c9557846001600160a01b0316846001600160a01b03167febe7adb4feddf2afa5de463169fdc706254a55c9cf2b930ac84bb49e28cfe6bb856040518082815260200191505060405180910390a35b90506000805460ff60a01b1916600160a01b1790559392505050565b6000546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b158015612cfc57600080fd5b505afa158015612d10573d6000803e3d6000fd5b505050506040513d6020811015612d2657600080fd5b5051612d72576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015612dbf57600080fd5b505afa158015612dd3573d6000803e3d6000fd5b505050506040513d6020811015612de957600080fd5b505115612e30576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6208aa8960eb1b6001600160e01b031987161415612765576040805162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a20556e657870656374656420617373657420747970650000000000604482015290519081900360640190fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6007546001600160a01b031681565b6000546040805163288c314960e21b815233600482015290516001600160a01b039092169163a230c52491602480820192602092909190829003018186803b158015612f0757600080fd5b505afa158015612f1b573d6000803e3d6000fd5b505050506040513d6020811015612f3157600080fd5b5051612f7d576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba10309036b2b6b132b960511b604482015290519081900360640190fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015612fca57600080fd5b505afa158015612fde573d6000803e3d6000fd5b505050506040513d6020811015612ff457600080fd5b50511561303b576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b3480613080576040805162461bcd60e51b815260206004820152600f60248201526e0506f6f6c3a20657468496e203e203608c1b604482015290519081900360640190fd5b600061309a8261308e611887565b9063ffffffff61429216565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156130ec57600080fd5b505afa158015613100573d6000803e3d6000fd5b505050506040513d602081101561311657600080fd5b5051905060006131268383612900565b9050619c408111156131695760405162461bcd60e51b81526004018080602001828103825260248152602001806148d36024913960400191505060405180910390fd5b600061317685858561215c565b9050858110156131b75760405162461bcd60e51b81526004018080602001828103825260298152602001806149186029913960400191505060405180910390fd5b600554604080516340c10f1960e01b81523360048201526024810184905290516001600160a01b03909216916340c10f199160448082019260009290919082900301818387803b15801561320a57600080fd5b505af115801561321e573d6000803e3d6000fd5b5050604080518881526020810185905281513394507fb4bf7fd11bc97d76c39ed13880388ee221d6971dd18f90e65179e0056d24671193509081900390910190a2505050505050565b600080600080600080869050806001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156132c957600080fd5b505afa1580156132dd573d6000803e3d6000fd5b505050506040513d60208110156132f357600080fd5b505195506132ff6147f4565b505050506001600160a01b0393909316600090815260026020908152604091829020825160808101845281546001600160701b03808216808452600160701b8304909116948301859052600160e01b90910463ffffffff16948201859052600190920154606090910181905294969095509093919250565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b1580156133c257600080fd5b505afa1580156133d6573d6000803e3d6000fd5b505050506040513d60208110156133ec57600080fd5b50516134295760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b6609a929cbe8aa8960cb1b6001600160c01b03198316141561344f57600981905561349c565b6040805162461bcd60e51b815260206004820152601760248201527f506f6f6c3a20756e6b6e6f776e20706172616d65746572000000000000000000604482015290519081900360640190fd5b5050565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b1580156134eb57600080fd5b505afa1580156134ff573d6000803e3d6000fd5b505050506040513d602081101561351557600080fd5b50516135525760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b6001600160a01b0384166135ad576040805162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a206173736574206973207a65726f20616464726573730000000000604482015290519081900360640190fd5b826001600160701b0316826001600160701b03161015613606576040805162461bcd60e51b815260206004820152600f60248201526e2837b7b61d1036b0bc101e1036b4b760891b604482015290519081900360640190fd5b670de0b6b3a7640000811115613663576040805162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a206d617820736c69707061676520726174696f203e203100000000604482015290519081900360640190fd5b60005b6001548110156136e6576001818154811061367d57fe5b6000918252602090912001546001600160a01b03868116911614156136de576040805162461bcd60e51b8152602060048201526012602482015271506f6f6c3a2061737365742065786973747360701b604482015290519081900360640190fd5b600101613666565b506001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b039096166001600160a01b031990961686179055604080516080810182526001600160701b0395861681529385166020858101918252600086840181815260608801968752988152600290915291909120935184549151965163ffffffff16600160e01b026001600160e01b03978716600160701b02600160701b600160e01b0319929097166001600160701b0319909316929092171694909417949094169290921781559051910155565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b15801561381257600080fd5b505afa158015613826573d6000803e3d6000fd5b505050506040513d602081101561383c57600080fd5b50516138795760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b816001600160701b0316836001600160701b031611156138d2576040805162461bcd60e51b815260206004820152600f60248201526e0a0deded87440dad2dc407c40dac2f608b1b604482015290519081900360640190fd5b670de0b6b3a764000081111561392f576040805162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a206d617820736c69707061676520726174696f203e203100000000604482015290519081900360640190fd5b60005b600154811015612113576001818154811061394957fe5b6000918252602090912001546001600160a01b0386811691161461396c576139c6565b506001600160a01b038416600090815260026020526040902080546001600160701b03848116600160701b02600160701b600160e01b03199187166001600160701b031990931692909217161781556001018190556139ce565b600101613932565b50505050565b60005460408051632c1a733d60e11b815233600482015290516001600160a01b0390921691635834e67a91602480820192602092909190829003018186803b158015613a1f57600080fd5b505afa158015613a33573d6000803e3d6000fd5b505050506040513d6020811015613a4957600080fd5b5051613a865760405162461bcd60e51b81526004018080602001828103825260228152602001806149416022913960400191505060405180910390fd5b630545741560e41b6001600160c01b031983161415613abf57600780546001600160a01b0319166001600160a01b03831617905561349c565b630535741560e41b6001600160c01b031983161415613af857600880546001600160a01b0319166001600160a01b03831617905561349c565b67141490d7d191515160c21b6001600160c01b03198316141561344f57600a80546001600160a01b0319166001600160a01b03831617905561349c565b619c4081565b6006546001600160a01b031681565b600a546001600160a01b031681565b60018181548110613b6657fe5b6000918252602090912001546001600160a01b0316905081565b600080613b8b611887565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663b775a49d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613bdd57600080fd5b505afa158015613bf1573d6000803e3d6000fd5b505050506040513d6020811015613c0757600080fd5b505190506000613c178383610c84565b600a5460408051632ae2073360e11b81526001600160a01b0389811660048301526024820185905291519394509116916355c40e6691604480820192602092909190829003018186803b158015613c6d57600080fd5b505afa158015613c81573d6000803e3d6000fd5b505050506040513d6020811015613c9757600080fd5b505195945050505050565b600054604080516323c5b10760e21b815233600482015290516001600160a01b0390921691638f16c41c91602480820192602092909190829003018186803b158015613ced57600080fd5b505afa158015613d01573d6000803e3d6000fd5b505050506040513d6020811015613d1757600080fd5b5051613d545760405162461bcd60e51b81526004018080602001828103825260228152602001806149636022913960400191505060405180910390fd5b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015613da157600080fd5b505afa158015613db5573d6000803e3d6000fd5b505050506040513d6020811015613dcb57600080fd5b505115613e12576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b826139ce6001600160a01b03821684308563ffffffff6144ad16565b6000546001600160a01b031615613e8b576000546001600160a01b03163314613e8b576040805162461bcd60e51b815260206004820152600a6024820152692737ba1036b0b9ba32b960b11b604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b031681565b6000610cef826111e5565b6004546001600160a01b031681565b6005546001600160a01b031681565b6000546001600160a01b031681565b6000809054906101000a90046001600160a01b03166001600160a01b031663ff0938a76040518163ffffffff1660e01b815260040160206040518083038186803b158015613f4157600080fd5b505afa158015613f55573d6000803e3d6000fd5b505050506040513d6020811015613f6b57600080fd5b505115613fb2576040805162461bcd60e51b815260206004820152601060248201526f14de5cdd195b481a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6008546001600160a01b0316331461400c576040805162461bcd60e51b81526020600482015260186024820152772837b7b61d103737ba1039bbb0b821b7b73a3937b63632b960411b604482015290519081900360640190fd5b600054600160a01b900460ff16614058576040805162461bcd60e51b815260206004820152601f602482015260008051602061481c833981519152604482015290519081900360640190fd5b6000805460ff60a01b191681556001600160a01b03808516808352600260209081526040808520600754600954835163d56b5b1560e01b8152919096166004820152602481018290526044810194909452606484018890526084840187905260a48401949094525192939273cafea6a946406b0b48a77348a4f70dfeed0f46649263d56b5b159260c4808301939192829003018186803b1580156140fb57600080fd5b505af415801561410f573d6000803e3d6000fd5b505050506040513d602081101561412557600080fd5b5051604080518681526020810183905281519293506001600160a01b0388169273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee927fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb928290030190a350506000805460ff60a01b1916600160a01b179055505050565b6000826141ac57506000610cef565b828202828482816141b957fe5b0414611c1f5760405162461bcd60e51b81526004018080602001828103825260218152602001806148f76021913960400191505060405180910390fd5b6000611c1f83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614507565b600082820183811015611c1f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611c1f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506145a9565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052614326908490614603565b505050565b6000611c1f83610cd284611b7f838383838383838360038362588040670de0b6b3a764000063ffffffff61419d16565b600061436f846001600160a01b03166147bb565b61437b57506000611c1f565b604080516001600160a01b038581166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17815292518251889460009360609390871692869282918083835b602083106143f95780518252601f1990920191602091820191016143da565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461445b576040519150601f19603f3d011682016040523d82523d6000602084013e614460565b606091505b509150915081614477576000945050505050611c1f565b805161448a576001945050505050611c1f565b80806020019051602081101561449f57600080fd5b505198975050505050505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526139ce908590614603565b600081836145935760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614558578181015183820152602001614540565b50505050905090810190601f1680156145855780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161459f57fe5b0495945050505050565b600081848411156145fb5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614558578181015183820152602001614540565b505050900390565b614615826001600160a01b03166147bb565b614666576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106146a45780518252601f199092019160209182019101614685565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614706576040519150601f19603f3d011682016040523d82523d6000602084013e61470b565b606091505b509150915081614762576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156139ce5780806020019051602081101561477e57600080fd5b50516139ce5760405162461bcd60e51b815260040180806020018281038252602a815260200180614985602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061127b575050151592915050565b6040805160808101825260008082526020820181905291810182905260608101919091529056fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c00506f6f6c3a2050757263686173657320776f72746820686967686572207468616e203525206f66204d435265746820617265206e6f7420616c6c6f776564506f6f6c3a204d4352252063616e6e6f742066616c6c2062656c6f772031303025506f6f6c3a2053616c657320776f727468206d6f7265207468616e203525206f66204d435265746820617265206e6f7420616c6c6f776564506f6f6c3a2043616e6e6f74207075726368617365206966204d435225203e2034303025536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77506f6f6c3a20746f6b656e734f7574206973206c657373207468616e206d696e546f6b656e734f757443616c6c6572206973206e6f7420617574686f72697a656420746f20676f7665726e43616c6c6572206973206e6f7420616e20696e7465726e616c20636f6e74726163745361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564506f6f6c3a2045544820616d6f756e7420646f6573206e6f74206d61746368207072656d69756d506f6f6c3a204e584d20746f6b656e7320617265206c6f636b656420666f7220766f74696e67a265627a7a72315820ac66113c020348db134b54bfcf79295308d58fff60cdd9c6bff72265dfed7dba64736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000001bfd82675dbcc7762c84019ca518e701c0cd07e000000000000000000000000cafeae8bf47145bd573bfc436d1728cff224ca13000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000d3c21bcecceda1000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000001a784379d99db4200000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000058d15e17628000
-----Decoded View---------------
Arg [0] : _assets (address[]): 0x6B175474E89094C44Da98b954EedeAC495271d0F
Arg [1] : _minAmounts (uint112[]): 1000000000000000000000000
Arg [2] : _maxAmounts (uint112[]): 2000000000000000000000000
Arg [3] : _maxSlippageRatios (uint256[]): 25000000000000000
Arg [4] : _master (address): 0x01BFd82675DBCc7762C84019cA518e701C0cD07e
Arg [5] : _priceOracle (address): 0xcafeaE8bF47145BD573BFC436D1728Cff224cA13
Arg [6] : _twapOracle (address): 0xcafea1C9f94e077DF44D95c4A1ad5a5747a18b5C
Arg [7] : _swapController (address): 0x551D5500F613a4beC77BA8B834b5eEd52ad5764f
-----Encoded View---------------
16 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [3] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [4] : 00000000000000000000000001bfd82675dbcc7762c84019ca518e701c0cd07e
Arg [5] : 000000000000000000000000cafeae8bf47145bd573bfc436d1728cff224ca13
Arg [6] : 000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c
Arg [7] : 000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [11] : 00000000000000000000000000000000000000000000d3c21bcecceda1000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [13] : 00000000000000000000000000000000000000000001a784379d99db42000000
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [15] : 0000000000000000000000000000000000000000000000000058d15e17628000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ 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.