Polygon Sponsored slots available. Book your slot here!
Contract Overview
My Name Tag:
Not Available, login to update
Txn Hash |
Method
|
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0xac60623eca12390b19b86d474e5c37bed65ceb46512a514b02dfa67fb2594e81 | Update Price | 22634493 | 526 days 9 hrs ago | 0x236eccab8cdcfedb099de85c4060024ba3ce4d46 | IN | 0xe0e828643266fab54716503f82fb404867214f39 | 0 MATIC | 0.00122223 | |
0x51d210cc1074c2584c4f99d1298e2a2a323fdca271ca7f48aed5d41f58015b92 | Update Price | 22634461 | 526 days 9 hrs ago | 0x236eccab8cdcfedb099de85c4060024ba3ce4d46 | IN | 0xe0e828643266fab54716503f82fb404867214f39 | 0 MATIC | 0.0031596 | |
0x79da7d019238e9e362a75ee16a5e22cdd378f44d82150c0299874f837da55b56 | 0x60c06040 | 22634321 | 526 days 9 hrs ago | 0x236eccab8cdcfedb099de85c4060024ba3ce4d46 | IN | Create: IndexedUniswapV2Oracle | 0 MATIC | 0.08233467 |
[ Download CSV Export ]
Contract Name:
IndexedUniswapV2Oracle
Compiler Version
v0.6.8+commit.0bbfe453
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; /* ========== Internal Libraries ========== */ import "./lib/PriceLibrary.sol"; import "./lib/FixedPoint.sol"; import "./lib/IndexedPriceMapLibrary.sol"; /* ========== Internal Inheritance ========== */ import "./interfaces/IIndexedUniswapV2Oracle.sol"; contract IndexedUniswapV2Oracle is IIndexedUniswapV2Oracle { using PriceLibrary for address; using PriceLibrary for PriceLibrary.PriceObservation; using PriceLibrary for PriceLibrary.TwoWayAveragePrice; using FixedPoint for FixedPoint.uq112x112; using FixedPoint for FixedPoint.uq144x112; using IndexedPriceMapLibrary for IndexedPriceMapLibrary.IndexedPriceMap; /* ========== Immutables ========== */ address internal immutable _uniswapFactory; address internal immutable _weth; /* ========== Storage ========== */ // Price observations for tokens indexed by hour. mapping(address => IndexedPriceMapLibrary.IndexedPriceMap) internal _tokenPriceMaps; /* ========== Modifiers ========== */ modifier validMinMax(uint256 minTimeElapsed, uint256 maxTimeElapsed) { require( maxTimeElapsed >= minTimeElapsed, "IndexedUniswapV2Oracle::validMinMax: Minimum age can not be higher than maximum." ); _; } /* ========== Constructor ========== */ constructor(address uniswapFactory, address weth) public { _uniswapFactory = uniswapFactory; _weth = weth; } /* ========== Mutative Functions ========== */ /** * @dev Attempts to update the price of `token` and returns a boolean * indicating whether it was updated. * * Note: The price can be updated if there is no observation for the current hour * and at least 30 minutes have passed since the last observation. */ function updatePrice(address token) public override returns (bool/* didUpdatePrice */) { if (token == _weth) return true; PriceLibrary.PriceObservation memory observation = _uniswapFactory.observeTwoWayPrice(token, _weth); return _tokenPriceMaps[token].writePriceObservation(observation); } /** * @dev Attempts to update the price of each token in `tokens` and returns a boolean * array indicating which tokens had their prices updated. * * Note: The price can be updated if there is no observation for the current hour * and at least 30 minutes have passed since the last observation. */ function updatePrices(address[] calldata tokens) external override returns (bool[] memory pricesUpdated) { uint256 len = tokens.length; pricesUpdated = new bool[](len); for (uint256 i = 0; i < len; i++) { pricesUpdated[i] = updatePrice(tokens[i]); } } /* ========== Meta Price Queries ========== */ /** * @dev Returns a boolean indicating whether a price was recorded for `token` at `priceKey`. * * @param token Token to check if the oracle has a price for * @param priceKey Index of the hour to check */ function hasPriceObservationInWindow(address token, uint256 priceKey) external view override returns (bool) { return _tokenPriceMaps[token].hasPriceInWindow(priceKey); } /** * @dev Returns the price observation for `token` recorded in `priceKey`. * Reverts if no prices have been recorded for that key. * * @param token Token to retrieve a price for * @param priceKey Index of the hour to query */ function getPriceObservationInWindow(address token, uint256 priceKey) external view override returns (PriceLibrary.PriceObservation memory observation) { observation = _tokenPriceMaps[token].getPriceInWindow(priceKey); require( observation.timestamp != 0, "IndexedUniswapV2Oracle::getPriceObservationInWindow: No price observed in given hour." ); } /** * @dev Returns all price observations for `token` recorded between `timeFrom` and `timeTo`. */ function getPriceObservationsInRange(address token, uint256 timeFrom, uint256 timeTo) external view override returns (PriceLibrary.PriceObservation[] memory prices) { prices = _tokenPriceMaps[token].getPriceObservationsInRange(timeFrom, timeTo); } /* ========== Price Update Queries ========== */ /** * @dev Returns a boolean indicating whether the price of `token` can be updated. * * Note: The price can be updated if there is no observation for the current hour * and at least 30 minutes have passed since the last observation. */ function canUpdatePrice(address token) external view override returns (bool/* canUpdatePrice */) { if (!_uniswapFactory.pairInitialized(token, _weth)) return false; return _tokenPriceMaps[token].canUpdatePrice(uint32(now)); } /** * @dev Returns a boolean array indicating whether the price of each token in * `tokens` can be updated. * * Note: The price can be updated if there is no observation for the current hour * and at least 30 minutes have passed since the last observation. */ function canUpdatePrices(address[] calldata tokens) external view override returns (bool[] memory canUpdateArr) { uint256 len = tokens.length; canUpdateArr = new bool[](len); for (uint256 i = 0; i < len; i++) { address token = tokens[i]; bool timeAllowed = _tokenPriceMaps[token].canUpdatePrice(uint32(now)); canUpdateArr[i] = timeAllowed && _uniswapFactory.pairInitialized(token, _weth); } } /* ========== Price Queries: Singular ========== */ /** * @dev Returns the TwoWayAveragePrice struct representing the average price of * weth in terms of `token` and the average price of `token` in terms of weth. * * Computes the time-weighted average price of weth in terms of `token` and the price * of `token` in terms of weth by getting the current prices from Uniswap and searching * for a historical price which is between `minTimeElapsed` and `maxTimeElapsed` seconds old. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeTwoWayAveragePrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (PriceLibrary.TwoWayAveragePrice memory) { return _getTwoWayPrice(token, minTimeElapsed, maxTimeElapsed); } /** * @dev Returns the UQ112x112 struct representing the average price of * `token` in terms of weth. * * Computes the time-weighted average price of `token` in terms of weth by getting the * current price from Uniswap and searching for a historical price which is between * `minTimeElapsed` and `maxTimeElapsed` seconds old. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeAverageTokenPrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (FixedPoint.uq112x112 memory priceAverage) { return _getTokenPrice(token, minTimeElapsed, maxTimeElapsed); } /** * @dev Returns the UQ112x112 struct representing the average price of * weth in terms of `token`. * * Computes the time-weighted average price of weth in terms of `token` by getting the * current price from Uniswap and searching for a historical price which is between * `minTimeElapsed` and `maxTimeElapsed` seconds old. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeAverageEthPrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (FixedPoint.uq112x112 memory priceAverage) { return _getEthPrice(token, minTimeElapsed, maxTimeElapsed); } /* ========== Price Queries: Multiple ========== */ /** * @dev Returns the TwoWayAveragePrice structs representing the average price of * weth in terms of each token in `tokens` and the average price of each token * in terms of weth. * * Computes the time-weighted average price of weth in terms of each token and the price * of each token in terms of weth by getting the current prices from Uniswap and searching * for a historical price which is between `minTimeElapsed` and `maxTimeElapsed` seconds old. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeTwoWayAveragePrices( address[] calldata tokens, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (PriceLibrary.TwoWayAveragePrice[] memory prices) { uint256 len = tokens.length; prices = new PriceLibrary.TwoWayAveragePrice[](len); for (uint256 i = 0; i < len; i++) { prices[i] = _getTwoWayPrice(tokens[i], minTimeElapsed, maxTimeElapsed); } } /** * @dev Returns the UQ112x112 structs representing the average price of * each token in `tokens` in terms of weth. * * Computes the time-weighted average price of each token in terms of weth by getting * the current price from Uniswap and searching for a historical price which is between * `minTimeElapsed` and `maxTimeElapsed` seconds old. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeAverageTokenPrices( address[] calldata tokens, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (FixedPoint.uq112x112[] memory averagePrices) { uint256 len = tokens.length; averagePrices = new FixedPoint.uq112x112[](len); for (uint256 i = 0; i < len; i++) { averagePrices[i] = _getTokenPrice(tokens[i], minTimeElapsed, maxTimeElapsed); } } /** * @dev Returns the UQ112x112 structs representing the average price of * weth in terms of each token in `tokens`. * * Computes the time-weighted average price of weth in terms of each token by getting * the current price from Uniswap and searching for a historical price which is between * `minTimeElapsed` and `maxTimeElapsed` seconds old. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeAverageEthPrices( address[] calldata tokens, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (FixedPoint.uq112x112[] memory averagePrices) { uint256 len = tokens.length; averagePrices = new FixedPoint.uq112x112[](len); for (uint256 i = 0; i < len; i++) { averagePrices[i] = _getEthPrice(tokens[i], minTimeElapsed, maxTimeElapsed); } } /* ========== Value Queries: Singular ========== */ /** * @dev Compute the average value of `tokenAmount` ether in terms of weth. * * Computes the time-weighted average price of `token` in terms of weth by getting * the current price from Uniswap and searching for a historical price which is between * `minTimeElapsed` and `maxTimeElapsed` seconds old, then multiplies by `wethAmount`. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeAverageEthForTokens( address token, uint256 tokenAmount, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (uint144 /* averageValueInWETH */) { FixedPoint.uq112x112 memory tokenPrice = _getTokenPrice(token, minTimeElapsed, maxTimeElapsed); return tokenPrice.mul(tokenAmount).decode144(); } /** * @dev Compute the average value of `wethAmount` ether in terms of `token`. * * Computes the time-weighted average price of weth in terms of the token by getting * the current price from Uniswap and searching for a historical price which is between * `minTimeElapsed` and `maxTimeElapsed` seconds old, then multiplies by `wethAmount`. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeAverageTokensForEth( address token, uint256 wethAmount, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (uint144 /* averageValueInToken */) { FixedPoint.uq112x112 memory ethPrice = _getEthPrice(token, minTimeElapsed, maxTimeElapsed); return ethPrice.mul(wethAmount).decode144(); } /* ========== Value Queries: Multiple ========== */ /** * @dev Compute the average value of each amount of tokens in `tokenAmounts` in terms * of the corresponding token in `tokens`. * * Computes the time-weighted average price of each token in terms of weth by getting * the current price from Uniswap and searching for a historical price which is between * `minTimeElapsed` and `maxTimeElapsed` seconds old, then multiplies by the corresponding * amount in `tokenAmounts`. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeAverageEthForTokens( address[] calldata tokens, uint256[] calldata tokenAmounts, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (uint144[] memory averageValuesInWETH) { uint256 len = tokens.length; require( tokenAmounts.length == len, "IndexedUniswapV2Oracle::computeAverageEthForTokens: Tokens and amounts have different lengths." ); averageValuesInWETH = new uint144[](len); for (uint256 i = 0; i < len; i++) { averageValuesInWETH[i] = _getTokenPrice( tokens[i], minTimeElapsed, maxTimeElapsed ).mul(tokenAmounts[i]).decode144(); } } /** * @dev Compute the average value of each amount of ether in `wethAmounts` in terms * of the corresponding token in `tokens`. * * Computes the time-weighted average price of weth in terms of each token by getting * the current price from Uniswap and searching for a historical price which is between * `minTimeElapsed` and `maxTimeElapsed` seconds old, then multiplies by the corresponding * amount in `wethAmounts`. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is less than one hour. * Note: `minTimeElapsed` is only accurate to the nearest hour (rounded up) unless * it is less than one hour. */ function computeAverageTokensForEth( address[] calldata tokens, uint256[] calldata wethAmounts, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view override validMinMax(minTimeElapsed, maxTimeElapsed) returns (uint144[] memory averageValuesInWETH) { uint256 len = tokens.length; require( wethAmounts.length == len, "IndexedUniswapV2Oracle::computeAverageTokensForEth: Tokens and amounts have different lengths." ); averageValuesInWETH = new uint144[](len); for (uint256 i = 0; i < len; i++) { averageValuesInWETH[i] = _getEthPrice( tokens[i], minTimeElapsed, maxTimeElapsed ).mul(wethAmounts[i]).decode144(); } } /* ========== Internal Functions ========== */ function _getTwoWayPrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) internal view returns (PriceLibrary.TwoWayAveragePrice memory) { if (token == _weth) { return PriceLibrary.TwoWayAveragePrice( FixedPoint.encode(1)._x, FixedPoint.encode(1)._x ); } // Get the current cumulative price PriceLibrary.PriceObservation memory current = _uniswapFactory.observeTwoWayPrice(token, _weth); // Get the latest usable price (bool foundPrice, uint256 lastPriceKey) = _tokenPriceMaps[token].getLastPriceObservation( current.timestamp, minTimeElapsed, maxTimeElapsed ); require(foundPrice, "IndexedUniswapV2Oracle::_getTwoWayPrice: No price found in provided range."); PriceLibrary.PriceObservation memory previous = _tokenPriceMaps[token].priceMap[lastPriceKey]; return previous.computeTwoWayAveragePrice(current); } function _getTokenPrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) internal view returns (FixedPoint.uq112x112 memory) { if (token == _weth) { return FixedPoint.fraction(1, 1); } (uint32 timestamp, uint224 priceCumulativeEnd) = _uniswapFactory.observePrice(token, _weth); (bool foundPrice, uint256 lastPriceKey) = _tokenPriceMaps[token].getLastPriceObservation( timestamp, minTimeElapsed, maxTimeElapsed ); require(foundPrice, "IndexedUniswapV2Oracle::_getTokenPrice: No price found in provided range."); PriceLibrary.PriceObservation storage previous = _tokenPriceMaps[token].priceMap[lastPriceKey]; return PriceLibrary.computeAveragePrice( previous.timestamp, previous.priceCumulativeLast, timestamp, priceCumulativeEnd ); } function _getEthPrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) internal view returns (FixedPoint.uq112x112 memory) { if (token == _weth) { return FixedPoint.fraction(1, 1); } (uint32 timestamp, uint224 priceCumulativeEnd) = _uniswapFactory.observePrice(_weth, token); (bool foundPrice, uint256 lastPriceKey) = _tokenPriceMaps[token].getLastPriceObservation( timestamp, minTimeElapsed, maxTimeElapsed ); require(foundPrice, "IndexedUniswapV2Oracle::_getEthPrice: No price found in provided range."); PriceLibrary.PriceObservation storage previous = _tokenPriceMaps[token].priceMap[lastPriceKey]; return PriceLibrary.computeAveragePrice( previous.timestamp, previous.ethPriceCumulativeLast, timestamp, priceCumulativeEnd ); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; /* ========== Internal Libraries ========== */ import "./FixedPoint.sol"; import "./UniswapV2OracleLibrary.sol"; import "./UniswapV2Library.sol"; library PriceLibrary { using FixedPoint for FixedPoint.uq112x112; using FixedPoint for FixedPoint.uq144x112; /* ========= Structs ========= */ struct PriceObservation { uint32 timestamp; uint224 priceCumulativeLast; uint224 ethPriceCumulativeLast; } /** * @dev Average prices for a token in terms of weth and weth in terms of the token. * * Note: The average weth price is not equivalent to the reciprocal of the average * token price. See the UniSwap whitepaper for more info. */ struct TwoWayAveragePrice { uint224 priceAverage; uint224 ethPriceAverage; } /* ========= View Functions ========= */ function pairInitialized( address uniswapFactory, address token, address weth ) internal view returns (bool) { address pair = UniswapV2Library.pairFor(uniswapFactory, token, weth); (uint112 reserve0, uint112 reserve1,) = IUniswapV2Pair(pair).getReserves(); return reserve0 != 0 && reserve1 != 0; } function observePrice( address uniswapFactory, address tokenIn, address quoteToken ) internal view returns (uint32 /* timestamp */, uint224 /* priceCumulativeLast */) { (address token0, address token1) = UniswapV2Library.sortTokens(tokenIn, quoteToken); address pair = UniswapV2Library.calculatePair(uniswapFactory, token0, token1); if (token0 == tokenIn) { (uint256 price0Cumulative, uint32 blockTimestamp) = UniswapV2OracleLibrary.currentCumulativePrice0(pair); return (blockTimestamp, uint224(price0Cumulative)); } else { (uint256 price1Cumulative, uint32 blockTimestamp) = UniswapV2OracleLibrary.currentCumulativePrice1(pair); return (blockTimestamp, uint224(price1Cumulative)); } } /** * @dev Query the current cumulative price of a token in terms of weth * and the current cumulative price of weth in terms of the token. */ function observeTwoWayPrice( address uniswapFactory, address token, address weth ) internal view returns (PriceObservation memory) { (address token0, address token1) = UniswapV2Library.sortTokens(token, weth); address pair = UniswapV2Library.calculatePair(uniswapFactory, token0, token1); // Get the sorted token prices ( uint256 price0Cumulative, uint256 price1Cumulative, uint32 blockTimestamp ) = UniswapV2OracleLibrary.currentCumulativePrices(pair); // Check which token is weth and which is the token, // then build the price observation. if (token0 == token) { return PriceObservation({ timestamp: blockTimestamp, priceCumulativeLast: uint224(price0Cumulative), ethPriceCumulativeLast: uint224(price1Cumulative) }); } else { return PriceObservation({ timestamp: blockTimestamp, priceCumulativeLast: uint224(price1Cumulative), ethPriceCumulativeLast: uint224(price0Cumulative) }); } } /* ========= Utility Functions ========= */ /** * @dev Computes the average price of a token in terms of weth * and the average price of weth in terms of a token using two * price observations. */ function computeTwoWayAveragePrice( PriceObservation memory observation1, PriceObservation memory observation2 ) internal pure returns (TwoWayAveragePrice memory) { uint32 timeElapsed = uint32(observation2.timestamp - observation1.timestamp); FixedPoint.uq112x112 memory priceAverage = UniswapV2OracleLibrary.computeAveragePrice( observation1.priceCumulativeLast, observation2.priceCumulativeLast, timeElapsed ); FixedPoint.uq112x112 memory ethPriceAverage = UniswapV2OracleLibrary.computeAveragePrice( observation1.ethPriceCumulativeLast, observation2.ethPriceCumulativeLast, timeElapsed ); return TwoWayAveragePrice({ priceAverage: priceAverage._x, ethPriceAverage: ethPriceAverage._x }); } function computeAveragePrice( uint32 timestampStart, uint224 priceCumulativeStart, uint32 timestampEnd, uint224 priceCumulativeEnd ) internal pure returns (FixedPoint.uq112x112 memory) { return UniswapV2OracleLibrary.computeAveragePrice( priceCumulativeStart, priceCumulativeEnd, uint32(timestampEnd - timestampStart) ); } /** * @dev Computes the average price of the token the price observations * are for in terms of weth. */ function computeAverageTokenPrice( PriceObservation memory observation1, PriceObservation memory observation2 ) internal pure returns (FixedPoint.uq112x112 memory) { return UniswapV2OracleLibrary.computeAveragePrice( observation1.priceCumulativeLast, observation2.priceCumulativeLast, uint32(observation2.timestamp - observation1.timestamp) ); } /** * @dev Computes the average price of weth in terms of the token * the price observations are for. */ function computeAverageEthPrice( PriceObservation memory observation1, PriceObservation memory observation2 ) internal pure returns (FixedPoint.uq112x112 memory) { return UniswapV2OracleLibrary.computeAveragePrice( observation1.ethPriceCumulativeLast, observation2.ethPriceCumulativeLast, uint32(observation2.timestamp - observation1.timestamp) ); } /** * @dev Compute the average value in weth of `tokenAmount` of the * token that the average price values are for. */ function computeAverageEthForTokens( TwoWayAveragePrice memory prices, uint256 tokenAmount ) internal pure returns (uint144) { return FixedPoint.uq112x112(prices.priceAverage).mul(tokenAmount).decode144(); } /** * @dev Compute the average value of `wethAmount` weth in terms of * the token that the average price values are for. */ function computeAverageTokensForEth( TwoWayAveragePrice memory prices, uint256 wethAmount ) internal pure returns (uint144) { return FixedPoint.uq112x112(prices.ethPriceAverage).mul(wethAmount).decode144(); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; /************************************************************************************************ From https://github.com/Uniswap/uniswap-lib/blob/master/contracts/libraries/FixedPoint.sol Copied from the github repository at commit hash 9642a0705fdaf36b477354a4167a8cd765250860. Modifications: - Removed `sqrt` function Subject to the GPL-3.0 license *************************************************************************************************/ // 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; uint private constant Q112 = uint(1) << RESOLUTION; uint private constant Q224 = Q112 << RESOLUTION; // 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); } // take the reciprocal of a UQ112x112 function reciprocal(uq112x112 memory self) internal pure returns (uq112x112 memory) { require(self._x != 0, "FixedPoint: ZERO_RECIPROCAL"); return uq112x112(uint224(Q224 / self._x)); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; /* ========== Internal Interfaces ========== */ import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; /* ========== Internal Libraries ========== */ import "./FixedPoint.sol"; /************************************************************************************************ Originally from https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/libraries/UniswapV2OracleLibrary.sol This source code has been modified from the original, which was copied from the github repository at commit hash 6d03bede0a97c72323fa1c379ed3fdf7231d0b26. Subject to the GPL-3.0 license *************************************************************************************************/ // 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 prices using counterfactuals to save gas and avoid a call to sync. function currentCumulativePrices(address pair) internal view returns ( uint256 price0Cumulative, uint256 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(); require( reserve0 != 0 && reserve1 != 0, "UniswapV2OracleLibrary::currentCumulativePrices: Pair has no reserves." ); if (blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price0Cumulative += ( uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed ); // counterfactual price1Cumulative += ( uint256(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed ); } } // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. // only gets the first price function currentCumulativePrice0(address pair) internal view returns (uint256 price0Cumulative, uint32 blockTimestamp) { blockTimestamp = currentBlockTimestamp(); price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast(); // 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(); require( reserve0 != 0 && reserve1 != 0, "UniswapV2OracleLibrary::currentCumulativePrice0: Pair has no reserves." ); if (blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price0Cumulative += ( uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed ); } } // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. // only gets the second price function currentCumulativePrice1(address pair) internal view returns (uint256 price1Cumulative, uint32 blockTimestamp) { blockTimestamp = currentBlockTimestamp(); 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(); require( reserve0 != 0 && reserve1 != 0, "UniswapV2OracleLibrary::currentCumulativePrice1: Pair has no reserves." ); if (blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price1Cumulative += ( uint256(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed ); } } function computeAveragePrice( uint224 priceCumulativeStart, uint224 priceCumulativeEnd, uint32 timeElapsed ) internal pure returns (FixedPoint.uq112x112 memory priceAverage) { // overflow is desired. priceAverage = FixedPoint.uq112x112( uint224((priceCumulativeEnd - priceCumulativeStart) / timeElapsed) ); } }
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; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; /************************************************************************************************ Originally from https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol This source code has been modified from the original, which was copied from the github repository at commit hash 87edfdcaf49ccc52591502993db4c8c08ea9eec0. Subject to the GPL-3.0 license *************************************************************************************************/ library UniswapV2Library { // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS"); } function calculatePair( address factory, address token0, address token1 ) internal pure returns (address pair) { pair = address( uint256( keccak256( abi.encodePacked( hex"ff", factory, keccak256(abi.encodePacked(token0, token1)), hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash ) ) ) ); } // calculates the CREATE2 address for a pair without making any external calls function pairFor( address factory, address tokenA, address tokenB ) internal pure returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = calculatePair(factory, token0, token1); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; /* ========== Internal Libraries ========== */ import "./PriceLibrary.sol"; import "./KeyIndex.sol"; library IndexedPriceMapLibrary { using PriceLibrary for address; using KeyIndex for mapping(uint256 => uint256); /* ========== Constants ========== */ // Period over which prices are observed, each period should have 1 price observation. uint256 public constant OBSERVATION_PERIOD = 1 hours; // Minimum time elapsed between stored price observations uint256 public constant MINIMUM_OBSERVATION_DELAY = 0.5 hours; /* ========== Struct ========== */ struct IndexedPriceMap { mapping(uint256 => uint256) keyIndex; mapping(uint256 => PriceLibrary.PriceObservation) priceMap; } /* ========= Utility Functions ========= */ /** * @dev Returns the price key for `timestamp`, which is the hour index. */ function toPriceKey(uint256 timestamp) internal pure returns (uint256/* priceKey */) { return timestamp / OBSERVATION_PERIOD; } /** * @dev Returns the number of seconds that have passed since the beginning of the hour. */ function timeElapsedSinceWindowStart(uint256 timestamp) internal pure returns (uint256/* timeElapsed */) { return timestamp % OBSERVATION_PERIOD; } /* ========= Mutative Functions ========= */ /** * @dev Writes `observation` to storage if the price can be updated. If it is * updated, also marks the price key for the observation as having a value in * the key index. * * Note: The price can be updated if there is none recorded for the current * hour 30 minutes have passed since the last price update. * Returns a boolean indicating whether the price was updated. */ function writePriceObservation( IndexedPriceMap storage indexedPriceMap, PriceLibrary.PriceObservation memory observation ) internal returns (bool/* didUpdatePrice */) { bool canUpdate = sufficientDelaySinceLastPrice(indexedPriceMap, observation.timestamp); if (canUpdate) { uint256 priceKey = toPriceKey(observation.timestamp); canUpdate = indexedPriceMap.keyIndex.markSetKey(priceKey); if (canUpdate) { indexedPriceMap.priceMap[priceKey] = observation; } } return canUpdate; } /* ========= Price Update View Functions ========= */ /** * @dev Checks whether sufficient time has passed since the beginning of the observation * window or since the price recorded in the previous window (if any) for a new price * to be recorded. */ function sufficientDelaySinceLastPrice( IndexedPriceMap storage indexedPriceMap, uint32 newTimestamp ) internal view returns (bool/* hasSufficientDelay */) { uint256 priceKey = toPriceKey(newTimestamp); // If half the observation period has already passed since the beginning of the // current window, we can write the price without checking the previous window. if (timeElapsedSinceWindowStart(newTimestamp) >= MINIMUM_OBSERVATION_DELAY) { return true; } else { // Verify that at least half the observation period has passed since the last price observation. PriceLibrary.PriceObservation storage lastObservation = indexedPriceMap.priceMap[priceKey - 1]; if ( lastObservation.timestamp == 0 || newTimestamp - lastObservation.timestamp >= MINIMUM_OBSERVATION_DELAY ) { return true; } } return false; } /** * @dev Checks if a price can be updated. PriceLibrary can be updated if there is no price * observation for the current hour and at least 30 minutes have passed since the * observation in the previous hour (if there is one). */ function canUpdatePrice( IndexedPriceMap storage indexedPriceMap, uint32 newTimestamp ) internal view returns (bool/* canUpdatePrice */) { uint256 priceKey = toPriceKey(newTimestamp); // Verify there is not already a price for the same observation window if (indexedPriceMap.keyIndex.hasKey(priceKey)) return false; return sufficientDelaySinceLastPrice(indexedPriceMap, newTimestamp); } /* ========= Price View Functions ========= */ /** * @dev Checks the key index to see if a price is recorded for `priceKey` */ function hasPriceInWindow( IndexedPriceMap storage indexedPriceMap, uint256 priceKey ) internal view returns (bool) { return indexedPriceMap.keyIndex.hasKey(priceKey); } /** * @dev Returns the price observation for `priceKey` */ function getPriceInWindow( IndexedPriceMap storage indexedPriceMap, uint256 priceKey ) internal view returns (PriceLibrary.PriceObservation memory) { return indexedPriceMap.priceMap[priceKey]; } function getPriceObservationsInRange( IndexedPriceMap storage indexedPriceMap, uint256 timeFrom, uint256 timeTo ) internal view returns (PriceLibrary.PriceObservation[] memory prices) { uint256 priceKeyFrom = toPriceKey(timeFrom); uint256 priceKeyTo = toPriceKey(timeTo); require(priceKeyTo > priceKeyFrom, "IndexedPriceMapLibrary::getPriceObservationsInRange: Invalid time range"); bytes memory bitPositions = indexedPriceMap.keyIndex.getEncodedSetKeysInRange(priceKeyFrom, priceKeyTo); // Divide by 2 because length is in bytes and relative indices are stored as uint16 uint256 len = bitPositions.length / 2; prices = new PriceLibrary.PriceObservation[](len); uint256 ptr; assembly { ptr := add(bitPositions, 32) } for (uint256 i = 0; i < len; i++) { uint256 relativeIndex; assembly { relativeIndex := shr(0xf0, mload(ptr)) ptr := add(ptr, 2) } uint256 key = priceKeyFrom + relativeIndex; prices[i] = indexedPriceMap.priceMap[key]; } } /** * @dev Finds the most recent price observation before `timestamp` with a minimum * difference in observation times of `minTimeElapsed` and a maximum difference in * observation times of `maxTimeElapsed`. * * Note: `maxTimeElapsed` is only accurate to the nearest hour (rounded down) unless * it is below one hour. * * @param indexedPriceMap Struct with the indexed price mapping for the token. * @param timestamp Timestamp to search backwards from. * @param minTimeElapsed Minimum time elapsed between price observations. * @param maxTimeElapsed Maximum time elapsed between price observations. * Only accurate to the nearest hour (rounded down) unless it is below 1 hour. */ function getLastPriceObservation( IndexedPriceMap storage indexedPriceMap, uint256 timestamp, uint256 minTimeElapsed, uint256 maxTimeElapsed ) internal view returns (bool /* foundPrice */, uint256 /* lastPriceKey */) { uint256 priceKey = toPriceKey(timestamp); uint256 windowTimeElapsed = timeElapsedSinceWindowStart(timestamp); bool canBeThisWindow = minTimeElapsed <= windowTimeElapsed; bool mustBeThisWindow = maxTimeElapsed <= windowTimeElapsed; // If the observation window for `timestamp` could include a price observation less than `maxTimeElapsed` // older than `timestamp` and the time elapsed since the beginning of the hour for `timestamp` is not higher // than `maxTimeElapsed`, any allowed price must exist in the observation window for `timestamp`. if (canBeThisWindow || mustBeThisWindow) { PriceLibrary.PriceObservation storage observation = indexedPriceMap.priceMap[priceKey]; uint32 obsTimestamp = observation.timestamp; if ( obsTimestamp != 0 && timestamp > obsTimestamp && timestamp - obsTimestamp <= maxTimeElapsed && timestamp - obsTimestamp >= minTimeElapsed ) { return (true, priceKey); } if (mustBeThisWindow) { return (false, 0); } } uint256 beginSearchTime = timestamp - minTimeElapsed; priceKey = toPriceKey(beginSearchTime); uint256 maxDistance = toPriceKey(maxTimeElapsed); return indexedPriceMap.keyIndex.findLastSetKey(priceKey, maxDistance); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; /* ========== Internal Libraries ========== */ import "./Bits.sol"; /** * @dev Library for indexing keys stored in a sequential mapping for easier * queries. * * Every set of 256 keys in the value map is assigned a single index which * records set values as bits, where 1 indicates the map has a value at a given * key and 0 indicates it does not. * * The 'value map' is the map which stores the values with sequential keys. * The 'key index' is the map which records the indices for every 256 keys * in the value map. * * The 'key index' is the mapping which stores the indices for each 256 values * in the map. For example, the key '256' in the value map would have a key * in the key index of `1`, where the 0th bit in the index records whether a * value is set in the value map . */ library KeyIndex { using Bits for uint256; using Bits for bytes; /* ========= Utility Functions ========= */ /** * @dev Compute the map key for a given index key and position. * Multiplies indexKey by 256 and adds indexPosition. */ function toMapKey(uint256 indexKey, uint256 indexPosition) internal pure returns (uint256) { return (indexKey * 256) + indexPosition; } /** * @dev Returns the key in the key index which stores the index for the 256-bit * index which includes `mapKey` and the position in the index for that key. */ function indexKeyAndPosition(uint256 mapKey) internal pure returns (uint256 indexKey, uint256 indexPosition) { indexKey = mapKey / 256; indexPosition = mapKey % 256; } /* ========= Mutative Functions ========= */ /** * @dev Sets a bit at the position in `indexMap` corresponding to `mapKey` if the * bit is not already set. * * @param keyIndex Mapping with indices of set keys in the value map * @param mapKey Position in the value map to mark as set */ function markSetKey( mapping(uint256 => uint256) storage keyIndex, uint256 mapKey ) internal returns (bool /* didSetKey */) { (uint256 indexKey, uint256 indexPosition) = indexKeyAndPosition(mapKey); // console.log("IPOS", indexPosition); uint256 localIndex = keyIndex[indexKey]; bool canSetKey = !localIndex.bitSet(indexPosition); if (canSetKey) { keyIndex[indexKey] = localIndex.setBit(indexPosition); } return canSetKey; } /* ========= View Functions ========= */ /** * @dev Returns a boolean indicating whether a value is stored for `mapKey` in the map index. */ function hasKey( mapping(uint256 => uint256) storage keyIndex, uint256 mapKey ) internal view returns (bool) { (uint256 indexKey, uint256 indexPosition) = indexKeyAndPosition(mapKey); uint256 localIndex = keyIndex[indexKey]; if (localIndex == 0) return false; return localIndex.bitSet(indexPosition); } /** * @dev Returns a packed uint16 array with the offsets of all set keys * between `mapKeyFrom` and `mapKeyTo`. Offsets are relative to `mapKeyFrom` */ function getEncodedSetKeysInRange( mapping(uint256 => uint256) storage keyIndex, uint256 mapKeyFrom, uint256 mapKeyTo ) internal view returns (bytes memory bitPositions) { uint256 rangeSize = mapKeyTo - mapKeyFrom; (uint256 indexKeyStart, uint256 indexPositionStart) = indexKeyAndPosition(mapKeyFrom); (uint256 indexKeyEnd, uint256 indexPositionEnd) = indexKeyAndPosition(mapKeyTo); // Expand memory too accomodate the maximum number of bits that could be found // Length is 2*range because values are stored as uint16s // 30 is added because 32 bytes are stored at a time and this would go past rangeSize*2 // if most bits are set bitPositions = new bytes((2 * rangeSize) + 30); // Set the length to 0, as it is used by the `writeSetBits` fn assembly { mstore(bitPositions, 0) } uint256 indexKey = indexKeyStart; // Clear the bits before `indexPositionStart` so they are not included in the search result uint256 localIndex = keyIndex[indexKey].clearBitsBefore(indexPositionStart); uint16 offset = 0; // Check each index until the last one is reached while (indexKey < indexKeyEnd) { // Relative index is set by adding provided `offset` to the bit index bitPositions.writeSetBits(localIndex, offset); indexKey += 1; localIndex = keyIndex[indexKey]; offset += 256; } // Clear the bits after `indexPositionEnd` before searching for set bits localIndex = localIndex.clearBitsAfter(indexPositionEnd); bitPositions.writeSetBits(localIndex, offset); } /** * @dev Find the most recent position before `mapKey` which the index map records * as having a set value. Returns the key in the value map for that position. * * @param keyIndex Mapping with indices of set keys in the value map * @param mapKey Position in the value map to look behind * @param maxDistance Maximum distance between the found value and `mapKey` */ function findLastSetKey( mapping(uint256 => uint256) storage keyIndex, uint256 mapKey, uint256 maxDistance ) internal view returns (bool/* found */, uint256/* mapKey */) { (uint256 indexKey, uint256 indexPosition) = indexKeyAndPosition(mapKey); uint256 distance = 0; bool found; uint256 position; uint256 localIndex; // If the position is 0, we must go to the previous index if (indexPosition == 0) { require(indexKey != 0, "KeyIndex::findLastSetKey:Can not query value prior to 0."); indexKey -= 1; distance = 1; } else { localIndex = keyIndex[indexKey]; (found, position) = localIndex.nextLowestBitSet(indexPosition); if (found) { distance += indexPosition - position; } else { distance += indexPosition + 1; indexKey -= 1; } } while (!found && distance <= maxDistance) { localIndex = keyIndex[indexKey]; if (localIndex == 0) { if (indexKey == 0) return (false, 0); distance += 256; indexKey -= 1; } else { position = localIndex.highestBitSet(); distance += 255 - position; found = true; } } if (distance > maxDistance) { return (false, 0); } return (true, toMapKey(indexKey, position)); } /** * @dev Find the next position after `mapKey` which the index map records as * having a set value. Returns the key in the value map for that position. * * @param keyIndex Mapping with indices of set values in the value map * @param mapKey Position in the value map to look ahead * @param maxDistance Maximum distance between the found value and `mapKey` */ function findNextSetKey( mapping(uint256 => uint256) storage keyIndex, uint256 mapKey, uint256 maxDistance ) internal view returns (bool/* found */, uint256/* mapKey */) { (uint256 indexKey, uint256 indexPosition) = indexKeyAndPosition(mapKey); uint256 distance = 0; bool found; uint256 position; uint256 localIndex; if (indexPosition == 255) { indexKey += 1; position = indexPosition; distance = 1; } else { localIndex = keyIndex[indexKey]; (found, position) = localIndex.nextHighestBitSet(indexPosition); if (found) { distance += position - indexPosition; } else { distance += 256 - indexPosition; indexKey += 1; } } while (!found && distance <= maxDistance) { localIndex = keyIndex[indexKey]; if (localIndex == 0) { distance += 256; indexKey += 1; } else { position = localIndex.lowestBitSet(); distance += position; found = true; } } if (distance > maxDistance) { return (false, 0); } return (true, toMapKey(indexKey, position)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; library Bits { uint256 internal constant ONE = uint256(1); uint256 internal constant ONES = uint256(~0); /** * @dev Sets the bit at the given 'index' in 'self' to '1'. * Returns the modified value. */ function setBit(uint256 self, uint256 index) internal pure returns (uint256) { return self | (ONE << index); } /** * @dev Returns a boolean indicating whether the bit at the given `index` in `self` is set. */ function bitSet(uint256 self, uint256 index) internal pure returns (bool) { return (self >> index) & 1 == 1; } /** * @dev Clears all bits in the exclusive range [index:255] */ function clearBitsAfter(uint256 self, uint256 index) internal pure returns (uint256) { return self & (ONES >> (255 - index)); } /** * @dev Clears bits in the exclusive range [0:index] */ function clearBitsBefore(uint256 self, uint256 index) internal pure returns (uint256) { return self & (ONES << (index)); } /** * @dev Writes the index of every set bit in `val` as a uint16 in `bitPositions`. * Adds `offset` to the stored bit index. * * `bitPositions` must have a length equal to twice the maximum number of bits that * could be found plus 31. Each index is stored as a uint16 to accomodate `offset` * because this is used in functions which would otherwise need expensive methods * to handle relative indices in multi-integer searches. * The specified length ensures that solc will handle memory allocation, and the * addition of 31 allows us to store whole words at a time. * After being declared, the actual length stored in memory must be set to 0 with: * `assembly { mstore(bitPositions, 0) }` because the length is used to count found bits. * * @param bitPositions Packed uint16 array for positions of set bits * @param val Value to search set bits in * @param offset Value added to the stored position, used to simplify large searches. */ function writeSetBits(bytes memory bitPositions, uint256 val, uint16 offset) internal pure { if (val == 0) return; assembly { // Read the current length, which is the number of stored bytes let len := mload(bitPositions) // Set the starting pointer by adding the length to the bytes data pointer // This does not change and is later used to compute the new length let startPtr := add(add(bitPositions, 32), len) // Set the variable pointer which is used to track where to write memory values let ptr := startPtr // Increment the number of bits to shift until the shifted integer is 0 // Add 3 to the index each loop because that is the number of bits being checked // at a time. for {let i := 0} gt(shr(i, val), 0) {i := add(i, 3)} { // Loop until the last 8 bits are not all 0 for {} eq(and(shr(i, val), 255), 0) {i := add(i, 8)} {} // Take only the last 3 bits let x := and(shr(i, val), 7) // Use a switch statement as a lookup table with every possible combination of 3 bits. switch x case 0 {}// no bits set case 1 {// bit 0 set // shift left 240 bits to write uint16, increment ptr by 2 bytes mstore(ptr, shl(0xf0, add(i, offset))) ptr := add(ptr, 2) } case 2 {// bit 1 set // shift left 240 bits to write uint16, increment ptr by 2 bytes mstore(ptr, shl(0xf0, add(add(i, 1), offset))) ptr := add(ptr, 2) } case 3 {// bits 0,1 set // shift first left 240 bits and second 224 to write two uint16s // increment ptr by 4 bytes mstore( ptr, or(// use OR to avoid multiple memory writes shl(0xf0, add(i, offset)), shl(0xe0, add(add(i, 1), offset)) ) ) ptr := add(ptr, 4) } case 4 {// bit 2 set // shift left 240 bits to write uint16, increment ptr by 2 bytes mstore(ptr, shl(0xf0, add(add(i, 2), offset))) ptr := add(ptr, 2) } case 5 {// 5: bits 0,2 set // shift first left 240 bits and second 224 bits to write two uint16s mstore( ptr, or(// use OR to avoid multiple memory writes shl(0xf0, add(i, offset)), shl(0xe0, add(add(i, 2), offset)) ) ) ptr := add(ptr, 4)// increment ptr by 4 bytes } case 6 {// bits 1,2 set // shift first left 240 bits and second 224 to write two uint16s mstore( ptr, or(// use OR to avoid multiple memory writes shl(0xf0, add(add(i, 1), offset)), shl(0xe0, add(add(i, 2), offset)) ) ) ptr := add(ptr, 4)// increment ptr by 4 bytes } case 7 {//bits 0,1,2 set // shift first left 240 bits, second 224, third 208 to write three uint16s mstore( ptr, or(// use OR to avoid multiple memory writes shl(0xf0, add(i, offset)), or( shl(0xe0, add(add(i, 1), offset)), shl(0xd0, add(add(i, 2), offset)) ) ) ) ptr := add(ptr, 6)// increment ptr by 6 bytes } } // subtract current pointer from initial to get byte length let newLen := sub(ptr, startPtr) // write byte length mstore(bitPositions, add(len, newLen)) } } /** * @dev Returns the index of the highest bit set in `self`. * Note: Requires that `self != 0` */ function highestBitSet(uint256 self) internal pure returns (uint256 r) { uint256 x = self; require (x > 0, "Bits::highestBitSet: Value 0 has no bits set"); if (x >= 0x100000000000000000000000000000000) {x >>= 128; r += 128;} if (x >= 0x10000000000000000) {x >>= 64; r += 64;} if (x >= 0x100000000) {x >>= 32; r += 32;} if (x >= 0x10000) {x >>= 16; r += 16;} if (x >= 0x100) {x >>= 8; r += 8;} if (x >= 0x10) {x >>= 4; r += 4;} if (x >= 0x4) {x >>= 2; r += 2;} if (x >= 0x2) r += 1; // No need to shift x anymore } /** * @dev Returns the index of the lowest bit set in `self`. * Note: Requires that `self != 0` */ function lowestBitSet(uint256 self) internal pure returns (uint256 _z) { require (self > 0, "Bits::lowestBitSet: Value 0 has no bits set"); uint256 _magic = 0x00818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff; uint256 val = (self & -self) * _magic >> 248; uint256 _y = val >> 5; _z = ( _y < 4 ? _y < 2 ? _y == 0 ? 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100 : 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606 : _y == 2 ? 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707 : 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e : _y < 6 ? _y == 4 ? 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff : 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616 : _y == 6 ? 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe : 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd ); _z >>= (val & 0x1f) << 3; return _z & 0xff; } /** * @dev Returns a boolean indicating whether `bit` is the highest set bit * in the integer and the index of the next lowest set bit if it is not. */ function nextLowestBitSet(uint256 self, uint256 bit) internal pure returns (bool haveValueBefore, uint256 previousBit) { uint256 val = self << (256 - bit); if (val == 0) { return (false, 0); } return (true, (highestBitSet(val) - (256 - bit))); } /** * @dev Returns a boolean indicating whether `bit` is the lowest set bit * in the integer and the index of the next highest set bit if it is not. */ function nextHighestBitSet(uint256 self, uint256 bit) internal pure returns (bool haveValueAfter, uint256 nextBit) { uint256 val = self >> (bit + 1); if (val == 0) { return (false, 0); } return (true, lowestBitSet(val) + (bit + 1)); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; /* ========== Libraries ========== */ import "../lib/PriceLibrary.sol"; import "../lib/FixedPoint.sol"; interface IIndexedUniswapV2Oracle { /* ========== Mutative Functions ========== */ function updatePrice(address token) external returns (bool); function updatePrices(address[] calldata tokens) external returns (bool[] memory); /* ========== Meta Price Queries ========== */ function hasPriceObservationInWindow(address token, uint256 priceKey) external view returns (bool); function getPriceObservationInWindow( address token, uint256 priceKey ) external view returns (PriceLibrary.PriceObservation memory); function getPriceObservationsInRange( address token, uint256 timeFrom, uint256 timeTo ) external view returns (PriceLibrary.PriceObservation[] memory prices); /* ========== Price Update Queries ========== */ function canUpdatePrice(address token) external view returns (bool); function canUpdatePrices(address[] calldata tokens) external view returns (bool[] memory); /* ========== Price Queries: Singular ========== */ function computeTwoWayAveragePrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (PriceLibrary.TwoWayAveragePrice memory); function computeAverageTokenPrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (FixedPoint.uq112x112 memory); function computeAverageEthPrice( address token, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (FixedPoint.uq112x112 memory); /* ========== Price Queries: Multiple ========== */ function computeTwoWayAveragePrices( address[] calldata tokens, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (PriceLibrary.TwoWayAveragePrice[] memory); function computeAverageTokenPrices( address[] calldata tokens, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (FixedPoint.uq112x112[] memory); function computeAverageEthPrices( address[] calldata tokens, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (FixedPoint.uq112x112[] memory); /* ========== Value Queries: Singular ========== */ function computeAverageEthForTokens( address token, uint256 tokenAmount, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (uint144); function computeAverageTokensForEth( address token, uint256 wethAmount, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (uint144); /* ========== Value Queries: Multiple ========== */ function computeAverageEthForTokens( address[] calldata tokens, uint256[] calldata tokenAmounts, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (uint144[] memory); function computeAverageTokensForEth( address[] calldata tokens, uint256[] calldata wethAmounts, uint256 minTimeElapsed, uint256 maxTimeElapsed ) external view returns (uint144[] memory); }
{ "metadata": { "useLiteralContent": false }, "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"uniswapFactory","type":"address"},{"internalType":"address","name":"weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"canUpdatePrice","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"canUpdatePrices","outputs":[{"internalType":"bool[]","name":"canUpdateArr","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeAverageEthForTokens","outputs":[{"internalType":"uint144[]","name":"averageValuesInWETH","type":"uint144[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeAverageEthForTokens","outputs":[{"internalType":"uint144","name":"","type":"uint144"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeAverageEthPrice","outputs":[{"components":[{"internalType":"uint224","name":"_x","type":"uint224"}],"internalType":"struct FixedPoint.uq112x112","name":"priceAverage","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeAverageEthPrices","outputs":[{"components":[{"internalType":"uint224","name":"_x","type":"uint224"}],"internalType":"struct FixedPoint.uq112x112[]","name":"averagePrices","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeAverageTokenPrice","outputs":[{"components":[{"internalType":"uint224","name":"_x","type":"uint224"}],"internalType":"struct FixedPoint.uq112x112","name":"priceAverage","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeAverageTokenPrices","outputs":[{"components":[{"internalType":"uint224","name":"_x","type":"uint224"}],"internalType":"struct FixedPoint.uq112x112[]","name":"averagePrices","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"wethAmounts","type":"uint256[]"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeAverageTokensForEth","outputs":[{"internalType":"uint144[]","name":"averageValuesInWETH","type":"uint144[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"wethAmount","type":"uint256"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeAverageTokensForEth","outputs":[{"internalType":"uint144","name":"","type":"uint144"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeTwoWayAveragePrice","outputs":[{"components":[{"internalType":"uint224","name":"priceAverage","type":"uint224"},{"internalType":"uint224","name":"ethPriceAverage","type":"uint224"}],"internalType":"struct PriceLibrary.TwoWayAveragePrice","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"minTimeElapsed","type":"uint256"},{"internalType":"uint256","name":"maxTimeElapsed","type":"uint256"}],"name":"computeTwoWayAveragePrices","outputs":[{"components":[{"internalType":"uint224","name":"priceAverage","type":"uint224"},{"internalType":"uint224","name":"ethPriceAverage","type":"uint224"}],"internalType":"struct PriceLibrary.TwoWayAveragePrice[]","name":"prices","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"priceKey","type":"uint256"}],"name":"getPriceObservationInWindow","outputs":[{"components":[{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"uint224","name":"priceCumulativeLast","type":"uint224"},{"internalType":"uint224","name":"ethPriceCumulativeLast","type":"uint224"}],"internalType":"struct PriceLibrary.PriceObservation","name":"observation","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"timeFrom","type":"uint256"},{"internalType":"uint256","name":"timeTo","type":"uint256"}],"name":"getPriceObservationsInRange","outputs":[{"components":[{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"uint224","name":"priceCumulativeLast","type":"uint224"},{"internalType":"uint224","name":"ethPriceCumulativeLast","type":"uint224"}],"internalType":"struct PriceLibrary.PriceObservation[]","name":"prices","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"priceKey","type":"uint256"}],"name":"hasPriceObservationInWindow","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"updatePrice","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"updatePrices","outputs":[{"internalType":"bool[]","name":"pricesUpdated","type":"bool[]"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b50604051620031cb380380620031cb833981016040819052620000349162000053565b6001600160601b0319606092831b8116608052911b1660a052620000aa565b6000806040838503121562000066578182fd5b8251620000738162000091565b6020840151909250620000868162000091565b809150509250929050565b6001600160a01b0381168114620000a757600080fd5b50565b60805160601c60a05160601c6130b16200011a6000398061061052806109c05280610a495280610ac15280610cc85280610d445280610e2b5280610ea15280610fde528061108f5250806105ed528061099d5280610a9e5280610d225280610e7e528061106c52506130b16000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c80637c906a2a116100a257806396e85ced1161007157806396e85ced14610265578063bf6dd82e14610278578063c735e38c1461028b578063cdee7f6e146102ab578063ffd97b6f146102be5761010b565b80637c906a2a1461020c5780637e5296e01461021f57806388a14c3c1461023f5780639691b116146102525761010b565b80634f2acedf116100de5780634f2acedf1461019957806357653615146101b95780635acd73d7146101d9578063768d2c19146101ec5761010b565b806310bc482a146101105780632d726197146101395780633a9d6535146101595780634506006014610179575b600080fd5b61012361011e36600461254f565b6102de565b6040516101309190612982565b60405180910390f35b61014c6101473660046126aa565b61030f565b60405161013091906128ff565b61016c610167366004612579565b6103f1565b604051610130919061303c565b61018c610187366004612630565b610430565b6040516101309190612941565b6101ac6101a73660046125ac565b610551565b604051610130919061304f565b6101cc6101c7366004612579565b6105a9565b604051610130919061302e565b6101236101e7366004612534565b6105de565b6101ff6101fa3660046126aa565b610676565b60405161013091906128b2565b61018c61021a366004612630565b610743565b61023261022d3660046125f1565b610845565b604051610130919061282a565b61023261024d3660046125f1565b6108e6565b61016c610260366004612579565b610a10565b610123610273366004612534565b610a45565b6101ac6102863660046125ac565b610b1d565b61029e61029936600461254f565b610b54565b6040516101309190613020565b61014c6102b93660046126aa565b610bab565b6102d16102cc366004612579565b610c78565b6040516101309190612870565b6001600160a01b0382166000908152602081905260408120610306908363ffffffff610cac16565b90505b92915050565b606082828181101561033c5760405162461bcd60e51b815260040161033390612ab5565b60405180910390fd5b85806001600160401b038111801561035357600080fd5b5060405190808252806020026020018201604052801561038d57816020015b61037a612480565b8152602001906001900390816103725790505b50935060005b818110156103e5576103c68989838181106103aa57fe5b90506020020160208101906103bf9190612534565b8888610cbe565b8582815181106103d257fe5b6020908102919091010152600101610393565b50505050949350505050565b6103f9612480565b82828181101561041b5760405162461bcd60e51b815260040161033390612ab5565b610426868686610e21565b9695505050505050565b60608282818110156104545760405162461bcd60e51b815260040161033390612ab5565b878681146104745760405162461bcd60e51b815260040161033390612c4c565b806001600160401b038111801561048a57600080fd5b506040519080825280602002602001820160405280156104b4578160200160208202803683370190505b50935060005b81811015610543576105176105128a8a848181106104d457fe5b905060200201356105068e8e868181106104ea57fe5b90506020020160208101906104ff9190612534565b8b8b610cbe565b9063ffffffff610f6e16565b610fcd565b85828151811061052357fe5b6001600160901b03909216602092830291909101909101526001016104ba565b505050509695505050505050565b60008282818110156105755760405162461bcd60e51b815260040161033390612ab5565b61057d612480565b610588888787610cbe565b905061059d610512828963ffffffff610f6e16565b98975050505050505050565b6105b1612492565b8282818110156105d35760405162461bcd60e51b815260040161033390612ab5565b610426868686610fd4565b600061063a6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016837f000000000000000000000000000000000000000000000000000000000000000063ffffffff61118816565b61064657506000610671565b6001600160a01b038216600090815260208190526040902061066e904263ffffffff61123e16565b90505b919050565b606082828181101561069a5760405162461bcd60e51b815260040161033390612ab5565b85806001600160401b03811180156106b157600080fd5b506040519080825280602002602001820160405280156106eb57816020015b6106d8612492565b8152602001906001900390816106d05790505b50935060005b818110156103e55761072489898381811061070857fe5b905060200201602081019061071d9190612534565b8888610fd4565b85828151811061073057fe5b60209081029190910101526001016106f1565b60608282818110156107675760405162461bcd60e51b815260040161033390612ab5565b878681146107875760405162461bcd60e51b815260040161033390612e14565b806001600160401b038111801561079d57600080fd5b506040519080825280602002602001820160405280156107c7578160200160208202803683370190505b50935060005b81811015610543576108196105128a8a848181106107e757fe5b905060200201356105068e8e868181106107fd57fe5b90506020020160208101906108129190612534565b8b8b610e21565b85828151811061082557fe5b6001600160901b03909216602092830291909101909101526001016107cd565b606081806001600160401b038111801561085e57600080fd5b50604051908082528060200260200182016040528015610888578160200160208202803683370190505b50915060005b818110156108de576108ba8585838181106108a557fe5b90506020020160208101906102739190612534565b8382815181106108c657fe5b9115156020928302919091019091015260010161088e565b505092915050565b606081806001600160401b03811180156108ff57600080fd5b50604051908082528060200260200182016040528015610929578160200160208202803683370190505b50915060005b818110156108de57600085858381811061094557fe5b905060200201602081019061095a9190612534565b6001600160a01b038116600090815260208190526040812091925090610986904263ffffffff61123e16565b90508080156109ea57506109ea6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016837f000000000000000000000000000000000000000000000000000000000000000063ffffffff61118816565b8584815181106109f657fe5b91151560209283029190910190910152505060010161092f565b610a18612480565b828281811015610a3a5760405162461bcd60e51b815260040161033390612ab5565b610426868686610cbe565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415610a8957506001610671565b610a916124a9565b610aeb6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016847f000000000000000000000000000000000000000000000000000000000000000063ffffffff61127b16565b6001600160a01b0384166000908152602081905260409020909150610b16908263ffffffff61135e16565b9392505050565b6000828281811015610b415760405162461bcd60e51b815260040161033390612ab5565b610b49612480565b610588888787610e21565b610b5c6124a9565b6001600160a01b0383166000908152602081905260409020610b84908363ffffffff61141216565b805190915063ffffffff166103095760405162461bcd60e51b815260040161033390612eda565b6060828281811015610bcf5760405162461bcd60e51b815260040161033390612ab5565b85806001600160401b0381118015610be657600080fd5b50604051908082528060200260200182016040528015610c2057816020015b610c0d612480565b815260200190600190039081610c055790505b50935060005b818110156103e557610c59898983818110610c3d57fe5b9050602002016020810190610c529190612534565b8888610e21565b858281518110610c6557fe5b6020908102919091010152600101610c26565b6001600160a01b0383166000908152602081905260409020606090610ca490848463ffffffff61146816565b949350505050565b6000610306838363ffffffff6115a816565b610cc6612480565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161415610d1257610d0b6001806115eb565b9050610b16565b600080610d6f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008863ffffffff61165f16565b6001600160a01b0388166000908152602081905260408120929450909250908190610da79063ffffffff808716908a908a906116cb16565b9150915081610dc85760405162461bcd60e51b815260040161033390612b9a565b6001600160a01b03881660009081526020818152604080832084845260019081019092529091208054918101549091610e149163ffffffff909116906001600160e01b031687876117c5565b9998505050505050505050565b610e29612480565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161415610e6e57610d0b6001806115eb565b600080610ecb6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016877f000000000000000000000000000000000000000000000000000000000000000063ffffffff61165f16565b6001600160a01b0388166000908152602081905260408120929450909250908190610f039063ffffffff808716908a908a906116cb16565b9150915081610f245760405162461bcd60e51b815260040161033390612b2b565b6001600160a01b03881660009081526020818152604080832084845260010190915290208054610e149063ffffffff81169064010000000090046001600160e01b031687876117c5565b610f766124c9565b6000821580610f9c57505082516001600160e01b031682810290838281610f9957fe5b04145b610fb85760405162461bcd60e51b815260040161033390612e97565b60408051602081019091529081529392505050565b5160701c90565b610fdc612492565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316141561105757604051806040016040528061102b60016117e3565b516001600160e01b0316815260200161104460016117e3565b516001600160e01b031690529050610b16565b61105f6124a9565b6110b96001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016867f000000000000000000000000000000000000000000000000000000000000000063ffffffff61127b16565b80516001600160a01b03871660009081526020819052604081209293509182916110f1919063ffffffff90811690899089906116cb16565b91509150816111125760405162461bcd60e51b815260040161033390612a45565b61111a6124a9565b506001600160a01b03871660009081526020818152604080832084845260019081018352928190208151606081018352815463ffffffff80821683526001600160e01b036401000000009092048216958301959095529190940154169083015261059d908290869061180e16565b60008061119685858561187d565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156111d457600080fd5b505afa1580156111e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120c91906126f8565b5091509150816001600160701b031660001415801561123357506001600160701b03811615155b979650505050505050565b6000806112508363ffffffff1661189b565b9050611262848263ffffffff6115a816565b15611271576000915050610309565b610ca484846118a3565b6112836124a9565b600080611290858561192c565b9150915060006112a18784846119b6565b905060008060006112b184611a13565b925092509250886001600160a01b0316866001600160a01b031614156113115760405180606001604052808263ffffffff168152602001846001600160e01b03168152602001836001600160e01b03168152509650505050505050610b16565b60405180606001604052808263ffffffff168152602001836001600160e01b03168152602001846001600160e01b03168152509650505050505050610b16565b5050505050509392505050565b60008061136f8484600001516118a3565b9050801561030657600061138c846000015163ffffffff1661189b565b905061139e858263ffffffff611c2616565b9150811561140a57600081815260018681016020908152604092839020875181549289015163ffffffff1990931663ffffffff91821617166401000000006001600160e01b0393841602178155928701519290910180546001600160e01b031916929091169190911790555b509392505050565b61141a6124a9565b506000908152600191820160209081526040918290208251606081018452815463ffffffff8116825264010000000090046001600160e01b0390811693820193909352930154169082015290565b606060006114758461189b565b905060006114828461189b565b90508181116114a35760405162461bcd60e51b815260040161033390612da7565b60606114b687848463ffffffff611c8b16565b9050600060028251816114c557fe5b049050806001600160401b03811180156114de57600080fd5b5060405190808252806020026020018201604052801561151857816020015b6115056124a9565b8152602001906001900390816114fd5790505b5094506020820160005b8281101561135157815160f01c86810160008181526001808e0160209081526040928390208351606081018552815463ffffffff811682526001600160e01b03640100000000909104811693820193909352920154169181019190915289516002909501948a908590811061159357fe5b60209081029190910101525050600101611522565b60008060006115b684611d92565b6000828152602088905260409020549193509150806115db5760009350505050610309565b610426818363ffffffff611da016565b6115f3612480565b6000826001600160701b03161161161c5760405162461bcd60e51b815260040161033390612fe9565b6040805160208101909152806001600160701b038416600160701b600160e01b03607087901b168161164a57fe5b046001600160e01b0316815250905092915050565b60008060008061166f868661192c565b9150915060006116808884846119b6565b9050866001600160a01b0316836001600160a01b031614156116b7576000806116a883611daa565b975095506116c3945050505050565b6000806116a883611f25565b935093915050565b60008060006116d98661189b565b905060006116e687612086565b9050808611158186111581806116f95750805b1561178557600084815260018b0160205260409020805463ffffffff16801580159061172a57508063ffffffff168b115b801561173e5750888163ffffffff168c0311155b80156117525750898163ffffffff168c0310155b1561176957600186975097505050505050506117bc565b82156117825750600096508695506117bc945050505050565b50505b8789036117918161189b565b9450600061179e8961189b565b90506117b18c878363ffffffff61208e16565b975097505050505050505b94509492505050565b6117cd612480565b6117da84838786036121c6565b95945050505050565b6117eb612480565b50604080516020810190915260709190911b600160701b600160e01b0316815290565b611816612492565b8251825103611823612480565b61183685602001518560200151846121c6565b9050611840612480565b61185386604001518660400151856121c6565b6040805180820190915292516001600160e01b039081168452905116602083015250949350505050565b600080600061188c858561192c565b915091506104268683836119b6565b610e10900490565b6000806118b58363ffffffff1661189b565b90506107086118c98463ffffffff16612086565b106118d8576001915050610309565b600019810160009081526001850160205260409020805463ffffffff1615806119115750805461070863ffffffff918216860390911610155b1561192157600192505050610309565b506000949350505050565b600080826001600160a01b0316846001600160a01b031614156119615760405162461bcd60e51b815260040161033390612c07565b826001600160a01b0316846001600160a01b031610611981578284611984565b83835b90925090506001600160a01b0382166119af5760405162461bcd60e51b815260040161033390612f55565b9250929050565b60008383836040516020016119cc9291906127ad565b604051602081830303815290604052805190602001206040516020016119f39291906127d4565b60408051601f198184030181529190528051602090910120949350505050565b6000806000611a20612209565b9050836001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b158015611a5b57600080fd5b505afa158015611a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a93919061274c565b9250836001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b158015611ace57600080fd5b505afa158015611ae2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b06919061274c565b91506000806000866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611b4657600080fd5b505afa158015611b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b7e91906126f8565b925092509250826001600160701b0316600014158015611ba657506001600160701b03821615155b611bc25760405162461bcd60e51b815260040161033390612d3b565b8363ffffffff168163ffffffff1614611c1c5780840363ffffffff8116611be984866115eb565b516001600160e01b031602969096019563ffffffff8116611c0a85856115eb565b516001600160e01b0316029590950194505b5050509193909250565b6000806000611c3484611d92565b600082815260208890526040812054929450909250611c59828463ffffffff611da016565b159050801561042657611c72828463ffffffff61221316565b6000858152602089905260409020559695505050505050565b6060828203600080611c9c86611d92565b91509150600080611cac87611d92565b9150915084600202601e016001600160401b0381118015611ccc57600080fd5b506040519080825280601f01601f191660200182016040528015611cf7576020820181803683370190505b50600080825285815260208b905260408120549197508591611d1f908663ffffffff61221b16565b905060005b84831015611d6057611d3d89838363ffffffff61222416565b600192909201600081815260208d90526040902054909290915061010001611d24565b611d70828563ffffffff61237516565b9150611d8389838363ffffffff61222416565b50505050505050509392505050565b61010081049160ff90911690565b1c60019081161490565b600080611db5612209565b9050826001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b158015611df057600080fd5b505afa158015611e04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e28919061274c565b91506000806000856001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611e6857600080fd5b505afa158015611e7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea091906126f8565b925092509250826001600160701b0316600014158015611ec857506001600160701b03821615155b611ee45760405162461bcd60e51b815260040161033390612ccf565b8363ffffffff168163ffffffff1614611f1d5780840363ffffffff8116611f0b84866115eb565b516001600160e01b0316029590950194505b505050915091565b600080611f30612209565b9050826001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b158015611f6b57600080fd5b505afa158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa3919061274c565b91506000806000856001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611fe357600080fd5b505afa158015611ff7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201b91906126f8565b925092509250826001600160701b031660001415801561204357506001600160701b03821615155b61205f5760405162461bcd60e51b8152600401610333906129d9565b8363ffffffff168163ffffffff1614611f1d5780840363ffffffff8116611f0b85856115eb565b610e10900690565b60008060008061209d86611d92565b90925090506000808080846120d857856120c95760405162461bcd60e51b815260040161033390612f8c565b6001860395506001935061211e565b50600085815260208b905260409020546120f8818663ffffffff61238316565b9093509150821561210f578185038401935061211e565b60001990950194928401600101925b8215801561212c5750888411155b1561218d5750600085815260208b9052604090205480612170578561215e5750600096508695506116c3945050505050565b61010084019350600186039550612188565b612179816123be565b91508160ff0384019350600192505b61211e565b888411156121a85750600096508695506116c3945050505050565b60016121b48784612475565b97509750505050505050935093915050565b6121ce612480565b60405180602001604052808363ffffffff168686036001600160e01b0316816121f357fe5b046001600160e01b031681525090509392505050565b63ffffffff421690565b6001901b1790565b600019901b1690565b8161222e57612370565b82518060208501018060005b85811c1561236a575b85811c60ff1661225557600801612243565b85811c60071680801561229f57600181146122a457600281146122b757600381146122cd57600481146122ea5760058114612300576006811461231d576007811461233d57612360565b612360565b86830160f01b8452600284019350612360565b86600184010160f01b8452600284019350612360565b86600184010160e01b87840160f01b178452600484019350612360565b86600284010160f01b8452600284019350612360565b86600284010160e01b87840160f01b178452600484019350612360565b86600284010160e01b87600185010160f01b178452600484019350612360565b86600284010160d01b87600185010160e01b1787840160f01b1784526006840193505b505060030161223a565b50030183525b505050565b60001960ff919091031c1690565b60008061010083900384901b806123a15750600091508190506119af565b600184610100036123b1836123be565b0392509250509250929050565b600081806123de5760405162461bcd60e51b81526004016103339061298d565b600160801b81106123f1576080918201911c5b680100000000000000008110612409576040918201911c5b640100000000811061241d576020918201911c5b62010000811061242f576010918201911c5b6101008110612440576008918201911c5b60108110612450576004918201911c5b60048110612460576002918201911c5b6002811061246f576001820191505b50919050565b610100919091020190565b60408051602081019091526000815290565b604080518082019091526000808252602082015290565b604080516060810182526000808252602082018190529181019190915290565b6040518060200160405280600081525090565b80356001600160a01b038116811461030957600080fd5b60008083601f840112612504578182fd5b5081356001600160401b0381111561251a578182fd5b60208301915083602080830285010111156119af57600080fd5b600060208284031215612545578081fd5b61030683836124dc565b60008060408385031215612561578081fd5b61256b84846124dc565b946020939093013593505050565b60008060006060848603121561258d578081fd5b61259785856124dc565b95602085013595506040909401359392505050565b600080600080608085870312156125c1578081fd5b84356001600160a01b03811681146125d7578182fd5b966020860135965060408601359560600135945092505050565b60008060208385031215612603578182fd5b82356001600160401b03811115612618578283fd5b612624858286016124f3565b90969095509350505050565b60008060008060008060808789031215612648578182fd5b86356001600160401b038082111561265e578384fd5b61266a8a838b016124f3565b90985096506020890135915080821115612682578384fd5b5061268f89828a016124f3565b979a9699509760408101359660609091013595509350505050565b600080600080606085870312156126bf578384fd5b84356001600160401b038111156126d4578485fd5b6126e0878288016124f3565b90989097506020870135966040013595509350505050565b60008060006060848603121561270c578283fd5b835161271781613063565b602085015190935061272881613063565b604085015190925063ffffffff81168114612741578182fd5b809150509250925092565b60006020828403121561275d578081fd5b5051919050565b805163ffffffff1682526020808201516001600160e01b039081169184019190915260409182015116910152565b80516001600160e01b03908116835260209182015116910152565b6bffffffffffffffffffffffff19606093841b811682529190921b16601482015260280190565b6001600160f81b0319815260609290921b6bffffffffffffffffffffffff1916600183015260158201527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f603582015260550190565b6020808252825182820181905260009190848201906040850190845b81811015612864578351151583529284019291840191600101612846565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156128645761289f838551612764565b928401926060929092019160010161288c565b602080825282518282018190526000919060409081850190868401855b828110156128f2576128e2848351612792565b92840192908501906001016128cf565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612864578351516001600160e01b03168352928401929184019160010161291b565b6020808252825182820181905260009190848201906040850190845b818110156128645783516001600160901b03168352928401929184019160010161295d565b901515815260200190565b6020808252602c908201527f426974733a3a686967686573744269745365743a2056616c756520302068617360408201526b081b9bc8189a5d1cc81cd95d60a21b606082015260800190565b60208082526046908201527f556e697377617056324f7261636c654c6962726172793a3a63757272656e744360408201527f756d756c61746976655072696365313a205061697220686173206e6f2072657360608201526532b93b32b99760d11b608082015260a00190565b6020808252604a908201527f496e6465786564556e697377617056324f7261636c653a3a5f67657454776f5760408201527f617950726963653a204e6f20707269636520666f756e6420696e2070726f76696060820152693232b2103930b733b29760b11b608082015260a00190565b60208082526050908201527f496e6465786564556e697377617056324f7261636c653a3a76616c69644d696e60408201527f4d61783a204d696e696d756d206167652063616e206e6f74206265206869676860608201526f32b9103a3430b71036b0bc34b6bab69760811b608082015260a00190565b60208082526049908201527f496e6465786564556e697377617056324f7261636c653a3a5f676574546f6b6560408201527f6e50726963653a204e6f20707269636520666f756e6420696e2070726f76696460608201526832b2103930b733b29760b91b608082015260a00190565b60208082526047908201527f496e6465786564556e697377617056324f7261636c653a3a5f6765744574685060408201527f726963653a204e6f20707269636520666f756e6420696e2070726f7669646564606082015266103930b733b29760c91b608082015260a00190565b60208082526025908201527f556e697377617056324c6962726172793a204944454e544943414c5f41444452604082015264455353455360d81b606082015260800190565b6020808252605e908201527f496e6465786564556e697377617056324f7261636c653a3a636f6d707574654160408201527f766572616765546f6b656e73466f724574683a20546f6b656e7320616e64206160608201527f6d6f756e7473206861766520646966666572656e74206c656e677468732e0000608082015260a00190565b60208082526046908201527f556e697377617056324f7261636c654c6962726172793a3a63757272656e744360408201527f756d756c61746976655072696365303a205061697220686173206e6f2072657360608201526532b93b32b99760d11b608082015260a00190565b60208082526046908201527f556e697377617056324f7261636c654c6962726172793a3a63757272656e744360408201527f756d756c61746976655072696365733a205061697220686173206e6f2072657360608201526532b93b32b99760d11b608082015260a00190565b60208082526047908201527f496e646578656450726963654d61704c6962726172793a3a676574507269636560408201527f4f62736572766174696f6e73496e52616e67653a20496e76616c69642074696d606082015266652072616e676560c81b608082015260a00190565b6020808252605e908201527f496e6465786564556e697377617056324f7261636c653a3a636f6d707574654160408201527f766572616765457468466f72546f6b656e733a20546f6b656e7320616e64206160608201527f6d6f756e7473206861766520646966666572656e74206c656e677468732e0000608082015260a00190565b60208082526023908201527f4669786564506f696e743a204d554c5449504c49434154494f4e5f4f564552466040820152624c4f5760e81b606082015260800190565b60208082526055908201527f496e6465786564556e697377617056324f7261636c653a3a676574507269636560408201527f4f62736572766174696f6e496e57696e646f773a204e6f207072696365206f6260608201527439b2b93b32b21034b71033b4bb32b7103437bab91760591b608082015260a00190565b6020808252601e908201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604082015260600190565b60208082526038908201527f4b6579496e6465783a3a66696e644c6173745365744b65793a43616e206e6f7460408201527f2071756572792076616c7565207072696f7220746f20302e0000000000000000606082015260800190565b60208082526017908201527f4669786564506f696e743a204449565f42595f5a45524f000000000000000000604082015260600190565b606081016103098284612764565b604081016103098284612792565b90516001600160e01b0316815260200190565b6001600160901b0391909116815260200190565b6001600160701b038116811461307857600080fd5b5056fea2646970667358221220a846e57523fbe71d04a80087a86961afe3195a7659fb3586d4c1945e4b0904c164736f6c634300060800330000000000000000000000005757371414417b8c6caad45baef941abc7d3ab320000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005757371414417b8c6caad45baef941abc7d3ab320000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270
-----Decoded View---------------
Arg [0] : uniswapFactory (address): 0x5757371414417b8c6caad45baef941abc7d3ab32
Arg [1] : weth (address): 0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000005757371414417b8c6caad45baef941abc7d3ab32
Arg [1] : 0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270
Deployed ByteCode Sourcemap
356:19260:1:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;356:19260:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;3002:181:1;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;11370:486;;;;;;;;;:::i;:::-;;;;;;;;7138:324;;;;;;;;;:::i;:::-;;;;;;;;16152:737;;;;;;;;;:::i;:::-;;;;;;;;13546:422;;;;;;;;;:::i;:::-;;;;;;;;6219:324;;;;;;;;;:::i;:::-;;;;;;;;4520:235;;;;;;;;;:::i;9159:493::-;;;;;;;;;:::i;:::-;;;;;;;;14718:742;;;;;;;;;:::i;2436:289::-;;;;;;;;;:::i;:::-;;;;;;;;5039:428;;;;;;;;;:::i;8057:320::-;;;;;;;;;:::i;1810:304::-;;;;;;;;;:::i;12512:429::-;;;;;;;;;:::i;3436:392::-;;;;;;;;;:::i;:::-;;;;;;;;10266:490;;;;;;;;;:::i;3939:271::-;;;;;;;;;:::i;:::-;;;;;;;;3002:181;-1:-1:-1;;;;;3129:22:1;;3108:4;3129:22;;;;;;;;;;:49;;3169:8;3129:49;:39;:49;:::i;:::-;3122:56;;3002:181;;;;;:::o;11370:486::-;11590:43;11545:14;11561;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;;;;;;;;;11657:6;;-1:-1:-1;;;;;11692:31:1;::::1;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;11692:31:1;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1::0;11676:47:1;-1:-1:-1;11734:9:1::1;11729:123;11753:3;11749:1;:7;11729:123;;;11790:55;11803:6;;11810:1;11803:9;;;;;;;;;;;;;;;;;;;;;;11814:14;11830;11790:12;:55::i;:::-;11771:13;11785:1;11771:16;;;;;;;;;::::0;;::::1;::::0;;;;;:74;11758:3:::1;;11729:123;;;;1303:1;11370:486:::0;;;;;;;;:::o;7138:324::-;7347:40;;:::i;:::-;7302:14;7318;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;7404:53:::1;7419:5;7426:14;7442;7404;:53::i;:::-;7397:60:::0;7138:324;-1:-1:-1;;;;;;7138:324:1:o;16152:737::-;16411:36;16366:14;16382;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;16471:6;16505:25;;::::1;16490:150;;;;-1:-1:-1::0;;;16490:150:1::1;;;;;;;;;16682:3;-1:-1:-1::0;;;;;16668:18:1::1;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;16668:18:1;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;144:17;::::0;-1:-1;16668:18:1::1;-1:-1:-1::0;16646:40:1;-1:-1:-1;16697:9:1::1;16692:193;16716:3;16712:1;:7;16692:193;;;16759:119;:107;16851:11;;16863:1;16851:14;;;;;;;;;;;;;16759:87;16781:6;;16788:1;16781:9;;;;;;;;;;;;;;;;;;;;;;16800:14;16824;16759:12;:87::i;:::-;:91:::0;:107:::1;:91;:107;:::i;:::-;:117;:119::i;:::-;16734:19;16754:1;16734:22;;;;;;;;-1:-1:-1::0;;;;;16734:144:1;;::::1;:22;::::0;;::::1;::::0;;;;;;;:144;16721:3:::1;;16692:193;;;;1303:1;16152:737:::0;;;;;;;;;;:::o;13546:422::-;13781:7;13736:14;13752;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;13824:36:::1;;:::i;:::-;13863:51;13876:5;13883:14;13899;13863:12;:51::i;:::-;13824:90:::0;-1:-1:-1;13927:36:1::1;:24;13824:90:::0;13940:10;13927:24:::1;:12;:24;:::i;:36::-;13920:43:::0;13546:422;-1:-1:-1;;;;;;;;13546:422:1:o;6219:324::-;6429:38;;:::i;:::-;6384:14;6400;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;6484:54:::1;6500:5;6507:14;6523;6484:15;:54::i;4520:235::-:0;4591:4;4628:45;-1:-1:-1;;;;;4628:15:1;:31;4660:5;4667;4628:45;:31;:45;:::i;:::-;4623:64;;-1:-1:-1;4682:5:1;4675:12;;4623:64;-1:-1:-1;;;;;4700:22:1;;:15;:22;;;;;;;;;;:50;;4745:3;4700:50;:37;:50;:::i;:::-;4693:57;;4520:235;;;;:::o;9159:493::-;9382:47;9337:14;9353;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;9453:6;;-1:-1:-1;;;;;9481:42:1;::::1;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;9481:42:1;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1::0;9472:51:1;-1:-1:-1;9534:9:1::1;9529:119;9553:3;9549:1;:7;9529:119;;;9583:58;9599:6;;9606:1;9599:9;;;;;;;;;;;;;;;;;;;;;;9610:14;9626;9583:15;:58::i;:::-;9571:6;9578:1;9571:9;;;;;;;;;::::0;;::::1;::::0;;;;;:70;9558:3:::1;;9529:119;;14718:742:::0;14978:36;14933:14;14949;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;15038:6;15072:26;;::::1;15057:151;;;;-1:-1:-1::0;;;15057:151:1::1;;;;;;;;;15250:3;-1:-1:-1::0;;;;;15236:18:1::1;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;15236:18:1;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;144:17;::::0;-1:-1;15236:18:1::1;-1:-1:-1::0;15214:40:1;-1:-1:-1;15265:9:1::1;15260:196;15284:3;15280:1;:7;15260:196;;;15327:122;:110;15421:12;;15434:1;15421:15;;;;;;;;;;;;;15327:89;15351:6;;15358:1;15351:9;;;;;;;;;;;;;;;;;;;;;;15370:14;15394;15327;:89::i;:122::-;15302:19;15322:1;15302:22;;;;;;;;-1:-1:-1::0;;;;;15302:147:1;;::::1;:22;::::0;;::::1;::::0;;;;;;;:147;15289:3:::1;;15260:196;;2436:289:::0;2524:27;2575:6;;-1:-1:-1;;;;;2610:15:1;;2:2:-1;;;;27:1;24;17:12;2:2;2610:15:1;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;144:17;;-1:-1;2610:15:1;-1:-1:-1;2594:31:1;-1:-1:-1;2636:9:1;2631:90;2655:3;2651:1;:7;2631:90;;;2692:22;2704:6;;2711:1;2704:9;;;;;;;;;;;;;;;;;;;;;2692:22;2673:13;2687:1;2673:16;;;;;;;;:41;;;:16;;;;;;;;;;;:41;2660:3;;2631:90;;;;2436:289;;;;;:::o;5039:428::-;5123:26;5171:6;;-1:-1:-1;;;;;5205:15:1;;2:2:-1;;;;27:1;24;17:12;2:2;5205:15:1;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;144:17;;-1:-1;5205:15:1;-1:-1:-1;5190:30:1;-1:-1:-1;5231:9:1;5226:237;5250:3;5246:1;:7;5226:237;;;5268:13;5284:6;;5291:1;5284:9;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;5320:22:1;;5301:16;5320:22;;;;;;;;;;5268:25;;-1:-1:-1;5301:16:1;5320:50;;5365:3;5320:50;:37;:50;:::i;:::-;5301:69;;5396:11;:60;;;;-1:-1:-1;5411:45:1;-1:-1:-1;;;;;5411:15:1;:31;5443:5;5450;5411:45;:31;:45;:::i;:::-;5378:12;5391:1;5378:15;;;;;;;;:78;;;:15;;;;;;;;;;;:78;-1:-1:-1;;5255:3:1;;5226:237;;8057:320;8264:40;;:::i;:::-;8219:14;8235;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;8321:51:::1;8334:5;8341:14;8357;8321:12;:51::i;1810:304::-:0;1871:4;1916:5;-1:-1:-1;;;;;1907:14:1;:5;-1:-1:-1;;;;;1907:14:1;;1903:31;;;-1:-1:-1;1930:4:1;1923:11;;1903:31;1940:48;;:::i;:::-;1991;-1:-1:-1;;;;;1991:15:1;:34;2026:5;2033;1991:48;:34;:48;:::i;:::-;-1:-1:-1;;;;;2052:22:1;;:15;:22;;;;;;;;;;1940:99;;-1:-1:-1;2052:57:1;;1940:99;2052:57;:44;:57;:::i;:::-;2045:64;1810:304;-1:-1:-1;;;1810:304:1:o;12512:429::-;12748:7;12703:14;12719;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;12790:38:::1;;:::i;:::-;12831:53;12846:5;12853:14;12869;12831;:53::i;3436:392::-:0;3554:48;;:::i;:::-;-1:-1:-1;;;;;3626:22:1;;:15;:22;;;;;;;;;;:49;;3666:8;3626:49;:39;:49;:::i;:::-;3696:21;;3612:63;;-1:-1:-1;3696:26:1;;3681:142;;;;-1:-1:-1;;;3681:142:1;;;;;;;;10266:490;10488:43;10443:14;10459;1187;1169;:32;;1154:143;;;;-1:-1:-1;;;1154:143:1;;;;;;;;;10555:6;;-1:-1:-1;;;;;10590:31:1;::::1;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;10590:31:1;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1::0;10574:47:1;-1:-1:-1;10632:9:1::1;10627:125;10651:3;10647:1;:7;10627:125;;;10688:57;10703:6;;10710:1;10703:9;;;;;;;;;;;;;;;;;;;;;;10714:14;10730;10688;:57::i;:::-;10669:13;10683:1;10669:16;;;;;;;;;::::0;;::::1;::::0;;;;;:76;10656:3:::1;;10627:125;;3939:271:::0;-1:-1:-1;;;;;4137:22:1;;:15;:22;;;;;;;;;;4073:45;;4137:68;;4188:8;4198:6;4137:68;:50;:68;:::i;:::-;4128:77;3939:271;-1:-1:-1;;;;3939:271:1:o;4266:185:5:-;4386:4;4405:41;:15;4437:8;4405:41;:31;:41;:::i;18753:861:1:-;18889:27;;:::i;:::-;18939:5;-1:-1:-1;;;;;18930:14:1;:5;-1:-1:-1;;;;;18930:14:1;;18926:67;;;18961:25;18981:1;18984;18961:19;:25::i;:::-;18954:32;;;;18926:67;18999:16;;19047:42;-1:-1:-1;;;;;19047:15:1;:28;19076:5;19083;19047:42;:28;:42;:::i;:::-;-1:-1:-1;;;;;19137:22:1;;19096:15;19137:22;;;;;;;;;;18998:91;;-1:-1:-1;18998:91:1;;-1:-1:-1;19096:15:1;;;19137:113;;;;;;;19208:14;;19230;;19137:46;:113;:::i;:::-;19095:155;;;;19264:10;19256:94;;;;-1:-1:-1;;;19256:94:1;;;;;;;;;-1:-1:-1;;;;;19405:22:1;;19356:46;19405:22;;;;;;;;;;;:45;;;:31;;;;:45;;;;;;19503:18;;19529:31;;;;19405:45;;19463:146;;19503:18;;;;;-1:-1:-1;;;;;19529:31:1;19568:9;19585:18;19463:32;:146::i;:::-;19456:153;18753:861;-1:-1:-1;;;;;;;;;18753:861:1:o;17887:862::-;18025:27;;:::i;:::-;18075:5;-1:-1:-1;;;;;18066:14:1;:5;-1:-1:-1;;;;;18066:14:1;;18062:67;;;18097:25;18117:1;18120;18097:19;:25::i;18062:67::-;18135:16;;18183:42;-1:-1:-1;;;;;18183:15:1;:28;18212:5;18219;18183:42;:28;:42;:::i;:::-;-1:-1:-1;;;;;18273:22:1;;18232:15;18273:22;;;;;;;;;;18134:91;;-1:-1:-1;18134:91:1;;-1:-1:-1;18232:15:1;;;18273:113;;;;;;;18344:14;;18366;;18273:46;:113;:::i;:::-;18231:155;;;;18400:10;18392:96;;;;-1:-1:-1;;;18392:96:1;;;;;;;;;-1:-1:-1;;;;;18543:22:1;;18494:46;18543:22;;;;;;;;;;;:45;;;:31;;:45;;;;;18641:18;;18601:143;;18641:18;;;;18667:28;;;-1:-1:-1;;;;;18667:28:1;18703:9;18720:18;18601:32;:143::i;1647:253:4:-;1714:16;;:::i;:::-;1738:6;1765;;;:54;;-1:-1:-1;;1811:7:4;;-1:-1:-1;;;;;1806:13:4;1780:17;;;;1801:1;1780:17;1801:1;1775:27;;;;;:44;1765:54;1750:120;;;;-1:-1:-1;;;1750:120:4;;;;;;;;;1883:12;;;;;;;;;;;;;1647:253;-1:-1:-1;;;1647:253:4:o;2556:122::-;2651:7;873:3;2651:21;;2556:122::o;16942:941:1:-;17081:38;;:::i;:::-;17142:5;-1:-1:-1;;;;;17133:14:1;:5;-1:-1:-1;;;;;17133:14:1;;17129:147;;;17164:105;;;;;;;;17205:20;17223:1;17205:17;:20::i;:::-;:23;-1:-1:-1;;;;;17164:105:1;;;;;17238:20;17256:1;17238:17;:20::i;:::-;:23;-1:-1:-1;;;;;17164:105:1;;;17157:112;-1:-1:-1;17157:112:1;;17129:147;17321:44;;:::i;:::-;17368:48;-1:-1:-1;;;;;17368:15:1;:34;17403:5;17410;17368:48;:34;:48;:::i;:::-;17553:17;;-1:-1:-1;;;;;17499:22:1;;17458:15;17499:22;;;;;;;;;;17321:95;;-1:-1:-1;17458:15:1;;;17499:121;;:22;:121;;;;;17578:14;;17600;;17499:46;:121;:::i;:::-;17457:163;;;;17634:10;17626:97;;;;-1:-1:-1;;;17626:97:1;;;;;;;;;17729:45;;:::i;:::-;-1:-1:-1;;;;;;17777:22:1;;:15;:22;;;;;;;;;;;:45;;;:31;;;;:45;;;;;;17729:93;;;;;;;;;;;;;;;-1:-1:-1;;;;;17729:93:1;;;;;;;;;;;;;;;;;;;;;;;17835:43;;17729:93;;17870:7;;17835:34;:43;:::i;900:339:7:-;1029:4;1043:12;1058:53;1083:14;1099:5;1106:4;1058:24;:53::i;:::-;1043:68;;1118:16;1136;1172:4;-1:-1:-1;;;;;1157:32:7;;:34;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1157:34:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1157:34:7;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1157:34:7;;;;;;;;;1117:74;;;;;1204:8;-1:-1:-1;;;;;1204:13:7;1216:1;1204:13;;:30;;;;-1:-1:-1;;;;;;1221:13:7;;;;1204:30;1197:37;900:339;-1:-1:-1;;;;;;;900:339:7:o;3710:414:5:-;3831:4;3863:16;3882:24;3893:12;3882:24;;:10;:24::i;:::-;3863:43;-1:-1:-1;3991:41:5;:15;3863:43;3991:41;:31;:41;:::i;:::-;3987:59;;;4041:5;4034:12;;;;;3987:59;4059:60;4089:15;4106:12;4059:29;:60::i;2161:1035:7:-;2281:23;;:::i;:::-;2313:14;2329;2347:40;2375:5;2382:4;2347:27;:40::i;:::-;2312:75;;;;2393:12;2408:62;2439:14;2455:6;2463;2408:30;:62::i;:::-;2393:77;;2519:24;2551;2583:21;2613:52;2660:4;2613:46;:52::i;:::-;2511:154;;;;;;2783:5;-1:-1:-1;;;;;2773:15:7;:6;-1:-1:-1;;;;;2773:15:7;;2769:423;;;2805:176;;;;;;;;2843:14;2805:176;;;;;;2896:16;-1:-1:-1;;;;;2805:176:7;;;;;2955:16;-1:-1:-1;;;;;2805:176:7;;;;2798:183;;;;;;;;;;2769:423;3009:176;;;;;;;;3047:14;3009:176;;;;;;3100:16;-1:-1:-1;;;;;3009:176:7;;;;;3159:16;-1:-1:-1;;;;;3009:176:7;;;;3002:183;;;;;;;;;;2769:423;2161:1035;;;;;;;;;;;:::o;1750:538:5:-;1902:4;1934:14;1951:69;1981:15;1998:11;:21;;;1951:29;:69::i;:::-;1934:86;;2030:9;2026:236;;;2049:16;2068:33;2079:11;:21;;;2068:33;;:10;:33::i;:::-;2049:52;-1:-1:-1;2121:45:5;:15;2049:52;2121:45;:35;:45;:::i;:::-;2109:57;;2178:9;2174:82;;;2199:34;;;;:24;;;;:34;;;;;;;;;:48;;;;;;;;-1:-1:-1;;2199:48:5;;;;;;;;;;-1:-1:-1;;;;;2199:48:5;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2199:48:5;;;;;;;;;;;2174:82;2026:236;2274:9;1750:538;-1:-1:-1;;;1750:538:5:o;4522:210::-;4642:36;;:::i;:::-;-1:-1:-1;4693:34:5;;;;:24;;;;:34;;;;;;;;;4686:41;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4686:41:5;;;;;;;;;;;;;;;;;;;4522:210::o;4736:1057::-;4899:45;4954:20;4977;4988:8;4977:10;:20::i;:::-;4954:43;;5003:18;5024;5035:6;5024:10;:18::i;:::-;5003:39;;5069:12;5056:10;:25;5048:109;;;;-1:-1:-1;;;5048:109:5;;;;;;;;;5163:25;5191:75;:15;5241:12;5255:10;5191:75;:49;:75;:::i;:::-;5163:103;;5360:11;5396:1;5374:12;:19;:23;;;;;;5360:37;;5448:3;-1:-1:-1;;;;;5412:40:5;;5:9:-1;2:2;;;27:1;24;17:12;2:2;5412:40:5;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;5403:49:5;-1:-1:-1;5511:2:5;5493:21;;5458:11;5521:268;5545:3;5541:1;:7;5521:268;;;5638:10;;5632:4;5628:21;5705:28;;;5563:21;5753:29;;;:24;;;;:29;;;;;;;;;5741:41;;;;;;;;;;;;;;-1:-1:-1;;;;;5741:41:5;;;;;;;;;;;;;;;;;;;;;;;;:9;;5674:1;5665:11;;;;5741:6;;5748:1;;5741:9;;;;;;;;;;;;;;;:41;-1:-1:-1;;5550:3:5;;5521:268;;2563:330:6;2676:4;2689:16;2707:21;2732:27;2752:6;2732:19;:27::i;:::-;2765:18;2786;;;;;;;;;;;2688:71;;-1:-1:-1;2688:71:6;-1:-1:-1;2814:15:6;2810:33;;2838:5;2831:12;;;;;;;2810:33;2856:32;:10;2874:13;2856:32;:17;:32;:::i;2046:233:4:-;2127:16;;:::i;:::-;2173:1;2159:11;-1:-1:-1;;;;;2159:15:4;;2151:51;;;;-1:-1:-1;;;2151:51:4;;;;;;;;;2215:59;;;;;;;;;;-1:-1:-1;;;;;2225:48:4;;-1:-1:-1;;;;;;;873:3:4;2226:32;;;;2225:48;;;;;;-1:-1:-1;;;;;2215:59:4;;;;2208:66;;2046:233;;;;:::o;1243:760:7:-;1377:6;1401:7;1445:14;1461;1479:48;1507:7;1516:10;1479:27;:48::i;:::-;1444:83;;;;1533:12;1548:62;1579:14;1595:6;1603;1548:30;:62::i;:::-;1533:77;;1630:7;-1:-1:-1;;;;;1620:17:7;:6;-1:-1:-1;;;;;1620:17:7;;1616:383;;;1648:24;1674:21;1699:52;1746:4;1699:46;:52::i;:::-;1647:104;-1:-1:-1;1647:104:7;-1:-1:-1;1759:50:7;;-1:-1:-1;;;;;1759:50:7;1616:383;1831:24;1857:21;1882:52;1929:4;1882:46;:52::i;1243:760::-;;;;;;;:::o;6518:1554:5:-;6714:4;6737:7;6773:16;6792:21;6803:9;6792:10;:21::i;:::-;6773:40;;6819:25;6847:38;6875:9;6847:27;:38::i;:::-;6819:66;-1:-1:-1;6914:35:5;;;;6979;;;;6914;;7350;;;7369:16;7350:35;7346:490;;;7395:49;7447:34;;;:24;;;:34;;;;;7511:21;;;;7553:17;;;;;:53;;;7594:12;7582:24;;:9;:24;7553:53;:107;;;;;7646:14;7630:12;7618:24;;:9;:24;:42;;7553:107;:161;;;;;7700:14;7684:12;7672:24;;:9;:24;:42;;7553:161;7540:225;;;7741:4;7747:8;7733:23;;;;;;;;;;;;7540:225;7776:16;7772:58;;;-1:-1:-1;7812:5:5;;-1:-1:-1;7812:5:5;;-1:-1:-1;7804:17:5;;-1:-1:-1;;;;;7804:17:5;7772:58;7346:490;;;7868:26;;;7911:27;7868:26;7911:10;:27::i;:::-;7900:38;;7944:19;7966:26;7977:14;7966:10;:26::i;:::-;7944:48;-1:-1:-1;8005:62:5;:15;8045:8;7944:48;8005:62;:39;:62;:::i;:::-;7998:69;;;;;;;;;;6518:1554;;;;;;;;:::o;4196:368:7:-;4370:27;;:::i;:::-;4412:147;4462:20;4490:18;4538:14;4523:12;:29;4412:42;:147::i;:::-;4405:154;4196:368;-1:-1:-1;;;;;4196:368:7:o;1023:121:4:-;1073:16;;:::i;:::-;-1:-1:-1;1104:35:4;;;;;;;;;873:3;1114:24;;;;-1:-1:-1;;;;;;;1114:24:4;1104:35;;;1023:121::o;3412:780:7:-;3558:25;;:::i;:::-;3644:22;;3619;;:47;3673:40;;:::i;:::-;3716:147;3766:12;:32;;;3806:12;:32;;;3846:11;3716:42;:147::i;:::-;3673:190;;3869:43;;:::i;:::-;3915:153;3965:12;:35;;;4008:12;:35;;;4051:11;3915:42;:153::i;:::-;4081:106;;;;;;;;;4122:15;;-1:-1:-1;;;;;4081:106:7;;;;;4162:18;;4081:106;;;;;-1:-1:-1;4081:106:7;3412:780;-1:-1:-1;;;;3412:780:7:o;1574:242:8:-;1679:12;1700:14;1716;1734:26;1745:6;1753;1734:10;:26::i;:::-;1699:61;;;;1773:38;1787:7;1796:6;1804;1773:13;:38::i;906:133:5:-;461:7;1004:30;;;906:133::o;2559:901::-;2695:4;2731:16;2750:24;2761:12;2750:24;;:10;:24::i;:::-;2731:43;;585:9;2952:41;2980:12;2952:41;;:27;:41::i;:::-;:70;2948:490;;3039:4;3032:11;;;;;2948:490;-1:-1:-1;;3248:12:5;;3167:53;3223:38;;;:24;;;:38;;;;;3282:25;;;;:30;;:111;;-1:-1:-1;3339:25:5;;585:9;3339:25;;;;3324:40;;:69;;;;;3282:111;3269:163;;;3419:4;3412:11;;;;;;3269:163;-1:-1:-1;3450:5:5;;2559:901;-1:-1:-1;;;;2559:901:5:o;692:345:8:-;779:14;795;837:6;-1:-1:-1;;;;;827:16:8;:6;-1:-1:-1;;;;;827:16:8;;;819:66;;;;-1:-1:-1;;;819:66:8;;;;;;;;;919:6;-1:-1:-1;;;;;910:15:8;:6;-1:-1:-1;;;;;910:15:8;;:53;;948:6;956;910:53;;;929:6;937;910:53;891:72;;-1:-1:-1;891:72:8;-1:-1:-1;;;;;;977:20:8;;969:63;;;;-1:-1:-1;;;969:63:8;;;;;;;;;692:345;;;;;:::o;1041:448::-;1152:12;1283:7;1331:6;1339;1314:32;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1314:32:8;;;1304:43;;;;;;1232:228;;;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1232:228:8;;;1211:259;;49:4:-1;1211:259:8;;;;;1041:448;-1:-1:-1;;;;1041:448:8:o;1244:1217:9:-;1333:24;1365;1397:21;1450:23;:21;:23::i;:::-;1433:40;;1513:4;-1:-1:-1;;;;;1498:41:9;;:43;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1498:43:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1498:43:9;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1498:43:9;;;;;;;;;1479:62;;1581:4;-1:-1:-1;;;;;1566:41:9;;:43;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1566:43:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1566:43:9;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1566:43:9;;;;;;;;;1547:62;;1720:16;1744;1768:25;1817:4;-1:-1:-1;;;;;1802:32:9;;:34;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1802:34:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1802:34:9;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1802:34:9;;;;;;;;;1712:124;;;;;;1857:8;-1:-1:-1;;;;;1857:13:9;1869:1;1857:13;;:30;;;;-1:-1:-1;;;;;;1874:13:9;;;;1857:30;1842:131;;;;-1:-1:-1;;;1842:131:9;;;;;;;;;2005:14;1983:36;;:18;:36;;;1979:478;;2091:35;;;2226:73;;;2234:39;2254:8;2264;2234:19;:39::i;:::-;:42;-1:-1:-1;;;;;2226:51:9;:73;2196:111;;;;;2369:73;;;2377:39;2397:8;2407;2377:19;:39::i;:::-;:42;-1:-1:-1;;;;;2369:51:9;:73;2339:111;;;;;-1:-1:-1;1979:478:9;1244:1217;;;;;;;;:::o;1939:470:6:-;2051:4;2080:16;2098:21;2123:27;2143:6;2123:19;:27::i;:::-;2199:18;2220;;;;;;;;;;;2079:71;;-1:-1:-1;2079:71:6;;-1:-1:-1;2262:32:6;2220:18;2079:71;2262:32;:17;:32;:::i;:::-;2261:33;2244:50;;2304:9;2300:83;;;2344:32;:10;2362:13;2344:32;:17;:32;:::i;:::-;2323:18;;;;;;;;;;;:53;2395:9;1939:470;-1:-1:-1;;;;;;1939:470:6:o;3061:1572::-;3218:25;3271:21;;;3251:17;;3352:31;3282:10;3352:19;:31::i;:::-;3298:85;;;;3390:19;3411:24;3439:29;3459:8;3439:19;:29::i;:::-;3389:79;;;;3769:9;3765:1;:13;3782:2;3764:20;-1:-1:-1;;;;;3754:31:6;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3754:31:6;;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;108:14;3754:31:6;87:42:-1;143:17;;-1:-1;3754:31:6;-1:-1:-1;3890:1:6;3869:23;;;4054:18;;;;;;;;;;;3739:46;;-1:-1:-1;3918:13:6;;4054:54;;4089:18;4054:54;:34;:54;:::i;:::-;4033:75;-1:-1:-1;4114:13:6;4191:248;4209:11;4198:8;:22;4191:248;;;4306:45;:12;4332:10;4344:6;4306:45;:25;:45;:::i;:::-;4371:1;4359:13;;;;4393:18;;;;;;;;;;;;4359:13;;4393:18;;-1:-1:-1;4429:3:6;4419:13;4191:248;;;4534:43;:10;4560:16;4534:43;:25;:43;:::i;:::-;4521:56;-1:-1:-1;4583:45:6;:12;4521:56;4621:6;4583:45;:25;:45;:::i;:::-;3061:1572;;;;;;;;;;;;;:::o;1437:191::-;1586:3;1577:12;;;1611;;;;;1437:191::o;503:116:3:-;591:13;608:1;590:19;;;:24;;503:116::o;2591:956:9:-;2673:24;2699:21;2747:23;:21;:23::i;:::-;2730:40;;2810:4;-1:-1:-1;;;;;2795:41:9;;:43;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2795:43:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2795:43:9;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;2795:43:9;;;;;;;;;2776:62;;2949:16;2973;2997:25;3046:4;-1:-1:-1;;;;;3031:32:9;;:34;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3031:34:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;3031:34:9;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;3031:34:9;;;;;;;;;2941:124;;;;;;3086:8;-1:-1:-1;;;;;3086:13:9;3098:1;3086:13;;:30;;;;-1:-1:-1;;;;;;3103:13:9;;;;3086:30;3071:131;;;;-1:-1:-1;;;3071:131:9;;;;;;;;;3234:14;3212:36;;:18;:36;;;3208:335;;3320:35;;;3455:73;;;3463:39;3483:8;3493;3463:19;:39::i;:::-;:42;-1:-1:-1;;;;;3455:51:9;:73;3425:111;;;;;-1:-1:-1;3208:335:9;2591:956;;;;;;:::o;3678:::-;3760:24;3786:21;3834:23;:21;:23::i;:::-;3817:40;;3897:4;-1:-1:-1;;;;;3882:41:9;;:43;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3882:43:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;3882:43:9;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;3882:43:9;;;;;;;;;3863:62;;4036:16;4060;4084:25;4133:4;-1:-1:-1;;;;;4118:32:9;;:34;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;4118:34:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4118:34:9;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;4118:34:9;;;;;;;;;4028:124;;;;;;4173:8;-1:-1:-1;;;;;4173:13:9;4185:1;4173:13;;:30;;;;-1:-1:-1;;;;;;4190:13:9;;;;4173:30;4158:131;;;;-1:-1:-1;;;4158:131:9;;;;;;;;;4321:14;4299:36;;:18;:36;;;4295:335;;4407:35;;;4542:73;;;4550:39;4570:8;4580;4550:19;:39::i;1145:153:5:-;461:7;1263:30;;;1145:153::o;5027:1328:6:-;5185:4;5202:7;5232:16;5250:21;5275:27;5295:6;5275:19;:27::i;:::-;5231:71;;-1:-1:-1;5231:71:6;-1:-1:-1;5308:16:6;;;;5462:18;5458:434;;5498:13;5490:82;;;;-1:-1:-1;;;5490:82:6;;;;;;;;;5592:1;5580:13;;;;5612:1;5601:12;;5458:434;;;-1:-1:-1;5647:18:6;;;;;;;;;;;;5693:42;5647:18;5721:13;5693:42;:27;:42;:::i;:::-;5673:62;;-1:-1:-1;5673:62:6;-1:-1:-1;5743:143:6;;;;5792:8;5776:13;:24;5764:36;;;;5743:143;;;-1:-1:-1;;5864:13:6;;;;5825:29;;;5853:1;5825:29;;5743:143;5906:5;5905:6;:33;;;;;5927:11;5915:8;:23;;5905:33;5898:339;;;-1:-1:-1;5961:18:6;;;;;;;;;;;;5991:15;5987:244;;6022:13;6018:36;;-1:-1:-1;6045:5:6;;-1:-1:-1;6045:5:6;;-1:-1:-1;6037:17:6;;-1:-1:-1;;;;;6037:17:6;6018:36;6076:3;6064:15;;;;6101:1;6089:13;;;;5987:244;;;6138:26;:10;:24;:26::i;:::-;6127:37;;6192:8;6186:3;:14;6174:26;;;;6218:4;6210:12;;5987:244;5898:339;;;6257:11;6246:8;:22;6242:60;;;-1:-1:-1;6286:5:6;;-1:-1:-1;6286:5:6;;-1:-1:-1;6278:17:6;;-1:-1:-1;;;;;6278:17:6;6242:60;6315:4;6321:28;6330:8;6340;6321;:28::i;:::-;6307:43;;;;;;;;;;5027:1328;;;;;;:::o;4638:342:9:-;4784:40;;:::i;:::-;4875:100;;;;;;;;4957:11;4911:57;;4933:20;4912:18;:41;-1:-1:-1;;;;;4911:57:9;;;;;;;-1:-1:-1;;;;;4875:100:9;;;;4860:115;;4638:342;;;;;:::o;1031:113::-;1115:23;:15;:23;;1031:113::o;277:116:3:-;115:1;375:12;;367:21;;277:116::o;904:128::-;-1:-1:-1;;1011:15:3;;1003:24;;904:128::o;2026:3704::-;2127:8;2123:21;;2137:7;;2123:21;2254:12;2248:19;2472:3;2467:2;2453:12;2449:21;2445:31;2580:8;2794:1;2780:2763;2800:11;;;2797:18;2780:2763;;2895:55;2909:11;;;2922:3;2905:21;2895:55;;2944:1;2937:9;2895:55;;;3010:11;;;3023:1;3006:19;;3148:9;;;;3187:1;3182:191;;;;3389:1;3384:199;;;;3599:1;3594:404;;;;4014:1;4009:199;;;;4224:1;4219:400;;;;4635:1;4630:399;;;;5045:1;5040:495;;;;3129:2406;;3148:9;;;3182:191;3321:6;3318:1;3314:14;3308:4;3304:25;3299:3;3292:38;3359:1;3354:3;3350:11;3343:18;;3182:191;;3384:199;3531:6;3527:1;3524;3520:9;3516:22;3510:4;3506:33;3501:3;3494:46;3569:1;3564:3;3560:11;3553:18;;3384:199;;3594:404;3917:6;3913:1;3910;3906:9;3902:22;3896:4;3892:33;3866:6;3863:1;3859:14;3853:4;3849:25;3788:153;3769:3;3747:208;3984:1;3979:3;3975:11;3968:18;;3594:404;;4009:199;4156:6;4152:1;4149;4145:9;4141:22;4135:4;4131:33;4126:3;4119:46;4194:1;4189:3;4185:11;4178:18;;4009:199;;4219:400;4510:6;4506:1;4503;4499:9;4495:22;4489:4;4485:33;4459:6;4456:1;4452:14;4446:4;4442:25;4381:153;4362:3;4340:208;4578:1;4573:3;4569:11;4562:18;;4219:400;;4630:399;4921:6;4917:1;4914;4910:9;4906:22;4900:4;4896:33;4870:6;4866:1;4863;4859:9;4855:22;4849:4;4845:33;4784:161;4765:3;4743:216;4988:1;4983:3;4979:11;4972:18;;4630:399;;5040:495;5409:6;5405:1;5402;5398:9;5394:22;5388:4;5384:33;5356:6;5352:1;5349;5345:9;5341:22;5335:4;5331:33;5309:126;5283:6;5280:1;5276:14;5270:4;5266:25;5205:246;5186:3;5164:301;5494:1;5489:3;5485:11;5478:18;;3129:2406;-1:-1:-1;;2829:1:3;2822:9;2780:2763;;;-1:-1:-1;5630:18:3;5703:16;5682:38;;2159:3567;;;;:::o;698:133::-;-1:-1:-1;;813:3:3;:11;;;;804:21;796:30;;698:133::o;7839:283::-;7927:20;;8001:3;:9;;;7992:19;;;8021:8;8017:46;;-1:-1:-1;8047:5:3;;-1:-1:-1;8047:5:3;;-1:-1:-1;8039:17:3;;8017:46;8076:4;8111:3;8105;:9;8083:18;8097:3;8083:13;:18::i;:::-;:32;8068:49;;;;;7839:283;;;;;:::o;5845:555::-;5905:9;5934:4;5953:5;5944:63;;;;-1:-1:-1;;;5944:63:3;;;;;;;;;-1:-1:-1;;;6017:1:3;:40;6013:68;;6066:3;6071:8;;;;6060:9;6013:68;6095:19;6090:1;:24;6086:50;;6123:2;6127:7;;;;6117:8;6086:50;6150:11;6145:1;:16;6141:42;;6170:2;6174:7;;;;6164:8;6141:42;6197:7;6192:1;:12;6188:38;;6213:2;6217:7;;;;6207:8;6188:38;6240:5;6235:1;:10;6231:34;;6254:1;6257:6;;;;6248:7;6231:34;6279:4;6274:1;:9;6270:33;;6292:1;6295:6;;;;6286:7;6270:33;6317:3;6312:1;:8;6308:32;;6329:1;6332:6;;;;6323:7;6308:32;6354:3;6349:1;:8;6345:20;;6364:1;6359:6;;;;6345:20;5845:555;;;;:::o;1119:141:6:-;1235:3;1224:14;;;;1223:32;;1119:141::o;-1:-1:-1:-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;5:130::-;72:20;;-1:-1;;;;;41055:54;;41879:35;;41869:2;;41928:1;;41918:12;160:352;;;290:3;283:4;275:6;271:17;267:27;257:2;;-1:-1;;298:12;257:2;-1:-1;328:20;;-1:-1;;;;;357:30;;354:2;;;-1:-1;;390:12;354:2;434:4;426:6;422:17;410:29;;485:3;434:4;;469:6;465:17;426:6;451:32;;448:41;445:2;;;502:1;;492:12;1456:241;;1560:2;1548:9;1539:7;1535:23;1531:32;1528:2;;;-1:-1;;1566:12;1528:2;1628:53;1673:7;1649:22;1628:53;;1704:366;;;1825:2;1813:9;1804:7;1800:23;1796:32;1793:2;;;-1:-1;;1831:12;1793:2;1893:53;1938:7;1914:22;1893:53;;;1883:63;1983:2;2022:22;;;;1106:20;;-1:-1;;;1787:283;2077:491;;;;2215:2;2203:9;2194:7;2190:23;2186:32;2183:2;;;-1:-1;;2221:12;2183:2;2283:53;2328:7;2304:22;2283:53;;;2273:63;2373:2;2412:22;;1106:20;;-1:-1;2481:2;2520:22;;;1106:20;;2177:391;-1:-1;;;2177:391;2575:617;;;;;2730:3;2718:9;2709:7;2705:23;2701:33;2698:2;;;-1:-1;;2737:12;2698:2;72:20;;-1:-1;;;;;41055:54;;41879:35;;41869:2;;-1:-1;;41918:12;41869:2;2789:63;2889:2;2928:22;;1106:20;;-1:-1;2997:2;3036:22;;1106:20;;3105:2;3144:22;1106:20;;-1:-1;2692:500;-1:-1;;;2692:500;3199:397;;;3338:2;3326:9;3317:7;3313:23;3309:32;3306:2;;;-1:-1;;3344:12;3306:2;3402:17;3389:31;-1:-1;;;;;3432:6;3429:30;3426:2;;;-1:-1;;3462:12;3426:2;3500:80;3572:7;3563:6;3552:9;3548:22;3500:80;;;3490:90;;;;-1:-1;3300:296;-1:-1;;;;3300:296;3603:929;;;;;;;3828:3;3816:9;3807:7;3803:23;3799:33;3796:2;;;-1:-1;;3835:12;3796:2;3893:17;3880:31;-1:-1;;;;;3931:18;3923:6;3920:30;3917:2;;;-1:-1;;3953:12;3917:2;3991:80;4063:7;4054:6;4043:9;4039:22;3991:80;;;3981:90;;-1:-1;3981:90;-1:-1;4136:2;4121:18;;4108:32;;-1:-1;4149:30;;;4146:2;;;-1:-1;;4182:12;4146:2;;4220:80;4292:7;4283:6;4272:9;4268:22;4220:80;;;3790:742;;;;-1:-1;4210:90;4337:2;4376:22;;1106:20;;4445:2;4484:22;;;1106:20;;-1:-1;3790:742;-1:-1;;;;3790:742;4539:647;;;;;4712:2;4700:9;4691:7;4687:23;4683:32;4680:2;;;-1:-1;;4718:12;4680:2;4776:17;4763:31;-1:-1;;;;;4806:6;4803:30;4800:2;;;-1:-1;;4836:12;4800:2;4874:80;4946:7;4937:6;4926:9;4922:22;4874:80;;;4864:90;;;;-1:-1;4991:2;5030:22;;1106:20;;5099:2;5138:22;1106:20;;-1:-1;4674:512;-1:-1;;;;4674:512;5193:533;;;;5341:2;5329:9;5320:7;5316:23;5312:32;5309:2;;;-1:-1;;5347:12;5309:2;982:6;976:13;994:33;1021:5;994:33;;;5510:2;5560:22;;976:13;5399:74;;-1:-1;994:33;976:13;994:33;;;5629:2;5678:22;;1394:13;5518:74;;-1:-1;41416:10;41405:22;;42250:34;;42240:2;;-1:-1;;42288:12;42240:2;5637:73;;;;5303:423;;;;;;5733:263;;5848:2;5836:9;5827:7;5823:23;5819:32;5816:2;;;-1:-1;;5854:12;5816:2;-1:-1;1254:13;;5810:186;-1:-1;5810:186;20561:674;20783:23;;41416:10;41405:22;24409:36;;20967:4;20956:16;;;20950:23;-1:-1;;;;;41183:70;;;21027:14;;;24301:37;;;;21139:4;21128:16;;;21122:23;41183:70;21199:14;;24301:37;20685:550;22103:507;22332:23;;-1:-1;;;;;41183:70;;;24301:37;;22514:4;22503:16;;;22497:23;41183:70;22574:14;;24301:37;22231:379;24457:392;-1:-1;;41792:2;41788:14;;;;;7378:58;;41788:14;;;;;24710:2;24701:12;;7378:58;24812:12;;;24601:248;24856:926;-1:-1;;;;;;16588:87;;41792:2;41788:14;;;;-1:-1;;41788:14;16573:1;16694:11;;7378:58;25468:12;;;12300:58;16200:66;25579:12;;;16180:87;16286:12;;;25202:580;25789:358;25960:2;25974:47;;;37746:12;;25945:18;;;39245:19;;;25789:358;;25960:2;36874:14;;;;39285;;;;25789:358;7866:251;7891:6;7888:1;7885:13;7866:251;;;7952:13;;40648;40641:21;12054:34;;38546:14;;;;6145;;;;7913:1;7906:9;7866:251;;;-1:-1;26027:110;;25931:216;-1:-1;;;;;;25931:216;26154:506;26399:2;26413:47;;;37746:12;;26384:18;;;39245:19;;;26154:506;;26399:2;36874:14;;;;39285;;;;26154:506;8814:362;8839:6;8836:1;8833:13;8814:362;;;6329:114;6439:3;8906:6;8900:13;6329:114;;;38546:14;;;;6472:4;6463:14;;;;;8861:1;8854:9;8814:362;;26667:514;26916:2;26930:47;;;37746:12;;26901:18;;;39245:19;;;26667:514;;26916:2;39285:14;;;;;;36874;;;26667:514;9887:368;9912:6;9909:1;9906:13;9887:368;;;6651:118;6765:3;9979:6;9973:13;6651:118;;;6789:14;;;;38546;;;;9934:1;9927:9;9887:368;;;-1:-1;26983:188;;26887:294;-1:-1;;;;;;;26887:294;27188:478;27419:2;27433:47;;;37746:12;;27404:18;;;39245:19;;;27188:478;;27419:2;36874:14;;;;39285;;;;27188:478;10899:341;10924:6;10921:1;10918:13;10899:341;;;10985:13;;23494:23;-1:-1;;;;;41183:70;24301:37;;38546:14;;;;7079;;;;41066:42;10939:9;10899:341;;27673:370;27850:2;27864:47;;;37746:12;;27835:18;;;39245:19;;;27673:370;;27850:2;36874:14;;;;39285;;;;27673:370;11709:260;11734:6;11731:1;11728:13;11709:260;;;11795:13;;-1:-1;;;;;40931:50;24071:37;;38546:14;;;;7261;;;;11756:1;11749:9;11709:260;;28050:210;40648:13;;40641:21;12054:34;;28171:2;28156:18;;28142:118;28267:416;28467:2;28481:47;;;12595:2;28452:18;;;39245:19;12631:34;39285:14;;;12611:55;-1:-1;;;12686:12;;;12679:36;12734:12;;;28438:245;28690:416;28890:2;28904:47;;;12985:2;28875:18;;;39245:19;13021:34;39285:14;;;13001:55;13090:34;13076:12;;;13069:56;-1:-1;;;13145:12;;;13138:30;13187:12;;;28861:245;29113:416;29313:2;29327:47;;;13438:2;29298:18;;;39245:19;13474:34;39285:14;;;13454:55;13543:34;13529:12;;;13522:56;-1:-1;;;13598:12;;;13591:34;13644:12;;;29284:245;29536:416;29736:2;29750:47;;;13895:2;29721:18;;;39245:19;13931:34;39285:14;;;13911:55;14000:34;13986:12;;;13979:56;-1:-1;;;14055:12;;;14048:40;14107:12;;;29707:245;29959:416;30159:2;30173:47;;;14358:2;30144:18;;;39245:19;14394:34;39285:14;;;14374:55;14463:34;14449:12;;;14442:56;-1:-1;;;14518:12;;;14511:33;14563:12;;;30130:245;30382:416;30582:2;30596:47;;;14814:2;30567:18;;;39245:19;14850:34;39285:14;;;14830:55;14919:34;14905:12;;;14898:56;-1:-1;;;14974:12;;;14967:31;15017:12;;;30553:245;30805:416;31005:2;31019:47;;;15268:2;30990:18;;;39245:19;15304:34;39285:14;;;15284:55;-1:-1;;;15359:12;;;15352:29;15400:12;;;30976:245;31228:416;31428:2;31442:47;;;15651:2;31413:18;;;39245:19;15687:34;39285:14;;;15667:55;15756:34;15742:12;;;15735:56;15825:32;15811:12;;;15804:54;15877:12;;;31399:245;31651:416;31851:2;31865:47;;;16944:2;31836:18;;;39245:19;16980:34;39285:14;;;16960:55;17049:34;17035:12;;;17028:56;-1:-1;;;17104:12;;;17097:30;17146:12;;;31822:245;32074:416;32274:2;32288:47;;;17397:2;32259:18;;;39245:19;17433:34;39285:14;;;17413:55;17502:34;17488:12;;;17481:56;-1:-1;;;17557:12;;;17550:30;17599:12;;;32245:245;32497:416;32697:2;32711:47;;;17850:2;32682:18;;;39245:19;17886:34;39285:14;;;17866:55;17955:34;17941:12;;;17934:56;-1:-1;;;18010:12;;;18003:31;18053:12;;;32668:245;32920:416;33120:2;33134:47;;;18304:2;33105:18;;;39245:19;18340:34;39285:14;;;18320:55;18409:34;18395:12;;;18388:56;18478:32;18464:12;;;18457:54;18530:12;;;33091:245;33343:416;33543:2;33557:47;;;18781:2;33528:18;;;39245:19;18817:34;39285:14;;;18797:55;-1:-1;;;18872:12;;;18865:27;18911:12;;;33514:245;33766:416;33966:2;33980:47;;;19162:2;33951:18;;;39245:19;19198:34;39285:14;;;19178:55;19267:34;19253:12;;;19246:56;-1:-1;;;19322:12;;;19315:45;19379:12;;;33937:245;34189:416;34389:2;34403:47;;;19630:2;34374:18;;;39245:19;19666:32;39285:14;;;19646:53;19718:12;;;34360:245;34612:416;34812:2;34826:47;;;19969:2;34797:18;;;39245:19;20005:34;39285:14;;;19985:55;20074:26;20060:12;;;20053:48;20120:12;;;34783:245;35035:416;35235:2;35249:47;;;20371:2;35220:18;;;39245:19;20407:25;39285:14;;;20387:46;20452:12;;;35206:245;35458:358;35653:2;35638:18;;35667:139;35642:9;35779:6;35667:139;;35823:366;36022:2;36007:18;;36036:143;36011:9;36152:6;36036:143;;36196:330;23494:23;;-1:-1;;;;;41183:70;24301:37;;36377:2;36362:18;;36348:178;36533:222;-1:-1;;;;;40931:50;;;;24071:37;;36660:2;36645:18;;36631:124;41944:117;-1:-1;;;;;42031:5;40815:42;42006:5;42003:35;41993:2;;42052:1;;42042:12;41993:2;41987:74;
Swarm Source
ipfs://a846e57523fbe71d04a80087a86961afe3195a7659fb3586d4c1945e4b0904c1
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.