Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
MtrollerUser
Compiler Version
v0.5.16+commit.9c3226ce
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.5.16; import "./PriceOracle.sol"; import "./MtrollerInterface.sol"; import "./MtrollerCommon.sol"; import "./MTokenInterfaces.sol"; import "./Mmo.sol"; import "./ErrorReporter.sol"; import "./compound/ExponentialNoError.sol"; /** * @title Based on Compound's Mtroller Contract, with some modifications * @dev This contract must not declare any variables. All required storage must be inherited from MtrollerCommon * @author Compound, mmo.finance */ contract MtrollerUser is MtrollerCommon, MtrollerUserInterface { /** * @notice Constructs a new MtrollerUser */ constructor() public MtrollerCommon() { } /** * @notice Returns the type of implementation for this contract */ function isMDelegatorUserImplementation() public pure returns (bool) { return true; } /*** Assets You Are In ***/ /** * @notice Returns the assets an account has entered * @param account The address of the account to pull assets for * @return A dynamic list with the assets the account has entered */ function getAssetsIn(address account) external view returns (uint240[] memory) { uint240[] memory assetsIn = accountAssets[account]; return assetsIn; } /** * @notice Returns whether the given account is entered in the given asset * @param account The address of the account to check * @param mToken The mToken to check * @return True if the account is in the asset, otherwise false. */ function checkMembership(address account, uint240 mToken) external view returns (bool) { return accountMembership(mToken, account); } /** * @notice Returns whether the given account is entered in the given asset * @param account The address of the account to check * @param mToken The mToken to check * @return True if the account is in the asset, otherwise false. */ function accountMembership(uint240 mToken, address account) internal view returns (bool) { return markets[mToken]._accountMembership[account]; } /** * @notice Add assets to be included in account liquidity calculation * @param mTokens The list of mToken markets to be enabled * @return Success indicator for whether each corresponding market was entered (0 = success, * otherwise error code) */ function enterMarkets(uint240[] memory mTokens) public returns (uint[] memory) { uint len = mTokens.length; uint[] memory results = new uint[](len); for (uint i = 0; i < len; i++) { results[i] = uint(addToMarketInternal(mTokens[i], msg.sender)); } return results; } /** * @notice Allows the mToken contract to enter the market on a user's behalf * @param mToken The mToken market to be entered * @param owner The mToken owner on whose behalf the market should be entered * @return Success indicator for whether the market was entered */ function enterMarketOnBehalf(uint240 mToken, address owner) external returns (uint) { ( , , address mTokenAddress) = parseToken(mToken); require(msg.sender == mTokenAddress, "Only mToken contract can do this, only for own mToken"); return uint(addToMarketInternal(mToken, owner)); } /** * @notice Add the mToken market to the borrower's "assets in" for liquidity calculations * @param mToken The market to enter * @param borrower The address of the account to modify * @return Success indicator for whether the market was entered */ function addToMarketInternal(uint240 mToken, address borrower) internal returns (Error) { if (!isListed(mToken)) { // market is not listed, cannot join return Error.MARKET_NOT_LISTED; } if (accountMembership(mToken, borrower) == true) { // already joined return Error.NO_ERROR; } if (accountAssets[borrower].length >= maxAssets) { // no more assets allowed in the market for that borrower return Error.TOO_MANY_ASSETS; } // survived the gauntlet, add to list // NOTE: we store these somewhat redundantly as a significant optimization // this avoids having to iterate through the list for the most common use cases // that is, only when we need to perform liquidity checks // and not whenever we want to check if an account is in a particular market markets[mToken]._accountMembership[borrower] = true; accountAssets[borrower].push(mToken); emit MarketEntered(mToken, borrower); return Error.NO_ERROR; } /** * @notice Removes asset from sender's account liquidity calculation * @dev Sender must not have an outstanding borrow balance in the asset, * or be providing necessary collateral for an outstanding borrow. * @param mToken The asset to be removed * @return Whether or not the account successfully exited the market */ function exitMarket(uint240 mToken) external returns (uint) { return exitMarketInternal(mToken, msg.sender); } /** * @notice Allows the mToken contract to exit the market on a user's behalf * @param mToken The mToken market to be exited * @param owner The mToken owner on whose behalf the market should be exited * @return Success indicator for whether the market was exited */ function exitMarketOnBehalf(uint240 mToken, address owner) external returns (uint) { ( , , address mTokenAddress) = parseToken(mToken); require(msg.sender == mTokenAddress, "Only token contract can do this, only for own token"); return uint(exitMarketInternal(mToken, owner)); } function exitMarketInternal(uint240 mToken, address borrower) internal returns (uint) { /* Fail if mToken not listed */ if (!isListed(mToken)) { return uint(Error.MARKET_NOT_LISTED); } /* Get sender tokensHeld and amountOwed underlying from the mToken */ ( , , address mTokenAddress) = parseToken(mToken); (uint oErr, uint tokensHeld, uint amountOwed, ) = MTokenInterface(mTokenAddress).getAccountSnapshot(borrower, mToken); require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code /* Fail if the sender has a borrow balance */ if (amountOwed != 0) { return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED); } /* If the borrower still holds tokens in that market they have to be all redeemable */ if (tokensHeld != 0) { /* Fail if the sender is not permitted to redeem all of their tokens */ uint allowed = redeemAllowedInternal(mToken, borrower, tokensHeld); if (allowed != 0) { return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed); } } /* Return true if the sender is not already ‘in’ the market */ if (!accountMembership(mToken, borrower)) { return uint(Error.NO_ERROR); } /* Set mToken account membership to false */ delete markets[mToken]._accountMembership[borrower]; /* Delete mToken from the account’s list of assets */ // load into memory for faster iteration uint240[] memory userAssetList = accountAssets[borrower]; uint len = userAssetList.length; uint assetIndex = len; for (uint i = 0; i < len; i++) { if (userAssetList[i] == mToken) { assetIndex = i; break; } } // We *must* have found the asset in the list or our redundant data structure is broken assert(assetIndex < len); // copy last item in list to location of item to be removed, reduce length by 1 uint240[] storage storedList = accountAssets[borrower]; storedList[assetIndex] = storedList[storedList.length - 1]; storedList.length--; emit MarketExited(mToken, borrower); return uint(Error.NO_ERROR); } /** * @notice Sets the collateralFactor for a mToken market * @dev Admin function to set per-market collateralFactor * @param mToken The mToken to set the factor on * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) */ function _setCollateralFactor(uint240 mToken, uint newCollateralFactorMantissa) external returns (uint) { // Check caller is admin if (msg.sender != getAdmin()) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK); } return _setCollateralFactorInternal(mToken, newCollateralFactorMantissa); } function _setCollateralFactorInternal(uint240 mToken, uint newCollateralFactorMantissa) internal returns (uint) { // Verify market is listed if (!isListed(mToken)) { return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS); } // Checks in case of individual collateral factor (i.e., for sub-markets) if (mToken != getAnchorToken(mToken)) { // fail if price == 0 if (getPrice(mToken) == 0) { return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE); } // Checks that new individual collateral factor <= collateralFactorMaxMantissa if (newCollateralFactorMantissa > collateralFactorMaxMantissa) { return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION); } } // Set market's collateral factor to new collateral factor, remember old value uint oldCollateralFactorMantissa = markets[mToken]._collateralFactorMantissa; markets[mToken]._collateralFactorMantissa = newCollateralFactorMantissa; // Checks that total (=combined) collateral factor is in range, otherwise reverts collateralFactorMantissa(mToken); // Emit event with asset, old collateral factor, and new collateral factor emit NewCollateralFactor(mToken, oldCollateralFactorMantissa, newCollateralFactorMantissa); return uint(Error.NO_ERROR); } /*** Policy Hooks ***/ /** * @notice Checks if the given market is allowed for auctions * @param mToken The market for which to allow auctions * @param bidder The address wanting to use the auction * @return 0 if auctions are allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function auctionAllowed(uint240 mToken, address bidder) public view returns (uint) { // Shh - currently unused bidder; (MTokenType mTokenType, , address tokenAddress) = parseToken(mToken); // Pausing is a very serious situation - we revert to sound the alarms require(!auctionGuardianPaused[getAnchorToken(mToken)], "auction is paused"); require(!auctionGuardianPaused[mToken], "auction is paused"); if (!isListed(mToken)) { return uint(Error.MARKET_NOT_LISTED); } // Fail for fungible tokens if (mTokenType != MTokenType.ERC721_MTOKEN) { return uint(Error.MARKET_NOT_LISTED); } // Fail for non-existing (e.g. already redeemed) tokens if (MERC721Interface(tokenAddress).ownerOf(mToken) == address(0)) { return uint(Error.MARKET_NOT_LISTED); } // Keep the flywheel moving // updateMmoSupplyIndex(mToken); // distributeSupplierMmo(mToken, bidder); return uint(Error.NO_ERROR); } /** * @notice Checks if the account should be allowed to mint tokens in the given market * @dev Also, if the anchor market of the mToken is listed, this automatically lists the mToken. * To avoid rogue mTokens being listed this can only be called by the mToken's own contract. * @param mToken The market to verify the mint against * @param minter The account which would get the minted tokens * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function mintAllowed(uint240 mToken, address minter, uint mintAmount) external returns (uint) { // Shh - currently unused minter; mintAmount; // only allow calls from own mToken contract (to avoid listing of rogue mTokens) ( , uint72 mTokenSeqNr, address mTokenAddress) = parseToken(mToken); require(mTokenSeqNr <= MTokenCommon(mTokenAddress).totalCreatedMarkets(), "invalid mToken SeqNr"); require(msg.sender == mTokenAddress, "only mToken can call this"); // Pausing is a very serious situation - we revert to sound the alarms uint240 mTokenAnchor = getAnchorToken(mToken); require(!mintGuardianPaused[mTokenAnchor], "mint is paused"); require(!mintGuardianPaused[mToken], "mint is paused"); // Require anchor token to be listed already if (!isListed(mTokenAnchor)) { return uint(Error.MARKET_NOT_LISTED); } if (!isListed(mToken)) { // support new (sub-)market (collateral factor of the anchor token is used by default) uint err = _supportMarketInternal(mToken); if (err != uint(Error.NO_ERROR)) { return err; } // fail if price == 0 if (getPrice(mToken) == 0) { return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE); } } // Keep the flywheel moving // updateMmoSupplyIndex(mToken); // distributeSupplierMmo(mToken, minter); return uint(Error.NO_ERROR); } /** * @notice Validates mint and reverts on rejection. May emit logs. * @param mToken Asset being minted * @param minter The address minting the tokens * @param actualMintAmount The amount of the underlying asset being minted * @param mintTokens The number of tokens being minted */ function mintVerify(uint240 mToken, address minter, uint actualMintAmount, uint mintTokens) external view { // Shh - currently unused mToken; minter; actualMintAmount; mintTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets; } } /** * @notice Checks if the account should be allowed to redeem tokens in the given market * @param mToken The market to verify the redeem against * @param redeemer The account which would redeem the tokens * @param redeemTokens The number of mTokens to exchange for the underlying asset in the market * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function redeemAllowed(uint240 mToken, address redeemer, uint redeemTokens) external view returns (uint) { uint allowed = redeemAllowedInternal(mToken, redeemer, redeemTokens); if (allowed != uint(Error.NO_ERROR)) { return allowed; } // Keep the flywheel moving // updateMmoSupplyIndex(mToken); // distributeSupplierMmo(mToken, redeemer); return uint(Error.NO_ERROR); } function redeemAllowedInternal(uint240 mToken, address redeemer, uint redeemTokens) internal view returns (uint) { if (!isListed(mToken)) { return uint(Error.MARKET_NOT_LISTED); } /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ if (!accountMembership(mToken, redeemer)) { return uint(Error.NO_ERROR); } /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, mToken, redeemTokens, 0); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall > 0) { return uint(Error.INSUFFICIENT_LIQUIDITY); } return uint(Error.NO_ERROR); } /** * @notice Validates redeem and reverts on rejection. May emit logs. * @param mToken Asset being redeemed * @param redeemer The address redeeming the tokens * @param redeemAmount The amount of the underlying asset being redeemed * @param redeemTokens The number of tokens being redeemed */ function redeemVerify(uint240 mToken, address redeemer, uint redeemAmount, uint redeemTokens) external view { // Shh - currently unused mToken; redeemer; // If redeemTokens is zero, require aldo redeemAmount to be zero if (redeemTokens == 0 && redeemAmount > 0) { revert("redeemTokens zero"); } } /** * @notice Checks if the account should be allowed to borrow the underlying asset of the given market * @param mToken The market to verify the borrow against * @param borrower The account which would borrow the asset * @param borrowAmount The amount of underlying the account would borrow * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function borrowAllowed(uint240 mToken, address borrower, uint borrowAmount) external view returns (uint) { ( , , address mTokenAddress) = parseToken(mToken); // Pausing is a very serious situation - we revert to sound the alarms require(!borrowGuardianPaused[getAnchorToken(mToken)], "borrow is paused"); require(!borrowGuardianPaused[mToken], "borrow is paused"); if (!isListed(mToken)) { return uint(Error.MARKET_NOT_LISTED); } // This should never occur since borrow() should call enterMarketOnBehalf() first if (!accountMembership(mToken, borrower)) { return uint(Error.MARKET_NOT_ENTERED); } if (getPrice(mToken) == 0) { return uint(Error.PRICE_ERROR); } // Borrow cap is the minimum of the global cap of the mToken and the cap of the sub-market (if any) uint borrowCap = borrowCaps[getAnchorToken(mToken)]; uint borrowCapSubmarket = borrowCaps[mToken]; if (borrowCap == 0 || (borrowCapSubmarket != 0 && borrowCapSubmarket < borrowCap)) { borrowCap = borrowCapSubmarket; } // Borrow cap of 0 corresponds to unlimited borrowing if (borrowCap != 0) { uint totalBorrows = MTokenCommon(mTokenAddress).totalBorrows(mToken); uint nextTotalBorrows = add_(totalBorrows, borrowAmount); require(nextTotalBorrows < borrowCap, "market borrow cap reached"); } (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, mToken, 0, borrowAmount); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall > 0) { return uint(Error.INSUFFICIENT_LIQUIDITY); } // Keep the flywheel moving // Exp memory borrowIndex = Exp({mantissa: MTokenCommon(mTokenAddress).borrowIndex(mToken)}); // updateMmoBorrowIndex(mToken, borrowIndex); // distributeBorrowerMmo(mToken, borrower, borrowIndex); return uint(Error.NO_ERROR); } /** * @notice Validates borrow and reverts on rejection. May emit logs. * @param mToken Asset whose underlying is being borrowed * @param borrower The address borrowing the underlying * @param borrowAmount The amount of the underlying asset requested to borrow */ function borrowVerify(uint240 mToken, address borrower, uint borrowAmount) external view { // Shh - currently unused mToken; borrower; borrowAmount; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets; } } /** * @notice Checks if the account should be allowed to repay a borrow in the given market * @param mToken The market to verify the repay against * @param payer The account which would repay the asset * @param borrower The account which would borrowed the asset * @param repayAmount The amount of the underlying asset the account would repay * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function repayBorrowAllowed(uint240 mToken, address payer, address borrower, uint repayAmount) external view returns (uint) { // Shh - currently unused payer; borrower; repayAmount; // ( , , address mTokenAddress) = parseToken(mToken); if (!isListed(mToken)) { return uint(Error.MARKET_NOT_LISTED); } // Keep the flywheel moving // Exp memory borrowIndex = Exp({mantissa: MTokenCommon(mTokenAddress).borrowIndex(mToken)}); // updateMmoBorrowIndex(mToken, borrowIndex); // distributeBorrowerMmo(mToken, borrower, borrowIndex); return uint(Error.NO_ERROR); } /** * @notice Validates repayBorrow and reverts on rejection. May emit logs. * @param mToken Asset being repaid * @param payer The address repaying the borrow * @param borrower The address of the borrower * @param actualRepayAmount The amount of underlying being repaid * @param borrowerIndex The borrower index before repayment */ function repayBorrowVerify(uint240 mToken, address payer, address borrower, uint actualRepayAmount, uint borrowerIndex) external view { // Shh - currently unused mToken; payer; borrower; actualRepayAmount; borrowerIndex; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets; } } /** * @notice Checks if the liquidation should be allowed to occur * @param mTokenBorrowed The mToken in which underlying asset was borrowed by the borrower * @param mTokenCollateral The mToken which was used as collateral and will be seized * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param repayAmount The amount of underlying being repaid * @return 0 if the liquidation is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function liquidateBorrowAllowed(uint240 mTokenBorrowed, uint240 mTokenCollateral, address liquidator, address borrower, uint repayAmount) external view returns (uint) { // Shh - currently unused liquidator; /* Fail if mTokenCollateral is non-fungible (ERC-721) type */ (MTokenType mTokenType, , ) = parseToken(mTokenCollateral); if (mTokenType == MTokenType.ERC721_MTOKEN) { return uint(Error.INVALID_TOKEN_TYPE); } if (!isListed(mTokenBorrowed) || !isListed(mTokenCollateral)) { return uint(Error.MARKET_NOT_LISTED); } /* Fail if borrower not "in" the markets for both mTokenBorrowed and mTokenCollateral */ if (!accountMembership(mTokenBorrowed, borrower) || !accountMembership(mTokenCollateral, borrower)) { return uint(Error.MARKET_NOT_ENTERED); } /* The borrower must have shortfall in order to be liquidatable */ (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall == 0) { return uint(Error.INSUFFICIENT_SHORTFALL); } /* The liquidator may not repay more than what is allowed by the closeFactor */ ( , , address mTokenBorrowedAddress) = parseToken(mTokenBorrowed); uint borrowBalance = MTokenInterface(mTokenBorrowedAddress).borrowBalanceStored(borrower, mTokenBorrowed); uint maxClose = mul_ScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance); if (repayAmount > maxClose) { return uint(Error.TOO_MUCH_REPAY); } return uint(Error.NO_ERROR); } /** * @notice Check if liquidation of non-fungible (ERC-721) mToken collateral is allowed * @param mToken The mToken collateral to check * @return 0 if the liquidation is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function liquidateERC721Allowed(uint240 mToken) external view returns (uint) { /* Fail if mToken is not non-fungible (ERC-721) type */ (MTokenType mTokenType, , address mTokenAddress) = parseToken(mToken); if (mTokenType != MTokenType.ERC721_MTOKEN) { return uint(Error.INVALID_TOKEN_TYPE); } if (!isListed(mToken)) { return uint(Error.MARKET_NOT_LISTED); } /* Fail if owner not "in" the markets for mToken */ address owner = MERC721Interface(mTokenAddress).ownerOf(mToken); if (!accountMembership(mToken, owner)) { return uint(Error.MARKET_NOT_ENTERED); } /* Fail if mToken cannot be auctioned by sender (liquidator) */ uint err = auctionAllowed(mToken, msg.sender); if (err != uint(Error.NO_ERROR)) { return err; } /* Fail if mToken owner has no shortfall (anymore) */ uint shortfall; (err, , shortfall) = getAccountLiquidity(owner); if (err != uint(Error.NO_ERROR) || shortfall == 0) { return uint(Error.INSUFFICIENT_SHORTFALL); } /* Fail if sender (liquidator) is also owner */ if (msg.sender == owner) { return uint(Error.UNAUTHORIZED); } return uint(Error.NO_ERROR); } /** * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. * @param mTokenBorrowed The mToken in which underlying asset was borrowed by the borrower * @param mTokenCollateral The mToken which was used as collateral and will be seized * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param actualRepayAmount The amount of underlying in mTokenBorrowed actually being repaid * @param seizeTokens The number of mTokenCollateral tokens seized */ function liquidateBorrowVerify(uint240 mTokenBorrowed, uint240 mTokenCollateral, address liquidator, address borrower, uint actualRepayAmount, uint seizeTokens) external view { // Shh - currently unused mTokenBorrowed; mTokenCollateral; liquidator; borrower; actualRepayAmount; seizeTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets; } } /** * @notice Checks if the seizing of assets should be allowed to occur * @param mTokenCollateral The mToken which was used as collateral and will be seized * @param mTokenBorrowed The mToken in which underlying asset was borrowed by the borrower * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param seizeTokens The number of collateral tokens to seize */ function seizeAllowed(uint240 mTokenCollateral, uint240 mTokenBorrowed, address liquidator, address borrower, uint seizeTokens) external view returns (uint) { // Shh - currently unused liquidator; seizeTokens; ( , , address mTokenCollateralAddress) = parseToken(mTokenCollateral); ( , , address mTokenBorrowedAddress) = parseToken(mTokenBorrowed); // Pausing is a very serious situation - we revert to sound the alarms require(!seizeGuardianPaused[getAnchorToken(mTokenCollateral)], "seize is paused"); require(!seizeGuardianPaused[mTokenCollateral], "seize is paused"); if (!isListed(mTokenCollateral) || !isListed(mTokenBorrowed)) { return uint(Error.MARKET_NOT_LISTED); } /* Fail if borrower not "in" the markets for both mTokenBorrowed and mTokenCollateral */ if (!accountMembership(mTokenBorrowed, borrower) || !accountMembership(mTokenCollateral, borrower)) { return uint(Error.MARKET_NOT_ENTERED); } if (MTokenCommon(mTokenCollateralAddress).mtroller() != MTokenCommon(mTokenBorrowedAddress).mtroller()) { return uint(Error.MTROLLER_MISMATCH); } // Keep the flywheel moving // updateMmoSupplyIndex(mTokenCollateral); // distributeSupplierMmo(mTokenCollateral, borrower); // distributeSupplierMmo(mTokenCollateral, liquidator); return uint(Error.NO_ERROR); } /** * @notice Validates seize and reverts on rejection. May emit logs. * @param mTokenCollateral The mToken which was used as collateral and will be seized * @param mTokenBorrowed The mToken in which underlying asset was borrowed by the borrower * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param seizeTokens The number of collateral tokens to seize */ function seizeVerify(uint240 mTokenCollateral, uint240 mTokenBorrowed, address liquidator, address borrower, uint seizeTokens) external view { // Shh - currently unused mTokenCollateral; mTokenBorrowed; liquidator; borrower; seizeTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets; } } /** * @notice Checks if the account should be allowed to transfer tokens in the given market * @param mToken The market to verify the transfer against * @param src The account which sources the mTokens * @param dst The account which receives the mTokens * @param transferTokens The number of mTokens to transfer * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function transferAllowed(uint240 mToken, address src, address dst, uint transferTokens) external view returns (uint) { // Shh - currently unused dst; // Pausing is a very serious situation - we revert to sound the alarms require(!transferGuardianPaused[getAnchorToken(mToken)], "transfer is paused"); require(!transferGuardianPaused[mToken], "transfer is paused"); // Currently the only consideration is whether or not // the src is allowed to redeem this many tokens // NB: This also checks mToken validity uint allowed = redeemAllowedInternal(mToken, src, transferTokens); if (allowed != uint(Error.NO_ERROR)) { return allowed; } // Keep the flywheel moving // updateMmoSupplyIndex(mToken); // distributeSupplierMmo(mToken, src); // distributeSupplierMmo(mToken, dst); return uint(Error.NO_ERROR); } /** * @notice Validates transfer and reverts on rejection. May emit logs. * @param mToken The mToken being transferred * @param src The account which sources the mTokens * @param dst The account which receives the mTokens * @param transferTokens The number of mTokens to transfer */ function transferVerify(uint240 mToken, address src, address dst, uint transferTokens) external view { // Shh - currently unused mToken; src; dst; transferTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets; } } /*** Liquidity/Liquidation Calculations ***/ /** * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. * Note that `mTokenBalance` is the number of mTokens the account owns in the market, * whereas `borrowBalance` is the amount of underlying that the account has borrowed. */ struct AccountLiquidityLocalVars { uint sumCollateral; uint sumBorrowPlusEffects; uint mTokenBalance; uint borrowBalance; uint exchangeRateMantissa; uint oraclePriceMantissa; Exp collateralFactor; Exp exchangeRate; Exp oraclePrice; Exp tokensToDenom; } /** * @notice Determine the current account liquidity wrt collateral requirements * @param account The account to determine liquidity for * @return (possible error code (semi-opaque), account liquidity in excess of collateral requirements, * account shortfall below collateral requirements) */ function getAccountLiquidity(address account) public view returns (uint, uint, uint) { (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, 0, 0, 0); return (uint(err), liquidity, shortfall); } /** * @notice Determine the current account liquidity wrt collateral requirements * @param account The account to determine liquidity for * @return (possible error code, account liquidity in excess of collateral requirements, * account shortfall below collateral requirements) */ function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) { return getHypotheticalAccountLiquidityInternal(account, 0, 0, 0); } /** * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed * @param account The account to determine liquidity for * @param mTokenModify The mToken market to hypothetically redeem/borrow in * @param redeemTokens The number of mTokens to hypothetically redeem * @param borrowAmount The amount of underlying to hypothetically borrow * @return (possible error code (semi-opaque), hypothetical account liquidity in excess of collateral requirements, * hypothetical account shortfall below collateral requirements) */ function getHypotheticalAccountLiquidity( address account, uint240 mTokenModify, uint redeemTokens, uint borrowAmount) public view returns (uint, uint, uint) { (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, mTokenModify, redeemTokens, borrowAmount); return (uint(err), liquidity, shortfall); } /** * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed * @param account The account to determine liquidity for * @param mTokenModify The mToken market to hypothetically redeem/borrow in * @param redeemTokens The number of mTokens to hypothetically redeem * @param borrowAmount The amount of underlying to hypothetically borrow * @dev Note that we calculate the exchangeRateStored for each collateral mToken using stored data, * without calculating accumulated interest. * @return (possible error code, hypothetical account liquidity in excess of collateral requirements, * hypothetical account shortfall below collateral requirements) */ function getHypotheticalAccountLiquidityInternal( address account, uint240 mTokenModify, uint redeemTokens, uint borrowAmount) internal view returns (Error, uint, uint) { AccountLiquidityLocalVars memory vars; // Holds all our calculation results uint oErr; // For each asset the account is in uint240[] memory assets = accountAssets[account]; for (uint i = 0; i < assets.length; i++) { uint240 asset = assets[i]; ( , , address assetAddress) = parseToken(asset); // Read the balances and exchange rate from the mToken (oErr, vars.mTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = MTokenInterface(assetAddress).getAccountSnapshot(account, asset); if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades return (Error.SNAPSHOT_ERROR, 0, 0); } vars.collateralFactor = Exp({mantissa: collateralFactorMantissa(asset)}); vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); // Get the normalized price of the asset vars.oraclePriceMantissa = getPrice(asset); if (vars.oraclePriceMantissa == 0) { return (Error.PRICE_ERROR, 0, 0); } vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); // Pre-compute a conversion factor from tokens -> ether (normalized price value) vars.tokensToDenom = mul_(mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice); // sumCollateral += tokensToDenom * mTokenBalance vars.sumCollateral = mul_ScalarTruncateAddUInt(vars.tokensToDenom, vars.mTokenBalance, vars.sumCollateral); // sumBorrowPlusEffects += oraclePrice * borrowBalance vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects); // Calculate effects of interacting with mTokenModify if (asset == mTokenModify) { // redeem effect // sumBorrowPlusEffects += tokensToDenom * redeemTokens vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects); // borrow effect // sumBorrowPlusEffects += oraclePrice * borrowAmount vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects); } } // These are safe, as the underflow condition is checked first if (vars.sumCollateral > vars.sumBorrowPlusEffects) { return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0); } else { return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral); } } /** * @notice Calculate number of tokens of collateral asset to seize given an underlying amount * @dev Used in liquidation (called in mToken.liquidateBorrowFresh) * @param mTokenBorrowed The borrowed mToken * @param mTokenCollateral The collateral mToken * @param actualRepayAmount The amount of mTokenBorrowed underlying to convert into mTokenCollateral tokens * @return (errorCode, number of mTokenCollateral tokens to be seized in a liquidation) */ function liquidateCalculateSeizeTokens(uint240 mTokenBorrowed, uint240 mTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) { if (!isListed(mTokenBorrowed) || !isListed(mTokenCollateral)) { return (uint(Error.MARKET_NOT_LISTED), 0); } /* Read oracle prices for borrowed and collateral markets */ uint priceBorrowedMantissa = getPrice(mTokenBorrowed); uint priceCollateralMantissa = getPrice(mTokenCollateral); if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { return (uint(Error.PRICE_ERROR), 0); } /* * Get the exchange rate and calculate the number of collateral tokens to seize: * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral * seizeTokens = seizeAmount / exchangeRate * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) */ ( , , address mTokenCollateralAddress) = parseToken(mTokenCollateral); uint exchangeRateMantissa = MTokenInterface(mTokenCollateralAddress).exchangeRateStored(mTokenCollateral); // Note: reverts on error uint seizeTokens; Exp memory numerator; Exp memory numerator2; Exp memory denominator; /* old calculation (Compound version) numerator = mul_(Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa})); denominator = mul_(Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa})); ratio = div_(numerator, denominator); seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount); */ /* new calculation avoids underflow due to truncation for cases where seizeTokens == 1 */ numerator = mul_(Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa})); numerator2 = mul_(numerator, actualRepayAmount); denominator = mul_(Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa})); seizeTokens = truncate(div_(numerator2, denominator)); return (uint(Error.NO_ERROR), seizeTokens); } // /** // * @notice Return all of the markets // * @dev The automatic getter may be used to access an individual market. // * @return The list of market addresses // */ // not implemented for now //function getAllMarkets() public view returns (MToken[] memory) { // return allMarkets; //} /** * @notice Returns the current block number * @dev Can be overriden for test purposes. * @return uint The current block number */ function getBlockNumber() public view returns (uint) { return block.number; } /** * @notice Returns the current price of the given mToken asset from the oracle * @param mToken The mToken whose price to get * @return uint The underlying asset price mantissa (scaled by 1e18). For fungible underlying tokens that * means e.g. if one single underlying token costs 1 Wei then the asset price mantissa should be 1e18. * In case of underlying (ERC-721 compliant) NFTs one NFT always corresponds to oneUnit = 1e18 * internal calculatory units (see MTokenInterfaces.sol), therefore if e.g. one NFT costs 0.1 ETH * then the asset price mantissa returned here should be 0.1e18. * Zero means the price is unavailable. */ function getPrice(uint240 mToken) public view returns (uint) { require(mToken != getAnchorToken(mToken), "no getPrice for anchor token"); require(isListed(mToken), "mToken not listed"); ( , , address mTokenAddress) = parseToken(mToken); address uAddress = MTokenCommon(mTokenAddress).underlyingContract(); if (uAddress == underlyingContractETH()) { // Return price = 1.0 for ETH return 1.0e18; } uint256 uTokenID = MTokenCommon(mTokenAddress).underlyingIDs(mToken); return oracle.getUnderlyingPrice(uAddress, uTokenID); } /******* NOT PROPERLY CHECKED YET BELOW THIS POINT *****************/ /*** Mmo Distribution ***/ /** * @notice Set MMO speed for a single market * @param mToken The market whose MMO speed to update * @param mmoSpeed New MMO speed for market */ function setMmoSpeedInternal(uint240 mToken, uint mmoSpeed) internal { uint currentMmoSpeed = mmoSpeeds[mToken]; if (currentMmoSpeed != 0) { // note that MMO speed could be set to 0 to halt liquidity rewards for a market ( , , address mTokenAddress) = parseToken(mToken); Exp memory borrowIndex = Exp({mantissa: MTokenCommon(mTokenAddress).borrowIndex(mToken)}); updateMmoSupplyIndex(mToken); updateMmoBorrowIndex(mToken, borrowIndex); } else if (mmoSpeed != 0) { // Add the MMO market require(isListed(mToken), "mmo market is not listed"); if (mmoSupplyState[mToken].index == 0 && mmoSupplyState[mToken].block == 0) { mmoSupplyState[mToken] = MmoMarketState({ index: mmoInitialIndex, block: safe32(getBlockNumber(), "block number exceeds 32 bits") }); } if (mmoBorrowState[mToken].index == 0 && mmoBorrowState[mToken].block == 0) { mmoBorrowState[mToken] = MmoMarketState({ index: mmoInitialIndex, block: safe32(getBlockNumber(), "block number exceeds 32 bits") }); } } if (currentMmoSpeed != mmoSpeed) { mmoSpeeds[mToken] = mmoSpeed; emit MmoSpeedUpdated(mToken, mmoSpeed); } } /** * @notice Accrue MMO to the market by updating the supply index * @param mToken The market whose supply index to update */ function updateMmoSupplyIndex(uint240 mToken) internal { MmoMarketState storage supplyState = mmoSupplyState[mToken]; uint supplySpeed = mmoSpeeds[mToken]; uint blockNumber = getBlockNumber(); uint deltaBlocks = sub_(blockNumber, uint(supplyState.block)); if (deltaBlocks > 0 && supplySpeed > 0) { ( , , address mTokenAddress) = parseToken(mToken); uint supplyTokens = MTokenCommon(mTokenAddress).totalSupply(mToken); uint mmoAccrued = mul_(deltaBlocks, supplySpeed); Double memory ratio = supplyTokens > 0 ? fraction(mmoAccrued, supplyTokens) : Double({mantissa: 0}); Double memory index = add_(Double({mantissa: supplyState.index}), ratio); mmoSupplyState[mToken] = MmoMarketState({ index: safe224(index.mantissa, "new index exceeds 224 bits"), block: safe32(blockNumber, "block number exceeds 32 bits") }); } else if (deltaBlocks > 0) { supplyState.block = safe32(blockNumber, "block number exceeds 32 bits"); } } /** * @notice Accrue MMO to the market by updating the borrow index * @param mToken The market whose borrow index to update */ function updateMmoBorrowIndex(uint240 mToken, Exp memory marketBorrowIndex) internal { MmoMarketState storage borrowState = mmoBorrowState[mToken]; uint borrowSpeed = mmoSpeeds[mToken]; uint blockNumber = getBlockNumber(); uint deltaBlocks = sub_(blockNumber, uint(borrowState.block)); if (deltaBlocks > 0 && borrowSpeed > 0) { ( , , address mTokenAddress) = parseToken(mToken); uint borrowAmount = div_(MTokenCommon(mTokenAddress).totalBorrows(mToken), marketBorrowIndex); uint mmoAccrued = mul_(deltaBlocks, borrowSpeed); Double memory ratio = borrowAmount > 0 ? fraction(mmoAccrued, borrowAmount) : Double({mantissa: 0}); Double memory index = add_(Double({mantissa: borrowState.index}), ratio); mmoBorrowState[mToken] = MmoMarketState({ index: safe224(index.mantissa, "new index exceeds 224 bits"), block: safe32(blockNumber, "block number exceeds 32 bits") }); } else if (deltaBlocks > 0) { borrowState.block = safe32(blockNumber, "block number exceeds 32 bits"); } } /** * @notice Calculate MMO accrued by a supplier and possibly transfer it to them * @param mToken The market in which the supplier is interacting * @param supplier The address of the supplier to distribute MMO to */ function distributeSupplierMmo(uint240 mToken, address supplier) internal { MmoMarketState storage supplyState = mmoSupplyState[mToken]; Double memory supplyIndex = Double({mantissa: supplyState.index}); Double memory supplierIndex = Double({mantissa: mmoSupplierIndex[mToken][supplier]}); mmoSupplierIndex[mToken][supplier] = supplyIndex.mantissa; if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) { supplierIndex.mantissa = mmoInitialIndex; } Double memory deltaIndex = sub_(supplyIndex, supplierIndex); ( , , address mTokenAddress) = parseToken(mToken); uint supplierTokens = MTokenInterface(mTokenAddress).balanceOf(supplier, mToken); uint supplierDelta = mul_(supplierTokens, deltaIndex); uint supplierAccrued = add_(mmoAccrued[supplier], supplierDelta); mmoAccrued[supplier] = supplierAccrued; emit DistributedSupplierMmo(mToken, supplier, supplierDelta, supplyIndex.mantissa); } /** * @notice Calculate MMO accrued by a borrower and possibly transfer it to them * @dev Borrowers will not begin to accrue until after the first interaction with the protocol. * @param mToken The market in which the borrower is interacting * @param borrower The address of the borrower to distribute MMO to */ function distributeBorrowerMmo(uint240 mToken, address borrower, Exp memory marketBorrowIndex) internal { MmoMarketState storage borrowState = mmoBorrowState[mToken]; Double memory borrowIndex = Double({mantissa: borrowState.index}); Double memory borrowerIndex = Double({mantissa: mmoBorrowerIndex[mToken][borrower]}); mmoBorrowerIndex[mToken][borrower] = borrowIndex.mantissa; if (borrowerIndex.mantissa > 0) { Double memory deltaIndex = sub_(borrowIndex, borrowerIndex); ( , , address mTokenAddress) = parseToken(mToken); uint borrowerAmount = div_(MTokenInterface(mTokenAddress).borrowBalanceStored(borrower, mToken), marketBorrowIndex); uint borrowerDelta = mul_(borrowerAmount, deltaIndex); uint borrowerAccrued = add_(mmoAccrued[borrower], borrowerDelta); mmoAccrued[borrower] = borrowerAccrued; emit DistributedBorrowerMmo(mToken, borrower, borrowerDelta, borrowIndex.mantissa); } } /** * @notice Calculate additional accrued MMO for a contributor since last accrual * @param contributor The address to calculate contributor rewards for */ function updateContributorRewards(address contributor) public { uint mmoSpeed = mmoContributorSpeeds[contributor]; uint blockNumber = getBlockNumber(); uint deltaBlocks = sub_(blockNumber, lastContributorBlock[contributor]); if (deltaBlocks > 0 && mmoSpeed > 0) { uint newAccrued = mul_(deltaBlocks, mmoSpeed); uint contributorAccrued = add_(mmoAccrued[contributor], newAccrued); mmoAccrued[contributor] = contributorAccrued; lastContributorBlock[contributor] = blockNumber; } } // /** // * @notice Claim all the mmo accrued by holder in all markets // * @param holder The address to claim MMO for // */ // This is not yet implemented // function claimMmo(address holder) public { // return claimMmo(holder, allMarkets); // } /** * @notice Claim all the mmo accrued by holder in the specified markets * @param holder The address to claim MMO for * @param mTokens The list of markets to claim MMO in */ function claimMmo(address holder, uint240[] memory mTokens) public { address[] memory holders = new address[](1); holders[0] = holder; claimMmo(holders, mTokens, true, true); } /** * @notice Claim all mmo accrued by the holders * @param holders The addresses to claim MMO for * @param mTokens The list of markets to claim MMO in * @param borrowers Whether or not to claim MMO earned by borrowing * @param suppliers Whether or not to claim MMO earned by supplying */ function claimMmo(address[] memory holders, uint240[] memory mTokens, bool borrowers, bool suppliers) public { for (uint i = 0; i < mTokens.length; i++) { uint240 mToken = mTokens[i]; require(isListed(mToken), "market must be listed"); if (borrowers == true) { ( , , address mTokenAddress) = parseToken(mToken); Exp memory borrowIndex = Exp({mantissa: MTokenCommon(mTokenAddress).borrowIndex(mToken)}); updateMmoBorrowIndex(mToken, borrowIndex); for (uint j = 0; j < holders.length; j++) { distributeBorrowerMmo(mToken, holders[j], borrowIndex); mmoAccrued[holders[j]] = grantMmoInternal(holders[j], mmoAccrued[holders[j]]); } } if (suppliers == true) { updateMmoSupplyIndex(mToken); for (uint j = 0; j < holders.length; j++) { distributeSupplierMmo(mToken, holders[j]); mmoAccrued[holders[j]] = grantMmoInternal(holders[j], mmoAccrued[holders[j]]); } } } } /** * @notice Transfer MMO to the user * @dev Note: If there is not enough MMO, we do not perform the transfer all. * @param user The address of the user to transfer MMO to * @param amount The amount of MMO to (possibly) transfer * @return The amount of MMO which was NOT transferred to the user */ function grantMmoInternal(address user, uint amount) internal returns (uint) { Mmo mmo = Mmo(getMmoAddress()); uint mmoRemaining = mmo.balanceOf(address(this)); if (amount > 0 && amount <= mmoRemaining) { mmo.transfer(user, amount); return 0; } return amount; } /*** Mmo Distribution Admin ***/ /** * @notice Transfer MMO to the recipient * @dev Note: If there is not enough MMO, we do not perform the transfer all. * @param recipient The address of the recipient to transfer MMO to * @param amount The amount of MMO to (possibly) transfer */ function _grantMmo(address recipient, uint amount) public { require(msg.sender == getAdmin(), "only admin can grant mmo"); uint amountLeft = grantMmoInternal(recipient, amount); require(amountLeft == 0, "insufficient mmo for grant"); emit MmoGranted(recipient, amount); } /** * @notice Set MMO speed for a single market * @param mToken The market whose MMO speed to update * @param mmoSpeed New MMO speed for market */ function _setMmoSpeed(uint240 mToken, uint mmoSpeed) public { require(msg.sender == getAdmin(), "only admin can set mmo speed"); setMmoSpeedInternal(mToken, mmoSpeed); } /** * @notice Set MMO speed for a single contributor * @param contributor The contributor whose MMO speed to update * @param mmoSpeed New MMO speed for contributor */ function _setContributorMmoSpeed(address contributor, uint mmoSpeed) public { require(msg.sender == getAdmin(), "only admin can set mmo speed"); // note that MMO speed could be set to 0 to halt liquidity rewards for a contributor updateContributorRewards(contributor); if (mmoSpeed == 0) { // release storage delete lastContributorBlock[contributor]; } else { lastContributorBlock[contributor] = getBlockNumber(); } mmoContributorSpeeds[contributor] = mmoSpeed; emit ContributorMmoSpeedUpdated(contributor, mmoSpeed); } /** * @notice Return the address of the MMO token * @return The address of MMO */ function getMmoAddress() public view returns (address) { return mmoTokenAddress; } }
pragma solidity ^0.5.16; contract MtrollerErrorReporter { enum Error { NO_ERROR, UNAUTHORIZED, MTROLLER_MISMATCH, INSUFFICIENT_SHORTFALL, INSUFFICIENT_LIQUIDITY, INVALID_CLOSE_FACTOR, INVALID_COLLATERAL_FACTOR, INVALID_LIQUIDATION_INCENTIVE, MARKET_NOT_ENTERED, MARKET_NOT_LISTED, MARKET_ALREADY_LISTED, MATH_ERROR, NONZERO_BORROW_BALANCE, PRICE_ERROR, REJECTION, SNAPSHOT_ERROR, TOO_MANY_ASSETS, TOO_MUCH_REPAY, INVALID_TOKEN_TYPE } enum FailureInfo { ACCEPT_ADMIN_PENDING_ADMIN_CHECK, ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, EXIT_MARKET_BALANCE_OWED, EXIT_MARKET_REJECTION, SET_CLOSE_FACTOR_OWNER_CHECK, SET_CLOSE_FACTOR_VALIDATION, SET_COLLATERAL_FACTOR_OWNER_CHECK, SET_COLLATERAL_FACTOR_NO_EXISTS, SET_COLLATERAL_FACTOR_VALIDATION, SET_COLLATERAL_FACTOR_WITHOUT_PRICE, SET_IMPLEMENTATION_OWNER_CHECK, SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, SET_LIQUIDATION_INCENTIVE_VALIDATION, SET_MAX_ASSETS_OWNER_CHECK, SET_PENDING_ADMIN_OWNER_CHECK, SET_PENDING_IMPLEMENTATION_OWNER_CHECK, SET_PRICE_ORACLE_OWNER_CHECK, SUPPORT_MARKET_EXISTS, SUPPORT_MARKET_OWNER_CHECK, SET_PAUSE_GUARDIAN_OWNER_CHECK } /** * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary * contract-specific code that enables us to report opaque error codes from upgradeable contracts. **/ event Failure(uint error, uint info, uint detail); /** * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator */ function fail(Error err, FailureInfo info) internal returns (uint) { emit Failure(uint(err), uint(info), 0); return uint(err); } /** * @dev use this when reporting an opaque error from an upgradeable collaborator contract */ function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) { emit Failure(uint(err), uint(info), opaqueError); return uint(err); } } contract TokenErrorReporter { enum Error { NO_ERROR, UNAUTHORIZED, BAD_INPUT, MTROLLER_REJECTION, MTROLLER_CALCULATION_ERROR, INTEREST_RATE_MODEL_ERROR, INVALID_ACCOUNT_PAIR, INVALID_CLOSE_AMOUNT_REQUESTED, INVALID_COLLATERAL_FACTOR, INVALID_COLLATERAL, MATH_ERROR, MARKET_NOT_FRESH, MARKET_NOT_LISTED, TOKEN_INSUFFICIENT_ALLOWANCE, TOKEN_INSUFFICIENT_BALANCE, TOKEN_INSUFFICIENT_CASH, TOKEN_TRANSFER_IN_FAILED, TOKEN_TRANSFER_OUT_FAILED } /* * Note: FailureInfo (but not Error) is kept in alphabetical order * This is because FailureInfo grows significantly faster, and * the order of Error has some meaning, while the order of FailureInfo * is entirely arbitrary. */ enum FailureInfo { ACCEPT_ADMIN_PENDING_ADMIN_CHECK, ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, AUCTION_NOT_ALLOWED, BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, BORROW_ACCRUE_INTEREST_FAILED, BORROW_CASH_NOT_AVAILABLE, BORROW_FRESHNESS_CHECK, BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, BORROW_NEW_PLATFORM_FEE_CALCULATION_FAILED, BORROW_MARKET_NOT_LISTED, BORROW_MTROLLER_REJECTION, FLASH_LOAN_BORROW_FAILED, FLASH_OPERATION_NOT_DEFINED, LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, LIQUIDATE_COLLATERAL_NOT_FUNGIBLE, LIQUIDATE_COLLATERAL_NOT_EXISTING, LIQUIDATE_MTROLLER_REJECTION, LIQUIDATE_MTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, LIQUIDATE_FRESHNESS_CHECK, LIQUIDATE_GRACE_PERIOD_NOT_EXPIRED, LIQUIDATE_LIQUIDATOR_IS_BORROWER, LIQUIDATE_NOT_PREFERRED_LIQUIDATOR, LIQUIDATE_REPAY_BORROW_FRESH_FAILED, LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, LIQUIDATE_SEIZE_MTROLLER_REJECTION, LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, LIQUIDATE_SEIZE_TOO_MUCH, LIQUIDATE_SEIZE_NON_FUNGIBLE_ASSET, MINT_ACCRUE_INTEREST_FAILED, MINT_MTROLLER_REJECTION, MINT_EXCHANGE_CALCULATION_FAILED, MINT_EXCHANGE_RATE_READ_FAILED, MINT_FRESHNESS_CHECK, MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, MINT_NEW_TOTAL_CASH_CALCULATION_FAILED, MINT_TRANSFER_IN_FAILED, MINT_TRANSFER_IN_NOT_POSSIBLE, REDEEM_ACCRUE_INTEREST_FAILED, REDEEM_MTROLLER_REJECTION, REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, REDEEM_EXCHANGE_RATE_READ_FAILED, REDEEM_FRESHNESS_CHECK, REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, REDEEM_TRANSFER_OUT_NOT_POSSIBLE, REDEEM_MARKET_EXIT_NOT_POSSIBLE, REDEEM_NOT_OWNER, REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, REDUCE_RESERVES_ADMIN_CHECK, REDUCE_RESERVES_CASH_NOT_AVAILABLE, REDUCE_RESERVES_FRESH_CHECK, REDUCE_RESERVES_VALIDATION, REPAY_BEHALF_ACCRUE_INTEREST_FAILED, REPAY_BORROW_ACCRUE_INTEREST_FAILED, REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, REPAY_BORROW_MTROLLER_REJECTION, REPAY_BORROW_FRESHNESS_CHECK, REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, REPAY_BORROW_NEW_TOTAL_CASH_CALCULATION_FAILED, REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, SET_COLLATERAL_FACTOR_OWNER_CHECK, SET_COLLATERAL_FACTOR_VALIDATION, SET_GLOBAL_PARAMETERS_VALUE_CHECK, SET_MTROLLER_OWNER_CHECK, SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, SET_INTEREST_RATE_MODEL_FRESH_CHECK, SET_INTEREST_RATE_MODEL_OWNER_CHECK, SET_FLASH_WHITELIST_OWNER_CHECK, SET_MAX_ASSETS_OWNER_CHECK, SET_ORACLE_MARKET_NOT_LISTED, SET_PENDING_ADMIN_OWNER_CHECK, SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, SET_RESERVE_FACTOR_ADMIN_CHECK, SET_RESERVE_FACTOR_FRESH_CHECK, SET_RESERVE_FACTOR_BOUNDS_CHECK, SET_TOKEN_AUCTION_OWNER_CHECK, TRANSFER_MTROLLER_REJECTION, TRANSFER_NOT_ALLOWED, TRANSFER_NOT_ENOUGH, TRANSFER_TOO_MUCH, ADD_RESERVES_ACCRUE_INTEREST_FAILED, ADD_RESERVES_FRESH_CHECK, ADD_RESERVES_TOTAL_CASH_CALCULATION_FAILED, ADD_RESERVES_TOTAL_RESERVES_CALCULATION_FAILED, ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE } /** * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary * contract-specific code that enables us to report opaque error codes from upgradeable contracts. **/ event Failure(uint error, uint info, uint detail); /** * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator */ function fail(Error err, FailureInfo info) internal returns (uint) { emit Failure(uint(err), uint(info), 0); return uint(err); } /** * @dev use this when reporting an opaque error from an upgradeable collaborator contract */ function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) { emit Failure(uint(err), uint(info), opaqueError); return uint(err); } }
pragma solidity ^0.5.16; import "./MTokenStorage.sol"; import "./MTokenInterfaces.sol"; import "./MtrollerInterface.sol"; import "./ErrorReporter.sol"; import "./compound/Exponential.sol"; import "./compound/EIP20Interface.sol"; import "./compound/InterestRateModel.sol"; import "./open-zeppelin/token/ERC20/IERC20.sol"; import "./open-zeppelin/token/ERC721/IERC721.sol"; /** * @title Contract for MToken * @notice Abstract base for any type of MToken * @author mmo.finance, initially based on Compound */ contract MTokenCommon is MTokenV1Storage, MTokenCommonInterface, Exponential, TokenErrorReporter { /** * @notice Constructs a new MToken */ constructor() public { } /** * @notice Tells the address of the current admin (set in MDelegator.sol) * @return admin The address of the current admin */ function getAdmin() public view returns (address payable admin) { bytes32 position = mDelegatorAdminPosition; assembly { admin := sload(position) } } struct AccrueInterestLocalVars { uint currentBlockNumber; uint accrualBlockNumberPrior; uint cashPrior; uint borrowsPrior; uint reservesPrior; uint borrowIndexPrior; } /** * @notice Applies accrued interest to total borrows and reserves * @param mToken The mToken market to accrue interest for * @dev This calculates interest accrued from the last checkpointed block * up to the current block and writes new checkpoint to storage. */ function accrueInterest(uint240 mToken) public returns (uint) { AccrueInterestLocalVars memory vars; /* Remember the initial block number */ vars.currentBlockNumber = getBlockNumber(); vars.accrualBlockNumberPrior = accrualBlockNumber[mToken]; /* Short-circuit accumulating 0 interest */ if (vars.accrualBlockNumberPrior == vars.currentBlockNumber) { return uint(Error.NO_ERROR); } /* Read the previous values out of storage */ vars.cashPrior = totalCashUnderlying[mToken]; vars.borrowsPrior = totalBorrows[mToken]; vars.reservesPrior = totalReserves[mToken]; vars.borrowIndexPrior = borrowIndex[mToken]; /* Calculate the current borrow interest rate */ uint borrowRateMantissa = interestRateModel.getBorrowRate(vars.cashPrior, vars.borrowsPrior, vars.reservesPrior); require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high"); /* Calculate the number of blocks elapsed since the last accrual */ (MathError mathErr, uint blockDelta) = subUInt(vars.currentBlockNumber, vars.accrualBlockNumberPrior); require(mathErr == MathError.NO_ERROR, "could not calculate block delta"); /* * Calculate the interest accumulated into borrows and reserves and the new index: * simpleInterestFactor = borrowRate * blockDelta * interestAccumulated = simpleInterestFactor * totalBorrows * totalBorrowsNew = interestAccumulated + totalBorrows * totalReservesNew = interestAccumulated * reserveFactor + totalReserves * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex */ Exp memory simpleInterestFactor; uint interestAccumulated; uint totalBorrowsNew; uint totalReservesNew; uint borrowIndexNew; (mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), blockDelta); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr)); } (mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, vars.borrowsPrior); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr)); } (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, vars.borrowsPrior); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr)); } (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, vars.reservesPrior); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr)); } (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, vars.borrowIndexPrior, vars.borrowIndexPrior); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr)); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We write the previously calculated values into storage */ accrualBlockNumber[mToken] = vars.currentBlockNumber; borrowIndex[mToken] = borrowIndexNew; totalBorrows[mToken] = totalBorrowsNew; totalReserves[mToken] = totalReservesNew; /* We emit an AccrueInterest event */ emit AccrueInterest(mToken, vars.cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew); return uint(Error.NO_ERROR); } /** * @notice Calculates the exchange rate from the underlying to the MToken * @dev This function does not accrue interest before calculating the exchange rate * @param mToken The mToken whose exchange rate should be calculated * @return (error code, calculated exchange rate scaled by 1e18) */ function exchangeRateStoredInternal(uint240 mToken) internal view returns (MathError, uint) { uint _totalSupply = totalSupply[mToken]; if (_totalSupply == 0) { /* * If there are no tokens minted: * exchangeRate = initialExchangeRate */ return (MathError.NO_ERROR, initialExchangeRateMantissa); } else { /* * Otherwise: * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint totalCash = totalCashUnderlying[mToken]; uint cashPlusBorrowsMinusReserves; Exp memory exchangeRate; MathError mathErr; (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows[mToken], totalReserves[mToken]); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } return (MathError.NO_ERROR, exchangeRate.mantissa); } } /** * @notice Return the borrow balance of account based on stored data * @param account The address whose balance should be calculated * @param mToken The borrowed mToken * @return (error code, the calculated balance or 0 if error code is non-zero) */ function borrowBalanceStoredInternal(address account, uint240 mToken) internal view returns (MathError, uint) { /* Note: we do not assert that the market is up to date */ MathError mathErr; uint principalTimesIndex; uint result; /* Get borrowBalance and borrowIndex */ BorrowSnapshot storage borrowSnapshot = accountBorrows[mToken][account]; /* If borrowBalance = 0 then borrowIndex is likely also 0. * Rather than failing the calculation with a division by 0, we immediately return 0 in this case. */ if (borrowSnapshot.principal == 0) { return (MathError.NO_ERROR, 0); } /* Calculate new borrow balance using the interest index: * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex */ (mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex[mToken]); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } (mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } return (MathError.NO_ERROR, result); } /** * @dev Function to simply retrieve block number * This exists mainly for inheriting test contracts to stub this result. */ function getBlockNumber() internal view returns (uint) { return block.number; } /*** Error handling ***/ function requireNoError(uint errCode, string memory message) internal pure { if (errCode == uint(Error.NO_ERROR)) { return; } bytes memory fullMessage = new bytes(bytes(message).length + 5); uint i; for (i = 0; i < bytes(message).length; i++) { fullMessage[i] = bytes(message)[i]; } fullMessage[i+0] = byte(uint8(32)); fullMessage[i+1] = byte(uint8(40)); fullMessage[i+2] = byte(uint8(48 + ( errCode / 10 ))); fullMessage[i+3] = byte(uint8(48 + ( errCode % 10 ))); fullMessage[i+4] = byte(uint8(41)); require(errCode == uint(Error.NO_ERROR), string(fullMessage)); } /*** Reentrancy Guard ***/ /** * @dev Prevents a contract from calling itself, directly or indirectly. */ modifier nonReentrant() { require(_notEntered, "re-entered"); _notEntered = false; _; _notEntered = true; // get a gas-refund post-Istanbul } /** * @dev Prevents a contract from calling itself, directly or indirectly */ modifier nonReentrant2() { require(_notEntered2, "re-entered"); _notEntered2 = false; _; _notEntered2 = true; // get a gas-refund post-Istanbul } }
pragma solidity ^0.5.16; import "./PriceOracle.sol"; import "./MtrollerInterface.sol"; import "./TokenAuction.sol"; import "./compound/InterestRateModel.sol"; import "./compound/EIP20NonStandardInterface.sol"; import "./open-zeppelin/token/ERC721/IERC721Metadata.sol"; contract MTokenCommonInterface is MTokenIdentifier, MDelegatorIdentifier { /*** Market Events ***/ /** * @notice Event emitted when interest is accrued */ event AccrueInterest(uint240 mToken, uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows); /** * @notice Events emitted when tokens are minted */ event Mint(address minter, address beneficiary, uint mintAmountUnderlying, uint240 mTokenMinted, uint amountTokensMinted); /** * @notice Events emitted when tokens are transferred */ event Transfer(address from, address to, uint240 mToken, uint amountTokens); /** * @notice Event emitted when tokens are redeemed */ event Redeem(address redeemer, uint240 mToken, uint redeemTokens, uint256 underlyingID, uint underlyingRedeemAmount); /** * @notice Event emitted when underlying is borrowed */ event Borrow(address borrower, uint256 underlyingID, uint borrowAmount, uint paidOutAmount, uint accountBorrows, uint totalBorrows); /** * @notice Event emitted when underlying is borrowed in a flash loan operation */ event FlashBorrow(address borrower, uint256 underlyingID, address receiver, uint downPayment, uint borrowAmount, uint paidOutAmount); /** * @notice Event emitted when a borrow is repaid */ event RepayBorrow(address payer, address borrower, uint256 underlyingID, uint repayAmount, uint accountBorrows, uint totalBorrows); /** * @notice Event emitted when a borrow is liquidated */ event LiquidateBorrow(address liquidator, address borrower, uint240 mTokenBorrowed, uint repayAmountUnderlying, uint240 mTokenCollateral, uint seizeTokens); /** * @notice Event emitted when a grace period is started before liquidating a token with an auction */ event GracePeriod(uint240 mTokenCollateral, uint lastBlockOfGracePeriod); /*** Admin Events ***/ /** * @notice Event emitted when flash receiver whitlist is changed */ event FlashReceiverWhitelistChanged(address receiver, bool newState); /** * @notice Event emitted when interestRateModel is changed */ event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel); /** * @notice Event emitted when tokenAuction is changed */ event NewTokenAuction(TokenAuction oldTokenAuction, TokenAuction newTokenAuction); /** * @notice Event emitted when mtroller is changed */ event NewMtroller(MtrollerInterface oldMtroller, MtrollerInterface newMtroller); /** * @notice Event emitted when global protocol parameters are updated */ event NewGlobalProtocolParameters(uint newInitialExchangeRateMantissa, uint newReserveFactorMantissa, uint newProtocolSeizeShareMantissa, uint newBorrowFeeMantissa); /** * @notice Event emitted when global auction parameters are updated */ event NewGlobalAuctionParameters(uint newAuctionGracePeriod, uint newPreferredLiquidatorHeadstart, uint newMinimumOfferMantissa, uint newLiquidatorAuctionFeeMantissa, uint newProtocolAuctionFeeMantissa); /** * @notice Event emitted when the reserves are added */ event ReservesAdded(address benefactor, uint240 mToken, uint addAmount, uint newTotalReserves); /** * @notice Event emitted when the reserves are reduced */ event ReservesReduced(address admin, uint240 mToken, uint reduceAmount, uint newTotalReserves); /** * @notice Failure event */ event Failure(uint error, uint info, uint detail); function getAdmin() public view returns (address payable admin); function accrueInterest(uint240 mToken) public returns (uint); } contract MTokenAdminInterface is MTokenCommonInterface { /// @notice Indicator that this is a admin part contract (for inspection) function isMDelegatorAdminImplementation() public pure returns (bool); /*** Admin Functions ***/ function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint); function _setTokenAuction(TokenAuction newTokenAuction) public returns (uint); function _setMtroller(MtrollerInterface newMtroller) public returns (uint); function _setGlobalProtocolParameters(uint _initialExchangeRateMantissa, uint _reserveFactorMantissa, uint _protocolSeizeShareMantissa, uint _borrowFeeMantissa) public returns (uint); function _setGlobalAuctionParameters(uint _auctionGracePeriod, uint _preferredLiquidatorHeadstart, uint _minimumOfferMantissa, uint _liquidatorAuctionFeeMantissa, uint _protocolAuctionFeeMantissa) public returns (uint); function _reduceReserves(uint240 mToken, uint reduceAmount) external returns (uint); function _sweepERC20(address tokenContract) external returns (uint); function _sweepERC721(address tokenContract, uint256 tokenID) external; } contract MTokenUserInterface is MTokenCommonInterface { /// @notice Indicator that this is a user part contract (for inspection) function isMDelegatorUserImplementation() public pure returns (bool); /*** User Interface ***/ function balanceOf(address owner, uint240 mToken) external view returns (uint); function getAccountSnapshot(address account, uint240 mToken) external view returns (uint, uint, uint, uint); function borrowRatePerBlock(uint240 mToken) external view returns (uint); function supplyRatePerBlock(uint240 mToken) external view returns (uint); function totalBorrowsCurrent(uint240 mToken) external returns (uint); function borrowBalanceCurrent(address account, uint240 mToken) external returns (uint); function borrowBalanceStored(address account, uint240 mToken) public view returns (uint); function exchangeRateCurrent(uint240 mToken) external returns (uint); function exchangeRateStored(uint240 mToken) external view returns (uint); function getCash(uint240 mToken) external view returns (uint); function seize(uint240 mTokenBorrowed, address liquidator, address borrower, uint240 mTokenCollateral, uint seizeTokens) external returns (uint); } contract MTokenInterface is MTokenAdminInterface, MTokenUserInterface {} contract MFungibleTokenAdminInterface is MTokenAdminInterface { } contract MFungibleTokenUserInterface is MTokenUserInterface{ /*** Market Events ***/ event Transfer(address indexed from, address indexed to, uint amount); event Approval(address indexed owner, address indexed spender, uint amount); /*** User Interface ***/ function transfer(address dst, uint amount) external returns (bool); function transferFrom(address src, address dst, uint amount) external returns (bool); function approve(address spender, uint amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint); function balanceOf(address owner) external view returns (uint); function balanceOfUnderlying(address owner) external returns (uint); } contract MFungibleTokenInterface is MFungibleTokenAdminInterface, MFungibleTokenUserInterface {} contract MEtherAdminInterface is MFungibleTokenAdminInterface { /*** Admin Functions ***/ function initialize(MtrollerInterface mtroller_, InterestRateModel interestRateModel_, uint reserveFactorMantissa_, uint initialExchangeRateMantissa_, uint protocolSeizeShareMantissa_, string memory name_, string memory symbol_, uint8 decimals_) public; /*** User Interface ***/ function redeem(uint redeemTokens) external returns (uint); function redeemUnderlying(uint redeemAmount) external returns (uint); function borrow(uint borrowAmount) external returns (uint); function flashBorrow(uint borrowAmount, address payable receiver, bytes calldata flashParams) external payable returns (uint); function name() public view returns (string memory); function symbol() public view returns (string memory); function decimals() public view returns (uint8); } contract MEtherUserInterface is MFungibleTokenUserInterface { /*** Admin Functions ***/ function getProtocolAuctionFeeMantissa() external view returns (uint); function _addReserves() external payable returns (uint); /*** User Interface ***/ function mint() external payable returns (uint); function mintTo(address beneficiary) external payable returns (uint); function repayBorrow() external payable returns (uint); function repayBorrowBehalf(address borrower) external payable returns (uint); function liquidateBorrow(address borrower, uint240 mTokenCollateral) external payable returns (uint); } contract MEtherInterface is MEtherAdminInterface, MEtherUserInterface {} contract MERC721AdminInterface is MTokenAdminInterface, IERC721, IERC721Metadata { event NewTokenAuctionContract(TokenAuction oldTokenAuction, TokenAuction newTokenAuction); /*** Admin Functions ***/ function initialize(address underlyingContract_, MtrollerInterface mtroller_, InterestRateModel interestRateModel_, TokenAuction tokenAuction_, string memory name_, string memory symbol_) public; /*** User Interface ***/ function redeem(uint240 mToken) public returns (uint); function redeemUnderlying(uint256 underlyingID) external returns (uint); function redeemAndSell(uint240 mToken, uint sellPrice, address payable transferHandler, bytes memory transferParams) public returns (uint); function borrow(uint256 borrowUnderlyingID) external returns (uint); function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 tokenId) external view returns (string memory); } contract MERC721UserInterface is MTokenUserInterface, IERC721 { event LiquidateToPaymentToken(address indexed oldOwner, address indexed newOwner, uint240 mToken, uint256 auctioneerTokens, uint256 oldOwnerTokens); /*** Admin Functions ***/ // function _addReserves(uint240 mToken, uint addAmount) external payable returns (uint); /*** User Interface ***/ function mint(uint256 underlyingTokenID) external returns (uint240); function mintAndCollateralizeTo(address beneficiary, uint256 underlyingTokenID) external returns (uint240); function mintTo(address beneficiary, uint256 underlyingTokenID) public returns (uint240); // function repayBorrow(uint256 repayUnderlyingID) external payable returns (uint); // function repayBorrowBehalf(address borrower, uint256 repayUnderlyingID) external payable returns (uint); // function liquidateBorrow(address borrower, uint256 repayUnderlyingID, uint240 mTokenCollateral) external payable returns (uint); function addAuctionBid(uint240 mToken) external payable; function instantSellToHighestBidder(uint240 mToken, uint256 minimumPrice) public; function setAskingPrice(uint240 mToken, uint256 newAskingPrice) external; function startGracePeriod(uint240 mToken) external returns (uint); function liquidateToPaymentToken(uint240 mToken) external returns (uint, uint240, uint, uint); } contract MERC721Interface is MERC721AdminInterface, MERC721UserInterface {} contract FlashLoanReceiverInterface { function executeFlashOperation(address payable borrower, uint240 mToken, uint borrowAmount, uint paidOutAmount, bytes calldata flashParams) external returns (uint); function executeTransfer(uint256 tokenId, address payable seller, uint sellPrice, bytes calldata transferParams) external returns (uint); }
pragma solidity ^0.5.16; import "./MtrollerInterface.sol"; import "./TokenAuction.sol"; import "./compound/InterestRateModel.sol"; contract MDelegateeStorage { /** * @notice List of all public function selectors implemented by "admin type" contract * @dev Needs to be initialized in the constructor(s) */ bytes4[] public implementedSelectors; function implementedSelectorsLength() public view returns (uint) { return implementedSelectors.length; } } contract MTokenV1Storage is MDelegateeStorage { /** * @dev Guard variable for re-entrancy checks */ bool internal _notEntered; bool internal _notEntered2; /*** Global variables: addresses of other contracts to call. * These are set at contract initialization and can only be modified by a (timelock) admin ***/ /** * @notice Address of the underlying asset contract (this never changes again after initialization) */ address public underlyingContract; /** * @notice Contract address of model which tells what the current interest rate(s) should be */ InterestRateModel public interestRateModel; /** * @notice Contract used for (non-fungible) mToken auction (used only if applicable) */ TokenAuction public tokenAuction; /** * @notice Contract which oversees inter-mToken operations */ MtrollerInterface public mtroller; /*** Global variables: token identification constants. * These variables are set at contract initialization and never modified again ***/ /** * @notice EIP-20 token name for this token */ string public mName; /** * @notice EIP-20 token symbol for this token */ string public mSymbol; /** * @notice EIP-20 token decimals for this token */ uint8 public mDecimals; /*** Global variables: protocol control parameters. * These variables are set at contract initialization and can only be modified by a (timelock) admin ***/ /** * @notice Initial exchange rate used when minting the first mTokens (used when totalSupply = 0) */ uint internal initialExchangeRateMantissa; /** * @notice Fraction of interest currently set aside for reserves */ uint internal constant reserveFactorMaxMantissa = 50e16; // upper protocol limit (50%) uint public reserveFactorMantissa; /** * @notice Fraction of seized (fungible) collateral that is added to reserves */ uint internal constant protocolSeizeShareMaxMantissa = 5e16; // upper protocol limit (5%) uint public protocolSeizeShareMantissa; /** * @notice Fraction of new borrow amount set aside for reserves (one-time fee) */ uint internal constant borrowFeeMaxMantissa = 50e16; // upper protocol limit (50%) uint public borrowFeeMantissa; /** * @notice Mapping of addresses that are whitelisted as receiver for flash loans */ mapping (address => bool) public flashReceiverIsWhitelisted; /*** Global variables: auction liquidation control parameters. * The variables are set at contract initialization and can only be changed by a (timelock) admin ***/ /** * @notice Minimum and maximum values that can ever be used for the grace period, which is * the minimum time liquidators have to wait before they can seize a non-fungible mToken collateral */ uint256 public constant auctionMinGracePeriod = 2000; // lower limit (2000 blocks, i.e. about 8 hours) uint256 public constant auctionMaxGracePeriod = 50000; // upper limit (50000 blocks, i.e. about 8.5 days) uint256 public auctionGracePeriod; /** * @notice "Headstart" time in blocks the preferredLiquidator has available to liquidate a mToken * exclusively before everybody else is also allowed to do it. */ uint256 public constant preferredLiquidatorMaxHeadstart = 2000; // upper limit (2000 blocks, i.e. about 8 hours) uint256 public preferredLiquidatorHeadstart; /** * @notice Minimum offer required to win liquidation auction, relative to the NFTs regular price. */ uint public constant minimumOfferMaxMantissa = 80e16; // upper limit (80% of market price) uint public minimumOfferMantissa; /** * @notice Fee for the liquidator executing liquidateToPaymentToken(). */ uint public constant liquidatorAuctionFeeMaxMantissa = 10e16; // upper limit (10%) uint public liquidatorAuctionFeeMantissa; /** * @notice Fee for the protocol when executing liquidateToPaymentToken() or acceptHighestOffer(). * The funds are directly added to mEther reserves. */ uint public constant protocolAuctionFeeMaxMantissa = 20e16; // upper limit (50%) uint public protocolAuctionFeeMantissa; /*** Token variables: basic token identification. * These variables are only initialized the first time the given token is minted ***/ /** * @notice Mapping of mToken to underlying tokenID */ mapping (uint240 => uint256) public underlyingIDs; /** * @notice Mapping of underlying tokenID to mToken */ mapping (uint256 => uint240) public mTokenFromUnderlying; /** * @notice Total number of (ever) minted mTokens. Note: Burning a mToken (when redeeming the * underlying asset) DOES NOT reduce this count. The maximum possible amount of tokens that * can ever be minted by this contract is limited to 2^88-1, which is finite but high enough * to never be reached in realistic time spans. */ uint256 public totalCreatedMarkets; /** * @notice Maps mToken to block number that interest was last accrued at */ mapping (uint240 => uint) public accrualBlockNumber; /** * @notice Maps mToken to accumulator of the total earned interest rate since the opening of that market */ mapping (uint240 => uint) public borrowIndex; /*** Token variables: general token accounting. * These variables are initialized the first time the given token is minted and then adapted when needed ***/ /** * @notice Official record of token balances for each mToken, for each account */ mapping (uint240 => mapping (address => uint)) internal accountTokens; /** * @notice Container for borrow balance information * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action * @member interestIndex Global borrowIndex as of the most recent balance-changing action */ struct BorrowSnapshot { uint principal; uint interestIndex; } /** * @notice Mapping of account addresses to outstanding borrow balances, for any given mToken */ mapping(uint240 => mapping(address => BorrowSnapshot)) internal accountBorrows; /** * @notice Maximum borrow rate that can ever be applied (.0005% / block) */ uint internal constant borrowRateMaxMantissa = 0.0005e16; /** * @notice Maps mToken to total amount of cash of the underlying in that market */ mapping (uint240 => uint) public totalCashUnderlying; /** * @notice Maps mToken to total amount of outstanding borrows of the underlying in that market */ mapping (uint240 => uint) public totalBorrows; /** * @notice Maps mToken to total amount of reserves of the underlying held in that market */ mapping (uint240 => uint) public totalReserves; /** * @notice Maps mToken to total number of tokens in circulation in that market */ mapping (uint240 => uint) public totalSupply; /*** Token variables: Special variables used for fungible tokens (e.g. ERC-20). * These variables are initialized the first time the given token is minted and then adapted when needed ***/ /** * @notice Dummy ID for "underlying asset" in case of a (single) fungible token */ uint256 internal constant dummyTokenID = 1; /** * @notice The mToken for a (single) fungible token */ uint240 public thisFungibleMToken; /** * @notice Approved token transfer amounts on behalf of others (for fungible tokens) */ mapping (address => mapping (address => uint)) internal transferAllowances; /*** Token variables: Special variables used for non-fungible tokens (e.g. ERC-721). * These variables are initialized the first time the given token is minted and then adapted when needed ***/ /** * @notice Virtual amount of "cash" that corresponds to one underlying NFT. This is used as * calculatory units internally for mTokens with strictly non-fungible underlying (such as ERC-721) * to avoid loss of mathematical precision for calculations such as borrowing amounts. However, both * underlying NFT and associated mToken are still non-fungible (ERC-721 compliant) tokens and can * only be transferred as one item. */ uint internal constant oneUnit = 1e18; /** * @notice Mapping of mToken to the block number of the last block in their grace period (zero * if mToken is not in a grace period) */ mapping (uint240 => uint256) public lastBlockGracePeriod; /** * @notice Mapping of mToken to the address that has "fist mover" rights to do the liquidation * for the mToken (because that address first called startGracePeriod()) */ mapping (uint240 => address) public preferredLiquidator; /** * @notice Asking price that can be set by a mToken's current owner. At or above this price the mToken * will be instantly sold. Set to zero to disable. */ mapping (uint240 => uint256) public askingPrice; }
pragma solidity ^0.5.16; import "./open-zeppelin/token/ERC721/ERC721.sol"; import "./open-zeppelin/token/ERC721/IERC721Metadata.sol"; import "./open-zeppelin/token/ERC20/ERC20.sol"; contract TestNFT is ERC721, IERC721Metadata { string internal constant _name = "Glasses"; string internal constant _symbol = "GLSS"; uint256 public constant price = 0.1e18; uint256 public constant maxSupply = 1000; uint256 public nextTokenID; address payable public admin; string internal _baseURI; uint internal _digits; string internal _suffix; constructor(address payable _admin) ERC721(_name, _symbol) public { admin = msg.sender; _setMetadata("ipfs://QmWNi2ByeUbY1fWbMq841nvNW2tDTpNzyGAhxWDqoXTAEr", 0, ""); admin = _admin; } function mint() public payable returns (uint256 newTokenID) { require(nextTokenID < maxSupply, "all Glasses sold out"); require(msg.value >= price, "payment too low"); newTokenID = nextTokenID; nextTokenID++; _safeMint(msg.sender, newTokenID); } function () external payable { mint(); } //***** below this is just for trying out NFTX market functionality */ function buyAndRedeem(uint256 vaultId, uint256 amount, uint256[] calldata specificIds, address[] calldata path, address to) external payable { path; require(vaultId == 2, "wrong vault"); require(amount == 1, "wrong amount"); require(specificIds[0] == nextTokenID, "wrong ID"); require(to == msg.sender, "wrong to"); mint(); } //***** above this is just for trying out NFTX market functionality */ function name() external view returns (string memory) { return _name; } function symbol() external view returns (string memory) { return _symbol; } function tokenURI(uint256 tokenId) external view returns (string memory) { require(_exists(tokenId), "URI query for nonexistent token"); if (_digits == 0) { return string(abi.encodePacked(_baseURI, _suffix)); } else { bytes memory _tokenID = new bytes(_digits); uint _i = _digits; while (_i != 0) { _i--; _tokenID[_i] = bytes1(48 + uint8(tokenId % 10)); tokenId /= 10; } return string(abi.encodePacked(_baseURI, string(_tokenID), _suffix)); } } /*** Admin functions ***/ function _setMetadata(string memory newBaseURI, uint newDigits, string memory newSuffix) public { require(msg.sender == admin, "only admin"); require(newDigits < 10, "newDigits too big"); _baseURI = newBaseURI; _digits = newDigits; _suffix = newSuffix; } function _setAdmin(address payable newAdmin) public { require(msg.sender == admin, "only admin"); admin = newAdmin; } function _withdraw() external { require(msg.sender == admin, "only admin"); admin.transfer(address(this).balance); } } contract TestERC20 is ERC20 { constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) public { } function mint(uint256 amount) external { _mint(msg.sender, amount); } }
pragma solidity ^0.5.16; pragma experimental ABIEncoderV2; contract Mmo { /// @notice EIP-20 token name for this token string public constant name = "MMO Token"; /// @notice EIP-20 token symbol for this token string public constant symbol = "MMO"; /// @notice EIP-20 token decimals for this token uint8 public constant decimals = 18; /// @notice Total number of tokens in circulation uint public constant totalSupply = 10000000e18; // 10 million Mmo /// @notice Allowance amounts on behalf of others mapping (address => mapping (address => uint96)) internal allowances; /// @notice Official record of token balances for each account mapping (address => uint96) internal balances; /// @notice A record of each accounts delegate mapping (address => address) public delegates; /// @notice A checkpoint for marking number of votes from a given block struct Checkpoint { uint32 fromBlock; uint96 votes; } /// @notice A record of votes checkpoints for each account, by index mapping (address => mapping (uint32 => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping (address => uint32) public numCheckpoints; /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); /// @notice A record of states for signing / validating signatures mapping (address => uint) public nonces; /// @notice An event thats emitted when an account changes its delegate event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /// @notice An event thats emitted when a delegate account's vote balance changes event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance); /// @notice The standard EIP-20 transfer event event Transfer(address indexed from, address indexed to, uint256 amount); /// @notice The standard EIP-20 approval event event Approval(address indexed owner, address indexed spender, uint256 amount); /** * @notice Construct a new Mmo token * @param account The initial account to grant all the tokens */ constructor(address account) public { balances[account] = uint96(totalSupply); emit Transfer(address(0), account, totalSupply); } /** * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` * @param account The address of the account holding the funds * @param spender The address of the account spending the funds * @return The number of tokens approved */ function allowance(address account, address spender) external view returns (uint) { return allowances[account][spender]; } /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint rawAmount) external returns (bool) { uint96 amount; if (rawAmount == uint(-1)) { amount = uint96(-1); } else { amount = safe96(rawAmount, "Mmo::approve: amount exceeds 96 bits"); } allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } /** * @notice Get the number of tokens held by the `account` * @param account The address of the account to get the balance of * @return The number of tokens held */ function balanceOf(address account) external view returns (uint) { return balances[account]; } /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer(address dst, uint rawAmount) external returns (bool) { uint96 amount = safe96(rawAmount, "Mmo::transfer: amount exceeds 96 bits"); _transferTokens(msg.sender, dst, amount); return true; } /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom(address src, address dst, uint rawAmount) external returns (bool) { address spender = msg.sender; uint96 spenderAllowance = allowances[src][spender]; uint96 amount = safe96(rawAmount, "Mmo::approve: amount exceeds 96 bits"); if (spender != src && spenderAllowance != uint96(-1)) { uint96 newAllowance = sub96(spenderAllowance, amount, "Mmo::transferFrom: transfer amount exceeds spender allowance"); allowances[src][spender] = newAllowance; emit Approval(src, spender, newAllowance); } _transferTokens(src, dst, amount); return true; } /** * @notice Delegate votes from `msg.sender` to `delegatee` * @param delegatee The address to delegate votes to */ function delegate(address delegatee) public { return _delegate(msg.sender, delegatee); } /** * @notice Delegates votes from signatory to `delegatee` * @param delegatee The address to delegate votes to * @param nonce The contract state required to match the signature * @param expiry The time at which to expire the signature * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public { bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))); bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), "Mmo::delegateBySig: invalid signature"); require(nonce == nonces[signatory]++, "Mmo::delegateBySig: invalid nonce"); require(now <= expiry, "Mmo::delegateBySig: signature expired"); return _delegate(signatory, delegatee); } /** * @notice Gets the current votes balance for `account` * @param account The address to get votes balance * @return The number of current votes for `account` */ function getCurrentVotes(address account) external view returns (uint96) { uint32 nCheckpoints = numCheckpoints[account]; return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; } /** * @notice Determine the prior number of votes for an account as of a block number * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. * @param account The address of the account to check * @param blockNumber The block number to get the vote balance at * @return The number of votes the account had as of the given block */ function getPriorVotes(address account, uint blockNumber) public view returns (uint96) { require(blockNumber < block.number, "Mmo::getPriorVotes: not yet determined"); uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { return checkpoints[account][nCheckpoints - 1].votes; } // Next check implicit zero balance if (checkpoints[account][0].fromBlock > blockNumber) { return 0; } uint32 lower = 0; uint32 upper = nCheckpoints - 1; while (upper > lower) { uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint memory cp = checkpoints[account][center]; if (cp.fromBlock == blockNumber) { return cp.votes; } else if (cp.fromBlock < blockNumber) { lower = center; } else { upper = center - 1; } } return checkpoints[account][lower].votes; } function _delegate(address delegator, address delegatee) internal { address currentDelegate = delegates[delegator]; uint96 delegatorBalance = balances[delegator]; delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); _moveDelegates(currentDelegate, delegatee, delegatorBalance); } function _transferTokens(address src, address dst, uint96 amount) internal { require(src != address(0), "Mmo::_transferTokens: cannot transfer from the zero address"); require(dst != address(0), "Mmo::_transferTokens: cannot transfer to the zero address"); balances[src] = sub96(balances[src], amount, "Mmo::_transferTokens: transfer amount exceeds balance"); balances[dst] = add96(balances[dst], amount, "Mmo::_transferTokens: transfer amount overflows"); emit Transfer(src, dst, amount); _moveDelegates(delegates[src], delegates[dst], amount); } function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal { if (srcRep != dstRep && amount > 0) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0; uint96 srcRepNew = sub96(srcRepOld, amount, "Mmo::_moveVotes: vote amount underflows"); _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0; uint96 dstRepNew = add96(dstRepOld, amount, "Mmo::_moveVotes: vote amount overflows"); _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); } } } function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal { uint32 blockNumber = safe32(block.number, "Mmo::_writeCheckpoint: block number exceeds 32 bits"); if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) { checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; } else { checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes); numCheckpoints[delegatee] = nCheckpoints + 1; } emit DelegateVotesChanged(delegatee, oldVotes, newVotes); } function safe32(uint n, string memory errorMessage) internal pure returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function safe96(uint n, string memory errorMessage) internal pure returns (uint96) { require(n < 2**96, errorMessage); return uint96(n); } function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { uint96 c = a + b; require(c >= a, errorMessage); return c; } function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { require(b <= a, errorMessage); return a - b; } function getChainId() internal pure returns (uint) { uint256 chainId; assembly { chainId := chainid() } return chainId; } }
pragma solidity ^0.5.16; import "./PriceOracle.sol"; import "./MtrollerInterface.sol"; import "./MtrollerStorage.sol"; import "./MTokenInterfaces.sol"; import "./MTokenCommon.sol"; import "./Mmo.sol"; import "./ErrorReporter.sol"; import "./compound/ExponentialNoError.sol"; /** * @title Based on Compound's Mtroller Contract, with some modifications * @dev This contract must not declare any variables. All required storage must be in MtrollerV1Storage * @author Compound, mmo.finance */ contract MtrollerCommon is MtrollerV1Storage, MtrollerCommonInterface { /** * @notice Constructs a new MtrollerCommon */ constructor() public { } /** * @notice Tells the address of the current admin (set in MDelegator.sol) * @return admin The address of the current admin */ function getAdmin() public view returns (address payable admin) { bytes32 position = mDelegatorAdminPosition; assembly { admin := sload(position) } } /*** mToken identifier handling utilities ***/ /** * @notice Identifiers for mTokens are special uint240 numbers, where the highest order 8 bits is * an MTokenType enum, the lowest 160 bits are the address of the mToken's contract. The * remaining 72 bits in between are used as sequential ID number mTokenSeqNr (always > 0) for * non-fungible mTokens. For fungible tokens always mTokenSeqNr == 1. The mToken with * mTokenSeqNr == 0 is the special "anchor token" for a given mToken contract. */ /* Returns a special "contract" address reserved for the case when the underlying asset is Ether (ETH) */ function underlyingContractETH() public pure returns (address) { return address(uint160(-1)); } /** * @notice Construct the anchorToken from the given mToken contract address * @param mTokenContract The contract address of the mToken whose anchor token to return * @return uint240 The anchor token */ function getAnchorToken(address mTokenContract) public pure returns (uint240) { return assembleToken(MTokenIdentifier(mTokenContract).getTokenType(), 0, mTokenContract); } /** * @notice Construct the anchorToken from the given mToken * @param mToken The mToken whose anchor token to return * @return uint240 The anchor token for this mToken */ function getAnchorToken(uint240 mToken) internal pure returns (uint240) { return (mToken & 0xff000000000000000000ffffffffffffffffffffffffffffffffffffffff); } /** * @notice Creates an mToken identifier based on mTokenType, mTokenSeqNr and mTokenAddress * @dev Does not check for any errors in its arguments * @param mTokenType The MTokenType of the mToken * @param mTokenSeqNr The "serial number" of the mToken * @param mTokenAddress The address of the mToken's contract * @return uint240 The mToken identifier */ function assembleToken(MTokenType mTokenType, uint72 mTokenSeqNr, address mTokenAddress) public pure returns (uint240 mToken) { bytes10 mTokenData = bytes10(uint80(mTokenSeqNr) + (uint80(mTokenType) << 72)); return (uint240(bytes30(mTokenData)) + uint240(uint160(mTokenAddress))); } /** * @notice Given an mToken identifier, return the mToken's mTokenType, mTokenSeqNr and mTokenAddress * @dev Reverts on error (invalid mToken) * @param mToken The mToken to retreive the information from * @return (mTokenType The MTokenType of the mToken, * mTokenSeqNr The "serial number" of the mToken, * mTokenAddress The address of the mToken's contract) */ function parseToken(uint240 mToken) public pure returns (MTokenType mTokenType, uint72 mTokenSeqNr, address mTokenAddress) { mTokenAddress = address(uint160(mToken)); bytes10 mTokenData = bytes10(bytes30(mToken)); mTokenSeqNr = uint72(uint80(mTokenData)); mTokenType = MTokenType(uint8(mTokenData[0])); require(mTokenType == MTokenIdentifier(mTokenAddress).getTokenType(), "Invalid mToken type"); if (mTokenType == MTokenType.FUNGIBLE_MTOKEN) { require(mTokenSeqNr <= 1, "Invalid seqNr for fungible token"); } else if (mTokenType != MTokenType.ERC721_MTOKEN) { revert("Unknown mToken type"); } return (mTokenType, mTokenSeqNr, mTokenAddress); } /*** Assets You Are In ***/ /** * @notice Add the mToken market to the markets mapping and set it as listed * @dev Internal(!) function to set isListed and add support for the market * @param mToken The mToken market to list * @return uint 0=success, otherwise a failure. (See enum Error for details) */ function _supportMarketInternal(uint240 mToken) internal returns (uint) { if (isListed(mToken)) { return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS); } // Checks mToken format (full check) to make sure it is a valid mToken (reverts on error) ( , uint72 mTokenSeqNr, address mTokenAddress) = parseToken(mToken); require(mTokenSeqNr <= MTokenCommon(mTokenAddress).totalCreatedMarkets(), "invalid mToken SeqNr"); uint240 tokenAnchor = getAnchorToken(mTokenAddress); require(tokenAnchor == getAnchorToken(mToken), "invalid anchor token"); /** * Unless sender is admin, only allow listing if sender is mToken's own contract and mToken is * not the anchor token and the mToken's anchor token is already listed */ if (msg.sender != getAdmin()) { if (msg.sender != mTokenAddress || mToken == tokenAnchor || !isListed(tokenAnchor)) { return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK); } } // Set the mToken as listed markets[mToken] = Market({_isListed: true, _collateralFactorMantissa: 0}); // If the mToken is an anchor token, add it to the markets mapping (reverts on error) if (mToken == tokenAnchor) { _addMarketInternal(mToken); } emit MarketListed(mToken); return uint(Error.NO_ERROR); } function _addMarketInternal(uint240 mToken) internal { require(allMarketsIndex[mToken] == 0, "market already added"); allMarketsSize++; allMarkets[allMarketsSize] = mToken; allMarketsIndex[mToken] = allMarketsSize; } /** * @notice Checks if an mToken is listed (i.e., it is supported by the platform) * @dev For this to return true both the actual mToken and its anchorToken have to be listed. * The anchorToken needs to be listed explicitly by admin using _supportMarket(). Any other * mToken is listed automatically when mintAllowed() is called for that mToken, i.e. when it is * minted for the first time, but only if it's anchorToken is already listed. * @param mToken The mToken to check * @return true if both the mToken and its anchorToken are listed, false otherwise */ function isListed(uint240 mToken) internal view returns (bool) { if (!(markets[getAnchorToken(mToken)]._isListed)) { return false; } return (markets[mToken]._isListed); } /** * @notice Returns the current collateral factor of a mToken * @dev If the mTokens own (specific) collateral factor is zero or the anchor token's collateral * factor is zero, then the anchor token's collateral factor is returned, otherwise the specific factor. * Reverts if mToken is not listed or resulting collateral factor exceeds limit * @param mToken The mToken to return the collateral factor for * @return uint The mToken's current collateral factor, scaled by 1e18 */ function collateralFactorMantissa(uint240 mToken) public view returns (uint) { require(isListed(mToken), "mToken not listed"); uint240 tokenAnchor = getAnchorToken(mToken); uint result = markets[tokenAnchor]._collateralFactorMantissa; if (result == 0) { return 0; } if (mToken != tokenAnchor) { uint localFactor = markets[mToken]._collateralFactorMantissa; if (localFactor != 0) { result = localFactor; } } require(result <= collateralFactorMaxMantissa, "collateral factor too high"); return result; } }
pragma solidity ^0.5.16; import "./PriceOracle.sol"; contract MTokenIdentifier { /* mToken identifier handling */ enum MTokenType { INVALID_MTOKEN, FUNGIBLE_MTOKEN, ERC721_MTOKEN } /* * Marker for valid mToken contract. Derived MToken contracts need to override this returning * the correct MTokenType for that MToken */ function getTokenType() public pure returns (MTokenType) { return MTokenType.INVALID_MTOKEN; } } contract MDelegatorIdentifier { // Storage position of the admin of a delegator contract bytes32 internal constant mDelegatorAdminPosition = keccak256("com.mmo-finance.mDelegator.admin.address"); } contract MtrollerCommonInterface is MTokenIdentifier, MDelegatorIdentifier { /// @notice Emitted when an admin supports a market event MarketListed(uint240 mToken); /// @notice Emitted when a collateral factor is changed by admin event NewCollateralFactor(uint240 mToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa); /// @notice Emitted when an account enters a market event MarketEntered(uint240 mToken, address account); /// @notice Emitted when an account exits a market event MarketExited(uint240 mToken, address account); /// @notice Emitted when a new MMO speed is calculated for a market event MmoSpeedUpdated(uint240 indexed mToken, uint newSpeed); /// @notice Emitted when a new MMO speed is set for a contributor event ContributorMmoSpeedUpdated(address indexed contributor, uint newSpeed); /// @notice Emitted when MMO is distributed to a supplier event DistributedSupplierMmo(uint240 indexed mToken, address indexed supplier, uint mmoDelta, uint MmoSupplyIndex); /// @notice Emitted when MMO is distributed to a borrower event DistributedBorrowerMmo(uint240 indexed mToken, address indexed borrower, uint mmoDelta, uint mmoBorrowIndex); /// @notice Emitted when MMO is granted by admin event MmoGranted(address recipient, uint amount); /// @notice Emitted when close factor is changed by admin event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa); /// @notice Emitted when liquidation incentive is changed by admin event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa); /// @notice Emitted when maxAssets is changed by admin event NewMaxAssets(uint oldMaxAssets, uint newMaxAssets); /// @notice Emitted when price oracle is changed event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle); /// @notice Emitted when pause guardian is changed event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); /// @notice Emitted when an action is paused globally event ActionPaused(string action, bool pauseState); /// @notice Emitted when an action is paused on a market event ActionPaused(uint240 mToken, string action, bool pauseState); /// @notice Emitted when borrow cap for a mToken is changed event NewBorrowCap(uint240 indexed mToken, uint newBorrowCap); /// @notice Emitted when borrow cap guardian is changed event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian); function getAdmin() public view returns (address payable admin); function underlyingContractETH() public pure returns (address); function getAnchorToken(address mTokenContract) public pure returns (uint240); function assembleToken(MTokenType mTokenType, uint72 mTokenSeqNr, address mTokenAddress) public pure returns (uint240 mToken); function parseToken(uint240 mToken) public pure returns (MTokenType mTokenType, uint72 mTokenSeqNr, address mTokenAddress); function collateralFactorMantissa(uint240 mToken) public view returns (uint); } contract MtrollerUserInterface is MtrollerCommonInterface { /// @notice Indicator that this is a user part contract (for inspection) function isMDelegatorUserImplementation() public pure returns (bool); /*** Assets You Are In ***/ function getAssetsIn(address account) external view returns (uint240[] memory); function checkMembership(address account, uint240 mToken) external view returns (bool); function enterMarkets(uint240[] calldata mTokens) external returns (uint[] memory); function enterMarketOnBehalf(uint240 mToken, address owner) external returns (uint); function exitMarket(uint240 mToken) external returns (uint); function exitMarketOnBehalf(uint240 mToken, address owner) external returns (uint); function _setCollateralFactor(uint240 mToken, uint newCollateralFactorMantissa) external returns (uint); /*** Policy Hooks ***/ function auctionAllowed(uint240 mToken, address bidder) public view returns (uint); function mintAllowed(uint240 mToken, address minter, uint mintAmount) external returns (uint); function mintVerify(uint240 mToken, address minter, uint actualMintAmount, uint mintTokens) external view; function redeemAllowed(uint240 mToken, address redeemer, uint redeemTokens) external view returns (uint); function redeemVerify(uint240 mToken, address redeemer, uint redeemAmount, uint redeemTokens) external view; function borrowAllowed(uint240 mToken, address borrower, uint borrowAmount) external view returns (uint); function borrowVerify(uint240 mToken, address borrower, uint borrowAmount) external view; function repayBorrowAllowed(uint240 mToken, address payer, address borrower, uint repayAmount) external view returns (uint); function repayBorrowVerify(uint240 mToken, address payer, address borrower, uint actualRepayAmount, uint borrowerIndex) external view; function liquidateBorrowAllowed(uint240 mTokenBorrowed, uint240 mTokenCollateral, address liquidator, address borrower, uint repayAmount) external view returns (uint); function liquidateERC721Allowed(uint240 mToken) external view returns (uint); function liquidateBorrowVerify(uint240 mTokenBorrowed, uint240 mTokenCollateral, address liquidator, address borrower, uint actualRepayAmount, uint seizeTokens) external view; function seizeAllowed(uint240 mTokenCollateral, uint240 mTokenBorrowed, address liquidator, address borrower, uint seizeTokens) external view returns (uint); function seizeVerify(uint240 mTokenCollateral, uint240 mTokenBorrowed, address liquidator, address borrower, uint seizeTokens) external view; function transferAllowed(uint240 mToken, address src, address dst, uint transferTokens) external view returns (uint); function transferVerify(uint240 mToken, address src, address dst, uint transferTokens) external view; /*** Price and Liquidity/Liquidation Calculations ***/ function getAccountLiquidity(address account) public view returns (uint, uint, uint); function getHypotheticalAccountLiquidity(address account, uint240 mTokenModify, uint redeemTokens, uint borrowAmount) public view returns (uint, uint, uint); function liquidateCalculateSeizeTokens(uint240 mTokenBorrowed, uint240 mTokenCollateral, uint actualRepayAmount) external view returns (uint, uint); function getBlockNumber() public view returns (uint); function getPrice(uint240 mToken) public view returns (uint); /*** Mmo reward handling ***/ function updateContributorRewards(address contributor) public; function claimMmo(address holder, uint240[] memory mTokens) public; function claimMmo(address[] memory holders, uint240[] memory mTokens, bool borrowers, bool suppliers) public; /*** Mmo admin functions ***/ function _grantMmo(address recipient, uint amount) public; function _setMmoSpeed(uint240 mToken, uint mmoSpeed) public; function _setContributorMmoSpeed(address contributor, uint mmoSpeed) public; function getMmoAddress() public view returns (address); } contract MtrollerAdminInterface is MtrollerCommonInterface { function initialize(address _mmoTokenAddress, uint _maxAssets) public; /// @notice Indicator that this is a admin part contract (for inspection) function isMDelegatorAdminImplementation() public pure returns (bool); function _supportMarket(uint240 mToken) external returns (uint); function _setPriceOracle(PriceOracle newOracle) external returns (uint); function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint); function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint); function _setMaxAssets(uint newMaxAssets) external; function _setBorrowCapGuardian(address newBorrowCapGuardian) external; function _setMarketBorrowCaps(uint240[] calldata mTokens, uint[] calldata newBorrowCaps) external; function _setPauseGuardian(address newPauseGuardian) public returns (uint); function _setAuctionPaused(uint240 mToken, bool state) public returns (bool); function _setMintPaused(uint240 mToken, bool state) public returns (bool); function _setBorrowPaused(uint240 mToken, bool state) public returns (bool); function _setTransferPaused(uint240 mToken, bool state) public returns (bool); function _setSeizePaused(uint240 mToken, bool state) public returns (bool); } contract MtrollerInterface is MtrollerAdminInterface, MtrollerUserInterface {}
pragma solidity ^0.5.16; import "./PriceOracle.sol"; import "./MTokenInterfaces.sol"; import "./MTokenStorage.sol"; import "./ErrorReporter.sol"; import "./compound/ExponentialNoError.sol"; contract MtrollerV1Storage is MDelegateeStorage, MtrollerErrorReporter, ExponentialNoError { /*** Global variables: addresses of other contracts to call. * These are set at contract initialization and can only be modified by a (timelock) admin ***/ /** * @notice Address of the mmo token contract (this never changes again after initialization) */ address mmoTokenAddress; /** * @notice Oracle which gives the price of any given asset */ PriceOracle public oracle; /*** Global variables: protocol control parameters. * These variables are set at contract initialization and can only be modified by a (timelock) admin ***/ /** * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow */ uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05 (lower limit) uint internal constant closeFactorMaxMantissa = 1.0e18; // 1.0 (upper limit) uint public closeFactorMantissa; /** * @notice Multiplier representing the discount on collateral that a liquidator receives */ uint internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0 (lower limit = no incentive) uint internal constant liquidationIncentiveMaxMantissa = 2.0e18; // 2.0 (upper limit = 50% discount) uint public liquidationIncentiveMantissa; /** * @notice Max number of assets a single account can participate in (borrow or use as collateral). * This value is set at initialization and can only be modified by admin. */ uint public maxAssets; /** * @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow * cap could disable borrowing on the given market. */ address public borrowCapGuardian; /** * @notice The Pause Guardian can pause certain actions as a safety mechanism. * Actions which allow users to remove their own assets cannot be paused. * Liquidation / seizing / transfer can only be paused globally, not by market. */ address public pauseGuardian; /*** mToken variables: general token-specific parameters and permissions. * These variables are initialized the first time the given mToken is minted and then adapted when needed ***/ /** * @notice Per-account mapping of "mToken assets you are in", length of array capped by maxAssets */ mapping(address => uint240[]) public accountAssets; /// Structure for per-token metadata. TODO: Move these to individual mappings (no struct anymore) struct Market { /// @notice Whether or not this mToken market is listed, i.e. allowed to interact with the mtroller bool _isListed; /** * @notice Multiplier representing the most one can borrow against their collateral in this mToken market. * For instance, 0.9e18 to allow borrowing 90% of collateral value. * Must be between 0 and 1e18 (stored as a mantissa, i.e., scaled by 1e18) */ uint _collateralFactorMantissa; /// @notice Mapping of "accounts in this asset", per mToken market. mapping(address => bool) _accountMembership; } /// @notice No collateralFactorMantissa may exceed this value uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 /** * @notice Official mapping of mTokens -> Market metadata * @dev Used e.g. to determine if a market is supported. Do not access variables directly but use getter * functions _isListed(), _collateralFactorMantissa(), etc */ mapping(uint240 => Market) public markets; /*** mToken variables: per-token variables to control (emergency) pausing of certain functions. * These variables are inactive by default and only set by admin if needed ***/ mapping(uint240 => bool) public auctionGuardianPaused; mapping(uint240 => bool) public mintGuardianPaused; mapping(uint240 => bool) public borrowGuardianPaused; mapping(uint240 => bool) public transferGuardianPaused; mapping(uint240 => bool) public seizeGuardianPaused; // @notice Borrow caps enforced by borrowAllowed for each mToken address. Defaults to zero which corresponds to unlimited borrowing. mapping(uint240 => uint) public borrowCaps; /*** mToken variables: list of all markets (for book-keeping by the mtroller). * Only the anchor tokens are registered (when the admin calls _supportMarket() for that anchor token). * All other mTokens used (ever minted) can be retrieved from their contract using the respective anchor token. ***/ /// @notice A list of all markets mapping (uint => uint240) public allMarkets; mapping (uint240 => uint) public allMarketsIndex; uint public allMarketsSize; /*** MMO platform token variables: not really used so far ***/ /// @notice The rate at which the flywheel distributes MMO to mToken markets, per block. /// Only admin can set that. TODO: better use only with anchor mToken! mapping(uint240 => uint) public mmoSpeeds; struct MmoMarketState { /// @notice The market's last updated mmoBorrowIndex or mmoSupplyIndex uint224 index; /// @notice The block number the index was last updated at uint32 block; } /// @notice The MMO market supply state for each market mapping(uint240 => MmoMarketState) public mmoSupplyState; /// @notice The MMO market borrow state for each market mapping(uint240 => MmoMarketState) public mmoBorrowState; /// @notice The MMO borrow index for each market for each supplier as of the last time they accrued MMO mapping(uint240 => mapping(address => uint)) public mmoSupplierIndex; /// @notice The MMO borrow index for each market for each borrower as of the last time they accrued MMO mapping(uint240 => mapping(address => uint)) public mmoBorrowerIndex; /// @notice The MMO accrued but not yet transferred to each user mapping(address => uint) public mmoAccrued; /// @notice The portion of MMO that each contributor receives per block mapping(address => uint) public mmoContributorSpeeds; /// @notice Last block at which a contributor's MMO rewards have been allocated mapping(address => uint) public lastContributorBlock; /// @notice The initial MMO index for a market uint224 public constant mmoInitialIndex = 1e36; }
pragma solidity ^0.5.16; import "./MTokenTest_coins.sol"; contract PriceOracle { /// @notice Indicator that this is a PriceOracle contract (for inspection) bool public constant isPriceOracle = true; /** * @notice Get the price of an underlying token * @param underlyingToken The address of the underlying token contract * @param tokenID The ID of the underlying token if it is a NFT (0 for fungible tokens) * @return The underlying asset price mantissa (scaled by 1e18). For fungible underlying tokens that * means e.g. if one single underlying token costs 1 Wei then the asset price mantissa should be 1e18. * In case of underlying (ERC-721 compliant) NFTs one NFT always corresponds to oneUnit = 1e18 * internal calculatory units (see MTokenInterfaces.sol), therefore if e.g. one NFT costs 0.1 ETH * then the asset price mantissa returned here should be 0.1e18. * Zero means the price is unavailable. */ function getUnderlyingPrice(address underlyingToken, uint256 tokenID) public view returns (uint); } contract PriceOracleV0_1 is PriceOracle { event NewCollectionFloorPrice(uint oldFloorPrice, uint newFloorPrice); address admin; TestNFT glassesContract; IERC721 collectionContract; uint collectionFloorPrice; constructor(address _admin, TestNFT _glassesContract, IERC721 _collectionContract) public { admin = _admin; glassesContract = _glassesContract; collectionContract = _collectionContract; } function getUnderlyingPrice(address underlyingToken, uint256 tokenID) public view returns (uint) { tokenID; if (underlyingToken == address(uint160(-1))) { return 1.0e18; // relative price of MEther token is 1.0 (1 token = 1 Wei) } else if (underlyingToken == address(glassesContract)) { return glassesContract.price(); // one unit (1e18) of NFT price in wei } else if (underlyingToken == address(collectionContract)) { return collectionFloorPrice; // one unit (1e18) of NFT price in wei } else { return 0; } } function _setCollectionFloorPrice(uint newFloorPrice) external { require(msg.sender == admin, "only admin"); uint oldFloorPrice = collectionFloorPrice; collectionFloorPrice = newFloorPrice; emit NewCollectionFloorPrice(oldFloorPrice, newFloorPrice); } }
pragma solidity ^0.5.16; import "./MtrollerInterface.sol"; import "./MTokenInterfaces.sol"; import "./ErrorReporter.sol"; import "./compound/Exponential.sol"; import "./open-zeppelin/token/ERC721/IERC721.sol"; contract TokenAuction is Exponential, TokenErrorReporter { event NewAuctionOffer(uint240 tokenID, address offeror, uint256 totalOfferAmount); event AuctionOfferCancelled(uint240 tokenID, address offeror, uint256 cancelledOfferAmount); event HighestOfferAccepted(uint240 tokenID, address offeror, uint256 acceptedOfferAmount, uint256 auctioneerTokens, uint256 oldOwnerTokens); event AuctionRefund(address beneficiary, uint256 amount); struct Bidding { mapping (address => uint256) offers; mapping (address => uint256) offerIndex; uint256 nextOffer; mapping (uint256 => mapping (uint256 => address)) maxOfferor; } bool internal _notEntered; // re-entrancy check flag MEtherUserInterface public paymentToken; MtrollerUserInterface public mtroller; mapping (uint240 => Bidding) public biddings; // ETH account for each participant mapping (address => uint256) public refunds; constructor(MtrollerUserInterface _mtroller, MEtherUserInterface _fungiblePaymentToken) public { mtroller = _mtroller; paymentToken = _fungiblePaymentToken; _notEntered = true; // Start true prevents changing from zero to non-zero (smaller gas cost) } function addOfferETH( uint240 _mToken, address _bidder, address _oldOwner, uint256 _askingPrice ) external nonReentrant payable returns (uint256) { require (msg.value > 0, "No payment sent"); require(mtroller.auctionAllowed(_mToken, _bidder) == uint(Error.NO_ERROR), "Auction not allowed"); ( , , address _tokenAddress) = mtroller.parseToken(_mToken); require(msg.sender == _tokenAddress, "Only token contract"); uint256 _oldOffer = biddings[_mToken].offers[_bidder]; uint256 _newOffer = _oldOffer + msg.value; /* if new offer is >= asking price of mToken, we do not enter the bid but sell directly */ if (_newOffer >= _askingPrice && _askingPrice > 0) { if (_oldOffer > 0) { require(cancelOfferInternal(_mToken, _bidder) == _oldOffer, "Could not cancel offer"); } ( , uint256 oldOwnerTokens) = processPaymentInternal(_oldOwner, _newOffer, _oldOwner, 0); emit HighestOfferAccepted(_mToken, _bidder, _newOffer, 0, oldOwnerTokens); return _newOffer; } /* otherwise the new bid is entered normally */ else { if (_oldOffer == 0) { uint256 _nextIndex = biddings[_mToken].nextOffer; biddings[_mToken].offerIndex[_bidder] = _nextIndex; biddings[_mToken].nextOffer = _nextIndex + 1; } _updateOffer(_mToken, biddings[_mToken].offerIndex[_bidder], _bidder, _newOffer); emit NewAuctionOffer(_mToken, _bidder, _newOffer); return 0; } } function cancelOffer( uint240 _mToken ) public nonReentrant { // // for later version: if sender is the highest bidder try to start grace period // // and do not allow to cancel bid during grace period (+ 2 times preferred liquidator delay) // if (msg.sender == getMaxOfferor(_mToken)) { // ( , , address _mTokenAddress) = mtroller.parseToken(_mToken); // MERC721Interface(_mTokenAddress).startGracePeriod(_mToken); // } uint256 _oldOffer = cancelOfferInternal(_mToken, msg.sender); refunds[msg.sender] += _oldOffer; emit AuctionOfferCancelled(_mToken, msg.sender, _oldOffer); } function acceptHighestOffer( uint240 _mToken, address _oldOwner, address _auctioneer, uint256 _auctioneerFeeMantissa, uint256 _minimumPrice ) external nonReentrant returns (address _maxOfferor, uint256 _maxOffer, uint256 auctioneerTokens, uint256 oldOwnerTokens) { require(mtroller.auctionAllowed(_mToken, _auctioneer) == uint(Error.NO_ERROR), "Auction not allowed"); ( , , address _tokenAddress) = mtroller.parseToken(_mToken); require(msg.sender == _tokenAddress, "Only token contract"); _maxOfferor = getMaxOfferor(_mToken); // reverts if no valid offer found _maxOffer = cancelOfferInternal(_mToken, _maxOfferor); require(_maxOffer >= _minimumPrice, "Best offer too low"); /* process payment, reverts on error */ (auctioneerTokens, oldOwnerTokens) = processPaymentInternal(_oldOwner, _maxOffer, _auctioneer, _auctioneerFeeMantissa); emit HighestOfferAccepted(_mToken, _maxOfferor, _maxOffer, auctioneerTokens, oldOwnerTokens); return (_maxOfferor, _maxOffer, auctioneerTokens, oldOwnerTokens); } function processPaymentInternal( address _oldOwner, uint256 _price, address _broker, uint256 _brokerFeeMantissa ) internal returns (uint256 brokerTokens, uint256 oldOwnerTokens) { require(_oldOwner != address(0), "Invalid owner address"); require(_price > 0, "Invalid price"); /* calculate fees for protocol and add it to protocol's reserves (in underlying cash) */ uint256 _amountLeft = _price; Exp memory _feeShare = Exp({mantissa: paymentToken.getProtocolAuctionFeeMantissa()}); (MathError _mathErr, uint256 _fee) = mulScalarTruncate(_feeShare, _price); require(_mathErr == MathError.NO_ERROR, "Invalid protocol fee"); if (_fee > 0) { (_mathErr, _amountLeft) = subUInt(_price, _fee); require(_mathErr == MathError.NO_ERROR, "Invalid protocol fee"); paymentToken._addReserves.value(_fee)(); } /* calculate and pay broker's fee (if any) by minting corresponding paymentToken amount */ _feeShare = Exp({mantissa: _brokerFeeMantissa}); (_mathErr, _fee) = mulScalarTruncate(_feeShare, _price); require(_mathErr == MathError.NO_ERROR, "Invalid broker fee"); if (_fee > 0) { require(_broker != address(0), "Invalid broker address"); (_mathErr, _amountLeft) = subUInt(_amountLeft, _fee); require(_mathErr == MathError.NO_ERROR, "Invalid broker fee"); brokerTokens = paymentToken.mintTo.value(_fee)(_broker); } /* * Pay anything left to the old owner by minting a corresponding paymentToken amount. In case * of liquidation these paymentTokens can be liquidated in a next step. * NEVER pay underlying cash to the old owner here!! */ if (_amountLeft > 0) { oldOwnerTokens = paymentToken.mintTo.value(_amountLeft)(_oldOwner); } } function cancelOfferInternal( uint240 _mToken, address _offeror ) internal returns (uint256 _oldOffer) { _oldOffer = biddings[_mToken].offers[_offeror]; require (_oldOffer > 0, "No active offer found"); uint256 _thisIndex = biddings[_mToken].offerIndex[_offeror]; uint256 _nextIndex = biddings[_mToken].nextOffer; assert (_nextIndex > 0); _nextIndex--; if (_thisIndex != _nextIndex) { address _swappedOfferor = biddings[_mToken].maxOfferor[0][_nextIndex]; biddings[_mToken].offerIndex[_swappedOfferor] = _thisIndex; uint256 _newOffer = biddings[_mToken].offers[_swappedOfferor]; _updateOffer(_mToken, _thisIndex, _swappedOfferor, _newOffer); } _updateOffer(_mToken, _nextIndex, address(0), 0); delete biddings[_mToken].offers[_offeror]; delete biddings[_mToken].offerIndex[_offeror]; biddings[_mToken].nextOffer = _nextIndex; return _oldOffer; } /** @notice Withdraws any funds the contract has collected for the msg.sender from refunds and proceeds of sales or auctions. */ function withdrawAuctionRefund() public nonReentrant { require(refunds[msg.sender] > 0, "No outstanding refunds found"); uint256 _refundAmount = refunds[msg.sender]; refunds[msg.sender] = 0; msg.sender.transfer(_refundAmount); emit AuctionRefund(msg.sender, _refundAmount); } /** @notice Convenience function to cancel and withdraw in one call */ function cancelOfferAndWithdrawRefund( uint240 _mToken ) external { cancelOffer(_mToken); withdrawAuctionRefund(); } uint256 constant private clusterSize = (2**4); function _updateOffer( uint240 _mToken, uint256 _offerIndex, address _newOfferor, uint256 _newOffer ) internal { assert (biddings[_mToken].nextOffer > 0); assert (biddings[_mToken].offers[address(0)] == 0); uint256 _n = 0; address _origOfferor = _newOfferor; uint256 _origOffer = biddings[_mToken].offers[_newOfferor]; if (_newOffer != _origOffer) { biddings[_mToken].offers[_newOfferor] = _newOffer; } for (uint256 tmp = biddings[_mToken].nextOffer * clusterSize; tmp > 0; tmp = tmp / clusterSize) { uint256 _oldOffer; address _oldOfferor = biddings[_mToken].maxOfferor[_n][_offerIndex]; if (_oldOfferor != _newOfferor) { biddings[_mToken].maxOfferor[_n][_offerIndex] = _newOfferor; } _offerIndex = _offerIndex / clusterSize; address _maxOfferor = biddings[_mToken].maxOfferor[_n + 1][_offerIndex]; if (tmp < clusterSize) { if (_maxOfferor != address(0)) { biddings[_mToken].maxOfferor[_n + 1][_offerIndex] = address(0); } return; } if (_maxOfferor != address(0)) { if (_oldOfferor == _origOfferor) { _oldOffer = _origOffer; } else { _oldOffer = biddings[_mToken].offers[_oldOfferor]; } if ((_oldOfferor != _maxOfferor) && (_newOffer <= _oldOffer)) { return; } if ((_oldOfferor == _maxOfferor) && (_newOffer > _oldOffer)) { _n++; continue; } } uint256 _i = _offerIndex * clusterSize; _newOfferor = biddings[_mToken].maxOfferor[_n][_i]; _newOffer = biddings[_mToken].offers[_newOfferor]; _i++; while ((_i % clusterSize) != 0) { address _tmpOfferor = biddings[_mToken].maxOfferor[_n][_i]; if (biddings[_mToken].offers[_tmpOfferor] > _newOffer) { _newOfferor = _tmpOfferor; _newOffer = biddings[_mToken].offers[_tmpOfferor]; } _i++; } _n++; } } function getMaxOffer( uint240 _mToken ) public view returns (uint256) { if (biddings[_mToken].nextOffer == 0) { return 0; } return biddings[_mToken].offers[getMaxOfferor(_mToken)]; } function getMaxOfferor( uint240 _mToken ) public view returns (address) { uint256 _n = 0; for (uint256 tmp = biddings[_mToken].nextOffer * clusterSize; tmp > 0; tmp = tmp / clusterSize) { _n++; } require (_n > 0, "No valid offer found"); _n--; return biddings[_mToken].maxOfferor[_n][0]; } function getMaxOfferor( uint240 _mToken, uint256 _level, uint256 _offset ) public view returns (address[10] memory _offerors) { for (uint256 _i = 0; _i < 10; _i++) { _offerors[_i] = biddings[_mToken].maxOfferor[_level][_offset + _i]; } return _offerors; } function getOffer( uint240 _mToken, address _account ) public view returns (uint256) { return biddings[_mToken].offers[_account]; } function getOfferIndex( uint240 _mToken ) public view returns (uint256) { require (biddings[_mToken].offers[msg.sender] > 0, "No active offer"); return biddings[_mToken].offerIndex[msg.sender]; } function getCurrentOfferCount( uint240 _mToken ) external view returns (uint256) { return(biddings[_mToken].nextOffer); } function getOfferAtIndex( uint240 _mToken, uint256 _offerIndex ) external view returns (address offeror, uint256 offer) { require(biddings[_mToken].nextOffer > 0, "No valid offer"); require(_offerIndex < biddings[_mToken].nextOffer, "Offer index out of range"); offeror = biddings[_mToken].maxOfferor[0][_offerIndex]; offer = biddings[_mToken].offers[offeror]; } /** * @dev Block reentrancy (directly or indirectly) */ modifier nonReentrant() { require(_notEntered, "Reentrance not allowed"); _notEntered = false; _; _notEntered = true; // get a gas-refund post-Istanbul } // ************************************************************ // Test functions only below this point, remove in production! // function addOfferETH_Test( // uint240 _mToken, // address _sender, // uint256 _amount // ) // public // nonReentrant // { // require (_amount > 0, "No payment sent"); // uint256 _oldOffer = biddings[_mToken].offers[_sender]; // uint256 _newOffer = _oldOffer + _amount; // if (_oldOffer == 0) { // uint256 _nextIndex = biddings[_mToken].nextOffer; // biddings[_mToken].offerIndex[_sender] = _nextIndex; // biddings[_mToken].nextOffer = _nextIndex + 1; // } // _updateOffer(_mToken, biddings[_mToken].offerIndex[_sender], _sender, _newOffer); // emit NewAuctionOffer(_mToken, _sender, _newOffer); // } // function cancelOfferETH_Test( // uint240 _mToken, // address _sender // ) // public // nonReentrant // { // uint256 _oldOffer = biddings[_mToken].offers[_sender]; // require (_oldOffer > 0, "No active offer found"); // uint256 _thisIndex = biddings[_mToken].offerIndex[_sender]; // uint256 _nextIndex = biddings[_mToken].nextOffer; // assert (_nextIndex > 0); // _nextIndex--; // if (_thisIndex != _nextIndex) { // address _swappedOfferor = biddings[_mToken].maxOfferor[0][_nextIndex]; // biddings[_mToken].offerIndex[_swappedOfferor] = _thisIndex; // uint256 _newOffer = biddings[_mToken].offers[_swappedOfferor]; // _updateOffer(_mToken, _thisIndex, _swappedOfferor, _newOffer); // } // _updateOffer(_mToken, _nextIndex, address(0), 0); // delete biddings[_mToken].offers[_sender]; // delete biddings[_mToken].offerIndex[_sender]; // biddings[_mToken].nextOffer = _nextIndex; // refunds[_sender] += _oldOffer; // emit AuctionOfferCancelled(_mToken, _sender, _oldOffer); // } // function testBidding( // uint256 _start, // uint256 _cnt // ) // public // { // for (uint256 _i = _start; _i < (_start + _cnt); _i++) { // addOfferETH_Test(1, address(uint160(_i)), _i); // } // } }
pragma solidity ^0.5.16; /** * @title Careful Math * @author Compound * @notice Derived from OpenZeppelin's SafeMath library * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol */ contract CarefulMath { /** * @dev Possible error codes that we can return */ enum MathError { NO_ERROR, DIVISION_BY_ZERO, INTEGER_OVERFLOW, INTEGER_UNDERFLOW } /** * @dev Multiplies two numbers, returns an error on overflow. */ function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { if (a == 0) { return (MathError.NO_ERROR, 0); } uint c = a * b; if (c / a != b) { return (MathError.INTEGER_OVERFLOW, 0); } else { return (MathError.NO_ERROR, c); } } /** * @dev Integer division of two numbers, truncating the quotient. */ function divUInt(uint a, uint b) internal pure returns (MathError, uint) { if (b == 0) { return (MathError.DIVISION_BY_ZERO, 0); } return (MathError.NO_ERROR, a / b); } /** * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). */ function subUInt(uint a, uint b) internal pure returns (MathError, uint) { if (b <= a) { return (MathError.NO_ERROR, a - b); } else { return (MathError.INTEGER_UNDERFLOW, 0); } } /** * @dev Adds two numbers, returns an error on overflow. */ function addUInt(uint a, uint b) internal pure returns (MathError, uint) { uint c = a + b; if (c >= a) { return (MathError.NO_ERROR, c); } else { return (MathError.INTEGER_OVERFLOW, 0); } } /** * @dev add a and b and then subtract c */ function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { (MathError err0, uint sum) = addUInt(a, b); if (err0 != MathError.NO_ERROR) { return (err0, 0); } return subUInt(sum, c); } }
pragma solidity ^0.5.16; /** * @title ERC 20 Token Standard Interface * https://eips.ethereum.org/EIPS/eip-20 */ interface EIP20Interface { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); /** * @notice Get the total number of tokens in circulation * @return The supply of tokens */ function totalSupply() external view returns (uint256); /** * @notice Gets the balance of the specified address * @param owner The address from which the balance will be retrieved * @return The balance */ function balanceOf(address owner) external view returns (uint256 balance); /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer(address dst, uint256 amount) external returns (bool success); /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom(address src, address dst, uint256 amount) external returns (bool success); /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved (-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint256 amount) external returns (bool success); /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return The number of tokens allowed to be spent (-1 means infinite) */ function allowance(address owner, address spender) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); }
pragma solidity ^0.5.16; /** * @title EIP20NonStandardInterface * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ interface EIP20NonStandardInterface { /** * @notice Get the total number of tokens in circulation * @return The supply of tokens */ function totalSupply() external view returns (uint256); /** * @notice Gets the balance of the specified address * @param owner The address from which the balance will be retrieved * @return The balance */ function balanceOf(address owner) external view returns (uint256 balance); /// /// !!!!!!!!!!!!!! /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification /// !!!!!!!!!!!!!! /// /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer */ function transfer(address dst, uint256 amount) external; /// /// !!!!!!!!!!!!!! /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification /// !!!!!!!!!!!!!! /// /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer */ function transferFrom(address src, address dst, uint256 amount) external; /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved * @return Whether or not the approval succeeded */ function approve(address spender, uint256 amount) external returns (bool success); /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return The number of tokens allowed to be spent */ function allowance(address owner, address spender) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); }
pragma solidity ^0.5.16; import "./CarefulMath.sol"; import "./ExponentialNoError.sol"; /** * @title Exponential module for storing fixed-precision decimals * @author Compound * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: * `Exp({mantissa: 5100000000000000000})`. */ contract Exponential is CarefulMath, ExponentialNoError { /** * @dev Creates an exponential from numerator and denominator values. * Note: Returns an error if (`num` * 10e18) > MAX_INT, * or if `denom` is zero. */ function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } (MathError err1, uint rational) = divUInt(scaledNumerator, denom); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: rational})); } /** * @dev Adds two exponentials, returning a new exponential. */ function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } /** * @dev Subtracts two exponentials, returning a new exponential. */ function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } /** * @dev Multiply an Exp by a scalar, returning a new Exp. */ function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(product)); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return addUInt(truncate(product), addend); } /** * @dev Divide an Exp by a scalar, returning a new Exp. */ function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); } /** * @dev Divide a scalar by an Exp, returning a new Exp. */ function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) { /* We are doing this as: getExp(mulUInt(expScale, scalar), divisor.mantissa) How it works: Exp = a / b; Scalar = s; `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` */ (MathError err0, uint numerator) = mulUInt(expScale, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return getExp(numerator, divisor.mantissa); } /** * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. */ function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) { (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(fraction)); } /** * @dev Multiplies two exponentials, returning a new exponential. */ function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } // We add half the scale before dividing so that we get rounding instead of truncation. // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. assert(err2 == MathError.NO_ERROR); return (MathError.NO_ERROR, Exp({mantissa: product})); } /** * @dev Multiplies two exponentials given their mantissas, returning a new exponential. */ function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) { return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); } /** * @dev Multiplies three exponentials, returning a new exponential. */ function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) { (MathError err, Exp memory ab) = mulExp(a, b); if (err != MathError.NO_ERROR) { return (err, ab); } return mulExp(ab, c); } /** * @dev Divides two exponentials, returning a new exponential. * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) */ function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { return getExp(a.mantissa, b.mantissa); } }
pragma solidity ^0.5.16; /** * @title Exponential module for storing fixed-precision decimals * @author Compound * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: * `Exp({mantissa: 5100000000000000000})`. */ contract ExponentialNoError { uint constant expScale = 1e18; uint constant doubleScale = 1e36; uint constant halfExpScale = expScale/2; uint constant mantissaOne = expScale; struct Exp { uint mantissa; } struct Double { uint mantissa; } /** * @dev Truncates the given exp to a whole number value. * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 */ function truncate(Exp memory exp) pure internal returns (uint) { // Note: We are not using careful math here as we're performing a division that cannot fail return exp.mantissa / expScale; } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { Exp memory product = mul_(a, scalar); return truncate(product); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { Exp memory product = mul_(a, scalar); return add_(truncate(product), addend); } /** * @dev Checks if first Exp is less than second Exp. */ function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa < right.mantissa; } /** * @dev Checks if left Exp <= right Exp. */ function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa <= right.mantissa; } /** * @dev Checks if left Exp > right Exp. */ function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa > right.mantissa; } /** * @dev returns true if Exp is exactly zero */ function isZeroExp(Exp memory value) pure internal returns (bool) { return value.mantissa == 0; } function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { require(n < 2**224, errorMessage); return uint224(n); } function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(uint a, uint b) pure internal returns (uint) { return add_(a, b, "addition overflow"); } function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { uint c = a + b; require(c >= a, errorMessage); return c; } function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(uint a, uint b) pure internal returns (uint) { return sub_(a, b, "subtraction underflow"); } function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { require(b <= a, errorMessage); return a - b; } function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); } function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Exp memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / expScale; } function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); } function mul_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Double memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / doubleScale; } function mul_(uint a, uint b) pure internal returns (uint) { return mul_(a, b, "multiplication overflow"); } function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { if (a == 0 || b == 0) { return 0; } uint c = a * b; require(c / a == b, errorMessage); return c; } function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); } function div_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Exp memory b) pure internal returns (uint) { return div_(mul_(a, expScale), b.mantissa); } function div_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); } function div_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Double memory b) pure internal returns (uint) { return div_(mul_(a, doubleScale), b.mantissa); } function div_(uint a, uint b) pure internal returns (uint) { return div_(a, b, "divide by zero"); } function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { require(b > 0, errorMessage); return a / b; } function fraction(uint a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a, doubleScale), b)}); } }
pragma solidity ^0.5.16; /** * @title Compound's InterestRateModel Interface * @author Compound */ contract InterestRateModel { /// @notice Indicator that this is an InterestRateModel contract (for inspection) bool public constant isInterestRateModel = true; /** * @notice Calculates the current borrow interest rate per block * @param cash The total amount of cash the market has * @param borrows The total amount of borrows the market has outstanding * @param reserves The total amount of reserves the market has * @return The borrow rate per block (as a percentage, and scaled by 1e18) */ function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint); /** * @notice Calculates the current supply interest rate per block * @param cash The total amount of cash the market has * @param borrows The total amount of borrows the market has outstanding * @param reserves The total amount of reserves the market has * @param reserveFactorMantissa The current reserve factor the market has * @return The supply rate per block (as a percentage, and scaled by 1e18) */ function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint); }
pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
pragma solidity ^0.5.0; import "../math/ZSafeMath.sol"; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath} * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using ZSafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { // The {SafeMath} overflow check can be skipped here, see the comment at the top counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } }
pragma solidity ^0.5.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } }
pragma solidity ^0.5.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library ZSafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
pragma solidity ^0.5.0; import "../../GSN/Context.sol"; import "./IERC20.sol"; import "../../math/ZSafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using ZSafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; constructor(string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } }
pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
pragma solidity ^0.5.0; import "../../GSN/Context.sol"; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "../../math/ZSafeMath.sol"; import "../../utils/Address.sol"; import "../../drafts/Counters.sol"; import "../../introspection/ERC165.sol"; /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract ERC721 is Context, ERC165, IERC721 { using ZSafeMath for uint256; using Address for address; using Counters for Counters.Counter; // Token name string private _name; // Token symbol string private _symbol; // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; // Mapping from token ID to owner mapping (uint256 => address) private _tokenOwner; // Mapping from token ID to approved address mapping (uint256 => address) private _tokenApprovals; // Mapping from owner to number of owned token mapping (address => Counters.Counter) private _ownedTokensCount; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) private _operatorApprovals; /* * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde * * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ * 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd */ bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; constructor(string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(_INTERFACE_ID_ERC721); } /** * @dev Gets the balance of the specified address. * @param owner address to query the balance of * @return uint256 representing the amount owned by the passed address */ function balanceOf(address owner) public view returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _ownedTokensCount[owner].current(); } /** * @dev Gets the owner of the specified token ID. * @param tokenId uint256 ID of the token to query the owner of * @return address currently marked as the owner of the given token ID */ function ownerOf(uint256 tokenId) public view returns (address) { address owner = _tokenOwner[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev Approves another address to transfer the given token ID * The zero address indicates there is no approved address. * There can only be one approved address per token at a given time. * Can only be called by the token owner or an approved operator. * @param to address to be approved for the given token ID * @param tokenId uint256 ID of the token to be approved */ function approve(address to, uint256 tokenId) public { address owner = ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _tokenApprovals[tokenId] = to; emit Approval(owner, to, tokenId); } /** * @dev Gets the approved address for a token ID, or zero if no address set * Reverts if the token ID does not exist. * @param tokenId uint256 ID of the token to query the approval of * @return address currently approved for the given token ID */ function getApproved(uint256 tokenId) public view returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev Sets or unsets the approval of a given operator * An operator is allowed to transfer all tokens of the sender on their behalf. * @param to operator address to set the approval * @param approved representing the status of the approval to be set */ function setApprovalForAll(address to, bool approved) public { require(to != _msgSender(), "ERC721: approve to caller"); _operatorApprovals[_msgSender()][to] = approved; emit ApprovalForAll(_msgSender(), to, approved); } /** * @dev Tells whether an operator is approved by a given owner. * @param owner owner address which you want to query the approval of * @param operator operator address which you want to query the approval of * @return bool whether the given operator is approved by the given owner */ function isApprovedForAll(address owner, address operator) public view returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev Transfers the ownership of a given token ID to another address. * Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * Requires the msg.sender to be the owner, approved, or operator. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function transferFrom(address from, address to, uint256 tokenId) public { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transferFrom(from, to, tokenId); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received}, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the msg.sender to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function safeTransferFrom(address from, address to, uint256 tokenId) public { safeTransferFrom(from, to, tokenId, ""); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received}, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the _msgSender() to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransferFrom(from, to, tokenId, _data); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the msg.sender to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal { _transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether the specified token exists. * @param tokenId uint256 ID of the token to query the existence of * @return bool whether the token exists */ function _exists(uint256 tokenId) internal view returns (bool) { address owner = _tokenOwner[tokenId]; return owner != address(0); } /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Internal function to safely mint a new token. * Reverts if the given token ID already exists. * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * @param to The address that will own the minted token * @param tokenId uint256 ID of the token to be minted */ function _safeMint(address to, uint256 tokenId) internal { _safeMint(to, tokenId, ""); } /** * @dev Internal function to safely mint a new token. * Reverts if the given token ID already exists. * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * @param to The address that will own the minted token * @param tokenId uint256 ID of the token to be minted * @param _data bytes data to send along with a safe transfer check */ function _safeMint(address to, uint256 tokenId, bytes memory _data) internal { _mint(to, tokenId); require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Internal function to mint a new token. * Reverts if the given token ID already exists. * @param to The address that will own the minted token * @param tokenId uint256 ID of the token to be minted */ function _mint(address to, uint256 tokenId) internal { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _tokenOwner[tokenId] = to; _ownedTokensCount[to].increment(); emit Transfer(address(0), to, tokenId); } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * Deprecated, use {_burn} instead. * @param owner owner of the token to burn * @param tokenId uint256 ID of the token being burned */ function _burn(address owner, uint256 tokenId) internal { require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own"); _clearApproval(tokenId); _ownedTokensCount[owner].decrement(); _tokenOwner[tokenId] = address(0); emit Transfer(owner, address(0), tokenId); } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * @param tokenId uint256 ID of the token being burned */ function _burn(uint256 tokenId) internal { _burn(ownerOf(tokenId), tokenId); } /** * @dev Internal function to transfer ownership of a given token ID to another address. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function _transferFrom(address from, address to, uint256 tokenId) internal { require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); _clearApproval(tokenId); _ownedTokensCount[from].decrement(); _ownedTokensCount[to].increment(); _tokenOwner[tokenId] = to; emit Transfer(from, to, tokenId); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * This is an internal detail of the `ERC721` contract and its use is deprecated. * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) internal returns (bool) { if (!to.isContract()) { return true; } // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = to.call(abi.encodeWithSelector( IERC721Receiver(to).onERC721Received.selector, _msgSender(), from, tokenId, _data )); if (!success) { if (returndata.length > 0) { // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert("ERC721: transfer to non ERC721Receiver implementer"); } } else { bytes4 retval = abi.decode(returndata, (bytes4)); return (retval == _ERC721_RECEIVED); } } /** * @dev Private function to clear current approval of a given token ID. * @param tokenId uint256 ID of the token to be transferred */ function _clearApproval(uint256 tokenId) private { if (_tokenApprovals[tokenId] != address(0)) { _tokenApprovals[tokenId] = address(0); } } }
pragma solidity ^0.5.0; import "../../introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ contract IERC721 is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of NFTs in `owner`'s account. */ function balanceOf(address owner) public view returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ function ownerOf(uint256 tokenId) public view returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * * * Requirements: * - `from`, `to` cannot be zero. * - `tokenId` must be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this * NFT by either {approve} or {setApprovalForAll}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * Requirements: * - If the caller is not `from`, it must be approved to move this NFT by * either {approve} or {setApprovalForAll}. */ function transferFrom(address from, address to, uint256 tokenId) public; function approve(address to, uint256 tokenId) public; function getApproved(uint256 tokenId) public view returns (address operator); function setApprovalForAll(address operator, bool _approved) public; function isApprovedForAll(address owner, address operator) public view returns (bool); function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; }
pragma solidity ^0.5.0; import "./IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ contract IERC721Metadata is IERC721 { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 tokenId) external view returns (string memory); }
pragma solidity ^0.5.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ contract IERC721Receiver { /** * @notice Handle the receipt of an NFT * @dev The ERC721 smart contract calls this function on the recipient * after a {IERC721-safeTransferFrom}. This function MUST return the function selector, * otherwise the caller will revert the transaction. The selector to be * returned can be obtained as `this.onERC721Received.selector`. This * function MAY throw to revert and reject the transfer. * Note: the ERC721 contract address is always the message sender. * @param operator The address which called `safeTransferFrom` function * @param from The address which previously owned the token * @param tokenId The NFT identifier which is being transferred * @param data Additional data with no specified format * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4); }
pragma solidity ^0.5.5; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } }
{ "remappings": [], "optimizer": { "enabled": true, "runs": 500 }, "evmVersion": "istanbul", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"ContributorMmoSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"mmoDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mmoBorrowIndex","type":"uint256"}],"name":"DistributedBorrowerMmo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":true,"internalType":"address","name":"supplier","type":"address"},{"indexed":false,"internalType":"uint256","name":"mmoDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"MmoSupplyIndex","type":"uint256"}],"name":"DistributedSupplierMmo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"MarketListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"MmoGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"MmoSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"newBorrowCap","type":"uint256"}],"name":"NewBorrowCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldBorrowCapGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"NewBorrowCapGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCloseFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"NewCloseFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"oldCollateralFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"NewCollateralFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidationIncentiveMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"NewLiquidationIncentive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxAssets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxAssets","type":"uint256"}],"name":"NewMaxAssets","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPauseGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"NewPauseGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract PriceOracle","name":"oldPriceOracle","type":"address"},{"indexed":false,"internalType":"contract PriceOracle","name":"newPriceOracle","type":"address"}],"name":"NewPriceOracle","type":"event"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"_grantMmo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"_setCollateralFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"contributor","type":"address"},{"internalType":"uint256","name":"mmoSpeed","type":"uint256"}],"name":"_setContributorMmoSpeed","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"uint256","name":"mmoSpeed","type":"uint256"}],"name":"_setMmoSpeed","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountAssets","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allMarkets","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"allMarketsIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allMarketsSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"enum MTokenIdentifier.MTokenType","name":"mTokenType","type":"uint8"},{"internalType":"uint72","name":"mTokenSeqNr","type":"uint72"},{"internalType":"address","name":"mTokenAddress","type":"address"}],"name":"assembleToken","outputs":[{"internalType":"uint240","name":"mToken","type":"uint240"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"bidder","type":"address"}],"name":"auctionAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"auctionGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowCapGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"borrowCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowVerify","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint240[]","name":"mTokens","type":"uint240[]"}],"name":"claimMmo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"holders","type":"address[]"},{"internalType":"uint240[]","name":"mTokens","type":"uint240[]"},{"internalType":"bool","name":"borrowers","type":"bool"},{"internalType":"bool","name":"suppliers","type":"bool"}],"name":"claimMmo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"closeFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"collateralFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"owner","type":"address"}],"name":"enterMarketOnBehalf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240[]","name":"mTokens","type":"uint240[]"}],"name":"enterMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"exitMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"owner","type":"address"}],"name":"exitMarketOnBehalf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAdmin","outputs":[{"internalType":"address payable","name":"admin","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"mTokenContract","type":"address"}],"name":"getAnchorToken","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAssetsIn","outputs":[{"internalType":"uint240[]","name":"","type":"uint240[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint240","name":"mTokenModify","type":"uint240"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"getHypotheticalAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMmoAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTokenType","outputs":[{"internalType":"enum MTokenIdentifier.MTokenType","name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"implementedSelectors","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementedSelectorsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isMDelegatorUserImplementation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastContributorBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mTokenBorrowed","type":"uint240"},{"internalType":"uint240","name":"mTokenCollateral","type":"uint240"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mTokenBorrowed","type":"uint240"},{"internalType":"uint240","name":"mTokenCollateral","type":"uint240"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"liquidateBorrowVerify","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mTokenBorrowed","type":"uint240"},{"internalType":"uint240","name":"mTokenCollateral","type":"uint240"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateCalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"liquidateERC721Allowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"liquidationIncentiveMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"markets","outputs":[{"internalType":"bool","name":"_isListed","type":"bool"},{"internalType":"uint256","name":"_collateralFactorMantissa","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mintAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"actualMintAmount","type":"uint256"},{"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"mintVerify","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mmoAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"mmoBorrowState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"},{"internalType":"address","name":"","type":"address"}],"name":"mmoBorrowerIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mmoContributorSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mmoInitialIndex","outputs":[{"internalType":"uint224","name":"","type":"uint224"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"mmoSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"},{"internalType":"address","name":"","type":"address"}],"name":"mmoSupplierIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"mmoSupplyState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"contract PriceOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"parseToken","outputs":[{"internalType":"enum MTokenIdentifier.MTokenType","name":"mTokenType","type":"uint8"},{"internalType":"uint72","name":"mTokenSeqNr","type":"uint72"},{"internalType":"address","name":"mTokenAddress","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"pauseGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemVerify","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"borrowerIndex","type":"uint256"}],"name":"repayBorrowVerify","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mTokenCollateral","type":"uint240"},{"internalType":"uint240","name":"mTokenBorrowed","type":"uint240"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"seizeGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mTokenCollateral","type":"uint240"},{"internalType":"uint240","name":"mTokenBorrowed","type":"uint240"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeVerify","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"transferGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferVerify","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"underlyingContractETH","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"updateContributorRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061579a80620000216000396000f3fe608060405234801561001057600080fd5b506004361061041d5760003560e01c806380b6d4f01161022b578063ca0b57b311610130578063e87a22aa116100b8578063f2e6a94811610087578063f2e6a94814611239578063fa1a717314611265578063fac3da101461128b578063fcab1819146112cb578063fe54bce3146112f75761041d565b8063e87a22aa146111a4578063efc95b28146111df578063f0193f95146111e7578063f22e84ee146112135761041d565b8063d837909c116100ff578063d837909c146110da578063dce1544914611100578063df83bb551461112c578063e191aceb14611161578063e87554461461119c5761041d565b8063ca0b57b314610fb4578063d149d64314611009578063d4978c721461104e578063d4a9b745146110995761041d565b8063a4484b00116101b3578063be10069811610182578063be10069814610ec3578063bea6b8b814610f08578063c03e35e114610f2e578063c466544914610f54578063c86d3ee614610f8e5761041d565b8063a4484b0014610c2b578063a512ae7d14610c7a578063abfceffc14610d6d578063b817c41a14610d935761041d565b806386cfa66b116101fa57806386cfa66b14610b705780639070f91a14610b9657806391a5f17f14610bd157806394b2294b14610bfd578063998dd3ca14610c055761041d565b806380b6d4f014610aae578063828c4bf314610ae3578063840910f214610b09578063866bb10214610b2f5761041d565b8063534ce5a11161033157806370670422116102b957806377ed1dad1161028857806377ed1dad1461099c5780637b6889b7146109dd5780637d6b652b14610a225780637dc0d1d014610a715780638007c97214610a795761041d565b80637067042214610922578063715e31ca146109485780637323d1f41461096e578063741b2525146109765761041d565b80635f41b85d116103005780635f41b85d1461084f57806363d69e6514610857578063664305f0146108c357806366728b0c146109125780636e9960c31461091a5761041d565b8063534ce5a114610764578063548b6598146107995780635a638fbe146107e75780635ec88c791461080b5761041d565b806324a3d622116103b45780633a99d448116103835780633a99d448146106ed5780633ce7d72c1461071357806342cbb15c1461071b5780634ada90af1461072357806352d84d1e1461072b5761041d565b806324a3d6221461062f5780633228fc9c1461063757806339291dd11461065d5780633984938c1461069e5761041d565b8063126b19df116103f0578063126b19df146105615780631f530b2a146105aa5780632197597b146105e557806321af45691461060b5761041d565b80630583e1db1461042257806309f291171461045a5780630bff4ef5146104805780630decf9d9146104ae575b600080fd5b6104486004803603602081101561043857600080fd5b50356001600160f01b031661132c565b60408051918252519081900360200190f35b6104486004803603602081101561047057600080fd5b50356001600160f01b0316611485565b6104ac6004803603604081101561049657600080fd5b506001600160a01b0381351690602001356115b4565b005b6104ac600480360360408110156104c457600080fd5b6001600160a01b0382351691908101906040810160208201356401000000008111156104ef57600080fd5b82018360208201111561050157600080fd5b8035906020019184602083028401116401000000008311171561052357600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506116c3945050505050565b6105966004803603604081101561057757600080fd5b5080356001600160a01b031690602001356001600160f01b0316611725565b604080519115158252519081900360200190f35b6104ac600480360360608110156105c057600080fd5b506001600160f01b03813516906001600160a01b036020820135169060400135611720565b610448600480360360208110156105fb57600080fd5b50356001600160a01b031661173a565b61061361174c565b604080516001600160a01b039092168252519081900360200190f35b61061361175b565b6104486004803603602081101561064d57600080fd5b50356001600160f01b031661176a565b6104ac6004803603608081101561067357600080fd5b506001600160f01b03813516906001600160a01b03602082013516906040810135906060013561177c565b6106d4600480360360608110156106b457600080fd5b506001600160f01b038135811691602081013590911690604001356117e2565b6040805192835260208301919091528051918290030190f35b6105966004803603602081101561070357600080fd5b50356001600160f01b0316611981565b610448611996565b61044861199d565b6104486119a1565b6107486004803603602081101561074157600080fd5b50356119a7565b604080516001600160f01b039092168252519081900360200190f35b6104486004803603604081101561077a57600080fd5b5080356001600160f01b031690602001356001600160a01b03166119c2565b6107bf600480360360208110156107af57600080fd5b50356001600160f01b0316611b7e565b604080516001600160e01b03909316835263ffffffff90911660208301528051918290030190f35b6107ef611ba8565b604080516001600160e01b039092168252519081900360200190f35b6108316004803603602081101561082157600080fd5b50356001600160a01b0316611bbb565b60408051938452602084019290925282820152519081900360600190f35b610596611bf0565b61087d6004803603602081101561086d57600080fd5b50356001600160f01b0316611bf5565b6040518084600281111561088d57fe5b60ff16815268ffffffffffffffffff9093166020840152506001600160a01b031660408083019190915251908190036060019150f35b610448600480360360a08110156108d957600080fd5b506001600160f01b0381358116916020810135909116906001600160a01b03604082013581169160608101359091169060800135611dce565b61061361200a565b610613612019565b6107486004803603602081101561093857600080fd5b50356001600160a01b031661203c565b6104486004803603602081101561095e57600080fd5b50356001600160f01b03166120ae565b6106136120c0565b6104ac6004803603602081101561098c57600080fd5b50356001600160a01b03166120c6565b610831600480360360808110156109b257600080fd5b506001600160a01b03813516906001600160f01b036020820135169060408101359060600135612189565b610448600480360360808110156109f357600080fd5b506001600160f01b03813516906001600160a01b036020820135811691604081013590911690606001356121c3565b610448600480360360a0811015610a3857600080fd5b506001600160f01b0381358116916020810135909116906001600160a01b036040820135811691606081013590911690608001356122c3565b610613612485565b61044860048036036040811015610a8f57600080fd5b5080356001600160f01b031690602001356001600160a01b0316612494565b61044860048036036040811015610ac457600080fd5b5080356001600160f01b031690602001356001600160a01b03166124b1565b61059660048036036020811015610af957600080fd5b50356001600160f01b031661251d565b61059660048036036020811015610b1f57600080fd5b50356001600160f01b0316612532565b610b5560048036036020811015610b4557600080fd5b50356001600160f01b0316612547565b60408051921515835260208301919091528051918290030190f35b6107bf60048036036020811015610b8657600080fd5b50356001600160f01b0316612566565b61044860048036036060811015610bac57600080fd5b506001600160f01b03813516906001600160a01b036020820135169060400135612590565b6104ac60048036036040811015610be757600080fd5b506001600160f01b038135169060200135612860565b6104486128db565b61044860048036036020811015610c1b57600080fd5b50356001600160f01b03166128e1565b6104ac600480360360a0811015610c4157600080fd5b506001600160f01b0381358116916020810135909116906001600160a01b036040820135811691606081013590911690608001356128f3565b610d1d60048036036020811015610c9057600080fd5b810190602081018135640100000000811115610cab57600080fd5b820183602082011115610cbd57600080fd5b80359060200191846020830284011164010000000083111715610cdf57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506128fa945050505050565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610d59578181015183820152602001610d41565b505050509050019250505060405180910390f35b610d1d60048036036020811015610d8357600080fd5b50356001600160a01b031661298b565b6104ac60048036036080811015610da957600080fd5b810190602081018135640100000000811115610dc457600080fd5b820183602082011115610dd657600080fd5b80359060200191846020830284011164010000000083111715610df857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610e4857600080fd5b820183602082011115610e5a57600080fd5b80359060200191846020830284011164010000000083111715610e7c57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550505050803515159150602001351515612a14565b6104ac60048036036080811015610ed957600080fd5b506001600160f01b03813516906001600160a01b036020820135811691604081013590911690606001356117dc565b61044860048036036020811015610f1e57600080fd5b50356001600160a01b0316612cb9565b61044860048036036020811015610f4457600080fd5b50356001600160a01b0316612ccb565b610f7160048036036020811015610f6a57600080fd5b5035612cdd565b604080516001600160e01b03199092168252519081900360200190f35b61044860048036036020811015610fa457600080fd5b50356001600160f01b0316612d11565b6104ac600480360360c0811015610fca57600080fd5b506001600160f01b0381358116916020810135909116906001600160a01b03604082013581169160608101359091169060808101359060a00135612d1d565b6104486004803603608081101561101f57600080fd5b506001600160f01b03813516906001600160a01b03602082013581169160408101359091169060600135612d25565b6104ac600480360360a081101561106457600080fd5b506001600160f01b03813516906001600160a01b036020820135811691604081013590911690606081013590608001356128f3565b6104ac600480360360808110156110af57600080fd5b506001600160f01b03813516906001600160a01b0360208201351690604081013590606001356117dc565b610596600480360360208110156110f057600080fd5b50356001600160f01b0316612d3c565b6107486004803603604081101561111657600080fd5b506001600160a01b038135169060200135612d51565b6104486004803603604081101561114257600080fd5b5080356001600160f01b031690602001356001600160a01b0316612d86565b6104486004803603606081101561117757600080fd5b506001600160f01b03813516906001600160a01b036020820135169060400135612de7565b610448612e04565b610448600480360360608110156111ba57600080fd5b506001600160f01b03813516906001600160a01b036020820135169060400135612e0a565b610448613077565b6104ac600480360360408110156111fd57600080fd5b506001600160a01b03813516906020013561307d565b6105966004803603602081101561122957600080fd5b50356001600160f01b0316613194565b6104486004803603604081101561124f57600080fd5b506001600160f01b0381351690602001356131a9565b6104486004803603602081101561127b57600080fd5b50356001600160f01b03166131e8565b610748600480360360608110156112a157600080fd5b50803560ff1690602081013568ffffffffffffffffff1690604001356001600160a01b0316613461565b6112d36134b8565b604051808260028111156112e357fe5b60ff16815260200191505060405180910390f35b6104486004803603604081101561130d57600080fd5b5080356001600160f01b031690602001356001600160a01b03166134bd565b600080600061133a84611bf5565b9193509091506002905082600281111561135057fe5b146113615760125b92505050611480565b61136a846134da565b611375576009611358565b6000816001600160a01b0316636352211e866040518263ffffffff1660e01b815260040180826001600160f01b0316815260200191505060206040518083038186803b1580156113c457600080fd5b505afa1580156113d8573d6000803e3d6000fd5b505050506040513d60208110156113ee57600080fd5b505190506113fc8582613531565b61140d5760085b9350505050611480565b600061141986336119c2565b9050801561142c57935061148092505050565b600061143783611bbb565b919350909150508115158061144a575080155b1561145e5760035b95505050505050611480565b336001600160a01b0384161415611476576001611452565b6000955050505050505b919050565b6000611490826134da565b6114d5576040805162461bcd60e51b81526020600482015260116024820152701b551bdad95b881b9bdd081b1a5cdd1959607a1b604482015290519081900360640190fd5b60006114e08361356a565b6001600160f01b0381166000908152600960205260409020600101549091508061150f57600092505050611480565b816001600160f01b0316846001600160f01b031614611550576001600160f01b038416600090815260096020526040902060010154801561154e578091505b505b670c7d713b49da00008111156115ad576040805162461bcd60e51b815260206004820152601a60248201527f636f6c6c61746572616c20666163746f7220746f6f2068696768000000000000604482015290519081900360640190fd5b9392505050565b6115bc612019565b6001600160a01b0316336001600160a01b031614611621576040805162461bcd60e51b815260206004820152601c60248201527f6f6e6c792061646d696e2063616e20736574206d6d6f20737065656400000000604482015290519081900360640190fd5b61162a826120c6565b8061164d576001600160a01b0382166000908152601a602052604081205561166f565b61165561199d565b6001600160a01b0383166000908152601a60205260409020555b6001600160a01b038216600081815260196020908152604091829020849055815184815291517fae3a17f08499cb0a69892e0bdf8867c64c7459e0e787049b2fc28b4695922d7d9281900390910190a25050565b6040805160018082528183019092526060916020808301908038833901905050905082816000815181106116f357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506117208183600180612a14565b505050565b60006117318284613531565b90505b92915050565b60196020526000908152604090205481565b6006546001600160a01b031681565b6007546001600160a01b031681565b600f6020526000908152604090205481565b8015801561178a5750600082115b156117dc576040805162461bcd60e51b815260206004820152601160248201527f72656465656d546f6b656e73207a65726f000000000000000000000000000000604482015290519081900360640190fd5b50505050565b6000806117ee856134da565b158061180057506117fe846134da565b155b156118115750600990506000611979565b600061181c866131e8565b90506000611829866131e8565b9050811580611836575080155b1561184b57600d935060009250611979915050565b600061185687611bf5565b925050506000816001600160a01b031663458f1022896040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b1580156118b257600080fd5b505afa1580156118c6573d6000803e3d6000fd5b505050506040513d60208110156118dc57600080fd5b5051905060006118ea6155f6565b6118f26155f6565b6118fa6155f6565b611922604051806020016040528060045481525060405180602001604052808b81525061358d565b925061192e838c6135cc565b915061195660405180602001604052808981525060405180602001604052808881525061358d565b905061196a61196583836135f6565b613629565b60009a50985050505050505050505b935093915050565b600c6020526000908152604090205460ff1681565b6000545b90565b4390565b60045481565b6010602052600090815260409020546001600160f01b031681565b600080806119cf85611bf5565b9250509150600a60006119e18761356a565b6001600160f01b0316815260208101919091526040016000205460ff1615611a44576040805162461bcd60e51b8152602060048201526011602482015270185d58dd1a5bdb881a5cc81c185d5cd959607a1b604482015290519081900360640190fd5b6001600160f01b0385166000908152600a602052604090205460ff1615611aa6576040805162461bcd60e51b8152602060048201526011602482015270185d58dd1a5bdb881a5cc81c185d5cd959607a1b604482015290519081900360640190fd5b611aaf856134da565b611abf5760095b92505050611734565b6002826002811115611acd57fe5b14611ad9576009611ab6565b60006001600160a01b0316816001600160a01b0316636352211e876040518263ffffffff1660e01b815260040180826001600160f01b0316815260200191505060206040518083038186803b158015611b3157600080fd5b505afa158015611b45573d6000803e3d6000fd5b505050506040513d6020811015611b5b57600080fd5b50516001600160a01b03161415611b73576009611ab6565b600095945050505050565b6015602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b6ec097ce7bc90715b34b9f100000000081565b600080600080600080611bd2876000806000613638565b925092509250826012811115611be457fe5b97919650945092505050565b600190565b600069ffffffffffffffffffff60a083901c1682601081901b80841a6002811115611c1c57fe5b9350816001600160a01b031663fcab18196040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5757600080fd5b505afa158015611c6b573d6000803e3d6000fd5b505050506040513d6020811015611c8157600080fd5b50516002811115611c8e57fe5b846002811115611c9a57fe5b14611cec576040805162461bcd60e51b815260206004820152601360248201527f496e76616c6964206d546f6b656e207479706500000000000000000000000000604482015290519081900360640190fd5b6001846002811115611cfa57fe5b1415611d665760018368ffffffffffffffffff161115611d61576040805162461bcd60e51b815260206004820181905260248201527f496e76616c6964207365714e7220666f722066756e6769626c6520746f6b656e604482015290519081900360640190fd5b611dc6565b6002846002811115611d7457fe5b14611dc6576040805162461bcd60e51b815260206004820152601360248201527f556e6b6e6f776e206d546f6b656e207479706500000000000000000000000000604482015290519081900360640190fd5b509193909250565b600080611dda87611bf5565b925050506000611de987611bf5565b92505050600e6000611dfa8a61356a565b6001600160f01b0316815260208101919091526040016000205460ff1615611e5b576040805162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b604482015290519081900360640190fd5b6001600160f01b0388166000908152600e602052604090205460ff1615611ebb576040805162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b604482015290519081900360640190fd5b611ec4886134da565b1580611ed65750611ed4876134da565b155b15611ee75760095b92505050612001565b611ef18786613531565b1580611f045750611f028886613531565b155b15611f10576008611ede565b806001600160a01b03166344c09b106040518163ffffffff1660e01b815260040160206040518083038186803b158015611f4957600080fd5b505afa158015611f5d573d6000803e3d6000fd5b505050506040513d6020811015611f7357600080fd5b50516040805163044c09b160e41b815290516001600160a01b03928316928516916344c09b10916004808301926020929190829003018186803b158015611fb957600080fd5b505afa158015611fcd573d6000803e3d6000fd5b505050506040513d6020811015611fe357600080fd5b50516001600160a01b031614611ffa576002611ede565b6000925050505b95945050505050565b6001546001600160a01b031690565b600080604051808061571960289139604051908190036028019020549392505050565b6000611734826001600160a01b031663fcab18196040518163ffffffff1660e01b815260040160206040518083038186803b15801561207a57600080fd5b505afa15801561208e573d6000803e3d6000fd5b505050506040513d60208110156120a457600080fd5b5051600084613461565b60136020526000908152604090205481565b60001990565b6001600160a01b038116600090815260196020526040812054906120e861199d565b6001600160a01b0384166000908152601a60205260408120549192509061211090839061392b565b90506000811180156121225750600083115b156117dc576000612133828561396d565b6001600160a01b0386166000908152601860205260408120549192509061215a90836139af565b6001600160a01b038716600090815260186020908152604080832093909355601a905220849055505050505050565b60008060008060008061219e8a8a8a8a613638565b9250925092508260128111156121b057fe5b95509093509150505b9450945094915050565b6000600d60006121d28761356a565b6001600160f01b0316815260208101919091526040016000205460ff1615612236576040805162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160f01b0385166000908152600d602052604090205460ff1615612299576040805162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b604482015290519081900360640190fd5b60006122a68686856139f1565b905080156122b55790506122bb565b60009150505b949350505050565b6000806122cf86611bf5565b50909150600290508160028111156122e357fe5b14156122f45760125b915050612001565b6122fd876134da565b158061230f575061230d866134da565b155b1561231b5760096122ec565b6123258785613531565b158061233857506123368685613531565b155b156123445760086122ec565b60008061235086613a78565b9193509091506000905082601281111561236657fe5b146123815781601281111561237757fe5b9350505050612001565b8061238d576003612377565b60006123988a611bf5565b925050506000816001600160a01b031663e48695fa898d6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160f01b03166001600160f01b031681526020019250505060206040518083038186803b15801561240e57600080fd5b505afa158015612422573d6000803e3d6000fd5b505050506040513d602081101561243857600080fd5b50516040805160208101909152600354815290915060009061245a9083613a98565b9050808811156124735760119650505050505050612001565b60009c9b505050505050505050505050565b6002546001600160a01b031681565b601660209081526000928352604080842090915290825290205481565b6000806124bd84611bf5565b925050506001600160a01b03811633146125085760405162461bcd60e51b81526004018080602001828103825260358152602001806156e46035913960400191505060405180910390fd5b6125128484613ab7565b60128111156122bb57fe5b600b6020526000908152604090205460ff1681565b600e6020526000908152604090205460ff1681565b6009602052600090815260409020805460019091015460ff9091169082565b6014602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b60008061259c85611bf5565b92505050600c60006125ad8761356a565b6001600160f01b0316815260208101919091526040016000205460ff161561260f576040805162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6001600160f01b0385166000908152600c602052604090205460ff1615612670576040805162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b604482015290519081900360640190fd5b612679856134da565b6126885760095b9150506115ad565b6126928585613531565b61269d576008612680565b6126a6856131e8565b6126b157600d612680565b6000600f60006126c08861356a565b6001600160f01b0390811682526020808301939093526040918201600090812054918a168152600f9093529120549091508115806127075750801580159061270757508181105b15612710578091505b8115612801576000836001600160a01b0316635a874303896040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b15801561276e57600080fd5b505afa158015612782573d6000803e3d6000fd5b505050506040513d602081101561279857600080fd5b5051905060006127a882886139af565b90508381106127fe576040805162461bcd60e51b815260206004820152601960248201527f6d61726b657420626f72726f7720636170207265616368656400000000000000604482015290519081900360640190fd5b50505b600080612811888a60008a613638565b9193509091506000905082601281111561282757fe5b146128445781601281111561283857fe5b955050505050506115ad565b8015612851576004612838565b50600098975050505050505050565b612868612019565b6001600160a01b0316336001600160a01b0316146128cd576040805162461bcd60e51b815260206004820152601c60248201527f6f6e6c792061646d696e2063616e20736574206d6d6f20737065656400000000604482015290519081900360640190fd5b6128d78282613bbb565b5050565b60055481565b60116020526000908152604090205481565b5050505050565b606060008251905060608160405190808252806020026020018201604052801561292e578160200160208202803883390190505b50905060005b828110156129835761295985828151811061294b57fe5b602002602001015133613ab7565b601281111561296457fe5b82828151811061297057fe5b6020908102919091010152600101612934565b509392505050565b60608060086000846001600160a01b03166001600160a01b03168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015612a0757602002820191906000526020600020905b81546001600160f01b031681526001909101906020018083116129e9575b5093979650505050505050565b60005b83518110156128f3576000848281518110612a2e57fe5b60200260200101519050612a41816134da565b612a92576040805162461bcd60e51b815260206004820152601560248201527f6d61726b6574206d757374206265206c69737465640000000000000000000000604482015290519081900360640190fd5b60018415151415612c0e576000612aa882611bf5565b92505050612ab46155f6565b6040518060200160405280836001600160a01b031663d46e761c866040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b158015612b1557600080fd5b505afa158015612b29573d6000803e3d6000fd5b505050506040513d6020811015612b3f57600080fd5b505190529050612b4f8382613f5f565b60005b8851811015612c0a57612b79848a8381518110612b6b57fe5b602002602001015184614238565b612bce898281518110612b8857fe5b6020026020010151601860008c8581518110612ba057fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054614405565b601860008b8481518110612bde57fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600101612b52565b5050505b60018315151415612cb057612c228161453f565b60005b8651811015612cae57612c4b82888381518110612c3e57fe5b602002602001015161480e565b612c72878281518110612c5a57fe5b6020026020010151601860008a8581518110612ba057fe5b60186000898481518110612c8257fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600101612c25565b505b50600101612a17565b601a6020526000908152604090205481565b60186020526000908152604090205481565b60008181548110612cea57fe5b9060005260206000209060089182820401919006600402915054906101000a900460e01b81565b60006117348233614a0d565b505050505050565b6000612d30856134da565b611b73575060096122bb565b600d6020526000908152604090205460ff1681565b60086020528160005260406000208181548110612d6a57fe5b6000918252602090912001546001600160f01b03169150829050565b600080612d9284611bf5565b925050506001600160a01b0381163314612ddd5760405162461bcd60e51b81526004018080602001828103825260338152602001806156b16033913960400191505060405180910390fd5b6122bb8484614a0d565b600080612df58585856139f1565b90508015611b735790506115ad565b60035481565b60008080612e1786611bf5565b9250925050806001600160a01b0316630f06a9726040518163ffffffff1660e01b815260040160206040518083038186803b158015612e5557600080fd5b505afa158015612e69573d6000803e3d6000fd5b505050506040513d6020811015612e7f57600080fd5b505168ffffffffffffffffff83161115612ed7576040805162461bcd60e51b815260206004820152601460248201527334b73b30b634b21036aa37b5b2b71029b2b8a73960611b604482015290519081900360640190fd5b336001600160a01b03821614612f34576040805162461bcd60e51b815260206004820152601960248201527f6f6e6c79206d546f6b656e2063616e2063616c6c207468697300000000000000604482015290519081900360640190fd5b6000612f3f8761356a565b6001600160f01b0381166000908152600b602052604090205490915060ff1615612fa1576040805162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b604482015290519081900360640190fd5b6001600160f01b0387166000908152600b602052604090205460ff1615613000576040805162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b604482015290519081900360640190fd5b613009816134da565b61301957600993505050506115ad565b613022876134da565b61306a57600061303188614d63565b905080156130445793506115ad92505050565b61304d886131e8565b6130685761305d600d6009614fd8565b9450505050506115ad565b505b6000979650505050505050565b60125481565b613085612019565b6001600160a01b0316336001600160a01b0316146130ea576040805162461bcd60e51b815260206004820152601860248201527f6f6e6c792061646d696e2063616e206772616e74206d6d6f0000000000000000604482015290519081900360640190fd5b60006130f68383614405565b9050801561314b576040805162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e74206d6d6f20666f72206772616e74000000000000604482015290519081900360640190fd5b604080516001600160a01b03851681526020810184905281517f2e99fc57d866b27ce07b96c6a6399762e10030d95faee941c25a4997bc49ec00929181900390910190a1505050565b600a6020526000908152604090205460ff1681565b60006131b3612019565b6001600160a01b0316336001600160a01b0316146131de576131d760016006614fd8565b9050611734565b611731838361503e565b60006131f38261356a565b6001600160f01b0316826001600160f01b03161415613259576040805162461bcd60e51b815260206004820152601c60248201527f6e6f20676574507269636520666f7220616e63686f7220746f6b656e00000000604482015290519081900360640190fd5b613262826134da565b6132a7576040805162461bcd60e51b81526020600482015260116024820152701b551bdad95b881b9bdd081b1a5cdd1959607a1b604482015290519081900360640190fd5b60006132b283611bf5565b925050506000816001600160a01b03166310cfe9066040518163ffffffff1660e01b815260040160206040518083038186803b1580156132f157600080fd5b505afa158015613305573d6000803e3d6000fd5b505050506040513d602081101561331b57600080fd5b505190506133276120c0565b6001600160a01b0316816001600160a01b0316141561335257670de0b6b3a764000092505050611480565b6000826001600160a01b0316635553d7b6866040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b1580156133aa57600080fd5b505afa1580156133be573d6000803e3d6000fd5b505050506040513d60208110156133d457600080fd5b505160025460408051634cb973e160e11b81526001600160a01b038681166004830152602482018590529151939450911691639972e7c291604480820192602092909190829003018186803b15801561342c57600080fd5b505afa158015613440573d6000803e3d6000fd5b505050506040513d602081101561345657600080fd5b505195945050505050565b600080604885600281111561347257fe5b69ffffffffffffffffffff60a01b68ffffffffffffffffff871669ffffffffffffffffffff9290921690921b0160a01b166001600160a01b038416019150509392505050565b600090565b601760209081526000928352604080842090915290825290205481565b6000600960006134e98461356a565b6001600160f01b0316815260208101919091526040016000205460ff1661351257506000611480565b506001600160f01b031660009081526009602052604090205460ff1690565b6001600160f01b03821660009081526009602090815260408083206001600160a01b038516845260020190915290205460ff1692915050565b7dff000000000000000000ffffffffffffffffffffffffffffffffffffffff1690565b6135956155f6565b6040518060200160405280670de0b6b3a76400006135bb8660000151866000015161396d565b816135c257fe5b0490529392505050565b6135d46155f6565b60405180602001604052806135ed85600001518561396d565b90529392505050565b6135fe6155f6565b60405180602001604052806135ed6136228660000151670de0b6b3a764000061396d565b855161512a565b51670de0b6b3a7640000900490565b6000806000613645615609565b6001600160a01b038816600090815260086020908152604080832080548251818502810185019093528083526060938301828280156136ad57602002820191906000526020600020905b81546001600160f01b0316815260019091019060200180831161368f575b50939450600093505050505b81518110156138ec5760008282815181106136d057fe5b6020026020010151905060006136e582611bf5565b92505050806001600160a01b031663646fb1b48e846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160f01b03166001600160f01b031681526020019250505060806040518083038186803b15801561375957600080fd5b505afa15801561376d573d6000803e3d6000fd5b505050506040513d608081101561378357600080fd5b508051602082015160408084015160609485015160808c0152938a019390935291880191909152945084156137c95750600f9750600096508695506121b9945050505050565b60405180602001604052806137dd84611485565b905260c087015260408051602081019091526080870151815260e0870152613804826131e8565b60a087018190526138265750600d9750600096508695506121b9945050505050565b604080516020810190915260a0870151815261010087015260c086015160e0870151613860916138559161358d565b87610100015161358d565b61012087018190526040870151875161387a92919061516c565b86526101008601516060870151602088015161389792919061516c565b60208701526001600160f01b03828116908d1614156138e2576138c48661012001518c886020015161516c565b602087018190526101008701516138dc918c9061516c565b60208701525b50506001016136b9565b5060208301518351111561391257505060208101519051600094500391508290506121b9565b50508051602090910151600094508493500390506121b9565b600061173183836040518060400160405280601581526020017f7375627472616374696f6e20756e646572666c6f770000000000000000000000815250615194565b600061173183836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f7700000000000000000081525061522b565b600061173183836040518060400160405280601181526020017f6164646974696f6e206f766572666c6f770000000000000000000000000000008152506152aa565b60006139fc846134da565b613a0a5760095b90506115ad565b613a148484613531565b613a1f576000613a03565b600080613a2f8587866000613638565b91935090915060009050826012811115613a4557fe5b14613a5f57816012811115613a5657fe5b925050506115ad565b8015613a6c576004613a56565b60009695505050505050565b6000806000613a8b846000806000613638565b9250925092509193909250565b6000613aa26155f6565b613aac84846135cc565b90506122bb81613629565b6000613ac2836134da565b613ace57506009611734565b613ad88383613531565b151560011415613aea57506000611734565b6005546001600160a01b03831660009081526008602052604090205410613b1357506010611734565b6001600160f01b03831660008181526009602090815260408083206001600160a01b03871680855260029091018352818420805460ff19166001908117909155600884528285208054918201815585529383902090930180546001600160f01b0319168517905580519384529083019190915280517fb84836f7818d814ca2164a48af216be85ae605b2364af712e17509d96b1bdfcb9281900390910190a150600092915050565b6001600160f01b0382166000908152601360205260409020548015613c9c576000613be584611bf5565b92505050613bf16155f6565b6040518060200160405280836001600160a01b031663d46e761c886040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b158015613c5257600080fd5b505afa158015613c66573d6000803e3d6000fd5b505050506040513d6020811015613c7c57600080fd5b505190529050613c8b8561453f565b613c958582613f5f565b5050613f03565b8115613f0357613cab836134da565b613cfc576040805162461bcd60e51b815260206004820152601860248201527f6d6d6f206d61726b6574206973206e6f74206c69737465640000000000000000604482015290519081900360640190fd5b6001600160f01b0383166000908152601460205260409020546001600160e01b0316158015613d4e57506001600160f01b038316600090815260146020526040902054600160e01b900463ffffffff16155b15613e1d5760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b03168152602001613dc2613d8761199d565b6040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b63ffffffff9081169091526001600160f01b0385166000908152601460209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b6001600160f01b0383166000908152601560205260409020546001600160e01b0316158015613e6f57506001600160f01b038316600090815260156020526040902054600160e01b900463ffffffff16155b15613f035760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b03168152602001613ea8613d8761199d565b63ffffffff9081169091526001600160f01b0385166000908152601560209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b818114611720576001600160f01b038316600081815260136020908152604091829020859055815185815291517f1b6f034636f23dabb8bb7f49c5a29717431fe7ecb6107364c8a1d53c2db8dd929281900390910190a2505050565b6001600160f01b038216600090815260156020908152604080832060139092528220549091613f8c61199d565b8354909150600090613fac908390600160e01b900463ffffffff1661392b565b9050600081118015613fbe5750600083115b156141cc576000613fce87611bf5565b92505050600061405f826001600160a01b0316635a8743038a6040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b15801561402d57600080fd5b505afa158015614041573d6000803e3d6000fd5b505050506040513d602081101561405757600080fd5b50518861535d565b9050600061406d848761396d565b90506140776155f6565b60008311614094576040518060200160405280600081525061409e565b61409e828461537b565b90506140a86155f6565b604080516020810190915289546001600160e01b031681526140ca90836153b0565b9050604051806040016040528061411a83600001516040518060400160405280601a81526020017f6e657720696e64657820657863656564732032323420626974730000000000008152506153d5565b6001600160e01b03168152602001614167896040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b63ffffffff9081169091526001600160f01b038d166000908152601560209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b0319909416939093171691909117905550612d1d9350505050565b8015612d1d57614211826040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b845463ffffffff91909116600160e01b026001600160e01b03909116178455505050505050565b6001600160f01b03831660009081526015602052604090206142586155f6565b50604080516020810190915281546001600160e01b031681526142796155f6565b5060408051602080820183526001600160f01b0388166000908152601782528381206001600160a01b0389168083528184529482208054855286519590925290915291909155805115612d1d576142ce6155f6565b6142d8838361542a565b905060006142e588611bf5565b92505050600061435e826001600160a01b031663e48695fa8a8c6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160f01b03166001600160f01b031681526020019250505060206040518083038186803b15801561402d57600080fd5b9050600061436c828561544f565b6001600160a01b038a166000908152601860205260408120549192509061439390836139af565b6001600160a01b038b166000818152601860209081526040918290208490558a51825187815291820152815193945091926001600160f01b038f16927f4aabcdfa995af92795e2e0edddeb2fa8814eadd55f7a34e422fcf589dd92549c92908290030190a35050505050505050505050565b60008061441061200a565b604080516370a0823160e01b815230600482015290519192506000916001600160a01b038416916370a08231916024808301926020929190829003018186803b15801561445c57600080fd5b505afa158015614470573d6000803e3d6000fd5b505050506040513d602081101561448657600080fd5b5051905083158015906144995750808411155b1561453657816001600160a01b031663a9059cbb86866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156144fe57600080fd5b505af1158015614512573d6000803e3d6000fd5b505050506040513d602081101561452857600080fd5b506000935061173492505050565b50919392505050565b6001600160f01b03811660009081526014602090815260408083206013909252822054909161456c61199d565b835490915060009061458c908390600160e01b900463ffffffff1661392b565b905060008111801561459e5750600083115b156147a35760006145ae86611bf5565b925050506000816001600160a01b03166338c4e18a886040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b15801561460a57600080fd5b505afa15801561461e573d6000803e3d6000fd5b505050506040513d602081101561463457600080fd5b505190506000614644848761396d565b905061464e6155f6565b6000831161466b5760405180602001604052806000815250614675565b614675828461537b565b905061467f6155f6565b604080516020810190915289546001600160e01b031681526146a190836153b0565b905060405180604001604052806146f183600001516040518060400160405280601a81526020017f6e657720696e64657820657863656564732032323420626974730000000000008152506153d5565b6001600160e01b0316815260200161473e896040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b63ffffffff9081169091526001600160f01b038c166000908152601460209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b03199094169390931716919091179055506128f39350505050565b80156128f3576147e8826040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b845463ffffffff91909116600160e01b026001600160e01b039091161784555050505050565b6001600160f01b038216600090815260146020526040902061482e6155f6565b50604080516020810190915281546001600160e01b0316815261484f6155f6565b5060408051602080820183526001600160f01b0387166000908152601682528381206001600160a01b038816808352818452948220805485528651959092529091529190915580511580156148a45750815115155b156148bc576ec097ce7bc90715b34b9f100000000081525b6148c46155f6565b6148ce838361542a565b905060006148db87611bf5565b6040805163145ff3d760e31b81526001600160a01b038b811660048301526001600160f01b038d166024830152915192955060009450908516925063a2ff9eb8916044808301926020929190829003018186803b15801561493b57600080fd5b505afa15801561494f573d6000803e3d6000fd5b505050506040513d602081101561496557600080fd5b505190506000614975828561544f565b6001600160a01b0389166000908152601860205260408120549192509061499c90836139af565b6001600160a01b038a166000818152601860209081526040918290208490558a51825187815291820152815193945091926001600160f01b038e16927fd848beb8ae16f4e6aa1ac02dd25815b133820ae520bd1051555c7d4f3b2d1bab92908290030190a350505050505050505050565b6000614a18836134da565b614a235760096131d7565b6000614a2e84611bf5565b925050506000806000836001600160a01b031663646fb1b487896040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160f01b03166001600160f01b031681526020019250505060806040518083038186803b158015614aa757600080fd5b505afa158015614abb573d6000803e3d6000fd5b505050506040513d6080811015614ad157600080fd5b508051602082015160409092015190945090925090508215614b245760405162461bcd60e51b81526004018080602001828103825260258152602001806157416025913960400191505060405180910390fd5b8015614b4157614b36600c6002614fd8565b945050505050611734565b8115614b77576000614b548888856139f1565b90508015614b7557614b69600e60038361547e565b95505050505050611734565b505b614b818787613531565b614b8c576000614b36565b6001600160f01b03871660009081526009602090815260408083206001600160a01b038a1684526002018252808320805460ff191690556008825291829020805483518184028101840190945280845260609392830182828015614c1957602002820191906000526020600020905b81546001600160f01b03168152600190910190602001808311614bfb575b5050835193945083925060009150505b82811015614c6e578a6001600160f01b0316848281518110614c4757fe5b60200260200101516001600160f01b03161415614c6657809150614c6e565b600101614c29565b50818110614c7857fe5b6001600160a01b0389166000908152600860205260409020805481906000198101908110614ca257fe5b9060005260206000200160009054906101000a90046001600160f01b0316818381548110614ccc57fe5b600091825260209091200180546001600160f01b0319166001600160f01b03929092169190911790558054614d05826000198301615673565b50604080516001600160f01b038d1681526001600160a01b038c16602082015281517f766f4c673c528d32fb0a1a17ad9fc5093cad3bf9782dc99d0433e37e93ab4229929181900390910190a160009b9a5050505050505050505050565b6000614d6e826134da565b15614d8657614d7f600a6011614fd8565b9050611480565b600080614d9284611bf5565b9250925050806001600160a01b0316630f06a9726040518163ffffffff1660e01b815260040160206040518083038186803b158015614dd057600080fd5b505afa158015614de4573d6000803e3d6000fd5b505050506040513d6020811015614dfa57600080fd5b505168ffffffffffffffffff83161115614e52576040805162461bcd60e51b815260206004820152601460248201527334b73b30b634b21036aa37b5b2b71029b2b8a73960611b604482015290519081900360640190fd5b6000614e5d8261203c565b9050614e688561356a565b6001600160f01b0316816001600160f01b031614614ecd576040805162461bcd60e51b815260206004820152601460248201527f696e76616c696420616e63686f7220746f6b656e000000000000000000000000604482015290519081900360640190fd5b614ed5612019565b6001600160a01b0316336001600160a01b031614614f3857336001600160a01b038316141580614f165750806001600160f01b0316856001600160f01b0316145b80614f275750614f25816134da565b155b15614f385761140360016012614fd8565b6040805180820182526001808252600060208084018281526001600160f01b038b81168085526009909352959092209351845460ff1916901515178455905192909101919091559082161415614f9157614f91856154e4565b604080516001600160f01b038716815290517f908fbebaccdaf25831159c6a147e2a7171f531a437bc2bcd1771345e39d8eaa29181900360200190a1600095945050505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601281111561500757fe5b83601381111561501357fe5b604080519283526020830191909152600082820152519081900360600190a182601281111561173157fe5b6000615049836134da565b615059576131d760096007614fd8565b6150628361356a565b6001600160f01b0316836001600160f01b0316146150af57615083836131e8565b615093576131d7600d6009614fd8565b670c7d713b49da00008211156150af576131d760066008614fd8565b6001600160f01b03831660009081526009602052604090206001018054908390556150d984611485565b50604080516001600160f01b03861681526020810183905280820185905290517f4e6ab8ea475303fbda79a98086e1b9d09347d04176232aa30c7ccf7cb1ea7fa89181900360600190a160006122bb565b600061173183836040518060400160405280600e81526020017f646976696465206279207a65726f000000000000000000000000000000000000815250615594565b60006151766155f6565b61518085856135cc565b905061200161518e82613629565b846139af565b600081848411156152235760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156151e85781810151838201526020016151d0565b50505050905090810190601f1680156152155780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000831580615238575082155b15615245575060006115ad565b8383028385828161525257fe5b041483906152a15760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b50949350505050565b600083830182858210156152a15760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b60008164010000000084106153555760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b509192915050565b600061173161537484670de0b6b3a764000061396d565b835161512a565b6153836155f6565b60405180602001604052806135ed6153aa866ec097ce7bc90715b34b9f100000000061396d565b8561512a565b6153b86155f6565b60405180602001604052806135ed856000015185600001516139af565b600081600160e01b84106153555760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b6154326155f6565b60405180602001604052806135ed8560000151856000015161392b565b60006ec097ce7bc90715b34b9f100000000061546f84846000015161396d565b8161547657fe5b049392505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460128111156154ad57fe5b8460138111156154b957fe5b604080519283526020830191909152818101859052519081900360600190a18360128111156122bb57fe5b6001600160f01b0381166000908152601160205260409020541561554f576040805162461bcd60e51b815260206004820152601460248201527f6d61726b657420616c7265616479206164646564000000000000000000000000604482015290519081900360640190fd5b60128054600101808255600090815260106020908152604080832080546001600160f01b039096166001600160f01b0319909616861790559254938252601190522055565b600081836155e35760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b508284816155ed57fe5b04949350505050565b6040518060200160405280600081525090565b6040518061014001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016156476155f6565b81526020016156546155f6565b81526020016156616155f6565b815260200161566e6155f6565b905290565b8154818355818111156117205760008381526020902061172091810190830161199a91905b808211156156ac5760008155600101615698565b509056fe4f6e6c7920746f6b656e20636f6e74726163742063616e20646f20746869732c206f6e6c7920666f72206f776e20746f6b656e4f6e6c79206d546f6b656e20636f6e74726163742063616e20646f20746869732c206f6e6c7920666f72206f776e206d546f6b656e636f6d2e6d6d6f2d66696e616e63652e6d44656c656761746f722e61646d696e2e61646472657373657869744d61726b65743a206765744163636f756e74536e617073686f74206661696c6564a265627a7a7231582038c417064fdce1d64d3ddab8301b11ec93c21d4b3bd1af6f51ef51f6464c828864736f6c63430005100032
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061041d5760003560e01c806380b6d4f01161022b578063ca0b57b311610130578063e87a22aa116100b8578063f2e6a94811610087578063f2e6a94814611239578063fa1a717314611265578063fac3da101461128b578063fcab1819146112cb578063fe54bce3146112f75761041d565b8063e87a22aa146111a4578063efc95b28146111df578063f0193f95146111e7578063f22e84ee146112135761041d565b8063d837909c116100ff578063d837909c146110da578063dce1544914611100578063df83bb551461112c578063e191aceb14611161578063e87554461461119c5761041d565b8063ca0b57b314610fb4578063d149d64314611009578063d4978c721461104e578063d4a9b745146110995761041d565b8063a4484b00116101b3578063be10069811610182578063be10069814610ec3578063bea6b8b814610f08578063c03e35e114610f2e578063c466544914610f54578063c86d3ee614610f8e5761041d565b8063a4484b0014610c2b578063a512ae7d14610c7a578063abfceffc14610d6d578063b817c41a14610d935761041d565b806386cfa66b116101fa57806386cfa66b14610b705780639070f91a14610b9657806391a5f17f14610bd157806394b2294b14610bfd578063998dd3ca14610c055761041d565b806380b6d4f014610aae578063828c4bf314610ae3578063840910f214610b09578063866bb10214610b2f5761041d565b8063534ce5a11161033157806370670422116102b957806377ed1dad1161028857806377ed1dad1461099c5780637b6889b7146109dd5780637d6b652b14610a225780637dc0d1d014610a715780638007c97214610a795761041d565b80637067042214610922578063715e31ca146109485780637323d1f41461096e578063741b2525146109765761041d565b80635f41b85d116103005780635f41b85d1461084f57806363d69e6514610857578063664305f0146108c357806366728b0c146109125780636e9960c31461091a5761041d565b8063534ce5a114610764578063548b6598146107995780635a638fbe146107e75780635ec88c791461080b5761041d565b806324a3d622116103b45780633a99d448116103835780633a99d448146106ed5780633ce7d72c1461071357806342cbb15c1461071b5780634ada90af1461072357806352d84d1e1461072b5761041d565b806324a3d6221461062f5780633228fc9c1461063757806339291dd11461065d5780633984938c1461069e5761041d565b8063126b19df116103f0578063126b19df146105615780631f530b2a146105aa5780632197597b146105e557806321af45691461060b5761041d565b80630583e1db1461042257806309f291171461045a5780630bff4ef5146104805780630decf9d9146104ae575b600080fd5b6104486004803603602081101561043857600080fd5b50356001600160f01b031661132c565b60408051918252519081900360200190f35b6104486004803603602081101561047057600080fd5b50356001600160f01b0316611485565b6104ac6004803603604081101561049657600080fd5b506001600160a01b0381351690602001356115b4565b005b6104ac600480360360408110156104c457600080fd5b6001600160a01b0382351691908101906040810160208201356401000000008111156104ef57600080fd5b82018360208201111561050157600080fd5b8035906020019184602083028401116401000000008311171561052357600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506116c3945050505050565b6105966004803603604081101561057757600080fd5b5080356001600160a01b031690602001356001600160f01b0316611725565b604080519115158252519081900360200190f35b6104ac600480360360608110156105c057600080fd5b506001600160f01b03813516906001600160a01b036020820135169060400135611720565b610448600480360360208110156105fb57600080fd5b50356001600160a01b031661173a565b61061361174c565b604080516001600160a01b039092168252519081900360200190f35b61061361175b565b6104486004803603602081101561064d57600080fd5b50356001600160f01b031661176a565b6104ac6004803603608081101561067357600080fd5b506001600160f01b03813516906001600160a01b03602082013516906040810135906060013561177c565b6106d4600480360360608110156106b457600080fd5b506001600160f01b038135811691602081013590911690604001356117e2565b6040805192835260208301919091528051918290030190f35b6105966004803603602081101561070357600080fd5b50356001600160f01b0316611981565b610448611996565b61044861199d565b6104486119a1565b6107486004803603602081101561074157600080fd5b50356119a7565b604080516001600160f01b039092168252519081900360200190f35b6104486004803603604081101561077a57600080fd5b5080356001600160f01b031690602001356001600160a01b03166119c2565b6107bf600480360360208110156107af57600080fd5b50356001600160f01b0316611b7e565b604080516001600160e01b03909316835263ffffffff90911660208301528051918290030190f35b6107ef611ba8565b604080516001600160e01b039092168252519081900360200190f35b6108316004803603602081101561082157600080fd5b50356001600160a01b0316611bbb565b60408051938452602084019290925282820152519081900360600190f35b610596611bf0565b61087d6004803603602081101561086d57600080fd5b50356001600160f01b0316611bf5565b6040518084600281111561088d57fe5b60ff16815268ffffffffffffffffff9093166020840152506001600160a01b031660408083019190915251908190036060019150f35b610448600480360360a08110156108d957600080fd5b506001600160f01b0381358116916020810135909116906001600160a01b03604082013581169160608101359091169060800135611dce565b61061361200a565b610613612019565b6107486004803603602081101561093857600080fd5b50356001600160a01b031661203c565b6104486004803603602081101561095e57600080fd5b50356001600160f01b03166120ae565b6106136120c0565b6104ac6004803603602081101561098c57600080fd5b50356001600160a01b03166120c6565b610831600480360360808110156109b257600080fd5b506001600160a01b03813516906001600160f01b036020820135169060408101359060600135612189565b610448600480360360808110156109f357600080fd5b506001600160f01b03813516906001600160a01b036020820135811691604081013590911690606001356121c3565b610448600480360360a0811015610a3857600080fd5b506001600160f01b0381358116916020810135909116906001600160a01b036040820135811691606081013590911690608001356122c3565b610613612485565b61044860048036036040811015610a8f57600080fd5b5080356001600160f01b031690602001356001600160a01b0316612494565b61044860048036036040811015610ac457600080fd5b5080356001600160f01b031690602001356001600160a01b03166124b1565b61059660048036036020811015610af957600080fd5b50356001600160f01b031661251d565b61059660048036036020811015610b1f57600080fd5b50356001600160f01b0316612532565b610b5560048036036020811015610b4557600080fd5b50356001600160f01b0316612547565b60408051921515835260208301919091528051918290030190f35b6107bf60048036036020811015610b8657600080fd5b50356001600160f01b0316612566565b61044860048036036060811015610bac57600080fd5b506001600160f01b03813516906001600160a01b036020820135169060400135612590565b6104ac60048036036040811015610be757600080fd5b506001600160f01b038135169060200135612860565b6104486128db565b61044860048036036020811015610c1b57600080fd5b50356001600160f01b03166128e1565b6104ac600480360360a0811015610c4157600080fd5b506001600160f01b0381358116916020810135909116906001600160a01b036040820135811691606081013590911690608001356128f3565b610d1d60048036036020811015610c9057600080fd5b810190602081018135640100000000811115610cab57600080fd5b820183602082011115610cbd57600080fd5b80359060200191846020830284011164010000000083111715610cdf57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506128fa945050505050565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610d59578181015183820152602001610d41565b505050509050019250505060405180910390f35b610d1d60048036036020811015610d8357600080fd5b50356001600160a01b031661298b565b6104ac60048036036080811015610da957600080fd5b810190602081018135640100000000811115610dc457600080fd5b820183602082011115610dd657600080fd5b80359060200191846020830284011164010000000083111715610df857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610e4857600080fd5b820183602082011115610e5a57600080fd5b80359060200191846020830284011164010000000083111715610e7c57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550505050803515159150602001351515612a14565b6104ac60048036036080811015610ed957600080fd5b506001600160f01b03813516906001600160a01b036020820135811691604081013590911690606001356117dc565b61044860048036036020811015610f1e57600080fd5b50356001600160a01b0316612cb9565b61044860048036036020811015610f4457600080fd5b50356001600160a01b0316612ccb565b610f7160048036036020811015610f6a57600080fd5b5035612cdd565b604080516001600160e01b03199092168252519081900360200190f35b61044860048036036020811015610fa457600080fd5b50356001600160f01b0316612d11565b6104ac600480360360c0811015610fca57600080fd5b506001600160f01b0381358116916020810135909116906001600160a01b03604082013581169160608101359091169060808101359060a00135612d1d565b6104486004803603608081101561101f57600080fd5b506001600160f01b03813516906001600160a01b03602082013581169160408101359091169060600135612d25565b6104ac600480360360a081101561106457600080fd5b506001600160f01b03813516906001600160a01b036020820135811691604081013590911690606081013590608001356128f3565b6104ac600480360360808110156110af57600080fd5b506001600160f01b03813516906001600160a01b0360208201351690604081013590606001356117dc565b610596600480360360208110156110f057600080fd5b50356001600160f01b0316612d3c565b6107486004803603604081101561111657600080fd5b506001600160a01b038135169060200135612d51565b6104486004803603604081101561114257600080fd5b5080356001600160f01b031690602001356001600160a01b0316612d86565b6104486004803603606081101561117757600080fd5b506001600160f01b03813516906001600160a01b036020820135169060400135612de7565b610448612e04565b610448600480360360608110156111ba57600080fd5b506001600160f01b03813516906001600160a01b036020820135169060400135612e0a565b610448613077565b6104ac600480360360408110156111fd57600080fd5b506001600160a01b03813516906020013561307d565b6105966004803603602081101561122957600080fd5b50356001600160f01b0316613194565b6104486004803603604081101561124f57600080fd5b506001600160f01b0381351690602001356131a9565b6104486004803603602081101561127b57600080fd5b50356001600160f01b03166131e8565b610748600480360360608110156112a157600080fd5b50803560ff1690602081013568ffffffffffffffffff1690604001356001600160a01b0316613461565b6112d36134b8565b604051808260028111156112e357fe5b60ff16815260200191505060405180910390f35b6104486004803603604081101561130d57600080fd5b5080356001600160f01b031690602001356001600160a01b03166134bd565b600080600061133a84611bf5565b9193509091506002905082600281111561135057fe5b146113615760125b92505050611480565b61136a846134da565b611375576009611358565b6000816001600160a01b0316636352211e866040518263ffffffff1660e01b815260040180826001600160f01b0316815260200191505060206040518083038186803b1580156113c457600080fd5b505afa1580156113d8573d6000803e3d6000fd5b505050506040513d60208110156113ee57600080fd5b505190506113fc8582613531565b61140d5760085b9350505050611480565b600061141986336119c2565b9050801561142c57935061148092505050565b600061143783611bbb565b919350909150508115158061144a575080155b1561145e5760035b95505050505050611480565b336001600160a01b0384161415611476576001611452565b6000955050505050505b919050565b6000611490826134da565b6114d5576040805162461bcd60e51b81526020600482015260116024820152701b551bdad95b881b9bdd081b1a5cdd1959607a1b604482015290519081900360640190fd5b60006114e08361356a565b6001600160f01b0381166000908152600960205260409020600101549091508061150f57600092505050611480565b816001600160f01b0316846001600160f01b031614611550576001600160f01b038416600090815260096020526040902060010154801561154e578091505b505b670c7d713b49da00008111156115ad576040805162461bcd60e51b815260206004820152601a60248201527f636f6c6c61746572616c20666163746f7220746f6f2068696768000000000000604482015290519081900360640190fd5b9392505050565b6115bc612019565b6001600160a01b0316336001600160a01b031614611621576040805162461bcd60e51b815260206004820152601c60248201527f6f6e6c792061646d696e2063616e20736574206d6d6f20737065656400000000604482015290519081900360640190fd5b61162a826120c6565b8061164d576001600160a01b0382166000908152601a602052604081205561166f565b61165561199d565b6001600160a01b0383166000908152601a60205260409020555b6001600160a01b038216600081815260196020908152604091829020849055815184815291517fae3a17f08499cb0a69892e0bdf8867c64c7459e0e787049b2fc28b4695922d7d9281900390910190a25050565b6040805160018082528183019092526060916020808301908038833901905050905082816000815181106116f357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506117208183600180612a14565b505050565b60006117318284613531565b90505b92915050565b60196020526000908152604090205481565b6006546001600160a01b031681565b6007546001600160a01b031681565b600f6020526000908152604090205481565b8015801561178a5750600082115b156117dc576040805162461bcd60e51b815260206004820152601160248201527f72656465656d546f6b656e73207a65726f000000000000000000000000000000604482015290519081900360640190fd5b50505050565b6000806117ee856134da565b158061180057506117fe846134da565b155b156118115750600990506000611979565b600061181c866131e8565b90506000611829866131e8565b9050811580611836575080155b1561184b57600d935060009250611979915050565b600061185687611bf5565b925050506000816001600160a01b031663458f1022896040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b1580156118b257600080fd5b505afa1580156118c6573d6000803e3d6000fd5b505050506040513d60208110156118dc57600080fd5b5051905060006118ea6155f6565b6118f26155f6565b6118fa6155f6565b611922604051806020016040528060045481525060405180602001604052808b81525061358d565b925061192e838c6135cc565b915061195660405180602001604052808981525060405180602001604052808881525061358d565b905061196a61196583836135f6565b613629565b60009a50985050505050505050505b935093915050565b600c6020526000908152604090205460ff1681565b6000545b90565b4390565b60045481565b6010602052600090815260409020546001600160f01b031681565b600080806119cf85611bf5565b9250509150600a60006119e18761356a565b6001600160f01b0316815260208101919091526040016000205460ff1615611a44576040805162461bcd60e51b8152602060048201526011602482015270185d58dd1a5bdb881a5cc81c185d5cd959607a1b604482015290519081900360640190fd5b6001600160f01b0385166000908152600a602052604090205460ff1615611aa6576040805162461bcd60e51b8152602060048201526011602482015270185d58dd1a5bdb881a5cc81c185d5cd959607a1b604482015290519081900360640190fd5b611aaf856134da565b611abf5760095b92505050611734565b6002826002811115611acd57fe5b14611ad9576009611ab6565b60006001600160a01b0316816001600160a01b0316636352211e876040518263ffffffff1660e01b815260040180826001600160f01b0316815260200191505060206040518083038186803b158015611b3157600080fd5b505afa158015611b45573d6000803e3d6000fd5b505050506040513d6020811015611b5b57600080fd5b50516001600160a01b03161415611b73576009611ab6565b600095945050505050565b6015602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b6ec097ce7bc90715b34b9f100000000081565b600080600080600080611bd2876000806000613638565b925092509250826012811115611be457fe5b97919650945092505050565b600190565b600069ffffffffffffffffffff60a083901c1682601081901b80841a6002811115611c1c57fe5b9350816001600160a01b031663fcab18196040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5757600080fd5b505afa158015611c6b573d6000803e3d6000fd5b505050506040513d6020811015611c8157600080fd5b50516002811115611c8e57fe5b846002811115611c9a57fe5b14611cec576040805162461bcd60e51b815260206004820152601360248201527f496e76616c6964206d546f6b656e207479706500000000000000000000000000604482015290519081900360640190fd5b6001846002811115611cfa57fe5b1415611d665760018368ffffffffffffffffff161115611d61576040805162461bcd60e51b815260206004820181905260248201527f496e76616c6964207365714e7220666f722066756e6769626c6520746f6b656e604482015290519081900360640190fd5b611dc6565b6002846002811115611d7457fe5b14611dc6576040805162461bcd60e51b815260206004820152601360248201527f556e6b6e6f776e206d546f6b656e207479706500000000000000000000000000604482015290519081900360640190fd5b509193909250565b600080611dda87611bf5565b925050506000611de987611bf5565b92505050600e6000611dfa8a61356a565b6001600160f01b0316815260208101919091526040016000205460ff1615611e5b576040805162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b604482015290519081900360640190fd5b6001600160f01b0388166000908152600e602052604090205460ff1615611ebb576040805162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b604482015290519081900360640190fd5b611ec4886134da565b1580611ed65750611ed4876134da565b155b15611ee75760095b92505050612001565b611ef18786613531565b1580611f045750611f028886613531565b155b15611f10576008611ede565b806001600160a01b03166344c09b106040518163ffffffff1660e01b815260040160206040518083038186803b158015611f4957600080fd5b505afa158015611f5d573d6000803e3d6000fd5b505050506040513d6020811015611f7357600080fd5b50516040805163044c09b160e41b815290516001600160a01b03928316928516916344c09b10916004808301926020929190829003018186803b158015611fb957600080fd5b505afa158015611fcd573d6000803e3d6000fd5b505050506040513d6020811015611fe357600080fd5b50516001600160a01b031614611ffa576002611ede565b6000925050505b95945050505050565b6001546001600160a01b031690565b600080604051808061571960289139604051908190036028019020549392505050565b6000611734826001600160a01b031663fcab18196040518163ffffffff1660e01b815260040160206040518083038186803b15801561207a57600080fd5b505afa15801561208e573d6000803e3d6000fd5b505050506040513d60208110156120a457600080fd5b5051600084613461565b60136020526000908152604090205481565b60001990565b6001600160a01b038116600090815260196020526040812054906120e861199d565b6001600160a01b0384166000908152601a60205260408120549192509061211090839061392b565b90506000811180156121225750600083115b156117dc576000612133828561396d565b6001600160a01b0386166000908152601860205260408120549192509061215a90836139af565b6001600160a01b038716600090815260186020908152604080832093909355601a905220849055505050505050565b60008060008060008061219e8a8a8a8a613638565b9250925092508260128111156121b057fe5b95509093509150505b9450945094915050565b6000600d60006121d28761356a565b6001600160f01b0316815260208101919091526040016000205460ff1615612236576040805162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160f01b0385166000908152600d602052604090205460ff1615612299576040805162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b604482015290519081900360640190fd5b60006122a68686856139f1565b905080156122b55790506122bb565b60009150505b949350505050565b6000806122cf86611bf5565b50909150600290508160028111156122e357fe5b14156122f45760125b915050612001565b6122fd876134da565b158061230f575061230d866134da565b155b1561231b5760096122ec565b6123258785613531565b158061233857506123368685613531565b155b156123445760086122ec565b60008061235086613a78565b9193509091506000905082601281111561236657fe5b146123815781601281111561237757fe5b9350505050612001565b8061238d576003612377565b60006123988a611bf5565b925050506000816001600160a01b031663e48695fa898d6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160f01b03166001600160f01b031681526020019250505060206040518083038186803b15801561240e57600080fd5b505afa158015612422573d6000803e3d6000fd5b505050506040513d602081101561243857600080fd5b50516040805160208101909152600354815290915060009061245a9083613a98565b9050808811156124735760119650505050505050612001565b60009c9b505050505050505050505050565b6002546001600160a01b031681565b601660209081526000928352604080842090915290825290205481565b6000806124bd84611bf5565b925050506001600160a01b03811633146125085760405162461bcd60e51b81526004018080602001828103825260358152602001806156e46035913960400191505060405180910390fd5b6125128484613ab7565b60128111156122bb57fe5b600b6020526000908152604090205460ff1681565b600e6020526000908152604090205460ff1681565b6009602052600090815260409020805460019091015460ff9091169082565b6014602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b60008061259c85611bf5565b92505050600c60006125ad8761356a565b6001600160f01b0316815260208101919091526040016000205460ff161561260f576040805162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6001600160f01b0385166000908152600c602052604090205460ff1615612670576040805162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b604482015290519081900360640190fd5b612679856134da565b6126885760095b9150506115ad565b6126928585613531565b61269d576008612680565b6126a6856131e8565b6126b157600d612680565b6000600f60006126c08861356a565b6001600160f01b0390811682526020808301939093526040918201600090812054918a168152600f9093529120549091508115806127075750801580159061270757508181105b15612710578091505b8115612801576000836001600160a01b0316635a874303896040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b15801561276e57600080fd5b505afa158015612782573d6000803e3d6000fd5b505050506040513d602081101561279857600080fd5b5051905060006127a882886139af565b90508381106127fe576040805162461bcd60e51b815260206004820152601960248201527f6d61726b657420626f72726f7720636170207265616368656400000000000000604482015290519081900360640190fd5b50505b600080612811888a60008a613638565b9193509091506000905082601281111561282757fe5b146128445781601281111561283857fe5b955050505050506115ad565b8015612851576004612838565b50600098975050505050505050565b612868612019565b6001600160a01b0316336001600160a01b0316146128cd576040805162461bcd60e51b815260206004820152601c60248201527f6f6e6c792061646d696e2063616e20736574206d6d6f20737065656400000000604482015290519081900360640190fd5b6128d78282613bbb565b5050565b60055481565b60116020526000908152604090205481565b5050505050565b606060008251905060608160405190808252806020026020018201604052801561292e578160200160208202803883390190505b50905060005b828110156129835761295985828151811061294b57fe5b602002602001015133613ab7565b601281111561296457fe5b82828151811061297057fe5b6020908102919091010152600101612934565b509392505050565b60608060086000846001600160a01b03166001600160a01b03168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015612a0757602002820191906000526020600020905b81546001600160f01b031681526001909101906020018083116129e9575b5093979650505050505050565b60005b83518110156128f3576000848281518110612a2e57fe5b60200260200101519050612a41816134da565b612a92576040805162461bcd60e51b815260206004820152601560248201527f6d61726b6574206d757374206265206c69737465640000000000000000000000604482015290519081900360640190fd5b60018415151415612c0e576000612aa882611bf5565b92505050612ab46155f6565b6040518060200160405280836001600160a01b031663d46e761c866040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b158015612b1557600080fd5b505afa158015612b29573d6000803e3d6000fd5b505050506040513d6020811015612b3f57600080fd5b505190529050612b4f8382613f5f565b60005b8851811015612c0a57612b79848a8381518110612b6b57fe5b602002602001015184614238565b612bce898281518110612b8857fe5b6020026020010151601860008c8581518110612ba057fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054614405565b601860008b8481518110612bde57fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600101612b52565b5050505b60018315151415612cb057612c228161453f565b60005b8651811015612cae57612c4b82888381518110612c3e57fe5b602002602001015161480e565b612c72878281518110612c5a57fe5b6020026020010151601860008a8581518110612ba057fe5b60186000898481518110612c8257fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600101612c25565b505b50600101612a17565b601a6020526000908152604090205481565b60186020526000908152604090205481565b60008181548110612cea57fe5b9060005260206000209060089182820401919006600402915054906101000a900460e01b81565b60006117348233614a0d565b505050505050565b6000612d30856134da565b611b73575060096122bb565b600d6020526000908152604090205460ff1681565b60086020528160005260406000208181548110612d6a57fe5b6000918252602090912001546001600160f01b03169150829050565b600080612d9284611bf5565b925050506001600160a01b0381163314612ddd5760405162461bcd60e51b81526004018080602001828103825260338152602001806156b16033913960400191505060405180910390fd5b6122bb8484614a0d565b600080612df58585856139f1565b90508015611b735790506115ad565b60035481565b60008080612e1786611bf5565b9250925050806001600160a01b0316630f06a9726040518163ffffffff1660e01b815260040160206040518083038186803b158015612e5557600080fd5b505afa158015612e69573d6000803e3d6000fd5b505050506040513d6020811015612e7f57600080fd5b505168ffffffffffffffffff83161115612ed7576040805162461bcd60e51b815260206004820152601460248201527334b73b30b634b21036aa37b5b2b71029b2b8a73960611b604482015290519081900360640190fd5b336001600160a01b03821614612f34576040805162461bcd60e51b815260206004820152601960248201527f6f6e6c79206d546f6b656e2063616e2063616c6c207468697300000000000000604482015290519081900360640190fd5b6000612f3f8761356a565b6001600160f01b0381166000908152600b602052604090205490915060ff1615612fa1576040805162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b604482015290519081900360640190fd5b6001600160f01b0387166000908152600b602052604090205460ff1615613000576040805162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b604482015290519081900360640190fd5b613009816134da565b61301957600993505050506115ad565b613022876134da565b61306a57600061303188614d63565b905080156130445793506115ad92505050565b61304d886131e8565b6130685761305d600d6009614fd8565b9450505050506115ad565b505b6000979650505050505050565b60125481565b613085612019565b6001600160a01b0316336001600160a01b0316146130ea576040805162461bcd60e51b815260206004820152601860248201527f6f6e6c792061646d696e2063616e206772616e74206d6d6f0000000000000000604482015290519081900360640190fd5b60006130f68383614405565b9050801561314b576040805162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e74206d6d6f20666f72206772616e74000000000000604482015290519081900360640190fd5b604080516001600160a01b03851681526020810184905281517f2e99fc57d866b27ce07b96c6a6399762e10030d95faee941c25a4997bc49ec00929181900390910190a1505050565b600a6020526000908152604090205460ff1681565b60006131b3612019565b6001600160a01b0316336001600160a01b0316146131de576131d760016006614fd8565b9050611734565b611731838361503e565b60006131f38261356a565b6001600160f01b0316826001600160f01b03161415613259576040805162461bcd60e51b815260206004820152601c60248201527f6e6f20676574507269636520666f7220616e63686f7220746f6b656e00000000604482015290519081900360640190fd5b613262826134da565b6132a7576040805162461bcd60e51b81526020600482015260116024820152701b551bdad95b881b9bdd081b1a5cdd1959607a1b604482015290519081900360640190fd5b60006132b283611bf5565b925050506000816001600160a01b03166310cfe9066040518163ffffffff1660e01b815260040160206040518083038186803b1580156132f157600080fd5b505afa158015613305573d6000803e3d6000fd5b505050506040513d602081101561331b57600080fd5b505190506133276120c0565b6001600160a01b0316816001600160a01b0316141561335257670de0b6b3a764000092505050611480565b6000826001600160a01b0316635553d7b6866040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b1580156133aa57600080fd5b505afa1580156133be573d6000803e3d6000fd5b505050506040513d60208110156133d457600080fd5b505160025460408051634cb973e160e11b81526001600160a01b038681166004830152602482018590529151939450911691639972e7c291604480820192602092909190829003018186803b15801561342c57600080fd5b505afa158015613440573d6000803e3d6000fd5b505050506040513d602081101561345657600080fd5b505195945050505050565b600080604885600281111561347257fe5b69ffffffffffffffffffff60a01b68ffffffffffffffffff871669ffffffffffffffffffff9290921690921b0160a01b166001600160a01b038416019150509392505050565b600090565b601760209081526000928352604080842090915290825290205481565b6000600960006134e98461356a565b6001600160f01b0316815260208101919091526040016000205460ff1661351257506000611480565b506001600160f01b031660009081526009602052604090205460ff1690565b6001600160f01b03821660009081526009602090815260408083206001600160a01b038516845260020190915290205460ff1692915050565b7dff000000000000000000ffffffffffffffffffffffffffffffffffffffff1690565b6135956155f6565b6040518060200160405280670de0b6b3a76400006135bb8660000151866000015161396d565b816135c257fe5b0490529392505050565b6135d46155f6565b60405180602001604052806135ed85600001518561396d565b90529392505050565b6135fe6155f6565b60405180602001604052806135ed6136228660000151670de0b6b3a764000061396d565b855161512a565b51670de0b6b3a7640000900490565b6000806000613645615609565b6001600160a01b038816600090815260086020908152604080832080548251818502810185019093528083526060938301828280156136ad57602002820191906000526020600020905b81546001600160f01b0316815260019091019060200180831161368f575b50939450600093505050505b81518110156138ec5760008282815181106136d057fe5b6020026020010151905060006136e582611bf5565b92505050806001600160a01b031663646fb1b48e846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160f01b03166001600160f01b031681526020019250505060806040518083038186803b15801561375957600080fd5b505afa15801561376d573d6000803e3d6000fd5b505050506040513d608081101561378357600080fd5b508051602082015160408084015160609485015160808c0152938a019390935291880191909152945084156137c95750600f9750600096508695506121b9945050505050565b60405180602001604052806137dd84611485565b905260c087015260408051602081019091526080870151815260e0870152613804826131e8565b60a087018190526138265750600d9750600096508695506121b9945050505050565b604080516020810190915260a0870151815261010087015260c086015160e0870151613860916138559161358d565b87610100015161358d565b61012087018190526040870151875161387a92919061516c565b86526101008601516060870151602088015161389792919061516c565b60208701526001600160f01b03828116908d1614156138e2576138c48661012001518c886020015161516c565b602087018190526101008701516138dc918c9061516c565b60208701525b50506001016136b9565b5060208301518351111561391257505060208101519051600094500391508290506121b9565b50508051602090910151600094508493500390506121b9565b600061173183836040518060400160405280601581526020017f7375627472616374696f6e20756e646572666c6f770000000000000000000000815250615194565b600061173183836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f7700000000000000000081525061522b565b600061173183836040518060400160405280601181526020017f6164646974696f6e206f766572666c6f770000000000000000000000000000008152506152aa565b60006139fc846134da565b613a0a5760095b90506115ad565b613a148484613531565b613a1f576000613a03565b600080613a2f8587866000613638565b91935090915060009050826012811115613a4557fe5b14613a5f57816012811115613a5657fe5b925050506115ad565b8015613a6c576004613a56565b60009695505050505050565b6000806000613a8b846000806000613638565b9250925092509193909250565b6000613aa26155f6565b613aac84846135cc565b90506122bb81613629565b6000613ac2836134da565b613ace57506009611734565b613ad88383613531565b151560011415613aea57506000611734565b6005546001600160a01b03831660009081526008602052604090205410613b1357506010611734565b6001600160f01b03831660008181526009602090815260408083206001600160a01b03871680855260029091018352818420805460ff19166001908117909155600884528285208054918201815585529383902090930180546001600160f01b0319168517905580519384529083019190915280517fb84836f7818d814ca2164a48af216be85ae605b2364af712e17509d96b1bdfcb9281900390910190a150600092915050565b6001600160f01b0382166000908152601360205260409020548015613c9c576000613be584611bf5565b92505050613bf16155f6565b6040518060200160405280836001600160a01b031663d46e761c886040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b158015613c5257600080fd5b505afa158015613c66573d6000803e3d6000fd5b505050506040513d6020811015613c7c57600080fd5b505190529050613c8b8561453f565b613c958582613f5f565b5050613f03565b8115613f0357613cab836134da565b613cfc576040805162461bcd60e51b815260206004820152601860248201527f6d6d6f206d61726b6574206973206e6f74206c69737465640000000000000000604482015290519081900360640190fd5b6001600160f01b0383166000908152601460205260409020546001600160e01b0316158015613d4e57506001600160f01b038316600090815260146020526040902054600160e01b900463ffffffff16155b15613e1d5760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b03168152602001613dc2613d8761199d565b6040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b63ffffffff9081169091526001600160f01b0385166000908152601460209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b6001600160f01b0383166000908152601560205260409020546001600160e01b0316158015613e6f57506001600160f01b038316600090815260156020526040902054600160e01b900463ffffffff16155b15613f035760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b03168152602001613ea8613d8761199d565b63ffffffff9081169091526001600160f01b0385166000908152601560209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b818114611720576001600160f01b038316600081815260136020908152604091829020859055815185815291517f1b6f034636f23dabb8bb7f49c5a29717431fe7ecb6107364c8a1d53c2db8dd929281900390910190a2505050565b6001600160f01b038216600090815260156020908152604080832060139092528220549091613f8c61199d565b8354909150600090613fac908390600160e01b900463ffffffff1661392b565b9050600081118015613fbe5750600083115b156141cc576000613fce87611bf5565b92505050600061405f826001600160a01b0316635a8743038a6040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b15801561402d57600080fd5b505afa158015614041573d6000803e3d6000fd5b505050506040513d602081101561405757600080fd5b50518861535d565b9050600061406d848761396d565b90506140776155f6565b60008311614094576040518060200160405280600081525061409e565b61409e828461537b565b90506140a86155f6565b604080516020810190915289546001600160e01b031681526140ca90836153b0565b9050604051806040016040528061411a83600001516040518060400160405280601a81526020017f6e657720696e64657820657863656564732032323420626974730000000000008152506153d5565b6001600160e01b03168152602001614167896040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b63ffffffff9081169091526001600160f01b038d166000908152601560209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b0319909416939093171691909117905550612d1d9350505050565b8015612d1d57614211826040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b845463ffffffff91909116600160e01b026001600160e01b03909116178455505050505050565b6001600160f01b03831660009081526015602052604090206142586155f6565b50604080516020810190915281546001600160e01b031681526142796155f6565b5060408051602080820183526001600160f01b0388166000908152601782528381206001600160a01b0389168083528184529482208054855286519590925290915291909155805115612d1d576142ce6155f6565b6142d8838361542a565b905060006142e588611bf5565b92505050600061435e826001600160a01b031663e48695fa8a8c6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160f01b03166001600160f01b031681526020019250505060206040518083038186803b15801561402d57600080fd5b9050600061436c828561544f565b6001600160a01b038a166000908152601860205260408120549192509061439390836139af565b6001600160a01b038b166000818152601860209081526040918290208490558a51825187815291820152815193945091926001600160f01b038f16927f4aabcdfa995af92795e2e0edddeb2fa8814eadd55f7a34e422fcf589dd92549c92908290030190a35050505050505050505050565b60008061441061200a565b604080516370a0823160e01b815230600482015290519192506000916001600160a01b038416916370a08231916024808301926020929190829003018186803b15801561445c57600080fd5b505afa158015614470573d6000803e3d6000fd5b505050506040513d602081101561448657600080fd5b5051905083158015906144995750808411155b1561453657816001600160a01b031663a9059cbb86866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156144fe57600080fd5b505af1158015614512573d6000803e3d6000fd5b505050506040513d602081101561452857600080fd5b506000935061173492505050565b50919392505050565b6001600160f01b03811660009081526014602090815260408083206013909252822054909161456c61199d565b835490915060009061458c908390600160e01b900463ffffffff1661392b565b905060008111801561459e5750600083115b156147a35760006145ae86611bf5565b925050506000816001600160a01b03166338c4e18a886040518263ffffffff1660e01b815260040180826001600160f01b03166001600160f01b0316815260200191505060206040518083038186803b15801561460a57600080fd5b505afa15801561461e573d6000803e3d6000fd5b505050506040513d602081101561463457600080fd5b505190506000614644848761396d565b905061464e6155f6565b6000831161466b5760405180602001604052806000815250614675565b614675828461537b565b905061467f6155f6565b604080516020810190915289546001600160e01b031681526146a190836153b0565b905060405180604001604052806146f183600001516040518060400160405280601a81526020017f6e657720696e64657820657863656564732032323420626974730000000000008152506153d5565b6001600160e01b0316815260200161473e896040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b63ffffffff9081169091526001600160f01b038c166000908152601460209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b03199094169390931716919091179055506128f39350505050565b80156128f3576147e8826040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506152ff565b845463ffffffff91909116600160e01b026001600160e01b039091161784555050505050565b6001600160f01b038216600090815260146020526040902061482e6155f6565b50604080516020810190915281546001600160e01b0316815261484f6155f6565b5060408051602080820183526001600160f01b0387166000908152601682528381206001600160a01b038816808352818452948220805485528651959092529091529190915580511580156148a45750815115155b156148bc576ec097ce7bc90715b34b9f100000000081525b6148c46155f6565b6148ce838361542a565b905060006148db87611bf5565b6040805163145ff3d760e31b81526001600160a01b038b811660048301526001600160f01b038d166024830152915192955060009450908516925063a2ff9eb8916044808301926020929190829003018186803b15801561493b57600080fd5b505afa15801561494f573d6000803e3d6000fd5b505050506040513d602081101561496557600080fd5b505190506000614975828561544f565b6001600160a01b0389166000908152601860205260408120549192509061499c90836139af565b6001600160a01b038a166000818152601860209081526040918290208490558a51825187815291820152815193945091926001600160f01b038e16927fd848beb8ae16f4e6aa1ac02dd25815b133820ae520bd1051555c7d4f3b2d1bab92908290030190a350505050505050505050565b6000614a18836134da565b614a235760096131d7565b6000614a2e84611bf5565b925050506000806000836001600160a01b031663646fb1b487896040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160f01b03166001600160f01b031681526020019250505060806040518083038186803b158015614aa757600080fd5b505afa158015614abb573d6000803e3d6000fd5b505050506040513d6080811015614ad157600080fd5b508051602082015160409092015190945090925090508215614b245760405162461bcd60e51b81526004018080602001828103825260258152602001806157416025913960400191505060405180910390fd5b8015614b4157614b36600c6002614fd8565b945050505050611734565b8115614b77576000614b548888856139f1565b90508015614b7557614b69600e60038361547e565b95505050505050611734565b505b614b818787613531565b614b8c576000614b36565b6001600160f01b03871660009081526009602090815260408083206001600160a01b038a1684526002018252808320805460ff191690556008825291829020805483518184028101840190945280845260609392830182828015614c1957602002820191906000526020600020905b81546001600160f01b03168152600190910190602001808311614bfb575b5050835193945083925060009150505b82811015614c6e578a6001600160f01b0316848281518110614c4757fe5b60200260200101516001600160f01b03161415614c6657809150614c6e565b600101614c29565b50818110614c7857fe5b6001600160a01b0389166000908152600860205260409020805481906000198101908110614ca257fe5b9060005260206000200160009054906101000a90046001600160f01b0316818381548110614ccc57fe5b600091825260209091200180546001600160f01b0319166001600160f01b03929092169190911790558054614d05826000198301615673565b50604080516001600160f01b038d1681526001600160a01b038c16602082015281517f766f4c673c528d32fb0a1a17ad9fc5093cad3bf9782dc99d0433e37e93ab4229929181900390910190a160009b9a5050505050505050505050565b6000614d6e826134da565b15614d8657614d7f600a6011614fd8565b9050611480565b600080614d9284611bf5565b9250925050806001600160a01b0316630f06a9726040518163ffffffff1660e01b815260040160206040518083038186803b158015614dd057600080fd5b505afa158015614de4573d6000803e3d6000fd5b505050506040513d6020811015614dfa57600080fd5b505168ffffffffffffffffff83161115614e52576040805162461bcd60e51b815260206004820152601460248201527334b73b30b634b21036aa37b5b2b71029b2b8a73960611b604482015290519081900360640190fd5b6000614e5d8261203c565b9050614e688561356a565b6001600160f01b0316816001600160f01b031614614ecd576040805162461bcd60e51b815260206004820152601460248201527f696e76616c696420616e63686f7220746f6b656e000000000000000000000000604482015290519081900360640190fd5b614ed5612019565b6001600160a01b0316336001600160a01b031614614f3857336001600160a01b038316141580614f165750806001600160f01b0316856001600160f01b0316145b80614f275750614f25816134da565b155b15614f385761140360016012614fd8565b6040805180820182526001808252600060208084018281526001600160f01b038b81168085526009909352959092209351845460ff1916901515178455905192909101919091559082161415614f9157614f91856154e4565b604080516001600160f01b038716815290517f908fbebaccdaf25831159c6a147e2a7171f531a437bc2bcd1771345e39d8eaa29181900360200190a1600095945050505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601281111561500757fe5b83601381111561501357fe5b604080519283526020830191909152600082820152519081900360600190a182601281111561173157fe5b6000615049836134da565b615059576131d760096007614fd8565b6150628361356a565b6001600160f01b0316836001600160f01b0316146150af57615083836131e8565b615093576131d7600d6009614fd8565b670c7d713b49da00008211156150af576131d760066008614fd8565b6001600160f01b03831660009081526009602052604090206001018054908390556150d984611485565b50604080516001600160f01b03861681526020810183905280820185905290517f4e6ab8ea475303fbda79a98086e1b9d09347d04176232aa30c7ccf7cb1ea7fa89181900360600190a160006122bb565b600061173183836040518060400160405280600e81526020017f646976696465206279207a65726f000000000000000000000000000000000000815250615594565b60006151766155f6565b61518085856135cc565b905061200161518e82613629565b846139af565b600081848411156152235760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156151e85781810151838201526020016151d0565b50505050905090810190601f1680156152155780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000831580615238575082155b15615245575060006115ad565b8383028385828161525257fe5b041483906152a15760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b50949350505050565b600083830182858210156152a15760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b60008164010000000084106153555760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b509192915050565b600061173161537484670de0b6b3a764000061396d565b835161512a565b6153836155f6565b60405180602001604052806135ed6153aa866ec097ce7bc90715b34b9f100000000061396d565b8561512a565b6153b86155f6565b60405180602001604052806135ed856000015185600001516139af565b600081600160e01b84106153555760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b6154326155f6565b60405180602001604052806135ed8560000151856000015161392b565b60006ec097ce7bc90715b34b9f100000000061546f84846000015161396d565b8161547657fe5b049392505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460128111156154ad57fe5b8460138111156154b957fe5b604080519283526020830191909152818101859052519081900360600190a18360128111156122bb57fe5b6001600160f01b0381166000908152601160205260409020541561554f576040805162461bcd60e51b815260206004820152601460248201527f6d61726b657420616c7265616479206164646564000000000000000000000000604482015290519081900360640190fd5b60128054600101808255600090815260106020908152604080832080546001600160f01b039096166001600160f01b0319909616861790559254938252601190522055565b600081836155e35760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156151e85781810151838201526020016151d0565b508284816155ed57fe5b04949350505050565b6040518060200160405280600081525090565b6040518061014001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016156476155f6565b81526020016156546155f6565b81526020016156616155f6565b815260200161566e6155f6565b905290565b8154818355818111156117205760008381526020902061172091810190830161199a91905b808211156156ac5760008155600101615698565b509056fe4f6e6c7920746f6b656e20636f6e74726163742063616e20646f20746869732c206f6e6c7920666f72206f776e20746f6b656e4f6e6c79206d546f6b656e20636f6e74726163742063616e20646f20746869732c206f6e6c7920666f72206f776e206d546f6b656e636f6d2e6d6d6f2d66696e616e63652e6d44656c656761746f722e61646d696e2e61646472657373657869744d61726b65743a206765744163636f756e74536e617073686f74206661696c6564a265627a7a7231582038c417064fdce1d64d3ddab8301b11ec93c21d4b3bd1af6f51ef51f6464c828864736f6c63430005100032
Deployed Bytecode Sourcemap
489:56600:9:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;489:56600:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25399:1381;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;25399:1381:9;-1:-1:-1;;;;;25399:1381:9;;:::i;:::-;;;;;;;;;;;;;;;;8083:656:6;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;8083:656:6;-1:-1:-1;;;;;8083:656:6;;:::i;56238:639:9:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;56238:639:9;;;;;;;;:::i;:::-;;52606:208;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;52606:208:9;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;52606:208:9;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;52606:208:9;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;52606:208:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;52606:208:9;;-1:-1:-1;52606:208:9;;-1:-1:-1;;;;;52606:208:9:i;1575:147::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1575:147:9;;-1:-1:-1;;;;;1575:147:9;;;;;-1:-1:-1;;;;;1575:147:9;;:::i;:::-;;;;;;;;;;;;;;;;;;20477:315;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;20477:315:9;;;;-1:-1:-1;;;;;20477:315:9;;;;;;;;;;:::i;6500:52:8:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6500:52:8;-1:-1:-1;;;;;6500:52:8;;:::i;2027:32::-;;;:::i;:::-;;;;-1:-1:-1;;;;;2027:32:8;;;;;;;;;;;;;;2336:28;;;:::i;4592:42::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4592:42:8;-1:-1:-1;;;;;4592:42:8;;:::i;17228:370:9:-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;17228:370:9;;;;-1:-1:-1;;;;;17228:370:9;;;;;;;;;;;;;;;:::i;40080:2243::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;40080:2243:9;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;4274:52:8;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4274:52:8;-1:-1:-1;;;;;4274:52:8;;:::i;383:118:3:-;;;:::i;42836:91:9:-;;;:::i;1564:40:8:-;;;:::i;5005:43::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5005:43:8;;:::i;:::-;;;;-1:-1:-1;;;;;5005:43:8;;;;;;;;;;;;;;11071:1096:9;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11071:1096:9;;-1:-1:-1;;;;;11071:1096:9;;;;;-1:-1:-1;;;;;11071:1096:9;;:::i;5865:56:8:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5865:56:8;-1:-1:-1;;;;;5865:56:8;;:::i;:::-;;;;-1:-1:-1;;;;;5865:56:8;;;;;;;;;;;;;;;;;;;;;;6759:46;;;:::i;:::-;;;;-1:-1:-1;;;;;6759:46:8;;;;;;;;;;;;;;33947:260:9;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;33947:260:9;-1:-1:-1;;;;;33947:260:9;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;766:99;;;:::i;3807:765:6:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3807:765:6;-1:-1:-1;;;;;3807:765:6;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3807:765:6;;;;;;;;;;;;;;;;;-1:-1:-1;3807:765:6;28360:1502:9;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;28360:1502:9;;;;;;;;;;;;;-1:-1:-1;;;;;28360:1502:9;;;;;;;;;;;;;;;;;;;:::i;56990:96::-;;;:::i;845:194:6:-;;;:::i;2064:185::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2064:185:6;-1:-1:-1;;;;;2064:185:6;;:::i;5393:41:8:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5393:41:8;-1:-1:-1;;;;;5393:41:8;;:::i;1704:109:6:-;;;:::i;51516:582:9:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;51516:582:9;-1:-1:-1;;;;;51516:582:9;;:::i;35380:400::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;35380:400:9;;;;-1:-1:-1;;;;;35380:400:9;;;;;;;;;;;;;;;:::i;31244:971::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;31244:971:9;;;;-1:-1:-1;;;;;31244:971:9;;;;;;;;;;;;;;;;;;;:::i;23363:1757::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;23363:1757:9;;;;;;;;;;;;;-1:-1:-1;;;;;23363:1757:9;;;;;;;;;;;;;;;;;;;:::i;707:25:8:-;;;:::i;6039:68::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6039:68:8;;-1:-1:-1;;;;;6039:68:8;;;;;-1:-1:-1;;;;;6039:68:8;;:::i;3097:314:9:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3097:314:9;;-1:-1:-1;;;;;3097:314:9;;;;;-1:-1:-1;;;;;3097:314:9;;:::i;4217:50:8:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4217:50:8;-1:-1:-1;;;;;4217:50:8;;:::i;4394:51::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4394:51:8;-1:-1:-1;;;;;4394:51:8;;:::i;3911:41::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3911:41:8;-1:-1:-1;;;;;3911:41:8;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;5739:56;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5739:56:8;-1:-1:-1;;;;;5739:56:8;;:::i;18039:2131:9:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;18039:2131:9;;;;-1:-1:-1;;;;;18039:2131:9;;;;;;;;;;:::i;55842:192::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;55842:192:9;;;;;;;;:::i;1814:21:8:-;;;:::i;5055:48::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5055:48:8;-1:-1:-1;;;;;5055:48:8;;:::i;30353:422:9:-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;30353:422:9;;;;;;;;;;;;;-1:-1:-1;;;;;30353:422:9;;;;;;;;;;;;;;;;;;;:::i;2451:332::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;2451:332:9;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;2451:332:9;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;2451:332:9;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;2451:332:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;2451:332:9;;-1:-1:-1;2451:332:9;;-1:-1:-1;;;;;2451:332:9:i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;2451:332:9;;;;;;;;;;;;;;;;;1124:174;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1124:174:9;-1:-1:-1;;;;;1124:174:9;;:::i;53152:1178::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;53152:1178:9;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;53152:1178:9;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;53152:1178:9;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;53152:1178:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;53152:1178:9;;;;;;;;-1:-1:-1;53152:1178:9;;-1:-1:-1;;21:11;5:28;;2:2;;;46:1;43;36:12;2:2;53152:1178:9;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;53152:1178:9;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;53152:1178:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;53152:1178:9;;-1:-1:-1;;;;53152:1178:9;;;;;-1:-1:-1;53152:1178:9;;;;;;:::i;32547:338::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;32547:338:9;;;;-1:-1:-1;;;;;32547:338:9;;;;;;;;;;;;;;;;;;;:::i;6646:52:8:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6646:52:8;-1:-1:-1;;;;;6646:52:8;;:::i;6372:42::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6372:42:8;-1:-1:-1;;;;;6372:42:8;;:::i;338:36:3:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;338:36:3;;:::i;:::-;;;;-1:-1:-1;;;;;;338:36:3;;;;;;;;;;;;;;5208:124:9;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5208:124:9;-1:-1:-1;;;;;5208:124:9;;:::i;27383:484::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;27383:484:9;;;;;;;;;;;;;-1:-1:-1;;;;;27383:484:9;;;;;;;;;;;;;;;;;;;;;;;;:::i;21289:690::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;21289:690:9;;;;-1:-1:-1;;;;;21289:690:9;;;;;;;;;;;;;;;;;;;:::i;22366:405::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;22366:405:9;;;;-1:-1:-1;;;;;22366:405:9;;;;;;;;;;;;;;;;;;;;;;;;:::i;14767:355::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;14767:355:9;;;;-1:-1:-1;;;;;14767:355:9;;;;;;;;;;;;;;;:::i;4333:54:8:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4333:54:8;-1:-1:-1;;;;;4333:54:8;;:::i;2701:50::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;2701:50:8;;;;;;;;:::i;5642:310:9:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5642:310:9;;-1:-1:-1;;;;;5642:310:9;;;;;-1:-1:-1;;;;;5642:310:9;;:::i;15573:458::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;15573:458:9;;;;-1:-1:-1;;;;;15573:458:9;;;;;;;;;;:::i;1200:31:8:-;;;:::i;12817:1618:9:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;12817:1618:9;;;;-1:-1:-1;;;;;12817:1618:9;;;;;;;;;;:::i;5110:26:8:-;;;:::i;55346:312:9:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;55346:312:9;;;;;;;;:::i;4157:53:8:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4157:53:8;-1:-1:-1;;;;;4157:53:8;;:::i;8792:374:9:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;8792:374:9;;;;;;;;:::i;43629:640::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43629:640:9;-1:-1:-1;;;;;43629:640:9;;:::i;3057:305:6:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3057:305:6;;;;;;;;;;;;;;;-1:-1:-1;;;;;3057:305:6;;:::i;405:108:7:-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6225:68:8;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6225:68:8;;-1:-1:-1;;;;;6225:68:8;;;;;-1:-1:-1;;;;;6225:68:8;;:::i;25399:1381:9:-;25470:4;25554:21;25579;25604:18;25615:6;25604:10;:18::i;:::-;25553:69;;-1:-1:-1;25553:69:9;;-1:-1:-1;25651:24:9;;-1:-1:-1;25637:10:9;:38;;;;;;;;;25633:108;;25704:24;25699:30;25692:37;;;;;;25633:108;25762:16;25771:6;25762:8;:16::i;:::-;25757:86;;25807:23;25802:29;;25757:86;25916:13;25949;-1:-1:-1;;;;;25932:39:9;;25972:6;25932:47;;;;;;;;;;;;;-1:-1:-1;;;;;25932:47:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25932:47:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;25932:47:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;25932:47:9;;-1:-1:-1;25995:32:9;26013:6;25932:47;25995:17;:32::i;:::-;25990:103;;26056:24;26051:30;26044:37;;;;;;;25990:103;26178:8;26189:34;26204:6;26212:10;26189:14;:34::i;:::-;26178:45;-1:-1:-1;26238:27:9;;26234:70;;26289:3;-1:-1:-1;26282:10:9;;-1:-1:-1;;;26282:10:9;26234:70;26379:14;26425:26;26445:5;26425:19;:26::i;:::-;26404:47;;-1:-1:-1;26404:47:9;;-1:-1:-1;;26466:27:9;;;;:45;;-1:-1:-1;26497:14:9;;26466:45;26462:119;;;26540:28;26535:34;26528:41;;;;;;;;;26462:119;26654:10;-1:-1:-1;;;;;26654:19:9;;;26650:83;;;26702:18;26697:24;;26650:83;26757:14;26745:27;;;;;;;25399:1381;;;;:::o;8083:656:6:-;8154:4;8179:16;8188:6;8179:8;:16::i;:::-;8171:46;;;;;-1:-1:-1;;;8171:46:6;;;;;;;;;;;;-1:-1:-1;;;8171:46:6;;;;;;;;;;;;;;;8228:19;8250:22;8265:6;8250:14;:22::i;:::-;-1:-1:-1;;;;;8297:20:6;;8283:11;8297:20;;;:7;:20;;;;;:46;;;8228:44;;-1:-1:-1;8358:11:6;8354:52;;8393:1;8386:8;;;;;;8354:52;8430:11;-1:-1:-1;;;;;8420:21:6;:6;-1:-1:-1;;;;;8420:21:6;;8416:205;;-1:-1:-1;;;;;8477:15:6;;8458:16;8477:15;;;:7;:15;;;;;:41;;;8537:16;;8533:77;;8583:11;8574:20;;8533:77;8416:205;;3628:6:8;8639::6;:37;;8631:76;;;;;-1:-1:-1;;;8631:76:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;8725:6;8083:656;-1:-1:-1;;;8083:656:6:o;56238:639:9:-;56347:10;:8;:10::i;:::-;-1:-1:-1;;;;;56333:24:9;:10;-1:-1:-1;;;;;56333:24:9;;56325:65;;;;;-1:-1:-1;;;56325:65:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;56497:37;56522:11;56497:24;:37::i;:::-;56549:13;56545:203;;-1:-1:-1;;;;;56618:33:9;;;;;;:20;:33;;;;;56611:40;56545:203;;;56720:16;:14;:16::i;:::-;-1:-1:-1;;;;;56684:33:9;;;;;;:20;:33;;;;;:52;56545:203;-1:-1:-1;;;;;56758:33:9;;;;;;:20;:33;;;;;;;;;:44;;;56820:49;;;;;;;;;;;;;;;;;56238:639;;:::o;52606:208::-;52711:16;;;52725:1;52711:16;;;;;;;;;52684:24;;52711:16;;;;;;105:10:-1;52711:16:9;88:34:-1;136:17;;-1:-1;52711:16:9;52684:43;;52751:6;52738:7;52746:1;52738:10;;;;;;;;;;;;;:19;-1:-1:-1;;;;;52738:19:9;;;-1:-1:-1;;;;;52738:19:9;;;;;52768:38;52777:7;52786;52795:4;52801;52768:8;:38::i;:::-;52606:208;;;:::o;1575:147::-;1656:4;1680:34;1698:6;1706:7;1680:17;:34::i;:::-;1673:41;;1575:147;;;;;:::o;6500:52:8:-;;;;;;;;;;;;;:::o;2027:32::-;;;-1:-1:-1;;;;;2027:32:8;;:::o;2336:28::-;;;-1:-1:-1;;;;;2336:28:8;;:::o;4592:42::-;;;;;;;;;;;;;:::o;17228:370:9:-;17498:17;;:37;;;;;17534:1;17519:12;:16;17498:37;17494:97;;;17552:27;;;-1:-1:-1;;;17552:27:9;;;;;;;;;;;;;;;;;;;;;;;;;;;17494:97;17228:370;;;;:::o;40080:2243::-;40216:4;40222;40244:24;40253:14;40244:8;:24::i;:::-;40243:25;:56;;;;40273:26;40282:16;40273:8;:26::i;:::-;40272:27;40243:56;40239:130;;;-1:-1:-1;40329:23:9;;-1:-1:-1;40355:1:9;40316:41;;40239:130;40449:26;40478:24;40487:14;40478:8;:24::i;:::-;40449:53;;40513:28;40544:26;40553:16;40544:8;:26::i;:::-;40513:57;-1:-1:-1;40585:26:9;;;:58;;-1:-1:-1;40615:28:9;;40585:58;40581:126;;;40673:17;40660:35;-1:-1:-1;40693:1:9;;-1:-1:-1;40660:35:9;;-1:-1:-1;;40660:35:9;40581:126;41106:31;41141:28;41152:16;41141:10;:28::i;:::-;41100:69;;;;41180:25;41224:23;-1:-1:-1;;;;;41208:59:9;;41268:16;41208:77;;;;;;;;;;;;;-1:-1:-1;;;;;41208:77:9;-1:-1:-1;;;;;41208:77:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41208:77:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;41208:77:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;41208:77:9;;-1:-1:-1;41322:16:9;41349:20;;:::i;:::-;41380:21;;:::i;:::-;41412:22;;:::i;:::-;41937:91;41942:45;;;;;;;;41957:28;;41942:45;;;41989:38;;;;;;;;42004:21;41989:38;;;41937:4;:91::i;:::-;41925:103;;42052:34;42057:9;42068:17;42052:4;:34::i;:::-;42039:47;;42111:85;42116:40;;;;;;;;42131:23;42116:40;;;42158:37;;;;;;;;42173:20;42158:37;;;42111:4;:85::i;:::-;42097:99;;42221:39;42230:29;42235:10;42247:11;42230:4;:29::i;:::-;42221:8;:39::i;:::-;42286:14;;-1:-1:-1;42207:53:9;-1:-1:-1;;;;;;;;;40080:2243:9;;;;;;;:::o;4274:52:8:-;;;;;;;;;;;;;;;:::o;383:118:3:-;442:4;466:27;383:118;;:::o;42836:91:9:-;42907:12;42836:91;:::o;1564:40:8:-;;;;:::o;5005:43::-;;;;;;;;;;;;-1:-1:-1;;;;;5005:43:8;;:::o;11071:1096:9:-;11148:4;11220:21;11245:20;11269:18;11280:6;11269:10;:18::i;:::-;11219:68;;;;;11389:21;:45;11411:22;11426:6;11411:14;:22::i;:::-;-1:-1:-1;;;;;11389:45:9;;;;;;;;;;;;-1:-1:-1;11389:45:9;;;;11388:46;11380:76;;;;;-1:-1:-1;;;11380:76:9;;;;;;;;;;;;-1:-1:-1;;;11380:76:9;;;;;;;;;;;;;;;-1:-1:-1;;;;;11476:29:9;;;;;;:21;:29;;;;;;;;11475:30;11467:60;;;;;-1:-1:-1;;;11467:60:9;;;;;;;;;;;;-1:-1:-1;;;11467:60:9;;;;;;;;;;;;;;;11545:16;11554:6;11545:8;:16::i;:::-;11540:86;;11590:23;11585:29;11578:36;;;;;;11540:86;11693:24;11679:10;:38;;;;;;;;;11675:107;;11746:23;11741:29;;11675:107;11921:1;-1:-1:-1;;;;;11863:60:9;11880:12;-1:-1:-1;;;;;11863:38:9;;11902:6;11863:46;;;;;;;;;;;;;-1:-1:-1;;;;;11863:46:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11863:46:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11863:46:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11863:46:9;-1:-1:-1;;;;;11863:60:9;;11859:129;;;11952:23;11947:29;;11859:129;12144:14;12132:27;11071:1096;-1:-1:-1;;;;;11071:1096:9:o;5865:56:8:-;;;;;;;;;;;;-1:-1:-1;;;;;5865:56:8;;;-1:-1:-1;;;5865:56:8;;;;;:::o;6759:46::-;6801:4;6759:46;:::o;33947:260:9:-;34014:4;34020;34026;34044:9;34055:14;34071;34089:57;34129:7;34138:1;34141;34144;34089:39;:57::i;:::-;34043:103;;;;;;34172:3;34167:9;;;;;;;;34159:40;34178:9;;-1:-1:-1;34178:9:9;-1:-1:-1;33947:260:9;-1:-1:-1;;;33947:260:9:o;766:99::-;853:4;766:99;:::o;3807:765:6:-;3864:21;4069:18;;;;;;3973:6;4021:15;;;;;3864:21;4129:13;4112:32;;;;;;;;4099:45;;4194:13;-1:-1:-1;;;;;4177:44:6;;:46;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4177:46:6;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4177:46:6;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4177:46:6;4163:60;;;;;;;;:10;:60;;;;;;;;;4155:92;;;;;-1:-1:-1;;;4155:92:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;4276:26;4262:10;:40;;;;;;;;;4258:249;;;4342:1;4327:11;:16;;;;4319:61;;;;;-1:-1:-1;;;4319:61:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4258:249;;;4425:24;4411:10;:38;;;;;;;;;4407:100;;4466:29;;;-1:-1:-1;;;4466:29:6;;;;;;;;;;;;;;;;;;;;;;;;;;;4407:100;-1:-1:-1;3807:765:6;;;;;:::o;28360:1502:9:-;28511:4;28614:31;28649:28;28660:16;28649:10;:28::i;:::-;28608:69;;;;28694:29;28727:26;28738:14;28727:10;:26::i;:::-;28688:65;;;;28855:19;:53;28875:32;28890:16;28875:14;:32::i;:::-;-1:-1:-1;;;;;28855:53:9;;;;;;;;;;;;-1:-1:-1;28855:53:9;;;;28854:54;28846:82;;;;;-1:-1:-1;;;28846:82:9;;;;;;;;;;;;-1:-1:-1;;;28846:82:9;;;;;;;;;;;;;;;-1:-1:-1;;;;;28948:37:9;;;;;;:19;:37;;;;;;;;28947:38;28939:66;;;;;-1:-1:-1;;;28939:66:9;;;;;;;;;;;;-1:-1:-1;;;28939:66:9;;;;;;;;;;;;;;;29023:26;29032:16;29023:8;:26::i;:::-;29022:27;:56;;;;29054:24;29063:14;29054:8;:24::i;:::-;29053:25;29022:56;29018:125;;;29107:23;29102:29;29095:36;;;;;;29018:125;29258:43;29276:14;29292:8;29258:17;:43::i;:::-;29257:44;:94;;;;29306:45;29324:16;29342:8;29306:17;:45::i;:::-;29305:46;29257:94;29253:164;;;29380:24;29375:30;;29253:164;29498:21;-1:-1:-1;;;;;29485:44:9;;:46;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;29485:46:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;29485:46:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;29485:46:9;29433:48;;;-1:-1:-1;;;29433:48:9;;;;-1:-1:-1;;;;;29433:98:9;;;;:46;;;;;:48;;;;;29485:46;;29433:48;;;;;;;:46;:48;;;5:2:-1;;;;30:1;27;20:12;5:2;29433:48:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;29433:48:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;29433:48:9;-1:-1:-1;;;;;29433:98:9;;29429:167;;29560:23;29555:29;;29429:167;29839:14;29827:27;;;;28360:1502;;;;;;;;:::o;56990:96::-;57063:15;;-1:-1:-1;;;;;57063:15:9;56990:96;:::o;845:194:6:-;886:21;920:16;681:53:7;;;;;;;;;;;;;;;;;;1006:15:6;;982:50;-1:-1:-1;;;982:50:6:o;2064:185::-;2133:7;2160:81;2191:14;-1:-1:-1;;;;;2174:45:6;;:47;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2174:47:6;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2174:47:6;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2174:47:6;2223:1;2226:14;2160:13;:81::i;5393:41:8:-;;;;;;;;;;;;;:::o;1704:109:6:-;-1:-1:-1;;1704:109:6;:::o;51516:582:9:-;-1:-1:-1;;;;;51605:33:9;;51589:13;51605:33;;;:20;:33;;;;;;;51668:16;:14;:16::i;:::-;-1:-1:-1;;;;;51732:33:9;;51695:16;51732:33;;;:20;:33;;;;;;51649:35;;-1:-1:-1;51695:16:9;51714:52;;51649:35;;51714:4;:52::i;:::-;51695:71;;51795:1;51781:11;:15;:31;;;;;51811:1;51800:8;:12;51781:31;51777:314;;;51829:15;51847:27;51852:11;51865:8;51847:4;:27::i;:::-;-1:-1:-1;;;;;51920:23:9;;51889;51920;;;:10;:23;;;;;;51829:45;;-1:-1:-1;51889:23:9;51915:41;;51829:45;51915:4;:41::i;:::-;-1:-1:-1;;;;;51973:23:9;;;;;;:10;:23;;;;;;;;:44;;;;52032:20;:33;;;:47;;;-1:-1:-1;;51516:582:9;;;;:::o;35380:400::-;35556:4;35562;35568;35586:9;35597:14;35613;35631:90;35671:7;35680:12;35694;35708;35631:39;:90::i;:::-;35585:136;;;;;;35745:3;35740:9;;;;;;;;35732:40;-1:-1:-1;35751:9:9;;-1:-1:-1;35762:9:9;-1:-1:-1;;35380:400:9;;;;;;;;;:::o;31244:971::-;31355:4;31512:22;:46;31535:22;31550:6;31535:14;:22::i;:::-;-1:-1:-1;;;;;31512:46:9;;;;;;;;;;;;-1:-1:-1;31512:46:9;;;;31511:47;31503:78;;;;;-1:-1:-1;;;31503:78:9;;;;;;;;;;;;-1:-1:-1;;;31503:78:9;;;;;;;;;;;;;;;-1:-1:-1;;;;;31601:30:9;;;;;;:22;:30;;;;;;;;31600:31;31592:62;;;;;-1:-1:-1;;;31592:62:9;;;;;;;;;;;;-1:-1:-1;;;31592:62:9;;;;;;;;;;;;;;;31837:12;31852:50;31874:6;31882:3;31887:14;31852:21;:50::i;:::-;31837:65;-1:-1:-1;31917:31:9;;31913:78;;31972:7;-1:-1:-1;31965:14:9;;31913:78;32192:14;32180:27;;;31244:971;;;;;;;:::o;23363:1757::-;23524:4;23671:21;23700:28;23711:16;23700:10;:28::i;:::-;-1:-1:-1;23670:58:9;;-1:-1:-1;23757:24:9;;-1:-1:-1;23743:10:9;:38;;;;;;;;;23739:108;;;23810:24;23805:30;23798:37;;;;;23739:108;23864:24;23873:14;23864:8;:24::i;:::-;23863:25;:56;;;;23893:26;23902:16;23893:8;:26::i;:::-;23892:27;23863:56;23859:125;;;23948:23;23943:29;;23859:125;24099:43;24117:14;24133:8;24099:17;:43::i;:::-;24098:44;:94;;;;24147:45;24165:16;24183:8;24147:17;:45::i;:::-;24146:46;24098:94;24094:164;;;24221:24;24216:30;;24094:164;24347:9;24360:14;24378:37;24406:8;24378:27;:37::i;:::-;24346:69;;-1:-1:-1;24346:69:9;;-1:-1:-1;24437:14:9;;-1:-1:-1;24430:3:9;:21;;;;;;;;;24426:70;;24480:3;24475:9;;;;;;;;24468:16;;;;;;;24426:70;24510:14;24506:88;;24553:28;24548:34;;24506:88;24701:29;24734:26;24745:14;24734:10;:26::i;:::-;24695:65;;;;24771:18;24808:21;-1:-1:-1;;;;;24792:58:9;;24851:8;24861:14;24792:84;;;;;;;;;;;;;-1:-1:-1;;;;;24792:84:9;-1:-1:-1;;;;;24792:84:9;;;;;;-1:-1:-1;;;;;24792:84:9;-1:-1:-1;;;;;24792:84:9;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24792:84:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;24792:84:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;24792:84:9;24922:36;;;24792:84;24922:36;;;;;24937:19;;24922:36;;24792:84;;-1:-1:-1;24887:13:9;;24903:71;;24792:84;24903:18;:71::i;:::-;24887:87;;25003:8;24989:11;:22;24985:88;;;25040:20;25028:33;;;;;;;;;;24985:88;25097:14;25085:27;23363:1757;-1:-1:-1;;;;;;;;;;;;23363:1757:9:o;707:25:8:-;;;-1:-1:-1;;;;;707:25:8;;:::o;6039:68::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;3097:314:9:-;3175:4;3198:21;3223:18;3234:6;3223:10;:18::i;:::-;3192:49;-1:-1:-1;;;;;;;;3260:27:9;;:10;:27;3252:93;;;;-1:-1:-1;;;3252:93:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3368:34;3388:6;3396:5;3368:19;:34::i;:::-;3363:40;;;;;;;4217:50:8;;;;;;;;;;;;;;;:::o;4394:51::-;;;;;;;;;;;;;;;:::o;3911:41::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;5739:56::-;;;;;;;;;;;;-1:-1:-1;;;;;5739:56:8;;;-1:-1:-1;;;5739:56:8;;;;;:::o;18039:2131:9:-;18138:4;18163:21;18188:18;18199:6;18188:10;:18::i;:::-;18157:49;;;;18308:20;:44;18329:22;18344:6;18329:14;:22::i;:::-;-1:-1:-1;;;;;18308:44:9;;;;;;;;;;;;-1:-1:-1;18308:44:9;;;;18307:45;18299:74;;;;;-1:-1:-1;;;18299:74:9;;;;;;;;;;;;-1:-1:-1;;;18299:74:9;;;;;;;;;;;;;;;-1:-1:-1;;;;;18393:28:9;;;;;;:20;:28;;;;;;;;18392:29;18384:58;;;;;-1:-1:-1;;;18384:58:9;;;;;;;;;;;;-1:-1:-1;;;18384:58:9;;;;;;;;;;;;;;;18460:16;18469:6;18460:8;:16::i;:::-;18455:86;;18505:23;18500:29;18493:36;;;;;18455:86;18649:35;18667:6;18675:8;18649:17;:35::i;:::-;18644:106;;18713:24;18708:30;;18644:106;18766:16;18775:6;18766:8;:16::i;:::-;18762:84;;18816:17;18811:23;;18762:84;18967:14;18984:10;:34;18995:22;19010:6;18995:14;:22::i;:::-;-1:-1:-1;;;;;18984:34:9;;;;;;;;;;;;;;;;;-1:-1:-1;18984:34:9;;;;19055:18;;;;;:10;:18;;;;;;18984:34;;-1:-1:-1;19088:14:9;;;:77;;-1:-1:-1;19107:23:9;;;;;:57;;;19155:9;19134:18;:30;19107:57;19084:140;;;19194:18;19182:30;;19084:140;19301:14;;19297:267;;19332:17;19365:13;-1:-1:-1;;;;;19352:40:9;;19393:6;19352:48;;;;;;;;;;;;;-1:-1:-1;;;;;19352:48:9;-1:-1:-1;;;;;19352:48:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;19352:48:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;19352:48:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;19352:48:9;;-1:-1:-1;19415:21:9;19439:32;19352:48;19458:12;19439:4;:32::i;:::-;19415:56;;19513:9;19494:16;:28;19486:66;;;;;-1:-1:-1;;;19486:66:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;19297:267;;;19577:9;19590:14;19608:74;19648:8;19658:6;19666:1;19669:12;19608:39;:74::i;:::-;19576:106;;-1:-1:-1;19576:106:9;;-1:-1:-1;19704:14:9;;-1:-1:-1;19697:3:9;:21;;;;;;;;;19693:70;;19747:3;19742:9;;;;;;;;19735:16;;;;;;;;;19693:70;19777:13;;19773:87;;19819:28;19814:34;;19773:87;-1:-1:-1;20147:14:9;;18039:2131;-1:-1:-1;;;;;;;;18039:2131:9:o;55842:192::-;55935:10;:8;:10::i;:::-;-1:-1:-1;;;;;55921:24:9;:10;-1:-1:-1;;;;;55921:24:9;;55913:65;;;;;-1:-1:-1;;;55913:65:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;55989:37;56009:6;56017:8;55989:19;:37::i;:::-;55842:192;;:::o;1814:21:8:-;;;;:::o;5055:48::-;;;;;;;;;;;;;:::o;30353:422:9:-;;;;;;:::o;2451:332::-;2515:13;2541:8;2552:7;:14;2541:25;;2579:21;2614:3;2603:15;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;2603:15:9;-1:-1:-1;2579:39:9;-1:-1:-1;2634:6:9;2629:120;2650:3;2646:1;:7;2629:120;;;2693:43;2713:7;2721:1;2713:10;;;;;;;;;;;;;;2725;2693:19;:43::i;:::-;2688:49;;;;;;;;2675:7;2683:1;2675:10;;;;;;;;;;;;;;;;;:62;2655:3;;2629:120;;;-1:-1:-1;2768:7:9;2451:332;-1:-1:-1;;;2451:332:9:o;1124:174::-;1185:16;1214:25;1242:13;:22;1256:7;-1:-1:-1;;;;;1242:22:9;-1:-1:-1;;;;;1242:22:9;;;;;;;;;;;;1214:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1214:50:9;;;;;;;;;;;;;;;;-1:-1:-1;1214:50:9;;1124:174;-1:-1:-1;;;;;;;1124:174:9:o;53152:1178::-;53277:6;53272:1051;53293:7;:14;53289:1;:18;53272:1051;;;53329:14;53346:7;53354:1;53346:10;;;;;;;;;;;;;;53329:27;;53379:16;53388:6;53379:8;:16::i;:::-;53371:50;;;;;-1:-1:-1;;;53371:50:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;53453:4;53440:17;;;;53436:532;;;53484:21;53509:18;53520:6;53509:10;:18::i;:::-;53478:49;;;;53546:22;;:::i;:::-;53571:64;;;;;;;;53599:13;-1:-1:-1;;;;;53586:39:9;;53626:6;53586:47;;;;;;;;;;;;;-1:-1:-1;;;;;53586:47:9;-1:-1:-1;;;;;53586:47:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;53586:47:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;53586:47:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;53586:47:9;53571:64;;53546:89;-1:-1:-1;53654:41:9;53675:6;53546:89;53654:20;:41::i;:::-;53719:6;53714:239;53735:7;:14;53731:1;:18;53714:239;;;53779:54;53801:6;53809:7;53817:1;53809:10;;;;;;;;;;;;;;53821:11;53779:21;:54::i;:::-;53881:52;53898:7;53906:1;53898:10;;;;;;;;;;;;;;53910;:22;53921:7;53929:1;53921:10;;;;;;;;;;;;;;-1:-1:-1;;;;;53910:22:9;-1:-1:-1;;;;;53910:22:9;;;;;;;;;;;;;53881:16;:52::i;:::-;53856:10;:22;53867:7;53875:1;53867:10;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;53856:22:9;;;;;;;;;;;-1:-1:-1;53856:22:9;:77;53751:3;;53714:239;;;;53436:532;;;53999:4;53986:17;;;;53982:330;;;54024:28;54045:6;54024:20;:28::i;:::-;54076:6;54071:226;54092:7;:14;54088:1;:18;54071:226;;;54136:41;54158:6;54166:7;54174:1;54166:10;;;;;;;;;;;;;;54136:21;:41::i;:::-;54225:52;54242:7;54250:1;54242:10;;;;;;;;;;;;;;54254;:22;54265:7;54273:1;54265:10;;;;;;;54225:52;54200:10;:22;54211:7;54219:1;54211:10;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;54200:22:9;;;;;;;;;;;-1:-1:-1;54200:22:9;:77;54108:3;;54071:226;;;;53982:330;-1:-1:-1;53309:3:9;;53272:1051;;6646:52:8;;;;;;;;;;;;;:::o;6372:42::-;;;;;;;;;;;;;:::o;338:36:3:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5208:124:9:-;5262:4;5286:38;5305:6;5313:10;5286:18;:38::i;27383:484::-;;;;;;;:::o;21289:690::-;21407:4;21588:16;21597:6;21588:8;:16::i;:::-;21583:86;;-1:-1:-1;21633:23:9;21621:36;;4333:54:8;;;;;;;;;;;;;;;:::o;2701:50::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2701:50:8;;-1:-1:-1;2701:50:8;;-1:-1:-1;2701:50:8:o;5642:310:9:-;5719:4;5742:21;5767:18;5778:6;5767:10;:18::i;:::-;5736:49;-1:-1:-1;;;;;;;;5804:27:9;;:10;:27;5796:91;;;;-1:-1:-1;;;5796:91:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5910:33;5929:6;5937:5;5910:18;:33::i;15573:458::-;15672:4;15691:12;15706:53;15728:6;15736:8;15746:12;15706:21;:53::i;:::-;15691:68;-1:-1:-1;15776:31:9;;15772:78;;15831:7;-1:-1:-1;15824:14:9;;1200:31:8;;;;:::o;12817:1618:9:-;12905:4;13091:18;13111:21;13136:18;13147:6;13136:10;:18::i;:::-;13087:67;;;;;13201:13;-1:-1:-1;;;;;13188:47:9;;:49;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;13188:49:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;13188:49:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;13188:49:9;13173:64;;;;;13165:97;;;;;-1:-1:-1;;;13165:97:9;;;;;;;;;;;;-1:-1:-1;;;13165:97:9;;;;;;;;;;;;;;;13281:10;-1:-1:-1;;;;;13281:27:9;;;13273:65;;;;;-1:-1:-1;;;13273:65:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;13431:20;13454:22;13469:6;13454:14;:22::i;:::-;-1:-1:-1;;;;;13496:32:9;;;;;;:18;:32;;;;;;13431:45;;-1:-1:-1;13496:32:9;;13495:33;13487:60;;;;;-1:-1:-1;;;13487:60:9;;;;;;;;;;;;-1:-1:-1;;;13487:60:9;;;;;;;;;;;;;;;-1:-1:-1;;;;;13567:26:9;;;;;;:18;:26;;;;;;;;13566:27;13558:54;;;;;-1:-1:-1;;;13558:54:9;;;;;;;;;;;;-1:-1:-1;;;13558:54:9;;;;;;;;;;;;;;;13684:22;13693:12;13684:8;:22::i;:::-;13679:92;;13735:23;13723:36;;;;;;;13679:92;13788:16;13797:6;13788:8;:16::i;:::-;13783:473;;13921:8;13932:30;13955:6;13932:22;:30::i;:::-;13921:41;-1:-1:-1;13981:27:9;;13977:78;;14036:3;-1:-1:-1;14029:10:9;;-1:-1:-1;;;14029:10:9;13977:78;14108:16;14117:6;14108:8;:16::i;:::-;14104:141;;14157:72;14162:17;14181:47;14157:4;:72::i;:::-;14150:79;;;;;;;;14104:141;13783:473;;14412:14;14400:27;12817:1618;-1:-1:-1;;;;;;;12817:1618:9:o;5110:26:8:-;;;;:::o;55346:312:9:-;55437:10;:8;:10::i;:::-;-1:-1:-1;;;;;55423:24:9;:10;-1:-1:-1;;;;;55423:24:9;;55415:61;;;;;-1:-1:-1;;;55415:61:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;55487:15;55505:35;55522:9;55533:6;55505:16;:35::i;:::-;55487:53;-1:-1:-1;55559:15:9;;55551:54;;;;;-1:-1:-1;;;55551:54:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;55621:29;;;-1:-1:-1;;;;;55621:29:9;;;;;;;;;;;;;;;;;;;;;;;55346:312;;;:::o;4157:53:8:-;;;;;;;;;;;;;;;:::o;8792:374:9:-;8890:4;8959:10;:8;:10::i;:::-;-1:-1:-1;;;;;8945:24:9;:10;-1:-1:-1;;;;;8945:24:9;;8941:135;;8993:71;8998:18;9018:45;8993:4;:71::i;:::-;8986:78;;;;8941:135;9093:65;9122:6;9130:27;9093:28;:65::i;43629:640::-;43684:4;43719:22;43734:6;43719:14;:22::i;:::-;-1:-1:-1;;;;;43709:32:9;:6;-1:-1:-1;;;;;43709:32:9;;;43701:73;;;;;-1:-1:-1;;;43701:73:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;43793:16;43802:6;43793:8;:16::i;:::-;43785:46;;;;;-1:-1:-1;;;43785:46:9;;;;;;;;;;;;-1:-1:-1;;;43785:46:9;;;;;;;;;;;;;;;43848:21;43873:18;43884:6;43873:10;:18::i;:::-;43842:49;;;;43902:16;43934:13;-1:-1:-1;;;;;43921:46:9;;:48;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43921:48:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43921:48:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43921:48:9;;-1:-1:-1;43998:23:9;:21;:23::i;:::-;-1:-1:-1;;;;;43986:35:9;:8;-1:-1:-1;;;;;43986:35:9;;43982:136;;;44088:6;44081:13;;;;;;43982:136;44130:16;44162:13;-1:-1:-1;;;;;44149:41:9;;44191:6;44149:49;;;;;;;;;;;;;-1:-1:-1;;;;;44149:49:9;-1:-1:-1;;;;;44149:49:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;44149:49:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;44149:49:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;44149:49:9;44216:6;;:45;;;-1:-1:-1;;;44216:45:9;;-1:-1:-1;;;;;44216:45:9;;;;;;;;;;;;;;;44149:49;;-1:-1:-1;44216:6:9;;;:25;;:45;;;;;44149:49;;44216:45;;;;;;;;:6;:45;;;5:2:-1;;;;30:1;27;20:12;5:2;44216:45:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;44216:45:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;44216:45:9;;43629:640;-1:-1:-1;;;;;43629:640:9:o;3057:305:6:-;3167:14;3194:18;3268:2;3253:10;3246:18;;;;;;;;-1:-1:-1;;;3223:19:6;;;3246:24;;;;;;;;3223:48;3291:28;;;-1:-1:-1;;;;;3322:31:6;;3291:62;;-1:-1:-1;;3057:305:6;;;;;:::o;405:108:7:-;450:10;405:108;:::o;6225:68:8:-;;;;;;;;;;;;;;;;;;;;;;;;:::o;7327:215:6:-;7384:4;7407:7;:31;7415:22;7430:6;7415:14;:22::i;:::-;-1:-1:-1;;;;;7407:31:6;;;;;;;;;;;;-1:-1:-1;7407:31:6;:41;;;7401:89;;-1:-1:-1;7473:5:6;7466:12;;7401:89;-1:-1:-1;;;;;;7508:15:6;;;;;:7;:15;;;;;:25;;;;7327:215::o;1999:158:9:-;-1:-1:-1;;;;;2106:15:9;;2082:4;2106:15;;;:7;:15;;;;;;;;-1:-1:-1;;;;;2106:43:9;;;;:34;;:43;;;;;;;;1999:158;;;;:::o;2467:171:6:-;2567:62;2558:71;;2467:171::o;3998:157:16:-;4063:10;;:::i;:::-;4092:56;;;;;;;;410:4;4107:28;4112:1;:10;;;4124:1;:10;;;4107:4;:28::i;:::-;:39;;;;;;4092:56;;4085:63;3998:157;-1:-1:-1;;;3998:157:16:o;4161:131::-;4220:10;;:::i;:::-;4249:36;;;;;;;;4264:19;4269:1;:10;;;4281:1;4264:4;:19::i;:::-;4249:36;;4242:43;4161:131;-1:-1:-1;;;4161:131:16:o;5253:162::-;5318:10;;:::i;:::-;5347:61;;;;;;;;5362:44;5367:26;5372:1;:10;;;410:4;5367;:26::i;:::-;5395:10;;5362:4;:44::i;789:210::-;969:12;410:4;969:23;;;789:210::o;36567:3005:9:-;36753:5;36760:4;36766;36785:37;;:::i;:::-;-1:-1:-1;;;;;36963:22:9;;36870:9;36963:22;;;:13;:22;;;;;;;;36937:48;;;;;;;;;;;;;;;;;:23;;:48;;36963:22;36937:48;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;36937:48:9;;;;;;;;;;;;;;;;-1:-1:-1;36937:48:9;;-1:-1:-1;37001:6:9;;-1:-1:-1;;;;36996:2225:9;37017:6;:13;37013:1;:17;36996:2225;;;37054:13;37070:6;37077:1;37070:9;;;;;;;;;;;;;;37054:25;;37100:20;37124:17;37135:5;37124:10;:17::i;:::-;37094:47;;;;37318:12;-1:-1:-1;;;;;37302:48:9;;37351:7;37360:5;37302:64;;;;;;;;;;;;;-1:-1:-1;;;;;37302:64:9;-1:-1:-1;;;;;37302:64:9;;;;;;-1:-1:-1;;;;;37302:64:9;-1:-1:-1;;;;;37302:64:9;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37302:64:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;37302:64:9;;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;37302:64:9;;;;;;;;;;;;;;;;;37273:25;;37226:140;37253:18;;;37226:140;;;;37233:18;;;37226:140;;;;37302:64;-1:-1:-1;37385:9:9;;37381:166;;-1:-1:-1;37504:20:9;;-1:-1:-1;37526:1:9;;-1:-1:-1;37526:1:9;;-1:-1:-1;37496:35:9;;-1:-1:-1;;;;;37496:35:9;37381:166;37585:48;;;;;;;;37600:31;37625:5;37600:24;:31::i;:::-;37585:48;;37561:21;;;:72;37668:42;;;;;;;;;-1:-1:-1;;;37683:25:9;37668:42;;37648:17;;;:62;37808:15;37817:5;37808:8;:15::i;:::-;37781:24;;;:42;;;37838:102;;-1:-1:-1;37900:17:9;;-1:-1:-1;37919:1:9;;-1:-1:-1;37919:1:9;;-1:-1:-1;37892:32:9;;-1:-1:-1;;;;;37892:32:9;37838:102;37973:41;;;;;;;;;37988:24;;;;37973:41;;37954:16;;;:60;38156:21;;;;38179:17;;;;38146:70;;38151:46;;:4;:46::i;:::-;38199:4;:16;;;38146:4;:70::i;:::-;38125:18;;;:91;;;38363:18;;;;38383;;38317:85;;38125:91;38363:18;38317:25;:85::i;:::-;38296:106;;38541:16;;;;38559:18;;;;38579:25;;;;38515:90;;38541:16;38559:18;38515:25;:90::i;:::-;38487:25;;;:118;-1:-1:-1;;;;;38693:21:9;;;;;;;38689:521;;;38870:86;38896:4;:18;;;38916:12;38930:4;:25;;;38870;:86::i;:::-;38842:25;;;:114;;;39136:16;;;;39110:84;;39154:12;;39110:25;:84::i;:::-;39082:25;;;:112;38689:521;-1:-1:-1;;37032:3:9;;36996:2225;;;-1:-1:-1;39330:25:9;;;;39309:18;;:46;39305:260;;;-1:-1:-1;;39417:25:9;;;;39396:18;;39380:14;;-1:-1:-1;39396:46:9;;-1:-1:-1;39380:14:9;;-1:-1:-1;39372:74:9;;39305:260;-1:-1:-1;;39534:18:9;;39506:25;;;;;39487:14;;-1:-1:-1;39487:14:9;;-1:-1:-1;39506:46:9;;-1:-1:-1;39479:74:9;;3713:118:16;3766:4;3789:35;3794:1;3797;3789:35;;;;;;;;;;;;;;;;;:4;:35::i;4878:120::-;4931:4;4954:37;4959:1;4962;4954:37;;;;;;;;;;;;;;;;;:4;:37::i;3096:114::-;3149:4;3172:31;3177:1;3180;3172:31;;;;;;;;;;;;;;;;;:4;:31::i;16039:847:9:-;16146:4;16168:16;16177:6;16168:8;:16::i;:::-;16163:86;;16213:23;16208:29;16201:36;;;;16163:86;16360:35;16378:6;16386:8;16360:17;:35::i;:::-;16355:96;;16424:14;16419:20;;16355:96;16556:9;16569:14;16587:74;16627:8;16637:6;16645:12;16659:1;16587:39;:74::i;:::-;16555:106;;-1:-1:-1;16555:106:9;;-1:-1:-1;16683:14:9;;-1:-1:-1;16676:3:9;:21;;;;;;;;;16672:70;;16726:3;16721:9;;;;;;;;16714:16;;;;;;16672:70;16756:13;;16752:87;;16798:28;16793:34;;16752:87;16863:14;16851:27;16039:847;-1:-1:-1;;;;;;16039:847:9:o;34556:179::-;34633:5;34640:4;34646;34670:57;34710:7;34719:1;34722;34725;34670:39;:57::i;:::-;34663:64;;;;;;34556:179;;;;;:::o;1107:171:16:-;1185:4;1201:18;;:::i;:::-;1222:15;1227:1;1230:6;1222:4;:15::i;:::-;1201:36;;1254:17;1263:7;1254:8;:17::i;3704:1133:9:-;3785:5;3808:16;3817:6;3808:8;:16::i;:::-;3803:130;;-1:-1:-1;3898:23:9;3891:30;;3803:130;3949:35;3967:6;3975:8;3949:17;:35::i;:::-;:43;;3988:4;3949:43;3945:128;;;-1:-1:-1;4047:14:9;4040:21;;3945:128;4123:9;;-1:-1:-1;;;;;4089:23:9;;;;;;:13;:23;;;;;:30;:43;4085:175;;-1:-1:-1;4227:21:9;4220:28;;4085:175;-1:-1:-1;;;;;4648:15:9;;;;;;:7;:15;;;;;;;;-1:-1:-1;;;;;4648:44:9;;;;;:34;;;;:44;;;;;:51;;-1:-1:-1;;4648:51:9;4695:4;4648:51;;;;;;4710:13;:23;;;;;27:10:-1;;23:18;;;45:23;;4710:36:9;;;;;;;;;;;-1:-1:-1;;;;;;4710:36:9;;;;;4764:31;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4815:14:9;3704:1133;;;;:::o;44560:1466::-;-1:-1:-1;;;;;44663:17:9;;44640:20;44663:17;;;:9;:17;;;;;;44695:20;;44691:1175;;44832:21;44857:18;44868:6;44857:10;:18::i;:::-;44825:50;;;;44890:22;;:::i;:::-;44915:64;;;;;;;;44943:13;-1:-1:-1;;;;;44930:39:9;;44970:6;44930:47;;;;;;;;;;;;;-1:-1:-1;;;;;44930:47:9;-1:-1:-1;;;;;44930:47:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;44930:47:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;44930:47:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;44930:47:9;44915:64;;44890:89;-1:-1:-1;44994:28:9;45015:6;44994:20;:28::i;:::-;45037:41;45058:6;45066:11;45037:20;:41::i;:::-;44691:1175;;;;;45100:13;;45096:770;;45173:16;45182:6;45173:8;:16::i;:::-;45165:53;;;;;-1:-1:-1;;;45165:53:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;45239:22:9;;;;;;:14;:22;;;;;:28;-1:-1:-1;;;;;45239:28:9;:33;:70;;;;-1:-1:-1;;;;;;45276:22:9;;;;;;:14;:22;;;;;:28;-1:-1:-1;;;45276:28:9;;;;:33;45239:70;45235:302;;;45355:166;;;;;;;;6801:4:8;-1:-1:-1;;;;;45355:166:9;;;;;45445:56;45452:16;:14;:16::i;:::-;45445:56;;;;;;;;;;;;;;;;;:6;:56::i;:::-;45355:166;;;;;;;-1:-1:-1;;;;;45330:22:9;;;;;;:14;:22;;;;;;;;:191;;;;;;;;;;;;-1:-1:-1;;;45330:191:9;-1:-1:-1;;;;;45330:191:9;;;-1:-1:-1;;;;;;45330:191:9;;;;;;;;;;;;;;45235:302;-1:-1:-1;;;;;45557:22:9;;;;;;:14;:22;;;;;:28;-1:-1:-1;;;;;45557:28:9;:33;:70;;;;-1:-1:-1;;;;;;45594:22:9;;;;;;:14;:22;;;;;:28;-1:-1:-1;;;45594:28:9;;;;:33;45557:70;45553:302;;;45673:166;;;;;;;;6801:4:8;-1:-1:-1;;;;;45673:166:9;;;;;45763:56;45770:16;:14;:16::i;45763:56::-;45673:166;;;;;;;-1:-1:-1;;;;;45648:22:9;;;;;;:14;:22;;;;;;;;:191;;;;;;;;;;;;-1:-1:-1;;;45648:191:9;-1:-1:-1;;;;;45648:191:9;;;-1:-1:-1;;;;;;45648:191:9;;;;;;;;;;;;;;45553:302;45901:8;45882:15;:27;45878:141;;-1:-1:-1;;;;;45926:17:9;;;;;;:9;:17;;;;;;;;;:28;;;45974:33;;;;;;;;;;;;;;;;;44560:1466;;;:::o;47464:1178::-;-1:-1:-1;;;;;47597:22:9;;47560:34;47597:22;;;:14;:22;;;;;;;;47649:9;:17;;;;;;47597:22;;47696:16;:14;:16::i;:::-;47765:17;;47677:35;;-1:-1:-1;47723:16:9;;47742:42;;47677:35;;-1:-1:-1;;;47765:17:9;;;;47742:4;:42::i;:::-;47723:61;;47813:1;47799:11;:15;:34;;;;;47832:1;47818:11;:15;47799:34;47795:840;;;47856:21;47881:18;47892:6;47881:10;:18::i;:::-;47850:49;;;;47914:17;47934:73;47952:13;-1:-1:-1;;;;;47939:40:9;;47980:6;47939:48;;;;;;;;;;;;;-1:-1:-1;;;;;47939:48:9;-1:-1:-1;;;;;47939:48:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;47939:48:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;47939:48:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;47939:48:9;47989:17;47934:4;:73::i;:::-;47914:93;;48022:15;48040:30;48045:11;48058;48040:4;:30::i;:::-;48022:48;;48085:19;;:::i;:::-;48122:1;48107:12;:16;:77;;48163:21;;;;;;;;48181:1;48163:21;;;48107:77;;;48126:34;48135:10;48147:12;48126:8;:34::i;:::-;48085:99;;48199:19;;:::i;:::-;48226:37;;;;;;;;;48244:17;;-1:-1:-1;;;;;48244:17:9;48226:37;;48221:50;;48265:5;48221:4;:50::i;:::-;48199:72;;48311:187;;;;;;;;48352:53;48360:5;:14;;;48352:53;;;;;;;;;;;;;;;;;:7;:53::i;:::-;-1:-1:-1;;;;;48311:187:9;;;;;48431:51;48438:11;48431:51;;;;;;;;;;;;;;;;;:6;:51::i;:::-;48311:187;;;;;;;-1:-1:-1;;;;;48286:22:9;;;;;;:14;:22;;;;;;;;:212;;;;;;;;;;;;-1:-1:-1;;;48286:212:9;-1:-1:-1;;;;;48286:212:9;;;-1:-1:-1;;;;;;48286:212:9;;;;;;;;;;;;;;-1:-1:-1;47795:840:9;;-1:-1:-1;;;;47795:840:9;;48520:15;;48516:119;;48572:51;48579:11;48572:51;;;;;;;;;;;;;;;;;:6;:51::i;:::-;48552:71;;;;;;;-1:-1:-1;;;48552:71:9;-1:-1:-1;;;;;48552:71:9;;;;;;47464:1178;;;;;;:::o;50286:1042::-;-1:-1:-1;;;;;50438:22:9;;50401:34;50438:22;;;:14;:22;;;;;50471:25;;:::i;:::-;-1:-1:-1;50499:37:9;;;;;;;;;50517:17;;-1:-1:-1;;;;;50517:17:9;50499:37;;50547:27;;:::i;:::-;-1:-1:-1;50577:54:9;;;;;;;;;-1:-1:-1;;;;;50595:24:9;;-1:-1:-1;50595:24:9;;;:16;:24;;;;;-1:-1:-1;;;;;50595:34:9;;;;;;;;;;;;;50577:54;;50679:20;;50642:34;;;;;;;:57;;;;50716:22;;:26;50712:609;;50759:24;;:::i;:::-;50786:32;50791:11;50804:13;50786:4;:32::i;:::-;50759:59;;50839:21;50864:18;50875:6;50864:10;:18::i;:::-;50833:49;;;;50897:19;50919:93;50940:13;-1:-1:-1;;;;;50924:50:9;;50975:8;50985:6;50924:68;;;;;;;;;;;;;-1:-1:-1;;;;;50924:68:9;-1:-1:-1;;;;;50924:68:9;;;;;;-1:-1:-1;;;;;50924:68:9;-1:-1:-1;;;;;50924:68:9;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;50919:93:9;50897:115;;51027:18;51048:32;51053:14;51069:10;51048:4;:32::i;:::-;-1:-1:-1;;;;;51123:20:9;;51095;51123;;;:10;:20;;;;;;51027:53;;-1:-1:-1;51095:20:9;51118:41;;51027:53;51118:4;:41::i;:::-;-1:-1:-1;;;;;51174:20:9;;;;;;:10;:20;;;;;;;;;:38;;;51288:20;;51232:77;;;;;;;;;;;51095:64;;-1:-1:-1;51174:20:9;;-1:-1:-1;;;;;51232:77:9;;;;;;;;;;;;50712:609;;;;;50286:1042;;;;;;:::o;54678:337::-;54749:4;54766:7;54780:15;:13;:15::i;:::-;54827:28;;;-1:-1:-1;;;54827:28:9;;54849:4;54827:28;;;;;;54766:30;;-1:-1:-1;54807:17:9;;-1:-1:-1;;;;;54827:13:9;;;;;:28;;;;;;;;;;;;;;:13;:28;;;5:2:-1;;;;30:1;27;20:12;5:2;54827:28:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;54827:28:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;54827:28:9;;-1:-1:-1;54870:10:9;;;;;:36;;;54894:12;54884:6;:22;;54870:36;54866:118;;;54923:3;-1:-1:-1;;;;;54923:12:9;;54936:4;54942:6;54923:26;;;;;;;;;;;;;-1:-1:-1;;;;;54923:26:9;-1:-1:-1;;;;;54923:26:9;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54923:26:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;54923:26:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;54971:1:9;;-1:-1:-1;54964:8:9;;-1:-1:-1;;;54964:8:9;54866:118;-1:-1:-1;55001:6:9;;54678:337;-1:-1:-1;;;54678:337:9:o;46184:1122::-;-1:-1:-1;;;;;46287:22:9;;46250:34;46287:22;;;:14;:22;;;;;;;;46339:9;:17;;;;;;46287:22;;46386:16;:14;:16::i;:::-;46455:17;;46367:35;;-1:-1:-1;46413:16:9;;46432:42;;46367:35;;-1:-1:-1;;;46455:17:9;;;;46432:4;:42::i;:::-;46413:61;;46503:1;46489:11;:15;:34;;;;;46522:1;46508:11;:15;46489:34;46485:814;;;46546:21;46571:18;46582:6;46571:10;:18::i;:::-;46540:49;;;;46604:17;46637:13;-1:-1:-1;;;;;46624:39:9;;46664:6;46624:47;;;;;;;;;;;;;-1:-1:-1;;;;;46624:47:9;-1:-1:-1;;;;;46624:47:9;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;46624:47:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;46624:47:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;46624:47:9;;-1:-1:-1;46686:15:9;46704:30;46709:11;46722;46704:4;:30::i;:::-;46686:48;;46749:19;;:::i;:::-;46786:1;46771:12;:16;:77;;46827:21;;;;;;;;46845:1;46827:21;;;46771:77;;;46790:34;46799:10;46811:12;46790:8;:34::i;:::-;46749:99;;46863:19;;:::i;:::-;46890:37;;;;;;;;;46908:17;;-1:-1:-1;;;;;46908:17:9;46890:37;;46885:50;;46929:5;46885:4;:50::i;:::-;46863:72;;46975:187;;;;;;;;47016:53;47024:5;:14;;;47016:53;;;;;;;;;;;;;;;;;:7;:53::i;:::-;-1:-1:-1;;;;;46975:187:9;;;;;47095:51;47102:11;47095:51;;;;;;;;;;;;;;;;;:6;:51::i;:::-;46975:187;;;;;;;-1:-1:-1;;;;;46950:22:9;;;;;;:14;:22;;;;;;;;:212;;;;;;;;;;;;-1:-1:-1;;;46950:212:9;-1:-1:-1;;;;;46950:212:9;;;-1:-1:-1;;;;;;46950:212:9;;;;;;;;;;;;;;-1:-1:-1;46485:814:9;;-1:-1:-1;;;;46485:814:9;;47184:15;;47180:119;;47236:51;47243:11;47236:51;;;;;;;;;;;;;;;;;:6;:51::i;:::-;47216:71;;;;;;;-1:-1:-1;;;47216:71:9;-1:-1:-1;;;;;47216:71:9;;;;;;46184:1122;;;;;:::o;48896:1035::-;-1:-1:-1;;;;;49018:22:9;;48981:34;49018:22;;;:14;:22;;;;;49051:25;;:::i;:::-;-1:-1:-1;49079:37:9;;;;;;;;;49097:17;;-1:-1:-1;;;;;49097:17:9;49079:37;;49127:27;;:::i;:::-;-1:-1:-1;49157:54:9;;;;;;;;;-1:-1:-1;;;;;49175:24:9;;-1:-1:-1;49175:24:9;;;:16;:24;;;;;-1:-1:-1;;;;;49175:34:9;;;;;;;;;;;;;49157:54;;49259:20;;49222:34;;;;;;;:57;;;;49296:22;;:27;:55;;;;-1:-1:-1;49327:20:9;;:24;;49296:55;49292:128;;;6801:4:8;49368:40:9;;49292:128;49432:24;;:::i;:::-;49459:32;49464:11;49477:13;49459:4;:32::i;:::-;49432:59;;49508:21;49533:18;49544:6;49533:10;:18::i;:::-;49584:58;;;-1:-1:-1;;;49584:58:9;;-1:-1:-1;;;;;49584:58:9;;;;;;;-1:-1:-1;;;;;49584:58:9;;;;;;;;49502:49;;-1:-1:-1;49562:19:9;;-1:-1:-1;49584:40:9;;;;-1:-1:-1;49584:40:9;;:58;;;;;;;;;;;;;;:40;:58;;;5:2:-1;;;;30:1;27;20:12;5:2;49584:58:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;49584:58:9;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;49584:58:9;;-1:-1:-1;49653:18:9;49674:32;49584:58;49695:10;49674:4;:32::i;:::-;-1:-1:-1;;;;;49745:20:9;;49717;49745;;;:10;:20;;;;;;49653:53;;-1:-1:-1;49717:20:9;49740:41;;49653:53;49740:4;:41::i;:::-;-1:-1:-1;;;;;49792:20:9;;;;;;:10;:20;;;;;;;;;:38;;;49902:20;;49846:77;;;;;;;;;;;49717:64;;-1:-1:-1;49792:20:9;;-1:-1:-1;;;;;49846:77:9;;;;;;;;;;;;48896:1035;;;;;;;;;;:::o;5960:2451::-;6040:4;6103:16;6112:6;6103:8;:16::i;:::-;6098:86;;6148:23;6143:29;;6098:86;6281:21;6306:18;6317:6;6306:10;:18::i;:::-;6275:49;;;;6336:9;6347:15;6364;6401:13;-1:-1:-1;;;;;6385:49:9;;6435:8;6445:6;6385:67;;;;;;;;;;;;;-1:-1:-1;;;;;6385:67:9;-1:-1:-1;;;;;6385:67:9;;;;;;-1:-1:-1;;;;;6385:67:9;-1:-1:-1;;;;;6385:67:9;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;6385:67:9;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;6385:67:9;;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;6385:67:9;;;;;;;;;;;;;-1:-1:-1;6385:67:9;;-1:-1:-1;6385:67:9;-1:-1:-1;6471:9:9;;6463:59;;;;-1:-1:-1;;;6463:59:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6620:15;;6616:127;;6659:72;6664:28;6694:36;6659:4;:72::i;:::-;6652:79;;;;;;;;6616:127;6855:15;;6851:344;;6972:12;6987:51;7009:6;7017:8;7027:10;6987:21;:51::i;:::-;6972:66;-1:-1:-1;7057:12:9;;7053:131;;7097:71;7108:15;7125:33;7160:7;7097:10;:71::i;:::-;7090:78;;;;;;;;;7053:131;6851:344;;7288:35;7306:6;7314:8;7288:17;:35::i;:::-;7283:96;;7352:14;7347:20;;7283:96;-1:-1:-1;;;;;7452:15:9;;;;;;:7;:15;;;;;;;;-1:-1:-1;;;;;7452:44:9;;;;:34;;:44;;;;;7445:51;;-1:-1:-1;;7445:51:9;;;7657:13;:23;;;;;;7624:56;;;;;;;;;;;;;;;;;:30;;:56;;;7657:23;7624:56;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;7624:56:9;;;;;;;;;;;;;;;;-1:-1:-1;;7702:20:9;;7624:56;;-1:-1:-1;7702:20:9;;-1:-1:-1;7691:8:9;;-1:-1:-1;;7765:162:9;7786:3;7782:1;:7;7765:162;;;7835:6;-1:-1:-1;;;;;7815:26:9;:13;7829:1;7815:16;;;;;;;;;;;;;;-1:-1:-1;;;;;7815:26:9;;7811:105;;;7875:1;7862:14;;7895:5;;7811:105;7791:3;;7765:162;;;;8056:3;8043:10;:16;8036:24;;;;-1:-1:-1;;;;;8193:23:9;;8162:28;8193:23;;;:13;:23;;;;;8263:17;;8193:23;;-1:-1:-1;;8263:21:9;;;8252:33;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;8252:33:9;8227:10;8238;8227:22;;;;;;;;;;;;;;;;;:58;;-1:-1:-1;;;;;;8227:58:9;-1:-1:-1;;;;;8227:58:9;;;;;;;;;;8296:19;;;;-1:-1:-1;;8296:19:9;;;:::i;:::-;-1:-1:-1;8333:30:9;;;-1:-1:-1;;;;;8333:30:9;;;;-1:-1:-1;;;;;8333:30:9;;;;;;;;;;;;;;;;;;;8388:14;8376:27;5960:2451;-1:-1:-1;;;;;;;;;;;5960:2451:9:o;4931:1501:6:-;4997:4;5018:16;5027:6;5018:8;:16::i;:::-;5014:124;;;5058:68;5063:27;5092:33;5058:4;:68::i;:::-;5051:75;;;;5014:124;5253:18;5273:21;5298:18;5309:6;5298:10;:18::i;:::-;5249:67;;;;;5363:13;-1:-1:-1;;;;;5350:47:6;;:49;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5350:49:6;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5350:49:6;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5350:49:6;5335:64;;;;;5327:97;;;;;-1:-1:-1;;;5327:97:6;;;;;;;;;;;;-1:-1:-1;;;5327:97:6;;;;;;;;;;;;;;;5435:19;5457:29;5472:13;5457:14;:29::i;:::-;5435:51;;5520:22;5535:6;5520:14;:22::i;:::-;-1:-1:-1;;;;;5505:37:6;:11;-1:-1:-1;;;;;5505:37:6;;5497:70;;;;;-1:-1:-1;;;5497:70:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;5809:10;:8;:10::i;:::-;-1:-1:-1;;;;;5795:24:6;:10;-1:-1:-1;;;;;5795:24:6;;5791:246;;5840:10;-1:-1:-1;;;;;5840:27:6;;;;;:52;;;5881:11;-1:-1:-1;;;;;5871:21:6;:6;-1:-1:-1;;;;;5871:21:6;;5840:52;:78;;;;5897:21;5906:11;5897:8;:21::i;:::-;5896:22;5840:78;5836:190;;;5946:64;5951:18;5971:38;5946:4;:64::i;5836:190::-;6104:55;;;;;;;;6123:4;6104:55;;;-1:-1:-1;6104:55:6;;;;;;;-1:-1:-1;;;;;6086:15:6;;;;;;:7;:15;;;;;;;:73;;;;-1:-1:-1;;6086:73:6;;;;;;;;;;;;;;;;;6271:21;;;;6267:80;;;6309:26;6328:6;6309:18;:26::i;:::-;6364:20;;;-1:-1:-1;;;;;6364:20:6;;;;;;;;;;;;;;;6409:14;6397:27;4931:1501;-1:-1:-1;;;;;4931:1501:6:o;1912:153:0:-;1973:4;1995:33;2008:3;2003:9;;;;;;;;2019:4;2014:10;;;;;;;;1995:33;;;;;;;;;;;;;2026:1;1995:33;;;;;;;;;;;;;2053:3;2048:9;;;;;;;9174:1550:9;9280:4;9338:16;9347:6;9338:8;:16::i;:::-;9333:131;;9378:74;9383:23;9408:43;9378:4;:74::i;9333:131::-;9573:22;9588:6;9573:14;:22::i;:::-;-1:-1:-1;;;;;9563:32:9;:6;-1:-1:-1;;;;;9563:32:9;;9559:536;;9651:16;9660:6;9651:8;:16::i;:::-;9647:141;;9700:72;9705:17;9724:47;9700:4;:72::i;9647:141::-;3628:6:8;9900:27:9;:57;9896:188;;;9985:83;9990:31;10023:44;9985:4;:83::i;9896:188::-;-1:-1:-1;;;;;10230:15:9;;10195:32;10230:15;;;:7;:15;;;;;:41;;;;10282:71;;;;10457:32;10238:6;10457:24;:32::i;:::-;-1:-1:-1;10591:85:9;;;-1:-1:-1;;;;;10591:85:9;;;;;;;;;;;;;;;;;;;;;;;;;;;10701:14;10696:20;;6153:111:16;6206:4;6229:28;6234:1;6237;6229:28;;;;;;;;;;;;;;;;;:4;:28::i;1418:205::-;1516:4;1532:18;;:::i;:::-;1553:15;1558:1;1561:6;1553:4;:15::i;:::-;1532:36;;1585:31;1590:17;1599:7;1590:8;:17::i;:::-;1609:6;1585:4;:31::i;3837:155::-;3918:4;3950:12;3942:6;;;;3934:29;;;;-1:-1:-1;;;3934:29:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;3934:29:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;3980:5:16;;;3837:155::o;5004:243::-;5085:4;5105:6;;;:16;;-1:-1:-1;5115:6:16;;5105:16;5101:55;;;-1:-1:-1;5144:1:16;5137:8;;5101:55;5174:5;;;5178:1;5174;:5;:1;5197:5;;;;;:10;5209:12;5189:33;;;;;-1:-1:-1;;;5189:33:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;5189:33:16;-1:-1:-1;5239:1:16;5004:243;-1:-1:-1;;;;5004:243:16:o;3216:175::-;3297:4;3322:5;;;3353:12;3345:6;;;;3337:29;;;;-1:-1:-1;;;3337:29:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;2616:158:16;2691:6;2728:12;2721:5;2717:9;;2709:32;;;;-1:-1:-1;;;2709:32:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;2709:32:16;-1:-1:-1;2765:1:16;;2616:158;-1:-1:-1;;2616:158:16:o;5558:124::-;5617:4;5640:35;5645:17;5650:1;410:4;5645;:17::i;:::-;5664:10;;5640:4;:35::i;6430:145::-;6487:13;;:::i;:::-;6519:49;;;;;;;;6537:29;6542:20;6547:1;448:4;6542;:20::i;:::-;6564:1;6537:4;:29::i;2932:158::-;3003:13;;:::i;:::-;3035:48;;;;;;;;3053:28;3058:1;:10;;;3070:1;:10;;;3053:4;:28::i;2448:162::-;2524:7;2563:12;-1:-1:-1;;;2551:10:16;;2543:33;;;;-1:-1:-1;;;2543:33:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;3549:158:16;3620:13;;:::i;:::-;3652:48;;;;;;;;3670:28;3675:1;:10;;;3687:1;:10;;;3670:4;:28::i;4747:125::-;4809:4;448;4832:19;4837:1;4840;:10;;;4832:4;:19::i;:::-;:33;;;;;;;4747:125;-1:-1:-1;;;4747:125:16:o;2188:187:0:-;2273:4;2295:43;2308:3;2303:9;;;;;;;;2319:4;2314:10;;;;;;;;2295:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;2363:3;2358:9;;;;;;;6440:257:6;-1:-1:-1;;;;;6512:23:6;;;;;;:15;:23;;;;;;:28;6504:61;;;;;-1:-1:-1;;;6504:61:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;6576:14;:16;;;;;;;:14;6603:26;;;:10;:26;;;;;;;;:35;;-1:-1:-1;;;;;6603:35:6;;;-1:-1:-1;;;;;;6603:35:6;;;;;;;6675:14;;6649:23;;;:15;:23;;;:40;6440:257::o;6270:154:16:-;6351:4;6382:12;6375:5;6367:28;;;;-1:-1:-1;;;6367:28:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;6367:28:16;;6416:1;6412;:5;;;;;;;6270:154;-1:-1:-1;;;;6270:154:16:o;489:56600:9:-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Swarm Source
bzzr://38c417064fdce1d64d3ddab8301b11ec93c21d4b3bd1af6f51ef51f6464c8288
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.