Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Sponsored
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Markets
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "../BaseLogic.sol"; import "../IRiskManager.sol"; import "../PToken.sol"; /// @notice Activating and querying markets, and maintaining entered markets lists contract Markets is BaseLogic { constructor(bytes32 moduleGitCommit_) BaseLogic(MODULEID__MARKETS, moduleGitCommit_) {} /// @notice Create an Euler pool and associated EToken and DToken addresses. /// @param underlying The address of an ERC20-compliant token. There must be an initialised uniswap3 pool for the underlying/reference asset pair. /// @return The created EToken, or the existing EToken if already activated. function activateMarket(address underlying) external nonReentrant returns (address) { require(pTokenLookup[underlying] == address(0), "e/markets/invalid-token"); return doActivateMarket(underlying); } function doActivateMarket(address underlying) private returns (address) { // Pre-existing if (underlyingLookup[underlying].eTokenAddress != address(0)) return underlyingLookup[underlying].eTokenAddress; // Validation require(trustedSenders[underlying].moduleId == 0 && underlying != address(this), "e/markets/invalid-token"); uint8 decimals = IERC20(underlying).decimals(); require(decimals <= 18, "e/too-many-decimals"); // Get risk manager parameters IRiskManager.NewMarketParameters memory params; { bytes memory result = callInternalModule(MODULEID__RISK_MANAGER, abi.encodeWithSelector(IRiskManager.getNewMarketParameters.selector, underlying)); (params) = abi.decode(result, (IRiskManager.NewMarketParameters)); } // Create proxies address childEToken = params.config.eTokenAddress = _createProxy(MODULEID__ETOKEN); address childDToken = _createProxy(MODULEID__DTOKEN); // Setup storage underlyingLookup[underlying] = params.config; dTokenLookup[childDToken] = childEToken; AssetStorage storage assetStorage = eTokenLookup[childEToken]; assetStorage.underlying = underlying; assetStorage.pricingType = params.pricingType; assetStorage.pricingParameters = params.pricingParameters; assetStorage.dTokenAddress = childDToken; assetStorage.lastInterestAccumulatorUpdate = uint40(block.timestamp); assetStorage.underlyingDecimals = decimals; assetStorage.interestRateModel = uint32(MODULEID__IRM_DEFAULT); assetStorage.reserveFee = type(uint32).max; // default assetStorage.interestAccumulator = INITIAL_INTEREST_ACCUMULATOR; emit MarketActivated(underlying, childEToken, childDToken); return childEToken; } /// @notice Create a pToken and activate it on Euler. pTokens are protected wrappers around assets that prevent borrowing. /// @param underlying The address of an ERC20-compliant token. There must already be an activated market on Euler for this underlying, and it must have a non-zero collateral factor. /// @return The created pToken, or an existing one if already activated. function activatePToken(address underlying) external nonReentrant returns (address) { if (reversePTokenLookup[underlying] != address(0)) return reversePTokenLookup[underlying]; { AssetConfig memory config = resolveAssetConfig(underlying); require(config.collateralFactor != 0, "e/ptoken/not-collateral"); } address pTokenAddr = address(new PToken(address(this), underlying)); pTokenLookup[pTokenAddr] = underlying; reversePTokenLookup[underlying] = pTokenAddr; emit PTokenActivated(underlying, pTokenAddr); doActivateMarket(pTokenAddr); return pTokenAddr; } // General market accessors /// @notice Given an underlying, lookup the associated EToken /// @param underlying Token address /// @return EToken address, or address(0) if not activated function underlyingToEToken(address underlying) external view returns (address) { return underlyingLookup[underlying].eTokenAddress; } /// @notice Given an underlying, lookup the associated DToken /// @param underlying Token address /// @return DToken address, or address(0) if not activated function underlyingToDToken(address underlying) external view returns (address) { return eTokenLookup[underlyingLookup[underlying].eTokenAddress].dTokenAddress; } /// @notice Given an underlying, lookup the associated PToken /// @param underlying Token address /// @return PToken address, or address(0) if it doesn't exist function underlyingToPToken(address underlying) external view returns (address) { return reversePTokenLookup[underlying]; } /// @notice Looks up the Euler-related configuration for a token, and resolves all default-value placeholders to their currently configured values. /// @param underlying Token address /// @return Configuration struct function underlyingToAssetConfig(address underlying) external view returns (AssetConfig memory) { return resolveAssetConfig(underlying); } /// @notice Looks up the Euler-related configuration for a token, and returns it unresolved (with default-value placeholders) /// @param underlying Token address /// @return config Configuration struct function underlyingToAssetConfigUnresolved(address underlying) external view returns (AssetConfig memory config) { config = underlyingLookup[underlying]; require(config.eTokenAddress != address(0), "e/market-not-activated"); } /// @notice Given an EToken address, looks up the associated underlying /// @param eToken EToken address /// @return underlying Token address function eTokenToUnderlying(address eToken) external view returns (address underlying) { underlying = eTokenLookup[eToken].underlying; require(underlying != address(0), "e/invalid-etoken"); } /// @notice Given an EToken address, looks up the associated DToken /// @param eToken EToken address /// @return dTokenAddr DToken address function eTokenToDToken(address eToken) external view returns (address dTokenAddr) { dTokenAddr = eTokenLookup[eToken].dTokenAddress; require(dTokenAddr != address(0), "e/invalid-etoken"); } function getAssetStorage(address underlying) private view returns (AssetStorage storage) { address eTokenAddr = underlyingLookup[underlying].eTokenAddress; require(eTokenAddr != address(0), "e/market-not-activated"); return eTokenLookup[eTokenAddr]; } /// @notice Looks up an asset's currently configured interest rate model /// @param underlying Token address /// @return Module ID that represents the interest rate model (IRM) function interestRateModel(address underlying) external view returns (uint) { AssetStorage storage assetStorage = getAssetStorage(underlying); return assetStorage.interestRateModel; } /// @notice Retrieves the current interest rate for an asset /// @param underlying Token address /// @return The interest rate in yield-per-second, scaled by 10**27 function interestRate(address underlying) external view returns (int96) { AssetStorage storage assetStorage = getAssetStorage(underlying); return assetStorage.interestRate; } /// @notice Retrieves the current interest rate accumulator for an asset /// @param underlying Token address /// @return An opaque accumulator that increases as interest is accrued function interestAccumulator(address underlying) external view returns (uint) { AssetStorage storage assetStorage = getAssetStorage(underlying); AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage); return assetCache.interestAccumulator; } /// @notice Retrieves the reserve fee in effect for an asset /// @param underlying Token address /// @return Amount of interest that is redirected to the reserves, as a fraction scaled by RESERVE_FEE_SCALE (4e9) function reserveFee(address underlying) external view returns (uint32) { AssetStorage storage assetStorage = getAssetStorage(underlying); return assetStorage.reserveFee == type(uint32).max ? uint32(DEFAULT_RESERVE_FEE) : assetStorage.reserveFee; } /// @notice Retrieves the pricing config for an asset /// @param underlying Token address /// @return pricingType (1=pegged, 2=uniswap3, 3=forwarded) /// @return pricingParameters If uniswap3 pricingType then this represents the uniswap pool fee used, otherwise unused /// @return pricingForwarded If forwarded pricingType then this is the address prices are forwarded to, otherwise address(0) function getPricingConfig(address underlying) external view returns (uint16 pricingType, uint32 pricingParameters, address pricingForwarded) { AssetStorage storage assetStorage = getAssetStorage(underlying); pricingType = assetStorage.pricingType; pricingParameters = assetStorage.pricingParameters; pricingForwarded = pricingType == PRICINGTYPE__FORWARDED ? pTokenLookup[underlying] : address(0); } // Enter/exit markets /// @notice Retrieves the list of entered markets for an account (assets enabled for collateral or borrowing) /// @param account User account /// @return List of underlying token addresses function getEnteredMarkets(address account) external view returns (address[] memory) { return getEnteredMarketsArray(account); } /// @notice Add an asset to the entered market list, or do nothing if already entered /// @param subAccountId 0 for primary, 1-255 for a sub-account /// @param newMarket Underlying token address function enterMarket(uint subAccountId, address newMarket) external nonReentrant { address msgSender = unpackTrailingParamMsgSender(); address account = getSubAccount(msgSender, subAccountId); require(underlyingLookup[newMarket].eTokenAddress != address(0), "e/market-not-activated"); doEnterMarket(account, newMarket); } /// @notice Remove an asset from the entered market list, or do nothing if not already present /// @param subAccountId 0 for primary, 1-255 for a sub-account /// @param oldMarket Underlying token address function exitMarket(uint subAccountId, address oldMarket) external nonReentrant { address msgSender = unpackTrailingParamMsgSender(); address account = getSubAccount(msgSender, subAccountId); AssetConfig memory config = resolveAssetConfig(oldMarket); AssetStorage storage assetStorage = eTokenLookup[config.eTokenAddress]; uint balance = assetStorage.users[account].balance; uint owed = assetStorage.users[account].owed; require(owed == 0, "e/outstanding-borrow"); doExitMarket(account, oldMarket); if (config.collateralFactor != 0 && balance != 0) { checkLiquidity(account); } } }
// 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) 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; function computeLiquidity(address account) external returns (LiquidityStatus memory status); function computeAssetLiquidities(address account) external returns (AssetLiquidity[] memory assets); function getPrice(address underlying) external returns (uint twap, uint twapPeriod); function getPriceFull(address underlying) external returns (uint twap, uint twapPeriod, uint currPrice); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./Interfaces.sol"; import "./Utils.sol"; /// @notice Protected Tokens are simple wrappers for tokens, allowing you to use tokens as collateral without permitting borrowing contract PToken { address immutable euler; address immutable underlyingToken; constructor(address euler_, address underlying_) { euler = euler_; underlyingToken = underlying_; } mapping(address => uint) balances; mapping(address => mapping(address => uint)) allowances; uint totalBalances; event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); /// @notice PToken name, ie "Euler Protected DAI" function name() external view returns (string memory) { return string(abi.encodePacked("Euler Protected ", IERC20(underlyingToken).name())); } /// @notice PToken symbol, ie "pDAI" function symbol() external view returns (string memory) { return string(abi.encodePacked("p", IERC20(underlyingToken).symbol())); } /// @notice Number of decimals, which is same as the underlying's function decimals() external view returns (uint8) { return IERC20(underlyingToken).decimals(); } /// @notice Address of the underlying asset function underlying() external view returns (address) { return underlyingToken; } /// @notice Balance of an account's wrapped tokens function balanceOf(address who) external view returns (uint) { return balances[who]; } /// @notice Sum of all wrapped token balances function totalSupply() external view returns (uint) { return totalBalances; } /// @notice Retrieve the current allowance /// @param holder Address giving permission to access tokens /// @param spender Trusted address function allowance(address holder, address spender) external view returns (uint) { return allowances[holder][spender]; } /// @notice Transfer your own pTokens to another address /// @param recipient Recipient address /// @param amount Amount of wrapped token to transfer function transfer(address recipient, uint amount) external returns (bool) { return transferFrom(msg.sender, recipient, amount); } /// @notice Transfer pTokens from one address to another. The euler address is automatically granted approval. /// @param from This address must've approved the to address /// @param recipient Recipient address /// @param amount Amount to transfer function transferFrom(address from, address recipient, uint amount) public returns (bool) { require(balances[from] >= amount, "insufficient balance"); if (from != msg.sender && msg.sender != euler && allowances[from][msg.sender] != type(uint).max) { require(allowances[from][msg.sender] >= amount, "insufficient allowance"); allowances[from][msg.sender] -= amount; emit Approval(from, msg.sender, allowances[from][msg.sender]); } balances[from] -= amount; balances[recipient] += amount; emit Transfer(from, recipient, amount); return true; } /// @notice Allow spender to access an amount of your pTokens. It is not necessary to approve the euler address. /// @param spender Trusted address /// @param amount Use max uint256 for "infinite" allowance function approve(address spender, uint amount) external returns (bool) { allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } /// @notice Convert underlying tokens to pTokens /// @param amount In underlying units (which are equivalent to pToken units) function wrap(uint amount) external { Utils.safeTransferFrom(underlyingToken, msg.sender, address(this), amount); claimSurplus(msg.sender); } /// @notice Convert pTokens to underlying tokens /// @param amount In pToken units (which are equivalent to underlying units) function unwrap(uint amount) external { doUnwrap(msg.sender, amount); } // Only callable by the euler contract: function forceUnwrap(address who, uint amount) external { require(msg.sender == euler, "permission denied"); doUnwrap(who, amount); } /// @notice Claim any surplus tokens held by the PToken contract. This should only be used by contracts. /// @param who Beneficiary to be credited for the surplus token amount function claimSurplus(address who) public { uint currBalance = IERC20(underlyingToken).balanceOf(address(this)); require(currBalance > totalBalances, "no surplus balance to claim"); uint amount = currBalance - totalBalances; totalBalances += amount; balances[who] += amount; emit Transfer(address(0), who, amount); } // Internal shared: function doUnwrap(address who, uint amount) private { require(balances[who] >= amount, "insufficient balance"); totalBalances -= amount; balances[who] -= amount; Utils.safeTransfer(underlyingToken, who, amount); emit Transfer(who, address(0), amount); } }
// 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 { mstore(0, 0) calldatacopy(12, sub(calldatasize(), 40), 20) msgSender := mload(0) } } function unpackTrailingParams() internal pure returns (address msgSender, address proxyAddr) { assembly { mstore(0, 0) calldatacopy(12, sub(calldatasize(), 40), 20) msgSender := mload(0) calldatacopy(12, sub(calldatasize(), 20), 20) proxyAddr := mload(0) } } // 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 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 = 10; 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; }
{ "optimizer": { "enabled": true, "runs": 1000000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"bytes32","name":"moduleGitCommit_","type":"bytes32"}],"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":"underlying","type":"address"}],"name":"activateMarket","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"activatePToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"eToken","type":"address"}],"name":"eTokenToDToken","outputs":[{"internalType":"address","name":"dTokenAddr","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"eToken","type":"address"}],"name":"eTokenToUnderlying","outputs":[{"internalType":"address","name":"underlying","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"subAccountId","type":"uint256"},{"internalType":"address","name":"newMarket","type":"address"}],"name":"enterMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"subAccountId","type":"uint256"},{"internalType":"address","name":"oldMarket","type":"address"}],"name":"exitMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getEnteredMarkets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"getPricingConfig","outputs":[{"internalType":"uint16","name":"pricingType","type":"uint16"},{"internalType":"uint32","name":"pricingParameters","type":"uint32"},{"internalType":"address","name":"pricingForwarded","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"interestAccumulator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"interestRate","outputs":[{"internalType":"int96","name":"","type":"int96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"interestRateModel","outputs":[{"internalType":"uint256","name":"","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":"underlying","type":"address"}],"name":"reserveFee","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"underlyingToAssetConfig","outputs":[{"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":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"underlyingToAssetConfigUnresolved","outputs":[{"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"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"underlyingToDToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"underlyingToEToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"underlyingToPToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162004c5638038062004c56833981016040819052620000349162000042565b600260805260a0526200005c565b6000602082840312156200005557600080fd5b5051919050565b60805160a051614bd46200008260003960006102f3015260006103fe0152614bd46000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80638948874911620000dd578063b74b1ed5116200008b578063bcc343ae116200006e578063bcc343ae146200047b578063c8a5fba31462000492578063fd7948d414620004a957600080fd5b8063b74b1ed51462000437578063b93982a0146200046457600080fd5b80638f34bdbc11620000c05780638f34bdbc14620003e1578063a1308f2714620003f8578063b409dd9b146200042057600080fd5b806389488749146200037f5780638ccb720b14620003bb57600080fd5b8063546422d6116200013b5780636b5e3606116200011e5780636b5e3606146200032457806373f0b437146200033b5780637c2c69c0146200035457600080fd5b8063546422d6146200029a57806369a92ea314620002ed57600080fd5b80630d771df714620001715780631b30058214620001b25780634e80717714620002005780634e9cfac21462000217575b600080fd5b620001886200018236600462002f9c565b620004e5565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b62000188620001c336600462002f9c565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600860209081526040808320548416835260099091529020600201541690565b620001886200021136600462002f9c565b62000746565b6200022e6200022836600462002f9c565b62000862565b604051620001a99190600060a08201905073ffffffffffffffffffffffffffffffffffffffff8351168252602083015115156020830152604083015163ffffffff8082166040850152806060860151166060850152505062ffffff608084015116608083015292915050565b620002b1620002ab36600462002f9c565b6200089e565b6040805161ffff909416845263ffffffff909216602084015273ffffffffffffffffffffffffffffffffffffffff1690820152606001620001a9565b620003157f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001620001a9565b620001886200033536600462002f9c565b62000942565b620003526200034c36600462002fbc565b620009db565b005b6200036b6200036536600462002f9c565b62000b14565b604051600b9190910b8152602001620001a9565b620001886200039036600462002f9c565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541690565b620003d2620003cc36600462002f9c565b62000b3b565b604051620001a9919062002fef565b6200022e620003f236600462002f9c565b62000b48565b620003157f000000000000000000000000000000000000000000000000000000000000000081565b620003156200043136600462002f9c565b62000cb4565b6200044e6200044836600462002f9c565b62000cda565b60405163ffffffff9091168152602001620001a9565b620001886200047536600462002f9c565b62000d4a565b620003156200048c36600462002f9c565b62000dde565b62000352620004a336600462002fbc565b62000e08565b62000188620004ba36600462002f9c565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600c60205260409020541690565b600060016000541462000559576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f652f7265656e7472616e6379000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6002600090815573ffffffffffffffffffffffffffffffffffffffff8381168252600c6020526040909120541615620005bb575073ffffffffffffffffffffffffffffffffffffffff8082166000908152600c6020526040902054166200073c565b6000620005c88362000fcb565b9050806040015163ffffffff166000141562000641576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f70746f6b656e2f6e6f742d636f6c6c61746572616c000000000000000000604482015260640162000550565b5060003083604051620006549062002f5a565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000695573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff8082166000818152600b602090815260408083208054958a167fffffffffffffffffffffffff00000000000000000000000000000000000000009687168117909155808452600c90925280832080549095168417909455925193945090927f73fb3a739df7a607a2d4190be1c2d2beb0a1a1d66712602ace77dfa83381b73f9190a3620007388162001176565b5090505b6001600055919050565b6000600160005414620007b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f652f7265656e7472616e63790000000000000000000000000000000000000000604482015260640162000550565b6002600090815573ffffffffffffffffffffffffffffffffffffffff8381168252600b60205260409091205416156200084c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6d61726b6574732f696e76616c69642d746f6b656e000000000000000000604482015260640162000550565b620008578262001176565b600160005592915050565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152620008988262000fcb565b92915050565b600080600080620008af85620018bd565b80547a010000000000000000000000000000000000000000000000000000810461ffff1695507c0100000000000000000000000000000000000000000000000000000000900463ffffffff1693509050600384146200091057600062000939565b73ffffffffffffffffffffffffffffffffffffffff8086166000908152600b6020526040902054165b93959294505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600960205260409020600201541680620009d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f652f696e76616c69642d65746f6b656e00000000000000000000000000000000604482015260640162000550565b919050565b60016000541462000a49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f652f7265656e7472616e63790000000000000000000000000000000000000000604482015260640162000550565b6002600090815562000a5a6200197a565b9050600062000a6a828562001990565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152600860205260409020549192501662000afd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640162000550565b62000b09818462001a04565b505060016000555050565b60008062000b2283620018bd565b546a01000000000000000000009004600b0b9392505050565b6060620008988262001ccf565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091525073ffffffffffffffffffffffffffffffffffffffff818116600090815260086020908152604091829020825160a081018452905493841680825274010000000000000000000000000000000000000000850460ff161515928201929092527501000000000000000000000000000000000000000000840463ffffffff90811693820193909352790100000000000000000000000000000000000000000000000000840490921660608301527d01000000000000000000000000000000000000000000000000000000000090920462ffffff16608082015290620009d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640162000550565b60008062000cc283620018bd565b546601000000000000900463ffffffff169392505050565b60008062000ce883620018bd565b8054909150760100000000000000000000000000000000000000000000900463ffffffff9081161462000d3d578054760100000000000000000000000000000000000000000000900463ffffffff1662000d43565b6336d616005b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600960205260409020600101541680620009d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f652f696e76616c69642d65746f6b656e00000000000000000000000000000000604482015260640162000550565b60008062000dec83620018bd565b9050600062000dfc848362001e7a565b60800151949350505050565b60016000541462000e76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f652f7265656e7472616e63790000000000000000000000000000000000000000604482015260640162000550565b6002600090815562000e876200197a565b9050600062000e97828562001990565b9050600062000ea68462000fcb565b805173ffffffffffffffffffffffffffffffffffffffff9081166000908152600960209081526040808320938716835260058401909152902054919250906dffffffffffffffffffffffffffff8116906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff16801562000f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f652f6f75747374616e64696e672d626f72726f77000000000000000000000000604482015260640162000550565b62000f92858862001f07565b604084015163ffffffff161580159062000fab57508115155b1562000fbc5762000fbc8562002286565b50506001600055505050505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff828116600090815260086020908152604091829020825160a081018452905493841680825274010000000000000000000000000000000000000000850460ff161515928201929092527501000000000000000000000000000000000000000000840463ffffffff90811693820193909352790100000000000000000000000000000000000000000000000000840490921660608301527d01000000000000000000000000000000000000000000000000000000000090920462ffffff1660808201529062001136576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640162000550565b606081015163ffffffff908116141562001155576342c1d80060608201525b608081015162ffffff90811614156200089857610708608082015292915050565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526008602052604081205490911615620011d2575073ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541690565b73ffffffffffffffffffffffffffffffffffffffff821660009081526005602052604090205463ffffffff1615801562001222575073ffffffffffffffffffffffffffffffffffffffff82163014155b6200128a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6d61726b6574732f696e76616c69642d746f6b656e000000000000000000604482015260640162000550565b60008273ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620012d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620012fe91906200304b565b905060128160ff16111562001370576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f652f746f6f2d6d616e792d646563696d616c7300000000000000000000000000604482015260640162000550565b620013b6604080516060808201835260008083526020808401829052845160a0810186528281529081018290528085018290529182018190526080820152909182015290565b60405173ffffffffffffffffffffffffffffffffffffffff851660248201526000906200148b90620f4240907f8eddcd9200000000000000000000000000000000000000000000000000000000906044015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526200236e565b905080806020019051810190620014a3919062003150565b9150506000620014b66207a1206200240c565b604083015173ffffffffffffffffffffffffffffffffffffffff9091169081905290506000620014e96207a1216200240c565b90508260400151600860008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff02191690831515021790555060408201518160000160156101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160196101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601d6101000a81548162ffffff021916908362ffffff16021790555090505081600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050868160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550836000015181600001601a6101000a81548161ffff021916908361ffff160217905550836020015181600001601c6101000a81548163ffffffff021916908363ffffffff160217905550818160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550428160000160006101000a81548164ffffffffff021916908364ffffffffff160217905550848160000160056101000a81548160ff021916908360ff160217905550621e84808160000160066101000a81548163ffffffff021916908363ffffffff16021790555063ffffffff8160000160166101000a81548163ffffffff021916908363ffffffff1602179055506b033b2e3c9fd0803ce800000081600401819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167f2ece124509c63be11a6985ae00b93c8cb8f8d8898f6e5239fc9e38bc7190966760405160405180910390a4509095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600860205260408120549091168062001950576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640162000550565b73ffffffffffffffffffffffffffffffffffffffff16600090815260096020526040902092915050565b600080600052601460283603600c375060005190565b60006101008210620019ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f652f7375622d6163636f756e742d69642d746f6f2d6269670000000000000000604482015260640162000550565b501890565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600660209081526040808320805460079093529220660100000000000090910463ffffffff1690811562001b0657825473ffffffffffffffffffffffffffffffffffffffff8581166a010000000000000000000090920416141562001a86575050505050565b60015b8263ffffffff1681101562001b04578473ffffffffffffffffffffffffffffffffffffffff168282640100000000811062001ac85762001ac86200324f565b015473ffffffffffffffffffffffffffffffffffffffff16141562001aef57505050505050565b8062001afb81620032ad565b91505062001a89565b505b600a8263ffffffff161062001b78576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f652f746f6f2d6d616e792d656e74657265642d6d61726b657473000000000000604482015260640162000550565b63ffffffff821662001bd55782547fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000073ffffffffffffffffffffffffffffffffffffffff86160217835562001c3a565b83818363ffffffff16640100000000811062001bf55762001bf56200324f565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b62001c47826001620032e9565b835463ffffffff919091166601000000000000027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff90911617835560405173ffffffffffffffffffffffffffffffffffffffff80871691908616907f1c0971b8e0f7bb4e90bdbd87cfe682c36c383e2fc3dc4716ecc02771186293cc90600090a35050505050565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526006602052604081205460609263ffffffff6601000000000000830416926a010000000000000000000090920416908267ffffffffffffffff81111562001d375762001d3762003070565b60405190808252806020026020018201604052801562001d61578160200160208202803683370190505b50905063ffffffff831662001d7857949350505050565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260076020526040812082519091849184919062001db55762001db56200324f565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260015b8463ffffffff1681101562001e6f578181640100000000811062001e055762001e056200324f565b0154835173ffffffffffffffffffffffffffffffffffffffff9091169084908390811062001e375762001e376200324f565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015262001e6781620032ad565b905062001ddd565b509095945050505050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081019190915262001f0083838362002686565b5092915050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600660209081526040808320805460079093529220660100000000000090910463ffffffff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262001f7957505050505050565b835473ffffffffffffffffffffffffffffffffffffffff8681166a010000000000000000000090920416141562001fb35750600062002064565b60015b8363ffffffff1681101562002032578573ffffffffffffffffffffffffffffffffffffffff168382640100000000811062001ff55762001ff56200324f565b015473ffffffffffffffffffffffffffffffffffffffff1614156200201d5780915062002032565b806200202981620032ad565b91505062001fb6565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114156200206457505050505050565b60006200207360018562003314565b63ffffffff169050808214620021855781620020f65782816401000000008110620020a257620020a26200324f565b015485547fffff0000000000000000000000000000000000000000ffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff9091166a01000000000000000000000217855562002185565b828164010000000081106200210f576200210f6200324f565b015473ffffffffffffffffffffffffffffffffffffffff16838364010000000081106200214057620021406200324f565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b84547fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff16660100000000000063ffffffff83160217855580156200222357600083826401000000008110620021de57620021de6200324f565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b8673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f7a35d9c64b6bcbe8e9104e3f481fb44a765d4b2a54cfa1c2d434a46c69f0418960405160405180910390a350505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526006602052604090205460ff16806200230e5760405173ffffffffffffffffffffffffffffffffffffffff831660248201526200230990620f4240907fc39b543a000000000000000000000000000000000000000000000000000000009060440162001408565b505050565b60ff8116600114156200236a5773ffffffffffffffffffffffffffffffffffffffff8216600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021790555b5050565b60008281526003602052604080822054905160609291829173ffffffffffffffffffffffffffffffffffffffff90911690620023ac9086906200333c565b600060405180830381855af49150503d8060008114620023e9576040519150601f19603f3d011682016040523d82523d6000602084013e620023ee565b606091505b5091509150816200240457620024048162002b31565b949350505050565b60008162002477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f652f6372656174652d70726f78792f696e76616c69642d6d6f64756c65000000604482015260640162000550565b620f423f821115620024e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f652f6372656174652d70726f78792f696e7465726e616c2d6d6f64756c650000604482015260640162000550565b60008281526004602052604090205473ffffffffffffffffffffffffffffffffffffffff16156200253a575060009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60006040516200254a9062002f68565b604051809103906000f08015801562002567573d6000803e3d6000fd5b5090506207a11f8311620025c257600083815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b60408051808201825263ffffffff80861682526000602080840182815273ffffffffffffffffffffffffffffffffffffffff878116808552600590935292869020945185549151909316640100000000027fffffffffffffffff00000000000000000000000000000000000000000000000090911692909316919091179190911790915590517f6c6ffd7df9a0cfaa14ee2cf752003968de6c340564276242aa48ca641b09bce490620026789086815260200190565b60405180910390a292915050565b73ffffffffffffffffffffffffffffffffffffffff83168152815464ffffffffff811660a083015265010000000000810460ff90811660c084018190526601000000000000830463ffffffff90811660e08601526a01000000000000000000008404600b0b610100860152760100000000000000000000000000000000000000000000840481166101208601527a010000000000000000000000000000000000000000000000000000840461ffff166101408601527c010000000000000000000000000000000000000000000000000000000090930490921661016084015260018401547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16606084015260038401546dffffffffffffffffffffffffffff80821660208601526e01000000000000000000000000000090910471ffffffffffffffffffffffffffffffffffff166040850152600485015460808501526012839003909116600a0a6101a0840181905260009291816200280e576200280e6200337a565b046101c0840152600062002823843062002ba4565b9050836101c00151811162002846576101a084015181026101808501526200284f565b60006101808501525b8360a0015164ffffffffff16421462002b28576001925060008460a0015164ffffffffff1642620028819190620033a9565b905060006b033b2e3c9fd0803ce80000008660800151620028d1886101000151600b0b6b033b2e3c9fd0803ce8000000620028bd9190620033c3565b856b033b2e3c9fd0803ce800000062002cca565b620028dd91906200343d565b620028e991906200347d565b90506000866080015182886040015171ffffffffffffffffffffffffffffffffffff166200291891906200343d565b6200292491906200347d565b606088015160208901519192506bffffffffffffffffffffffff16906dffffffffffffffffffffffffffff16600062002966633b9aca0063ee6b28006200343d565b6101208b015163ffffffff9081161462002986578a61012001516200298c565b6336d616005b63ffffffff168b6040015171ffffffffffffffffffffffffffffffffffff1686620029b89190620033a9565b620029c491906200343d565b620029d091906200347d565b9050801562002a57576000620029eb633b9aca00866200347d565b8b6101800151620029fd9190620034b9565b905062002a0b8282620033a9565b62002a1784836200343d565b62002a2391906200347d565b92508a602001516dffffffffffffffffffffffffffff168362002a479190620033a9565b62002a539085620034b9565b9350505b6dffffffffffffffffffffffffffff821180159062002a88575071ffffffffffffffffffffffffffffffffffff8411155b1562002b215762002a998462002d94565b71ffffffffffffffffffffffffffffffffffff1660408b015260808a0185905264ffffffffff421660a08b015260208a01516dffffffffffffffffffffffffffff16821462002b215762002aed8362002e3e565b6bffffffffffffffffffffffff1660608b015262002b0b8262002ede565b6dffffffffffffffffffffffffffff1660208b01525b5050505050505b50509392505050565b80511562002b4157805181602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f652f656d7074792d6572726f7200000000000000000000000000000000000000604482015260640162000550565b60408051835173ffffffffffffffffffffffffffffffffffffffff848116602480850191909152845180850390910181526044840185526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790529351600094859384931691614e209162002c3d916200333c565b6000604051808303818686fa925050503d806000811462002c7b576040519150601f19603f3d011682016040523d82523d6000602084013e62002c80565b606091505b509150915081158062002c94575060208151105b1562002ca65760009350505062002cc1565b8080602001905181019062002cbc9190620034d4565b935050505b60405292915050565b600083801562002d755760018416801562002ce85785925062002cec565b8392505b50600283046002850494505b841562002d6e57858602868782041462002d1157600080fd5b8181018181101562002d2257600080fd5b859004965050600185161562002d6257858302838782041415871515161562002d4a57600080fd5b8181018181101562002d5b57600080fd5b8590049350505b60028504945062002cf8565b5062002d8c565b83801562002d87576000925062002b28565b839250505b509392505050565b600071ffffffffffffffffffffffffffffffffffff82111562002e3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f652f646562742d616d6f756e742d746f6f2d6c617267652d746f2d656e636f6460448201527f6500000000000000000000000000000000000000000000000000000000000000606482015260840162000550565b5090565b60006bffffffffffffffffffffffff82111562002e3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f652f736d616c6c2d616d6f756e742d746f6f2d6c617267652d746f2d656e636f60448201527f6465000000000000000000000000000000000000000000000000000000000000606482015260840162000550565b60006dffffffffffffffffffffffffffff82111562002e3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f616d6f756e742d746f6f2d6c617267652d746f2d656e636f646500000000604482015260640162000550565b61147a80620034ef83390190565b610236806200496983390190565b73ffffffffffffffffffffffffffffffffffffffff8116811462002f9957600080fd5b50565b60006020828403121562002faf57600080fd5b813562000d438162002f76565b6000806040838503121562002fd057600080fd5b82359150602083013562002fe48162002f76565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156200303f57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016200300b565b50909695505050505050565b6000602082840312156200305e57600080fd5b815160ff8116811462000d4357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715620030ea577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290565b60405160a0810167ffffffffffffffff81118282101715620030ea577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b805163ffffffff81168114620009d657600080fd5b600081830360e08112156200316457600080fd5b6200316e6200309f565b835161ffff811681146200318157600080fd5b815262003191602085016200313b565b602082015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc083011215620031c757600080fd5b620031d1620030f0565b91506040840151620031e38162002f76565b825260608401518015158114620031f957600080fd5b60208301526200320c608085016200313b565b60408301526200321f60a085016200313b565b606083015260c084015162ffffff811681146200323b57600080fd5b608083015260408101919091529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415620032e257620032e26200327e565b5060010190565b600063ffffffff8083168185168083038211156200330b576200330b6200327e565b01949350505050565b600063ffffffff838116908316818110156200333457620033346200327e565b039392505050565b6000825160005b818110156200335f576020818601810151858301520162003343565b818111156200336f576000828501525b509190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082821015620033be57620033be6200327e565b500390565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038413811516156200340057620034006200327e565b827f80000000000000000000000000000000000000000000000000000000000000000384128116156200343757620034376200327e565b50500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156200347857620034786200327e565b500290565b600082620034b4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008219821115620034cf57620034cf6200327e565b500190565b600060208284031215620034e757600080fd5b505191905056fe60c060405234801561001057600080fd5b5060405161147a38038061147a83398101604081905261002f91610062565b6001600160a01b039182166080521660a052610095565b80516001600160a01b038116811461005d57600080fd5b919050565b6000806040838503121561007557600080fd5b61007e83610046565b915061008c60208401610046565b90509250929050565b60805160a05161138f6100eb6000396000818161019e0152818161029c01528181610818015281816108ae015281816109b201528181610b670152610c7d0152600081816104000152610562015261138f6000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806370a082311161008c578063b77dfe0311610066578063b77dfe0314610219578063dd62ed3e1461022c578063de0e9a3e14610272578063ea598cb01461028557600080fd5b806370a08231146101c857806395d89b41146101fe578063a9059cbb1461020657600080fd5b80631ed575db116100c85780631ed575db1461014257806323b872dd14610157578063313ce5671461016a5780636f307dc31461018457600080fd5b806306fdde03146100ef578063095ea7b31461010d57806318160ddd14610130575b600080fd5b6100f7610298565b6040516101049190610fb6565b60405180910390f35b61012061011b366004611030565b61036f565b6040519015158152602001610104565b6002545b604051908152602001610104565b610155610150366004611030565b6103e8565b005b61012061016536600461105a565b61049a565b610172610814565b60405160ff9091168152602001610104565b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610104565b6101346101d6366004611096565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6100f76108aa565b610120610214366004611030565b61096d565b610155610227366004611096565b610981565b61013461023a3660046110b1565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6101556102803660046110e4565b610b55565b6101556102933660046110e4565b610b62565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610305573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261034b919081019061112c565b60405160200161035b91906111f7565b604051602081830303815290604052905090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103d79086815260200190565b60405180910390a350600192915050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461048c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f7065726d697373696f6e2064656e69656400000000000000000000000000000060448201526064015b60405180910390fd5b6104968282610b97565b5050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040812054821115610529576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e73756666696369656e742062616c616e63650000000000000000000000006044820152606401610483565b73ffffffffffffffffffffffffffffffffffffffff8416331480159061058557503373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614155b80156105e1575073ffffffffffffffffffffffffffffffffffffffff841660009081526001602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b1561072d5773ffffffffffffffffffffffffffffffffffffffff84166000908152600160209081526040808320338452909152902054821115610680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e73756666696369656e7420616c6c6f77616e6365000000000000000000006044820152606401610483565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600160209081526040808320338452909152812080548492906106c090849061126b565b909155505073ffffffffffffffffffffffffffffffffffffffff8416600081815260016020908152604080832033808552908352928190205490519081529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35b73ffffffffffffffffffffffffffffffffffffffff84166000908152602081905260408120805484929061076290849061126b565b909155505073ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120805484929061079c908490611282565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161080291815260200190565b60405180910390a35060019392505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610881573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a5919061129a565b905090565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610917573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261095d919081019061112c565b60405160200161035b91906112bd565b600061097a33848461049a565b9392505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a329190611302565b90506002548111610a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6e6f20737572706c75732062616c616e636520746f20636c61696d00000000006044820152606401610483565b600060025482610aaf919061126b565b90508060026000828254610ac39190611282565b909155505073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604081208054839290610afd908490611282565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8416906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b610b5f3382610b97565b50565b610b8e7f0000000000000000000000000000000000000000000000000000000000000000333084610cf5565b610b5f33610981565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260208190526040902054811115610c26576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e73756666696369656e742062616c616e63650000000000000000000000006044820152606401610483565b8060026000828254610c38919061126b565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054839290610c7290849061126b565b90915550610ca390507f00000000000000000000000000000000000000000000000000000000000000008383610e42565b60405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691610d94919061131b565b6000604051808303816000865af19150503d8060008114610dd1576040519150601f19603f3d011682016040523d82523d6000602084013e610dd6565b606091505b5091509150818015610e00575080511580610e00575080806020019051810190610e009190611337565b8190610e39576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104839190610fb6565b50505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691610ed9919061131b565b6000604051808303816000865af19150503d8060008114610f16576040519150601f19603f3d011682016040523d82523d6000602084013e610f1b565b606091505b5091509150818015610f45575080511580610f45575080806020019051810190610f459190611337565b8190610f7e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104839190610fb6565b505050505050565b60005b83811015610fa1578181015183820152602001610f89565b83811115610fb0576000848401525b50505050565b6020815260008251806020840152610fd5816040850160208701610f86565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461102b57600080fd5b919050565b6000806040838503121561104357600080fd5b61104c83611007565b946020939093013593505050565b60008060006060848603121561106f57600080fd5b61107884611007565b925061108660208501611007565b9150604084013590509250925092565b6000602082840312156110a857600080fd5b61097a82611007565b600080604083850312156110c457600080fd5b6110cd83611007565b91506110db60208401611007565b90509250929050565b6000602082840312156110f657600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561113e57600080fd5b815167ffffffffffffffff8082111561115657600080fd5b818401915084601f83011261116a57600080fd5b81518181111561117c5761117c6110fd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156111c2576111c26110fd565b816040528281528760208487010111156111db57600080fd5b6111ec836020830160208801610f86565b979650505050505050565b7f45756c65722050726f746563746564200000000000000000000000000000000081526000825161122f816010850160208701610f86565b9190910160100192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561127d5761127d61123c565b500390565b600082198211156112955761129561123c565b500190565b6000602082840312156112ac57600080fd5b815160ff8116811461097a57600080fd5b7f70000000000000000000000000000000000000000000000000000000000000008152600082516112f5816001850160208701610f86565b9190910160010192915050565b60006020828403121561131457600080fd5b5051919050565b6000825161132d818460208701610f86565b9190910192915050565b60006020828403121561134957600080fd5b8151801515811461097a57600080fdfea2646970667358221220321885289a5e13a4a38fa627d95b9d1c350a9bffc0432aee3d7d29d2dcd7209f64736f6c634300080a003360a060405234801561001057600080fd5b503360805260805161020761002f6000396000601301526102076000f3fe608060405234801561001057600080fd5b507f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff8216141561017b5760008081523681601f378051801561008657600181146100b157600281146100df57600381146101105760048114610144578182fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff36016020a0508081f35b6020517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdf36016040a1508081f35b6040516020517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf36016060a2508081f35b6060516040516020517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f36016080a3508081f35b6080516060516040516020517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f360160a0a4508081f35b7fe9c4a3ac000000000000000000000000000000000000000000000000000000006000523660006004373360601b366004015260008036601801600080855af13d6000803e8080156101cc573d6000f35b3d6000fdfea26469706673582212204c86fe253b9f19cb088c17838d424c049f387d68d1102741a6d20e8ab7bc03d164736f6c634300080a0033a2646970667358221220bab4ca0cee53832e0638f7772d7f036b1e48f23adb2847292921470e52a1b94764736f6c634300080a0033000000000000000000000000c9126e6d1b3fc9a50a2e324bccb8ee3be06ac3ab
Deployed Bytecode
0x60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80638948874911620000dd578063b74b1ed5116200008b578063bcc343ae116200006e578063bcc343ae146200047b578063c8a5fba31462000492578063fd7948d414620004a957600080fd5b8063b74b1ed51462000437578063b93982a0146200046457600080fd5b80638f34bdbc11620000c05780638f34bdbc14620003e1578063a1308f2714620003f8578063b409dd9b146200042057600080fd5b806389488749146200037f5780638ccb720b14620003bb57600080fd5b8063546422d6116200013b5780636b5e3606116200011e5780636b5e3606146200032457806373f0b437146200033b5780637c2c69c0146200035457600080fd5b8063546422d6146200029a57806369a92ea314620002ed57600080fd5b80630d771df714620001715780631b30058214620001b25780634e80717714620002005780634e9cfac21462000217575b600080fd5b620001886200018236600462002f9c565b620004e5565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b62000188620001c336600462002f9c565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600860209081526040808320548416835260099091529020600201541690565b620001886200021136600462002f9c565b62000746565b6200022e6200022836600462002f9c565b62000862565b604051620001a99190600060a08201905073ffffffffffffffffffffffffffffffffffffffff8351168252602083015115156020830152604083015163ffffffff8082166040850152806060860151166060850152505062ffffff608084015116608083015292915050565b620002b1620002ab36600462002f9c565b6200089e565b6040805161ffff909416845263ffffffff909216602084015273ffffffffffffffffffffffffffffffffffffffff1690820152606001620001a9565b620003157f000000000000000000000000c9126e6d1b3fc9a50a2e324bccb8ee3be06ac3ab81565b604051908152602001620001a9565b620001886200033536600462002f9c565b62000942565b620003526200034c36600462002fbc565b620009db565b005b6200036b6200036536600462002f9c565b62000b14565b604051600b9190910b8152602001620001a9565b620001886200039036600462002f9c565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541690565b620003d2620003cc36600462002f9c565b62000b3b565b604051620001a9919062002fef565b6200022e620003f236600462002f9c565b62000b48565b620003157f000000000000000000000000000000000000000000000000000000000000000281565b620003156200043136600462002f9c565b62000cb4565b6200044e6200044836600462002f9c565b62000cda565b60405163ffffffff9091168152602001620001a9565b620001886200047536600462002f9c565b62000d4a565b620003156200048c36600462002f9c565b62000dde565b62000352620004a336600462002fbc565b62000e08565b62000188620004ba36600462002f9c565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600c60205260409020541690565b600060016000541462000559576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f652f7265656e7472616e6379000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6002600090815573ffffffffffffffffffffffffffffffffffffffff8381168252600c6020526040909120541615620005bb575073ffffffffffffffffffffffffffffffffffffffff8082166000908152600c6020526040902054166200073c565b6000620005c88362000fcb565b9050806040015163ffffffff166000141562000641576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f70746f6b656e2f6e6f742d636f6c6c61746572616c000000000000000000604482015260640162000550565b5060003083604051620006549062002f5a565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000695573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff8082166000818152600b602090815260408083208054958a167fffffffffffffffffffffffff00000000000000000000000000000000000000009687168117909155808452600c90925280832080549095168417909455925193945090927f73fb3a739df7a607a2d4190be1c2d2beb0a1a1d66712602ace77dfa83381b73f9190a3620007388162001176565b5090505b6001600055919050565b6000600160005414620007b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f652f7265656e7472616e63790000000000000000000000000000000000000000604482015260640162000550565b6002600090815573ffffffffffffffffffffffffffffffffffffffff8381168252600b60205260409091205416156200084c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6d61726b6574732f696e76616c69642d746f6b656e000000000000000000604482015260640162000550565b620008578262001176565b600160005592915050565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152620008988262000fcb565b92915050565b600080600080620008af85620018bd565b80547a010000000000000000000000000000000000000000000000000000810461ffff1695507c0100000000000000000000000000000000000000000000000000000000900463ffffffff1693509050600384146200091057600062000939565b73ffffffffffffffffffffffffffffffffffffffff8086166000908152600b6020526040902054165b93959294505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600960205260409020600201541680620009d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f652f696e76616c69642d65746f6b656e00000000000000000000000000000000604482015260640162000550565b919050565b60016000541462000a49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f652f7265656e7472616e63790000000000000000000000000000000000000000604482015260640162000550565b6002600090815562000a5a6200197a565b9050600062000a6a828562001990565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152600860205260409020549192501662000afd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640162000550565b62000b09818462001a04565b505060016000555050565b60008062000b2283620018bd565b546a01000000000000000000009004600b0b9392505050565b6060620008988262001ccf565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091525073ffffffffffffffffffffffffffffffffffffffff818116600090815260086020908152604091829020825160a081018452905493841680825274010000000000000000000000000000000000000000850460ff161515928201929092527501000000000000000000000000000000000000000000840463ffffffff90811693820193909352790100000000000000000000000000000000000000000000000000840490921660608301527d01000000000000000000000000000000000000000000000000000000000090920462ffffff16608082015290620009d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640162000550565b60008062000cc283620018bd565b546601000000000000900463ffffffff169392505050565b60008062000ce883620018bd565b8054909150760100000000000000000000000000000000000000000000900463ffffffff9081161462000d3d578054760100000000000000000000000000000000000000000000900463ffffffff1662000d43565b6336d616005b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600960205260409020600101541680620009d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f652f696e76616c69642d65746f6b656e00000000000000000000000000000000604482015260640162000550565b60008062000dec83620018bd565b9050600062000dfc848362001e7a565b60800151949350505050565b60016000541462000e76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f652f7265656e7472616e63790000000000000000000000000000000000000000604482015260640162000550565b6002600090815562000e876200197a565b9050600062000e97828562001990565b9050600062000ea68462000fcb565b805173ffffffffffffffffffffffffffffffffffffffff9081166000908152600960209081526040808320938716835260058401909152902054919250906dffffffffffffffffffffffffffff8116906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff16801562000f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f652f6f75747374616e64696e672d626f72726f77000000000000000000000000604482015260640162000550565b62000f92858862001f07565b604084015163ffffffff161580159062000fab57508115155b1562000fbc5762000fbc8562002286565b50506001600055505050505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff828116600090815260086020908152604091829020825160a081018452905493841680825274010000000000000000000000000000000000000000850460ff161515928201929092527501000000000000000000000000000000000000000000840463ffffffff90811693820193909352790100000000000000000000000000000000000000000000000000840490921660608301527d01000000000000000000000000000000000000000000000000000000000090920462ffffff1660808201529062001136576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640162000550565b606081015163ffffffff908116141562001155576342c1d80060608201525b608081015162ffffff90811614156200089857610708608082015292915050565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526008602052604081205490911615620011d2575073ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541690565b73ffffffffffffffffffffffffffffffffffffffff821660009081526005602052604090205463ffffffff1615801562001222575073ffffffffffffffffffffffffffffffffffffffff82163014155b6200128a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6d61726b6574732f696e76616c69642d746f6b656e000000000000000000604482015260640162000550565b60008273ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620012d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620012fe91906200304b565b905060128160ff16111562001370576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f652f746f6f2d6d616e792d646563696d616c7300000000000000000000000000604482015260640162000550565b620013b6604080516060808201835260008083526020808401829052845160a0810186528281529081018290528085018290529182018190526080820152909182015290565b60405173ffffffffffffffffffffffffffffffffffffffff851660248201526000906200148b90620f4240907f8eddcd9200000000000000000000000000000000000000000000000000000000906044015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526200236e565b905080806020019051810190620014a3919062003150565b9150506000620014b66207a1206200240c565b604083015173ffffffffffffffffffffffffffffffffffffffff9091169081905290506000620014e96207a1216200240c565b90508260400151600860008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff02191690831515021790555060408201518160000160156101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160196101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601d6101000a81548162ffffff021916908362ffffff16021790555090505081600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050868160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550836000015181600001601a6101000a81548161ffff021916908361ffff160217905550836020015181600001601c6101000a81548163ffffffff021916908363ffffffff160217905550818160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550428160000160006101000a81548164ffffffffff021916908364ffffffffff160217905550848160000160056101000a81548160ff021916908360ff160217905550621e84808160000160066101000a81548163ffffffff021916908363ffffffff16021790555063ffffffff8160000160166101000a81548163ffffffff021916908363ffffffff1602179055506b033b2e3c9fd0803ce800000081600401819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167f2ece124509c63be11a6985ae00b93c8cb8f8d8898f6e5239fc9e38bc7190966760405160405180910390a4509095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600860205260408120549091168062001950576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640162000550565b73ffffffffffffffffffffffffffffffffffffffff16600090815260096020526040902092915050565b600080600052601460283603600c375060005190565b60006101008210620019ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f652f7375622d6163636f756e742d69642d746f6f2d6269670000000000000000604482015260640162000550565b501890565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600660209081526040808320805460079093529220660100000000000090910463ffffffff1690811562001b0657825473ffffffffffffffffffffffffffffffffffffffff8581166a010000000000000000000090920416141562001a86575050505050565b60015b8263ffffffff1681101562001b04578473ffffffffffffffffffffffffffffffffffffffff168282640100000000811062001ac85762001ac86200324f565b015473ffffffffffffffffffffffffffffffffffffffff16141562001aef57505050505050565b8062001afb81620032ad565b91505062001a89565b505b600a8263ffffffff161062001b78576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f652f746f6f2d6d616e792d656e74657265642d6d61726b657473000000000000604482015260640162000550565b63ffffffff821662001bd55782547fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000073ffffffffffffffffffffffffffffffffffffffff86160217835562001c3a565b83818363ffffffff16640100000000811062001bf55762001bf56200324f565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b62001c47826001620032e9565b835463ffffffff919091166601000000000000027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff90911617835560405173ffffffffffffffffffffffffffffffffffffffff80871691908616907f1c0971b8e0f7bb4e90bdbd87cfe682c36c383e2fc3dc4716ecc02771186293cc90600090a35050505050565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526006602052604081205460609263ffffffff6601000000000000830416926a010000000000000000000090920416908267ffffffffffffffff81111562001d375762001d3762003070565b60405190808252806020026020018201604052801562001d61578160200160208202803683370190505b50905063ffffffff831662001d7857949350505050565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260076020526040812082519091849184919062001db55762001db56200324f565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260015b8463ffffffff1681101562001e6f578181640100000000811062001e055762001e056200324f565b0154835173ffffffffffffffffffffffffffffffffffffffff9091169084908390811062001e375762001e376200324f565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015262001e6781620032ad565b905062001ddd565b509095945050505050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081019190915262001f0083838362002686565b5092915050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600660209081526040808320805460079093529220660100000000000090910463ffffffff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262001f7957505050505050565b835473ffffffffffffffffffffffffffffffffffffffff8681166a010000000000000000000090920416141562001fb35750600062002064565b60015b8363ffffffff1681101562002032578573ffffffffffffffffffffffffffffffffffffffff168382640100000000811062001ff55762001ff56200324f565b015473ffffffffffffffffffffffffffffffffffffffff1614156200201d5780915062002032565b806200202981620032ad565b91505062001fb6565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114156200206457505050505050565b60006200207360018562003314565b63ffffffff169050808214620021855781620020f65782816401000000008110620020a257620020a26200324f565b015485547fffff0000000000000000000000000000000000000000ffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff9091166a01000000000000000000000217855562002185565b828164010000000081106200210f576200210f6200324f565b015473ffffffffffffffffffffffffffffffffffffffff16838364010000000081106200214057620021406200324f565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b84547fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff16660100000000000063ffffffff83160217855580156200222357600083826401000000008110620021de57620021de6200324f565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b8673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f7a35d9c64b6bcbe8e9104e3f481fb44a765d4b2a54cfa1c2d434a46c69f0418960405160405180910390a350505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526006602052604090205460ff16806200230e5760405173ffffffffffffffffffffffffffffffffffffffff831660248201526200230990620f4240907fc39b543a000000000000000000000000000000000000000000000000000000009060440162001408565b505050565b60ff8116600114156200236a5773ffffffffffffffffffffffffffffffffffffffff8216600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021790555b5050565b60008281526003602052604080822054905160609291829173ffffffffffffffffffffffffffffffffffffffff90911690620023ac9086906200333c565b600060405180830381855af49150503d8060008114620023e9576040519150601f19603f3d011682016040523d82523d6000602084013e620023ee565b606091505b5091509150816200240457620024048162002b31565b949350505050565b60008162002477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f652f6372656174652d70726f78792f696e76616c69642d6d6f64756c65000000604482015260640162000550565b620f423f821115620024e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f652f6372656174652d70726f78792f696e7465726e616c2d6d6f64756c650000604482015260640162000550565b60008281526004602052604090205473ffffffffffffffffffffffffffffffffffffffff16156200253a575060009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60006040516200254a9062002f68565b604051809103906000f08015801562002567573d6000803e3d6000fd5b5090506207a11f8311620025c257600083815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b60408051808201825263ffffffff80861682526000602080840182815273ffffffffffffffffffffffffffffffffffffffff878116808552600590935292869020945185549151909316640100000000027fffffffffffffffff00000000000000000000000000000000000000000000000090911692909316919091179190911790915590517f6c6ffd7df9a0cfaa14ee2cf752003968de6c340564276242aa48ca641b09bce490620026789086815260200190565b60405180910390a292915050565b73ffffffffffffffffffffffffffffffffffffffff83168152815464ffffffffff811660a083015265010000000000810460ff90811660c084018190526601000000000000830463ffffffff90811660e08601526a01000000000000000000008404600b0b610100860152760100000000000000000000000000000000000000000000840481166101208601527a010000000000000000000000000000000000000000000000000000840461ffff166101408601527c010000000000000000000000000000000000000000000000000000000090930490921661016084015260018401547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16606084015260038401546dffffffffffffffffffffffffffff80821660208601526e01000000000000000000000000000090910471ffffffffffffffffffffffffffffffffffff166040850152600485015460808501526012839003909116600a0a6101a0840181905260009291816200280e576200280e6200337a565b046101c0840152600062002823843062002ba4565b9050836101c00151811162002846576101a084015181026101808501526200284f565b60006101808501525b8360a0015164ffffffffff16421462002b28576001925060008460a0015164ffffffffff1642620028819190620033a9565b905060006b033b2e3c9fd0803ce80000008660800151620028d1886101000151600b0b6b033b2e3c9fd0803ce8000000620028bd9190620033c3565b856b033b2e3c9fd0803ce800000062002cca565b620028dd91906200343d565b620028e991906200347d565b90506000866080015182886040015171ffffffffffffffffffffffffffffffffffff166200291891906200343d565b6200292491906200347d565b606088015160208901519192506bffffffffffffffffffffffff16906dffffffffffffffffffffffffffff16600062002966633b9aca0063ee6b28006200343d565b6101208b015163ffffffff9081161462002986578a61012001516200298c565b6336d616005b63ffffffff168b6040015171ffffffffffffffffffffffffffffffffffff1686620029b89190620033a9565b620029c491906200343d565b620029d091906200347d565b9050801562002a57576000620029eb633b9aca00866200347d565b8b6101800151620029fd9190620034b9565b905062002a0b8282620033a9565b62002a1784836200343d565b62002a2391906200347d565b92508a602001516dffffffffffffffffffffffffffff168362002a479190620033a9565b62002a539085620034b9565b9350505b6dffffffffffffffffffffffffffff821180159062002a88575071ffffffffffffffffffffffffffffffffffff8411155b1562002b215762002a998462002d94565b71ffffffffffffffffffffffffffffffffffff1660408b015260808a0185905264ffffffffff421660a08b015260208a01516dffffffffffffffffffffffffffff16821462002b215762002aed8362002e3e565b6bffffffffffffffffffffffff1660608b015262002b0b8262002ede565b6dffffffffffffffffffffffffffff1660208b01525b5050505050505b50509392505050565b80511562002b4157805181602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f652f656d7074792d6572726f7200000000000000000000000000000000000000604482015260640162000550565b60408051835173ffffffffffffffffffffffffffffffffffffffff848116602480850191909152845180850390910181526044840185526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790529351600094859384931691614e209162002c3d916200333c565b6000604051808303818686fa925050503d806000811462002c7b576040519150601f19603f3d011682016040523d82523d6000602084013e62002c80565b606091505b509150915081158062002c94575060208151105b1562002ca65760009350505062002cc1565b8080602001905181019062002cbc9190620034d4565b935050505b60405292915050565b600083801562002d755760018416801562002ce85785925062002cec565b8392505b50600283046002850494505b841562002d6e57858602868782041462002d1157600080fd5b8181018181101562002d2257600080fd5b859004965050600185161562002d6257858302838782041415871515161562002d4a57600080fd5b8181018181101562002d5b57600080fd5b8590049350505b60028504945062002cf8565b5062002d8c565b83801562002d87576000925062002b28565b839250505b509392505050565b600071ffffffffffffffffffffffffffffffffffff82111562002e3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f652f646562742d616d6f756e742d746f6f2d6c617267652d746f2d656e636f6460448201527f6500000000000000000000000000000000000000000000000000000000000000606482015260840162000550565b5090565b60006bffffffffffffffffffffffff82111562002e3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f652f736d616c6c2d616d6f756e742d746f6f2d6c617267652d746f2d656e636f60448201527f6465000000000000000000000000000000000000000000000000000000000000606482015260840162000550565b60006dffffffffffffffffffffffffffff82111562002e3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f616d6f756e742d746f6f2d6c617267652d746f2d656e636f646500000000604482015260640162000550565b61147a80620034ef83390190565b610236806200496983390190565b73ffffffffffffffffffffffffffffffffffffffff8116811462002f9957600080fd5b50565b60006020828403121562002faf57600080fd5b813562000d438162002f76565b6000806040838503121562002fd057600080fd5b82359150602083013562002fe48162002f76565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156200303f57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016200300b565b50909695505050505050565b6000602082840312156200305e57600080fd5b815160ff8116811462000d4357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715620030ea577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290565b60405160a0810167ffffffffffffffff81118282101715620030ea577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b805163ffffffff81168114620009d657600080fd5b600081830360e08112156200316457600080fd5b6200316e6200309f565b835161ffff811681146200318157600080fd5b815262003191602085016200313b565b602082015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc083011215620031c757600080fd5b620031d1620030f0565b91506040840151620031e38162002f76565b825260608401518015158114620031f957600080fd5b60208301526200320c608085016200313b565b60408301526200321f60a085016200313b565b606083015260c084015162ffffff811681146200323b57600080fd5b608083015260408101919091529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415620032e257620032e26200327e565b5060010190565b600063ffffffff8083168185168083038211156200330b576200330b6200327e565b01949350505050565b600063ffffffff838116908316818110156200333457620033346200327e565b039392505050565b6000825160005b818110156200335f576020818601810151858301520162003343565b818111156200336f576000828501525b509190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082821015620033be57620033be6200327e565b500390565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038413811516156200340057620034006200327e565b827f80000000000000000000000000000000000000000000000000000000000000000384128116156200343757620034376200327e565b50500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156200347857620034786200327e565b500290565b600082620034b4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008219821115620034cf57620034cf6200327e565b500190565b600060208284031215620034e757600080fd5b505191905056fe60c060405234801561001057600080fd5b5060405161147a38038061147a83398101604081905261002f91610062565b6001600160a01b039182166080521660a052610095565b80516001600160a01b038116811461005d57600080fd5b919050565b6000806040838503121561007557600080fd5b61007e83610046565b915061008c60208401610046565b90509250929050565b60805160a05161138f6100eb6000396000818161019e0152818161029c01528181610818015281816108ae015281816109b201528181610b670152610c7d0152600081816104000152610562015261138f6000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806370a082311161008c578063b77dfe0311610066578063b77dfe0314610219578063dd62ed3e1461022c578063de0e9a3e14610272578063ea598cb01461028557600080fd5b806370a08231146101c857806395d89b41146101fe578063a9059cbb1461020657600080fd5b80631ed575db116100c85780631ed575db1461014257806323b872dd14610157578063313ce5671461016a5780636f307dc31461018457600080fd5b806306fdde03146100ef578063095ea7b31461010d57806318160ddd14610130575b600080fd5b6100f7610298565b6040516101049190610fb6565b60405180910390f35b61012061011b366004611030565b61036f565b6040519015158152602001610104565b6002545b604051908152602001610104565b610155610150366004611030565b6103e8565b005b61012061016536600461105a565b61049a565b610172610814565b60405160ff9091168152602001610104565b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610104565b6101346101d6366004611096565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6100f76108aa565b610120610214366004611030565b61096d565b610155610227366004611096565b610981565b61013461023a3660046110b1565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6101556102803660046110e4565b610b55565b6101556102933660046110e4565b610b62565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610305573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261034b919081019061112c565b60405160200161035b91906111f7565b604051602081830303815290604052905090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103d79086815260200190565b60405180910390a350600192915050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461048c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f7065726d697373696f6e2064656e69656400000000000000000000000000000060448201526064015b60405180910390fd5b6104968282610b97565b5050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040812054821115610529576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e73756666696369656e742062616c616e63650000000000000000000000006044820152606401610483565b73ffffffffffffffffffffffffffffffffffffffff8416331480159061058557503373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614155b80156105e1575073ffffffffffffffffffffffffffffffffffffffff841660009081526001602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b1561072d5773ffffffffffffffffffffffffffffffffffffffff84166000908152600160209081526040808320338452909152902054821115610680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e73756666696369656e7420616c6c6f77616e6365000000000000000000006044820152606401610483565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600160209081526040808320338452909152812080548492906106c090849061126b565b909155505073ffffffffffffffffffffffffffffffffffffffff8416600081815260016020908152604080832033808552908352928190205490519081529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35b73ffffffffffffffffffffffffffffffffffffffff84166000908152602081905260408120805484929061076290849061126b565b909155505073ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120805484929061079c908490611282565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161080291815260200190565b60405180910390a35060019392505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610881573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a5919061129a565b905090565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610917573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261095d919081019061112c565b60405160200161035b91906112bd565b600061097a33848461049a565b9392505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a329190611302565b90506002548111610a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6e6f20737572706c75732062616c616e636520746f20636c61696d00000000006044820152606401610483565b600060025482610aaf919061126b565b90508060026000828254610ac39190611282565b909155505073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604081208054839290610afd908490611282565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8416906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b610b5f3382610b97565b50565b610b8e7f0000000000000000000000000000000000000000000000000000000000000000333084610cf5565b610b5f33610981565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260208190526040902054811115610c26576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e73756666696369656e742062616c616e63650000000000000000000000006044820152606401610483565b8060026000828254610c38919061126b565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054839290610c7290849061126b565b90915550610ca390507f00000000000000000000000000000000000000000000000000000000000000008383610e42565b60405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691610d94919061131b565b6000604051808303816000865af19150503d8060008114610dd1576040519150601f19603f3d011682016040523d82523d6000602084013e610dd6565b606091505b5091509150818015610e00575080511580610e00575080806020019051810190610e009190611337565b8190610e39576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104839190610fb6565b50505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691610ed9919061131b565b6000604051808303816000865af19150503d8060008114610f16576040519150601f19603f3d011682016040523d82523d6000602084013e610f1b565b606091505b5091509150818015610f45575080511580610f45575080806020019051810190610f459190611337565b8190610f7e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104839190610fb6565b505050505050565b60005b83811015610fa1578181015183820152602001610f89565b83811115610fb0576000848401525b50505050565b6020815260008251806020840152610fd5816040850160208701610f86565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461102b57600080fd5b919050565b6000806040838503121561104357600080fd5b61104c83611007565b946020939093013593505050565b60008060006060848603121561106f57600080fd5b61107884611007565b925061108660208501611007565b9150604084013590509250925092565b6000602082840312156110a857600080fd5b61097a82611007565b600080604083850312156110c457600080fd5b6110cd83611007565b91506110db60208401611007565b90509250929050565b6000602082840312156110f657600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561113e57600080fd5b815167ffffffffffffffff8082111561115657600080fd5b818401915084601f83011261116a57600080fd5b81518181111561117c5761117c6110fd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156111c2576111c26110fd565b816040528281528760208487010111156111db57600080fd5b6111ec836020830160208801610f86565b979650505050505050565b7f45756c65722050726f746563746564200000000000000000000000000000000081526000825161122f816010850160208701610f86565b9190910160100192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561127d5761127d61123c565b500390565b600082198211156112955761129561123c565b500190565b6000602082840312156112ac57600080fd5b815160ff8116811461097a57600080fd5b7f70000000000000000000000000000000000000000000000000000000000000008152600082516112f5816001850160208701610f86565b9190910160010192915050565b60006020828403121561131457600080fd5b5051919050565b6000825161132d818460208701610f86565b9190910192915050565b60006020828403121561134957600080fd5b8151801515811461097a57600080fdfea2646970667358221220321885289a5e13a4a38fa627d95b9d1c350a9bffc0432aee3d7d29d2dcd7209f64736f6c634300080a003360a060405234801561001057600080fd5b503360805260805161020761002f6000396000601301526102076000f3fe608060405234801561001057600080fd5b507f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff8216141561017b5760008081523681601f378051801561008657600181146100b157600281146100df57600381146101105760048114610144578182fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff36016020a0508081f35b6020517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdf36016040a1508081f35b6040516020517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf36016060a2508081f35b6060516040516020517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f36016080a3508081f35b6080516060516040516020517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f360160a0a4508081f35b7fe9c4a3ac000000000000000000000000000000000000000000000000000000006000523660006004373360601b366004015260008036601801600080855af13d6000803e8080156101cc573d6000f35b3d6000fdfea26469706673582212204c86fe253b9f19cb088c17838d424c049f387d68d1102741a6d20e8ab7bc03d164736f6c634300080a0033a2646970667358221220bab4ca0cee53832e0638f7772d7f036b1e48f23adb2847292921470e52a1b94764736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c9126e6d1b3fc9a50a2e324bccb8ee3be06ac3ab
-----Decoded View---------------
Arg [0] : moduleGitCommit_ (bytes32): 0x000000000000000000000000c9126e6d1b3fc9a50a2e324bccb8ee3be06ac3ab
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c9126e6d1b3fc9a50a2e324bccb8ee3be06ac3ab
Deployed Bytecode Sourcemap
237:11032:12:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3238:664;;;;;;:::i;:::-;;:::i;:::-;;;601:42:14;589:55;;;571:74;;559:2;544:18;3238:664:12;;;;;;;;4432:174;;;;;;:::i;:::-;4542:28;;;;4503:7;4542:28;;;:16;:28;;;;;;;;:42;;;4529:56;;:12;:56;;;;;:70;;;;;4432:174;679:220;;;;;;:::i;:::-;;:::i;5154:150::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;806:4:14;848:3;837:9;833:19;825:27;;898:42;889:6;883:13;879:62;868:9;861:81;1012:4;1004:6;1000:17;994:24;987:32;980:40;973:4;962:9;958:20;951:70;1068:4;1060:6;1056:17;1050:24;1093:10;1159:2;1145:12;1141:21;1134:4;1123:9;1119:20;1112:51;1231:2;1223:4;1215:6;1211:17;1205:24;1201:33;1194:4;1183:9;1179:20;1172:63;;;1303:8;1295:4;1287:6;1283:17;1277:24;1273:39;1266:4;1255:9;1251:20;1244:69;656:663;;;;;8977:437:12;;;;;;:::i;:::-;;:::i;:::-;;;;1552:6:14;1540:19;;;1522:38;;1608:10;1596:23;;;1591:2;1576:18;;1569:51;1668:42;1656:55;1636:18;;;1629:83;1510:2;1495:18;8977:437:12;1324:394:14;241:40:3;;;;;;;;1869:25:14;;;1857:2;1842:18;241:40:3;1723:177:14;6298:210:12;;;;;;:::i;:::-;;:::i;10006:359::-;;;;;;:::i;:::-;;:::i;:::-;;7376:195;;;;;;:::i;:::-;;:::i;:::-;;;2396:2:14;2385:22;;;;2367:41;;2355:2;2340:18;7376:195:12;2225:189:14;4111:146:12;;;;;;:::i;:::-;4208:28;;;;4182:7;4208:28;;;:16;:28;;;;;:42;;;4111:146;9653:140;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;5524:246::-;;;;;;:::i;:::-;;:::i;205:30:3:-;;;;;6989:204:12;;;;;;:::i;:::-;;:::i;8289:268::-;;;;;;:::i;:::-;;:::i;:::-;;;3461:10:14;3449:23;;;3431:42;;3419:2;3404:18;8289:268:12;3287:192:14;5930:211:12;;;;;;:::i;:::-;;:::i;7770:289::-;;;;;;:::i;:::-;;:::i;10587:680::-;;;;;;:::i;:::-;;:::i;4784:135::-;;;;;;:::i;:::-;4881:31;;;;4855:7;4881:31;;;:19;:31;;;;;;;;4784:135;3238:664;3313:7;1390:1:4;1389:14:0;;:42;1381:67;;;;;;;3686:2:14;1381:67:0;;;3668:21:14;3725:2;3705:18;;;3698:30;3764:14;3744:18;;;3737:42;3796:18;;1381:67:0;;;;;;;;;1445:1:4;1459:14:0;:39;;;3336:45:12::1;:31:::0;;::::1;::::0;;:19:::1;:31;::::0;;;;;;::::1;:45:::0;3332:89:::1;;-1:-1:-1::0;3390:31:12::1;::::0;;::::1;;::::0;;;:19:::1;:31;::::0;;;;;::::1;3383:38;;3332:89;3446:25;3474:30;3493:10;3474:18;:30::i;:::-;3446:58;;3526:6;:23;;;:28;;3553:1;3526:28;;3518:64;;;::::0;::::1;::::0;;4027:2:14;3518:64:12::1;::::0;::::1;4009:21:14::0;4066:2;4046:18;;;4039:30;4105:25;4085:18;;;4078:53;4148:18;;3518:64:12::1;3825:347:14::0;3518:64:12::1;3432:161;3604:18;3652:4;3659:10;3633:37;;;;;:::i;:::-;4361:42:14::0;4430:15;;;4412:34;;4482:15;;4477:2;4462:18;;4455:43;4339:2;4324:18;3633:37:12::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;3682:24:12::1;::::0;;::::1;;::::0;;;:12:::1;:24;::::0;;;;;;;:37;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;3729:31;;;:19:::1;:31:::0;;;;;;:44;;;;::::1;::::0;::::1;::::0;;;3789:39;;3604:67;;-1:-1:-1;3682:24:12;;3789:39:::1;::::0;3682:24;3789:39:::1;3839:28;3856:10;3839:16;:28::i;:::-;-1:-1:-1::0;3885:10:12;-1:-1:-1;1508:1:0::1;1390::4::0;1519:14:0;:41;3238:664:12;;-1:-1:-1;3238:664:12:o;679:220::-;754:7;1390:1:4;1389:14:0;;:42;1381:67;;;;;;;3686:2:14;1381:67:0;;;3668:21:14;3725:2;3705:18;;;3698:30;3764:14;3744:18;;;3737:42;3796:18;;1381:67:0;3484:336:14;1381:67:0;1445:1:4;1459:14:0;:39;;;781:38:12::1;:24:::0;;::::1;::::0;;:12:::1;:24;::::0;;;;;;::::1;:38:::0;773:74:::1;;;::::0;::::1;::::0;;4711:2:14;773:74:12::1;::::0;::::1;4693:21:14::0;4750:2;4730:18;;;4723:30;4789:25;4769:18;;;4762:53;4832:18;;773:74:12::1;4509:347:14::0;773:74:12::1;864:28;881:10;864:16;:28::i;:::-;1390:1:4::0;1519:14:0;:41;857:35:12;679:220;-1:-1:-1;;679:220:12:o;5154:150::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5267:30:12;5286:10;5267:18;:30::i;:::-;5260:37;5154:150;-1:-1:-1;;5154:150:12:o;8977:437::-;9046:18;9066:24;9092;9128:33;9164:27;9180:10;9164:15;:27::i;:::-;9216:24;;;;;;;;-1:-1:-1;9270:30:12;;;;;;-1:-1:-1;9216:24:12;-1:-1:-1;1806:1:4;9330:37:12;;:77;;9405:1;9330:77;;;9370:24;;;;;;;;:12;:24;;;;;;;9330:77;8977:437;;;;-1:-1:-1;;;8977:437:12:o;6298:210::-;6404:20;;;;6361:18;6404:20;;;:12;:20;;;;;:34;;;;6456:24;6448:53;;;;;;;5063:2:14;6448:53:12;;;5045:21:14;5102:2;5082:18;;;5075:30;5141:18;5121;;;5114:46;5177:18;;6448:53:12;4861:340:14;6448:53:12;6298:210;;;:::o;10006:359::-;1390:1:4;1389:14:0;;:42;1381:67;;;;;;;3686:2:14;1381:67:0;;;3668:21:14;3725:2;3705:18;;;3698:30;3764:14;3744:18;;;3737:42;3796:18;;1381:67:0;3484:336:14;1381:67:0;1445:1:4;1459:14:0;:39;;;10117:30:12::1;:28;:30::i;:::-;10097:50;;10157:15;10175:38;10189:9;10200:12;10175:13;:38::i;:::-;10232:55;:27:::0;;::::1;10285:1;10232:27:::0;;;:16:::1;:27;::::0;;;;:41;10157:56;;-1:-1:-1;10232:41:12::1;10224:90;;;::::0;::::1;::::0;;5408:2:14;10224:90:12::1;::::0;::::1;5390:21:14::0;5447:2;5427:18;;;5420:30;5486:24;5466:18;;;5459:52;5528:18;;10224:90:12::1;5206:346:14::0;10224:90:12::1;10325:33;10339:7;10348:9;10325:13;:33::i;:::-;-1:-1:-1::0;;1390:1:4;1519:14:0;:41;-1:-1:-1;;10006:359:12:o;7376:195::-;7441:5;7458:33;7494:27;7510:10;7494:15;:27::i;:::-;7539:25;;;;;;;7376:195;-1:-1:-1;;;7376:195:12:o;9653:140::-;9720:16;9755:31;9778:7;9755:22;:31::i;5524:246::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5656:28:12;;;;;;;;:16;:28;;;;;;;;;5647:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5694:69;;;;;;;5408:2:14;5694:69:12;;;5390:21:14;5447:2;5427:18;;;5420:30;5486:24;5466:18;;;5459:52;5528:18;;5694:69:12;5206:346:14;6989:204:12;7059:4;7075:33;7111:27;7127:10;7111:15;:27::i;:::-;7156:30;;;;;;;;-1:-1:-1;;;6989:204:12:o;8289:268::-;8352:6;8370:33;8406:27;8422:10;8406:15;:27::i;:::-;8451:23;;8370:63;;-1:-1:-1;8451:23:12;;;8478:16;8451:23;;;:43;:99;;8527:23;;;;;;;8451:99;;;923:20:4;8451:99:12;8444:106;8289:268;-1:-1:-1;;;8289:268:12:o;5930:211::-;6040:20;;;;5997:18;6040:20;;;:12;:20;;;;;:31;;;;6089:24;6081:53;;;;;;;5063:2:14;6081:53:12;;;5045:21:14;5102:2;5082:18;;;5075:30;5141:18;5121;;;5114:46;5177:18;;6081:53:12;4861:340:14;7770:289:12;7842:4;7858:33;7894:27;7910:10;7894:15;:27::i;:::-;7858:63;;7931:28;7962:42;7979:10;7991:12;7962:16;:42::i;:::-;8022:30;;;;7770:289;-1:-1:-1;;;;7770:289:12:o;10587:680::-;1390:1:4;1389:14:0;;:42;1381:67;;;;;;;3686:2:14;1381:67:0;;;3668:21:14;3725:2;3705:18;;;3698:30;3764:14;3744:18;;;3737:42;3796:18;;1381:67:0;3484:336:14;1381:67:0;1445:1:4;1459:14:0;:39;;;10697:30:12::1;:28;:30::i;:::-;10677:50;;10737:15;10755:38;10769:9;10780:12;10755:13;:38::i;:::-;10737:56;;10804:25;10832:29;10851:9;10832:18;:29::i;:::-;10920:20:::0;;10907:34:::1;::::0;;::::1;10871:33;10907:34:::0;;;:12:::1;:34;::::0;;;;;;;10967:27;;::::1;::::0;;:18:::1;::::0;::::1;:27:::0;;;;;:35;10920:20;;-1:-1:-1;10907:34:12;10967:35:::1;::::0;::::1;::::0;11024:32;;::::1;;;11075:9:::0;;11067:42:::1;;;::::0;::::1;::::0;;5759:2:14;11067:42:12::1;::::0;::::1;5741:21:14::0;5798:2;5778:18;;;5771:30;5837:22;5817:18;;;5810:50;5877:18;;11067:42:12::1;5557:344:14::0;11067:42:12::1;11120:32;11133:7;11142:9;11120:12;:32::i;:::-;11167:23;::::0;::::1;::::0;:28:::1;;::::0;;::::1;::::0;:44:::1;;-1:-1:-1::0;11199:12:12;;::::1;11167:44;11163:98;;;11227:23;11242:7;11227:14;:23::i;:::-;-1:-1:-1::0;;1390:1:4;1519:14:0;:41;-1:-1:-1;;;;;;10587:680:12:o;4431:466:2:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4560:28:2;;;;4532:25;4560:28;;;:16;:28;;;;;;;;;4532:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4598:69;;;;;;;5408:2:14;4598:69:2;;;5390:21:14;5447:2;5427:18;;;5420:30;5486:24;5466:18;;;5459:52;5528:18;;4598:69:2;5206:346:14;4598:69:2;4682:19;;;;4705:16;4682:39;;;;4678:88;;;1278:20:4;4723:19:2;;;:43;4678:88;4780:17;;;;4801:16;4780:37;;;;4776:90;;;1209:7:4;4819:17:2;;;:47;4884:6;4431:466;-1:-1:-1;;4431:466:2:o;905:1937:12:-;1016:56;:28;;;968:7;1016:28;;;:16;:28;;;;;:42;968:7;;1016:42;:56;1012:111;;-1:-1:-1;1081:28:12;;;;;;;;:16;:28;;;;;:42;;;905:1937::o;1012:111::-;1166:26;;;;;;;:14;:26;;;;;:35;;;:40;:71;;;;-1:-1:-1;1210:27:12;;;1232:4;1210:27;;1166:71;1158:107;;;;;;;4711:2:14;1158:107:12;;;4693:21:14;4750:2;4730:18;;;4723:30;4789:25;4769:18;;;4762:53;4832:18;;1158:107:12;4509:347:14;1158:107:12;1276:14;1300:10;1293:27;;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1276:46;;1352:2;1340:8;:14;;;;1332:46;;;;;;;6386:2:14;1332:46:12;;;6368:21:14;6425:2;6405:18;;;6398:30;6464:21;6444:18;;;6437:49;6503:18;;1332:46:12;6184:343:14;1332:46:12;1430;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1430:46:12;1619:80;;601:42:14;589:55;;1619:80:12;;;571:74:14;1501:19:12;;1523:177;;2522:9:4;;1642:44:12;;544:18:14;;1619:80:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1523:18;:177::i;:::-;1501:199;;1736:6;1725:54;;;;;;;;;;;;:::i;:::-;1714:65;;1487:303;1828:19;1880:30;2320:7:4;1880:12:12;:30::i;:::-;1850:13;;;;:60;;;;;;;;;-1:-1:-1;1850:27:12;1942:30;2375:7:4;1942:12:12;:30::i;:::-;1920:52;;2041:6;:13;;;2010:16;:28;2027:10;2010:28;;;;;;;;;;;;;;;:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2093:11;2065:12;:25;2078:11;2065:25;;;;;;;;;;;;;;;;:39;;;;;;;;;;;;;;;;;;2115:33;2151:12;:25;2164:11;2151:25;;;;;;;;;;;;;;;2115:61;;2213:10;2187:12;:23;;;:36;;;;;;;;;;;;;;;;;;2260:6;:18;;;2233:12;:24;;;:45;;;;;;;;;;;;;;;;;;2321:6;:24;;;2288:12;:30;;;:57;;;;;;;;;;;;;;;;;;2385:11;2356:12;:26;;;:40;;;;;;;;;;;;;;;;;;2459:15;2407:12;:42;;;:68;;;;;;;;;;;;;;;;;;2519:8;2485:12;:31;;;:42;;;;;;;;;;;;;;;;;;2646:9:4;2537:12:12;:30;;;:62;;;;;;;;;;;;;;;;;;2635:16;2609:12;:23;;;:42;;;;;;;;;;;;;;;;;;1004:4:4;2673:12:12;:32;;:63;;;;2794:11;2753:53;;2781:11;2753:53;;2769:10;2753:53;;;;;;;;;;;;-1:-1:-1;2824:11:12;;905:1937;-1:-1:-1;;;;;905:1937:12:o;6515:279::-;6635:28;;;;6582:20;6635:28;;;:16;:28;;;;;:42;6582:20;;6635:42;6695:24;6687:59;;;;;;;5408:2:14;6687:59:12;;;5390:21:14;5447:2;5427:18;;;5420:30;5486:24;5466:18;;;5459:52;5528:18;;6687:59:12;5206:346:14;6687:59:12;6763:24;;;;;;:12;:24;;;;;;6515:279;-1:-1:-1;;6515:279:12:o;459:236:3:-;522:17;584:1;581;574:12;642:2;637;621:14;617:23;613:2;600:45;-1:-1:-1;677:1:3;671:8;;459:236::o;402:229:2:-;484:7;526:3;511:12;:18;503:55;;;;;;;9239:2:14;503:55:2;;;9221:21:14;9278:2;9258:18;;;9251:30;9317:26;9297:18;;;9290:54;9361:18;;503:55:2;9037:348:14;503:55:2;-1:-1:-1;583:40:2;;402:229::o;2090:937::-;2209:22;;;2169:37;2209:22;;;:13;:22;;;;;;;;2269:32;;2367:14;:23;;;;;2269:32;;;;;;;2405:22;;2401:277;;2447:33;;:47;;;;:33;;;;;:47;2443:60;;;2496:7;;;2090:937;;:::o;2443:60::-;2549:1;2535:133;2556:17;2552:21;;:1;:21;2535:133;;;2616:10;2602:24;;:7;2610:1;2602:10;;;;;;;:::i;:::-;;;;;:24;2598:37;;;2628:7;;;;2090:937;;:::o;2598:37::-;2575:3;;;;:::i;:::-;;;;2535:133;;;;2401:277;544:2:4;2696:17:2;:39;;;2688:78;;;;;;;10170:2:14;2688:78:2;;;10152:21:14;10209:2;10189:18;;;10182:30;10248:28;10228:18;;;10221:56;10294:18;;2688:78:2;9968:350:14;2688:78:2;2781:22;;;2777:128;;2805:46;;;;;;;;;;;;2777:128;;;2895:10;2866:7;2874:17;2866:26;;;;;;;;;:::i;:::-;;:39;;;;;;;;;;;;;;;2777:128;2951:21;:17;2971:1;2951:21;:::i;:::-;2916:56;;;;;;;;;;;;;;;;2988:32;;;;;;;;;;;;;2916;;2988;2159:868;;;2090:937;;:::o;846:631::-;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;9715:203::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9859:52:2;9874:10;9886:12;9900:10;9859:14;:52::i;:::-;;9715:203;;;;:::o;3099:1304::-;3217:22;;;3177:37;3217:22;;;:13;:22;;;;;;;;3277:32;;3375:14;:23;;;;;3277:32;;;;;;;3427:14;3277:32;3452:35;;3480:7;;;;3099:1304;;:::o;3452:35::-;3519:33;;:47;;;;:33;;;;;:47;3515:387;;;-1:-1:-1;3596:1:2;3515:387;;;3642:1;3628:190;3649:17;3645:21;;:1;:21;3628:190;;;3709:10;3695:24;;:7;3703:1;3695:10;;;;;;;:::i;:::-;;;;;:24;3691:113;;;3757:1;3743:15;;3780:5;;3691:113;3668:3;;;;:::i;:::-;;;;3628:190;;;;3851:14;3836:11;:29;3832:42;;;3867:7;;;;3099:1304;;:::o;3832:42::-;3912:20;3935:21;3955:1;3935:17;:21;:::i;:::-;3912:44;;;;3986:15;3971:11;:30;3967:209;;4021:16;4017:148;;4075:7;4083:15;4075:24;;;;;;;:::i;:::-;;;4039:60;;;;4075:24;;;;4039:60;;;;;4017:148;;;4141:7;4149:15;4141:24;;;;;;;:::i;:::-;;;;;4118:7;4126:11;4118:20;;;;;;;:::i;:::-;;:47;;;;;;;;;;;;;;;4017:148;4186:58;;;;;;;;;;;;4259:20;;4255:63;;4316:1;4281:7;4289:15;4281:24;;;;;;;:::i;:::-;;:37;;;;;;;;;;;;;;;4255:63;4388:7;4365:31;;4376:10;4365:31;;;;;;;;;;;;3167:1236;;;;;3099:1304;;:::o;24612:446::-;24687:22;;;24672:12;24687:22;;;:13;:22;;;;;:43;;;24745:30;24741:311;;24834:71;;601:42:14;589:55;;24834:71:2;;;571:74:14;24791:115:2;;2522:9:4;;24857:38:2;;544:18:14;;24834:71:2;425:226:14;24791:115:2;;24662:396;24612:446;:::o;24741:311::-;24927:31;;;1555:1:4;24927:31:2;24923:129;;;24974:22;;;;;;;:13;:22;;;;;:67;;;;1610:1:4;24974:67:2;;;24923:129;24662:396;24612:446;:::o;1063:258:0:-;1169:12;1206:22;;;:12;:22;;;;;;;:42;;1144:12;;1169;;;1206:22;;;;;:42;;1242:5;;1206:42;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1168:80;;;;1263:7;1258:33;;1272:19;1284:6;1272:11;:19::i;:::-;1308:6;1063:258;-1:-1:-1;;;;1063:258:0:o;249:808::-;309:7;336:18;328:60;;;;;;;11415:2:14;328:60:0;;;11397:21:14;11454:2;11434:18;;;11427:30;11493:31;11473:18;;;11466:59;11542:18;;328:60:0;11213:353:14;328:60:0;2436:7:4;406:13:0;:38;;398:81;;;;;;;11773:2:14;398:81:0;;;11755:21:14;11812:2;11792:18;;;11785:30;11851:32;11831:18;;;11824:60;11901:18;;398:81:0;11571:354:14;398:81:0;620:1;582:26;;;:11;:26;;;;;;:40;:26;:40;578:79;;-1:-1:-1;631:26:0;;;;:11;:26;;;;;;;;;249:808::o;578:79::-;706:17;734:11;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;706:40;;2230:7:4;761:13:0;:51;757:95;;814:26;;;;:11;:26;;;;;:38;;;;;;;;;;757:95;891:78;;;;;;;;;;;;;;-1:-1:-1;891:78:0;;;;;;;;863:25;;;;;;:14;:25;;;;;;;:106;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;985:38;;;;;;928:13;1869:25:14;;1857:2;1842:18;;1723:177;985:38:0;;;;;;;;1041:9;249:808;-1:-1:-1;;249:808:0: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;2580:232:0:-;2650:13;;:17;2646:126;;2740:6;2734:13;2725:6;2721:2;2717:15;2710:38;2646:126;2782:23;;;;;13468:2:14;2782:23:0;;;13450:21:14;13507:2;13487:18;;;13480:30;13546:15;13526:18;;;13519:43;13579:18;;2782:23:0;13266:337:14;11837:857:2;2125:4:0;2119:11;;12105:21:2;;:32:::1;589:55:14::0;;;12150:58:2::1;::::0;;::::1;571:74:14::0;;;;12150:58:2;;;;;;;;;;544:18:14;;;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;;;;;;;13999:2:14;10726:76:2;;;13981:21:14;14038:2;14018:18;;;14011:30;14077:34;14057:18;;;14050:62;14148:3;14128:18;;;14121:31;14169:19;;10726:76:2;13797:397:14;10726:76:2;-1:-1:-1;10827:6:2;10645:196::o;10442:197::-;10505:6;350:16:4;10531:31:2;;;10523:78;;;;;;;14401:2:14;10523:78:2;;;14383:21:14;14440:2;14420:18;;;14413:30;14479:34;14459:18;;;14452:62;14550:4;14530:18;;;14523:32;14572:19;;10523:78:2;14199:398:14;10254:182:2;10312:7;280:17:4;10339:25:2;;;10331:66;;;;;;;14804:2:14;10331:66:2;;;14786:21:14;14843:2;14823:18;;;14816:30;14882;14862:18;;;14855:58;14930:18;;10331:66:2;14602:352:14;-1:-1:-1;;;;;;;;:::o;:::-;;;;;;;;:::o;14:154:14:-;100:42;93:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;69:93;14:154;:::o;173:247::-;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;340:9;327:23;359:31;384:5;359:31;:::i;1905:315::-;1973:6;1981;2034:2;2022:9;2013:7;2009:23;2005:32;2002:52;;;2050:1;2047;2040:12;2002:52;2086:9;2073:23;2063:33;;2146:2;2135:9;2131:18;2118:32;2159:31;2184:5;2159:31;:::i;:::-;2209:5;2199:15;;;1905:315;;;;;:::o;2419:681::-;2590:2;2642:21;;;2712:13;;2615:18;;;2734:22;;;2561:4;;2590:2;2813:15;;;;2787:2;2772:18;;;2561:4;2856:218;2870:6;2867:1;2864:13;2856:218;;;2935:13;;2950:42;2931:62;2919:75;;3049:15;;;;3014:12;;;;2892:1;2885:9;2856:218;;;-1:-1:-1;3091:3:14;;2419:681;-1:-1:-1;;;;;;2419:681:14:o;5906:273::-;5974:6;6027:2;6015:9;6006:7;6002:23;5998:32;5995:52;;;6043:1;6040;6033:12;5995:52;6075:9;6069:16;6125:4;6118:5;6114:16;6107:5;6104:27;6094:55;;6145:1;6142;6135:12;6532:184;6584:77;6581:1;6574:88;6681:4;6678:1;6671:15;6705:4;6702:1;6695:15;6721:407;6793:2;6787:9;6835:4;6823:17;;6870:18;6855:34;;6891:22;;;6852:62;6849:242;;;6947:77;6944:1;6937:88;7048:4;7045:1;7038:15;7076:4;7073:1;7066:15;6849:242;7107:2;7100:22;6721:407;:::o;7133:402::-;7200:2;7194:9;7242:4;7230:17;;7277:18;7262:34;;7298:22;;;7259:62;7256:242;;;7354:77;7351:1;7344:88;7455:4;7452:1;7445:15;7483:4;7480:1;7473:15;7540:167;7618:13;;7671:10;7660:22;;7650:33;;7640:61;;7697:1;7694;7687:12;7712:1320;7819:6;7863:9;7854:7;7850:23;7893:3;7889:2;7885:12;7882:32;;;7910:1;7907;7900:12;7882:32;7936:22;;:::i;:::-;7988:9;7982:16;8042:6;8033:7;8029:20;8020:7;8017:33;8007:61;;8064:1;8061;8054:12;8007:61;8077:22;;8131:48;8175:2;8160:18;;8131:48;:::i;:::-;8126:2;8119:5;8115:14;8108:72;8273:4;8204:66;8200:2;8196:75;8192:86;8189:106;;;8291:1;8288;8281:12;8189:106;8319:17;;:::i;:::-;8304:32;;8381:2;8370:9;8366:18;8360:25;8394:33;8419:7;8394:33;:::i;:::-;8436:24;;8505:4;8490:20;;8484:27;8549:15;;8542:23;8530:36;;8520:64;;8580:1;8577;8570:12;8520:64;8613:2;8600:16;;8593:33;8660:49;8704:3;8689:19;;8660:49;:::i;:::-;8655:2;8646:7;8642:16;8635:75;8746:50;8790:4;8779:9;8775:20;8746:50;:::i;:::-;8739:4;8730:7;8726:18;8719:78;8842:3;8831:9;8827:19;8821:26;8891:8;8882:7;8878:22;8869:7;8866:35;8856:63;;8915:1;8912;8905:12;8856:63;8948:3;8935:17;;8928:34;8989:2;8978:14;;8971:31;;;;8982:5;7712:1320;-1:-1:-1;;;7712:1320:14:o;9390:184::-;9442:77;9439:1;9432:88;9539:4;9536:1;9529:15;9563:4;9560:1;9553:15;9579:184;9631:77;9628:1;9621:88;9728:4;9725:1;9718:15;9752:4;9749:1;9742:15;9768:195;9807:3;9838:66;9831:5;9828:77;9825:103;;;9908:18;;:::i;:::-;-1:-1:-1;9955:1:14;9944:13;;9768:195::o;10323:228::-;10362:3;10390:10;10427:2;10424:1;10420:10;10457:2;10454:1;10450:10;10488:3;10484:2;10480:12;10475:3;10472:21;10469:47;;;10496:18;;:::i;:::-;10532:13;;10323:228;-1:-1:-1;;;;10323:228:14:o;10556:221::-;10595:4;10624:10;10684;;;;10654;;10706:12;;;10703:38;;;10721:18;;:::i;:::-;10758:13;;10556:221;-1:-1:-1;;;10556:221:14:o;10782:426::-;10911:3;10949:6;10943:13;10974:1;10984:129;10998:6;10995:1;10992:13;10984:129;;;11096:4;11080:14;;;11076:25;;11070:32;11057:11;;;11050:53;11013:12;10984:129;;;11131:6;11128:1;11125:13;11122:48;;;11166:1;11157:6;11152:3;11148:16;11141:27;11122:48;-1:-1:-1;11186:16:14;;;;;10782:426;-1:-1:-1;;10782:426:14:o;11930:184::-;11982:77;11979:1;11972:88;12079:4;12076:1;12069:15;12103:4;12100:1;12093:15;12119:125;12159:4;12187:1;12184;12181:8;12178:34;;;12192:18;;:::i;:::-;-1:-1:-1;12229:9:14;;12119:125::o;12249:367::-;12288:3;12323:1;12320;12316:9;12432:1;12364:66;12360:74;12357:1;12353:82;12348:2;12341:10;12337:99;12334:125;;;12439:18;;:::i;:::-;12558:1;12490:66;12486:74;12483:1;12479:82;12475:2;12471:91;12468:117;;;12565:18;;:::i;:::-;-1:-1:-1;;12601:9:14;;12249:367::o;12621:228::-;12661:7;12787:1;12719:66;12715:74;12712:1;12709:81;12704:1;12697:9;12690:17;12686:105;12683:131;;;12794:18;;:::i;:::-;-1:-1:-1;12834:9:14;;12621:228::o;12854:274::-;12894:1;12920;12910:189;;12955:77;12952:1;12945:88;13056:4;13053:1;13046:15;13084:4;13081:1;13074:15;12910:189;-1:-1:-1;13113:9:14;;12854:274::o;13133:128::-;13173:3;13204:1;13200:6;13197:1;13194:13;13191:39;;;13210:18;;:::i;:::-;-1:-1:-1;13246:9:14;;13133:128::o;13608:184::-;13678:6;13731:2;13719:9;13710:7;13706:23;13702:32;13699:52;;;13747:1;13744;13737:12;13699:52;-1:-1:-1;13770:16:14;;13608:184;-1:-1:-1;13608:184:14:o
Swarm Source
ipfs://bab4ca0cee53832e0638f7772d7f036b1e48f23adb2847292921470e52a1b947
Loading...
Loading
Loading...
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.