Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RiskManager
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../BaseLogic.sol";
import "../IRiskManager.sol";
import "../vendor/TickMath.sol";
import "../vendor/FullMath.sol";
interface IUniswapV3Factory {
function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
}
interface IUniswapV3Pool {
function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked);
function liquidity() external view returns (uint128);
function observe(uint32[] calldata secondsAgos) external view returns (int56[] memory tickCumulatives, uint160[] memory liquidityCumulatives);
function observations(uint256 index) external view returns (uint32 blockTimestamp, int56 tickCumulative, uint160 liquidityCumulative, bool initialized);
function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
}
contract RiskManager is IRiskManager, BaseLogic {
// Construction
address immutable referenceAsset; // Token must have 18 decimals
address immutable uniswapFactory;
bytes32 immutable uniswapPoolInitCodeHash;
struct RiskManagerSettings {
address referenceAsset;
address uniswapFactory;
bytes32 uniswapPoolInitCodeHash;
}
constructor(bytes32 moduleGitCommit_, RiskManagerSettings memory settings) BaseLogic(MODULEID__RISK_MANAGER, moduleGitCommit_) {
referenceAsset = settings.referenceAsset;
uniswapFactory = settings.uniswapFactory;
uniswapPoolInitCodeHash = settings.uniswapPoolInitCodeHash;
}
// Default market parameters
function getNewMarketParameters(address underlying) external override returns (NewMarketParameters memory p) {
p.config.borrowIsolated = true;
p.config.collateralFactor = uint32(0);
p.config.borrowFactor = type(uint32).max;
p.config.twapWindow = type(uint24).max;
if (underlying == referenceAsset) {
// 1:1 peg
p.pricingType = PRICINGTYPE__PEGGED;
p.pricingParameters = uint32(0);
} else if (pTokenLookup[underlying] != address(0)) {
p.pricingType = PRICINGTYPE__FORWARDED;
p.pricingParameters = uint32(0);
p.config.collateralFactor = underlyingLookup[pTokenLookup[underlying]].collateralFactor;
} else {
// Uniswap3 TWAP
// The uniswap pool (fee-level) with the highest in-range liquidity is used by default.
// This is a heuristic and can easily be manipulated by the activator, so users should
// verify the selection is suitable before using the pool. Otherwise, governance will
// need to change the pricing config for the market.
address pool = address(0);
uint24 fee = 0;
{
uint24[4] memory fees = [uint24(3000), 10000, 500, 100];
uint128 bestLiquidity = 0;
for (uint i = 0; i < fees.length; ++i) {
address candidatePool = IUniswapV3Factory(uniswapFactory).getPool(underlying, referenceAsset, fees[i]);
if (candidatePool == address(0)) continue;
uint128 liquidity = IUniswapV3Pool(candidatePool).liquidity();
if (pool == address(0) || liquidity > bestLiquidity) {
pool = candidatePool;
fee = fees[i];
bestLiquidity = liquidity;
}
}
}
require(pool != address(0), "e/no-uniswap-pool-avail");
require(computeUniswapPoolAddress(underlying, fee) == pool, "e/bad-uniswap-pool-addr");
p.pricingType = PRICINGTYPE__UNISWAP3_TWAP;
p.pricingParameters = uint32(fee);
try IUniswapV3Pool(pool).increaseObservationCardinalityNext(MIN_UNISWAP3_OBSERVATION_CARDINALITY) {
// Success
} catch Error(string memory err) {
if (keccak256(bytes(err)) == keccak256("LOK")) revert("e/risk/uniswap-pool-not-inited");
revert(string(abi.encodePacked("e/risk/uniswap/", err)));
} catch (bytes memory returnData) {
revertBytes(returnData);
}
}
}
// Pricing
function computeUniswapPoolAddress(address underlying, uint24 fee) private view returns (address) {
address tokenA = underlying;
address tokenB = referenceAsset;
if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
return address(uint160(uint256(keccak256(abi.encodePacked(
hex'ff',
uniswapFactory,
keccak256(abi.encode(tokenA, tokenB, fee)),
uniswapPoolInitCodeHash
)))));
}
function decodeSqrtPriceX96(AssetCache memory assetCache, uint sqrtPriceX96) private view returns (uint price) {
if (uint160(assetCache.underlying) < uint160(referenceAsset)) {
price = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, uint(2**(96*2)) / 1e18) / assetCache.underlyingDecimalsScaler;
} else {
price = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, uint(2**(96*2)) / (1e18 * assetCache.underlyingDecimalsScaler));
if (price == 0) return 1e36;
price = 1e36 / price;
}
if (price > 1e36) price = 1e36;
else if (price == 0) price = 1;
}
function callUniswapObserve(AssetCache memory assetCache, address pool, uint ago) private view returns (uint, uint) {
uint32[] memory secondsAgos = new uint32[](2);
secondsAgos[0] = uint32(ago);
secondsAgos[1] = 0;
(bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IUniswapV3Pool.observe.selector, secondsAgos));
if (!success) {
if (keccak256(data) != keccak256(abi.encodeWithSignature("Error(string)", "OLD"))) revertBytes(data);
// The oldest available observation in the ring buffer is the index following the current (accounting for wrapping),
// since this is the one that will be overwritten next.
(,, uint16 index, uint16 cardinality,,,) = IUniswapV3Pool(pool).slot0();
(uint32 oldestAvailableAge,,,bool initialized) = IUniswapV3Pool(pool).observations((index + 1) % cardinality);
// If the following observation in a ring buffer of our current cardinality is uninitialized, then all the
// observations at higher indices are also uninitialized, so we wrap back to index 0, which we now know
// to be the oldest available observation.
if (!initialized) (oldestAvailableAge,,,) = IUniswapV3Pool(pool).observations(0);
// Call observe() again to get the oldest available
ago = block.timestamp - oldestAvailableAge;
secondsAgos[0] = uint32(ago);
(success, data) = pool.staticcall(abi.encodeWithSelector(IUniswapV3Pool.observe.selector, secondsAgos));
if (!success) revertBytes(data);
}
// If uniswap pool doesn't exist, then data will be empty and this decode will throw:
int56[] memory tickCumulatives = abi.decode(data, (int56[])); // don't bother decoding the liquidityCumulatives array
int24 tick = int24((tickCumulatives[1] - tickCumulatives[0]) / int56(int(ago)));
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(tick);
return (decodeSqrtPriceX96(assetCache, sqrtPriceX96), ago);
}
function resolvePricingConfig(AssetCache memory assetCache, AssetConfig memory config) private view returns (address underlying, uint16 pricingType, uint32 pricingParameters, uint24 twapWindow) {
if (assetCache.pricingType == PRICINGTYPE__FORWARDED) {
underlying = pTokenLookup[assetCache.underlying];
AssetConfig memory newConfig = resolveAssetConfig(underlying);
twapWindow = newConfig.twapWindow;
AssetStorage storage newAssetStorage = eTokenLookup[newConfig.eTokenAddress];
pricingType = newAssetStorage.pricingType;
pricingParameters = newAssetStorage.pricingParameters;
require(pricingType != PRICINGTYPE__FORWARDED, "e/nested-price-forwarding");
} else {
underlying = assetCache.underlying;
pricingType = assetCache.pricingType;
pricingParameters = assetCache.pricingParameters;
twapWindow = config.twapWindow;
}
}
function getPriceInternal(AssetCache memory assetCache, AssetConfig memory config) public view FREEMEM returns (uint twap, uint twapPeriod) {
(address underlying, uint16 pricingType, uint32 pricingParameters, uint24 twapWindow) = resolvePricingConfig(assetCache, config);
if (pricingType == PRICINGTYPE__PEGGED) {
twap = 1e18;
twapPeriod = twapWindow;
} else if (pricingType == PRICINGTYPE__UNISWAP3_TWAP) {
address pool = computeUniswapPoolAddress(underlying, uint24(pricingParameters));
(twap, twapPeriod) = callUniswapObserve(assetCache, pool, twapWindow);
} else {
revert("e/unknown-pricing-type");
}
}
function getPrice(address underlying) external view override returns (uint twap, uint twapPeriod) {
AssetConfig memory config = resolveAssetConfig(underlying);
AssetStorage storage assetStorage = eTokenLookup[config.eTokenAddress];
AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage);
(twap, twapPeriod) = getPriceInternal(assetCache, config);
}
// This function is only meant to be called from a view so it doesn't need to be optimised.
// The Euler protocol itself doesn't ever use currPrice as returned by this function.
function getPriceFull(address underlying) external view override returns (uint twap, uint twapPeriod, uint currPrice) {
AssetConfig memory config = resolveAssetConfig(underlying);
AssetStorage storage assetStorage = eTokenLookup[config.eTokenAddress];
AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage);
(twap, twapPeriod) = getPriceInternal(assetCache, config);
(address newUnderlying, uint16 pricingType, uint32 pricingParameters,) = resolvePricingConfig(assetCache, config);
if (pricingType == PRICINGTYPE__PEGGED) {
currPrice = 1e18;
} else if (pricingType == PRICINGTYPE__UNISWAP3_TWAP || pricingType == PRICINGTYPE__FORWARDED) {
AssetCache memory newAssetCache = loadAssetCacheRO(newUnderlying, assetStorage);
address pool = computeUniswapPoolAddress(newUnderlying, uint24(pricingParameters));
(uint160 sqrtPriceX96,,,,,,) = IUniswapV3Pool(pool).slot0();
currPrice = decodeSqrtPriceX96(newAssetCache, sqrtPriceX96);
} else {
revert("e/unknown-pricing-type");
}
}
// Liquidity
function computeLiquidityRaw(address account, address[] memory underlyings) private view returns (LiquidityStatus memory status) {
status.collateralValue = 0;
status.liabilityValue = 0;
status.numBorrows = 0;
status.borrowIsolated = false;
AssetConfig memory config;
AssetStorage storage assetStorage;
AssetCache memory assetCache;
for (uint i = 0; i < underlyings.length; ++i) {
address underlying = underlyings[i];
bool assetCacheAndPriceInited = false;
uint price;
config = resolveAssetConfig(underlying);
assetStorage = eTokenLookup[config.eTokenAddress];
uint balance = assetStorage.users[account].balance;
uint owed = assetStorage.users[account].owed;
if (balance != 0 && config.collateralFactor != 0) {
initAssetCache(underlying, assetStorage, assetCache);
(price,) = getPriceInternal(assetCache, config);
assetCacheAndPriceInited = true;
uint assetCollateral = balanceToUnderlyingAmount(assetCache, balance);
assetCollateral = assetCollateral * price / 1e18;
assetCollateral = assetCollateral * config.collateralFactor / CONFIG_FACTOR_SCALE;
status.collateralValue += assetCollateral;
}
if (owed != 0) {
if (!assetCacheAndPriceInited) {
initAssetCache(underlying, assetStorage, assetCache);
(price,) = getPriceInternal(assetCache, config);
assetCacheAndPriceInited = true;
}
status.numBorrows++;
if (config.borrowIsolated) status.borrowIsolated = true;
uint assetLiability = getCurrentOwed(assetStorage, assetCache, account);
assetLiability = assetLiability * price / 1e18;
assetLiability = config.borrowFactor != 0 ? assetLiability * CONFIG_FACTOR_SCALE / config.borrowFactor : MAX_SANE_DEBT_AMOUNT;
status.liabilityValue += assetLiability;
}
}
}
function computeLiquidity(address account) public view override returns (LiquidityStatus memory) {
return computeLiquidityRaw(account, getEnteredMarketsArray(account));
}
function computeAssetLiquidities(address account) external view override returns (AssetLiquidity[] memory) {
address[] memory underlyings = getEnteredMarketsArray(account);
AssetLiquidity[] memory output = new AssetLiquidity[](underlyings.length);
address[] memory singleUnderlying = new address[](1);
for (uint i = 0; i < underlyings.length; ++i) {
output[i].underlying = singleUnderlying[0] = underlyings[i];
output[i].status = computeLiquidityRaw(account, singleUnderlying);
}
return output;
}
function requireLiquidity(address account) external view override {
LiquidityStatus memory status = computeLiquidity(account);
require(!status.borrowIsolated || status.numBorrows == 1, "e/borrow-isolation-violation");
require(status.collateralValue >= status.liabilityValue, "e/collateral-violation");
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import "./BaseModule.sol";
import "./BaseIRM.sol";
import "./Interfaces.sol";
import "./Utils.sol";
import "./vendor/RPow.sol";
import "./IRiskManager.sol";
abstract contract BaseLogic is BaseModule {
constructor(uint moduleId_, bytes32 moduleGitCommit_) BaseModule(moduleId_, moduleGitCommit_) {}
// Account auth
function getSubAccount(address primary, uint subAccountId) internal pure returns (address) {
require(subAccountId < 256, "e/sub-account-id-too-big");
return address(uint160(primary) ^ uint160(subAccountId));
}
function isSubAccountOf(address primary, address subAccount) internal pure returns (bool) {
return (uint160(primary) | 0xFF) == (uint160(subAccount) | 0xFF);
}
// Entered markets array
function getEnteredMarketsArray(address account) internal view returns (address[] memory) {
uint32 numMarketsEntered = accountLookup[account].numMarketsEntered;
address firstMarketEntered = accountLookup[account].firstMarketEntered;
address[] memory output = new address[](numMarketsEntered);
if (numMarketsEntered == 0) return output;
address[MAX_POSSIBLE_ENTERED_MARKETS] storage markets = marketsEntered[account];
output[0] = firstMarketEntered;
for (uint i = 1; i < numMarketsEntered; ++i) {
output[i] = markets[i];
}
return output;
}
function isEnteredInMarket(address account, address underlying) internal view returns (bool) {
uint32 numMarketsEntered = accountLookup[account].numMarketsEntered;
address firstMarketEntered = accountLookup[account].firstMarketEntered;
if (numMarketsEntered == 0) return false;
if (firstMarketEntered == underlying) return true;
address[MAX_POSSIBLE_ENTERED_MARKETS] storage markets = marketsEntered[account];
for (uint i = 1; i < numMarketsEntered; ++i) {
if (markets[i] == underlying) return true;
}
return false;
}
function doEnterMarket(address account, address underlying) internal {
AccountStorage storage accountStorage = accountLookup[account];
uint32 numMarketsEntered = accountStorage.numMarketsEntered;
address[MAX_POSSIBLE_ENTERED_MARKETS] storage markets = marketsEntered[account];
if (numMarketsEntered != 0) {
if (accountStorage.firstMarketEntered == underlying) return; // already entered
for (uint i = 1; i < numMarketsEntered; i++) {
if (markets[i] == underlying) return; // already entered
}
}
require(numMarketsEntered < MAX_ENTERED_MARKETS, "e/too-many-entered-markets");
if (numMarketsEntered == 0) accountStorage.firstMarketEntered = underlying;
else markets[numMarketsEntered] = underlying;
accountStorage.numMarketsEntered = numMarketsEntered + 1;
emit EnterMarket(underlying, account);
}
// Liquidity check must be done by caller after calling this
function doExitMarket(address account, address underlying) internal {
AccountStorage storage accountStorage = accountLookup[account];
uint32 numMarketsEntered = accountStorage.numMarketsEntered;
address[MAX_POSSIBLE_ENTERED_MARKETS] storage markets = marketsEntered[account];
uint searchIndex = type(uint).max;
if (numMarketsEntered == 0) return; // already exited
if (accountStorage.firstMarketEntered == underlying) {
searchIndex = 0;
} else {
for (uint i = 1; i < numMarketsEntered; i++) {
if (markets[i] == underlying) {
searchIndex = i;
break;
}
}
if (searchIndex == type(uint).max) return; // already exited
}
uint lastMarketIndex = numMarketsEntered - 1;
if (searchIndex != lastMarketIndex) {
if (searchIndex == 0) accountStorage.firstMarketEntered = markets[lastMarketIndex];
else markets[searchIndex] = markets[lastMarketIndex];
}
accountStorage.numMarketsEntered = uint32(lastMarketIndex);
if (lastMarketIndex != 0) markets[lastMarketIndex] = address(0); // zero out for storage refund
emit ExitMarket(underlying, account);
}
// AssetConfig
function resolveAssetConfig(address underlying) internal view returns (AssetConfig memory) {
AssetConfig memory config = underlyingLookup[underlying];
require(config.eTokenAddress != address(0), "e/market-not-activated");
if (config.borrowFactor == type(uint32).max) config.borrowFactor = DEFAULT_BORROW_FACTOR;
if (config.twapWindow == type(uint24).max) config.twapWindow = DEFAULT_TWAP_WINDOW_SECONDS;
return config;
}
// AssetCache
struct AssetCache {
address underlying;
uint112 totalBalances;
uint144 totalBorrows;
uint96 reserveBalance;
uint interestAccumulator;
uint40 lastInterestAccumulatorUpdate;
uint8 underlyingDecimals;
uint32 interestRateModel;
int96 interestRate;
uint32 reserveFee;
uint16 pricingType;
uint32 pricingParameters;
uint poolSize; // result of calling balanceOf on underlying (in external units)
uint underlyingDecimalsScaler;
uint maxExternalAmount;
}
function initAssetCache(address underlying, AssetStorage storage assetStorage, AssetCache memory assetCache) internal view returns (bool dirty) {
dirty = false;
assetCache.underlying = underlying;
// Storage loads
assetCache.lastInterestAccumulatorUpdate = assetStorage.lastInterestAccumulatorUpdate;
uint8 underlyingDecimals = assetCache.underlyingDecimals = assetStorage.underlyingDecimals;
assetCache.interestRateModel = assetStorage.interestRateModel;
assetCache.interestRate = assetStorage.interestRate;
assetCache.reserveFee = assetStorage.reserveFee;
assetCache.pricingType = assetStorage.pricingType;
assetCache.pricingParameters = assetStorage.pricingParameters;
assetCache.reserveBalance = assetStorage.reserveBalance;
assetCache.totalBalances = assetStorage.totalBalances;
assetCache.totalBorrows = assetStorage.totalBorrows;
assetCache.interestAccumulator = assetStorage.interestAccumulator;
// Derived state
unchecked {
assetCache.underlyingDecimalsScaler = 10**(18 - underlyingDecimals);
assetCache.maxExternalAmount = MAX_SANE_AMOUNT / assetCache.underlyingDecimalsScaler;
}
uint poolSize = callBalanceOf(assetCache, address(this));
if (poolSize <= assetCache.maxExternalAmount) {
unchecked { assetCache.poolSize = poolSize * assetCache.underlyingDecimalsScaler; }
} else {
assetCache.poolSize = 0;
}
// Update interest accumulator and reserves
if (block.timestamp != assetCache.lastInterestAccumulatorUpdate) {
dirty = true;
uint deltaT = block.timestamp - assetCache.lastInterestAccumulatorUpdate;
// Compute new values
uint newInterestAccumulator = (RPow.rpow(uint(int(assetCache.interestRate) + 1e27), deltaT, 1e27) * assetCache.interestAccumulator) / 1e27;
uint newTotalBorrows = assetCache.totalBorrows * newInterestAccumulator / assetCache.interestAccumulator;
uint newReserveBalance = assetCache.reserveBalance;
uint newTotalBalances = assetCache.totalBalances;
uint feeAmount = (newTotalBorrows - assetCache.totalBorrows)
* (assetCache.reserveFee == type(uint32).max ? DEFAULT_RESERVE_FEE : assetCache.reserveFee)
/ (RESERVE_FEE_SCALE * INTERNAL_DEBT_PRECISION);
if (feeAmount != 0) {
uint poolAssets = assetCache.poolSize + (newTotalBorrows / INTERNAL_DEBT_PRECISION);
newTotalBalances = poolAssets * newTotalBalances / (poolAssets - feeAmount);
newReserveBalance += newTotalBalances - assetCache.totalBalances;
}
// Store new values in assetCache, only if no overflows will occur
if (newTotalBalances <= MAX_SANE_AMOUNT && newTotalBorrows <= MAX_SANE_DEBT_AMOUNT) {
assetCache.totalBorrows = encodeDebtAmount(newTotalBorrows);
assetCache.interestAccumulator = newInterestAccumulator;
assetCache.lastInterestAccumulatorUpdate = uint40(block.timestamp);
if (newTotalBalances != assetCache.totalBalances) {
assetCache.reserveBalance = encodeSmallAmount(newReserveBalance);
assetCache.totalBalances = encodeAmount(newTotalBalances);
}
}
}
}
function loadAssetCache(address underlying, AssetStorage storage assetStorage) internal returns (AssetCache memory assetCache) {
if (initAssetCache(underlying, assetStorage, assetCache)) {
assetStorage.lastInterestAccumulatorUpdate = assetCache.lastInterestAccumulatorUpdate;
assetStorage.underlying = assetCache.underlying; // avoid an SLOAD of this slot
assetStorage.reserveBalance = assetCache.reserveBalance;
assetStorage.totalBalances = assetCache.totalBalances;
assetStorage.totalBorrows = assetCache.totalBorrows;
assetStorage.interestAccumulator = assetCache.interestAccumulator;
}
}
function loadAssetCacheRO(address underlying, AssetStorage storage assetStorage) internal view returns (AssetCache memory assetCache) {
initAssetCache(underlying, assetStorage, assetCache);
}
// Utils
function decodeExternalAmount(AssetCache memory assetCache, uint externalAmount) internal pure returns (uint scaledAmount) {
require(externalAmount <= assetCache.maxExternalAmount, "e/amount-too-large");
unchecked { scaledAmount = externalAmount * assetCache.underlyingDecimalsScaler; }
}
function encodeAmount(uint amount) internal pure returns (uint112) {
require(amount <= MAX_SANE_AMOUNT, "e/amount-too-large-to-encode");
return uint112(amount);
}
function encodeSmallAmount(uint amount) internal pure returns (uint96) {
require(amount <= MAX_SANE_SMALL_AMOUNT, "e/small-amount-too-large-to-encode");
return uint96(amount);
}
function encodeDebtAmount(uint amount) internal pure returns (uint144) {
require(amount <= MAX_SANE_DEBT_AMOUNT, "e/debt-amount-too-large-to-encode");
return uint144(amount);
}
function computeExchangeRate(AssetCache memory assetCache) private pure returns (uint) {
if (assetCache.totalBalances == 0) return 1e18;
return (assetCache.poolSize + (assetCache.totalBorrows / INTERNAL_DEBT_PRECISION)) * 1e18 / assetCache.totalBalances;
}
function underlyingAmountToBalance(AssetCache memory assetCache, uint amount) internal pure returns (uint) {
uint exchangeRate = computeExchangeRate(assetCache);
return amount * 1e18 / exchangeRate;
}
function underlyingAmountToBalanceRoundUp(AssetCache memory assetCache, uint amount) internal pure returns (uint) {
uint exchangeRate = computeExchangeRate(assetCache);
return (amount * 1e18 + (exchangeRate - 1)) / exchangeRate;
}
function balanceToUnderlyingAmount(AssetCache memory assetCache, uint amount) internal pure returns (uint) {
uint exchangeRate = computeExchangeRate(assetCache);
return amount * exchangeRate / 1e18;
}
function callBalanceOf(AssetCache memory assetCache, address account) internal view FREEMEM returns (uint) {
// We set a gas limit so that a malicious token can't eat up all gas and cause a liquidity check to fail.
(bool success, bytes memory data) = assetCache.underlying.staticcall{gas: 20000}(abi.encodeWithSelector(IERC20.balanceOf.selector, account));
// If token's balanceOf() call fails for any reason, return 0. This prevents malicious tokens from causing liquidity checks to fail.
// If the contract doesn't exist (maybe because selfdestructed), then data.length will be 0 and we will return 0.
// Data length > 32 is allowed because some legitimate tokens append extra data that can be safely ignored.
if (!success || data.length < 32) return 0;
return abi.decode(data, (uint256));
}
function updateInterestRate(AssetStorage storage assetStorage, AssetCache memory assetCache) internal {
uint32 utilisation;
{
uint totalBorrows = assetCache.totalBorrows / INTERNAL_DEBT_PRECISION;
uint poolAssets = assetCache.poolSize + totalBorrows;
if (poolAssets == 0) utilisation = 0; // empty pool arbitrarily given utilisation of 0
else utilisation = uint32(totalBorrows * (uint(type(uint32).max) * 1e18) / poolAssets / 1e18);
}
bytes memory result = callInternalModule(assetCache.interestRateModel,
abi.encodeWithSelector(BaseIRM.computeInterestRate.selector, assetCache.underlying, utilisation));
(int96 newInterestRate) = abi.decode(result, (int96));
assetStorage.interestRate = assetCache.interestRate = newInterestRate;
}
function logAssetStatus(AssetCache memory a) internal {
emit AssetStatus(a.underlying, a.totalBalances, a.totalBorrows / INTERNAL_DEBT_PRECISION, a.reserveBalance, a.poolSize, a.interestAccumulator, a.interestRate, block.timestamp);
}
// Balances
function increaseBalance(AssetStorage storage assetStorage, AssetCache memory assetCache, address eTokenAddress, address account, uint amount) internal {
assetStorage.users[account].balance = encodeAmount(assetStorage.users[account].balance + amount);
assetStorage.totalBalances = assetCache.totalBalances = encodeAmount(uint(assetCache.totalBalances) + amount);
updateInterestRate(assetStorage, assetCache);
emit Deposit(assetCache.underlying, account, amount);
emitViaProxy_Transfer(eTokenAddress, address(0), account, amount);
}
function decreaseBalance(AssetStorage storage assetStorage, AssetCache memory assetCache, address eTokenAddress, address account, uint amount) internal {
uint origBalance = assetStorage.users[account].balance;
require(origBalance >= amount, "e/insufficient-balance");
assetStorage.users[account].balance = encodeAmount(origBalance - amount);
assetStorage.totalBalances = assetCache.totalBalances = encodeAmount(assetCache.totalBalances - amount);
updateInterestRate(assetStorage, assetCache);
emit Withdraw(assetCache.underlying, account, amount);
emitViaProxy_Transfer(eTokenAddress, account, address(0), amount);
}
function transferBalance(AssetStorage storage assetStorage, AssetCache memory assetCache, address eTokenAddress, address from, address to, uint amount) internal {
uint origFromBalance = assetStorage.users[from].balance;
require(origFromBalance >= amount, "e/insufficient-balance");
uint newFromBalance;
unchecked { newFromBalance = origFromBalance - amount; }
assetStorage.users[from].balance = encodeAmount(newFromBalance);
assetStorage.users[to].balance = encodeAmount(assetStorage.users[to].balance + amount);
emit Withdraw(assetCache.underlying, from, amount);
emit Deposit(assetCache.underlying, to, amount);
emitViaProxy_Transfer(eTokenAddress, from, to, amount);
}
function withdrawAmounts(AssetStorage storage assetStorage, AssetCache memory assetCache, address account, uint amount) internal view returns (uint, uint) {
uint amountInternal;
if (amount == type(uint).max) {
amountInternal = assetStorage.users[account].balance;
amount = balanceToUnderlyingAmount(assetCache, amountInternal);
} else {
amount = decodeExternalAmount(assetCache, amount);
amountInternal = underlyingAmountToBalanceRoundUp(assetCache, amount);
}
return (amount, amountInternal);
}
// Borrows
// Returns internal precision
function getCurrentOwedExact(AssetStorage storage assetStorage, AssetCache memory assetCache, address account, uint owed) internal view returns (uint) {
// Don't bother loading the user's accumulator
if (owed == 0) return 0;
// Can't divide by 0 here: If owed is non-zero, we must've initialised the user's interestAccumulator
return owed * assetCache.interestAccumulator / assetStorage.users[account].interestAccumulator;
}
// When non-zero, we round *up* to the smallest external unit so that outstanding dust in a loan can be repaid.
// unchecked is OK here since owed is always loaded from storage, so we know it fits into a uint144 (pre-interest accural)
// Takes and returns 27 decimals precision.
function roundUpOwed(AssetCache memory assetCache, uint owed) private pure returns (uint) {
if (owed == 0) return 0;
unchecked {
uint scale = INTERNAL_DEBT_PRECISION * assetCache.underlyingDecimalsScaler;
return (owed + scale - 1) / scale * scale;
}
}
// Returns 18-decimals precision (debt amount is rounded up)
function getCurrentOwed(AssetStorage storage assetStorage, AssetCache memory assetCache, address account) internal view returns (uint) {
return roundUpOwed(assetCache, getCurrentOwedExact(assetStorage, assetCache, account, assetStorage.users[account].owed)) / INTERNAL_DEBT_PRECISION;
}
function updateUserBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address account) private returns (uint newOwedExact, uint prevOwedExact) {
prevOwedExact = assetStorage.users[account].owed;
newOwedExact = getCurrentOwedExact(assetStorage, assetCache, account, prevOwedExact);
assetStorage.users[account].owed = encodeDebtAmount(newOwedExact);
assetStorage.users[account].interestAccumulator = assetCache.interestAccumulator;
}
function logBorrowChange(AssetCache memory assetCache, address dTokenAddress, address account, uint prevOwed, uint owed) private {
prevOwed = roundUpOwed(assetCache, prevOwed) / INTERNAL_DEBT_PRECISION;
owed = roundUpOwed(assetCache, owed) / INTERNAL_DEBT_PRECISION;
if (owed > prevOwed) {
uint change = owed - prevOwed;
emit Borrow(assetCache.underlying, account, change);
emitViaProxy_Transfer(dTokenAddress, address(0), account, change);
} else if (prevOwed > owed) {
uint change = prevOwed - owed;
emit Repay(assetCache.underlying, account, change);
emitViaProxy_Transfer(dTokenAddress, account, address(0), change);
}
}
function increaseBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address dTokenAddress, address account, uint amount) internal {
amount *= INTERNAL_DEBT_PRECISION;
require(assetCache.pricingType != PRICINGTYPE__FORWARDED || pTokenLookup[assetCache.underlying] == address(0), "e/borrow-not-supported");
(uint owed, uint prevOwed) = updateUserBorrow(assetStorage, assetCache, account);
if (owed == 0) doEnterMarket(account, assetCache.underlying);
owed += amount;
assetStorage.users[account].owed = encodeDebtAmount(owed);
assetStorage.totalBorrows = assetCache.totalBorrows = encodeDebtAmount(assetCache.totalBorrows + amount);
updateInterestRate(assetStorage, assetCache);
logBorrowChange(assetCache, dTokenAddress, account, prevOwed, owed);
}
function decreaseBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address dTokenAddress, address account, uint origAmount) internal {
uint amount = origAmount * INTERNAL_DEBT_PRECISION;
(uint owed, uint prevOwed) = updateUserBorrow(assetStorage, assetCache, account);
uint owedRoundedUp = roundUpOwed(assetCache, owed);
require(amount <= owedRoundedUp, "e/repay-too-much");
uint owedRemaining;
unchecked { owedRemaining = owedRoundedUp - amount; }
if (owed > assetCache.totalBorrows) owed = assetCache.totalBorrows;
assetStorage.users[account].owed = encodeDebtAmount(owedRemaining);
assetStorage.totalBorrows = assetCache.totalBorrows = encodeDebtAmount(assetCache.totalBorrows - owed + owedRemaining);
updateInterestRate(assetStorage, assetCache);
logBorrowChange(assetCache, dTokenAddress, account, prevOwed, owedRemaining);
}
function transferBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address dTokenAddress, address from, address to, uint origAmount) internal {
uint amount = origAmount * INTERNAL_DEBT_PRECISION;
(uint fromOwed, uint fromOwedPrev) = updateUserBorrow(assetStorage, assetCache, from);
(uint toOwed, uint toOwedPrev) = updateUserBorrow(assetStorage, assetCache, to);
if (toOwed == 0) doEnterMarket(to, assetCache.underlying);
// If amount was rounded up, transfer exact amount owed
if (amount > fromOwed && amount - fromOwed < INTERNAL_DEBT_PRECISION * assetCache.underlyingDecimalsScaler) amount = fromOwed;
require(fromOwed >= amount, "e/insufficient-balance");
unchecked { fromOwed -= amount; }
// Transfer any residual dust
if (fromOwed < INTERNAL_DEBT_PRECISION) {
amount += fromOwed;
fromOwed = 0;
}
toOwed += amount;
assetStorage.users[from].owed = encodeDebtAmount(fromOwed);
assetStorage.users[to].owed = encodeDebtAmount(toOwed);
logBorrowChange(assetCache, dTokenAddress, from, fromOwedPrev, fromOwed);
logBorrowChange(assetCache, dTokenAddress, to, toOwedPrev, toOwed);
}
// Reserves
function increaseReserves(AssetStorage storage assetStorage, AssetCache memory assetCache, uint amount) internal {
assetStorage.reserveBalance = assetCache.reserveBalance = encodeSmallAmount(assetCache.reserveBalance + amount);
assetStorage.totalBalances = assetCache.totalBalances = encodeAmount(assetCache.totalBalances + amount);
}
// Token asset transfers
// amounts are in underlying units
function pullTokens(AssetCache memory assetCache, address from, uint amount) internal returns (uint amountTransferred) {
uint poolSizeBefore = assetCache.poolSize;
Utils.safeTransferFrom(assetCache.underlying, from, address(this), amount / assetCache.underlyingDecimalsScaler);
uint poolSizeAfter = assetCache.poolSize = decodeExternalAmount(assetCache, callBalanceOf(assetCache, address(this)));
require(poolSizeAfter >= poolSizeBefore, "e/negative-transfer-amount");
unchecked { amountTransferred = poolSizeAfter - poolSizeBefore; }
}
function pushTokens(AssetCache memory assetCache, address to, uint amount) internal returns (uint amountTransferred) {
uint poolSizeBefore = assetCache.poolSize;
Utils.safeTransfer(assetCache.underlying, to, amount / assetCache.underlyingDecimalsScaler);
uint poolSizeAfter = assetCache.poolSize = decodeExternalAmount(assetCache, callBalanceOf(assetCache, address(this)));
require(poolSizeBefore >= poolSizeAfter, "e/negative-transfer-amount");
unchecked { amountTransferred = poolSizeBefore - poolSizeAfter; }
}
// Liquidity
function getAssetPrice(address asset) internal returns (uint) {
bytes memory result = callInternalModule(MODULEID__RISK_MANAGER, abi.encodeWithSelector(IRiskManager.getPrice.selector, asset));
return abi.decode(result, (uint));
}
function getAccountLiquidity(address account) internal returns (uint collateralValue, uint liabilityValue) {
bytes memory result = callInternalModule(MODULEID__RISK_MANAGER, abi.encodeWithSelector(IRiskManager.computeLiquidity.selector, account));
(IRiskManager.LiquidityStatus memory status) = abi.decode(result, (IRiskManager.LiquidityStatus));
collateralValue = status.collateralValue;
liabilityValue = status.liabilityValue;
}
function checkLiquidity(address account) internal {
uint8 status = accountLookup[account].deferLiquidityStatus;
if (status == DEFERLIQUIDITY__NONE) {
callInternalModule(MODULEID__RISK_MANAGER, abi.encodeWithSelector(IRiskManager.requireLiquidity.selector, account));
} else if (status == DEFERLIQUIDITY__CLEAN) {
accountLookup[account].deferLiquidityStatus = DEFERLIQUIDITY__DIRTY;
}
}
// Optional average liquidity tracking
function computeNewAverageLiquidity(address account, uint deltaT) private returns (uint) {
uint currDuration = deltaT >= AVERAGE_LIQUIDITY_PERIOD ? AVERAGE_LIQUIDITY_PERIOD : deltaT;
uint prevDuration = AVERAGE_LIQUIDITY_PERIOD - currDuration;
uint currAverageLiquidity;
{
(uint collateralValue, uint liabilityValue) = getAccountLiquidity(account);
currAverageLiquidity = collateralValue > liabilityValue ? collateralValue - liabilityValue : 0;
}
return (accountLookup[account].averageLiquidity * prevDuration / AVERAGE_LIQUIDITY_PERIOD) +
(currAverageLiquidity * currDuration / AVERAGE_LIQUIDITY_PERIOD);
}
function getUpdatedAverageLiquidity(address account) internal returns (uint) {
uint lastAverageLiquidityUpdate = accountLookup[account].lastAverageLiquidityUpdate;
if (lastAverageLiquidityUpdate == 0) return 0;
uint deltaT = block.timestamp - lastAverageLiquidityUpdate;
if (deltaT == 0) return accountLookup[account].averageLiquidity;
return computeNewAverageLiquidity(account, deltaT);
}
function getUpdatedAverageLiquidityWithDelegate(address account) internal returns (uint) {
address delegate = accountLookup[account].averageLiquidityDelegate;
return delegate != address(0) && accountLookup[delegate].averageLiquidityDelegate == account
? getUpdatedAverageLiquidity(delegate)
: getUpdatedAverageLiquidity(account);
}
function updateAverageLiquidity(address account) internal {
uint lastAverageLiquidityUpdate = accountLookup[account].lastAverageLiquidityUpdate;
if (lastAverageLiquidityUpdate == 0) return;
uint deltaT = block.timestamp - lastAverageLiquidityUpdate;
if (deltaT == 0) return;
accountLookup[account].lastAverageLiquidityUpdate = uint40(block.timestamp);
accountLookup[account].averageLiquidity = computeNewAverageLiquidity(account, deltaT);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import "./Storage.sol";
// This interface is used to avoid a circular dependency between BaseLogic and RiskManager
interface IRiskManager {
struct NewMarketParameters {
uint16 pricingType;
uint32 pricingParameters;
Storage.AssetConfig config;
}
struct LiquidityStatus {
uint collateralValue;
uint liabilityValue;
uint numBorrows;
bool borrowIsolated;
}
struct AssetLiquidity {
address underlying;
LiquidityStatus status;
}
function getNewMarketParameters(address underlying) external returns (NewMarketParameters memory);
function requireLiquidity(address account) external view;
function computeLiquidity(address account) external view returns (LiquidityStatus memory status);
function computeAssetLiquidities(address account) external view returns (AssetLiquidity[] memory assets);
function getPrice(address underlying) external view returns (uint twap, uint twapPeriod);
function getPriceFull(address underlying) external view returns (uint twap, uint twapPeriod, uint currPrice);
}// SPDX-License-Identifier: GPL-2.0-or-later
// From Uniswap3 Core
// Updated to Solidity 0.8 by Euler:
// * Cast MAX_TICK to int256 before casting to uint
// * Wrapped function bodies with "unchecked {}" so as to not add any extra gas costs
pragma solidity ^0.8.0;
/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
unchecked {
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
require(absTick <= uint256(int(MAX_TICK)), 'T');
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
if (tick > 0) ratio = type(uint256).max / ratio;
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
}
/// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
/// ever return.
/// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
/// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
unchecked {
// second inequality must be < because the price can never reach the price at the max tick
require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R');
uint256 ratio = uint256(sqrtPriceX96) << 32;
uint256 r = ratio;
uint256 msb = 0;
assembly {
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(5, gt(r, 0xFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(4, gt(r, 0xFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(3, gt(r, 0xFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(2, gt(r, 0xF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(1, gt(r, 0x3))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := gt(r, 0x1)
msb := or(msb, f)
}
if (msb >= 128) r = ratio >> (msb - 127);
else r = ratio << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
}
}
}// SPDX-License-Identifier: MIT
// From Uniswap3 Core
// Updated to Solidity 0.8 by Euler:
// * Rewrite unary negation of denominator, which is a uint
// * Wrapped function bodies with "unchecked {}" so as to not add any extra gas costs
pragma solidity ^0.8.0;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = denominator & (~denominator + 1);
// Divide denominator by power of two
assembly {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256
// Because the division is now exact we can divide by multiplying
// with the modular inverse of denominator. This will give us the
// correct result modulo 2**256. Since the precoditions guarantee
// that the outcome is less than 2**256, this is the final result.
// We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inv;
return result;
}
}
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
function mulDivRoundingUp(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) > 0) {
require(result < type(uint256).max);
result++;
}
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import "./Base.sol";
abstract contract BaseModule is Base {
// Construction
// public accessors common to all modules
uint immutable public moduleId;
bytes32 immutable public moduleGitCommit;
constructor(uint moduleId_, bytes32 moduleGitCommit_) {
moduleId = moduleId_;
moduleGitCommit = moduleGitCommit_;
}
// Accessing parameters
function unpackTrailingParamMsgSender() internal pure returns (address msgSender) {
assembly {
msgSender := shr(96, calldataload(sub(calldatasize(), 40)))
}
}
function unpackTrailingParams() internal pure returns (address msgSender, address proxyAddr) {
assembly {
msgSender := shr(96, calldataload(sub(calldatasize(), 40)))
proxyAddr := shr(96, calldataload(sub(calldatasize(), 20)))
}
}
// Emit logs via proxies
function emitViaProxy_Transfer(address proxyAddr, address from, address to, uint value) internal FREEMEM {
(bool success,) = proxyAddr.call(abi.encodePacked(
uint8(3),
keccak256(bytes('Transfer(address,address,uint256)')),
bytes32(uint(uint160(from))),
bytes32(uint(uint160(to))),
value
));
require(success, "e/log-proxy-fail");
}
function emitViaProxy_Approval(address proxyAddr, address owner, address spender, uint value) internal FREEMEM {
(bool success,) = proxyAddr.call(abi.encodePacked(
uint8(3),
keccak256(bytes('Approval(address,address,uint256)')),
bytes32(uint(uint160(owner))),
bytes32(uint(uint160(spender))),
value
));
require(success, "e/log-proxy-fail");
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import "./BaseModule.sol";
abstract contract BaseIRM is BaseModule {
constructor(uint moduleId_, bytes32 moduleGitCommit_) BaseModule(moduleId_, moduleGitCommit_) {}
int96 internal constant MAX_ALLOWED_INTEREST_RATE = int96(int(uint(5 * 1e27) / SECONDS_PER_YEAR)); // 500% APR
int96 internal constant MIN_ALLOWED_INTEREST_RATE = 0;
function computeInterestRateImpl(address, uint32) internal virtual returns (int96);
function computeInterestRate(address underlying, uint32 utilisation) external returns (int96) {
int96 rate = computeInterestRateImpl(underlying, utilisation);
if (rate > MAX_ALLOWED_INTEREST_RATE) rate = MAX_ALLOWED_INTEREST_RATE;
else if (rate < MIN_ALLOWED_INTEREST_RATE) rate = MIN_ALLOWED_INTEREST_RATE;
return rate;
}
function reset(address underlying, bytes calldata resetParams) external virtual {}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view 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);
}
interface IERC20Permit {
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
function nonces(address owner) external view returns (uint);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
interface IERC3156FlashBorrower {
function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes calldata data) external returns (bytes32);
}
interface IERC3156FlashLender {
function maxFlashLoan(address token) external view returns (uint256);
function flashFee(address token, uint256 amount) external view returns (uint256);
function flashLoan(IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import "./Interfaces.sol";
library Utils {
function safeTransferFrom(address token, address from, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), string(data));
}
function safeTransfer(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), string(data));
}
function safeApprove(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), string(data));
}
}// SPDX-License-Identifier: AGPL-3.0-or-later // From MakerDAO DSS // Copyright (C) 2018 Rain <[email protected]> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity ^0.8.0; library RPow { function rpow(uint x, uint n, uint base) internal pure returns (uint z) { assembly { switch x case 0 {switch n case 0 {z := base} default {z := 0}} default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, base) if mod(n,2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0,0) } z := div(zxRound, base) } } } } } }
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
//import "hardhat/console.sol"; // DEV_MODE
import "./Storage.sol";
import "./Events.sol";
import "./Proxy.sol";
abstract contract Base is Storage, Events {
// Modules
function _createProxy(uint proxyModuleId) internal returns (address) {
require(proxyModuleId != 0, "e/create-proxy/invalid-module");
require(proxyModuleId <= MAX_EXTERNAL_MODULEID, "e/create-proxy/internal-module");
// If we've already created a proxy for a single-proxy module, just return it:
if (proxyLookup[proxyModuleId] != address(0)) return proxyLookup[proxyModuleId];
// Otherwise create a proxy:
address proxyAddr = address(new Proxy());
if (proxyModuleId <= MAX_EXTERNAL_SINGLE_PROXY_MODULEID) proxyLookup[proxyModuleId] = proxyAddr;
trustedSenders[proxyAddr] = TrustedSenderInfo({ moduleId: uint32(proxyModuleId), moduleImpl: address(0) });
emit ProxyCreated(proxyAddr, proxyModuleId);
return proxyAddr;
}
function callInternalModule(uint moduleId, bytes memory input) internal returns (bytes memory) {
(bool success, bytes memory result) = moduleLookup[moduleId].delegatecall(input);
if (!success) revertBytes(result);
return result;
}
// Modifiers
modifier nonReentrant() {
require(reentrancyLock == REENTRANCYLOCK__UNLOCKED, "e/reentrancy");
reentrancyLock = REENTRANCYLOCK__LOCKED;
_;
reentrancyLock = REENTRANCYLOCK__UNLOCKED;
}
modifier reentrantOK() { // documentation only
_;
}
// WARNING: Must be very careful with this modifier. It resets the free memory pointer
// to the value it was when the function started. This saves gas if more memory will
// be allocated in the future. However, if the memory will be later referenced
// (for example because the function has returned a pointer to it) then you cannot
// use this modifier.
modifier FREEMEM() {
uint origFreeMemPtr;
assembly {
origFreeMemPtr := mload(0x40)
}
_;
/*
assembly { // DEV_MODE: overwrite the freed memory with garbage to detect bugs
let garbage := 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
for { let i := origFreeMemPtr } lt(i, mload(0x40)) { i := add(i, 32) } { mstore(i, garbage) }
}
*/
assembly {
mstore(0x40, origFreeMemPtr)
}
}
// Error handling
function revertBytes(bytes memory errMsg) internal pure {
if (errMsg.length > 0) {
assembly {
revert(add(32, errMsg), mload(errMsg))
}
}
revert("e/empty-error");
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import "./Constants.sol";
abstract contract Storage is Constants {
// Dispatcher and upgrades
uint reentrancyLock;
address upgradeAdmin;
address governorAdmin;
mapping(uint => address) moduleLookup; // moduleId => module implementation
mapping(uint => address) proxyLookup; // moduleId => proxy address (only for single-proxy modules)
struct TrustedSenderInfo {
uint32 moduleId; // 0 = un-trusted
address moduleImpl; // only non-zero for external single-proxy modules
}
mapping(address => TrustedSenderInfo) trustedSenders; // sender address => moduleId (0 = un-trusted)
// Account-level state
// Sub-accounts are considered distinct accounts
struct AccountStorage {
// Packed slot: 1 + 5 + 4 + 20 = 30
uint8 deferLiquidityStatus;
uint40 lastAverageLiquidityUpdate;
uint32 numMarketsEntered;
address firstMarketEntered;
uint averageLiquidity;
address averageLiquidityDelegate;
}
mapping(address => AccountStorage) accountLookup;
mapping(address => address[MAX_POSSIBLE_ENTERED_MARKETS]) marketsEntered;
// Markets and assets
struct AssetConfig {
// Packed slot: 20 + 1 + 4 + 4 + 3 = 32
address eTokenAddress;
bool borrowIsolated;
uint32 collateralFactor;
uint32 borrowFactor;
uint24 twapWindow;
}
struct UserAsset {
uint112 balance;
uint144 owed;
uint interestAccumulator;
}
struct AssetStorage {
// Packed slot: 5 + 1 + 4 + 12 + 4 + 2 + 4 = 32
uint40 lastInterestAccumulatorUpdate;
uint8 underlyingDecimals; // Not dynamic, but put here to live in same storage slot
uint32 interestRateModel;
int96 interestRate;
uint32 reserveFee;
uint16 pricingType;
uint32 pricingParameters;
address underlying;
uint96 reserveBalance;
address dTokenAddress;
uint112 totalBalances;
uint144 totalBorrows;
uint interestAccumulator;
mapping(address => UserAsset) users;
mapping(address => mapping(address => uint)) eTokenAllowance;
mapping(address => mapping(address => uint)) dTokenAllowance;
}
mapping(address => AssetConfig) internal underlyingLookup; // underlying => AssetConfig
mapping(address => AssetStorage) internal eTokenLookup; // EToken => AssetStorage
mapping(address => address) internal dTokenLookup; // DToken => EToken
mapping(address => address) internal pTokenLookup; // PToken => underlying
mapping(address => address) internal reversePTokenLookup; // underlying => PToken
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import "./Storage.sol";
abstract contract Events {
event Genesis();
event ProxyCreated(address indexed proxy, uint moduleId);
event MarketActivated(address indexed underlying, address indexed eToken, address indexed dToken);
event PTokenActivated(address indexed underlying, address indexed pToken);
event EnterMarket(address indexed underlying, address indexed account);
event ExitMarket(address indexed underlying, address indexed account);
event Deposit(address indexed underlying, address indexed account, uint amount);
event Withdraw(address indexed underlying, address indexed account, uint amount);
event Borrow(address indexed underlying, address indexed account, uint amount);
event Repay(address indexed underlying, address indexed account, uint amount);
event Liquidation(address indexed liquidator, address indexed violator, address indexed underlying, address collateral, uint repay, uint yield, uint healthScore, uint baseDiscount, uint discount);
event TrackAverageLiquidity(address indexed account);
event UnTrackAverageLiquidity(address indexed account);
event DelegateAverageLiquidity(address indexed account, address indexed delegate);
event PTokenWrap(address indexed underlying, address indexed account, uint amount);
event PTokenUnWrap(address indexed underlying, address indexed account, uint amount);
event AssetStatus(address indexed underlying, uint totalBalances, uint totalBorrows, uint96 reserveBalance, uint poolSize, uint interestAccumulator, int96 interestRate, uint timestamp);
event RequestDeposit(address indexed account, uint amount);
event RequestWithdraw(address indexed account, uint amount);
event RequestMint(address indexed account, uint amount);
event RequestBurn(address indexed account, uint amount);
event RequestTransferEToken(address indexed from, address indexed to, uint amount);
event RequestBorrow(address indexed account, uint amount);
event RequestRepay(address indexed account, uint amount);
event RequestTransferDToken(address indexed from, address indexed to, uint amount);
event RequestLiquidate(address indexed liquidator, address indexed violator, address indexed underlying, address collateral, uint repay, uint minYield);
event InstallerSetUpgradeAdmin(address indexed newUpgradeAdmin);
event InstallerSetGovernorAdmin(address indexed newGovernorAdmin);
event InstallerInstallModule(uint indexed moduleId, address indexed moduleImpl, bytes32 moduleGitCommit);
event GovSetAssetConfig(address indexed underlying, Storage.AssetConfig newConfig);
event GovSetIRM(address indexed underlying, uint interestRateModel, bytes resetParams);
event GovSetPricingConfig(address indexed underlying, uint16 newPricingType, uint32 newPricingParameter);
event GovSetReserveFee(address indexed underlying, uint32 newReserveFee);
event GovConvertReserves(address indexed underlying, address indexed recipient, uint amount);
event RequestSwap(address indexed accountIn, address indexed accountOut, address indexed underlyingIn, address underlyingOut, uint amount, uint swapType);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
contract Proxy {
address immutable creator;
constructor() {
creator = msg.sender;
}
// External interface
fallback() external {
address creator_ = creator;
if (msg.sender == creator_) {
assembly {
mstore(0, 0)
calldatacopy(31, 0, calldatasize())
switch mload(0) // numTopics
case 0 { log0(32, sub(calldatasize(), 1)) }
case 1 { log1(64, sub(calldatasize(), 33), mload(32)) }
case 2 { log2(96, sub(calldatasize(), 65), mload(32), mload(64)) }
case 3 { log3(128, sub(calldatasize(), 97), mload(32), mload(64), mload(96)) }
case 4 { log4(160, sub(calldatasize(), 129), mload(32), mload(64), mload(96), mload(128)) }
default { revert(0, 0) }
return(0, 0)
}
} else {
assembly {
mstore(0, 0xe9c4a3ac00000000000000000000000000000000000000000000000000000000) // dispatch() selector
calldatacopy(4, 0, calldatasize())
mstore(add(4, calldatasize()), shl(96, caller()))
let result := call(gas(), creator_, 0, 0, add(24, calldatasize()), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
abstract contract Constants {
// Universal
uint internal constant SECONDS_PER_YEAR = 365.2425 * 86400; // Gregorian calendar
// Protocol parameters
uint internal constant MAX_SANE_AMOUNT = type(uint112).max;
uint internal constant MAX_SANE_SMALL_AMOUNT = type(uint96).max;
uint internal constant MAX_SANE_DEBT_AMOUNT = type(uint144).max;
uint internal constant INTERNAL_DEBT_PRECISION = 1e9;
uint internal constant MAX_ENTERED_MARKETS = 10; // per sub-account
uint internal constant MAX_POSSIBLE_ENTERED_MARKETS = 2**32; // limited by size of AccountStorage.numMarketsEntered
uint internal constant CONFIG_FACTOR_SCALE = 4_000_000_000; // must fit into a uint32
uint internal constant RESERVE_FEE_SCALE = 4_000_000_000; // must fit into a uint32
uint32 internal constant DEFAULT_RESERVE_FEE = uint32(0.23 * 4_000_000_000);
uint internal constant INITIAL_INTEREST_ACCUMULATOR = 1e27;
uint internal constant AVERAGE_LIQUIDITY_PERIOD = 24 * 60 * 60;
uint16 internal constant MIN_UNISWAP3_OBSERVATION_CARDINALITY = 144;
uint24 internal constant DEFAULT_TWAP_WINDOW_SECONDS = 30 * 60;
uint32 internal constant DEFAULT_BORROW_FACTOR = uint32(0.28 * 4_000_000_000);
// Implementation internals
uint internal constant REENTRANCYLOCK__UNLOCKED = 1;
uint internal constant REENTRANCYLOCK__LOCKED = 2;
uint8 internal constant DEFERLIQUIDITY__NONE = 0;
uint8 internal constant DEFERLIQUIDITY__CLEAN = 1;
uint8 internal constant DEFERLIQUIDITY__DIRTY = 2;
// Pricing types
uint16 internal constant PRICINGTYPE__PEGGED = 1;
uint16 internal constant PRICINGTYPE__UNISWAP3_TWAP = 2;
uint16 internal constant PRICINGTYPE__FORWARDED = 3;
// Modules
// Public single-proxy modules
uint internal constant MODULEID__INSTALLER = 1;
uint internal constant MODULEID__MARKETS = 2;
uint internal constant MODULEID__LIQUIDATION = 3;
uint internal constant MODULEID__GOVERNANCE = 4;
uint internal constant MODULEID__EXEC = 5;
uint internal constant MODULEID__SWAP = 6;
uint internal constant MAX_EXTERNAL_SINGLE_PROXY_MODULEID = 499_999;
// Public multi-proxy modules
uint internal constant MODULEID__ETOKEN = 500_000;
uint internal constant MODULEID__DTOKEN = 500_001;
uint internal constant MAX_EXTERNAL_MODULEID = 999_999;
// Internal modules
uint internal constant MODULEID__RISK_MANAGER = 1_000_000;
// Interest rate models
// Default for new markets
uint internal constant MODULEID__IRM_DEFAULT = 2_000_000;
// Testing-only
uint internal constant MODULEID__IRM_ZERO = 2_000_001;
uint internal constant MODULEID__IRM_FIXED = 2_000_002;
uint internal constant MODULEID__IRM_LINEAR = 2_000_100;
// Classes
uint internal constant MODULEID__IRM_CLASS__STABLE = 2_000_500;
uint internal constant MODULEID__IRM_CLASS__MAJOR = 2_000_501;
uint internal constant MODULEID__IRM_CLASS__MIDCAP = 2_000_502;
// Swap types
uint internal constant SWAP_TYPE__UNI_EXACT_INPUT_SINGLE = 1;
uint internal constant SWAP_TYPE__UNI_EXACT_INPUT = 2;
uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_SINGLE = 3;
uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT = 4;
uint internal constant SWAP_TYPE__1INCH = 5;
uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_SINGLE_REPAY = 6;
uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_REPAY = 7;
}{
"optimizer": {
"enabled": true,
"runs": 1000000
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"bytes32","name":"moduleGitCommit_","type":"bytes32"},{"components":[{"internalType":"address","name":"referenceAsset","type":"address"},{"internalType":"address","name":"uniswapFactory","type":"address"},{"internalType":"bytes32","name":"uniswapPoolInitCodeHash","type":"bytes32"}],"internalType":"struct RiskManager.RiskManagerSettings","name":"settings","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalBalances","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"reserveBalance","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"poolSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulator","type":"uint256"},{"indexed":false,"internalType":"int96","name":"interestRate","type":"int96"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"AssetStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"}],"name":"DelegateAverageLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"EnterMarket","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"ExitMarket","type":"event"},{"anonymous":false,"inputs":[],"name":"Genesis","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"GovConvertReserves","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"components":[{"internalType":"address","name":"eTokenAddress","type":"address"},{"internalType":"bool","name":"borrowIsolated","type":"bool"},{"internalType":"uint32","name":"collateralFactor","type":"uint32"},{"internalType":"uint32","name":"borrowFactor","type":"uint32"},{"internalType":"uint24","name":"twapWindow","type":"uint24"}],"indexed":false,"internalType":"struct Storage.AssetConfig","name":"newConfig","type":"tuple"}],"name":"GovSetAssetConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint256","name":"interestRateModel","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"resetParams","type":"bytes"}],"name":"GovSetIRM","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint16","name":"newPricingType","type":"uint16"},{"indexed":false,"internalType":"uint32","name":"newPricingParameter","type":"uint32"}],"name":"GovSetPricingConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint32","name":"newReserveFee","type":"uint32"}],"name":"GovSetReserveFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"moduleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"moduleImpl","type":"address"},{"indexed":false,"internalType":"bytes32","name":"moduleGitCommit","type":"bytes32"}],"name":"InstallerInstallModule","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newGovernorAdmin","type":"address"}],"name":"InstallerSetGovernorAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newUpgradeAdmin","type":"address"}],"name":"InstallerSetUpgradeAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"violator","type":"address"},{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"repay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"yield","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"healthScore","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseDiscount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"discount","type":"uint256"}],"name":"Liquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"eToken","type":"address"},{"indexed":true,"internalType":"address","name":"dToken","type":"address"}],"name":"MarketActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"pToken","type":"address"}],"name":"PTokenActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PTokenUnWrap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PTokenWrap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proxy","type":"address"},{"indexed":false,"internalType":"uint256","name":"moduleId","type":"uint256"}],"name":"ProxyCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"violator","type":"address"},{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"repay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minYield","type":"uint256"}],"name":"RequestLiquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestRepay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"accountIn","type":"address"},{"indexed":true,"internalType":"address","name":"accountOut","type":"address"},{"indexed":true,"internalType":"address","name":"underlyingIn","type":"address"},{"indexed":false,"internalType":"address","name":"underlyingOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapType","type":"uint256"}],"name":"RequestSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestTransferDToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestTransferEToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"TrackAverageLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"UnTrackAverageLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"computeAssetLiquidities","outputs":[{"components":[{"internalType":"address","name":"underlying","type":"address"},{"components":[{"internalType":"uint256","name":"collateralValue","type":"uint256"},{"internalType":"uint256","name":"liabilityValue","type":"uint256"},{"internalType":"uint256","name":"numBorrows","type":"uint256"},{"internalType":"bool","name":"borrowIsolated","type":"bool"}],"internalType":"struct IRiskManager.LiquidityStatus","name":"status","type":"tuple"}],"internalType":"struct IRiskManager.AssetLiquidity[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"computeLiquidity","outputs":[{"components":[{"internalType":"uint256","name":"collateralValue","type":"uint256"},{"internalType":"uint256","name":"liabilityValue","type":"uint256"},{"internalType":"uint256","name":"numBorrows","type":"uint256"},{"internalType":"bool","name":"borrowIsolated","type":"bool"}],"internalType":"struct IRiskManager.LiquidityStatus","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"getNewMarketParameters","outputs":[{"components":[{"internalType":"uint16","name":"pricingType","type":"uint16"},{"internalType":"uint32","name":"pricingParameters","type":"uint32"},{"components":[{"internalType":"address","name":"eTokenAddress","type":"address"},{"internalType":"bool","name":"borrowIsolated","type":"bool"},{"internalType":"uint32","name":"collateralFactor","type":"uint32"},{"internalType":"uint32","name":"borrowFactor","type":"uint32"},{"internalType":"uint24","name":"twapWindow","type":"uint24"}],"internalType":"struct Storage.AssetConfig","name":"config","type":"tuple"}],"internalType":"struct IRiskManager.NewMarketParameters","name":"p","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"twap","type":"uint256"},{"internalType":"uint256","name":"twapPeriod","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"getPriceFull","outputs":[{"internalType":"uint256","name":"twap","type":"uint256"},{"internalType":"uint256","name":"twapPeriod","type":"uint256"},{"internalType":"uint256","name":"currPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint112","name":"totalBalances","type":"uint112"},{"internalType":"uint144","name":"totalBorrows","type":"uint144"},{"internalType":"uint96","name":"reserveBalance","type":"uint96"},{"internalType":"uint256","name":"interestAccumulator","type":"uint256"},{"internalType":"uint40","name":"lastInterestAccumulatorUpdate","type":"uint40"},{"internalType":"uint8","name":"underlyingDecimals","type":"uint8"},{"internalType":"uint32","name":"interestRateModel","type":"uint32"},{"internalType":"int96","name":"interestRate","type":"int96"},{"internalType":"uint32","name":"reserveFee","type":"uint32"},{"internalType":"uint16","name":"pricingType","type":"uint16"},{"internalType":"uint32","name":"pricingParameters","type":"uint32"},{"internalType":"uint256","name":"poolSize","type":"uint256"},{"internalType":"uint256","name":"underlyingDecimalsScaler","type":"uint256"},{"internalType":"uint256","name":"maxExternalAmount","type":"uint256"}],"internalType":"struct BaseLogic.AssetCache","name":"assetCache","type":"tuple"},{"components":[{"internalType":"address","name":"eTokenAddress","type":"address"},{"internalType":"bool","name":"borrowIsolated","type":"bool"},{"internalType":"uint32","name":"collateralFactor","type":"uint32"},{"internalType":"uint32","name":"borrowFactor","type":"uint32"},{"internalType":"uint24","name":"twapWindow","type":"uint24"}],"internalType":"struct Storage.AssetConfig","name":"config","type":"tuple"}],"name":"getPriceInternal","outputs":[{"internalType":"uint256","name":"twap","type":"uint256"},{"internalType":"uint256","name":"twapPeriod","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"moduleGitCommit","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"moduleId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"requireLiquidity","outputs":[],"stateMutability":"view","type":"function"}]Contract Creation Code
6101206040523480156200001257600080fd5b5060405162003c4b38038062003c4b833981016040819052620000359162000086565b620f424060805260a09190915280516001600160a01b0390811660c05260208201511660e05260400151610100526200011d565b80516001600160a01b03811681146200008157600080fd5b919050565b60008082840360808112156200009b57600080fd5b835192506060601f1982011215620000b257600080fd5b50604051606081016001600160401b0381118282101715620000e457634e487b7160e01b600052604160045260246000fd5b604052620000f56020850162000069565b8152620001056040850162000069565b60208201526060939093015160408401525092909150565b60805160a05160c05160e05161010051613ace6200017d600039600061166d0152600081816104990152611632015260008181610372015281816104d6015281816115b9015261191a0152600060fe015260006101f10152613ace6000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80639693fa6b11610076578063c39b543a1161005b578063c39b543a14610213578063ebd7ba1914610228578063f70c2fde1461024857600080fd5b80639693fa6b146101be578063a1308f27146101ec57600080fd5b806337fe974a146100a857806341976e09146100d157806369a92ea3146100f95780638eddcd921461012e575b600080fd5b6100bb6100b6366004612f86565b61025b565b6040516100c89190612fa3565b60405180910390f35b6100e46100df366004612f86565b6102a0565b604080519283526020830191909152016100c8565b6101207f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100c8565b61014161013c366004612f86565b6102fa565b60408051825161ffff16815260208084015163ffffffff9081168284015293830151805173ffffffffffffffffffffffffffffffffffffffff16838501529081015115156060808401919091529281015184166080808401919091529281015190931660a082015291015162ffffff1660c082015260e0016100c8565b6101d16101cc366004612f86565b6109db565b604080519384526020840192909252908201526060016100c8565b6101207f000000000000000000000000000000000000000000000000000000000000000081565b610226610221366004612f86565b610bab565b005b61023b610236366004612f86565b610ca6565b6040516100c89190612fd0565b6100e461025636600461328d565b610e20565b61028860405180608001604052806000815260200160008152602001600081526020016000151581525090565b61029a8261029584610eae565b611047565b92915050565b60008060006102ae84611382565b805173ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604081209192506102e18683611529565b90506102ed8184610e20565b9097909650945050505050565b61033f604080516060808201835260008083526020808401829052845160a0810186528281529081018290528085018290529182018190526080820152909182015290565b60408181018051600160209091015280516000920191909152805163ffffffff6060909101525162ffffff6080909101527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811690831614156103c2576001815260006020820152919050565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600b6020526040902054161561045c57600381526000602080830182905273ffffffffffffffffffffffffffffffffffffffff8085168352600b825260408084205490911683526008909152908190205481830151750100000000000000000000000000000000000000000090910463ffffffff16910152919050565b60408051608081018252610bb8815261271060208201526101f49181019190915260646060820152600090819081805b60048110156106c05760007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631698ee82897f0000000000000000000000000000000000000000000000000000000000000000878660048110610507576105076133bc565b60200201516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015262ffffff166044820152606401602060405180830381865afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ac91906133eb565b905073ffffffffffffffffffffffffffffffffffffffff81166105cf57506106b0565b60008173ffffffffffffffffffffffffffffffffffffffff16631a6865026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561061c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106409190613408565b905073ffffffffffffffffffffffffffffffffffffffff871615806106885750836fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff16115b156106ad578196508483600481106106a2576106a26133bc565b602002015195508093505b50505b6106b981613469565b905061048c565b50505073ffffffffffffffffffffffffffffffffffffffff8216610745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6e6f2d756e69737761702d706f6f6c2d617661696c00000000000000000060448201526064015b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1661076685836115b4565b73ffffffffffffffffffffffffffffffffffffffff16146107e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6261642d756e69737761702d706f6f6c2d61646472000000000000000000604482015260640161073c565b6002835262ffffff811660208401526040517f32148f670000000000000000000000000000000000000000000000000000000081526090600482015273ffffffffffffffffffffffffffffffffffffffff8316906332148f6790602401600060405180830381600087803b15801561085a57600080fd5b505af192505050801561086b575060015b6109d3576108776134a2565b806308c379a01415610996575061088c6134be565b806108975750610998565b805160208201207fe01ebc6b01bbf458b3d355b6e649efe64599751670c5d19175619893ecf975291415610927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f652f7269736b2f756e69737761702d706f6f6c2d6e6f742d696e697465640000604482015260640161073c565b80604051602001610938919061358b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261073c916004016135d0565b505b3d8080156109c2576040519150601f19603f3d011682016040523d82523d6000602084013e6109c7565b606091505b506109d18161173b565b505b50505b919050565b6000806000806109ea85611382565b805173ffffffffffffffffffffffffffffffffffffffff166000908152600960205260408120919250610a1d8783611529565b9050610a298184610e20565b909650945060008080610a3c84876117ac565b509194509250905061ffff821660011415610a6157670de0b6b3a76400009650610b9e565b61ffff821660021480610a78575061ffff82166003145b15610b3c576000610a898487611529565b90506000610a9785846115b4565b905060008173ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015610ae6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0a9190613621565b5050505050509050610b32838273ffffffffffffffffffffffffffffffffffffffff16611916565b9950505050610b9e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f756e6b6e6f776e2d70726963696e672d7479706500000000000000000000604482015260640161073c565b5050505050509193909250565b6000610bb68261025b565b905080606001511580610bcd575080604001516001145b610c33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f626f72726f772d69736f6c6174696f6e2d76696f6c6174696f6e00000000604482015260640161073c565b602081015181511015610ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f636f6c6c61746572616c2d76696f6c6174696f6e00000000000000000000604482015260640161073c565b5050565b60606000610cb383610eae565b90506000815167ffffffffffffffff811115610cd157610cd1613062565b604051908082528060200260200182016040528015610d0a57816020015b610cf7612f01565b815260200190600190039081610cef5790505b50604080516001808252818301909252919250600091906020808301908036833701905050905060005b8351811015610e1657838181518110610d4f57610d4f6133bc565b602002602001015182600081518110610d6a57610d6a6133bc565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250838281518110610db557610db56133bc565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff9091169052610de48683611047565b838281518110610df657610df66133bc565b60200260200101516020018190525080610e0f90613469565b9050610d34565b5090949350505050565b604051600090819081808080610e3689896117ac565b9350935093509350600161ffff168361ffff161415610e6757670de0b6b3a764000096508062ffffff169550610e9e565b61ffff831660021415610b3c576000610e8085846115b4565b9050610e928a828462ffffff16611a71565b9098509650610e9e9050565b5050505080604052509250929050565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526006602052604081205460609263ffffffff6601000000000000830416926a010000000000000000000090920416908267ffffffffffffffff811115610f1357610f13613062565b604051908082528060200260200182016040528015610f3c578160200160208202803683370190505b50905063ffffffff8316610f5257949350505050565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600760205260408120825190918491849190610f8c57610f8c6133bc565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260015b8463ffffffff1681101561103c5781816401000000008110610fd857610fd86133bc565b0154835173ffffffffffffffffffffffffffffffffffffffff90911690849083908110611007576110076133bc565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261103581613469565b9050610fb4565b509095945050505050565b61107460405180608001604052806000815260200160008152602001600081526020016000151581525090565b6000808252602080830182905260408084018390526060808501849052815160a08101835284815292830184905290820183905281018290526080810191909152604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c0810182905260005b855181101561137857600086828151811061114d5761114d6133bc565b6020026020010151905060008061116383611382565b805173ffffffffffffffffffffffffffffffffffffffff9081166000908152600960209081526040808320938f1683526005840190915290205491985096506dffffffffffffffffffffffffffff8116906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff1681158015906111f25750604089015163ffffffff1615155b1561127f5761120285898961208d565b5061120d878a610e20565b5060019450925060006112208884612500565b9050670de0b6b3a764000061123585836136c4565b61123f9190613730565b905063ee6b28008a6040015163ffffffff168261125c91906136c4565b6112669190613730565b9050808b60000181815161127a9190613744565b905250505b801561136257836112a85761129585898961208d565b506112a0878a610e20565b506001945092505b60408a018051906112b882613469565b9052506020890151156112cd57600160608b01525b60006112da89898f612533565b9050670de0b6b3a76400006112ef85836136c4565b6112f99190613730565b9050896060015163ffffffff16600014156113265771ffffffffffffffffffffffffffffffffffff611349565b60608a015163ffffffff1661133f63ee6b2800836136c4565b6113499190613730565b9050808b60200181815161135d9190613744565b905250505b50505050508061137190613469565b9050611130565b5050505092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff828116600090815260086020908152604091829020825160a081018452905493841680825274010000000000000000000000000000000000000000850460ff161515928201929092527501000000000000000000000000000000000000000000840463ffffffff90811693820193909352790100000000000000000000000000000000000000000000000000840490921660608301527d01000000000000000000000000000000000000000000000000000000000090920462ffffff166080820152906114eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640161073c565b606081015163ffffffff9081161415611509576342c1d80060608201525b608081015162ffffff908116141561029a57610708608082015292915050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c08101919091526115ad83838361208d565b5092915050565b6000827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff80821690831611156115fb57905b6040805173ffffffffffffffffffffffffffffffffffffffff808516602083015283169181019190915262ffffff851660608201527f000000000000000000000000000000000000000000000000000000000000000090608001604051602081830303815290604052805190602001207f00000000000000000000000000000000000000000000000000000000000000006040516020016116fc939291907fff00000000000000000000000000000000000000000000000000000000000000815260609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830191909152603582015260550190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012095945050505050565b80511561174a57805181602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f652f656d7074792d6572726f7200000000000000000000000000000000000000604482015260640161073c565b600080600080600361ffff1686610140015161ffff1614156118f057855173ffffffffffffffffffffffffffffffffffffffff9081166000908152600b602052604081205490911694506117ff85611382565b6080810151815173ffffffffffffffffffffffffffffffffffffffff16600090815260096020526040902080547a010000000000000000000000000000000000000000000000000000810461ffff1697507c0100000000000000000000000000000000000000000000000000000000900463ffffffff16955090935090915060038514156118e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f652f6e65737465642d70726963652d666f7277617264696e6700000000000000604482015260640161073c565b505061190d565b505083516101408501516101608601516080860151929450909250905b92959194509250565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1610156119bc576101a08301516119ab83806119a6670de0b6b3a76400007801000000000000000000000000000000000000000000000000613730565b6125b5565b6119b59190613730565b9050611a36565b6119fd8283856101a00151670de0b6b3a76400006119da91906136c4565b6119a6907801000000000000000000000000000000000000000000000000613730565b905080611a1a57506ec097ce7bc90715b34b9f100000000061029a565b611a33816ec097ce7bc90715b34b9f1000000000613730565b90505b6ec097ce7bc90715b34b9f1000000000811115611a6357506ec097ce7bc90715b34b9f100000000061029a565b8061029a5750600192915050565b6040805160028082526060820183526000928392839290916020830190803683370190505090508381600081518110611aac57611aac6133bc565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110611adb57611adb6133bc565b602002602001019063ffffffff16908163ffffffff16815250506000808673ffffffffffffffffffffffffffffffffffffffff1663883bdbfd60e01b84604051602401611b28919061375c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611bb1919061379a565b600060405180830381855afa9150503d8060008114611bec576040519150601f19603f3d011682016040523d82523d6000602084013e611bf1565b606091505b509150915081611fe85760405160206024820152600360448201527f4f4c4400000000000000000000000000000000000000000000000000000000006064820152608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f08c379a000000000000000000000000000000000000000000000000000000000178152915190912082519183019190912014611cc857611cc88161173b565b6000808873ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3a9190613621565b5050509350935050506000808a73ffffffffffffffffffffffffffffffffffffffff1663252c09d784866001611d7091906137b6565b611d7a91906137dc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815261ffff9091166004820152602401608060405180830381865afa158015611dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df5919061380f565b93505050915080611e96576040517f252c09d70000000000000000000000000000000000000000000000000000000081526000600482015273ffffffffffffffffffffffffffffffffffffffff8c169063252c09d790602401608060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f919061380f565b5091935050505b611ea663ffffffff83164261386a565b99508987600081518110611ebc57611ebc6133bc565b602002602001019063ffffffff16908163ffffffff16815250508a73ffffffffffffffffffffffffffffffffffffffff1663883bdbfd60e01b88604051602401611f06919061375c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611f8f919061379a565b600060405180830381855afa9150503d8060008114611fca576040519150601f19603f3d011682016040523d82523d6000602084013e611fcf565b606091505b50909650945085611fe357611fe38561173b565b505050505b600081806020019051810190611ffe9190613881565b905060008782600081518110612016576120166133bc565b602002602001015183600181518110612031576120316133bc565b6020026020010151612043919061392f565b61204d9190613997565b9050600061205a82612682565b905061207c8b8273ffffffffffffffffffffffffffffffffffffffff16611916565b9b989a509798505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83168152815464ffffffffff811660a083015265010000000000810460ff90811660c084018190526601000000000000830463ffffffff90811660e08601526a01000000000000000000008404600b0b610100860152760100000000000000000000000000000000000000000000840481166101208601527a010000000000000000000000000000000000000000000000000000840461ffff166101408601527c010000000000000000000000000000000000000000000000000000000090930490921661016084015260018401547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16606084015260038401546dffffffffffffffffffffffffffff80821660208601526e01000000000000000000000000000090910471ffffffffffffffffffffffffffffffffffff166040850152600485015460808501526012839003909116600a0a6101a08401819052600092918161221257612212613701565b046101c084015260006122258430612a16565b9050836101c001518111612246576101a0840151810261018085015261224f565b60006101808501525b8360a0015164ffffffffff1642146124f7576001925060008460a0015164ffffffffff164261227e919061386a565b905060006b033b2e3c9fd0803ce800000086608001516122ca886101000151600b0b6b033b2e3c9fd0803ce80000006122b79190613a0b565b856b033b2e3c9fd0803ce8000000612b33565b6122d491906136c4565b6122de9190613730565b90506000866080015182886040015171ffffffffffffffffffffffffffffffffffff1661230b91906136c4565b6123159190613730565b606088015160208901519192506bffffffffffffffffffffffff16906dffffffffffffffffffffffffffff166000612355633b9aca0063ee6b28006136c4565b6101208b015163ffffffff90811614612373578a6101200151612379565b6336d616005b63ffffffff168b6040015171ffffffffffffffffffffffffffffffffffff16866123a3919061386a565b6123ad91906136c4565b6123b79190613730565b9050801561242f5760006123cf633b9aca0086613730565b8b61018001516123df9190613744565b90506123eb828261386a565b6123f584836136c4565b6123ff9190613730565b92508a602001516dffffffffffffffffffffffffffff1683612421919061386a565b61242b9085613744565b9350505b6dffffffffffffffffffffffffffff821180159061245f575071ffffffffffffffffffffffffffffffffffff8411155b156124f05761246d84612bf0565b71ffffffffffffffffffffffffffffffffffff1660408b015260808a0185905264ffffffffff421660a08b015260208a01516dffffffffffffffffffffffffffff1682146124f0576124be83612c98565b6bffffffffffffffffffffffff1660608b01526124da82612d36565b6dffffffffffffffffffffffffffff1660208b01525b5050505050505b50509392505050565b60008061250c84612db0565b9050670de0b6b3a764000061252182856136c4565b61252b9190613730565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600584016020526040812054633b9aca00906125a190859061259c908890839088906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff16612e47565b612ea3565b6125ab9190613730565b90505b9392505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050806000141561260d576000841161260257600080fd5b5082900490506125ae565b80841161261957600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008060008360020b12612699578260020b6126a1565b8260020b6000035b9050620d89e8811115612710576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f5400000000000000000000000000000000000000000000000000000000000000604482015260640161073c565b60006001821661273157700100000000000000000000000000000000612743565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615612777576ffff97272373d413259a46990580e213a0260801c5b6004821615612796576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b60088216156127b5576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b60108216156127d4576fffcb9843d60f6159c9db58835c9266440260801c5b60208216156127f3576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615612812576fff2ea16466c96a3843ec78b326b528610260801c5b6080821615612831576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615612851576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615612871576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615612891576ff3392b0822b70005940c7a398e4b70f30260801c5b6108008216156128b1576fe7159475a2c29b7443b29c7fa6e889d90260801c5b6110008216156128d1576fd097f3bdfd2022b8845ad8f792aa58250260801c5b6120008216156128f1576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615612911576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615612931576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615612952576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615612972576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615612991576d2216e584f5fa1ea926041bedfe980260801c5b620800008216156129ae576b048a170391f7dc42444e8fa20260801c5b60008460020b13156129ed57807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff816129e9576129e9613701565b0490505b640100000000810615612a01576001612a04565b60005b60ff16602082901c0192505050919050565b60408051835173ffffffffffffffffffffffffffffffffffffffff848116602480850191909152845180850390910181526044840185526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790529351600094859384931691614e2091612aad9161379a565b6000604051808303818686fa925050503d8060008114612ae9576040519150601f19603f3d011682016040523d82523d6000602084013e612aee565b606091505b5091509150811580612b01575060208151105b15612b1157600093505050612b2a565b80806020019051810190612b259190613a7f565b935050505b60405292915050565b6000838015612bd357600184168015612b4e57859250612b52565b8392505b50600283046002850494505b8415612bcd578586028687820414612b7557600080fd5b81810181811015612b8557600080fd5b8590049650506001851615612bc2578583028387820414158715151615612bab57600080fd5b81810181811015612bbb57600080fd5b8590049350505b600285049450612b5e565b50612be8565b838015612be357600092506124f7565b839250505b509392505050565b600071ffffffffffffffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f652f646562742d616d6f756e742d746f6f2d6c617267652d746f2d656e636f6460448201527f6500000000000000000000000000000000000000000000000000000000000000606482015260840161073c565b5090565b60006bffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f652f736d616c6c2d616d6f756e742d746f6f2d6c617267652d746f2d656e636f60448201527f6465000000000000000000000000000000000000000000000000000000000000606482015260840161073c565b60006dffffffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f616d6f756e742d746f6f2d6c617267652d746f2d656e636f646500000000604482015260640161073c565b600081602001516dffffffffffffffffffffffffffff1660001415612dde5750670de0b6b3a7640000919050565b81602001516dffffffffffffffffffffffffffff16633b9aca00836040015171ffffffffffffffffffffffffffffffffffff16612e1b9190613730565b836101800151612e2b9190613744565b612e3d90670de0b6b3a76400006136c4565b61029a9190613730565b600081612e565750600061252b565b73ffffffffffffffffffffffffffffffffffffffff831660009081526005860160205260409020600101546080850151612e9090846136c4565b612e9a9190613730565b95945050505050565b600081612eb25750600061029a565b6101a0830151633b9aca000280807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8582010181612ef257612ef2613701565b0402949350505050565b905290565b6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001612efc60405180608001604052806000815260200160008152602001600081526020016000151581525090565b73ffffffffffffffffffffffffffffffffffffffff81168114612f7857600080fd5b50565b80356109d681612f56565b600060208284031215612f9857600080fd5b81356125ae81612f56565b8151815260208083015190820152604080830151908201526060808301511515908201526080810161029a565b6020808252825182820181905260009190848201906040850190845b81811015613056578351805173ffffffffffffffffffffffffffffffffffffffff168452850151613042868501828051825260208101516020830152604081015160408301526060810151151560608301525050565b509284019260a09290920191600101612fec565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff821117156130d5576130d5613062565b6040525050565b6040516101e0810167ffffffffffffffff8111828210171561310057613100613062565b60405290565b80356dffffffffffffffffffffffffffff811681146109d657600080fd5b803571ffffffffffffffffffffffffffffffffffff811681146109d657600080fd5b80356bffffffffffffffffffffffff811681146109d657600080fd5b803564ffffffffff811681146109d657600080fd5b60ff81168114612f7857600080fd5b80356109d681613177565b63ffffffff81168114612f7857600080fd5b80356109d681613191565b8035600b81900b81146109d657600080fd5b61ffff81168114612f7857600080fd5b80356109d6816131c0565b8015158114612f7857600080fd5b600060a082840312156131fb57600080fd5b60405160a0810181811067ffffffffffffffff8211171561321e5761321e613062565b604052905080823561322f81612f56565b8152602083013561323f816131db565b6020820152604083013561325281613191565b6040820152606083013561326581613191565b6060820152608083013562ffffff8116811461328057600080fd5b6080919091015292915050565b6000808284036102808112156132a257600080fd5b6101e0808212156132b257600080fd5b6132ba6130dc565b91506132c585612f7b565b82526132d360208601613106565b60208301526132e460408601613124565b60408301526132f560608601613146565b60608301526080850135608083015261331060a08601613162565b60a083015261332160c08601613186565b60c083015261333260e086016131a3565b60e08301526101006133458187016131ae565b908301526101206133578682016131a3565b908301526101406133698682016131d0565b9083015261016061337b8682016131a3565b9083015261018085810135908301526101a080860135908301526101c0808601359083015290925082906133b1868287016131e9565b925050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156133fd57600080fd5b81516125ae81612f56565b60006020828403121561341a57600080fd5b81516fffffffffffffffffffffffffffffffff811681146125ae57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561349b5761349b61343a565b5060010190565b600060033d11156134bb5760046000803e5060005160e01c5b90565b600060443d10156134cc5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff816024840111818411171561351a57505050505090565b82850191508151818111156135325750505050505090565b843d870101602082850101111561354c5750505050505090565b61103c60208286010187613091565b60005b8381101561357657818101518382015260200161355e565b83811115613585576000848401525b50505050565b7f652f7269736b2f756e69737761702f00000000000000000000000000000000008152600082516135c381600f85016020870161355b565b91909101600f0192915050565b60208152600082518060208401526135ef81604085016020870161355b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600080600080600080600060e0888a03121561363c57600080fd5b875161364781612f56565b8097505060208801518060020b811461365f57600080fd5b6040890151909650613670816131c0565b6060890151909550613681816131c0565b6080890151909450613692816131c0565b60a08901519093506136a381613177565b60c08901519092506136b4816131db565b8091505092959891949750929550565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156136fc576136fc61343a565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261373f5761373f613701565b500490565b600082198211156137575761375761343a565b500190565b6020808252825182820181905260009190848201906040850190845b8181101561305657835163ffffffff1683529284019291840191600101613778565b600082516137ac81846020870161355b565b9190910192915050565b600061ffff8083168185168083038211156137d3576137d361343a565b01949350505050565b600061ffff808416806137f1576137f1613701565b92169190910692915050565b8051600681900b81146109d657600080fd5b6000806000806080858703121561382557600080fd5b845161383081613191565b935061383e602086016137fd565b9250604085015161384e81612f56565b606086015190925061385f816131db565b939692955090935050565b60008282101561387c5761387c61343a565b500390565b6000602080838503121561389457600080fd5b825167ffffffffffffffff808211156138ac57600080fd5b818501915085601f8301126138c057600080fd5b8151818111156138d2576138d2613062565b8060051b91506040516138e785840182613091565b8181529183018401918481018884111561390057600080fd5b938501935b8385101561392357613916856137fd565b8152938501938501613905565b50979650505050505050565b60008160060b8360060b60008112817fffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000018312811516156139725761397261343a565b81667fffffffffffff01831381161561398d5761398d61343a565b5090039392505050565b60008160060b8360060b806139ae576139ae613701565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffffffffffffffffffffff8000000000000083141615613a0257613a0261343a565b90059392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03841381151615613a4557613a4561343a565b827f8000000000000000000000000000000000000000000000000000000000000000038412811615613a7957613a7961343a565b50500190565b600060208284031215613a9157600080fd5b505191905056fea264697066735822122049da3334e4e4abd0c5d85f3a1e678e0ca391f95c3fb85f584b53ad8f03a4f2cb64736f6c634300080a003300000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a13000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a35760003560e01c80639693fa6b11610076578063c39b543a1161005b578063c39b543a14610213578063ebd7ba1914610228578063f70c2fde1461024857600080fd5b80639693fa6b146101be578063a1308f27146101ec57600080fd5b806337fe974a146100a857806341976e09146100d157806369a92ea3146100f95780638eddcd921461012e575b600080fd5b6100bb6100b6366004612f86565b61025b565b6040516100c89190612fa3565b60405180910390f35b6100e46100df366004612f86565b6102a0565b604080519283526020830191909152016100c8565b6101207f00000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a1381565b6040519081526020016100c8565b61014161013c366004612f86565b6102fa565b60408051825161ffff16815260208084015163ffffffff9081168284015293830151805173ffffffffffffffffffffffffffffffffffffffff16838501529081015115156060808401919091529281015184166080808401919091529281015190931660a082015291015162ffffff1660c082015260e0016100c8565b6101d16101cc366004612f86565b6109db565b604080519384526020840192909252908201526060016100c8565b6101207f00000000000000000000000000000000000000000000000000000000000f424081565b610226610221366004612f86565b610bab565b005b61023b610236366004612f86565b610ca6565b6040516100c89190612fd0565b6100e461025636600461328d565b610e20565b61028860405180608001604052806000815260200160008152602001600081526020016000151581525090565b61029a8261029584610eae565b611047565b92915050565b60008060006102ae84611382565b805173ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604081209192506102e18683611529565b90506102ed8184610e20565b9097909650945050505050565b61033f604080516060808201835260008083526020808401829052845160a0810186528281529081018290528085018290529182018190526080820152909182015290565b60408181018051600160209091015280516000920191909152805163ffffffff6060909101525162ffffff6080909101527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff90811690831614156103c2576001815260006020820152919050565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600b6020526040902054161561045c57600381526000602080830182905273ffffffffffffffffffffffffffffffffffffffff8085168352600b825260408084205490911683526008909152908190205481830151750100000000000000000000000000000000000000000090910463ffffffff16910152919050565b60408051608081018252610bb8815261271060208201526101f49181019190915260646060820152600090819081805b60048110156106c05760007f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98473ffffffffffffffffffffffffffffffffffffffff16631698ee82897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2878660048110610507576105076133bc565b60200201516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015262ffffff166044820152606401602060405180830381865afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ac91906133eb565b905073ffffffffffffffffffffffffffffffffffffffff81166105cf57506106b0565b60008173ffffffffffffffffffffffffffffffffffffffff16631a6865026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561061c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106409190613408565b905073ffffffffffffffffffffffffffffffffffffffff871615806106885750836fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff16115b156106ad578196508483600481106106a2576106a26133bc565b602002015195508093505b50505b6106b981613469565b905061048c565b50505073ffffffffffffffffffffffffffffffffffffffff8216610745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6e6f2d756e69737761702d706f6f6c2d617661696c00000000000000000060448201526064015b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1661076685836115b4565b73ffffffffffffffffffffffffffffffffffffffff16146107e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6261642d756e69737761702d706f6f6c2d61646472000000000000000000604482015260640161073c565b6002835262ffffff811660208401526040517f32148f670000000000000000000000000000000000000000000000000000000081526090600482015273ffffffffffffffffffffffffffffffffffffffff8316906332148f6790602401600060405180830381600087803b15801561085a57600080fd5b505af192505050801561086b575060015b6109d3576108776134a2565b806308c379a01415610996575061088c6134be565b806108975750610998565b805160208201207fe01ebc6b01bbf458b3d355b6e649efe64599751670c5d19175619893ecf975291415610927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f652f7269736b2f756e69737761702d706f6f6c2d6e6f742d696e697465640000604482015260640161073c565b80604051602001610938919061358b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261073c916004016135d0565b505b3d8080156109c2576040519150601f19603f3d011682016040523d82523d6000602084013e6109c7565b606091505b506109d18161173b565b505b50505b919050565b6000806000806109ea85611382565b805173ffffffffffffffffffffffffffffffffffffffff166000908152600960205260408120919250610a1d8783611529565b9050610a298184610e20565b909650945060008080610a3c84876117ac565b509194509250905061ffff821660011415610a6157670de0b6b3a76400009650610b9e565b61ffff821660021480610a78575061ffff82166003145b15610b3c576000610a898487611529565b90506000610a9785846115b4565b905060008173ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015610ae6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0a9190613621565b5050505050509050610b32838273ffffffffffffffffffffffffffffffffffffffff16611916565b9950505050610b9e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f756e6b6e6f776e2d70726963696e672d7479706500000000000000000000604482015260640161073c565b5050505050509193909250565b6000610bb68261025b565b905080606001511580610bcd575080604001516001145b610c33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f626f72726f772d69736f6c6174696f6e2d76696f6c6174696f6e00000000604482015260640161073c565b602081015181511015610ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f636f6c6c61746572616c2d76696f6c6174696f6e00000000000000000000604482015260640161073c565b5050565b60606000610cb383610eae565b90506000815167ffffffffffffffff811115610cd157610cd1613062565b604051908082528060200260200182016040528015610d0a57816020015b610cf7612f01565b815260200190600190039081610cef5790505b50604080516001808252818301909252919250600091906020808301908036833701905050905060005b8351811015610e1657838181518110610d4f57610d4f6133bc565b602002602001015182600081518110610d6a57610d6a6133bc565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250838281518110610db557610db56133bc565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff9091169052610de48683611047565b838281518110610df657610df66133bc565b60200260200101516020018190525080610e0f90613469565b9050610d34565b5090949350505050565b604051600090819081808080610e3689896117ac565b9350935093509350600161ffff168361ffff161415610e6757670de0b6b3a764000096508062ffffff169550610e9e565b61ffff831660021415610b3c576000610e8085846115b4565b9050610e928a828462ffffff16611a71565b9098509650610e9e9050565b5050505080604052509250929050565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526006602052604081205460609263ffffffff6601000000000000830416926a010000000000000000000090920416908267ffffffffffffffff811115610f1357610f13613062565b604051908082528060200260200182016040528015610f3c578160200160208202803683370190505b50905063ffffffff8316610f5257949350505050565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600760205260408120825190918491849190610f8c57610f8c6133bc565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260015b8463ffffffff1681101561103c5781816401000000008110610fd857610fd86133bc565b0154835173ffffffffffffffffffffffffffffffffffffffff90911690849083908110611007576110076133bc565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261103581613469565b9050610fb4565b509095945050505050565b61107460405180608001604052806000815260200160008152602001600081526020016000151581525090565b6000808252602080830182905260408084018390526060808501849052815160a08101835284815292830184905290820183905281018290526080810191909152604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c0810182905260005b855181101561137857600086828151811061114d5761114d6133bc565b6020026020010151905060008061116383611382565b805173ffffffffffffffffffffffffffffffffffffffff9081166000908152600960209081526040808320938f1683526005840190915290205491985096506dffffffffffffffffffffffffffff8116906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff1681158015906111f25750604089015163ffffffff1615155b1561127f5761120285898961208d565b5061120d878a610e20565b5060019450925060006112208884612500565b9050670de0b6b3a764000061123585836136c4565b61123f9190613730565b905063ee6b28008a6040015163ffffffff168261125c91906136c4565b6112669190613730565b9050808b60000181815161127a9190613744565b905250505b801561136257836112a85761129585898961208d565b506112a0878a610e20565b506001945092505b60408a018051906112b882613469565b9052506020890151156112cd57600160608b01525b60006112da89898f612533565b9050670de0b6b3a76400006112ef85836136c4565b6112f99190613730565b9050896060015163ffffffff16600014156113265771ffffffffffffffffffffffffffffffffffff611349565b60608a015163ffffffff1661133f63ee6b2800836136c4565b6113499190613730565b9050808b60200181815161135d9190613744565b905250505b50505050508061137190613469565b9050611130565b5050505092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff828116600090815260086020908152604091829020825160a081018452905493841680825274010000000000000000000000000000000000000000850460ff161515928201929092527501000000000000000000000000000000000000000000840463ffffffff90811693820193909352790100000000000000000000000000000000000000000000000000840490921660608301527d01000000000000000000000000000000000000000000000000000000000090920462ffffff166080820152906114eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640161073c565b606081015163ffffffff9081161415611509576342c1d80060608201525b608081015162ffffff908116141561029a57610708608082015292915050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c08101919091526115ad83838361208d565b5092915050565b6000827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff80821690831611156115fb57905b6040805173ffffffffffffffffffffffffffffffffffffffff808516602083015283169181019190915262ffffff851660608201527f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98490608001604051602081830303815290604052805190602001207fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b546040516020016116fc939291907fff00000000000000000000000000000000000000000000000000000000000000815260609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830191909152603582015260550190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012095945050505050565b80511561174a57805181602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f652f656d7074792d6572726f7200000000000000000000000000000000000000604482015260640161073c565b600080600080600361ffff1686610140015161ffff1614156118f057855173ffffffffffffffffffffffffffffffffffffffff9081166000908152600b602052604081205490911694506117ff85611382565b6080810151815173ffffffffffffffffffffffffffffffffffffffff16600090815260096020526040902080547a010000000000000000000000000000000000000000000000000000810461ffff1697507c0100000000000000000000000000000000000000000000000000000000900463ffffffff16955090935090915060038514156118e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f652f6e65737465642d70726963652d666f7277617264696e6700000000000000604482015260640161073c565b505061190d565b505083516101408501516101608601516080860151929450909250905b92959194509250565b60007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1610156119bc576101a08301516119ab83806119a6670de0b6b3a76400007801000000000000000000000000000000000000000000000000613730565b6125b5565b6119b59190613730565b9050611a36565b6119fd8283856101a00151670de0b6b3a76400006119da91906136c4565b6119a6907801000000000000000000000000000000000000000000000000613730565b905080611a1a57506ec097ce7bc90715b34b9f100000000061029a565b611a33816ec097ce7bc90715b34b9f1000000000613730565b90505b6ec097ce7bc90715b34b9f1000000000811115611a6357506ec097ce7bc90715b34b9f100000000061029a565b8061029a5750600192915050565b6040805160028082526060820183526000928392839290916020830190803683370190505090508381600081518110611aac57611aac6133bc565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110611adb57611adb6133bc565b602002602001019063ffffffff16908163ffffffff16815250506000808673ffffffffffffffffffffffffffffffffffffffff1663883bdbfd60e01b84604051602401611b28919061375c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611bb1919061379a565b600060405180830381855afa9150503d8060008114611bec576040519150601f19603f3d011682016040523d82523d6000602084013e611bf1565b606091505b509150915081611fe85760405160206024820152600360448201527f4f4c4400000000000000000000000000000000000000000000000000000000006064820152608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f08c379a000000000000000000000000000000000000000000000000000000000178152915190912082519183019190912014611cc857611cc88161173b565b6000808873ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3a9190613621565b5050509350935050506000808a73ffffffffffffffffffffffffffffffffffffffff1663252c09d784866001611d7091906137b6565b611d7a91906137dc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815261ffff9091166004820152602401608060405180830381865afa158015611dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df5919061380f565b93505050915080611e96576040517f252c09d70000000000000000000000000000000000000000000000000000000081526000600482015273ffffffffffffffffffffffffffffffffffffffff8c169063252c09d790602401608060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f919061380f565b5091935050505b611ea663ffffffff83164261386a565b99508987600081518110611ebc57611ebc6133bc565b602002602001019063ffffffff16908163ffffffff16815250508a73ffffffffffffffffffffffffffffffffffffffff1663883bdbfd60e01b88604051602401611f06919061375c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611f8f919061379a565b600060405180830381855afa9150503d8060008114611fca576040519150601f19603f3d011682016040523d82523d6000602084013e611fcf565b606091505b50909650945085611fe357611fe38561173b565b505050505b600081806020019051810190611ffe9190613881565b905060008782600081518110612016576120166133bc565b602002602001015183600181518110612031576120316133bc565b6020026020010151612043919061392f565b61204d9190613997565b9050600061205a82612682565b905061207c8b8273ffffffffffffffffffffffffffffffffffffffff16611916565b9b989a509798505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83168152815464ffffffffff811660a083015265010000000000810460ff90811660c084018190526601000000000000830463ffffffff90811660e08601526a01000000000000000000008404600b0b610100860152760100000000000000000000000000000000000000000000840481166101208601527a010000000000000000000000000000000000000000000000000000840461ffff166101408601527c010000000000000000000000000000000000000000000000000000000090930490921661016084015260018401547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16606084015260038401546dffffffffffffffffffffffffffff80821660208601526e01000000000000000000000000000090910471ffffffffffffffffffffffffffffffffffff166040850152600485015460808501526012839003909116600a0a6101a08401819052600092918161221257612212613701565b046101c084015260006122258430612a16565b9050836101c001518111612246576101a0840151810261018085015261224f565b60006101808501525b8360a0015164ffffffffff1642146124f7576001925060008460a0015164ffffffffff164261227e919061386a565b905060006b033b2e3c9fd0803ce800000086608001516122ca886101000151600b0b6b033b2e3c9fd0803ce80000006122b79190613a0b565b856b033b2e3c9fd0803ce8000000612b33565b6122d491906136c4565b6122de9190613730565b90506000866080015182886040015171ffffffffffffffffffffffffffffffffffff1661230b91906136c4565b6123159190613730565b606088015160208901519192506bffffffffffffffffffffffff16906dffffffffffffffffffffffffffff166000612355633b9aca0063ee6b28006136c4565b6101208b015163ffffffff90811614612373578a6101200151612379565b6336d616005b63ffffffff168b6040015171ffffffffffffffffffffffffffffffffffff16866123a3919061386a565b6123ad91906136c4565b6123b79190613730565b9050801561242f5760006123cf633b9aca0086613730565b8b61018001516123df9190613744565b90506123eb828261386a565b6123f584836136c4565b6123ff9190613730565b92508a602001516dffffffffffffffffffffffffffff1683612421919061386a565b61242b9085613744565b9350505b6dffffffffffffffffffffffffffff821180159061245f575071ffffffffffffffffffffffffffffffffffff8411155b156124f05761246d84612bf0565b71ffffffffffffffffffffffffffffffffffff1660408b015260808a0185905264ffffffffff421660a08b015260208a01516dffffffffffffffffffffffffffff1682146124f0576124be83612c98565b6bffffffffffffffffffffffff1660608b01526124da82612d36565b6dffffffffffffffffffffffffffff1660208b01525b5050505050505b50509392505050565b60008061250c84612db0565b9050670de0b6b3a764000061252182856136c4565b61252b9190613730565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600584016020526040812054633b9aca00906125a190859061259c908890839088906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff16612e47565b612ea3565b6125ab9190613730565b90505b9392505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050806000141561260d576000841161260257600080fd5b5082900490506125ae565b80841161261957600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008060008360020b12612699578260020b6126a1565b8260020b6000035b9050620d89e8811115612710576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f5400000000000000000000000000000000000000000000000000000000000000604482015260640161073c565b60006001821661273157700100000000000000000000000000000000612743565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615612777576ffff97272373d413259a46990580e213a0260801c5b6004821615612796576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b60088216156127b5576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b60108216156127d4576fffcb9843d60f6159c9db58835c9266440260801c5b60208216156127f3576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615612812576fff2ea16466c96a3843ec78b326b528610260801c5b6080821615612831576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615612851576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615612871576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615612891576ff3392b0822b70005940c7a398e4b70f30260801c5b6108008216156128b1576fe7159475a2c29b7443b29c7fa6e889d90260801c5b6110008216156128d1576fd097f3bdfd2022b8845ad8f792aa58250260801c5b6120008216156128f1576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615612911576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615612931576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615612952576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615612972576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615612991576d2216e584f5fa1ea926041bedfe980260801c5b620800008216156129ae576b048a170391f7dc42444e8fa20260801c5b60008460020b13156129ed57807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff816129e9576129e9613701565b0490505b640100000000810615612a01576001612a04565b60005b60ff16602082901c0192505050919050565b60408051835173ffffffffffffffffffffffffffffffffffffffff848116602480850191909152845180850390910181526044840185526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790529351600094859384931691614e2091612aad9161379a565b6000604051808303818686fa925050503d8060008114612ae9576040519150601f19603f3d011682016040523d82523d6000602084013e612aee565b606091505b5091509150811580612b01575060208151105b15612b1157600093505050612b2a565b80806020019051810190612b259190613a7f565b935050505b60405292915050565b6000838015612bd357600184168015612b4e57859250612b52565b8392505b50600283046002850494505b8415612bcd578586028687820414612b7557600080fd5b81810181811015612b8557600080fd5b8590049650506001851615612bc2578583028387820414158715151615612bab57600080fd5b81810181811015612bbb57600080fd5b8590049350505b600285049450612b5e565b50612be8565b838015612be357600092506124f7565b839250505b509392505050565b600071ffffffffffffffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f652f646562742d616d6f756e742d746f6f2d6c617267652d746f2d656e636f6460448201527f6500000000000000000000000000000000000000000000000000000000000000606482015260840161073c565b5090565b60006bffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f652f736d616c6c2d616d6f756e742d746f6f2d6c617267652d746f2d656e636f60448201527f6465000000000000000000000000000000000000000000000000000000000000606482015260840161073c565b60006dffffffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f616d6f756e742d746f6f2d6c617267652d746f2d656e636f646500000000604482015260640161073c565b600081602001516dffffffffffffffffffffffffffff1660001415612dde5750670de0b6b3a7640000919050565b81602001516dffffffffffffffffffffffffffff16633b9aca00836040015171ffffffffffffffffffffffffffffffffffff16612e1b9190613730565b836101800151612e2b9190613744565b612e3d90670de0b6b3a76400006136c4565b61029a9190613730565b600081612e565750600061252b565b73ffffffffffffffffffffffffffffffffffffffff831660009081526005860160205260409020600101546080850151612e9090846136c4565b612e9a9190613730565b95945050505050565b600081612eb25750600061029a565b6101a0830151633b9aca000280807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8582010181612ef257612ef2613701565b0402949350505050565b905290565b6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001612efc60405180608001604052806000815260200160008152602001600081526020016000151581525090565b73ffffffffffffffffffffffffffffffffffffffff81168114612f7857600080fd5b50565b80356109d681612f56565b600060208284031215612f9857600080fd5b81356125ae81612f56565b8151815260208083015190820152604080830151908201526060808301511515908201526080810161029a565b6020808252825182820181905260009190848201906040850190845b81811015613056578351805173ffffffffffffffffffffffffffffffffffffffff168452850151613042868501828051825260208101516020830152604081015160408301526060810151151560608301525050565b509284019260a09290920191600101612fec565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff821117156130d5576130d5613062565b6040525050565b6040516101e0810167ffffffffffffffff8111828210171561310057613100613062565b60405290565b80356dffffffffffffffffffffffffffff811681146109d657600080fd5b803571ffffffffffffffffffffffffffffffffffff811681146109d657600080fd5b80356bffffffffffffffffffffffff811681146109d657600080fd5b803564ffffffffff811681146109d657600080fd5b60ff81168114612f7857600080fd5b80356109d681613177565b63ffffffff81168114612f7857600080fd5b80356109d681613191565b8035600b81900b81146109d657600080fd5b61ffff81168114612f7857600080fd5b80356109d6816131c0565b8015158114612f7857600080fd5b600060a082840312156131fb57600080fd5b60405160a0810181811067ffffffffffffffff8211171561321e5761321e613062565b604052905080823561322f81612f56565b8152602083013561323f816131db565b6020820152604083013561325281613191565b6040820152606083013561326581613191565b6060820152608083013562ffffff8116811461328057600080fd5b6080919091015292915050565b6000808284036102808112156132a257600080fd5b6101e0808212156132b257600080fd5b6132ba6130dc565b91506132c585612f7b565b82526132d360208601613106565b60208301526132e460408601613124565b60408301526132f560608601613146565b60608301526080850135608083015261331060a08601613162565b60a083015261332160c08601613186565b60c083015261333260e086016131a3565b60e08301526101006133458187016131ae565b908301526101206133578682016131a3565b908301526101406133698682016131d0565b9083015261016061337b8682016131a3565b9083015261018085810135908301526101a080860135908301526101c0808601359083015290925082906133b1868287016131e9565b925050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156133fd57600080fd5b81516125ae81612f56565b60006020828403121561341a57600080fd5b81516fffffffffffffffffffffffffffffffff811681146125ae57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561349b5761349b61343a565b5060010190565b600060033d11156134bb5760046000803e5060005160e01c5b90565b600060443d10156134cc5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff816024840111818411171561351a57505050505090565b82850191508151818111156135325750505050505090565b843d870101602082850101111561354c5750505050505090565b61103c60208286010187613091565b60005b8381101561357657818101518382015260200161355e565b83811115613585576000848401525b50505050565b7f652f7269736b2f756e69737761702f00000000000000000000000000000000008152600082516135c381600f85016020870161355b565b91909101600f0192915050565b60208152600082518060208401526135ef81604085016020870161355b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600080600080600080600060e0888a03121561363c57600080fd5b875161364781612f56565b8097505060208801518060020b811461365f57600080fd5b6040890151909650613670816131c0565b6060890151909550613681816131c0565b6080890151909450613692816131c0565b60a08901519093506136a381613177565b60c08901519092506136b4816131db565b8091505092959891949750929550565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156136fc576136fc61343a565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261373f5761373f613701565b500490565b600082198211156137575761375761343a565b500190565b6020808252825182820181905260009190848201906040850190845b8181101561305657835163ffffffff1683529284019291840191600101613778565b600082516137ac81846020870161355b565b9190910192915050565b600061ffff8083168185168083038211156137d3576137d361343a565b01949350505050565b600061ffff808416806137f1576137f1613701565b92169190910692915050565b8051600681900b81146109d657600080fd5b6000806000806080858703121561382557600080fd5b845161383081613191565b935061383e602086016137fd565b9250604085015161384e81612f56565b606086015190925061385f816131db565b939692955090935050565b60008282101561387c5761387c61343a565b500390565b6000602080838503121561389457600080fd5b825167ffffffffffffffff808211156138ac57600080fd5b818501915085601f8301126138c057600080fd5b8151818111156138d2576138d2613062565b8060051b91506040516138e785840182613091565b8181529183018401918481018884111561390057600080fd5b938501935b8385101561392357613916856137fd565b8152938501938501613905565b50979650505050505050565b60008160060b8360060b60008112817fffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000018312811516156139725761397261343a565b81667fffffffffffff01831381161561398d5761398d61343a565b5090039392505050565b60008160060b8360060b806139ae576139ae613701565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffffffffffffffffffffff8000000000000083141615613a0257613a0261343a565b90059392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03841381151615613a4557613a4561343a565b827f8000000000000000000000000000000000000000000000000000000000000000038412811615613a7957613a7961343a565b50500190565b600060208284031215613a9157600080fd5b505191905056fea264697066735822122049da3334e4e4abd0c5d85f3a1e678e0ca391f95c3fb85f584b53ad8f03a4f2cb64736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a13000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
-----Decoded View---------------
Arg [0] : moduleGitCommit_ (bytes32): 0x00000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a13
Arg [1] : settings (tuple):
Arg [1] : referenceAsset (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : uniswapFactory (address): 0x1F98431c8aD98523631AE4a59f267346ea31F984
Arg [3] : uniswapPoolInitCodeHash (bytes32): 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a13
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984
Arg [3] : e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
Deployed Bytecode Sourcemap
1015:13425:11:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13336:182;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;9394:404;;;;;;:::i;:::-;;:::i;:::-;;;;1303:25:15;;;1359:2;1344:18;;1337:34;;;;1276:18;9394:404:11;1129:248:15;241:40:3;;;;;;;;1528:25:15;;;1516:2;1501:18;241:40:3;1382:177:15;1733:2679:11;;;;;;:::i;:::-;;:::i;:::-;;;;1807:13:15;;1822:6;1803:26;1785:45;;1877:4;1865:17;;;1859:24;1902:10;1950:21;;;1928:20;;;1921:51;2009:17;;;2003:24;2069:21;;2092:42;2065:70;2043:20;;;2036:100;2192:25;;;2186:32;2179:40;2172:48;2167:2;2152:18;;;2145:76;;;;2268:25;;;2262:32;2258:41;;2252:3;2237:19;;;2230:70;;;;2347:23;;;2341:30;2337:39;;;2331:3;2316:19;;2309:68;2424:24;;2418:31;2451:8;2414:46;2408:3;2393:19;;2386:75;1772:3;1757:19;1733:2679:11;1564:903:15;9991:1142:11;;;;;;:::i;:::-;;:::i;:::-;;;;2674:25:15;;;2730:2;2715:18;;2708:34;;;;2758:18;;;2751:34;2662:2;2647:18;9991:1142:11;2472:319:15;205:30:3;;;;;14106:332:11;;;;;;:::i;:::-;;:::i;:::-;;13524:576;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;8677:711::-;;;;;;:::i;:::-;;:::i;13336:182::-;13409:22;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13409:22:11;13450:61;13470:7;13479:31;13502:7;13479:22;:31::i;:::-;13450:19;:61::i;:::-;13443:68;13336:182;-1:-1:-1;;13336:182:11:o;9394:404::-;9464:9;9475:15;9502:25;9530:30;9549:10;9530:18;:30::i;:::-;9619:20;;9606:34;;9570:33;9606:34;;;:12;:34;;;;;9502:58;;-1:-1:-1;9681:42:11;9698:10;9606:34;9681:16;:42::i;:::-;9650:73;;9755:36;9772:10;9784:6;9755:16;:36::i;:::-;9734:57;;;;-1:-1:-1;9394:404:11;-1:-1:-1;;;;;9394:404:11:o;1733:2679::-;1812:28;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1812:28:11;1852:8;;;;;;1878:4;1852:23;;;;:30;1892:8;;1852:30;1892:25;;:37;;;;1939:8;;1892:37;1939:21;;;;:40;1989:8;2011:16;1989:19;;;;:38;2056:14;2042:28;;;;;;;;2038:2368;;;1689:1:4;2110:35:11;;:13;2159:19;;;:31;1733:2679;;;:::o;2038:2368::-;2211:38;:24;;;2247:1;2211:24;;;:12;:24;;;;;;;:38;2207:2199;;1807:1:4;2265:38:11;;:13;2317:19;;;;:31;;;2408:24;;;;;;:12;:24;;;;;;;;;;2391:42;;:16;:42;;;;;;;:59;2363:8;;;;2391:59;;;;2317:31;2391:59;2363:25;;:87;1733:2679;;;:::o;2207:2199::-;2960:55;;;;;;;;2992:4;2960:55;;2999:5;2960:55;;;;3006:3;2960:55;;;;;;;3011:3;2960:55;;;;2874:12;;;;;;3077:563;3098:11;3094:1;:15;3077:563;;;3138:21;3180:14;3162:41;;;3204:10;3216:14;3232:4;3237:1;3232:7;;;;;;;:::i;:::-;;;;;3162:78;;;;;;;;;;9537:42:15;9606:15;;;3162:78:11;;;9588:34:15;9658:15;;;;9638:18;;;9631:43;9722:8;9710:21;9690:18;;;9683:49;9500:18;;3162:78:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3138:102;-1:-1:-1;3266:27:11;;;3262:41;;3295:8;;;3262:41;3326:17;3361:13;3346:39;;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3326:61;-1:-1:-1;3414:18:11;;;;;:47;;;3448:13;3436:25;;:9;:25;;;3414:47;3410:212;;;3496:13;3489:20;;3541:4;3546:1;3541:7;;;;;;;:::i;:::-;;;;;3535:13;;3590:9;3574:25;;3410:212;3116:524;;3077:563;3111:3;;;:::i;:::-;;;3077:563;;;-1:-1:-1;;;3676:18:11;;;3668:54;;;;;;;10900:2:15;3668:54:11;;;10882:21:15;10939:2;10919:18;;;10912:30;10978:25;10958:18;;;10951:53;11021:18;;3668:54:11;;;;;;;;;3790:4;3744:50;;:42;3770:10;3782:3;3744:25;:42::i;:::-;:50;;;3736:86;;;;;;;11252:2:15;3736:86:11;;;11234:21:15;11291:2;11271:18;;;11264:30;11330:25;11310:18;;;11303:53;11373:18;;3736:86:11;11050:347:15;3736:86:11;1750:1:4;3837:42:11;;3915:11;;;3893:19;;;:33;3945:93;;;;;1146:3:4;3945:93:11;;;11546:38:15;3945:55:11;;;;;;11519:18:15;;3945:93:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3941:455;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;4135:21;;;;;;4160:16;4135:41;4131:87;;;4178:40;;;;;12717:2:15;4178:40:11;;;12699:21:15;12756:2;12736:18;;;12729:30;12795:32;12775:18;;;12768:60;12845:18;;4178:40:11;12515:354:15;4131:87:11;4286:3;4250:40;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;4236:56;;;;;;;;:::i;3941:455::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4358:23;4370:10;4358:11;:23::i;:::-;4308:88;3941:455;2467:1939;;2207:2199;1733:2679;;;:::o;9991:1142::-;10065:9;10076:15;10093:14;10119:25;10147:30;10166:10;10147:18;:30::i;:::-;10236:20;;10223:34;;10187:33;10223:34;;;:12;:34;;;;;10119:58;;-1:-1:-1;10298:42:11;10315:10;10223:34;10298:16;:42::i;:::-;10267:73;;10372:36;10389:10;10401:6;10372:16;:36::i;:::-;10351:57;;-1:-1:-1;10351:57:11;-1:-1:-1;10420:21:11;;;10492:40;10513:10;10525:6;10492:20;:40::i;:::-;-1:-1:-1;10419:113:11;;-1:-1:-1;10419:113:11;-1:-1:-1;10419:113:11;-1:-1:-1;10547:34:11;;;1689:1:4;10547:34:11;10543:584;;;10609:4;10597:16;;10543:584;;;10634:41;;;1750:1:4;10634:41:11;;:82;;-1:-1:-1;10679:37:11;;;1807:1:4;10679:37:11;10634:82;10630:497;;;10732:31;10766:45;10783:13;10798:12;10766:16;:45::i;:::-;10732:79;;10825:12;10840:67;10866:13;10888:17;10840:25;:67::i;:::-;10825:82;;10922:20;10967:4;10952:26;;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10921:59;;;;;;;;11006:47;11025:13;11040:12;11006:47;;:18;:47::i;:::-;10994:59;;10718:346;;;10630:497;;;11084:32;;;;;15301:2:15;11084:32:11;;;15283:21:15;15340:2;15320:18;;;15313:30;15379:24;15359:18;;;15352:52;15421:18;;11084:32:11;15099:346:15;10630:497:11;10109:1024;;;;;;9991:1142;;;;;:::o;14106:332::-;14182:29;14214:25;14231:7;14214:16;:25::i;:::-;14182:57;;14259:6;:21;;;14258:22;:48;;;;14284:6;:17;;;14305:1;14284:22;14258:48;14250:89;;;;;;;15652:2:15;14250:89:11;;;15634:21:15;15691:2;15671:18;;;15664:30;15730;15710:18;;;15703:58;15778:18;;14250:89:11;15450:352:15;14250:89:11;14383:21;;;;14357:22;;:47;;14349:82;;;;;;;16009:2:15;14349:82:11;;;15991:21:15;16048:2;16028:18;;;16021:30;16087:24;16067:18;;;16060:52;16129:18;;14349:82:11;15807:346:15;14349:82:11;14172:266;14106:332;:::o;13524:576::-;13606:23;13641:28;13672:31;13695:7;13672:22;:31::i;:::-;13641:62;;13714:30;13768:11;:18;13747:40;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;13834:16:11;;;13848:1;13834:16;;;;;;;;;13714:73;;-1:-1:-1;13798:33:11;;13834:16;;;;;;;;;;;;-1:-1:-1;13834:16:11;13798:52;;13866:6;13861:209;13882:11;:18;13878:1;:22;13861:209;;;13966:11;13978:1;13966:14;;;;;;;;:::i;:::-;;;;;;;13944:16;13961:1;13944:19;;;;;;;;:::i;:::-;;;;;;:36;;;;;;;;;;13921:6;13928:1;13921:9;;;;;;;;:::i;:::-;;;;;;;;;;;:59;;;;;;14013:46;14033:7;14042:16;14013:19;:46::i;:::-;13994:6;14001:1;13994:9;;;;;;;;:::i;:::-;;;;;;;:16;;:65;;;;13902:3;;;;:::i;:::-;;;13861:209;;;-1:-1:-1;14087:6:11;;13524:576;-1:-1:-1;;;;13524:576:11:o;8677:711::-;2125:4:0;2119:11;8789:9:11;;;;;;;;8915:40:::1;8936:10:::0;8948:6;8915:20:::1;:40::i;:::-;8827:128;;;;;;;;1689:1:4;8970:34:11;;:11;:34;;;8966:416;;;9027:4;9020:11;;9058:10;9045:23;;;;8966:416;;;9089:41;::::0;::::1;1750:1:4;9089:41:11;9085:297;;;9146:12;9161:64;9187:10;9206:17;9161:25;:64::i;:::-;9146:79;;9260:48;9279:10;9291:4;9297:10;9260:48;;:18;:48::i;:::-;9239:69:::0;;-1:-1:-1;9239:69:11;-1:-1:-1;9085:297:11::1;::::0;-1:-1:-1;9085:297:11::1;;8817:571;;;;2518:14:0::0;2512:4;2505:28;2491:52;8677:711:11;;;;;:::o;846:631:2:-;973:22;;;;946:24;973:22;;;:13;:22;;;;;:40;918:16;;973:40;;;;;;1052:41;;;;;;973:40;1130:32;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1130:32:2;-1:-1:-1;1104:58:2;-1:-1:-1;1176:22:2;;;1172:41;;1207:6;846:631;-1:-1:-1;;;;846:631:2:o;1172:41::-;1280:23;;;1224:53;1280:23;;;:14;:23;;;;;1314:9;;1280:23;;1326:18;;1314:6;;1224:53;1314:9;;;;:::i;:::-;:30;;;;:9;;;;;;;;;;;:30;1369:1;1355:92;1376:17;1372:21;;:1;:21;1355:92;;;1426:7;1434:1;1426:10;;;;;;;:::i;:::-;;;1414:9;;1426:10;;;;;1414:6;;1421:1;;1414:9;;;;;;:::i;:::-;:22;;;;:9;;;;;;;;;;;:22;1395:3;;;:::i;:::-;;;1355:92;;;-1:-1:-1;1464:6:2;;846:631;-1:-1:-1;;;;;846:631:2:o;11158:2172:11:-;11256:29;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11256:29:11;11322:1;11297:26;;;11333:21;;;;:25;;;11368:17;;;;:21;;;11399;;;;:29;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11474:33:11;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11561:6:11;11556:1768;11577:11;:18;11573:1;:22;11556:1768;;;11616:18;11637:11;11649:1;11637:14;;;;;;;;:::i;:::-;;;;;;;11616:35;;11665:29;11716:10;11750:30;11769:10;11750:18;:30::i;:::-;11822:20;;11809:34;;;;;;;;:12;:34;;;;;;;;11873:27;;;;;:18;;;:27;;;;;:35;11822:20;;-1:-1:-1;11809:34:11;-1:-1:-1;11873:35:11;;;;11934:32;;;;;11985:12;;;;;:44;;-1:-1:-1;12001:23:11;;;;:28;;;;11985:44;11981:561;;;12049:52;12064:10;12076:12;12090:10;12049:14;:52::i;:::-;;12130:36;12147:10;12159:6;12130:16;:36::i;:::-;-1:-1:-1;12211:4:11;;-1:-1:-1;12119:47:11;-1:-1:-1;12234:20:11;12257:46;12283:10;12295:7;12257:25;:46::i;:::-;12234:69;-1:-1:-1;12365:4:11;12339:23;12357:5;12234:69;12339:23;:::i;:::-;:30;;;;:::i;:::-;12321:48;;736:13:4;12423:6:11;:23;;;12405:41;;:15;:41;;;;:::i;:::-;:63;;;;:::i;:::-;12387:81;;12512:15;12486:6;:22;;:41;;;;;;;:::i;:::-;;;-1:-1:-1;;11981:561:11;12560:9;;12556:758;;12594:24;12589:246;;12642:52;12657:10;12669:12;12683:10;12642:14;:52::i;:::-;;12727:36;12744:10;12756:6;12727:16;:36::i;:::-;-1:-1:-1;12812:4:11;;-1:-1:-1;12716:47:11;-1:-1:-1;12589:246:11;12853:17;;;:19;;;;;;:::i;:::-;;;-1:-1:-1;12894:21:11;;;;12890:55;;;12941:4;12917:21;;;:28;12890:55;12964:19;12986:49;13001:12;13015:10;13027:7;12986:14;:49::i;:::-;12964:71;-1:-1:-1;13095:4:11;13070:22;13087:5;12964:71;13070:22;:::i;:::-;:29;;;;:::i;:::-;13053:46;;13134:6;:19;;;:24;;13157:1;13134:24;;:108;;418:17:4;13134:108:11;;;13200:19;;;;13161:58;;:36;736:13:4;13161:14:11;:36;:::i;:::-;:58;;;;:::i;:::-;13117:125;;13285:14;13260:6;:21;;:39;;;;;;;:::i;:::-;;;-1:-1:-1;;12556:758:11;11602:1722;;;;;11597:3;;;;:::i;:::-;;;11556:1768;;;;11287:2043;;;11158:2172;;;;:::o;4431:466:2:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4560:28:2;;;;4532:25;4560:28;;;:16;:28;;;;;;;;;4532:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4598:69;;;;;;;17040:2:15;4598:69:2;;;17022:21:15;17079:2;17059:18;;;17052:30;17118:24;17098:18;;;17091:52;17160:18;;4598:69:2;16838:346:15;4598:69:2;4682:19;;;;4705:16;4682:39;;;;4678:88;;;1279:20:4;4723:19:2;;;:43;4678:88;4780:17;;;;4801:16;4780:37;;;;4776:90;;;1210:7:4;4819:17:2;;;:47;4884:6;4431:466;-1:-1:-1;;4431:466:2:o;9715:203::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9859:52:2;9874:10;9886:12;9900:10;9859:14;:52::i;:::-;;9715:203;;;;:::o;4436:508:11:-;4525:7;4561:10;4598:14;4626:15;;;;;;;;4622:56;;;4663:6;4622:56;4840:31;;;9537:42:15;9606:15;;;4840:31:11;;;9588:34:15;9658:15;;9638:18;;;9631:43;;;;9722:8;9710:21;;9690:18;;;9683:49;4795:14:11;;9500:18:15;;4840:31:11;;;;;;;;;;;;4830:42;;;;;;4893:23;4730:203;;;;;;;;;17487:66:15;17475:79;;17591:2;17587:15;;;;17604:66;17583:88;17579:1;17570:11;;17563:109;17697:2;17688:12;;17681:28;;;;17734:2;17725:12;;17718:28;17771:2;17762:12;;17189:591;4730:203:11;;;;;;;;;;;;;;4720:214;;4730:203;4720:214;;;;;4436:508;-1:-1:-1;;;;;4436:508:11:o;2580:232:0:-;2650:13;;:17;2646:126;;2740:6;2734:13;2725:6;2721:2;2717:15;2710:38;2646:126;2782:23;;;;;17987:2:15;2782:23:0;;;17969:21:15;18026:2;18006:18;;;17999:30;18065:15;18045:18;;;18038:43;18098:18;;2782:23:0;17785:337:15;7687:984:11;7796:18;7816;7836:24;7862:17;1807:1:4;7895:48:11;;:10;:22;;;:48;;;7891:774;;;7985:21;;7972:35;;;;;;;;:12;:35;;;;;;;;;;-1:-1:-1;8053:30:11;7972:35;8053:18;:30::i;:::-;8110:20;;;;8197:23;;8184:37;;8145:36;8184:37;;;:12;:37;;;;;8249:27;;;;;;;;-1:-1:-1;8310:33:11;;;;;;-1:-1:-1;8110:20:11;;-1:-1:-1;8110:20:11;;-1:-1:-1;1807:1:4;8366:37:11;;;8358:75;;;;;;;18329:2:15;8358:75:11;;;18311:21:15;18368:2;18348:18;;;18341:30;18407:27;18387:18;;;18380:55;18452:18;;8358:75:11;18127:349:15;8358:75:11;7945:499;;7891:774;;;-1:-1:-1;;8477:21:11;;8526:22;;;;8582:28;;;;8637:17;;;;8477:21;;-1:-1:-1;8526:22:11;;-1:-1:-1;8582:28:11;7891:774;7687:984;;;;;;;:::o;4951:629::-;5050:10;5117:14;5076:56;;5084:10;:21;;;5076:56;;;5072:421;;;5226:35;;;;5156:67;5172:12;;5200:22;5218:4;5205:9;5200:22;:::i;:::-;5156:15;:67::i;:::-;:105;;;;:::i;:::-;5148:113;;5072:421;;;5300:107;5316:12;5330;5370:10;:35;;;5363:4;:42;;;;:::i;:::-;5344:62;;5349:9;5344:62;:::i;5300:107::-;5292:115;-1:-1:-1;5425:10:11;5421:27;;-1:-1:-1;5444:4:11;5437:11;;5421:27;5470:12;5477:5;5470:4;:12;:::i;:::-;5462:20;;5072:421;5515:4;5507:5;:12;5503:70;;;-1:-1:-1;5529:4:11;5503:70;;;5552:10;5548:25;;-1:-1:-1;5572:1:11;4951:629;;;;:::o;5586:2095::-;5742:15;;;5755:1;5742:15;;;;;;;;5690:4;;;;;;5742:15;;;;;;;;;;;;-1:-1:-1;5742:15:11;5712:45;;5792:3;5768:11;5780:1;5768:14;;;;;;;;:::i;:::-;;;;;;:28;;;;;;;;;;;5823:1;5806:11;5818:1;5806:14;;;;;;;;:::i;:::-;;;;;;:18;;;;;;;;;;;5836:12;5850:17;5871:4;:15;;5910:31;;;5943:11;5887:68;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5871:85;;;;5887:68;5871:85;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5835:121;;;;5972:7;5967:1260;;6028:47;;19614:2:15;6028:47:11;;;19596:21:15;19653:1;19633:18;;;19626:29;19691:5;19671:18;;;19664:33;19714:18;;6028:47:11;;;;;;;;;;;;;;;;;;;;;;;;;6018:58;;;;;5999:15;;;;;;;;;:77;5995:100;;6078:17;6090:4;6078:11;:17::i;:::-;6312:12;6326:18;6366:4;6351:26;;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6308:71;;;;;;;;;6395:25;6423:16;6458:4;6443:33;;;6491:11;6478:5;6486:1;6478:9;;;;:::i;:::-;6477:25;;;;:::i;:::-;6443:60;;;;;;;;;;11576:6:15;11564:19;;;6443:60:11;;;11546:38:15;11519:18;;6443:60:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6394:109;;;;;;6814:11;6809:80;;6853:36;;;;;6887:1;6853:36;;;1528:25:15;6853:33:11;;;;;;1501:18:15;;6853:36:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;6827:62:11;;-1:-1:-1;;;6809:80:11;6975:36;;;;:15;:36;:::i;:::-;6969:42;;7049:3;7025:11;7037:1;7025:14;;;;;;;;:::i;:::-;;;;;;:28;;;;;;;;;;;7086:4;:15;;7125:31;;;7158:11;7102:68;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7086:85;;;;7102:68;7086:85;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7068:103:11;;-1:-1:-1;7068:103:11;-1:-1:-1;7068:103:11;7185:31;;7199:17;7211:4;7199:11;:17::i;:::-;5981:1246;;;;5967:1260;7332:30;7376:4;7365:27;;;;;;;;;;;;:::i;:::-;7332:60;;7459:10;7532:3;7500:15;7516:1;7500:18;;;;;;;;:::i;:::-;;;;;;;7479:15;7495:1;7479:18;;;;;;;;:::i;:::-;;;;;;;:39;;;;:::i;:::-;7478:59;;;;:::i;:::-;7459:79;;7549:20;7572:33;7600:4;7572:27;:33::i;:::-;7549:56;;7624:44;7643:10;7655:12;7624:44;;:18;:44::i;:::-;7616:58;7670:3;;-1:-1:-1;5586:2095:11;;-1:-1:-1;;;;;;;;;5586:2095:11:o;5504:3513:2:-;5682:34;;;;;5796:42;;;;;5753:40;;;:85;5907:31;;;;;;;5875:29;;;:63;;;5979:30;;;;;;;5948:28;;;:61;6045:25;;;;;5796:42;6019:23;;:51;6104:23;;;;;6080:21;;;:47;6162:24;;;;;6137:22;;;:49;6227:30;;;;;;;6196:28;;;:61;5796:42;6296:27;;;;;;;;6268:25;;;:55;6361:26;;;;;;;;6334:24;;;:53;6423:25;;;;;;-1:-1:-1;6397:23:2;;:51;6492:32;;;;-1:-1:-1;6459:30:2;;:65;6628:2;:23;;;6623:29;;;6045:25;6623:29;6585:35;;;:67;;;-1:-1:-1;;5907:31:2;6623:29;6697:53;;;;:::i;:::-;;6666:28;;;:84;6771:13;6787:40;6666:10;6821:4;6787:13;:40::i;:::-;6771:56;;6853:10;:28;;;6841:8;:40;6837:207;;6942:35;;;;6931:46;;6909:19;;;:68;6837:207;;;7032:1;7010:19;;;:23;6837:207;7130:10;:40;;;7111:59;;:15;:59;7107:1904;;7194:4;7186:12;;7213:11;7245:10;:40;;;7227:58;;:15;:58;;;;:::i;:::-;7213:72;;7335:27;7469:4;7435:10;:30;;;7366:66;7385:10;:23;;;7381:28;;7412:4;7381:35;;;;:::i;:::-;7419:6;7427:4;7366:9;:66::i;:::-;:99;;;;:::i;:::-;7365:108;;;;:::i;:::-;7335:138;;7488:20;7562:10;:30;;;7537:22;7511:10;:23;;;:48;;;;;;:::i;:::-;:81;;;;:::i;:::-;7632:25;;;;7695:24;;;;7488:104;;-1:-1:-1;7607:50:2;;;7671:48;;7607:22;7952:43;490:3:4;824:13;7952:43:2;:::i;:::-;7829:21;;;;7854:16;7829:41;;;;:87;;7895:10;:21;;;7829:87;;;923:20:4;7829:87:2;7751:166;;7770:10;:23;;;7752:41;;:15;:41;;;;:::i;:::-;7751:166;;;;:::i;:::-;:245;;;;:::i;:::-;7734:262;-1:-1:-1;8015:14:2;;8011:311;;8049:15;8090:41;490:3:4;8090:15:2;:41;:::i;:::-;8067:10;:19;;;:65;;;;:::i;:::-;8049:83;-1:-1:-1;8202:22:2;8215:9;8049:83;8202:22;:::i;:::-;8169:29;8182:16;8169:10;:29;:::i;:::-;:56;;;;:::i;:::-;8150:75;;8283:10;:24;;;8264:43;;:16;:43;;;;:::i;:::-;8243:64;;;;:::i;:::-;;;8031:291;8011:311;280:17:4;8420:35:2;;;;;:78;;-1:-1:-1;418:17:4;8459:39:2;;;8420:78;8416:585;;;8544:33;8561:15;8544:16;:33::i;:::-;8518:59;;:23;;;:59;8595:30;;;:55;;;8668:66;8718:15;8668:66;:40;;;:66;8777:24;;;;8757:44;;;;8753:234;;8853:36;8871:17;8853;:36::i;:::-;8825:64;;:25;;;:64;8938:30;8951:16;8938:12;:30::i;:::-;8911:57;;:24;;;:57;8753:234;7172:1839;;;;;;7107:1904;5648:3369;;5504:3513;;;;;:::o;11611:220::-;11712:4;11728:17;11748:31;11768:10;11748:19;:31::i;:::-;11728:51;-1:-1:-1;11820:4:2;11796:21;11728:51;11796:6;:21;:::i;:::-;:28;;;;:::i;:::-;11789:35;11611:220;-1:-1:-1;;;;11611:220:2:o;17666:298::-;17897:27;;;17795:4;17897:27;;;:18;;;:27;;;;;:32;490:3:4;;17818:113:2;;17830:10;;17842:88;;17897:18;;17830:10;;17897:27;;:32;;;;;17842:19;:88::i;:::-;17818:11;:113::i;:::-;:139;;;;:::i;:::-;17811:146;;17666:298;;;;;;:::o;953:3809:12:-;1065:14;;;1593:6;1590:1;1587;1580:20;1629:1;1626;1622:9;1613:18;;1680:5;1676:2;1673:13;1665:5;1661:2;1657:14;1653:34;1644:43;;;1769:5;1778:1;1769:10;1765:179;;;1817:1;1803:11;:15;1795:24;;;;;;-1:-1:-1;1870:23:12;;;;-1:-1:-1;1920:13:12;;1765:179;2071:5;2057:11;:19;2049:28;;;;;;2354:17;2430:11;2427:1;2424;2417:25;3727:1;2827;2812:12;;:16;;2797:32;;2924:22;;;;3708:1;:15;;3707:21;;3954:17;;;3950:21;;3943:28;4012:17;;;4008:21;;4001:28;4071:17;;;4067:21;;4060:28;4130:17;;;4126:21;;4119:28;4189:17;;;4185:21;;4178:28;4249:17;;;4245:21;;;4238:28;;;2782:12;3296;;;3292:23;;;3288:31;;;2559:20;;;2548:32;;;3347:12;;;;2602:21;;3052:16;;;;3338:21;;;;4713:11;;;-1:-1:-1;;;;953:3809:12:o;1558:2611:14:-;1621:20;1671:15;1696:1;1689:4;:8;;;:57;;1740:4;1733:12;;1689:57;;;1716:4;1709:12;;1708:13;;1689:57;1671:75;-1:-1:-1;840:9:14;1764:33;;;1756:47;;;;;;;23816:2:15;1756:47:14;;;23798:21:15;23855:1;23835:18;;;23828:29;23893:3;23873:18;;;23866:31;23914:18;;1756:47:14;23614:324:15;1756:47:14;1814:13;1840:3;1830:13;;:93;;1888:35;1830:93;;;1851:34;1830:93;1814:109;;;-1:-1:-1;1947:3:14;1937:13;;:18;1933:83;;1974:34;1966:42;2013:3;1965:51;1933:83;2040:3;2030:13;;:18;2026:83;;2067:34;2059:42;2106:3;2058:51;2026:83;2133:3;2123:13;;:18;2119:83;;2160:34;2152:42;2199:3;2151:51;2119:83;2226:4;2216:14;;:19;2212:84;;2254:34;2246:42;2293:3;2245:51;2212:84;2320:4;2310:14;;:19;2306:84;;2348:34;2340:42;2387:3;2339:51;2306:84;2414:4;2404:14;;:19;2400:84;;2442:34;2434:42;2481:3;2433:51;2400:84;2508:4;2498:14;;:19;2494:84;;2536:34;2528:42;2575:3;2527:51;2494:84;2602:5;2592:15;;:20;2588:85;;2631:34;2623:42;2670:3;2622:51;2588:85;2697:5;2687:15;;:20;2683:85;;2726:34;2718:42;2765:3;2717:51;2683:85;2792:5;2782:15;;:20;2778:85;;2821:34;2813:42;2860:3;2812:51;2778:85;2887:5;2877:15;;:20;2873:85;;2916:34;2908:42;2955:3;2907:51;2873:85;2982:6;2972:16;;:21;2968:86;;3012:34;3004:42;3051:3;3003:51;2968:86;3078:6;3068:16;;:21;3064:86;;3108:34;3100:42;3147:3;3099:51;3064:86;3174:6;3164:16;;:21;3160:86;;3204:34;3196:42;3243:3;3195:51;3160:86;3270:6;3260:16;;:21;3256:86;;3300:34;3292:42;3339:3;3291:51;3256:86;3366:7;3356:17;;:22;3352:86;;3397:33;3389:41;3435:3;3388:50;3352:86;3462:7;3452:17;;:22;3448:85;;3493:32;3485:40;3530:3;3484:49;3448:85;3557:7;3547:17;;:22;3543:83;;3588:30;3580:38;3623:3;3579:47;3543:83;3650:7;3640:17;;:22;3636:78;;3681:25;3673:33;3711:3;3672:42;3636:78;3736:1;3729:4;:8;;;3725:47;;;3767:5;3747:17;:25;;;;;:::i;:::-;;3739:33;;3725:47;4131:7;4122:5;:17;:22;:30;;4151:1;4122:30;;;4147:1;4122:30;4105:48;;4115:2;4106:5;:11;;4105:48;4082:72;;1651:2512;;1558:2611;;;:::o;11837:857:2:-;2125:4:0;2119:11;;12105:21:2;;:32:::1;24107:55:15::0;;;12150:58:2::1;::::0;;::::1;24089:74:15::0;;;;12150:58:2;;;;;;;;;;24062:18:15;;;12150:58:2;;::::1;::::0;::::1;::::0;;::::1;;12173:25:::0;12150:58:::1;::::0;;12105:104;;11938:4;;;;;;12105:32:::1;::::0;12143:5:::1;::::0;12105:104:::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12069:140;;;;12605:7;12604:8;:28;;;;12630:2;12616:4;:11;:16;12604:28;12600:42;;;12641:1;12634:8;;;;;;12600:42;12671:4;12660:27;;;;;;;;;;;;:::i;:::-;12653:34;;;;2150:1:0;2512:4:::0;2505:28;11837:857:2;;-1:-1:-1;;11837:857:2:o;835:1036:13:-;899:6;947:1;949:53;;;;1048:9;;;1058:20;;;;1094:1;1089:6;;1041:56;;1058:20;1072:4;1067:9;;1041:56;;1136:1;1130:4;1126:12;1191:1;1188;1184:9;1179:14;;1173:668;1196:1;1173:668;;;1255:1;1252;1248:9;1303:1;1299;1295:2;1291:10;1288:17;1278:44;;1318:1;1316;1309:11;1278:44;1366:4;1362:2;1358:13;1407:2;1398:7;1395:15;1392:34;;;1422:1;1420;1413:11;1392:34;1452:18;;;;-1:-1:-1;;1494:8:13;;;1491:332;;;1546:1;1543;1539:9;1621:1;1617;1613:2;1609:10;1606:17;1599:25;1594:1;1587:9;1580:17;1576:49;1573:68;;;1637:1;1635;1628:11;1573:68;1689:4;1685:2;1681:13;1734:2;1725:7;1722:15;1719:34;;;1749:1;1747;1740:11;1719:34;1783:18;;;;-1:-1:-1;;1491:332:13;1211:1;1209;1205:8;1200:13;;1173:668;;;1177:18;940:915;;949:53;964:1;966:18;;;;999:1;994:6;;957:44;;966:18;979:4;974:9;;957:44;940:915;;835:1036;;;;;:::o;10645:196:2:-;10707:7;418:17:4;10734:30:2;;;10726:76;;;;;;;24565:2:15;10726:76:2;;;24547:21:15;24604:2;24584:18;;;24577:30;24643:34;24623:18;;;24616:62;24714:3;24694:18;;;24687:31;24735:19;;10726:76:2;24363:397:15;10726:76:2;-1:-1:-1;10827:6:2;10645:196::o;10442:197::-;10505:6;350:16:4;10531:31:2;;;10523:78;;;;;;;24967:2:15;10523:78:2;;;24949:21:15;25006:2;24986:18;;;24979:30;25045:34;25025:18;;;25018:62;25116:4;25096:18;;;25089:32;25138:19;;10523:78:2;24765:398:15;10254:182:2;10312:7;280:17:4;10339:25:2;;;10331:66;;;;;;;25370:2:15;10331:66:2;;;25352:21:15;25409:2;25389:18;;;25382:30;25448;25428:18;;;25421:58;25496:18;;10331:66:2;25168:352:15;10847:276:2;10928:4;10948:10;:24;;;:29;;10976:1;10948:29;10944:46;;;-1:-1:-1;10986:4:2;;10847:276;-1:-1:-1;10847:276:2:o;10944:46::-;11092:10;:24;;;11007:109;;490:3:4;11031:10:2;:23;;;:49;;;;;;:::i;:::-;11008:10;:19;;;:73;;;;:::i;:::-;11007:82;;11085:4;11007:82;:::i;:::-;:109;;;;:::i;16531:461::-;16676:4;16751:9;16747:23;;-1:-1:-1;16769:1:2;16762:8;;16747:23;16938:27;;;;;;;:18;;;:27;;;;;:47;;;16905:30;;;;16898:37;;:4;:37;:::i;:::-;:87;;;;:::i;:::-;16891:94;16531:461;-1:-1:-1;;;;;16531:461:2:o;17290:304::-;17374:4;17394:9;17390:23;;-1:-1:-1;17412:1:2;17405:8;;17390:23;17487:35;;;;490:3:4;17461:61:2;;;17544:16;:12;;;:16;17461:61;17543:26;;;;:::i;:::-;;:34;;17290:304;-1:-1:-1;;;;17290:304:2:o;-1:-1:-1:-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:154:15;100:42;93:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;69:93;14:154;:::o;173:134::-;241:20;;270:31;241:20;270:31;:::i;312:247::-;371:6;424:2;412:9;403:7;399:23;395:32;392:52;;;440:1;437;430:12;392:52;479:9;466:23;498:31;523:5;498:31;:::i;853:271::-;645:12;;633:25;;707:4;696:16;;;690:23;674:14;;;667:47;763:4;752:16;;;746:23;730:14;;;723:47;833:4;822:16;;;816:23;809:31;802:39;786:14;;;779:63;1053:3;1038:19;;1066:52;564:284;2978:904;3213:2;3265:21;;;3335:13;;3238:18;;;3357:22;;;3184:4;;3213:2;3436:15;;;;3410:2;3395:18;;;3184:4;3479:377;3493:6;3490:1;3487:13;3479:377;;;3552:13;;3594:9;;3605:42;3590:58;3578:71;;3688:11;;3682:18;3713:61;3761:12;;;3682:18;651:5;645:12;640:3;633:25;707:4;700:5;696:16;690:23;683:4;678:3;674:14;667:47;763:4;756:5;752:16;746:23;739:4;734:3;730:14;723:47;833:4;826:5;822:16;816:23;809:31;802:39;795:4;790:3;786:14;779:63;;;564:284;3713:61;-1:-1:-1;3831:15:15;;;;3803:4;3794:14;;;;;3515:1;3508:9;3479:377;;;-1:-1:-1;3873:3:15;;2978:904;-1:-1:-1;;;;;;2978:904:15:o;3887:184::-;3939:77;3936:1;3929:88;4036:4;4033:1;4026:15;4060:4;4057:1;4050:15;4076:308;4182:66;4177:2;4171:4;4167:13;4163:86;4155:6;4151:99;4316:6;4304:10;4301:22;4280:18;4268:10;4265:34;4262:62;4259:88;;;4327:18;;:::i;:::-;4363:2;4356:22;-1:-1:-1;;4076:308:15:o;4389:250::-;4456:2;4450:9;4498:6;4486:19;;4535:18;4520:34;;4556:22;;;4517:62;4514:88;;;4582:18;;:::i;:::-;4618:2;4611:22;4389:250;:::o;4644:184::-;4712:20;;4772:30;4761:42;;4751:53;;4741:81;;4818:1;4815;4808:12;4833:192;4901:20;;4961:38;4950:50;;4940:61;;4930:89;;5015:1;5012;5005:12;5030:179;5097:20;;5157:26;5146:38;;5136:49;;5126:77;;5199:1;5196;5189:12;5214:165;5281:20;;5341:12;5330:24;;5320:35;;5310:63;;5369:1;5366;5359:12;5384:114;5468:4;5461:5;5457:16;5450:5;5447:27;5437:55;;5488:1;5485;5478:12;5503:130;5569:20;;5598:29;5569:20;5598:29;:::i;5638:121::-;5723:10;5716:5;5712:22;5705:5;5702:33;5692:61;;5749:1;5746;5739:12;5764:132;5831:20;;5860:30;5831:20;5860:30;:::i;5901:161::-;5967:20;;6027:2;6016:21;;;6006:32;;5996:60;;6052:1;6049;6042:12;6067:117;6152:6;6145:5;6141:18;6134:5;6131:29;6121:57;;6174:1;6171;6164:12;6189:132;6256:20;;6285:30;6256:20;6285:30;:::i;6326:118::-;6412:5;6405:13;6398:21;6391:5;6388:32;6378:60;;6434:1;6431;6424:12;6449:1066;6507:5;6555:4;6543:9;6538:3;6534:19;6530:30;6527:50;;;6573:1;6570;6563:12;6527:50;6606:2;6600:9;6648:4;6640:6;6636:17;6719:6;6707:10;6704:22;6683:18;6671:10;6668:34;6665:62;6662:88;;;6730:18;;:::i;:::-;6766:2;6759:22;6799:6;-1:-1:-1;6799:6:15;6829:23;;6861:33;6829:23;6861:33;:::i;:::-;6903:23;;6978:2;6963:18;;6950:32;6991:30;6950:32;6991:30;:::i;:::-;7049:2;7037:15;;7030:32;7114:2;7099:18;;7086:32;7127;7086;7127;:::i;:::-;7187:2;7175:15;;7168:32;7252:2;7237:18;;7224:32;7265;7224;7265;:::i;:::-;7325:2;7313:15;;7306:32;7390:3;7375:19;;7362:33;7439:8;7426:22;;7414:35;;7404:63;;7463:1;7460;7453:12;7404:63;7495:3;7483:16;;;;7476:33;6449:1066;;-1:-1:-1;;6449:1066:15:o;7520:1613::-;7644:6;7652;7696:9;7687:7;7683:23;7726:3;7722:2;7718:12;7715:32;;;7743:1;7740;7733:12;7715:32;7766:6;7792:2;7788;7784:11;7781:31;;;7808:1;7805;7798:12;7781:31;7834:17;;:::i;:::-;7821:30;;7874:29;7893:9;7874:29;:::i;:::-;7867:5;7860:44;7936:38;7970:2;7959:9;7955:18;7936:38;:::i;:::-;7931:2;7924:5;7920:14;7913:62;8007:38;8041:2;8030:9;8026:18;8007:38;:::i;:::-;8002:2;7995:5;7991:14;7984:62;8078:37;8111:2;8100:9;8096:18;8078:37;:::i;:::-;8073:2;8066:5;8062:14;8055:61;8177:3;8166:9;8162:19;8149:33;8143:3;8136:5;8132:15;8125:58;8216:38;8249:3;8238:9;8234:19;8216:38;:::i;:::-;8210:3;8203:5;8199:15;8192:63;8288:37;8320:3;8309:9;8305:19;8288:37;:::i;:::-;8282:3;8275:5;8271:15;8264:62;8359:38;8392:3;8381:9;8377:19;8359:38;:::i;:::-;8353:3;8346:5;8342:15;8335:63;8417:3;8452:36;8484:2;8473:9;8469:18;8452:36;:::i;:::-;8436:14;;;8429:60;8508:3;8543:37;8561:18;;;8543:37;:::i;:::-;8527:14;;;8520:61;8600:3;8635:37;8653:18;;;8635:37;:::i;:::-;8619:14;;;8612:61;8692:3;8727:37;8745:18;;;8727:37;:::i;:::-;8711:14;;;8704:61;8784:3;8832:18;;;8819:32;8803:14;;;8796:56;8871:3;8919:18;;;8906:32;8890:14;;;8883:56;8958:3;9006:18;;;8993:32;8977:14;;;8970:56;8715:5;;-1:-1:-1;8715:5:15;;9069:58;9119:7;9099:18;;;9069:58;:::i;:::-;9059:68;;;;7520:1613;;;;;:::o;9138:184::-;9190:77;9187:1;9180:88;9287:4;9284:1;9277:15;9311:4;9308:1;9301:15;9743:251;9813:6;9866:2;9854:9;9845:7;9841:23;9837:32;9834:52;;;9882:1;9879;9872:12;9834:52;9914:9;9908:16;9933:31;9958:5;9933:31;:::i;9999:305::-;10069:6;10122:2;10110:9;10101:7;10097:23;10093:32;10090:52;;;10138:1;10135;10128:12;10090:52;10170:9;10164:16;10220:34;10213:5;10209:46;10202:5;10199:57;10189:85;;10270:1;10267;10260:12;10309:184;10361:77;10358:1;10351:88;10458:4;10455:1;10448:15;10482:4;10479:1;10472:15;10498:195;10537:3;10568:66;10561:5;10558:77;10555:103;;;10638:18;;:::i;:::-;-1:-1:-1;10685:1:15;10674:13;;10498:195::o;11595:179::-;11630:3;11672:1;11654:16;11651:23;11648:120;;;11718:1;11715;11712;11697:23;-1:-1:-1;11755:1:15;11749:8;11744:3;11740:18;11648:120;11595:179;:::o;11779:731::-;11818:3;11860:4;11842:16;11839:26;11836:39;;;11779:731;:::o;11836:39::-;11902:2;11896:9;11924:66;12045:2;12027:16;12023:25;12020:1;12014:4;11999:50;12078:4;12072:11;12102:16;12137:18;12208:2;12201:4;12193:6;12189:17;12186:25;12181:2;12173:6;12170:14;12167:45;12164:58;;;12215:5;;;;;11779:731;:::o;12164:58::-;12252:6;12246:4;12242:17;12231:28;;12288:3;12282:10;12315:2;12307:6;12304:14;12301:27;;;12321:5;;;;;;11779:731;:::o;12301:27::-;12405:2;12386:16;12380:4;12376:27;12372:36;12365:4;12356:6;12351:3;12347:16;12343:27;12340:69;12337:82;;;12412:5;;;;;;11779:731;:::o;12337:82::-;12428:57;12479:4;12470:6;12462;12458:19;12454:30;12448:4;12428:57;:::i;12874:258::-;12946:1;12956:113;12970:6;12967:1;12964:13;12956:113;;;13046:11;;;13040:18;13027:11;;;13020:39;12992:2;12985:10;12956:113;;;13087:6;13084:1;13081:13;13078:48;;;13122:1;13113:6;13108:3;13104:16;13097:27;13078:48;;12874:258;;;:::o;13137:434::-;13399:17;13394:3;13387:30;13369:3;13446:6;13440:13;13462:62;13517:6;13512:2;13507:3;13503:12;13496:4;13488:6;13484:17;13462:62;:::i;:::-;13544:16;;;;13562:2;13540:25;;13137:434;-1:-1:-1;;13137:434:15:o;13576:442::-;13725:2;13714:9;13707:21;13688:4;13757:6;13751:13;13800:6;13795:2;13784:9;13780:18;13773:34;13816:66;13875:6;13870:2;13859:9;13855:18;13850:2;13842:6;13838:15;13816:66;:::i;:::-;13934:2;13922:15;13939:66;13918:88;13903:104;;;;14009:2;13899:113;;13576:442;-1:-1:-1;;13576:442:15:o;14023:1071::-;14137:6;14145;14153;14161;14169;14177;14185;14238:3;14226:9;14217:7;14213:23;14209:33;14206:53;;;14255:1;14252;14245:12;14206:53;14287:9;14281:16;14306:31;14331:5;14306:31;:::i;:::-;14356:5;14346:15;;;14406:2;14395:9;14391:18;14385:25;14455:7;14452:1;14441:22;14432:7;14429:35;14419:63;;14478:1;14475;14468:12;14419:63;14553:2;14538:18;;14532:25;14501:7;;-1:-1:-1;14566:32:15;14532:25;14566:32;:::i;:::-;14669:2;14654:18;;14648:25;14617:7;;-1:-1:-1;14682:32:15;14648:25;14682:32;:::i;:::-;14785:3;14770:19;;14764:26;14733:7;;-1:-1:-1;14799:32:15;14764:26;14799:32;:::i;:::-;14902:3;14887:19;;14881:26;14850:7;;-1:-1:-1;14916:31:15;14881:26;14916:31;:::i;:::-;15018:3;15003:19;;14997:26;14966:7;;-1:-1:-1;15032:30:15;14997:26;15032:30;:::i;:::-;15081:7;15071:17;;;14023:1071;;;;;;;;;;:::o;16158:228::-;16198:7;16324:1;16256:66;16252:74;16249:1;16246:81;16241:1;16234:9;16227:17;16223:105;16220:131;;;16331:18;;:::i;:::-;-1:-1:-1;16371:9:15;;16158:228::o;16391:184::-;16443:77;16440:1;16433:88;16540:4;16537:1;16530:15;16564:4;16561:1;16554:15;16580:120;16620:1;16646;16636:35;;16651:18;;:::i;:::-;-1:-1:-1;16685:9:15;;16580:120::o;16705:128::-;16745:3;16776:1;16772:6;16769:1;16766:13;16763:39;;;16782:18;;:::i;:::-;-1:-1:-1;16818:9:15;;16705:128::o;18481:647::-;18650:2;18702:21;;;18772:13;;18675:18;;;18794:22;;;18621:4;;18650:2;18873:15;;;;18847:2;18832:18;;;18621:4;18916:186;18930:6;18927:1;18924:13;18916:186;;;18995:13;;19010:10;18991:30;18979:43;;19077:15;;;;19042:12;;;;18952:1;18945:9;18916:186;;19133:274;19262:3;19300:6;19294:13;19316:53;19362:6;19357:3;19350:4;19342:6;19338:17;19316:53;:::i;:::-;19385:16;;;;;19133:274;-1:-1:-1;;19133:274:15:o;19743:224::-;19782:3;19810:6;19843:2;19840:1;19836:10;19873:2;19870:1;19866:10;19904:3;19900:2;19896:12;19891:3;19888:21;19885:47;;;19912:18;;:::i;:::-;19948:13;;19743:224;-1:-1:-1;;;;19743:224:15:o;19972:179::-;20003:1;20029:6;20062:2;20059:1;20055:10;20084:3;20074:37;;20091:18;;:::i;:::-;20129:10;;20125:20;;;;;19972:179;-1:-1:-1;;19972:179:15:o;20350:164::-;20427:13;;20480:1;20469:20;;;20459:31;;20449:59;;20504:1;20501;20494:12;20519:593;20610:6;20618;20626;20634;20687:3;20675:9;20666:7;20662:23;20658:33;20655:53;;;20704:1;20701;20694:12;20655:53;20736:9;20730:16;20755:30;20779:5;20755:30;:::i;:::-;20804:5;-1:-1:-1;20828:47:15;20871:2;20856:18;;20828:47;:::i;:::-;20818:57;;20920:2;20909:9;20905:18;20899:25;20933:33;20958:7;20933:33;:::i;:::-;21037:2;21022:18;;21016:25;20985:7;;-1:-1:-1;21050:30:15;21016:25;21050:30;:::i;:::-;20519:593;;;;-1:-1:-1;20519:593:15;;-1:-1:-1;;20519:593:15:o;21307:125::-;21347:4;21375:1;21372;21369:8;21366:34;;;21380:18;;:::i;:::-;-1:-1:-1;21417:9:15;;21307:125::o;21437:997::-;21530:6;21561:2;21604;21592:9;21583:7;21579:23;21575:32;21572:52;;;21620:1;21617;21610:12;21572:52;21653:9;21647:16;21682:18;21723:2;21715:6;21712:14;21709:34;;;21739:1;21736;21729:12;21709:34;21777:6;21766:9;21762:22;21752:32;;21822:7;21815:4;21811:2;21807:13;21803:27;21793:55;;21844:1;21841;21834:12;21793:55;21873:2;21867:9;21895:2;21891;21888:10;21885:36;;;21901:18;;:::i;:::-;21947:2;21944:1;21940:10;21930:20;;21979:2;21973:9;21991:40;22027:2;22023;22019:11;22011:6;21991:40;:::i;:::-;22066:18;;;22142:11;;;22138:20;;;22100:15;;;22170:19;;;22167:39;;;22202:1;22199;22192:12;22167:39;22226:11;;;;22246:157;22262:6;22257:3;22254:15;22246:157;;;22328:32;22356:3;22328:32;:::i;:::-;22316:45;;22279:12;;;;22381;;22246:157;;;-1:-1:-1;22422:6:15;21437:997;-1:-1:-1;;;;;;;21437:997:15:o;22439:404::-;22477:4;22521:1;22518;22507:16;22557:1;22554;22543:16;22587:1;22582:3;22578:11;22698:3;22630:66;22626:76;22621:3;22617:86;22612:2;22605:10;22601:103;22598:129;;;22707:18;;:::i;:::-;22778:3;22760:16;22756:26;22751:3;22747:36;22743:2;22739:45;22736:71;;;22787:18;;:::i;:::-;-1:-1:-1;22824:13:15;;;22439:404;-1:-1:-1;;;22439:404:15:o;22848:389::-;22886:1;22927;22924;22913:16;22963:1;22960;22949:16;22984:3;22974:37;;22991:18;;:::i;:::-;23112:66;23107:3;23104:75;23035:66;23030:3;23027:75;23023:157;23020:183;;;23183:18;;:::i;:::-;23217:14;;;22848:389;-1:-1:-1;;;22848:389:15:o;23242:367::-;23281:3;23316:1;23313;23309:9;23425:1;23357:66;23353:74;23350:1;23346:82;23341:2;23334:10;23330:99;23327:125;;;23432:18;;:::i;:::-;23551:1;23483:66;23479:74;23476:1;23472:82;23468:2;23464:91;23461:117;;;23558:18;;:::i;:::-;-1:-1:-1;;23594:9:15;;23242:367::o;24174:184::-;24244:6;24297:2;24285:9;24276:7;24272:23;24268:32;24265:52;;;24313:1;24310;24303:12;24265:52;-1:-1:-1;24336:16:15;;24174:184;-1:-1:-1;24174:184:15:o
Swarm Source
ipfs://49da3334e4e4abd0c5d85f3a1e678e0ca391f95c3fb85f584b53ad8f03a4f2cb
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.