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:
MERC721TokenAdmin
Compiler Version
v0.5.16+commit.9c3226ce
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.5.16; import "./MTokenAdmin.sol"; import "./MTokenInterfaces.sol"; import "./MtrollerInterface.sol"; import "./ErrorReporter.sol"; import "./compound/Exponential.sol"; import "./compound/InterestRateModel.sol"; import "./open-zeppelin/token/ERC721/IERC721Receiver.sol"; import "./open-zeppelin/token/ERC721/ERC721.sol"; import "./open-zeppelin/token/ERC20/IERC20.sol"; import "./open-zeppelin/introspection/ERC165.sol"; /** * @title ERC-721 Token Contract * @notice Base for mNFTs * @author mmo.finance */ contract MERC721TokenAdmin is MTokenAdmin, ERC721("MERC721","MERC721"), MERC721AdminInterface { /** * @notice Constructs a new MERC721TokenAdmin */ constructor() public MTokenAdmin() { implementedSelectors.push(bytes4(keccak256('initialize(address,address,address,address,string,string)'))); implementedSelectors.push(bytes4(keccak256('redeemAndSell(uint240,uint256,address,bytes)'))); implementedSelectors.push(bytes4(keccak256('redeem(uint240)'))); implementedSelectors.push(bytes4(keccak256('redeemUnderlying(uint256)'))); implementedSelectors.push(bytes4(keccak256('borrow(uint256)'))); implementedSelectors.push(bytes4(keccak256('name()'))); implementedSelectors.push(bytes4(keccak256('symbol()'))); implementedSelectors.push(bytes4(keccak256('tokenURI(uint256)'))); } /** * Marker function identifying this contract as "ERC721_MTOKEN" type */ function getTokenType() public pure returns (MTokenIdentifier.MTokenType) { return MTokenIdentifier.MTokenType.ERC721_MTOKEN; } /** * @notice Initialize a new ERC-721 MToken money market * @dev Since each non-fungible ERC-721 is unique and thus cannot have "reserves" in the conventional sense, we have to set * reserveFactorMantissa_ = 0 in the mToken initialisation. Similarly, we have to set protocolSeizeShareMantissa_ = 0 since * seizing a NFT asset can only be done in one piece and it cannot be split up to be transferred partly to the protocol. * @param underlyingContract_ The contract address of the underlying asset for this MToken * @param mtroller_ The address of the Mtroller * @param interestRateModel_ The address of the interest rate model * @param tokenAuction_ The address of the TokenAuction contract * @param name_ EIP-721 name of this MToken * @param symbol_ EIP-721 symbol of this MToken */ function initialize(address underlyingContract_, MtrollerInterface mtroller_, InterestRateModel interestRateModel_, TokenAuction tokenAuction_, string memory name_, string memory symbol_) public { MTokenAdmin.initialize(underlyingContract_, mtroller_, interestRateModel_, 0, mantissaOne, 0, name_, symbol_, 18); // _registerInterface(this.onERC721Received.selector); uint err = _setTokenAuction(tokenAuction_); require(err == uint(Error.NO_ERROR), "setting tokenAuction failed"); } /** * @notice Sender redeems mToken in exchange for the underlying nft asset. Also exits the mToken's market. * Redeem is only possible if after redeeming the owner still has positive overall liquidity (no shortfall), * unless the redeem is immediately followed by a sale in the same transaction (when transferHandler != address(0)) and * the received sale price is sufficient to cover any such shortfall. * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param mToken The mToken to redeem into underlying * @param sellPrice In case of redeem followed directly by a sale to another user, this is the (minimum) price to collect from the buyer * @param transferHandler If this is nonzero, the redeem is directly followed by a sale, the details of which are handled by a contract at this address (see Mortgage.sol) * @param transferParams Call parameters for the transferHandler call * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemAndSell(uint240 mToken, uint sellPrice, address payable transferHandler, bytes memory transferParams) public nonReentrant returns (uint) { /* Fail if sender not owner */ if (msg.sender != ownerOf(mToken)) { return fail(Error.UNAUTHORIZED, FailureInfo.REDEEM_NOT_OWNER); } /* Sanity check, this should never revert */ require(accountTokens[mToken][msg.sender] == oneUnit, "Invalid internal token amount"); /* Reset the asking price to zero (= "not set") */ if (askingPrice[mToken] > 0) { askingPrice[mToken] = 0; } /* Redeem / burn the mToken */ uint err = redeemInternal(mToken, oneUnit, 0, msg.sender, sellPrice, transferHandler, transferParams); if (err != uint(Error.NO_ERROR)) { return err; } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* Revert if market cannot be exited */ err = mtroller.exitMarketOnBehalf(mToken, msg.sender); requireNoError(err, "redeem market exit failed"); /* Burn the ERC-721 specific parts of the mToken */ _burn(mToken); return uint(Error.NO_ERROR); } /** * @notice Sender redeems mToken in exchange for the underlying nft asset. Also exits the mToken's market. * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param mToken The mToken to redeem into underlying * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeem(uint240 mToken) public returns (uint) { return redeemAndSell(mToken, 0, address(0), ""); } /** * @notice Sender redeems mToken in exchange for the underlying nft asset. Also exits the mToken's market. * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param underlyingID The ID of the underlying nft to be redeemed * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemUnderlying(uint256 underlyingID) external returns (uint) { return redeem(mTokenFromUnderlying[underlyingID]); } /** * @notice Sender enters mToken market and borrows NFT assets from the protocol to their own address. * @param borrowUnderlyingID The ID of the underlying NFT asset to borrow * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function borrow(uint256 borrowUnderlyingID) external returns (uint) { borrowUnderlyingID; /* No NFT borrowing for now */ return fail(Error.MTROLLER_REJECTION, FailureInfo.BORROW_MTROLLER_REJECTION); } /** * @notice Returns the name of the mToken (contract). For now this is simply the name of the underlying. * @return string The name of the mToken. */ function name() external view returns (string memory) { return IERC721Metadata(underlyingContract).name(); } /** * @notice Returns the symbol of the mToken (contract). For now this is simply the symbol of the underlying. * @return string The symbol of the mToken. */ function symbol() external view returns (string memory) { return IERC721Metadata(underlyingContract).symbol(); } /** * @notice Returns an URI for the given mToken. For now this is simply the URI of the underlying NFT. * @param tokenId The mToken whose URI to get. * @return string The URI of the mToken. */ function tokenURI(uint256 tokenId) external view returns (string memory) { require(_exists(tokenId), "URI query for nonexistent token"); require(tokenId <= uint240(-1), "URI query for nonexistent token"); uint240 mToken = uint240(tokenId); return IERC721Metadata(underlyingContract).tokenURI(underlyingIDs[mToken]); } /*** Safe Token ***/ /** * @notice Transfers an underlying NFT asset out of this contract * @dev Performs a transfer out, reverting upon failure. * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. * @param to The address where to transfer underlying assets to * @param underlyingID The ID of the underlying asset * @param amount The amount of underlying to transfer, must be == oneUnit here */ function doTransferOut(address payable to, uint256 underlyingID, uint amount, uint sellPrice, address payable transferHandler, bytes memory transferParams) internal returns (uint) { /** * For now, amounts transferred out must always be oneUnit. Later, with NFT borrowing enabled * amount could be larger than oneUnit and the difference would be the lender's and protocol's * profit and should be distributed here. */ require(amount == oneUnit, "Amount must be oneUnit"); if (transferHandler == address(0)) { // transfer without subsequent sale to a third party IERC721(underlyingContract).safeTransferFrom(address(this), to, underlyingID); require(IERC721(underlyingContract).ownerOf(underlyingID) == to, "Transfer out failed"); } else { // transfer followed by sale to a third party (handled by transferHandler) // transfer underlying to transferHandler first (reduced risk, grant access rights only from transferHandler) IERC721(underlyingContract).safeTransferFrom(address(this), transferHandler, underlyingID); MEtherUserInterface mEther = tokenAuction.paymentToken(); uint240 mEtherToken = MTokenCommon(address(mEther)).thisFungibleMToken(); uint oldBalance = to.balance; uint oldBorrowBalance = mEther.borrowBalanceCurrent(to, mEtherToken); uint error = FlashLoanReceiverInterface(transferHandler).executeTransfer(underlyingID, to, sellPrice, transferParams); require(error == uint(Error.NO_ERROR), "Transfer operation failed"); uint cashReceived = to.balance; require(cashReceived >= oldBalance, "Negative received payment"); cashReceived = cashReceived - oldBalance; uint borrowReduced = mEther.borrowBalanceStored(to, mEtherToken); require(oldBorrowBalance >= borrowReduced, "Borrow increased"); borrowReduced = oldBorrowBalance - borrowReduced; require((cashReceived + borrowReduced) >= sellPrice, "Received payment too low"); } return amount; } /** * @notice Transfers underlying assets from sender to a beneficiary (e.g. for flash loan down payment) * @dev Performs a transfer from, reverting upon failure (e.g. insufficient allowance from owner) * @param to the address where to transfer underlying assets to * @param underlyingID the ID of the underlying asset (in case of a NFT) or 1 (in case of a fungible asset) * @param amount the amount of underlying to transfer (for fungible assets) or oneUnit (for NFTs) * @return (uint) Returns the amount actually transferred (lower in case of a fee). */ function doTransferOutFromSender(address payable to, uint256 underlyingID, uint amount) internal returns (uint) { /** * For now, amounts transferred must always be oneUnit. Later, with NFT borrowing enabled * amount could be larger than oneUnit. */ require(amount == oneUnit, "Amount must be oneUnit"); IERC721(underlyingContract).safeTransferFrom(msg.sender, to, underlyingID); require(IERC721(underlyingContract).ownerOf(underlyingID) == to, "Transfer out failed"); return amount; } } contract MERC721InterfaceFull is MERC721TokenAdmin, MERC721Interface {}
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 "./MTokenCommon.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 ("admin" part) * @author mmo.finance, initially based on Compound */ contract MTokenAdmin is MTokenCommon, MTokenAdminInterface { /** * @notice Constructs a new MTokenAdmin */ constructor() public MTokenCommon() { implementedSelectors.push(bytes4(keccak256('isMDelegatorAdminImplementation()'))); implementedSelectors.push(bytes4(keccak256('_setFlashReceiverWhiteList(address,bool)'))); implementedSelectors.push(bytes4(keccak256('_setInterestRateModel(address)'))); implementedSelectors.push(bytes4(keccak256('_setTokenAuction(address)'))); implementedSelectors.push(bytes4(keccak256('_setMtroller(address)'))); implementedSelectors.push(bytes4(keccak256('_setGlobalProtocolParameters(uint256,uint256,uint256,uint256)'))); implementedSelectors.push(bytes4(keccak256('_setGlobalAuctionParameters(uint256,uint256,uint256,uint256,uint256)'))); implementedSelectors.push(bytes4(keccak256('_reduceReserves(uint240,uint256)'))); implementedSelectors.push(bytes4(keccak256('_sweepERC20(address)'))); implementedSelectors.push(bytes4(keccak256('_sweepERC721(address,uint256)'))); } /** * @notice Returns the type of implementation for this contract */ function isMDelegatorAdminImplementation() public pure returns (bool) { return true; } /*** Admin functions ***/ /** * @notice Initializes a new MToken money market * @param underlyingContract_ The contract address of the underlying asset for this MToken * @param mtroller_ The address of the Mtroller * @param interestRateModel_ The address of the interest rate model * @param reserveFactorMantissa_ The fraction of interest to set aside for reserves, scaled by 1e18 * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param protocolSeizeShareMantissa_ The fraction of seized collateral added to reserves, scaled by 1e18 * @param name_ EIP-20 name of this MToken * @param symbol_ EIP-20 symbol of this MToken * @param decimals_ EIP-20 decimal precision of this MToken */ function initialize(address underlyingContract_, MtrollerInterface mtroller_, InterestRateModel interestRateModel_, uint reserveFactorMantissa_, uint initialExchangeRateMantissa_, uint protocolSeizeShareMantissa_, string memory name_, string memory symbol_, uint8 decimals_) internal { require(msg.sender == getAdmin(), "only admin can initialize token contract"); // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund) _notEntered = true; _notEntered2 = true; // Allow initialization only once require(underlyingContract == address(0), "already initialized"); // Set the underlying contract address underlyingContract = underlyingContract_; // Set the interest rate model uint err = _setInterestRateModel(interestRateModel_); require(err == uint(Error.NO_ERROR), "setting interest rate model failed"); // Set the mtroller err = _setMtroller(mtroller_); require(err == uint(Error.NO_ERROR), "setting mtroller failed"); // Set initial exchange rate, the reserve factor, the protocol seize share, and the one-time borrow fee err = _setGlobalProtocolParameters(initialExchangeRateMantissa_, reserveFactorMantissa_, protocolSeizeShareMantissa_, 0.8e16); require(err == uint(Error.NO_ERROR), "setting global protocol parameters failed"); // Set global auction parameters err = _setGlobalAuctionParameters(auctionMinGracePeriod, 500, 0, 5e16, 0); require(err == uint(Error.NO_ERROR), "setting global auction parameters failed"); // Set the mToken name and symbol mName = name_; mSymbol = symbol_; mDecimals = decimals_; // Initialize the market for the anchor token uint240 tokenAnchor = mtroller.getAnchorToken(address(this)); require(accrualBlockNumber[tokenAnchor] == 0 && borrowIndex[tokenAnchor] == 0, "market may only be initialized once"); accrualBlockNumber[tokenAnchor] = getBlockNumber(); borrowIndex[tokenAnchor] = mantissaOne; // Accrue interest to execute changes err = accrueInterest(tokenAnchor); require(err == uint(Error.NO_ERROR), "accrue interest failed"); } struct RedeemLocalVars { Error err; MathError mathErr; uint exchangeRateMantissa; uint redeemTokens; uint redeemAmount; uint totalSupplyNew; uint accountTokensNew; uint totalCashNew; } /** * @notice Sender redeems mTokens in exchange for the underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param mToken The mToken to redeem * @param redeemTokensIn The number of mTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero) * @param redeemAmountIn The number of underlying tokens to receive from redeeming mTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero) * @param beneficiary The account that will get the redeemed underlying asset * @param sellPrice In case of redeem followed directly by a sale to another user, this is the (minimum) price to collect from the buyer * @param transferHandler If this is nonzero, the redeem is directly followed by a sale, the details of which are handled by a contract at this address (see Mortgage.sol) * @param transferParams Call parameters for the transferHandler call * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemInternal(uint240 mToken, uint redeemTokensIn, uint redeemAmountIn, address payable beneficiary, uint sellPrice, address payable transferHandler, bytes memory transferParams) internal returns (uint) { address payable redeemer = msg.sender; require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero"); uint err = accrueInterest(mToken); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed return fail(Error(err), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); } RedeemLocalVars memory vars; /* exchangeRate = invoke Exchange Rate Stored() */ (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal(mToken); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)); } /* If redeemTokensIn > 0: */ if (redeemTokensIn > 0) { /* * We calculate the exchange rate and the amount of underlying to be redeemed: * redeemTokens = redeemTokensIn * redeemAmount = redeemTokensIn x exchangeRateCurrent */ vars.redeemTokens = redeemTokensIn; (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr)); } } else { /* * We get the current exchange rate and calculate the amount to be redeemed: * redeemTokens = redeemAmountIn / exchangeRate * redeemAmount = redeemAmountIn */ (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa})); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr)); } vars.redeemAmount = redeemAmountIn; } /* * We calculate the new total supply and redeemer balance, checking for underflow: * totalSupplyNew = totalSupply - redeemTokens * accountTokensNew = accountTokens[redeemer] - redeemTokens */ (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply[mToken], vars.redeemTokens); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[mToken][redeemer], vars.redeemTokens); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } /* Fail gracefully if protocol has insufficient underlying cash */ (vars.mathErr, vars.totalCashNew) = subUInt(totalCashUnderlying[mToken], vars.redeemAmount); if (vars.mathErr != MathError.NO_ERROR) { return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We invoke doTransferOut for the redeemer and the redeemAmount. * Note: The mToken must handle variations between ETH, ERC-20, ERC-721, ERC-1155 underlying. * On success, the mToken has redeemAmount less of cash. * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ uint256 underlyingID = underlyingIDs[mToken]; // check transferHandler is whitelisted (if used) if (transferHandler != address(0)) { require(flashReceiverIsWhitelisted[transferHandler] || flashReceiverIsWhitelisted[address(0)], "flash receiver not whitelisted"); } doTransferOut(beneficiary, underlyingID, vars.redeemAmount, sellPrice, transferHandler, transferParams); /* We write previously calculated values into storage */ totalSupply[mToken] = vars.totalSupplyNew; accountTokens[mToken][redeemer] = vars.accountTokensNew; totalCashUnderlying[mToken] = vars.totalCashNew; /* We emit a Transfer event, and a Redeem event */ emit Transfer(redeemer, address(this), mToken, vars.redeemTokens); emit Redeem(redeemer, mToken, vars.redeemTokens, underlyingID, vars.redeemAmount); /* Revert whole transaction if redeem not allowed (i.e., user has any shortfall at the end). * We do this at the end to allow for redeems that include a sales transaction which can balance * user's liquidity */ err = mtroller.redeemAllowed(mToken, redeemer, 0); requireNoError(err, "redeem failed"); /* We call the defense hook */ mtroller.redeemVerify(mToken, redeemer, vars.redeemAmount, vars.redeemTokens); return uint(Error.NO_ERROR); } /** * @notice Sender borrows assets from the protocol to their own address * @param mToken The mToken whose underlying to borrow * @param borrowAmount The amount of the underlying asset to borrow * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function borrowInternal(uint240 mToken, uint borrowAmount) internal returns (uint) { // borrowFresh emits borrow-specific logs on errors, so we don't need to (uint err, ) = borrowPrivate(msg.sender, mToken, borrowAmount, address(0)); return err; } /** * @notice Sender borrows assets from the protocol to a receiver address in spite of having * insufficient collateral, but repays borrow or adds collateral to correct balance in the same block * @param mToken The mToken whose underlying to borrow * @param downPaymentAmount Additional funds transferred from sender to receiver (down payment) * @param borrowAmount The amount of the underlying asset to borrow * @param receiver The address receiving the borrowed funds. This address must be able to receive * the corresponding underlying of mToken and it must implement FlashLoanReceiverInterface. Any * such receiver address must be whitelisted before by admin, unless admin has enables all addresses * by whitelisting address(0). * @param flashParams Any other data necessary for flash loan repayment * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function flashBorrowInternal(uint240 mToken, uint downPaymentAmount, uint borrowAmount, address payable receiver, bytes memory flashParams) internal nonReentrant2 returns (uint) { // check receiver is not null, and is whitelisted require(receiver != address(0), "invalid flash loan receiver"); require(flashReceiverIsWhitelisted[receiver] || flashReceiverIsWhitelisted[address(0)], "flash receiver not whitelisted"); // Revert if flash borrowing fails (need to revert because of side-effects such as down payment) uint error; uint paidOutAmount; if (borrowAmount > 0) { (error, paidOutAmount) = borrowPrivate(msg.sender, mToken, borrowAmount, receiver); require(error == uint(Error.NO_ERROR), "flash borrow not allowed"); } /* Get down payment (if any) from the sender and also transfer it to the receiver. * Reverts if anything goes wrong. */ uint256 underlyingID = underlyingIDs[mToken]; if (downPaymentAmount > 0) { MathError mathErr; uint downPaymentPaid = doTransferOutFromSender(receiver, underlyingID, downPaymentAmount); (mathErr, paidOutAmount) = addUInt(paidOutAmount, downPaymentPaid); require(mathErr == MathError.NO_ERROR, "down payment calculation failed"); } /* Call user-defined code that eventually repays borrow or increases collaterals sufficiently */ error = FlashLoanReceiverInterface(receiver).executeFlashOperation(msg.sender, mToken, borrowAmount, paidOutAmount, flashParams); require(error == uint(Error.NO_ERROR), "execute flash operation failed"); /* Revert whole transaction if sender (=borrower) has any shortfall remaining at the end */ error = mtroller.borrowAllowed(mToken, msg.sender, 0); require(error == 0, "flash loan failed"); emit FlashBorrow(msg.sender, underlyingID, receiver, downPaymentAmount, borrowAmount, paidOutAmount); return uint(Error.NO_ERROR); } struct BorrowLocalVars { MathError mathErr; uint accountBorrows; uint accountBorrowsNew; uint totalBorrowsNew; uint totalCashNew; uint protocolFee; uint amountPaidOut; uint amountBorrowerReceived; uint totalReservesNew; } /** * @notice Borrows assets from the protocol to a certain address * @param borrower The address that borrows and receives assets * @param mToken The mToken whose underlying to borrow * @param borrowAmount The amount of the underlying asset to borrow * @param receiver The address receiving the borrowed funds in case of a flash loan, otherwise 0 * @return (possible error code 0=success, otherwise a failure (see ErrorReporter.sol for details), * amount actually received by borrower (borrowAmount - protocol fees - token transfer fees)) */ function borrowPrivate(address payable borrower, uint240 mToken, uint borrowAmount, address payable receiver) private nonReentrant returns (uint, uint) { /* Accrue interest */ uint error = accrueInterest(mToken); if (error != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed return (fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED), 0); } /* Fail if borrow not allowed (flash: fail if already has shortfall before borrowing anything) */ if (receiver != address(0)) { error = mtroller.borrowAllowed(mToken, borrower, 0); } else { error = mtroller.borrowAllowed(mToken, borrower, borrowAmount); } if (error != 0) { return (failOpaque(Error.MTROLLER_REJECTION, FailureInfo.BORROW_MTROLLER_REJECTION, error), 0); } // /* Verify market's block number equals current block number */ // if (accrualBlockNumber[mToken] != getBlockNumber()) { // return (fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK), 0); // } BorrowLocalVars memory vars; /* Fail gracefully if protocol has insufficient underlying cash */ (vars.mathErr, vars.totalCashNew) = subUInt(totalCashUnderlying[mToken], borrowAmount); if (vars.mathErr != MathError.NO_ERROR) { return (fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE), 0); } /* * We calculate the new borrower and total borrow balances, failing on overflow: * accountBorrowsNew = accountBorrows + borrowAmount * totalBorrowsNew = totalBorrows + borrowAmount */ (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower, mToken); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0); } (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, borrowAmount); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0); } (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows[mToken], borrowAmount); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0); } /* * We calculate the one-time platform fee (if any) on new borrows: * protocolFee = borrowFeeMantissa * borrowAmount * amountPaidOut = borrowAmount - protocolFee */ (vars.mathErr, vars.protocolFee) = mulScalarTruncate(Exp({mantissa: borrowFeeMantissa}), borrowAmount); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_PLATFORM_FEE_CALCULATION_FAILED, uint(vars.mathErr)), 0); } (vars.mathErr, vars.amountPaidOut) = subUInt(borrowAmount, vars.protocolFee); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_PLATFORM_FEE_CALCULATION_FAILED, uint(vars.mathErr)), 0); } /* Add protocolFee to totalReserves and totalCash, revert on overflow */ (vars.mathErr, vars.totalReservesNew) = addUInt(totalReserves[mToken], vars.protocolFee); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_PLATFORM_FEE_CALCULATION_FAILED, uint(vars.mathErr)), 0); } (vars.mathErr, vars.totalCashNew) = addUInt(vars.totalCashNew, vars.protocolFee); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_PLATFORM_FEE_CALCULATION_FAILED, uint(vars.mathErr)), 0); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We invoke doTransferOut for the borrower and the effective amountPaidOut. * Note: The mToken must handle variations between ETH, ERC-20, ERC-721, ERC-1155 underlying. * On success, the mToken has amountPaidOut less of cash. * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ uint256 underlyingID = underlyingIDs[mToken]; if (receiver != address(0)) { vars.amountBorrowerReceived = doTransferOut(receiver, underlyingID, vars.amountPaidOut, 0, address(0), ""); } else { vars.amountBorrowerReceived = doTransferOut(borrower, underlyingID, vars.amountPaidOut, 0, address(0), ""); } /* We write the previously calculated values into storage */ accountBorrows[mToken][borrower].principal = vars.accountBorrowsNew; accountBorrows[mToken][borrower].interestIndex = borrowIndex[mToken]; totalBorrows[mToken] = vars.totalBorrowsNew; totalCashUnderlying[mToken] = vars.totalCashNew; if (vars.protocolFee != 0) { totalReserves[mToken] = vars.totalReservesNew; emit ReservesAdded(address(this), mToken, vars.protocolFee, vars.totalReservesNew); } /* We emit a Borrow event */ emit Borrow(borrower, underlyingID, borrowAmount, vars.amountBorrowerReceived, vars.accountBorrowsNew, vars.totalBorrowsNew); /* We call the defense hook */ // unused function // mtroller.borrowVerify(address(this), borrower, borrowAmount); return (uint(Error.NO_ERROR), vars.amountBorrowerReceived); } /*** Admin Functions ***/ /** * @notice Manages the whitelist for flash loan receivers * @dev Admin function to manage whitelist entries for flash loan receivers * @param candidate the receiver address to take on/off the whitelist. putting the zero address * on the whitelist (candidate = 0, state = true) enables any address as flash loan receiver, * effectively disabling whitelisting * @param state true to put on whitelist, false to take off * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setFlashReceiverWhiteList(address candidate, bool state) external returns (uint) { // Check caller is admin if (msg.sender != getAdmin()) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_FLASH_WHITELIST_OWNER_CHECK); } // if state is modified, set new whitelist state and emit event if (flashReceiverIsWhitelisted[candidate] != state) { flashReceiverIsWhitelisted[candidate] = state; emit FlashReceiverWhitelistChanged(candidate, state); } return uint(Error.NO_ERROR); } /** * @notice sets a new interest rate model * @dev Admin function to set a new interest rate model. * @param newInterestRateModel the new interest rate model to use * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setInterestRateModel(InterestRateModel newInterestRateModel) public nonReentrant returns (uint) { // Check caller is admin if (msg.sender != getAdmin()) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK); } InterestRateModel oldInterestRateModel = interestRateModel; // Ensure invoke newInterestRateModel.isInterestRateModel() returns true require(newInterestRateModel.isInterestRateModel(), "marker method returned false"); // Set new interest rate model interestRateModel = newInterestRateModel; // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel); emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel); return uint(Error.NO_ERROR); } /** * @notice sets a new token auction contract * @dev Admin function to set a new token auction contract. * @param newTokenAuction the new token auction contract to use * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setTokenAuction(TokenAuction newTokenAuction) public nonReentrant returns (uint) { // Check caller is admin if (msg.sender != getAdmin()) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_TOKEN_AUCTION_OWNER_CHECK); } TokenAuction oldTokenAuction = tokenAuction; // Set new interest rate model tokenAuction = newTokenAuction; // Emit NewTokenAuction(oldTokenAuction, newTokenAuction); emit NewTokenAuction(oldTokenAuction, newTokenAuction); return uint(Error.NO_ERROR); } /** * @notice Sets a new mtroller for the market * @dev Admin function to set a new mtroller * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setMtroller(MtrollerInterface newMtroller) public nonReentrant returns (uint) { // Check caller is admin if (msg.sender != getAdmin()) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_MTROLLER_OWNER_CHECK); } MtrollerInterface oldMtroller = mtroller; // Ensure invoke mtroller.isMtroller() returns true require(MtrollerUserInterface(newMtroller).isMDelegatorUserImplementation(), "invalid mtroller"); require(MtrollerAdminInterface(newMtroller).isMDelegatorAdminImplementation(), "invalid mtroller"); // Set market's mtroller to newMtroller mtroller = newMtroller; // Emit NewMtroller(oldMtroller, newMtroller) emit NewMtroller(oldMtroller, newMtroller); return uint(Error.NO_ERROR); } /** * @notice Sets new values for the modifiable global parameters of the protocol * @dev Admin function to set global parameters. Setting a value of a parameter to uint(-1) means to not * change the current value of that parameter. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setGlobalProtocolParameters(uint _initialExchangeRateMantissa, uint _reserveFactorMantissa, uint _protocolSeizeShareMantissa, uint _borrowFeeMantissa) public returns (uint) { require(msg.sender == getAdmin(), "only admin can set global protocol parameters"); if (_initialExchangeRateMantissa != uint(-1) && _initialExchangeRateMantissa != initialExchangeRateMantissa) { if (_initialExchangeRateMantissa == 0) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } initialExchangeRateMantissa = _initialExchangeRateMantissa; } if (_reserveFactorMantissa != uint(-1) && _reserveFactorMantissa != reserveFactorMantissa) { if (_reserveFactorMantissa > reserveFactorMaxMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } reserveFactorMantissa = _reserveFactorMantissa; } if (_protocolSeizeShareMantissa != uint(-1) && _protocolSeizeShareMantissa != protocolSeizeShareMantissa) { if (_protocolSeizeShareMantissa > protocolSeizeShareMaxMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } protocolSeizeShareMantissa = _protocolSeizeShareMantissa; } if (_borrowFeeMantissa != uint(-1) && _borrowFeeMantissa != borrowFeeMantissa) { if (_borrowFeeMantissa > borrowFeeMaxMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } borrowFeeMantissa = _borrowFeeMantissa; } emit NewGlobalProtocolParameters(initialExchangeRateMantissa, reserveFactorMantissa, protocolSeizeShareMantissa, borrowFeeMantissa); return uint(Error.NO_ERROR); } function _setGlobalAuctionParameters( uint _auctionGracePeriod, uint _preferredLiquidatorHeadstart, uint _minimumOfferMantissa, uint _liquidatorAuctionFeeMantissa, uint _protocolAuctionFeeMantissa ) public returns (uint) { require(msg.sender == getAdmin(), "only admin can set global auction parameters"); if (_auctionGracePeriod != uint(-1) && _auctionGracePeriod != auctionGracePeriod) { if (_auctionGracePeriod < auctionMinGracePeriod || _auctionGracePeriod > auctionMaxGracePeriod) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } auctionGracePeriod = _auctionGracePeriod; } if (_preferredLiquidatorHeadstart != uint(-1) && _preferredLiquidatorHeadstart != preferredLiquidatorHeadstart) { if (_preferredLiquidatorHeadstart > preferredLiquidatorMaxHeadstart) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } preferredLiquidatorHeadstart = _preferredLiquidatorHeadstart; } if (_minimumOfferMantissa != uint(-1) && _minimumOfferMantissa != minimumOfferMantissa) { if (_minimumOfferMantissa > minimumOfferMaxMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } minimumOfferMantissa = _minimumOfferMantissa; } if (_liquidatorAuctionFeeMantissa != uint(-1) && _liquidatorAuctionFeeMantissa != liquidatorAuctionFeeMantissa) { if (_liquidatorAuctionFeeMantissa > liquidatorAuctionFeeMaxMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } liquidatorAuctionFeeMantissa = _liquidatorAuctionFeeMantissa; } if (_protocolAuctionFeeMantissa != uint(-1) && _protocolAuctionFeeMantissa != protocolAuctionFeeMantissa) { if (_protocolAuctionFeeMantissa > protocolAuctionFeeMaxMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_GLOBAL_PARAMETERS_VALUE_CHECK); } protocolAuctionFeeMantissa = _protocolAuctionFeeMantissa; } emit NewGlobalAuctionParameters(auctionGracePeriod, preferredLiquidatorHeadstart, minimumOfferMantissa, liquidatorAuctionFeeMantissa, protocolAuctionFeeMantissa); return uint(Error.NO_ERROR); } /** * @notice Accrues interest and reduces reserves for mToken by transferring to admin * @param mToken The mToken whose reserves to reduce * @param reduceAmount Amount of reduction to reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _reduceReserves(uint240 mToken, uint reduceAmount) external nonReentrant returns (uint) { uint error = accrueInterest(mToken); if (error != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. return fail(Error(error), FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED); } // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to. return _reduceReservesFresh(mToken, reduceAmount); } /** * @notice Reduces reserves for mToken by transferring to admin * @dev Requires fresh interest accrual * @param mToken The mToken whose reserves to reduce * @param reduceAmount Amount of reduction to reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _reduceReservesFresh(uint240 mToken, uint reduceAmount) internal returns (uint) { MathError mathErr; uint totalReservesNew; uint totalCashNew; // Check caller is admin address payable admin = getAdmin(); if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.REDUCE_RESERVES_ADMIN_CHECK); } // We fail gracefully unless market's block number equals current block number if (accrualBlockNumber[mToken] != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK); } /* Fail gracefully if protocol has insufficient reserves */ (mathErr, totalReservesNew) = subUInt(totalReserves[mToken], reduceAmount); if (mathErr != MathError.NO_ERROR) { return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); } /* Fail gracefully if protocol has insufficient underlying cash */ (mathErr, totalCashNew) = subUInt(totalCashUnderlying[mToken], reduceAmount); if (mathErr != MathError.NO_ERROR) { return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We invoke doTransferOut for admin and the reduceAmount. * Note: The mToken must handle variations between ETH, ERC-20, ERC-721, ERC-1155 underlying. * On success, the mToken has reduceAmount less of cash. * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ uint256 underlyingID = underlyingIDs[mToken]; doTransferOut(admin, underlyingID, reduceAmount, 0, address(0), ""); /* We write the previously calculated values into storage */ totalReserves[mToken] = totalReservesNew; totalCashUnderlying[mToken] = totalCashNew; emit ReservesReduced(admin, mToken, reduceAmount, totalReservesNew); return uint(Error.NO_ERROR); } /*** Safe Token ***/ /** * @notice Transfers underlying assets out of this contract * @dev Performs a transfer out, reverting upon failure. * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. * @param to the address where to transfer underlying assets to * @param underlyingID the ID of the underlying asset (in case of a NFT) or 1 (in case of a fungible asset) * @param amount the amount of underlying to transfer (for fungible assets) or oneUnit (for NFTs) * @return (uint) Returns the amount actually transferred out (lower in case of a fee). */ function doTransferOut(address payable to, uint256 underlyingID, uint amount, uint sellPrice, address payable transferHandler, bytes memory transferParams) internal returns (uint); /** * @notice Transfers underlying assets from sender to a beneficiary (e.g. for flash loan down payment) * @dev Performs a transfer from, reverting upon failure (e.g. insufficient allowance from owner) * @param to the address where to transfer underlying assets to * @param underlyingID the ID of the underlying asset (in case of a NFT) or 1 (in case of a fungible asset) * @param amount the amount of underlying to transfer (for fungible assets) or oneUnit (for NFTs) * @return (uint) Returns the amount actually transferred (lower in case of a fee). */ function doTransferOutFromSender(address payable to, uint256 underlyingID, uint amount) internal returns (uint); /** @notice Admin may collect any ERC-20 token that have been transferred to this contract inadvertently (otherwise they would be locked forever). @param tokenContract The contract address of the "lost" token. @return (uint) Returns the amount of tokens successfully collected, otherwise reverts. */ function _sweepERC20(address tokenContract) external nonReentrant returns (uint) { address admin = getAdmin(); require(msg.sender == admin, "Only admin can do that"); require(tokenContract != underlyingContract, "Cannot sweep underlying asset"); uint256 amount = IERC20(tokenContract).balanceOf(address(this)); require(amount > 0, "No leftover tokens found"); IERC20(tokenContract).transfer(admin, amount); return amount; } /** @notice Admin may collect any ERC-721 token that have been transferred to this contract inadvertently (otherwise they would be locked forever). @dev Reverts upon any failure. @param tokenContract The contract address of the "lost" token. @param tokenID The ID of the "lost" token. */ function _sweepERC721(address tokenContract, uint256 tokenID) external nonReentrant { address admin = getAdmin(); require(msg.sender == admin, "Only admin can do that"); if (tokenContract == underlyingContract) { // Only allow to sweep tokens that are not in use as supplied assets uint240 mToken = mTokenFromUnderlying[tokenID]; if (mToken != 0) { require(IERC721(tokenContract).ownerOf(mToken) == address(0), "Cannot sweep regular asset"); } } require(address(this) == IERC721(tokenContract).ownerOf(tokenID), "Token not owned by contract"); IERC721(tokenContract).safeTransferFrom(address(this), admin, tokenID); } } contract MTokenInterfaceFull is MTokenAdmin, MTokenInterface {}
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; 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 "./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":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidOutAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","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":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingID","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"downPayment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidOutAmount","type":"uint256"}],"name":"FlashBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"bool","name":"newState","type":"bool"}],"name":"FlashReceiverWhitelistChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint240","name":"mTokenCollateral","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"lastBlockOfGracePeriod","type":"uint256"}],"name":"GracePeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint240","name":"mTokenBorrowed","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"repayAmountUnderlying","type":"uint256"},{"indexed":false,"internalType":"uint240","name":"mTokenCollateral","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmountUnderlying","type":"uint256"},{"indexed":false,"internalType":"uint240","name":"mTokenMinted","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"amountTokensMinted","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAuctionGracePeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPreferredLiquidatorHeadstart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinimumOfferMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidatorAuctionFeeMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newProtocolAuctionFeeMantissa","type":"uint256"}],"name":"NewGlobalAuctionParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newInitialExchangeRateMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newProtocolSeizeShareMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBorrowFeeMantissa","type":"uint256"}],"name":"NewGlobalProtocolParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract MtrollerInterface","name":"oldMtroller","type":"address"},{"indexed":false,"internalType":"contract MtrollerInterface","name":"newMtroller","type":"address"}],"name":"NewMtroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract TokenAuction","name":"oldTokenAuction","type":"address"},{"indexed":false,"internalType":"contract TokenAuction","name":"newTokenAuction","type":"address"}],"name":"NewTokenAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract TokenAuction","name":"oldTokenAuction","type":"address"},{"indexed":false,"internalType":"contract TokenAuction","name":"newTokenAuction","type":"address"}],"name":"NewTokenAuctionContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"underlyingID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"underlyingRedeemAmount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint240","name":"mToken","type":"uint240"},{"indexed":false,"internalType":"uint256","name":"amountTokens","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"candidate","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"_setFlashReceiverWhiteList","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_auctionGracePeriod","type":"uint256"},{"internalType":"uint256","name":"_preferredLiquidatorHeadstart","type":"uint256"},{"internalType":"uint256","name":"_minimumOfferMantissa","type":"uint256"},{"internalType":"uint256","name":"_liquidatorAuctionFeeMantissa","type":"uint256"},{"internalType":"uint256","name":"_protocolAuctionFeeMantissa","type":"uint256"}],"name":"_setGlobalAuctionParameters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_initialExchangeRateMantissa","type":"uint256"},{"internalType":"uint256","name":"_reserveFactorMantissa","type":"uint256"},{"internalType":"uint256","name":"_protocolSeizeShareMantissa","type":"uint256"},{"internalType":"uint256","name":"_borrowFeeMantissa","type":"uint256"}],"name":"_setGlobalProtocolParameters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract MtrollerInterface","name":"newMtroller","type":"address"}],"name":"_setMtroller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract TokenAuction","name":"newTokenAuction","type":"address"}],"name":"_setTokenAuction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenContract","type":"address"}],"name":"_sweepERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"_sweepERC721","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"askingPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"auctionGracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"auctionMaxGracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"auctionMinGracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"borrowUnderlyingID","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"borrowFeeMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"flashReceiverIsWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"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":false,"inputs":[{"internalType":"address","name":"underlyingContract_","type":"address"},{"internalType":"contract MtrollerInterface","name":"mtroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"contract TokenAuction","name":"tokenAuction_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isMDelegatorAdminImplementation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"lastBlockGracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"liquidatorAuctionFeeMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"liquidatorAuctionFeeMaxMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mName","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mSymbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mTokenFromUnderlying","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minimumOfferMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minimumOfferMaxMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mtroller","outputs":[{"internalType":"contract MtrollerInterface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"preferredLiquidator","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"preferredLiquidatorHeadstart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"preferredLiquidatorMaxHeadstart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolAuctionFeeMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolAuctionFeeMaxMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolSeizeShareMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint240","name":"mToken","type":"uint240"},{"internalType":"uint256","name":"sellPrice","type":"uint256"},{"internalType":"address payable","name":"transferHandler","type":"address"},{"internalType":"bytes","name":"transferParams","type":"bytes"}],"name":"redeemAndSell","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"underlyingID","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"thisFungibleMToken","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenAuction","outputs":[{"internalType":"contract TokenAuction","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"totalCashUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalCreatedMarkets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"underlyingContract","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint240","name":"","type":"uint240"}],"name":"underlyingIDs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051806040016040528060078152602001664d45524337323160c81b815250604051806040016040528060078152602001664d45524337323160c81b8152506000604051808062005edc6021913960405190819003602101812083546001810185556000948552602085206008820401805460e09390931c60046007909316929092026101000a91820263ffffffff90920219909216179055905080602862005efd8239604080519182900360280182208454600181810187556000968752602087206008808404909101805460e095861c60046007968716810261010090810a92830263ffffffff93840219909416939093179093557f5f736574496e746572657374526174654d6f64656c28616464726573732900008952875198899003601e0189208b548087018d558c805285810460008051602062005ebc8339815191529081018054938b1c928a168702860a92830292850219909316919091179091557f5f736574546f6b656e41756374696f6e286164647265737329000000000000008a528851998a90036019018a208c548088018e558d805286810483018054928b1c918a168702860a918202918502199092161790557f5f7365744d74726f6c6c657228616464726573732900000000000000000000008a5297519889900360150189208b549586018c558b805293850490970180549390961c939094160290920a90810293021916919091179055905080603d62005f25823960405190819003603d01812083546001810185556000948552602085206008820401805460e09390931c60046007909316929092026101000a91820263ffffffff90920219909216179055905080604462005f9b823960408051918290036044018220845460018181018755600096875260208088206008808504909101805460e096871c60046007978816810261010090810a92830263ffffffff93840219909416939093179093557f5f72656475636552657365727665732875696e743234302c75696e74323536298a528851998a900390940189208b548087018d558c805284810460008051602062005ebc8339815191529081018054938b1c928a168602850a92830292880219909316919091179091557f5f737765657045524332302861646472657373290000000000000000000000008a528851998a90036014018a208c548088018e558d805285810483018054928b1c918a168602850a918202918802199092161790557f5f737765657045524337323128616464726573732c75696e74323536290000008a52975198899003601d019098208a549485018b5599805290830490950180549890941c9190921690930290930a91820291909202199093169290921790915550620004176301ffc9a760e01b6001600160e01b03620006ef16565b81516200042c90602390602085019062000774565b5080516200044290602490602084019062000774565b506200045e6380ac58cd60e01b6001600160e01b03620006ef16565b50506000604051808062005f626039913960405190819003603901812083546001810185556000948552602085206008820401805460e09390931c60046007909316929092026101000a91820263ffffffff90920219909216179055905080602c62005fdf82396040805191829003602c0182208454600181810187556000968752602087206008808404909101805460e095861c60046007968716810261010090810a92830263ffffffff93840219909416939093179093556e72656465656d2875696e743234302960881b8952875198899003600f9081018a208c548088018e558d805286810460008051602062005ebc8339815191529081018054938c1c928b168802870a92830292860219909316919091179091557f72656465656d556e6465726c79696e672875696e7432353629000000000000008b5289519a8b90036019018b208d548089018f558e805287810483018054928c1c918b168802870a918202918602199092161790556e626f72726f772875696e743235362960881b8b5289519a8b90039091018a208c548088018e558d805286810483018054928b1c918a168702860a91820291850219909216179055656e616d65282960d01b8a528851998a90036006018a208c548088018e558d805286810483018054928b1c918a168702860a918202918502199092161790556773796d626f6c282960c01b8a528851998a900385018a208c548088018e558d805286810483018054928b1c918a168702860a9182029185021990921617905570746f6b656e5552492875696e743235362960781b8a529751988990036011019098208a549485018b5599805291830490950180549890941c91909216909302900a9182029190920219909316929092179091555062000819565b6001600160e01b031980821614156200074f576040805162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015290519081900360640190fd5b6001600160e01b0319166000908152602260205260409020805460ff19166001179055565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620007b757805160ff1916838001178555620007e7565b82800160010185558215620007e7579182015b82811115620007e7578251825591602001919060010190620007ca565b50620007f5929150620007f9565b5090565b6200081691905b80821115620007f5576000815560010162000800565b90565b61569380620008296000396000f3fe608060405234801561001057600080fd5b50600436106103fc5760003560e01c8063803ab8d411610215578063c466544911610125578063e2bbb247116100b8578063f2b3abbd11610087578063f2b3abbd14610dc3578063f3f442dc14610de9578063f3fdb15a14610e15578063fcab181914610e1d578063ff10fd0314610e49576103fc565b8063e2bbb24714610d7d578063e55023e914610d85578063e985e9c514610d8d578063eb353e0b14610dbb576103fc565b8063cd9f132f116100f4578063cd9f132f14610b6d578063d313d52a14610d29578063d46e761c14610d31578063dc6336ca14610d57576103fc565b8063c466544914610c8f578063c5ebeaec14610cc9578063c87b56dd14610ce6578063cd9a107014610d03576103fc565b806395d89b41116101a8578063a8189fef11610177578063a8189fef14610b6d578063ab57934814610b75578063b4d443b314610b9b578063b88d4fde14610ba3578063b96f316214610c69576103fc565b806395d89b4114610a4e57806395d9abd614610a565780639d091b3e14610b21578063a22cb46514610b3f576103fc565b80639069195b116101e45780639069195b1461088d57806390f2b2ee146108955780639317c200146108c457806393e3f2dc14610a19576103fc565b8063803ab8d414610858578063852a12e31461086057806385a1f6821461087d578063898c9f0814610885576103fc565b80633ce7d72c116103105780635a874303116102a35780636752e702116102725780636752e702146107ce5780636cced083146107d65780636e9960c31461080457806370a082311461080c5780637ff1f2ce14610832576103fc565b80635a8743031461077b578063612cd875146107a15780636352211e146107a957806364865f7c146107c6576103fc565b80634fb0ed3d116102df5780634fb0ed3d1461071f5780635195a2ca14610727578063544c4f911461074d5780635553d7b614610755576103fc565b80633ce7d72c146106a057806342842e0e146106a857806344c09b10146106de57806348fb084f146106e6576103fc565b80630f06a9721161039357806323b872dd1161036257806323b872dd146105d257806326ce2a801461060857806338c4e18a1461062e5780633b954128146106545780633c3dfb7b1461067a576103fc565b80630f06a972146105b257806310cfe906146105ba578063173b9904146105c25780631b684a5e146105ca576103fc565b8063095ea7b3116103cf578063095ea7b31461052a5780630a6d9a90146105585780630b940c5c146105605780630bc90ee01461058c576103fc565b806301ffc9a71461040157806306fdde031461043c57806307195e5c146104b9578063081812fc146104f1575b600080fd5b6104286004803603602081101561041757600080fd5b50356001600160e01b031916610e6f565b604080519115158252519081900360200190f35b610444610e92565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561047e578181015183820152602001610466565b50505050905090810190601f1680156104ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104df600480360360208110156104cf57600080fd5b50356001600160a01b0316610fd5565b60408051918252519081900360200190f35b61050e6004803603602081101561050757600080fd5b5035611264565b604080516001600160a01b039092168252519081900360200190f35b6105566004803603604081101561054057600080fd5b506001600160a01b0381351690602001356112c6565b005b6104df6113ee565b6105566004803603604081101561057657600080fd5b506001600160a01b0381351690602001356113f4565b6104df600480360360208110156105a257600080fd5b50356001600160f01b0316611713565b6104df611725565b61050e61172b565b6104df611740565b6104df611746565b610556600480360360608110156105e857600080fd5b506001600160a01b0381358116916020810135909116906040013561174c565b6104df6004803603602081101561061e57600080fd5b50356001600160a01b03166117a8565b6104df6004803603602081101561064457600080fd5b50356001600160f01b03166118a1565b6104df6004803603602081101561066a57600080fd5b50356001600160f01b03166118b3565b6104286004803603602081101561069057600080fd5b50356001600160a01b03166118c5565b6104df6118da565b610556600480360360608110156106be57600080fd5b506001600160a01b038135811691602081013590911690604001356118e0565b61050e6118fb565b610703600480360360208110156106fc57600080fd5b503561190a565b604080516001600160f01b039092168252519081900360200190f35b61050e611925565b6104df6004803603602081101561073d57600080fd5b50356001600160f01b0316611934565b6104df611958565b6104df6004803603602081101561076b57600080fd5b50356001600160f01b031661195e565b6104df6004803603602081101561079157600080fd5b50356001600160f01b0316611970565b6104df611982565b61050e600480360360208110156107bf57600080fd5b503561198e565b6104286119e2565b6104df6119e7565b6104df600480360360408110156107ec57600080fd5b506001600160a01b03813516906020013515156119ed565b61050e611ab3565b6104df6004803603602081101561082257600080fd5b50356001600160a01b0316611ad6565b6104df6004803603602081101561084857600080fd5b50356001600160a01b0316611b3e565b610444611d7e565b6104df6004803603602081101561087657600080fd5b5035611e0c565b6104df611e2d565b6104df611e33565b610444611e39565b6104df600480360360808110156108ab57600080fd5b5080359060208101359060408101359060600135611e94565b610556600480360360c08110156108da57600080fd5b6001600160a01b03823581169260208101358216926040820135831692606083013516919081019060a08101608082013564010000000081111561091d57600080fd5b82018360208201111561092f57600080fd5b8035906020019184600183028401116401000000008311171561095157600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092959493602081019350359150506401000000008111156109a457600080fd5b8201836020820111156109b657600080fd5b803590602001918460018302840111640100000000831117156109d857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612032945050505050565b6104df600480360360a0811015610a2f57600080fd5b50803590602081013590604081013590606081013590608001356120b7565b6104446122a5565b6104df60048036036080811015610a6c57600080fd5b6001600160f01b03823516916020810135916001600160a01b036040830135169190810190608081016060820135640100000000811115610aac57600080fd5b820183602082011115610abe57600080fd5b80359060200191846001830284011164010000000083111715610ae057600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506122f5945050505050565b610b2961255a565b6040805160ff9092168252519081900360200190f35b61055660048036036040811015610b5557600080fd5b506001600160a01b0381351690602001351515612563565b6104df612668565b61050e60048036036020811015610b8b57600080fd5b50356001600160f01b031661266e565b610703612688565b61055660048036036080811015610bb957600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135640100000000811115610bf457600080fd5b820183602082011115610c0657600080fd5b80359060200191846001830284011164010000000083111715610c2857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612697945050505050565b6104df60048036036020811015610c7f57600080fd5b50356001600160f01b03166126f5565b610cac60048036036020811015610ca557600080fd5b5035612707565b604080516001600160e01b03199092168252519081900360200190f35b6104df60048036036020811015610cdf57600080fd5b503561273b565b61044460048036036020811015610cfc57600080fd5b5035612749565b6104df60048036036020811015610d1957600080fd5b50356001600160f01b031661295c565b6104df612d59565b6104df60048036036020811015610d4757600080fd5b50356001600160f01b0316612d5f565b6104df60048036036020811015610d6d57600080fd5b50356001600160f01b0316612d71565b6104df612d83565b6104df612d89565b61042860048036036040811015610da357600080fd5b506001600160a01b0381358116916020013516612d95565b6104df612dc3565b6104df60048036036020811015610dd957600080fd5b50356001600160a01b0316612dcf565b6104df60048036036040811015610dff57600080fd5b506001600160f01b038135169060200135612f73565b61050e613015565b610e25613024565b60405180826002811115610e3557fe5b60ff16815260200191505060405180910390f35b6104df60048036036020811015610e5f57600080fd5b50356001600160f01b0316613029565b6001600160e01b0319811660009081526022602052604090205460ff165b919050565b6060600160029054906101000a90046001600160a01b03166001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610ee257600080fd5b505afa158015610ef6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610f1f57600080fd5b8101908080516040519392919084640100000000821115610f3f57600080fd5b908301906020820185811115610f5457600080fd5b8251640100000000811182820188101715610f6e57600080fd5b82525081516020918201929091019080838360005b83811015610f9b578181015183820152602001610f83565b50505050905090810190601f168015610fc85780820380516001836020036101000a031916815260200191505b5060405250505090505b90565b60015460009060ff1661101c576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff191690556000611030611ab3565b9050336001600160a01b0382161461108f576040805162461bcd60e51b815260206004820152601660248201527f4f6e6c792061646d696e2063616e20646f207468617400000000000000000000604482015290519081900360640190fd5b6001546001600160a01b03848116620100009092041614156110f8576040805162461bcd60e51b815260206004820152601d60248201527f43616e6e6f7420737765657020756e6465726c79696e67206173736574000000604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038616916370a0823191602480820192602092909190829003018186803b15801561114257600080fd5b505afa158015611156573d6000803e3d6000fd5b505050506040513d602081101561116c57600080fd5b50519050806111c2576040805162461bcd60e51b815260206004820152601860248201527f4e6f206c6566746f76657220746f6b656e7320666f756e640000000000000000604482015290519081900360640190fd5b836001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561122257600080fd5b505af1158015611236573d6000803e3d6000fd5b505050506040513d602081101561124c57600080fd5b5090925050505b6001805460ff191681179055919050565b600061126f8261303b565b6112aa5760405162461bcd60e51b815260040180806020018281038252602c81526020018061550e602c913960400191505060405180910390fd5b506000908152602660205260409020546001600160a01b031690565b60006112d18261198e565b9050806001600160a01b0316836001600160a01b031614156113245760405162461bcd60e51b815260040180806020018281038252602181526020018061558b6021913960400191505060405180910390fd5b806001600160a01b0316611336613058565b6001600160a01b03161480611357575061135781611352613058565b612d95565b6113925760405162461bcd60e51b815260040180806020018281038252603881526020018061545b6038913960400191505060405180910390fd5b60008281526026602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600b5481565b60015460ff16611438576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff19169055600061144c611ab3565b9050336001600160a01b038216146114ab576040805162461bcd60e51b815260206004820152601660248201527f4f6e6c792061646d696e2063616e20646f207468617400000000000000000000604482015290519081900360640190fd5b6001546001600160a01b03848116620100009092041614156115c6576000828152601360205260409020546001600160f01b031680156115c45760006001600160a01b0316846001600160a01b0316636352211e836040518263ffffffff1660e01b815260040180826001600160f01b0316815260200191505060206040518083038186803b15801561153d57600080fd5b505afa158015611551573d6000803e3d6000fd5b505050506040513d602081101561156757600080fd5b50516001600160a01b0316146115c4576040805162461bcd60e51b815260206004820152601a60248201527f43616e6e6f7420737765657020726567756c6172206173736574000000000000604482015290519081900360640190fd5b505b826001600160a01b0316636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561160a57600080fd5b505afa15801561161e573d6000803e3d6000fd5b505050506040513d602081101561163457600080fd5b50516001600160a01b03163014611692576040805162461bcd60e51b815260206004820152601b60248201527f546f6b656e206e6f74206f776e656420627920636f6e74726163740000000000604482015290519081900360640190fd5b60408051632142170760e11b81523060048201526001600160a01b038381166024830152604482018590529151918516916342842e0e9160648082019260009290919082900301818387803b1580156116ea57600080fd5b505af11580156116fe573d6000803e3d6000fd5b50506001805460ff1916811790555050505050565b601b6020526000908152604090205481565b60145481565b6001546201000090046001600160a01b031681565b60095481565b600d5481565b61175d611757613058565b8261305c565b6117985760405162461bcd60e51b81526004018080602001828103825260318152602001806155ac6031913960400191505060405180910390fd5b6117a38383836130f8565b505050565b60015460009060ff166117ef576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff19169055611801611ab3565b6001600160a01b0316336001600160a01b03161461182c576118256001605961323c565b9050611253565b600380546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fd02b9ea8a918c48a5443286ad7bbb9d8e48146f8cb711a42b0109e1a46e3ab3b929181900390910190a160005b6001805460ff1916811790559392505050565b601c6020526000908152604090205481565b60196020526000908152604090205481565b600c6020526000908152604090205460ff1681565b60005490565b6117a383838360405180602001604052806000815250612697565b6004546001600160a01b031681565b6013602052600090815260409020546001600160f01b031681565b6003546001600160a01b031681565b600061195282600080604051806020016040528060008152506122f5565b92915050565b60105481565b60126020526000908152604090205481565b601a6020526000908152604090205481565b6702c68af0bb14000081565b6000818152602560205260408120546001600160a01b0316806119525760405162461bcd60e51b81526004018080602001828103825260298152602001806154e56029913960400191505060405180910390fd5b600190565b600a5481565b60006119f7611ab3565b6001600160a01b0316336001600160a01b031614611a2257611a1b6001605161323c565b9050611952565b6001600160a01b0383166000908152600c602052604090205460ff16151582151514611aa9576001600160a01b0383166000818152600c6020908152604091829020805460ff191686151590811790915582519384529083015280517f2e1e9be77cccab0d36f4e5683584850b1b1b8c0bc8613a8911959754f145e79b9281900390910190a15b60005b9392505050565b600080604051808061549360289139604051908190036028019020549392505050565b60006001600160a01b038216611b1d5760405162461bcd60e51b815260040180806020018281038252602a8152602001806154bb602a913960400191505060405180910390fd5b6001600160a01b0382166000908152602760205260409020611952906132a2565b60015460009060ff16611b85576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff19169055611b97611ab3565b6001600160a01b0316336001600160a01b031614611bbb576118256001604d61323c565b6004805460408051635f41b85d60e01b815290516001600160a01b039283169392861692635f41b85d92808201926020929091829003018186803b158015611c0257600080fd5b505afa158015611c16573d6000803e3d6000fd5b505050506040513d6020811015611c2c57600080fd5b5051611c72576040805162461bcd60e51b815260206004820152601060248201526f34b73b30b634b21036ba3937b63632b960811b604482015290519081900360640190fd5b826001600160a01b03166364865f7c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611cab57600080fd5b505afa158015611cbf573d6000803e3d6000fd5b505050506040513d6020811015611cd557600080fd5b5051611d1b576040805162461bcd60e51b815260206004820152601060248201526f34b73b30b634b21036ba3937b63632b960811b604482015290519081900360640190fd5b600480546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517fe006bb2a70c33154cb00e229b7c7f579ed53dc27d89d70e8b297a3d623060e8e9281900390910190a1600061188e565b6006805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015611e045780601f10611dd957610100808354040283529160200191611e04565b820191906000526020600020905b815481529060010190602001808311611de757829003601f168201915b505050505081565b600081815260136020526040812054611952906001600160f01b0316611934565b61c35081565b600e5481565b6005805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015611e045780601f10611dd957610100808354040283529160200191611e04565b6000611e9e611ab3565b6001600160a01b0316336001600160a01b031614611eed5760405162461bcd60e51b815260040180806020018281038252602d8152602001806153e0602d913960400191505060405180910390fd5b6000198514158015611f0157506008548514155b15611f245784611f1e57611f176002604c61323c565b905061202a565b60088590555b6000198414158015611f3857506009548414155b15611f5f576706f05b59d3b20000841115611f5957611f176002604c61323c565b60098490555b6000198314158015611f735750600a548314155b15611f995766b1a2bc2ec50000831115611f9357611f176002604c61323c565b600a8390555b6000198214158015611fad5750600b548214155b15611fd4576706f05b59d3b20000821115611fce57611f176002604c61323c565b600b8290555b600854600954600a54600b54604080519485526020850193909352838301919091526060830152517fa0c702f70b94ab8d7d21bab46c426f8d14b361d65a8d6464f073abe2d1aee0b19181900360800190a15060005b949350505050565b61204e8686866000670de0b6b3a76400006000888860126132a6565b6000612059846117a8565b905080156120ae576040805162461bcd60e51b815260206004820152601b60248201527f73657474696e6720746f6b656e41756374696f6e206661696c65640000000000604482015290519081900360640190fd5b50505050505050565b60006120c1611ab3565b6001600160a01b0316336001600160a01b0316146121105760405162461bcd60e51b815260040180806020018281038252602c815260200180615390602c913960400191505060405180910390fd5b60001986141580156121245750600d548614155b15612158576107d086108061213a575061c35086115b156121525761214b6002604c61323c565b905061229c565b600d8690555b600019851415801561216c5750600e548514155b1561218d576107d08511156121875761214b6002604c61323c565b600e8590555b60001984141580156121a15750600f548414155b156121c857670b1a2bc2ec5000008411156121c25761214b6002604c61323c565b600f8490555b60001983141580156121dc57506010548314155b156122035767016345785d8a00008311156121fd5761214b6002604c61323c565b60108390555b600019821415801561221757506011548214155b1561223e576702c68af0bb1400008211156122385761214b6002604c61323c565b60118290555b600d54600e54600f546010546011546040805195865260208601949094528484019290925260608401526080830152517f4c6615c4f0e96eb7f735a195a6965a1c69a802ade75651de4cd935b8fcba6bd89181900360a00190a15060005b95945050505050565b6060600160029054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610ee257600080fd5b60015460009060ff1661233c576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff191690556123586001600160f01b03861661198e565b6001600160a01b0316336001600160a01b0316146123835761237c6001603b61323c565b9050612546565b6001600160f01b0385166000908152601760209081526040808320338452909152902054670de0b6b3a764000014612402576040805162461bcd60e51b815260206004820152601d60248201527f496e76616c696420696e7465726e616c20746f6b656e20616d6f756e74000000604482015290519081900360640190fd5b6001600160f01b0385166000908152602160205260409020541561243a576001600160f01b0385166000908152602160205260408120555b600061245486670de0b6b3a76400006000338989896136c7565b90508015612463579050612546565b600480546040805163df83bb5560e01b81526001600160f01b038a1693810193909352336024840152516001600160a01b039091169163df83bb559160448083019260209291908290030181600087803b1580156124c057600080fd5b505af11580156124d4573d6000803e3d6000fd5b505050506040513d60208110156124ea57600080fd5b505160408051808201909152601981527f72656465656d206d61726b65742065786974206661696c656400000000000000602082015290915061252e908290613df0565b612540866001600160f01b0316613ff0565b60009150505b6001805460ff191681179055949350505050565b60075460ff1681565b61256b613058565b6001600160a01b0316826001600160a01b031614156125d1576040805162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015290519081900360640190fd5b80602860006125de613058565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155612622613058565b60408051841515815290516001600160a01b0392909216917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319181900360200190a35050565b6107d081565b60208052600090815260409020546001600160a01b031681565b601d546001600160f01b031681565b6126a86126a2613058565b8361305c565b6126e35760405162461bcd60e51b81526004018080602001828103825260318152602001806155ac6031913960400191505060405180910390fd5b6126ef84848484614005565b50505050565b60156020526000908152604090205481565b6000818154811061271457fe5b9060005260206000209060089182820401919006600402915054906101000a900460e01b81565b60006119526003601061323c565b60606127548261303b565b6127a5576040805162461bcd60e51b815260206004820152601f60248201527f55524920717565727920666f72206e6f6e6578697374656e7420746f6b656e00604482015290519081900360640190fd5b6001600160f01b03821115612801576040805162461bcd60e51b815260206004820152601f60248201527f55524920717565727920666f72206e6f6e6578697374656e7420746f6b656e00604482015290519081900360640190fd5b6001546001600160f01b03831660009081526012602052604080822054815163c87b56dd60e01b81526004810191909152905185936201000090046001600160a01b03169263c87b56dd9260248082019391829003018186803b15801561286757600080fd5b505afa15801561287b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156128a457600080fd5b81019080805160405193929190846401000000008211156128c457600080fd5b9083019060208201858111156128d957600080fd5b82516401000000008111828201881017156128f357600080fd5b82525081516020918201929091019080838360005b83811015612920578181015183820152602001612908565b50505050905090810190601f16801561294d5780820380516001836020036101000a031916815260200191505b50604052505050915050919050565b60006129666151eb565b61296e614057565b81526001600160f01b038316600090815260156020908152604090912054908201819052815114156129a4576000915050610e8d565b6001600160f01b038316600081815260196020908152604080832054858201908152848452601a83528184205460608701908152858552601b84528285205460808801908152958552601684528285205460a088015260025491519051955183516315f2405360e01b8152600481019290925260248201969096526044810195909552905192936001600160a01b03909116926315f2405392606480840193919291829003018186803b158015612a5a57600080fd5b505afa158015612a6e573d6000803e3d6000fd5b505050506040513d6020811015612a8457600080fd5b5051905065048c27395000811115612ae3576040805162461bcd60e51b815260206004820152601c60248201527f626f72726f772072617465206973206162737572646c79206869676800000000604482015290519081900360640190fd5b600080612af88460000151856020015161405b565b90925090506000826003811115612b0b57fe5b14612b5d576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b612b65615221565b600080600080612b8360405180602001604052808a81525087614081565b90975094506000876003811115612b9657fe5b14612bc357612bb3600a6006896003811115612bae57fe5b6140e9565b9950505050505050505050610e8d565b612bd1858a6060015161414f565b90975093506000876003811115612be457fe5b14612bfc57612bb3600a6001896003811115612bae57fe5b612c0a848a606001516141a2565b90975092506000876003811115612c1d57fe5b14612c3557612bb3600a6004896003811115612bae57fe5b612c546040518060200160405280600954815250858b608001516141c8565b90975091506000876003811115612c6757fe5b14612c7f57612bb3600a6005896003811115612bae57fe5b60a0890151612c90908690806141c8565b90975090506000876003811115612ca357fe5b14612cbb57612bb3600a6003896003811115612bae57fe5b88516001600160f01b038c1660008181526015602090815260408083209490945560168152838220859055601a8152838220879055601b815290839020859055828c0151835192835290820152808201869052606081018390526080810185905290517f2b81b82a202c39cb77f20e04085b90ad1d9896deee9ad11875c31a30f3c190a79181900360a00190a160009b9a5050505050505050505050565b60115481565b60166020526000908152604090205481565b60216020526000908152604090205481565b600f5481565b67016345785d8a000081565b6001600160a01b03918216600090815260286020908152604080832093909416825291909152205460ff1690565b670b1a2bc2ec50000081565b60015460009060ff16612e16576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff19169055612e28611ab3565b6001600160a01b0316336001600160a01b031614612e4c576118256001605061323c565b600254604080516310c8fc9560e11b815290516001600160a01b0392831692851691632191f92a916004808301926020929190829003018186803b158015612e9357600080fd5b505afa158015612ea7573d6000803e3d6000fd5b505050506040513d6020811015612ebd57600080fd5b5051612f10576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a1600061188e565b60015460009060ff16612fba576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff191690556000612fcf8461295c565b90508015612ff557612fed816011811115612fe657fe5b603c61323c565b915050613003565b612fff8484614224565b9150505b6001805460ff19168117905592915050565b6002546001600160a01b031681565b600290565b601f6020526000908152604090205481565b6000908152602560205260409020546001600160a01b0316151590565b3390565b60006130678261303b565b6130a25760405162461bcd60e51b815260040180806020018281038252602c81526020018061540d602c913960400191505060405180910390fd5b60006130ad8361198e565b9050806001600160a01b0316846001600160a01b031614806130e85750836001600160a01b03166130dd84611264565b6001600160a01b0316145b8061202a575061202a8185612d95565b826001600160a01b031661310b8261198e565b6001600160a01b0316146131505760405162461bcd60e51b81526004018080602001828103825260298152602001806155626029913960400191505060405180910390fd5b6001600160a01b0382166131955760405162461bcd60e51b81526004018080602001828103825260248152602001806153bc6024913960400191505060405180910390fd5b61319e816143ea565b6001600160a01b03831660009081526027602052604090206131bf90614425565b6001600160a01b03821660009081526027602052604090206131e09061443c565b60008181526025602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561326b57fe5b83606281111561327757fe5b604080519283526020830191909152600082820152519081900360600190a1826011811115611aac57fe5b5490565b6132ae611ab3565b6001600160a01b0316336001600160a01b0316146132fd5760405162461bcd60e51b815260040180806020018281038252602881526020018061553a6028913960400191505060405180910390fd5b6001805461ff001960ff1990911682171661010017908190556201000090046001600160a01b031615613377576040805162461bcd60e51b815260206004820152601360248201527f616c726561647920696e697469616c697a656400000000000000000000000000604482015290519081900360640190fd5b6001805475ffffffffffffffffffffffffffffffffffffffff00001916620100006001600160a01b038c160217905560006133b188612dcf565b905080156133f05760405162461bcd60e51b81526004018080602001828103825260228152602001806154396022913960400191505060405180910390fd5b6133f989611b3e565b9050801561344e576040805162461bcd60e51b815260206004820152601760248201527f73657474696e67206d74726f6c6c6572206661696c6564000000000000000000604482015290519081900360640190fd5b613461868887661c6bf526340000611e94565b905080156134a05760405162461bcd60e51b81526004018080602001828103825260298152602001806156026029913960400191505060405180910390fd5b6134ba6107d06101f4600066b1a2bc2ec5000060006120b7565b905080156134f95760405162461bcd60e51b81526004018080602001828103825260288152602001806153686028913960400191505060405180910390fd5b835161350c906005906020870190615234565b508251613520906006906020860190615234565b506007805460ff191660ff84161790556004805460408051633833821160e11b81523093810193909352516000926001600160a01b03909216916370670422916024808301926020929190829003018186803b15801561357f57600080fd5b505afa158015613593573d6000803e3d6000fd5b505050506040513d60208110156135a957600080fd5b50516001600160f01b0381166000908152601560205260409020549091501580156135ea57506001600160f01b038116600090815260166020526040902054155b6136255760405162461bcd60e51b81526004018080602001828103825260238152602001806153136023913960400191505060405180910390fd5b61362d614057565b6001600160f01b0382166000908152601560209081526040808320939093556016905220670de0b6b3a764000090556136658161295c565b915081156136ba576040805162461bcd60e51b815260206004820152601660248201527f61636372756520696e746572657374206661696c656400000000000000000000604482015290519081900360640190fd5b5050505050505050505050565b6000338715806136d5575086155b6137105760405162461bcd60e51b815260040180806020018281038252603481526020018061562b6034913960400191505060405180910390fd5b600061371b8a61295c565b905080156137425761373981601181111561373257fe5b603161323c565b92505050613de5565b61374a6152b2565b6137538b614445565b604083018190526020830182600381111561376a57fe5b600381111561377557fe5b905250600090508160200151600381111561378c57fe5b146137b2576137a8600a603583602001516003811115612bae57fe5b9350505050613de5565b891561383357606081018a9052604080516020810182529082015181526137d9908b61414f565b60808301819052602083018260038111156137f057fe5b60038111156137fb57fe5b905250600090508160200151600381111561381257fe5b1461382e576137a8600a603383602001516003811115612bae57fe5b6138ac565b61384f8960405180602001604052808460400151815250614532565b606083018190526020830182600381111561386657fe5b600381111561387157fe5b905250600090508160200151600381111561388857fe5b146138a4576137a8600a603483602001516003811115612bae57fe5b608081018990525b6001600160f01b038b166000908152601c602052604090205460608201516138d4919061405b565b60a08301819052602083018260038111156138eb57fe5b60038111156138f657fe5b905250600090508160200151600381111561390d57fe5b14613929576137a8600a603883602001516003811115612bae57fe5b6001600160f01b038b1660009081526017602090815260408083206001600160a01b03871684529091529020546060820151613965919061405b565b60c083018190526020830182600381111561397c57fe5b600381111561398757fe5b905250600090508160200151600381111561399e57fe5b146139ba576137a8600a603783602001516003811115612bae57fe5b6001600160f01b038b1660009081526019602052604090205460808201516139e2919061405b565b60e08301819052602083018260038111156139f957fe5b6003811115613a0457fe5b9052506000905081602001516003811115613a1b57fe5b14613a2c576137a8600f603961323c565b6001600160f01b038b166000908152601260205260409020546001600160a01b03871615613af6576001600160a01b0387166000908152600c602052604090205460ff1680613aa5575060008052600c6020527f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e85460ff165b613af6576040805162461bcd60e51b815260206004820152601e60248201527f666c617368207265636569766572206e6f742077686974656c69737465640000604482015290519081900360640190fd5b613b08898284608001518b8b8b614549565b5060a08201516001600160f01b038d166000818152601c602090815260408083209490945560c0860151601782528483206001600160a01b038a168085529083528584209190915560e087015184845260198352928590209290925560608087015185519384523092840192909252828501939093529181019190915290517f66ed29aeec2aa72b56b2b8f0d3626cef3638915b138caebcf264a45640e46e599181900360800190a17fcf56a6ceefee399a04b7b25cbcbdbc9ea3d7bceba48ca55c47c30f8ca2c2eec0848d846060015184866080015160405180866001600160a01b03166001600160a01b03168152602001856001600160f01b03166001600160f01b031681526020018481526020018381526020018281526020019550505050505060405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663e191aceb8d8660006040518463ffffffff1660e01b815260040180846001600160f01b03166001600160f01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060206040518083038186803b158015613cc257600080fd5b505afa158015613cd6573d6000803e3d6000fd5b505050506040513d6020811015613cec57600080fd5b505160408051808201909152600d81526c1c995919595b4819985a5b1959609a1b6020820152909350613d20908490613df0565b600460009054906101000a90046001600160a01b03166001600160a01b03166339291dd18d86856080015186606001516040518563ffffffff1660e01b815260040180856001600160f01b03166001600160f01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200182815260200194505050505060006040518083038186803b158015613dbd57600080fd5b505afa158015613dd1573d6000803e3d6000fd5b5060009250613dde915050565b9450505050505b979650505050505050565b81613dfa57613fec565b606081516005016040519080825280601f01601f191660200182016040528015613e2b576020820181803883390190505b50905060005b8251811015613e7c57828181518110613e4657fe5b602001015160f81c60f81b828281518110613e5d57fe5b60200101906001600160f81b031916908160001a905350600101613e31565b8151600160fd1b90839083908110613e9057fe5b60200101906001600160f81b031916908160001a905350602860f81b828260010181518110613ebb57fe5b60200101906001600160f81b031916908160001a905350600a840460300160f81b828260020181518110613eeb57fe5b60200101906001600160f81b031916908160001a905350600a840660300160f81b828260030181518110613f1b57fe5b60200101906001600160f81b031916908160001a905350602960f81b828260040181518110613f4657fe5b60200101906001600160f81b031916908160001a905350818415613fe85760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613fad578181015183820152602001613f95565b50505050905090810190601f168015613fda5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050505b5050565b614002613ffc8261198e565b82614c29565b50565b6140108484846130f8565b61401c84848484614d00565b6126ef5760405162461bcd60e51b81526004018080602001828103825260328152602001806153366032913960400191505060405180910390fd5b4390565b60008083831161407257506000905081830361407a565b506003905060005b9250929050565b600061408b615221565b60008061409c866000015186614f50565b909250905060008260038111156140af57fe5b146140ce5750604080516020810190915260008152909250905061407a565b60408051602081019091529081526000969095509350505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa084601181111561411857fe5b84606281111561412457fe5b604080519283526020830191909152818101859052519081900360600190a183601181111561202a57fe5b600080600061415c615221565b6141668686614081565b9092509050600082600381111561417957fe5b1461418a575091506000905061407a565b600061419582614f8f565b9350935050509250929050565b6000808383018481106141ba5760009250905061407a565b50600291506000905061407a565b60008060006141d5615221565b6141df8787614081565b909250905060008260038111156141f257fe5b14614203575091506000905061421c565b61421561420f82614f8f565b866141a2565b9350935050505b935093915050565b6000806000806000614234611ab3565b9050336001600160a01b0382161461425d576142526001603d61323c565b945050505050611952565b614265614057565b6001600160f01b0388166000908152601560205260409020541461428f57614252600b603f61323c565b6001600160f01b0387166000908152601b60205260409020546142b2908761405b565b909450925060008460038111156142c557fe5b146142d6576142526002604061323c565b6001600160f01b0387166000908152601960205260409020546142f9908761405b565b9094509150600084600381111561430c57fe5b1461431d57614252600f603e61323c565b600060126000896001600160f01b03166001600160f01b0316815260200190815260200160002054905061436582828960008060405180602001604052806000815250614549565b506001600160f01b0388166000818152601b60209081526040808320889055601982529182902086905581516001600160a01b03861681529081019290925281810189905260608201869052517fda3e40794fb56e711ccb786edc2367eefe141f8a12f51fbc2a4a58773a82e1be9181900360800190a1600098975050505050505050565b6000818152602660205260409020546001600160a01b03161561400257600090815260266020526040902080546001600160a01b0319169055565b805461443890600163ffffffff614f9e16565b9055565b80546001019055565b6001600160f01b0381166000908152601c60205260408120548190806144735750506008546000915061452d565b6001600160f01b03841660009081526019602052604081205490614495615221565b6001600160f01b0387166000908152601a6020908152604080832054601b9092528220546144c4918691614fe0565b9350905060008160038111156144d657fe5b146144eb5795506000945061452d9350505050565b6144f5838661501e565b92509050600081600381111561450757fe5b1461451c5795506000945061452d9350505050565b505160009550935061452d92505050565b915091565b600080600061453f615221565b61416686866150ce565b6000670de0b6b3a764000085146145a7576040805162461bcd60e51b815260206004820152601660248201527f416d6f756e74206d757374206265206f6e65556e697400000000000000000000604482015290519081900360640190fd5b6001600160a01b03831661471e5760015460408051632142170760e11b81523060048201526001600160a01b038a81166024830152604482018a9052915162010000909304909116916342842e0e9160648082019260009290919082900301818387803b15801561461757600080fd5b505af115801561462b573d6000803e3d6000fd5b50505050866001600160a01b0316600160029054906101000a90046001600160a01b03166001600160a01b0316636352211e886040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561469257600080fd5b505afa1580156146a6573d6000803e3d6000fd5b505050506040513d60208110156146bc57600080fd5b50516001600160a01b031614614719576040805162461bcd60e51b815260206004820152601360248201527f5472616e73666572206f7574206661696c656400000000000000000000000000604482015290519081900360640190fd5b614c1e565b60015460408051632142170760e11b81523060048201526001600160a01b038681166024830152604482018a9052915162010000909304909116916342842e0e9160648082019260009290919082900301818387803b15801561478057600080fd5b505af1158015614794573d6000803e3d6000fd5b505050506000600360009054906101000a90046001600160a01b03166001600160a01b0316633013ce296040518163ffffffff1660e01b815260040160206040518083038186803b1580156147e857600080fd5b505afa1580156147fc573d6000803e3d6000fd5b505050506040513d602081101561481257600080fd5b50516040805163b4d443b360e01b815290519192506000916001600160a01b0384169163b4d443b3916004808301926020929190829003018186803b15801561485a57600080fd5b505afa15801561486e573d6000803e3d6000fd5b505050506040513d602081101561488457600080fd5b505160408051630f42eabd60e21b81526001600160a01b03808d16600483018190526001600160f01b03851660248401529251939450913192600092861691633d0baaf491604480830192602092919082900301818787803b1580156148e957600080fd5b505af11580156148fd573d6000803e3d6000fd5b505050506040513d602081101561491357600080fd5b810190808051906020019092919050505090506000876001600160a01b03166375ce55308c8e8c8b6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156149ab578181015183820152602001614993565b50505050905090810190601f1680156149d85780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b1580156149fa57600080fd5b505af1158015614a0e573d6000803e3d6000fd5b505050506040513d6020811015614a2457600080fd5b505190508015614a7b576040805162461bcd60e51b815260206004820152601960248201527f5472616e73666572206f7065726174696f6e206661696c656400000000000000604482015290519081900360640190fd5b6001600160a01b038c163183811015614adb576040805162461bcd60e51b815260206004820152601960248201527f4e65676174697665207265636569766564207061796d656e7400000000000000604482015290519081900360640190fd5b604080516372434afd60e11b81526001600160a01b038f811660048301526001600160f01b03881660248301529151928690039260009289169163e48695fa916044808301926020929190829003018186803b158015614b3a57600080fd5b505afa158015614b4e573d6000803e3d6000fd5b505050506040513d6020811015614b6457600080fd5b5051905080841015614bbd576040805162461bcd60e51b815260206004820152601060248201527f426f72726f7720696e6372656173656400000000000000000000000000000000604482015290519081900360640190fd5b83038181018b1115614c16576040805162461bcd60e51b815260206004820152601860248201527f5265636569766564207061796d656e7420746f6f206c6f770000000000000000604482015290519081900360640190fd5b505050505050505b509295945050505050565b816001600160a01b0316614c3c8261198e565b6001600160a01b031614614c815760405162461bcd60e51b81526004018080602001828103825260258152602001806155dd6025913960400191505060405180910390fd5b614c8a816143ea565b6001600160a01b0382166000908152602760205260409020614cab90614425565b60008181526025602052604080822080546001600160a01b0319169055518291906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000614d14846001600160a01b031661512d565b614d205750600161202a565b600060606001600160a01b038616630a85bd0160e11b614d3e613058565b89888860405160240180856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614db7578181015183820152602001614d9f565b50505050905090810190601f168015614de45780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909a16999099178952518151919890975087965094509250829150849050835b60208310614e615780518252601f199092019160209182019101614e42565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614ec3576040519150601f19603f3d011682016040523d82523d6000602084013e614ec8565b606091505b509150915081614f1957805115614ee25780518082602001fd5b60405162461bcd60e51b81526004018080602001828103825260328152602001806153366032913960400191505060405180910390fd5b6000818060200190516020811015614f3057600080fd5b50516001600160e01b031916630a85bd0160e11b14935061202a92505050565b60008083614f635750600090508061407a565b83830283858281614f7057fe5b0414614f845750600291506000905061407a565b60009250905061407a565b51670de0b6b3a7640000900490565b6000611aac83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250615166565b600080600080614ff087876141a2565b9092509050600082600381111561500357fe5b14615014575091506000905061421c565b614215818661405b565b6000615028615221565b60008061503d86670de0b6b3a7640000614f50565b9092509050600082600381111561505057fe5b1461506f5750604080516020810190915260008152909250905061407a565b60008061507c83886151c0565b9092509050600082600381111561508f57fe5b146150b15750604080516020810190915260008152909450925061407a915050565b604080516020810190915290815260009890975095505050505050565b60006150d8615221565b6000806150ed670de0b6b3a764000087614f50565b9092509050600082600381111561510057fe5b1461511f5750604080516020810190915260008152909250905061407a565b61419581866000015161501e565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061202a575050151592915050565b600081848411156151b85760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613fad578181015183820152602001613f95565b505050900390565b600080826151d4575060019050600061407a565b60008385816151df57fe5b04915091509250929050565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060200160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061527557805160ff19168380011785556152a2565b828001600101855582156152a2579182015b828111156152a2578251825591602001919060010190615287565b506152ae9291506152f8565b5090565b6040805161010081019091528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b610fd291905b808211156152ae57600081556001016152fe56fe6d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e63654552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e74657273657474696e6720676c6f62616c2061756374696f6e20706172616d6574657273206661696c65646f6e6c792061646d696e2063616e2073657420676c6f62616c2061756374696f6e20706172616d65746572734552433732313a207472616e7366657220746f20746865207a65726f20616464726573736f6e6c792061646d696e2063616e2073657420676c6f62616c2070726f746f636f6c20706172616d65746572734552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e73657474696e6720696e7465726573742072617465206d6f64656c206661696c65644552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c636f6d2e6d6d6f2d66696e616e63652e6d44656c656761746f722e61646d696e2e616464726573734552433732313a2062616c616e636520717565727920666f7220746865207a65726f20616464726573734552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e6f6e6c792061646d696e2063616e20696e697469616c697a6520746f6b656e20636f6e74726163744552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732313a20617070726f76616c20746f2063757272656e74206f776e65724552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665644552433732313a206275726e206f6620746f6b656e2074686174206973206e6f74206f776e73657474696e6720676c6f62616c2070726f746f636f6c20706172616d6574657273206661696c65646f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726fa265627a7a723158209005a9de716f4718928270bc21a6a99c31d236136ec6e7608e2a9a59a3b144e564736f6c63430005100032290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56369734d44656c656761746f7241646d696e496d706c656d656e746174696f6e28295f736574466c617368526563656976657257686974654c69737428616464726573732c626f6f6c295f736574476c6f62616c50726f746f636f6c506172616d65746572732875696e743235362c75696e743235362c75696e743235362c75696e7432353629696e697469616c697a6528616464726573732c616464726573732c616464726573732c616464726573732c737472696e672c737472696e67295f736574476c6f62616c41756374696f6e506172616d65746572732875696e743235362c75696e743235362c75696e743235362c75696e743235362c75696e743235362972656465656d416e6453656c6c2875696e743234302c75696e743235362c616464726573732c627974657329
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103fc5760003560e01c8063803ab8d411610215578063c466544911610125578063e2bbb247116100b8578063f2b3abbd11610087578063f2b3abbd14610dc3578063f3f442dc14610de9578063f3fdb15a14610e15578063fcab181914610e1d578063ff10fd0314610e49576103fc565b8063e2bbb24714610d7d578063e55023e914610d85578063e985e9c514610d8d578063eb353e0b14610dbb576103fc565b8063cd9f132f116100f4578063cd9f132f14610b6d578063d313d52a14610d29578063d46e761c14610d31578063dc6336ca14610d57576103fc565b8063c466544914610c8f578063c5ebeaec14610cc9578063c87b56dd14610ce6578063cd9a107014610d03576103fc565b806395d89b41116101a8578063a8189fef11610177578063a8189fef14610b6d578063ab57934814610b75578063b4d443b314610b9b578063b88d4fde14610ba3578063b96f316214610c69576103fc565b806395d89b4114610a4e57806395d9abd614610a565780639d091b3e14610b21578063a22cb46514610b3f576103fc565b80639069195b116101e45780639069195b1461088d57806390f2b2ee146108955780639317c200146108c457806393e3f2dc14610a19576103fc565b8063803ab8d414610858578063852a12e31461086057806385a1f6821461087d578063898c9f0814610885576103fc565b80633ce7d72c116103105780635a874303116102a35780636752e702116102725780636752e702146107ce5780636cced083146107d65780636e9960c31461080457806370a082311461080c5780637ff1f2ce14610832576103fc565b80635a8743031461077b578063612cd875146107a15780636352211e146107a957806364865f7c146107c6576103fc565b80634fb0ed3d116102df5780634fb0ed3d1461071f5780635195a2ca14610727578063544c4f911461074d5780635553d7b614610755576103fc565b80633ce7d72c146106a057806342842e0e146106a857806344c09b10146106de57806348fb084f146106e6576103fc565b80630f06a9721161039357806323b872dd1161036257806323b872dd146105d257806326ce2a801461060857806338c4e18a1461062e5780633b954128146106545780633c3dfb7b1461067a576103fc565b80630f06a972146105b257806310cfe906146105ba578063173b9904146105c25780631b684a5e146105ca576103fc565b8063095ea7b3116103cf578063095ea7b31461052a5780630a6d9a90146105585780630b940c5c146105605780630bc90ee01461058c576103fc565b806301ffc9a71461040157806306fdde031461043c57806307195e5c146104b9578063081812fc146104f1575b600080fd5b6104286004803603602081101561041757600080fd5b50356001600160e01b031916610e6f565b604080519115158252519081900360200190f35b610444610e92565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561047e578181015183820152602001610466565b50505050905090810190601f1680156104ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104df600480360360208110156104cf57600080fd5b50356001600160a01b0316610fd5565b60408051918252519081900360200190f35b61050e6004803603602081101561050757600080fd5b5035611264565b604080516001600160a01b039092168252519081900360200190f35b6105566004803603604081101561054057600080fd5b506001600160a01b0381351690602001356112c6565b005b6104df6113ee565b6105566004803603604081101561057657600080fd5b506001600160a01b0381351690602001356113f4565b6104df600480360360208110156105a257600080fd5b50356001600160f01b0316611713565b6104df611725565b61050e61172b565b6104df611740565b6104df611746565b610556600480360360608110156105e857600080fd5b506001600160a01b0381358116916020810135909116906040013561174c565b6104df6004803603602081101561061e57600080fd5b50356001600160a01b03166117a8565b6104df6004803603602081101561064457600080fd5b50356001600160f01b03166118a1565b6104df6004803603602081101561066a57600080fd5b50356001600160f01b03166118b3565b6104286004803603602081101561069057600080fd5b50356001600160a01b03166118c5565b6104df6118da565b610556600480360360608110156106be57600080fd5b506001600160a01b038135811691602081013590911690604001356118e0565b61050e6118fb565b610703600480360360208110156106fc57600080fd5b503561190a565b604080516001600160f01b039092168252519081900360200190f35b61050e611925565b6104df6004803603602081101561073d57600080fd5b50356001600160f01b0316611934565b6104df611958565b6104df6004803603602081101561076b57600080fd5b50356001600160f01b031661195e565b6104df6004803603602081101561079157600080fd5b50356001600160f01b0316611970565b6104df611982565b61050e600480360360208110156107bf57600080fd5b503561198e565b6104286119e2565b6104df6119e7565b6104df600480360360408110156107ec57600080fd5b506001600160a01b03813516906020013515156119ed565b61050e611ab3565b6104df6004803603602081101561082257600080fd5b50356001600160a01b0316611ad6565b6104df6004803603602081101561084857600080fd5b50356001600160a01b0316611b3e565b610444611d7e565b6104df6004803603602081101561087657600080fd5b5035611e0c565b6104df611e2d565b6104df611e33565b610444611e39565b6104df600480360360808110156108ab57600080fd5b5080359060208101359060408101359060600135611e94565b610556600480360360c08110156108da57600080fd5b6001600160a01b03823581169260208101358216926040820135831692606083013516919081019060a08101608082013564010000000081111561091d57600080fd5b82018360208201111561092f57600080fd5b8035906020019184600183028401116401000000008311171561095157600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092959493602081019350359150506401000000008111156109a457600080fd5b8201836020820111156109b657600080fd5b803590602001918460018302840111640100000000831117156109d857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612032945050505050565b6104df600480360360a0811015610a2f57600080fd5b50803590602081013590604081013590606081013590608001356120b7565b6104446122a5565b6104df60048036036080811015610a6c57600080fd5b6001600160f01b03823516916020810135916001600160a01b036040830135169190810190608081016060820135640100000000811115610aac57600080fd5b820183602082011115610abe57600080fd5b80359060200191846001830284011164010000000083111715610ae057600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506122f5945050505050565b610b2961255a565b6040805160ff9092168252519081900360200190f35b61055660048036036040811015610b5557600080fd5b506001600160a01b0381351690602001351515612563565b6104df612668565b61050e60048036036020811015610b8b57600080fd5b50356001600160f01b031661266e565b610703612688565b61055660048036036080811015610bb957600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135640100000000811115610bf457600080fd5b820183602082011115610c0657600080fd5b80359060200191846001830284011164010000000083111715610c2857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612697945050505050565b6104df60048036036020811015610c7f57600080fd5b50356001600160f01b03166126f5565b610cac60048036036020811015610ca557600080fd5b5035612707565b604080516001600160e01b03199092168252519081900360200190f35b6104df60048036036020811015610cdf57600080fd5b503561273b565b61044460048036036020811015610cfc57600080fd5b5035612749565b6104df60048036036020811015610d1957600080fd5b50356001600160f01b031661295c565b6104df612d59565b6104df60048036036020811015610d4757600080fd5b50356001600160f01b0316612d5f565b6104df60048036036020811015610d6d57600080fd5b50356001600160f01b0316612d71565b6104df612d83565b6104df612d89565b61042860048036036040811015610da357600080fd5b506001600160a01b0381358116916020013516612d95565b6104df612dc3565b6104df60048036036020811015610dd957600080fd5b50356001600160a01b0316612dcf565b6104df60048036036040811015610dff57600080fd5b506001600160f01b038135169060200135612f73565b61050e613015565b610e25613024565b60405180826002811115610e3557fe5b60ff16815260200191505060405180910390f35b6104df60048036036020811015610e5f57600080fd5b50356001600160f01b0316613029565b6001600160e01b0319811660009081526022602052604090205460ff165b919050565b6060600160029054906101000a90046001600160a01b03166001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610ee257600080fd5b505afa158015610ef6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610f1f57600080fd5b8101908080516040519392919084640100000000821115610f3f57600080fd5b908301906020820185811115610f5457600080fd5b8251640100000000811182820188101715610f6e57600080fd5b82525081516020918201929091019080838360005b83811015610f9b578181015183820152602001610f83565b50505050905090810190601f168015610fc85780820380516001836020036101000a031916815260200191505b5060405250505090505b90565b60015460009060ff1661101c576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff191690556000611030611ab3565b9050336001600160a01b0382161461108f576040805162461bcd60e51b815260206004820152601660248201527f4f6e6c792061646d696e2063616e20646f207468617400000000000000000000604482015290519081900360640190fd5b6001546001600160a01b03848116620100009092041614156110f8576040805162461bcd60e51b815260206004820152601d60248201527f43616e6e6f7420737765657020756e6465726c79696e67206173736574000000604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038616916370a0823191602480820192602092909190829003018186803b15801561114257600080fd5b505afa158015611156573d6000803e3d6000fd5b505050506040513d602081101561116c57600080fd5b50519050806111c2576040805162461bcd60e51b815260206004820152601860248201527f4e6f206c6566746f76657220746f6b656e7320666f756e640000000000000000604482015290519081900360640190fd5b836001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561122257600080fd5b505af1158015611236573d6000803e3d6000fd5b505050506040513d602081101561124c57600080fd5b5090925050505b6001805460ff191681179055919050565b600061126f8261303b565b6112aa5760405162461bcd60e51b815260040180806020018281038252602c81526020018061550e602c913960400191505060405180910390fd5b506000908152602660205260409020546001600160a01b031690565b60006112d18261198e565b9050806001600160a01b0316836001600160a01b031614156113245760405162461bcd60e51b815260040180806020018281038252602181526020018061558b6021913960400191505060405180910390fd5b806001600160a01b0316611336613058565b6001600160a01b03161480611357575061135781611352613058565b612d95565b6113925760405162461bcd60e51b815260040180806020018281038252603881526020018061545b6038913960400191505060405180910390fd5b60008281526026602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600b5481565b60015460ff16611438576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff19169055600061144c611ab3565b9050336001600160a01b038216146114ab576040805162461bcd60e51b815260206004820152601660248201527f4f6e6c792061646d696e2063616e20646f207468617400000000000000000000604482015290519081900360640190fd5b6001546001600160a01b03848116620100009092041614156115c6576000828152601360205260409020546001600160f01b031680156115c45760006001600160a01b0316846001600160a01b0316636352211e836040518263ffffffff1660e01b815260040180826001600160f01b0316815260200191505060206040518083038186803b15801561153d57600080fd5b505afa158015611551573d6000803e3d6000fd5b505050506040513d602081101561156757600080fd5b50516001600160a01b0316146115c4576040805162461bcd60e51b815260206004820152601a60248201527f43616e6e6f7420737765657020726567756c6172206173736574000000000000604482015290519081900360640190fd5b505b826001600160a01b0316636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561160a57600080fd5b505afa15801561161e573d6000803e3d6000fd5b505050506040513d602081101561163457600080fd5b50516001600160a01b03163014611692576040805162461bcd60e51b815260206004820152601b60248201527f546f6b656e206e6f74206f776e656420627920636f6e74726163740000000000604482015290519081900360640190fd5b60408051632142170760e11b81523060048201526001600160a01b038381166024830152604482018590529151918516916342842e0e9160648082019260009290919082900301818387803b1580156116ea57600080fd5b505af11580156116fe573d6000803e3d6000fd5b50506001805460ff1916811790555050505050565b601b6020526000908152604090205481565b60145481565b6001546201000090046001600160a01b031681565b60095481565b600d5481565b61175d611757613058565b8261305c565b6117985760405162461bcd60e51b81526004018080602001828103825260318152602001806155ac6031913960400191505060405180910390fd5b6117a38383836130f8565b505050565b60015460009060ff166117ef576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff19169055611801611ab3565b6001600160a01b0316336001600160a01b03161461182c576118256001605961323c565b9050611253565b600380546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fd02b9ea8a918c48a5443286ad7bbb9d8e48146f8cb711a42b0109e1a46e3ab3b929181900390910190a160005b6001805460ff1916811790559392505050565b601c6020526000908152604090205481565b60196020526000908152604090205481565b600c6020526000908152604090205460ff1681565b60005490565b6117a383838360405180602001604052806000815250612697565b6004546001600160a01b031681565b6013602052600090815260409020546001600160f01b031681565b6003546001600160a01b031681565b600061195282600080604051806020016040528060008152506122f5565b92915050565b60105481565b60126020526000908152604090205481565b601a6020526000908152604090205481565b6702c68af0bb14000081565b6000818152602560205260408120546001600160a01b0316806119525760405162461bcd60e51b81526004018080602001828103825260298152602001806154e56029913960400191505060405180910390fd5b600190565b600a5481565b60006119f7611ab3565b6001600160a01b0316336001600160a01b031614611a2257611a1b6001605161323c565b9050611952565b6001600160a01b0383166000908152600c602052604090205460ff16151582151514611aa9576001600160a01b0383166000818152600c6020908152604091829020805460ff191686151590811790915582519384529083015280517f2e1e9be77cccab0d36f4e5683584850b1b1b8c0bc8613a8911959754f145e79b9281900390910190a15b60005b9392505050565b600080604051808061549360289139604051908190036028019020549392505050565b60006001600160a01b038216611b1d5760405162461bcd60e51b815260040180806020018281038252602a8152602001806154bb602a913960400191505060405180910390fd5b6001600160a01b0382166000908152602760205260409020611952906132a2565b60015460009060ff16611b85576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff19169055611b97611ab3565b6001600160a01b0316336001600160a01b031614611bbb576118256001604d61323c565b6004805460408051635f41b85d60e01b815290516001600160a01b039283169392861692635f41b85d92808201926020929091829003018186803b158015611c0257600080fd5b505afa158015611c16573d6000803e3d6000fd5b505050506040513d6020811015611c2c57600080fd5b5051611c72576040805162461bcd60e51b815260206004820152601060248201526f34b73b30b634b21036ba3937b63632b960811b604482015290519081900360640190fd5b826001600160a01b03166364865f7c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611cab57600080fd5b505afa158015611cbf573d6000803e3d6000fd5b505050506040513d6020811015611cd557600080fd5b5051611d1b576040805162461bcd60e51b815260206004820152601060248201526f34b73b30b634b21036ba3937b63632b960811b604482015290519081900360640190fd5b600480546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517fe006bb2a70c33154cb00e229b7c7f579ed53dc27d89d70e8b297a3d623060e8e9281900390910190a1600061188e565b6006805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015611e045780601f10611dd957610100808354040283529160200191611e04565b820191906000526020600020905b815481529060010190602001808311611de757829003601f168201915b505050505081565b600081815260136020526040812054611952906001600160f01b0316611934565b61c35081565b600e5481565b6005805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015611e045780601f10611dd957610100808354040283529160200191611e04565b6000611e9e611ab3565b6001600160a01b0316336001600160a01b031614611eed5760405162461bcd60e51b815260040180806020018281038252602d8152602001806153e0602d913960400191505060405180910390fd5b6000198514158015611f0157506008548514155b15611f245784611f1e57611f176002604c61323c565b905061202a565b60088590555b6000198414158015611f3857506009548414155b15611f5f576706f05b59d3b20000841115611f5957611f176002604c61323c565b60098490555b6000198314158015611f735750600a548314155b15611f995766b1a2bc2ec50000831115611f9357611f176002604c61323c565b600a8390555b6000198214158015611fad5750600b548214155b15611fd4576706f05b59d3b20000821115611fce57611f176002604c61323c565b600b8290555b600854600954600a54600b54604080519485526020850193909352838301919091526060830152517fa0c702f70b94ab8d7d21bab46c426f8d14b361d65a8d6464f073abe2d1aee0b19181900360800190a15060005b949350505050565b61204e8686866000670de0b6b3a76400006000888860126132a6565b6000612059846117a8565b905080156120ae576040805162461bcd60e51b815260206004820152601b60248201527f73657474696e6720746f6b656e41756374696f6e206661696c65640000000000604482015290519081900360640190fd5b50505050505050565b60006120c1611ab3565b6001600160a01b0316336001600160a01b0316146121105760405162461bcd60e51b815260040180806020018281038252602c815260200180615390602c913960400191505060405180910390fd5b60001986141580156121245750600d548614155b15612158576107d086108061213a575061c35086115b156121525761214b6002604c61323c565b905061229c565b600d8690555b600019851415801561216c5750600e548514155b1561218d576107d08511156121875761214b6002604c61323c565b600e8590555b60001984141580156121a15750600f548414155b156121c857670b1a2bc2ec5000008411156121c25761214b6002604c61323c565b600f8490555b60001983141580156121dc57506010548314155b156122035767016345785d8a00008311156121fd5761214b6002604c61323c565b60108390555b600019821415801561221757506011548214155b1561223e576702c68af0bb1400008211156122385761214b6002604c61323c565b60118290555b600d54600e54600f546010546011546040805195865260208601949094528484019290925260608401526080830152517f4c6615c4f0e96eb7f735a195a6965a1c69a802ade75651de4cd935b8fcba6bd89181900360a00190a15060005b95945050505050565b6060600160029054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610ee257600080fd5b60015460009060ff1661233c576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff191690556123586001600160f01b03861661198e565b6001600160a01b0316336001600160a01b0316146123835761237c6001603b61323c565b9050612546565b6001600160f01b0385166000908152601760209081526040808320338452909152902054670de0b6b3a764000014612402576040805162461bcd60e51b815260206004820152601d60248201527f496e76616c696420696e7465726e616c20746f6b656e20616d6f756e74000000604482015290519081900360640190fd5b6001600160f01b0385166000908152602160205260409020541561243a576001600160f01b0385166000908152602160205260408120555b600061245486670de0b6b3a76400006000338989896136c7565b90508015612463579050612546565b600480546040805163df83bb5560e01b81526001600160f01b038a1693810193909352336024840152516001600160a01b039091169163df83bb559160448083019260209291908290030181600087803b1580156124c057600080fd5b505af11580156124d4573d6000803e3d6000fd5b505050506040513d60208110156124ea57600080fd5b505160408051808201909152601981527f72656465656d206d61726b65742065786974206661696c656400000000000000602082015290915061252e908290613df0565b612540866001600160f01b0316613ff0565b60009150505b6001805460ff191681179055949350505050565b60075460ff1681565b61256b613058565b6001600160a01b0316826001600160a01b031614156125d1576040805162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015290519081900360640190fd5b80602860006125de613058565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155612622613058565b60408051841515815290516001600160a01b0392909216917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319181900360200190a35050565b6107d081565b60208052600090815260409020546001600160a01b031681565b601d546001600160f01b031681565b6126a86126a2613058565b8361305c565b6126e35760405162461bcd60e51b81526004018080602001828103825260318152602001806155ac6031913960400191505060405180910390fd5b6126ef84848484614005565b50505050565b60156020526000908152604090205481565b6000818154811061271457fe5b9060005260206000209060089182820401919006600402915054906101000a900460e01b81565b60006119526003601061323c565b60606127548261303b565b6127a5576040805162461bcd60e51b815260206004820152601f60248201527f55524920717565727920666f72206e6f6e6578697374656e7420746f6b656e00604482015290519081900360640190fd5b6001600160f01b03821115612801576040805162461bcd60e51b815260206004820152601f60248201527f55524920717565727920666f72206e6f6e6578697374656e7420746f6b656e00604482015290519081900360640190fd5b6001546001600160f01b03831660009081526012602052604080822054815163c87b56dd60e01b81526004810191909152905185936201000090046001600160a01b03169263c87b56dd9260248082019391829003018186803b15801561286757600080fd5b505afa15801561287b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156128a457600080fd5b81019080805160405193929190846401000000008211156128c457600080fd5b9083019060208201858111156128d957600080fd5b82516401000000008111828201881017156128f357600080fd5b82525081516020918201929091019080838360005b83811015612920578181015183820152602001612908565b50505050905090810190601f16801561294d5780820380516001836020036101000a031916815260200191505b50604052505050915050919050565b60006129666151eb565b61296e614057565b81526001600160f01b038316600090815260156020908152604090912054908201819052815114156129a4576000915050610e8d565b6001600160f01b038316600081815260196020908152604080832054858201908152848452601a83528184205460608701908152858552601b84528285205460808801908152958552601684528285205460a088015260025491519051955183516315f2405360e01b8152600481019290925260248201969096526044810195909552905192936001600160a01b03909116926315f2405392606480840193919291829003018186803b158015612a5a57600080fd5b505afa158015612a6e573d6000803e3d6000fd5b505050506040513d6020811015612a8457600080fd5b5051905065048c27395000811115612ae3576040805162461bcd60e51b815260206004820152601c60248201527f626f72726f772072617465206973206162737572646c79206869676800000000604482015290519081900360640190fd5b600080612af88460000151856020015161405b565b90925090506000826003811115612b0b57fe5b14612b5d576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b612b65615221565b600080600080612b8360405180602001604052808a81525087614081565b90975094506000876003811115612b9657fe5b14612bc357612bb3600a6006896003811115612bae57fe5b6140e9565b9950505050505050505050610e8d565b612bd1858a6060015161414f565b90975093506000876003811115612be457fe5b14612bfc57612bb3600a6001896003811115612bae57fe5b612c0a848a606001516141a2565b90975092506000876003811115612c1d57fe5b14612c3557612bb3600a6004896003811115612bae57fe5b612c546040518060200160405280600954815250858b608001516141c8565b90975091506000876003811115612c6757fe5b14612c7f57612bb3600a6005896003811115612bae57fe5b60a0890151612c90908690806141c8565b90975090506000876003811115612ca357fe5b14612cbb57612bb3600a6003896003811115612bae57fe5b88516001600160f01b038c1660008181526015602090815260408083209490945560168152838220859055601a8152838220879055601b815290839020859055828c0151835192835290820152808201869052606081018390526080810185905290517f2b81b82a202c39cb77f20e04085b90ad1d9896deee9ad11875c31a30f3c190a79181900360a00190a160009b9a5050505050505050505050565b60115481565b60166020526000908152604090205481565b60216020526000908152604090205481565b600f5481565b67016345785d8a000081565b6001600160a01b03918216600090815260286020908152604080832093909416825291909152205460ff1690565b670b1a2bc2ec50000081565b60015460009060ff16612e16576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff19169055612e28611ab3565b6001600160a01b0316336001600160a01b031614612e4c576118256001605061323c565b600254604080516310c8fc9560e11b815290516001600160a01b0392831692851691632191f92a916004808301926020929190829003018186803b158015612e9357600080fd5b505afa158015612ea7573d6000803e3d6000fd5b505050506040513d6020811015612ebd57600080fd5b5051612f10576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a1600061188e565b60015460009060ff16612fba576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6001805460ff191690556000612fcf8461295c565b90508015612ff557612fed816011811115612fe657fe5b603c61323c565b915050613003565b612fff8484614224565b9150505b6001805460ff19168117905592915050565b6002546001600160a01b031681565b600290565b601f6020526000908152604090205481565b6000908152602560205260409020546001600160a01b0316151590565b3390565b60006130678261303b565b6130a25760405162461bcd60e51b815260040180806020018281038252602c81526020018061540d602c913960400191505060405180910390fd5b60006130ad8361198e565b9050806001600160a01b0316846001600160a01b031614806130e85750836001600160a01b03166130dd84611264565b6001600160a01b0316145b8061202a575061202a8185612d95565b826001600160a01b031661310b8261198e565b6001600160a01b0316146131505760405162461bcd60e51b81526004018080602001828103825260298152602001806155626029913960400191505060405180910390fd5b6001600160a01b0382166131955760405162461bcd60e51b81526004018080602001828103825260248152602001806153bc6024913960400191505060405180910390fd5b61319e816143ea565b6001600160a01b03831660009081526027602052604090206131bf90614425565b6001600160a01b03821660009081526027602052604090206131e09061443c565b60008181526025602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561326b57fe5b83606281111561327757fe5b604080519283526020830191909152600082820152519081900360600190a1826011811115611aac57fe5b5490565b6132ae611ab3565b6001600160a01b0316336001600160a01b0316146132fd5760405162461bcd60e51b815260040180806020018281038252602881526020018061553a6028913960400191505060405180910390fd5b6001805461ff001960ff1990911682171661010017908190556201000090046001600160a01b031615613377576040805162461bcd60e51b815260206004820152601360248201527f616c726561647920696e697469616c697a656400000000000000000000000000604482015290519081900360640190fd5b6001805475ffffffffffffffffffffffffffffffffffffffff00001916620100006001600160a01b038c160217905560006133b188612dcf565b905080156133f05760405162461bcd60e51b81526004018080602001828103825260228152602001806154396022913960400191505060405180910390fd5b6133f989611b3e565b9050801561344e576040805162461bcd60e51b815260206004820152601760248201527f73657474696e67206d74726f6c6c6572206661696c6564000000000000000000604482015290519081900360640190fd5b613461868887661c6bf526340000611e94565b905080156134a05760405162461bcd60e51b81526004018080602001828103825260298152602001806156026029913960400191505060405180910390fd5b6134ba6107d06101f4600066b1a2bc2ec5000060006120b7565b905080156134f95760405162461bcd60e51b81526004018080602001828103825260288152602001806153686028913960400191505060405180910390fd5b835161350c906005906020870190615234565b508251613520906006906020860190615234565b506007805460ff191660ff84161790556004805460408051633833821160e11b81523093810193909352516000926001600160a01b03909216916370670422916024808301926020929190829003018186803b15801561357f57600080fd5b505afa158015613593573d6000803e3d6000fd5b505050506040513d60208110156135a957600080fd5b50516001600160f01b0381166000908152601560205260409020549091501580156135ea57506001600160f01b038116600090815260166020526040902054155b6136255760405162461bcd60e51b81526004018080602001828103825260238152602001806153136023913960400191505060405180910390fd5b61362d614057565b6001600160f01b0382166000908152601560209081526040808320939093556016905220670de0b6b3a764000090556136658161295c565b915081156136ba576040805162461bcd60e51b815260206004820152601660248201527f61636372756520696e746572657374206661696c656400000000000000000000604482015290519081900360640190fd5b5050505050505050505050565b6000338715806136d5575086155b6137105760405162461bcd60e51b815260040180806020018281038252603481526020018061562b6034913960400191505060405180910390fd5b600061371b8a61295c565b905080156137425761373981601181111561373257fe5b603161323c565b92505050613de5565b61374a6152b2565b6137538b614445565b604083018190526020830182600381111561376a57fe5b600381111561377557fe5b905250600090508160200151600381111561378c57fe5b146137b2576137a8600a603583602001516003811115612bae57fe5b9350505050613de5565b891561383357606081018a9052604080516020810182529082015181526137d9908b61414f565b60808301819052602083018260038111156137f057fe5b60038111156137fb57fe5b905250600090508160200151600381111561381257fe5b1461382e576137a8600a603383602001516003811115612bae57fe5b6138ac565b61384f8960405180602001604052808460400151815250614532565b606083018190526020830182600381111561386657fe5b600381111561387157fe5b905250600090508160200151600381111561388857fe5b146138a4576137a8600a603483602001516003811115612bae57fe5b608081018990525b6001600160f01b038b166000908152601c602052604090205460608201516138d4919061405b565b60a08301819052602083018260038111156138eb57fe5b60038111156138f657fe5b905250600090508160200151600381111561390d57fe5b14613929576137a8600a603883602001516003811115612bae57fe5b6001600160f01b038b1660009081526017602090815260408083206001600160a01b03871684529091529020546060820151613965919061405b565b60c083018190526020830182600381111561397c57fe5b600381111561398757fe5b905250600090508160200151600381111561399e57fe5b146139ba576137a8600a603783602001516003811115612bae57fe5b6001600160f01b038b1660009081526019602052604090205460808201516139e2919061405b565b60e08301819052602083018260038111156139f957fe5b6003811115613a0457fe5b9052506000905081602001516003811115613a1b57fe5b14613a2c576137a8600f603961323c565b6001600160f01b038b166000908152601260205260409020546001600160a01b03871615613af6576001600160a01b0387166000908152600c602052604090205460ff1680613aa5575060008052600c6020527f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e85460ff165b613af6576040805162461bcd60e51b815260206004820152601e60248201527f666c617368207265636569766572206e6f742077686974656c69737465640000604482015290519081900360640190fd5b613b08898284608001518b8b8b614549565b5060a08201516001600160f01b038d166000818152601c602090815260408083209490945560c0860151601782528483206001600160a01b038a168085529083528584209190915560e087015184845260198352928590209290925560608087015185519384523092840192909252828501939093529181019190915290517f66ed29aeec2aa72b56b2b8f0d3626cef3638915b138caebcf264a45640e46e599181900360800190a17fcf56a6ceefee399a04b7b25cbcbdbc9ea3d7bceba48ca55c47c30f8ca2c2eec0848d846060015184866080015160405180866001600160a01b03166001600160a01b03168152602001856001600160f01b03166001600160f01b031681526020018481526020018381526020018281526020019550505050505060405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663e191aceb8d8660006040518463ffffffff1660e01b815260040180846001600160f01b03166001600160f01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060206040518083038186803b158015613cc257600080fd5b505afa158015613cd6573d6000803e3d6000fd5b505050506040513d6020811015613cec57600080fd5b505160408051808201909152600d81526c1c995919595b4819985a5b1959609a1b6020820152909350613d20908490613df0565b600460009054906101000a90046001600160a01b03166001600160a01b03166339291dd18d86856080015186606001516040518563ffffffff1660e01b815260040180856001600160f01b03166001600160f01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200182815260200194505050505060006040518083038186803b158015613dbd57600080fd5b505afa158015613dd1573d6000803e3d6000fd5b5060009250613dde915050565b9450505050505b979650505050505050565b81613dfa57613fec565b606081516005016040519080825280601f01601f191660200182016040528015613e2b576020820181803883390190505b50905060005b8251811015613e7c57828181518110613e4657fe5b602001015160f81c60f81b828281518110613e5d57fe5b60200101906001600160f81b031916908160001a905350600101613e31565b8151600160fd1b90839083908110613e9057fe5b60200101906001600160f81b031916908160001a905350602860f81b828260010181518110613ebb57fe5b60200101906001600160f81b031916908160001a905350600a840460300160f81b828260020181518110613eeb57fe5b60200101906001600160f81b031916908160001a905350600a840660300160f81b828260030181518110613f1b57fe5b60200101906001600160f81b031916908160001a905350602960f81b828260040181518110613f4657fe5b60200101906001600160f81b031916908160001a905350818415613fe85760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613fad578181015183820152602001613f95565b50505050905090810190601f168015613fda5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050505b5050565b614002613ffc8261198e565b82614c29565b50565b6140108484846130f8565b61401c84848484614d00565b6126ef5760405162461bcd60e51b81526004018080602001828103825260328152602001806153366032913960400191505060405180910390fd5b4390565b60008083831161407257506000905081830361407a565b506003905060005b9250929050565b600061408b615221565b60008061409c866000015186614f50565b909250905060008260038111156140af57fe5b146140ce5750604080516020810190915260008152909250905061407a565b60408051602081019091529081526000969095509350505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa084601181111561411857fe5b84606281111561412457fe5b604080519283526020830191909152818101859052519081900360600190a183601181111561202a57fe5b600080600061415c615221565b6141668686614081565b9092509050600082600381111561417957fe5b1461418a575091506000905061407a565b600061419582614f8f565b9350935050509250929050565b6000808383018481106141ba5760009250905061407a565b50600291506000905061407a565b60008060006141d5615221565b6141df8787614081565b909250905060008260038111156141f257fe5b14614203575091506000905061421c565b61421561420f82614f8f565b866141a2565b9350935050505b935093915050565b6000806000806000614234611ab3565b9050336001600160a01b0382161461425d576142526001603d61323c565b945050505050611952565b614265614057565b6001600160f01b0388166000908152601560205260409020541461428f57614252600b603f61323c565b6001600160f01b0387166000908152601b60205260409020546142b2908761405b565b909450925060008460038111156142c557fe5b146142d6576142526002604061323c565b6001600160f01b0387166000908152601960205260409020546142f9908761405b565b9094509150600084600381111561430c57fe5b1461431d57614252600f603e61323c565b600060126000896001600160f01b03166001600160f01b0316815260200190815260200160002054905061436582828960008060405180602001604052806000815250614549565b506001600160f01b0388166000818152601b60209081526040808320889055601982529182902086905581516001600160a01b03861681529081019290925281810189905260608201869052517fda3e40794fb56e711ccb786edc2367eefe141f8a12f51fbc2a4a58773a82e1be9181900360800190a1600098975050505050505050565b6000818152602660205260409020546001600160a01b03161561400257600090815260266020526040902080546001600160a01b0319169055565b805461443890600163ffffffff614f9e16565b9055565b80546001019055565b6001600160f01b0381166000908152601c60205260408120548190806144735750506008546000915061452d565b6001600160f01b03841660009081526019602052604081205490614495615221565b6001600160f01b0387166000908152601a6020908152604080832054601b9092528220546144c4918691614fe0565b9350905060008160038111156144d657fe5b146144eb5795506000945061452d9350505050565b6144f5838661501e565b92509050600081600381111561450757fe5b1461451c5795506000945061452d9350505050565b505160009550935061452d92505050565b915091565b600080600061453f615221565b61416686866150ce565b6000670de0b6b3a764000085146145a7576040805162461bcd60e51b815260206004820152601660248201527f416d6f756e74206d757374206265206f6e65556e697400000000000000000000604482015290519081900360640190fd5b6001600160a01b03831661471e5760015460408051632142170760e11b81523060048201526001600160a01b038a81166024830152604482018a9052915162010000909304909116916342842e0e9160648082019260009290919082900301818387803b15801561461757600080fd5b505af115801561462b573d6000803e3d6000fd5b50505050866001600160a01b0316600160029054906101000a90046001600160a01b03166001600160a01b0316636352211e886040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561469257600080fd5b505afa1580156146a6573d6000803e3d6000fd5b505050506040513d60208110156146bc57600080fd5b50516001600160a01b031614614719576040805162461bcd60e51b815260206004820152601360248201527f5472616e73666572206f7574206661696c656400000000000000000000000000604482015290519081900360640190fd5b614c1e565b60015460408051632142170760e11b81523060048201526001600160a01b038681166024830152604482018a9052915162010000909304909116916342842e0e9160648082019260009290919082900301818387803b15801561478057600080fd5b505af1158015614794573d6000803e3d6000fd5b505050506000600360009054906101000a90046001600160a01b03166001600160a01b0316633013ce296040518163ffffffff1660e01b815260040160206040518083038186803b1580156147e857600080fd5b505afa1580156147fc573d6000803e3d6000fd5b505050506040513d602081101561481257600080fd5b50516040805163b4d443b360e01b815290519192506000916001600160a01b0384169163b4d443b3916004808301926020929190829003018186803b15801561485a57600080fd5b505afa15801561486e573d6000803e3d6000fd5b505050506040513d602081101561488457600080fd5b505160408051630f42eabd60e21b81526001600160a01b03808d16600483018190526001600160f01b03851660248401529251939450913192600092861691633d0baaf491604480830192602092919082900301818787803b1580156148e957600080fd5b505af11580156148fd573d6000803e3d6000fd5b505050506040513d602081101561491357600080fd5b810190808051906020019092919050505090506000876001600160a01b03166375ce55308c8e8c8b6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156149ab578181015183820152602001614993565b50505050905090810190601f1680156149d85780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b1580156149fa57600080fd5b505af1158015614a0e573d6000803e3d6000fd5b505050506040513d6020811015614a2457600080fd5b505190508015614a7b576040805162461bcd60e51b815260206004820152601960248201527f5472616e73666572206f7065726174696f6e206661696c656400000000000000604482015290519081900360640190fd5b6001600160a01b038c163183811015614adb576040805162461bcd60e51b815260206004820152601960248201527f4e65676174697665207265636569766564207061796d656e7400000000000000604482015290519081900360640190fd5b604080516372434afd60e11b81526001600160a01b038f811660048301526001600160f01b03881660248301529151928690039260009289169163e48695fa916044808301926020929190829003018186803b158015614b3a57600080fd5b505afa158015614b4e573d6000803e3d6000fd5b505050506040513d6020811015614b6457600080fd5b5051905080841015614bbd576040805162461bcd60e51b815260206004820152601060248201527f426f72726f7720696e6372656173656400000000000000000000000000000000604482015290519081900360640190fd5b83038181018b1115614c16576040805162461bcd60e51b815260206004820152601860248201527f5265636569766564207061796d656e7420746f6f206c6f770000000000000000604482015290519081900360640190fd5b505050505050505b509295945050505050565b816001600160a01b0316614c3c8261198e565b6001600160a01b031614614c815760405162461bcd60e51b81526004018080602001828103825260258152602001806155dd6025913960400191505060405180910390fd5b614c8a816143ea565b6001600160a01b0382166000908152602760205260409020614cab90614425565b60008181526025602052604080822080546001600160a01b0319169055518291906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000614d14846001600160a01b031661512d565b614d205750600161202a565b600060606001600160a01b038616630a85bd0160e11b614d3e613058565b89888860405160240180856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614db7578181015183820152602001614d9f565b50505050905090810190601f168015614de45780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909a16999099178952518151919890975087965094509250829150849050835b60208310614e615780518252601f199092019160209182019101614e42565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614ec3576040519150601f19603f3d011682016040523d82523d6000602084013e614ec8565b606091505b509150915081614f1957805115614ee25780518082602001fd5b60405162461bcd60e51b81526004018080602001828103825260328152602001806153366032913960400191505060405180910390fd5b6000818060200190516020811015614f3057600080fd5b50516001600160e01b031916630a85bd0160e11b14935061202a92505050565b60008083614f635750600090508061407a565b83830283858281614f7057fe5b0414614f845750600291506000905061407a565b60009250905061407a565b51670de0b6b3a7640000900490565b6000611aac83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250615166565b600080600080614ff087876141a2565b9092509050600082600381111561500357fe5b14615014575091506000905061421c565b614215818661405b565b6000615028615221565b60008061503d86670de0b6b3a7640000614f50565b9092509050600082600381111561505057fe5b1461506f5750604080516020810190915260008152909250905061407a565b60008061507c83886151c0565b9092509050600082600381111561508f57fe5b146150b15750604080516020810190915260008152909450925061407a915050565b604080516020810190915290815260009890975095505050505050565b60006150d8615221565b6000806150ed670de0b6b3a764000087614f50565b9092509050600082600381111561510057fe5b1461511f5750604080516020810190915260008152909250905061407a565b61419581866000015161501e565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061202a575050151592915050565b600081848411156151b85760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613fad578181015183820152602001613f95565b505050900390565b600080826151d4575060019050600061407a565b60008385816151df57fe5b04915091509250929050565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060200160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061527557805160ff19168380011785556152a2565b828001600101855582156152a2579182015b828111156152a2578251825591602001919060010190615287565b506152ae9291506152f8565b5090565b6040805161010081019091528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b610fd291905b808211156152ae57600081556001016152fe56fe6d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e63654552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e74657273657474696e6720676c6f62616c2061756374696f6e20706172616d6574657273206661696c65646f6e6c792061646d696e2063616e2073657420676c6f62616c2061756374696f6e20706172616d65746572734552433732313a207472616e7366657220746f20746865207a65726f20616464726573736f6e6c792061646d696e2063616e2073657420676c6f62616c2070726f746f636f6c20706172616d65746572734552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e73657474696e6720696e7465726573742072617465206d6f64656c206661696c65644552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c636f6d2e6d6d6f2d66696e616e63652e6d44656c656761746f722e61646d696e2e616464726573734552433732313a2062616c616e636520717565727920666f7220746865207a65726f20616464726573734552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e6f6e6c792061646d696e2063616e20696e697469616c697a6520746f6b656e20636f6e74726163744552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732313a20617070726f76616c20746f2063757272656e74206f776e65724552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665644552433732313a206275726e206f6620746f6b656e2074686174206973206e6f74206f776e73657474696e6720676c6f62616c2070726f746f636f6c20706172616d6574657273206661696c65646f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726fa265627a7a723158209005a9de716f4718928270bc21a6a99c31d236136ec6e7608e2a9a59a3b144e564736f6c63430005100032
Deployed Bytecode Sourcemap
549:11762:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;549:11762:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;915:133:18;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;915:133:18;-1:-1:-1;;;;;;915:133:18;;:::i;:::-;;;;;;;;;;;;;;;;;;7241:122:1;;;:::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;7241:122:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37269:491:2;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;37269:491:2;-1:-1:-1;;;;;37269:491:2;;:::i;:::-;;;;;;;;;;;;;;;;4470:200:23;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4470:200:23;;:::i;:::-;;;;-1:-1:-1;;;;;4470:200:23;;;;;;;;;;;;;;3770:415;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;3770:415:23;;;;;;;;:::i;:::-;;2946:29:5;;;:::i;38128:745:2:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;38128:745:2;;;;;;;;:::i;7714:46:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7714:46:5;-1:-1:-1;;;;;7714:46:5;;:::i;5780:34::-;;;:::i;1001:33::-;;;:::i;2471:::-;;;:::i;3783:::-;;;:::i;6116:287:23:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;6116:287:23;;;;;;;;;;;;;;;;;:::i;25262:588:2:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;25262:588:2;-1:-1:-1;;;;;25262:588:2;;:::i;7871:44:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7871:44:5;-1:-1:-1;;;;;7871:44:5;;:::i;7369:52::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7369:52:5;-1:-1:-1;;;;;7369:52:5;;:::i;3088:59::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3088:59:5;-1:-1:-1;;;;;3088:59:5;;:::i;383:118::-;;;:::i;7052:132:23:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;7052:132:23;;;;;;;;;;;;;;;;;:::i;1442:33:5:-;;;:::i;5348:56::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5348:56:5;;:::i;:::-;;;;-1:-1:-1;;;;;5348:56:5;;;;;;;;;;;;;;1319:32;;;:::i;5876:120:1:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5876:120:1;-1:-1:-1;;;;;5876:120:1;;:::i;4624:40:5:-;;;:::i;5216:49::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5216:49:5;-1:-1:-1;;;;;5216:49:5;;:::i;7548:45::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7548:45:5;-1:-1:-1;;;;;7548:45:5;;:::i;4851:58::-;;;:::i;3126:223:23:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3126:223:23;;:::i;1762:100:2:-;;;:::i;2709:38:5:-;;;:::i;23226:592:2:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;23226:592:2;;;;;;;;;;:::i;882:194:3:-;;;:::i;2700:207:23:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2700:207:23;-1:-1:-1;;;;;2700:207:23;;:::i;26069:830:2:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;26069:830:2;-1:-1:-1;;;;;26069:830:2;;:::i;1809:21:5:-;;;:::i;6379:140:1:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6379:140:1;;:::i;3672:53:5:-;;;:::i;4132:43::-;;;:::i;1712:19::-;;;:::i;27265:1911:2:-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;27265:1911:2;;;;;;;;;;;;;;;;;:::i;2529:607:1:-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;2529:607:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;2529:607:1;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;2529:607:1;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;2529:607:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;2529:607:1;;;;;;;;-1:-1:-1;2529:607:1;;-1:-1:-1;;21:11;5:28;;2:2;;;46:1;43;36:12;2:2;2529:607:1;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;2529:607:1;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;2529:607:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;2529:607:1;;-1:-1:-1;2529:607:1;;-1:-1:-1;;;;;2529:607:1:i;29184:2543:2:-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;29184:2543:2;;;;;;;;;;;;;;;;;;;;;;:::i;7555:126:1:-;;;:::i;4213:1293::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;4213:1293:1;;;;;;;;;-1:-1:-1;;;;;4213:1293:1;;;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;4213:1293:1;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;4213:1293:1;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;4213:1293:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;4213:1293:1;;-1:-1:-1;4213:1293:1;;-1:-1:-1;;;;;4213:1293:1:i;1910:22:5:-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;4963:249:23;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;4963:249:23;;;;;;;;;;:::i;4014:62:5:-;;;:::i;9758:55::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9758:55:5;-1:-1:-1;;;;;9758:55:5;;:::i;8365:33::-;;;:::i;7907:269:23:-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;7907:269:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;7907:269:23;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;7907:269:23;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;7907:269:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;7907:269:23;;-1:-1:-1;7907:269:23;;-1:-1:-1;;;;;7907:269:23:i;5919:51:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5919:51:5;-1:-1:-1;;;;;5919:51:5;;:::i;338:36::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;338:36:5;;:::i;:::-;;;;-1:-1:-1;;;;;;338:36:5;;;;;;;;;;;;;;6823:232:1;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6823:232:1;;:::i;7916:358::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7916:358:1;;:::i;1621:4069:3:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1621:4069:3;-1:-1:-1;;;;;1621:4069:3;;:::i;4937:38:5:-;;;:::i;6107:44::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6107:44:5;-1:-1:-1;;;;;6107:44:5;;:::i;10004:47::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10004:47:5;-1:-1:-1;;;;;10004:47:5;;:::i;4401:32::-;;;:::i;4536:60::-;;;:::i;5534:145:23:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;5534:145:23;;;;;;;;;;:::i;4305:52:5:-;;;:::i;24112:852:2:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;24112:852:2;-1:-1:-1;;;;;24112:852:2;;:::i;32049:601::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;32049:601:2;;;;;;;;:::i;1159:42:5:-;;;:::i;1523:141:1:-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9497:56:5;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9497:56:5;-1:-1:-1;;;;;9497:56:5;;:::i;915:133:18:-;-1:-1:-1;;;;;;1008:33:18;;985:4;1008:33;;;:20;:33;;;;;;;;915:133;;;;:::o;7241:122:1:-;7280:13;7329:18;;;;;;;;;-1:-1:-1;;;;;7329:18:1;-1:-1:-1;;;;;7313:40:1;;:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;7313:42:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;7313:42:1;;;;;;39:16:-1;36:1;17:17;2:54;101:4;7313:42:1;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;7313:42:1;;;;;;;;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;261:11;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;7313:42:1;;420:4:-1;411:14;;;;7313:42:1;;;;;411:14:-1;7313:42:1;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;7313:42:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7306:49;;7241:122;;:::o;37269:491:2:-;10050:11:3;;37344:4:2;;10050:11:3;;10042:34;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;;;;10087:11;:19;;-1:-1:-1;;10087:19:3;;;10101:5;37377:10:2;:8;:10::i;:::-;37361:26;-1:-1:-1;37406:10:2;-1:-1:-1;;;;;37406:19:2;;;37398:54;;;;;-1:-1:-1;;;37398:54:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;37488:18;;-1:-1:-1;;;;;37471:35:2;;;37488:18;;;;;37471:35;;37463:77;;;;;-1:-1:-1;;;37463:77:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;37568:46;;;-1:-1:-1;;;37568:46:2;;37608:4;37568:46;;;;;;37551:14;;-1:-1:-1;;;;;37568:31:2;;;;;:46;;;;;;;;;;;;;;;:31;:46;;;5:2:-1;;;;30:1;27;20:12;5:2;37568:46:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;37568:46:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;37568:46:2;;-1:-1:-1;37633:10:2;37625:47;;;;;-1:-1:-1;;;37625:47:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;37690:13;-1:-1:-1;;;;;37683:30:2;;37714:5;37721:6;37683:45;;;;;;;;;;;;;-1:-1:-1;;;;;37683:45:2;-1:-1:-1;;;;;37683:45:2;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37683:45:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;37683:45:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;37746:6:2;;-1:-1:-1;;;10117:1:3;10143:4;10129:18;;-1:-1:-1;;10129:18:3;;;;;37269:491:2;;-1:-1:-1;37269:491:2:o;4470:200:23:-;4529:7;4556:16;4564:7;4556;:16::i;:::-;4548:73;;;;-1:-1:-1;;;4548:73:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4639:24:23;;;;:15;:24;;;;;;-1:-1:-1;;;;;4639:24:23;;4470:200::o;3770:415::-;3833:13;3849:16;3857:7;3849;:16::i;:::-;3833:32;;3889:5;-1:-1:-1;;;;;3883:11:23;:2;-1:-1:-1;;;;;3883:11:23;;;3875:57;;;;-1:-1:-1;;;3875:57:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3967:5;-1:-1:-1;;;;;3951:21:23;:12;:10;:12::i;:::-;-1:-1:-1;;;;;3951:21:23;;:62;;;;3976:37;3993:5;4000:12;:10;:12::i;:::-;3976:16;:37::i;:::-;3943:152;;;;-1:-1:-1;;;3943:152:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4106:24;;;;:15;:24;;;;;;:29;;-1:-1:-1;;;;;;4106:29:23;-1:-1:-1;;;;;4106:29:23;;;;;;;;;4150:28;;4106:24;;4150:28;;;;;;;3770:415;;;:::o;2946:29:5:-;;;;:::o;38128:745:2:-;10050:11:3;;;;10042:34;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;;;;10087:11;:19;;-1:-1:-1;;10087:19:3;;;10101:5;38239:10:2;:8;:10::i;:::-;38223:26;-1:-1:-1;38268:10:2;-1:-1:-1;;;;;38268:19:2;;;38260:54;;;;;-1:-1:-1;;;38260:54:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;38346:18;;-1:-1:-1;;;;;38329:35:2;;;38346:18;;;;;38329:35;38325:353;;;38463:14;38480:29;;;:20;:29;;;;;;-1:-1:-1;;;;;38480:29:2;38528:11;;38524:143;;38618:1;-1:-1:-1;;;;;38568:52:2;38576:13;-1:-1:-1;;;;;38568:30:2;;38599:6;38568:38;;;;;;;;;;;;;-1:-1:-1;;;;;38568:38:2;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38568:38:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;38568:38:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;38568:38:2;-1:-1:-1;;;;;38568:52:2;;38560:91;;;;;-1:-1:-1;;;38560:91:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;38325:353;;38721:13;-1:-1:-1;;;;;38713:30:2;;38744:7;38713:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38713:39:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;38713:39:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;38713:39:2;-1:-1:-1;;;;;38696:56:2;38704:4;38696:56;38688:96;;;;;-1:-1:-1;;;38688:96:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;38795:70;;;-1:-1:-1;;;38795:70:2;;38843:4;38795:70;;;;-1:-1:-1;;;;;38795:70:2;;;;;;;;;;;;;;;:39;;;;;;:70;;;;;-1:-1:-1;;38795:70:2;;;;;;;;-1:-1:-1;38795:39:2;:70;;;5:2:-1;;;;30:1;27;20:12;5:2;38795:70:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;10143:4:3;10129:18;;-1:-1:-1;;10129:18:3;;;;;-1:-1:-1;;;;;38128:745:2:o;7714:46:5:-;;;;;;;;;;;;;:::o;5780:34::-;;;;:::o;1001:33::-;;;;;;-1:-1:-1;;;;;1001:33:5;;:::o;2471:::-;;;;:::o;3783:::-;;;;:::o;6116:287:23:-;6258:41;6277:12;:10;:12::i;:::-;6291:7;6258:18;:41::i;:::-;6250:103;;;;-1:-1:-1;;;6250:103:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6364:32;6378:4;6384:2;6388:7;6364:13;:32::i;:::-;6116:287;;;:::o;25262:588:2:-;10050:11:3;;25347:4:2;;10050:11:3;;10042:34;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;;;;10087:11;:19;;-1:-1:-1;;10087:19:3;;;25416:10:2;:8;:10::i;:::-;-1:-1:-1;;;;;25402:24:2;:10;-1:-1:-1;;;;;25402:24:2;;25398:131;;25450:67;25455:18;25475:41;25450:4;:67::i;:::-;25443:74;;;;25398:131;25572:12;;;-1:-1:-1;;;;;25637:30:2;;;-1:-1:-1;;;;;;25637:30:2;;;;;;;25753:49;;;25572:12;;;;25753:49;;;;;;;;;;;;;;;;;;;;;;;25827:14;25822:20;10143:4:3;10129:18;;-1:-1:-1;;10129:18:3;;;;;25815:27:2;25262:588;-1:-1:-1;;;25262:588:2:o;7871:44:5:-;;;;;;;;;;;;;:::o;7369:52::-;;;;;;;;;;;;;:::o;3088:59::-;;;;;;;;;;;;;;;:::o;383:118::-;442:4;466:27;383:118;:::o;7052:132:23:-;7138:39;7155:4;7161:2;7165:7;7138:39;;;;;;;;;;;;:16;:39::i;1442:33:5:-;;;-1:-1:-1;;;;;1442:33:5;;:::o;5348:56::-;;;;;;;;;;;;-1:-1:-1;;;;;5348:56:5;;:::o;1319:32::-;;;-1:-1:-1;;;;;1319:32:5;;:::o;5876:120:1:-;5924:4;5948:40;5962:6;5970:1;5981;5948:40;;;;;;;;;;;;:13;:40::i;:::-;5941:47;5876:120;-1:-1:-1;;5876:120:1:o;4624:40:5:-;;;;:::o;5216:49::-;;;;;;;;;;;;;:::o;7548:45::-;;;;;;;;;;;;;:::o;4851:58::-;4904:5;4851:58;:::o;3126:223:23:-;3181:7;3216:20;;;:11;:20;;;;;;-1:-1:-1;;;;;3216:20:23;3254:19;3246:73;;;;-1:-1:-1;;;3246:73:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1762:100:2;1850:4;1762:100;:::o;2709:38:5:-;;;;:::o;23226:592:2:-;23311:4;23380:10;:8;:10::i;:::-;-1:-1:-1;;;;;23366:24:2;:10;-1:-1:-1;;;;;23366:24:2;;23362:133;;23414:69;23419:18;23439:43;23414:4;:69::i;:::-;23407:76;;;;23362:133;-1:-1:-1;;;;;23584:37:2;;;;;;:26;:37;;;;;;;;:46;;;;;;23580:191;;-1:-1:-1;;;;;23647:37:2;;;;;;:26;:37;;;;;;;;;:45;;-1:-1:-1;;23647:45:2;;;;;;;;;;23712:47;;;;;;;;;;;;;;;;;;;;;23580:191;23795:14;23790:20;23783:27;23226:592;-1:-1:-1;;;23226:592:2:o;882:194:3:-;923:21;957:16;681:53:7;;;;;;;;;;;;;;;;;;1043:15:3;;1019:50;-1:-1:-1;;;1019:50:3:o;2700:207:23:-;2755:7;-1:-1:-1;;;;;2782:19:23;;2774:74;;;;-1:-1:-1;;;2774:74:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2866:24:23;;;;;;:17;:24;;;;;:34;;:32;:34::i;26069:830:2:-;10050:11:3;;26151:4:2;;10050:11:3;;10042:34;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;;;;10087:11;:19;;-1:-1:-1;;10087:19:3;;;26220:10:2;:8;:10::i;:::-;-1:-1:-1;;;;;26206:24:2;:10;-1:-1:-1;;;;;26206:24:2;;26202:126;;26254:62;26259:18;26279:36;26254:4;:62::i;26202:126::-;26372:8;;;26460:67;;;-1:-1:-1;;;26460:67:2;;;;-1:-1:-1;;;;;26372:8:2;;;;26460:65;;;;;;:67;;;;;;;;;;;;;:65;:67;;;5:2:-1;;;;30:1;27;20:12;5:2;26460:67:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;26460:67:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;26460:67:2;26452:96;;;;;-1:-1:-1;;;26452:96:2;;;;;;;;;;;;-1:-1:-1;;;26452:96:2;;;;;;;;;;;;;;;26590:11;-1:-1:-1;;;;;26567:67:2;;:69;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;26567:69:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;26567:69:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;26567:69:2;26559:98;;;;;-1:-1:-1;;;26559:98:2;;;;;;;;;;;;-1:-1:-1;;;26559:98:2;;;;;;;;;;;;;;;26719:8;:22;;-1:-1:-1;;;;;;26719:22:2;-1:-1:-1;;;;;26719:22:2;;;;;;;;;26814:37;;;;;;;;;;;;;;;;;;;;;;;;;;;26876:14;26871:20;;1809:21:5;;;;;;;;;;;;;;;-1:-1:-1;;1809:21:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;6379:140:1:-;6445:4;6476:34;;;:20;:34;;;;;;6469:42;;-1:-1:-1;;;;;6476:34:1;6469:6;:42::i;3672:53:5:-;3720:5;3672:53;:::o;4132:43::-;;;;:::o;1712:19::-;;;;;;;;;;;;;;;-1:-1:-1;;1712:19:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27265:1911:2;27442:4;27483:10;:8;:10::i;:::-;-1:-1:-1;;;;;27469:24:2;:10;-1:-1:-1;;;;;27469:24:2;;27461:82;;;;-1:-1:-1;;;27461:82:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;27560:28:2;:40;;:103;;;;;27636:27;;27604:28;:59;;27560:103;27556:357;;;27684:33;27680:149;;27745:68;27750:15;27767:45;27745:4;:68::i;:::-;27738:75;;;;27680:149;27843:27;:58;;;27556:357;-1:-1:-1;;27929:22:2;:34;;:85;;;;;27993:21;;27967:22;:47;;27929:85;27925:343;;;2429:5:5;28035:22:2;:49;28031:165;;;28112:68;28117:15;28134:45;28112:4;:68::i;28031:165::-;28210:21;:46;;;27925:343;-1:-1:-1;;28284:27:2;:39;;:100;;;;;28358:26;;28327:27;:57;;28284:100;28280:378;;;2669:4:5;28405:27:2;:59;28401:175;;;28492:68;28497:15;28514:45;28492:4;:68::i;28401:175::-;28590:26;:56;;;28280:378;-1:-1:-1;;28674:18:2;:30;;:73;;;;;28730:17;;28708:18;:39;;28674:73;28670:315;;;2904:5:5;28768:18:2;:41;28764:157;;;28837:68;28842:15;28859:45;28837:4;:68::i;28764:157::-;28935:17;:38;;;28670:315;29030:27;;29059:21;;29082:26;;29110:17;;29002:126;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;29153:14:2;27265:1911;;;;;;;:::o;2529:607:1:-;2820:113;2843:19;2864:9;2875:18;2895:1;410:4:14;2911:1:1;2914:5;2921:7;2930:2;2820:22;:113::i;:::-;3008:8;3019:31;3036:13;3019:16;:31::i;:::-;3008:42;-1:-1:-1;3069:27:1;;3061:67;;;;;-1:-1:-1;;;3061:67:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;2529:607;;;;;;;:::o;29184:2543:2:-;29477:4;29518:10;:8;:10::i;:::-;-1:-1:-1;;;;;29504:24:2;:10;-1:-1:-1;;;;;29504:24:2;;29496:81;;;;-1:-1:-1;;;29496:81:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;29594:19:2;:31;;:76;;;;;29652:18;;29629:19;:41;;29594:76;29590:369;;;3612:4:5;29691:19:2;:43;:90;;;;3720:5:5;29738:19:2;:43;29691:90;29687:206;;;29809:68;29814:15;29831:45;29809:4;:68::i;:::-;29802:75;;;;29687:206;29907:18;:40;;;29590:369;-1:-1:-1;;29975:29:2;:41;;:106;;;;;30053:28;;30020:29;:61;;29975:106;29971:392;;;4072:4:5;30102:29:2;:63;30098:179;;;30193:68;30198:15;30215:45;30193:4;:68::i;30098:179::-;30291:28;:60;;;29971:392;-1:-1:-1;;30379:21:2;:33;;:82;;;;;30441:20;;30416:21;:45;;30379:82;30375:336;;;4352:5:5;30482:21:2;:47;30478:163;;;30557:68;30562:15;30579:45;30557:4;:68::i;30478:163::-;30655:20;:44;;;30375:336;-1:-1:-1;;30727:29:2;:41;;:106;;;;;30805:28;;30772:29;:61;;30727:106;30723:392;;;4591:5:5;30854:29:2;:63;30850:179;;;30945:68;30950:15;30967:45;30945:4;:68::i;30850:179::-;31043:28;:60;;;30723:392;-1:-1:-1;;31131:27:2;:39;;:100;;;;;31205:26;;31174:27;:57;;31131:100;31127:379;;;4904:5:5;31252:27:2;:59;31248:175;;;31339:68;31344:15;31361:45;31339:4;:68::i;31248:175::-;31438:26;:56;;;31127:379;31550:18;;31570:28;;31600:20;;31622:28;;31652:26;;31523:156;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;31704:14:2;29184:2543;;;;;;;;:::o;7555:126:1:-;7596:13;7645:18;;;;;;;;;-1:-1:-1;;;;;7645:18:1;-1:-1:-1;;;;;7629:42:1;;:44;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;4213:1293:1;10050:11:3;;4359:4:1;;10050:11:3;;10042:34;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;;;;10087:11;:19;;-1:-1:-1;;10087:19:3;;;4434:15:1;-1:-1:-1;;;;;4434:15:1;;:7;:15::i;:::-;-1:-1:-1;;;;;4420:29:1;:10;-1:-1:-1;;;;;4420:29:1;;4416:123;;4473:54;4478:18;4498:28;4473:4;:54::i;:::-;4466:61;;;;4416:123;-1:-1:-1;;;;;4613:21:1;;;;;;:13;:21;;;;;;;;4635:10;4613:33;;;;;;;;9322:4:5;4613:44:1;4605:86;;;;;-1:-1:-1;;;4605:86:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4768:19:1;;4790:1;4768:19;;;:11;:19;;;;;;:23;4764:79;;-1:-1:-1;;;;;4808:19:1;;4830:1;4808:19;;;:11;:19;;;;;:23;4764:79;4895:8;4906:90;4921:6;9322:4:5;4938:1:1;4941:10;4953:9;4964:15;4981:14;4906;:90::i;:::-;4895:101;-1:-1:-1;5011:27:1;;5007:70;;5062:3;-1:-1:-1;5055:10:1;;5007:70;5265:8;;;:47;;;-1:-1:-1;;;5265:47:1;;-1:-1:-1;;;;;5265:47:1;;;;;;;;;5301:10;5265:47;;;;;-1:-1:-1;;;;;5265:8:1;;;;:27;;:47;;;;;;;;;;;;;;:8;;:47;;;5:2:-1;;;;30:1;27;20:12;5:2;5265:47:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5265:47:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5265:47:1;5323:48;;;;;;;;;;;;;5265:47;5323:48;;;5265:47;;-1:-1:-1;5323:48:1;;5265:47;;5323:14;:48::i;:::-;5445:13;5451:6;-1:-1:-1;;;;;5445:13:1;:5;:13::i;:::-;5483:14;5471:27;;;10117:1:3;10143:4;10129:18;;-1:-1:-1;;10129:18:3;;;;;4213:1293:1;;-1:-1:-1;;;;4213:1293:1:o;1910:22:5:-;;;;;;:::o;4963:249:23:-;5048:12;:10;:12::i;:::-;-1:-1:-1;;;;;5042:18:23;:2;-1:-1:-1;;;;;5042:18:23;;;5034:56;;;;;-1:-1:-1;;;5034:56:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;5140:8;5101:18;:32;5120:12;:10;:12::i;:::-;-1:-1:-1;;;;;5101:32:23;;;;;;;;;;;;;;;;;-1:-1:-1;5101:32:23;;;:36;;;;;;;;;;;;:47;;-1:-1:-1;;5101:47:23;;;;;;;;;;;5178:12;:10;:12::i;:::-;5163:42;;;;;;;;;;-1:-1:-1;;;;;5163:42:23;;;;;;;;;;;;;;4963:249;;:::o;4014:62:5:-;4072:4;4014:62;:::o;9758:55::-;;;;;;;;;;;;-1:-1:-1;;;;;9758:55:5;;:::o;8365:33::-;;;-1:-1:-1;;;;;8365:33:5;;:::o;7907:269:23:-;8021:41;8040:12;:10;:12::i;:::-;8054:7;8021:18;:41::i;:::-;8013:103;;;;-1:-1:-1;;;8013:103:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8126:43;8144:4;8150:2;8154:7;8163:5;8126:17;:43::i;:::-;7907:269;;;;:::o;5919:51:5:-;;;;;;;;;;;;;:::o;338:36::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;6823:232:1:-;6885:4;6978:69;6983:24;7009:37;6978:4;:69::i;7916:358::-;7974:13;8008:16;8016:7;8008;:16::i;:::-;8000:60;;;;;-1:-1:-1;;;8000:60:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;8079:22:1;;;8071:66;;;;;-1:-1:-1;;;8071:66:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;8215:18;;-1:-1:-1;;;;;8244:21:1;;8148:14;8244:21;;;:13;:21;;;;;;;8199:67;;-1:-1:-1;;;8199:67:1;;;;;;;;;;;8244:21;;8215:18;;;-1:-1:-1;;;;;8215:18:1;;8199:44;;:67;;;;;;;;;;;8215:18;8199:67;;;5:2:-1;;;;30:1;27;20:12;5:2;8199:67:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;8199:67:1;;;;;;39:16:-1;36:1;17:17;2:54;101:4;8199:67:1;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;8199:67:1;;;;;;;;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;261:11;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;8199:67:1;;420:4:-1;411:14;;;;8199:67:1;;;;;411:14:-1;8199:67:1;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;8199:67:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8192:74;;;7916:358;;;:::o;1621:4069:3:-;1677:4;1694:35;;:::i;:::-;1817:16;:14;:16::i;:::-;1791:42;;-1:-1:-1;;;;;1875:26:3;;1791:23;1875:26;;;:18;:26;;;;;;;;;1844:28;;;:57;;;2003:23;;1971:55;1967:115;;;2055:14;2043:27;;;;;1967:115;-1:-1:-1;;;;;2166:27:3;;;;;;:19;:27;;;;;;;;;2149:14;;;:44;;;2224:20;;;:12;:20;;;;;;2204:17;;;:40;;;2276:21;;;:13;:21;;;;;;2255:18;;;:42;;;2332:19;;;:11;:19;;;;;;2308:21;;;:43;2448:17;;2480:14;;2496:17;;2515:18;;2448:86;;-1:-1:-1;;;2448:86:3;;;;;;;;;;;;;;;;;;;;;;;;;2166:27;;-1:-1:-1;;;;;2448:17:3;;;;:31;;:86;;;;;2166:27;;2448:86;;;;;;:17;:86;;;5:2:-1;;;;30:1;27;20:12;5:2;2448:86:3;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2448:86:3;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2448:86:3;;-1:-1:-1;7248:9:5;2553:43:3;;;2545:84;;;;;-1:-1:-1;;;2545:84:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;2720:17;2739:15;2758:62;2766:4;:23;;;2791:4;:28;;;2758:7;:62::i;:::-;2719:101;;-1:-1:-1;2719:101:3;-1:-1:-1;2850:18:3;2839:7;:29;;;;;;;;;2831:73;;;;;-1:-1:-1;;;2831:73:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;3396:31;;:::i;:::-;3438:24;3473:20;3504:21;3536:19;3602:58;3612:35;;;;;;;;3627:18;3612:35;;;3649:10;3602:9;:58::i;:::-;3568:92;;-1:-1:-1;3568:92:3;-1:-1:-1;3686:18:3;3675:7;:29;;;;;;;;;3671:183;;3728:114;3739:16;3757:69;3833:7;3828:13;;;;;;;;3728:10;:114::i;:::-;3721:121;;;;;;;;;;;;;3671:183;3899:58;3917:20;3939:4;:17;;;3899;:58::i;:::-;3866:91;;-1:-1:-1;3866:91:3;-1:-1:-1;3983:18:3;3972:7;:29;;;;;;;;;3968:181;;4025:112;4036:16;4054:67;4128:7;4123:13;;;;;;;3968:181;4190:47;4198:19;4219:4;:17;;;4190:7;:47::i;:::-;4161:76;;-1:-1:-1;4161:76:3;-1:-1:-1;4263:18:3;4252:7;:29;;;;;;;;;4248:178;;4305:109;4316:16;4334:64;4405:7;4400:13;;;;;;;4248:178;4468:105;4493:38;;;;;;;;4508:21;;4493:38;;;4533:19;4554:4;:18;;;4468:24;:105::i;:::-;4438:135;;-1:-1:-1;4438:135:3;-1:-1:-1;4599:18:3;4588:7;:29;;;;;;;;;4584:179;;4641:110;4652:16;4670:65;4742:7;4737:13;;;;;;;4584:179;4850:21;;;;4803:92;;4828:20;;4850:21;4803:24;:92::i;:::-;4775:120;;-1:-1:-1;4775:120:3;-1:-1:-1;4921:18:3;4910:7;:29;;;;;;;;;4906:177;;4963:108;4974:16;4992:63;5062:7;5057:13;;;;;;;4906:177;5315:23;;-1:-1:-1;;;;;5286:26:3;;5315:23;5286:26;;;:18;:26;;;;;;;;:52;;;;5349:11;:19;;;;;:36;;;5396:12;:20;;;;;:38;;;5445:13;:21;;;;;;:40;;;5573:14;;;;5550:92;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5667:14;5655:27;1621:4069;-1:-1:-1;;;;;;;;;;;1621:4069:3:o;4937:38:5:-;;;;:::o;6107:44::-;;;;;;;;;;;;;:::o;10004:47::-;;;;;;;;;;;;;:::o;4401:32::-;;;;:::o;4536:60::-;4591:5;4536:60;:::o;5534:145:23:-;-1:-1:-1;;;;;5637:25:23;;;5614:4;5637:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;5534:145::o;4305:52:5:-;4352:5;4305:52;:::o;24112:852:2:-;10050:11:3;;24212:4:2;;10050:11:3;;10042:34;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;;;;10087:11;:19;;-1:-1:-1;;10087:19:3;;;24281:10:2;:8;:10::i;:::-;-1:-1:-1;;;;;24267:24:2;:10;-1:-1:-1;;;;;24267:24:2;;24263:137;;24315:73;24320:18;24340:47;24315:4;:73::i;24263:137::-;24453:17;;24571:42;;;-1:-1:-1;;;24571:42:2;;;;-1:-1:-1;;;;;24453:17:2;;;;24571:40;;;;;:42;;;;;;;;;;;;;;:40;:42;;;5:2:-1;;;;30:1;27;20:12;5:2;24571:42:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;24571:42:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;24571:42:2;24563:83;;;;;-1:-1:-1;;;24563:83:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;24699:17;:40;;-1:-1:-1;;;;;;24699:40:2;-1:-1:-1;;;;;24699:40:2;;;;;;;;;24846:70;;;;;;;;;;;;;;;;;;;;;;;;;;;24941:14;24936:20;;32049:601;10050:11:3;;32140:4:2;;10050:11:3;;10042:34;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;-1:-1:-1;;;10042:34:3;;;;;;;;;;;;;;;10087:11;:19;;-1:-1:-1;;10087:19:3;;;10101:5;32170:22:2;32185:6;32170:14;:22::i;:::-;32157:35;-1:-1:-1;32207:29:2;;32203:277;;32398:70;32409:5;32403:12;;;;;;;;32417:50;32398:4;:70::i;:::-;32391:77;;;;;32203:277;32600:42;32621:6;32629:12;32600:20;:42::i;:::-;32593:49;;;10117:1:3;10143:4;10129:18;;-1:-1:-1;;10129:18:3;;;;;32049:601:2;;-1:-1:-1;;32049:601:2:o;1159:42:5:-;;;-1:-1:-1;;;;;1159:42:5;;:::o;1523:141:1:-;1615:41;1523:141;:::o;9497:56:5:-;;;;;;;;;;;;;:::o;9345:152:23:-;9402:4;9434:20;;;:11;:20;;;;;;-1:-1:-1;;;;;9434:20:23;9471:19;;;9345:152::o;788:96:16:-;867:10;788:96;:::o;9858:329:23:-;9943:4;9967:16;9975:7;9967;:16::i;:::-;9959:73;;;;-1:-1:-1;;;9959:73:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10042:13;10058:16;10066:7;10058;:16::i;:::-;10042:32;;10103:5;-1:-1:-1;;;;;10092:16:23;:7;-1:-1:-1;;;;;10092:16:23;;:51;;;;10136:7;-1:-1:-1;;;;;10112:31:23;:20;10124:7;10112:11;:20::i;:::-;-1:-1:-1;;;;;10112:31:23;;10092:51;:87;;;;10147:32;10164:5;10171:7;10147:16;:32::i;13468:447::-;13581:4;-1:-1:-1;;;;;13561:24:23;:16;13569:7;13561;:16::i;:::-;-1:-1:-1;;;;;13561:24:23;;13553:78;;;;-1:-1:-1;;;13553:78:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;13649:16:23;;13641:65;;;;-1:-1:-1;;;13641:65:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13717:23;13732:7;13717:14;:23::i;:::-;-1:-1:-1;;;;;13751:23:23;;;;;;:17;:23;;;;;:35;;:33;:35::i;:::-;-1:-1:-1;;;;;13796:21:23;;;;;;:17;:21;;;;;:33;;:31;:33::i;:::-;13840:20;;;;:11;:20;;;;;;:25;;-1:-1:-1;;;;;;13840:25:23;-1:-1:-1;;;;;13840:25:23;;;;;;;;;13881:27;;13840:20;;13881:27;;;;;;;13468:447;;;:::o;8212:153:0:-;8273:4;8295:33;8308:3;8303:9;;;;;;;;8319:4;8314:10;;;;;;;;8295:33;;;;;;;;;;;;;8326:1;8295:33;;;;;;;;;;;;;8353:3;8348:9;;;;;;;1067:112:17;1158:14;;1067:112::o;2664:2466:2:-;3119:10;:8;:10::i;:::-;-1:-1:-1;;;;;3105:24:2;:10;-1:-1:-1;;;;;3105:24:2;;3097:77;;;;-1:-1:-1;;;3097:77:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3309:4;3295:18;;-1:-1:-1;;;;3295:18:2;;;;;3324:19;3295:18;3324:19;;;;;3407:18;;;-1:-1:-1;;;;;3407:18:2;:32;3399:64;;;;;-1:-1:-1;;;3399:64:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;3524:18;:40;;-1:-1:-1;;3524:40:2;;-1:-1:-1;;;;;3524:40:2;;;;;;-1:-1:-1;3628:41:2;3650:18;3628:21;:41::i;:::-;3617:52;-1:-1:-1;3688:27:2;;3680:74;;;;-1:-1:-1;;;3680:74:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3802:23;3815:9;3802:12;:23::i;:::-;3796:29;-1:-1:-1;3844:27:2;;3836:63;;;;;-1:-1:-1;;;3836:63:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;4031:119;4060:28;4090:22;4114:27;4143:6;4031:28;:119::i;:::-;4025:125;-1:-1:-1;4169:27:2;;4161:81;;;;-1:-1:-1;;;4161:81:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4303:67;3612:4:5;4354:3:2;4359:1;4362:4;4368:1;4303:27;:67::i;:::-;4297:73;-1:-1:-1;4389:27:2;;4381:80;;;;-1:-1:-1;;;4381:80:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4517:13;;;;:5;;:13;;;;;:::i;:::-;-1:-1:-1;4541:17:2;;;;:7;;:17;;;;;:::i;:::-;-1:-1:-1;4569:9:2;:21;;-1:-1:-1;;4569:21:2;;;;;;;4680:8;;;:38;;;-1:-1:-1;;;4680:38:2;;4712:4;4680:38;;;;;;;;-1:-1:-1;;;;;;;4680:8:2;;;;:23;;:38;;;;;;;;;;;;;;:8;:38;;;5:2:-1;;;;30:1;27;20:12;5:2;4680:38:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4680:38:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;4680:38:2;-1:-1:-1;;;;;4737:31:2;;;;;;:18;4680:38;4737:31;;;;;4680:38;;-1:-1:-1;4737:36:2;:69;;;;-1:-1:-1;;;;;;4777:24:2;;;;;;:11;:24;;;;;;:29;4737:69;4729:117;;;;-1:-1:-1;;;4729:117:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4891:16;:14;:16::i;:::-;-1:-1:-1;;;;;4857:31:2;;;;;;:18;:31;;;;;;;;:50;;;;4918:11;:24;;;410:4:14;4918:38:2;;5022:27;4876:11;5022:14;:27::i;:::-;5016:33;-1:-1:-1;5068:27:2;;5060:62;;;;;-1:-1:-1;;;5060:62:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;2664:2466;;;;;;;;;;;:::o;6495:5511::-;6702:4;6746:10;6775:19;;;:42;;-1:-1:-1;6798:19:2;;6775:42;6767:107;;;;-1:-1:-1;;;6767:107:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6887:8;6898:22;6913:6;6898:14;:22::i;:::-;6887:33;-1:-1:-1;6935:27:2;;6931:245;;7105:59;7116:3;7110:10;;;;;;;;7122:41;7105:4;:59::i;:::-;7098:66;;;;;;6931:245;7188:27;;:::i;:::-;7332:34;7359:6;7332:26;:34::i;:::-;7303:25;;;7288:78;;;7289:12;;;7288:78;;;;;;;;;;;;;;;;;;;-1:-1:-1;7397:18:2;;-1:-1:-1;7381:4:2;:12;;;:34;;;;;;;;;7377:168;;7439:94;7450:16;7468:44;7519:4;:12;;;7514:18;;;;;;;7439:94;7432:101;;;;;;;7377:168;7599:18;;7595:1290;;7875:17;;;:34;;;7980:42;;;;;;;;7995:25;;;;7980:42;;7962:77;;7895:14;7962:17;:77::i;:::-;7941:17;;;7926:113;;;7927:12;;;7926:113;;;;;;;;;;;;;;;;;;;-1:-1:-1;8074:18:2;;-1:-1:-1;8058:4:2;:12;;;:34;;;;;;;;;8054:185;;8120:103;8131:16;8149:53;8209:4;:12;;;8204:18;;;;;;;8054:185;7595:1290;;;8541:82;8564:14;8580:42;;;;;;;;8595:4;:25;;;8580:42;;;8541:22;:82::i;:::-;8520:17;;;8505:118;;;8506:12;;;8505:118;;;;;;;;;;;;;;;;;;;-1:-1:-1;8658:18:2;;-1:-1:-1;8642:4:2;:12;;;:34;;;;;;;;;8638:185;;8704:103;8715:16;8733:53;8793:4;:12;;;8788:18;;;;;;;8638:185;8839:17;;;:34;;;7595:1290;-1:-1:-1;;;;;9188:19:2;;;;;;:11;:19;;;;;;9209:17;;;;9180:47;;9188:19;9180:7;:47::i;:::-;9157:19;;;9142:85;;;9143:12;;;9142:85;;;;;;;;;;;;;;;;;;;-1:-1:-1;9258:18:2;;-1:-1:-1;9242:4:2;:12;;;:34;;;;;;;;;9238:178;;9300:104;9311:16;9329:54;9390:4;:12;;;9385:18;;;;;;;9238:178;-1:-1:-1;;;;;9476:21:2;;;;;;:13;:21;;;;;;;;-1:-1:-1;;;;;9476:31:2;;;;;;;;;;9509:17;;;;9468:59;;9476:31;9468:7;:59::i;:::-;9443:21;;;9428:99;;;9429:12;;;9428:99;;;;;;;;;;;;;;;;;;;-1:-1:-1;9558:18:2;;-1:-1:-1;9542:4:2;:12;;;:34;;;;;;;;;9538:181;;9600:107;9611:16;9629:57;9693:4;:12;;;9688:18;;;;;;;9538:181;-1:-1:-1;;;;;9851:27:2;;;;;;:19;:27;;;;;;9880:17;;;;9843:55;;9851:27;9843:7;:55::i;:::-;9822:17;;;9807:91;;;9808:12;;;9807:91;;;;;;;;;;;;;;;;;;;-1:-1:-1;9929:18:2;;-1:-1:-1;9913:4:2;:12;;;:34;;;;;;;;;9909:155;;9971:81;9976:29;10007:44;9971:4;:81::i;9909:155::-;-1:-1:-1;;;;;10599:21:2;;10576:20;10599:21;;;:13;:21;;;;;;-1:-1:-1;;;;;10694:29:2;;;10690:190;;-1:-1:-1;;;;;10748:43:2;;;;;;:26;:43;;;;;;;;;:85;;-1:-1:-1;10795:38:2;;;:26;:38;;;;;;10748:85;10740:128;;;;;-1:-1:-1;;;10740:128:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;10890:103;10904:11;10917:12;10931:4;:17;;;10950:9;10961:15;10978:14;10890:13;:103::i;:::-;-1:-1:-1;11094:19:2;;;;-1:-1:-1;;;;;11072:19:2;;;;;;:11;:19;;;;;;;;:41;;;;11158:21;;;;11124:13;:21;;;;;-1:-1:-1;;;;;11124:31:2;;;;;;;;;;;:55;;;;11220:17;;;;11190:27;;;:19;:27;;;;;;:47;;;;11357:17;;;;;11315:60;;;;;11342:4;11315:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11391:76;11398:8;11408:6;11416:4;:17;;;11435:12;11449:4;:17;;;11391:76;;;;-1:-1:-1;;;;;11391:76:2;-1:-1:-1;;;;;11391:76:2;;;;;;-1:-1:-1;;;;;11391:76:2;-1:-1:-1;;;;;11391:76:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11738:8;;;;;;;;;-1:-1:-1;;;;;11738:8:2;-1:-1:-1;;;;;11738:22:2;;11761:6;11769:8;11779:1;11738:43;;;;;;;;;;;;;-1:-1:-1;;;;;11738:43:2;-1:-1:-1;;;;;11738:43:2;;;;;;-1:-1:-1;;;;;11738:43:2;-1:-1:-1;;;;;11738:43:2;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11738:43:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11738:43:2;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11738:43:2;11792:36;;;;;;;;;;;;-1:-1:-1;;;11738:43:2;11792:36;;;11738:43;;-1:-1:-1;11792:36:2;;11738:43;;11792:14;:36::i;:::-;11881:8;;;;;;;;;-1:-1:-1;;;;;11881:8:2;-1:-1:-1;;;;;11881:21:2;;11903:6;11911:8;11921:4;:17;;;11940:4;:17;;;11881:77;;;;;;;;;;;;;-1:-1:-1;;;;;11881:77:2;-1:-1:-1;;;;;11881:77:2;;;;;;-1:-1:-1;;;;;11881:77:2;-1:-1:-1;;;;;11881:77:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11881:77:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;11983:14:2;;-1:-1:-1;11978:20:2;;-1:-1:-1;;11978:20:2;;11971:27;;;;;;6495:5511;;;;;;;;;;:::o;9155:712:3:-;9245:31;9241:70;;9293:7;;9241:70;9323:24;9366:7;9360:21;9384:1;9360:25;9350:36;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;9350:36:3;87:34:-1;135:17;;-1:-1;9350:36:3;-1:-1:-1;9323:63:3;-1:-1:-1;9397:6:3;9416:105;9438:7;9432:21;9428:1;:25;9416:105;;;9498:7;9507:1;9492:17;;;;;;;;;;;;;;;;9475:11;9487:1;9475:14;;;;;;;;;;;:34;-1:-1:-1;;;;;9475:34:3;;;;;;;;-1:-1:-1;9455:3:3;;9416:105;;;9533:16;;-1:-1:-1;;;9552:15:3;9533:11;;9545:1;;9533:16;;;;;;;;;:34;-1:-1:-1;;;;;9533:34:3;;;;;;;;;9608:2;9597:15;;9578:11;9590:1;9592;9590:3;9578:16;;;;;;;;;;;:34;-1:-1:-1;;;;;9578:34:3;;;;;;;;-1:-1:-1;9670:2:3;9660:7;:12;9653:2;:21;9642:34;;9623:11;9635:1;9637;9635:3;9623:16;;;;;;;;;;;:53;-1:-1:-1;;;;;9623:53:3;;;;;;;;-1:-1:-1;9734:2:3;9724:7;:12;9717:2;:21;9706:34;;9687:11;9699:1;9701;9699:3;9687:16;;;;;;;;;;;:53;-1:-1:-1;;;;;9687:53:3;;;;;;;;;9781:2;9770:15;;9751:11;9763:1;9765;9763:3;9751:16;;;;;;;;;;;:34;-1:-1:-1;;;;;9751:34:3;;;;;;;;-1:-1:-1;9846:11:3;9806:31;;9798:61;;;;-1:-1:-1;;;9798:61:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;9798:61:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9155:712;;;;;:::o;13001:90:23:-;13052:32;13058:16;13066:7;13058;:16::i;:::-;13076:7;13052:5;:32::i;:::-;13001:90;:::o;8881:269::-;8990:32;9004:4;9010:2;9014:7;8990:13;:32::i;:::-;9040:48;9063:4;9069:2;9073:7;9082:5;9040:22;:48::i;:::-;9032:111;;;;-1:-1:-1;;;9032:111:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9020:93:3;9093:12;9020:93;:::o;1303:230:10:-;1359:9;1370:4;1395:1;1390;:6;1386:141;;-1:-1:-1;1420:18:10;;-1:-1:-1;1440:5:10;;;1412:34;;1386:141;-1:-1:-1;1485:27:10;;-1:-1:-1;1514:1:10;1386:141;1303:230;;;;;:::o;1978:346:13:-;2047:9;2058:10;;:::i;:::-;2081:14;2097:19;2120:27;2128:1;:10;;;2140:6;2120:7;:27::i;:::-;2080:67;;-1:-1:-1;2080:67:13;-1:-1:-1;2169:18:13;2161:4;:26;;;;;;;;;2157:90;;-1:-1:-1;2217:18:13;;;;;;;;;-1:-1:-1;2217:18:13;;2211:4;;-1:-1:-1;2217:18:13;-1:-1:-1;2203:33:13;;2157:90;2285:31;;;;;;;;;;;;-1:-1:-1;;2285:31:13;;-1:-1:-1;1978:346:13;-1:-1:-1;;;;1978:346:13:o;8488:187:0:-;8573:4;8595:43;8608:3;8603:9;;;;;;;;8619:4;8614:10;;;;;;;;8595:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;8663:3;8658:9;;;;;;;2432:306:13;2509:9;2520:4;2537:13;2552:18;;:::i;:::-;2574:20;2584:1;2587:6;2574:9;:20::i;:::-;2536:58;;-1:-1:-1;2536:58:13;-1:-1:-1;2615:18:13;2608:3;:25;;;;;;;;;2604:71;;-1:-1:-1;2657:3:13;-1:-1:-1;2662:1:13;;-1:-1:-1;2649:15:13;;2604:71;2693:18;2713:17;2722:7;2713:8;:17::i;:::-;2685:46;;;;;;2432:306;;;;;:::o;1613:250:10:-;1669:9;;1705:5;;;1725:6;;;1721:136;;1755:18;;-1:-1:-1;1775:1:10;-1:-1:-1;1747:30:10;;1721:136;-1:-1:-1;1816:26:10;;-1:-1:-1;1844:1:10;;-1:-1:-1;1808:38:10;;2878:321:13;2975:9;2986:4;3003:13;3018:18;;:::i;:::-;3040:20;3050:1;3053:6;3040:9;:20::i;:::-;3002:58;;-1:-1:-1;3002:58:13;-1:-1:-1;3081:18:13;3074:3;:25;;;;;;;;;3070:71;;-1:-1:-1;3123:3:13;-1:-1:-1;3128:1:13;;-1:-1:-1;3115:15:13;;3070:71;3158:34;3166:17;3175:7;3166:8;:17::i;:::-;3185:6;3158:7;:34::i;:::-;3151:41;;;;;;2878:321;;;;;;;:::o;32996:2202:2:-;33079:4;33096:17;33124:21;33156:17;33220:21;33244:10;:8;:10::i;:::-;33220:34;-1:-1:-1;33269:10:2;-1:-1:-1;;;;;33269:19:2;;;33265:124;;33312:65;33317:18;33337:39;33312:4;:65::i;:::-;33305:72;;;;;;;;33265:124;33523:16;:14;:16::i;:::-;-1:-1:-1;;;;;33493:26:2;;;;;;:18;:26;;;;;;:46;33489:155;;33563:69;33568:22;33592:39;33563:4;:69::i;33489:155::-;-1:-1:-1;;;;;33763:21:2;;;;;;:13;:21;;;;;;33755:44;;33786:12;33755:7;:44::i;:::-;33725:74;;-1:-1:-1;33725:74:2;-1:-1:-1;33825:18:2;33814:7;:29;;;;;;;;;33810:130;;33867:61;33872:15;33889:38;33867:4;:61::i;33810:130::-;-1:-1:-1;;;;;34062:27:2;;;;;;:19;:27;;;;;;34054:50;;34091:12;34054:7;:50::i;:::-;34028:76;;-1:-1:-1;34028:76:2;-1:-1:-1;34130:18:2;34119:7;:29;;;;;;;;;34115:152;;34172:83;34177:29;34208:46;34172:4;:83::i;34115:152::-;34772:20;34795:13;:21;34809:6;-1:-1:-1;;;;;34795:21:2;-1:-1:-1;;;;;34795:21:2;;;;;;;;;;;;;34772:44;;34827:67;34841:5;34848:12;34862;34876:1;34887;34827:67;;;;;;;;;;;;:13;:67::i;:::-;-1:-1:-1;;;;;;34977:21:2;;;;;;:13;:21;;;;;;;;:40;;;35028:19;:27;;;;;;:42;;;35088:62;;-1:-1:-1;;;;;35088:62:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35175:14;35163:27;32996:2202;-1:-1:-1;;;;;;;;32996:2202:2:o;15767:171:23:-;15866:1;15830:24;;;:15;:24;;;;;;-1:-1:-1;;;;;15830:24:23;:38;15826:106;;15919:1;15884:24;;;:15;:24;;;;;:37;;-1:-1:-1;;;;;;15884:37:23;;;15767:171::o;1369:108:17:-;1449:14;;:21;;1468:1;1449:21;:18;:21;:::i;:::-;1432:38;;1369:108::o;1185:178::-;1337:19;;1355:1;1337:19;;;1185:178::o;6028:1237:3:-;-1:-1:-1;;;;;6151:19:3;;6103:9;6151:19;;;:11;:19;;;;;;6103:9;;6185:17;6181:1077;;-1:-1:-1;;6379:27:3;;6359:18;;-1:-1:-1;6351:56:3;;6181:1077;-1:-1:-1;;;;;6606:27:3;;6589:14;6606:27;;;:19;:27;;;;;;;6696:23;;:::i;:::-;-1:-1:-1;;;;;6836:20:3;;6734:17;6836:20;;;:12;:20;;;;;;;;;6858:13;:21;;;;;;6810:70;;6825:9;;6810:14;:70::i;:::-;6768:112;-1:-1:-1;6768:112:3;-1:-1:-1;6910:18:3;6899:7;:29;;;;;;;;;6895:89;;6957:7;-1:-1:-1;6966:1:3;;-1:-1:-1;6949:19:3;;-1:-1:-1;;;;6949:19:3;6895:89;7026:50;7033:28;7063:12;7026:6;:50::i;:::-;7000:76;-1:-1:-1;7000:76:3;-1:-1:-1;7106:18:3;7095:7;:29;;;;;;;;;7091:89;;7153:7;-1:-1:-1;7162:1:3;;-1:-1:-1;7145:19:3;;-1:-1:-1;;;;7145:19:3;7091:89;-1:-1:-1;7224:21:3;7204:18;;-1:-1:-1;7224:21:3;-1:-1:-1;7196:50:3;;-1:-1:-1;;;7196:50:3;6028:1237;;;;:::o;4424:330:13:-;4512:9;4523:4;4540:13;4555:19;;:::i;:::-;4578:31;4593:6;4601:7;4578:14;:31::i;8920:2212:1:-;9094:4;9322::5;9405:6:1;:17;9397:52;;;;;-1:-1:-1;;;9397:52:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;9464:29:1;;9460:1641;;9584:18;;9576:77;;;-1:-1:-1;;;9576:77:1;;9629:4;9576:77;;;;-1:-1:-1;;;;;9576:77:1;;;;;;;;;;;;;;;9584:18;;;;;;;;9576:44;;:77;;;;;-1:-1:-1;;9576:77:1;;;;;;;;-1:-1:-1;9584:18:1;9576:77;;;5:2:-1;;;;30:1;27;20:12;5:2;9576:77:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9576:77:1;;;;9729:2;-1:-1:-1;;;;;9676:55:1;9684:18;;;;;;;;;-1:-1:-1;;;;;9684:18:1;-1:-1:-1;;;;;9676:35:1;;9712:12;9676:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9676:49:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9676:49:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9676:49:1;-1:-1:-1;;;;;9676:55:1;;9668:87;;;;;-1:-1:-1;;;9668:87:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;9460:1641;;;10016:18;;10008:90;;;-1:-1:-1;;;10008:90:1;;10061:4;10008:90;;;;-1:-1:-1;;;;;10008:90:1;;;;;;;;;;;;;;;10016:18;;;;;;;;10008:44;;:90;;;;;-1:-1:-1;;10008:90:1;;;;;;;;-1:-1:-1;10016:18:1;10008:90;;;5:2:-1;;;;30:1;27;20:12;5:2;10008:90:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10008:90:1;;;;10113:26;10142:12;;;;;;;;;-1:-1:-1;;;;;10142:12:1;-1:-1:-1;;;;;10142:25:1;;:27;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10142:27:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10142:27:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10142:27:1;10206:50;;;-1:-1:-1;;;10206:50:1;;;;10142:27;;-1:-1:-1;10184:19:1;;-1:-1:-1;;;;;10206:48:1;;;;;:50;;;;;10142:27;;10206:50;;;;;;;:48;:50;;;5:2:-1;;;;30:1;27;20:12;5:2;10206:50:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10206:50:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10206:50:1;10338:44;;;-1:-1:-1;;;10338:44:1;;-1:-1:-1;;;;;10289:10:1;;;10338:44;;;;;;-1:-1:-1;;;;;10338:44:1;;;;;;;;10206:50;;-1:-1:-1;10289:10:1;;;10271:15;;10338:27;;;;;:44;;;;;10206:50;;10338:44;;;;;;;10271:15;10338:27;:44;;;5:2:-1;;;;30:1;27;20:12;5:2;10338:44:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10338:44:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;10338:44:1;;;;;;;;;;;;;;;;10314:68;;10397:10;10437:15;-1:-1:-1;;;;;10410:59:1;;10470:12;10484:2;10488:9;10499:14;10410:104;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;10410:104:1;-1:-1:-1;;;;;10410:104:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;10410:104:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10410:104:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10410:104:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10410:104:1;;-1:-1:-1;10537:29:1;;10529:67;;;;;-1:-1:-1;;;10529:67:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;10631:10:1;;;10664:26;;;;10656:64;;;;;-1:-1:-1;;;10656:64:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;10811:43;;;-1:-1:-1;;;10811:43:1;;-1:-1:-1;;;;;10811:43:1;;;;;;;-1:-1:-1;;;;;10811:43:1;;;;;;;;10750:25;;;;;10790:18;;10811:26;;;;;:43;;;;;;;;;;;;;;:26;:43;;;5:2:-1;;;;30:1;27;20:12;5:2;10811:43:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10811:43:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10811:43:1;;-1:-1:-1;10877:33:1;;;;10869:62;;;;;-1:-1:-1;;;10869:62:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;10962:32;;11018:28;;;11017:43;-1:-1:-1;11017:43:1;11009:80;;;;;-1:-1:-1;;;11009:80:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;9460:1641;;;;;;;;-1:-1:-1;11118:6:1;;8920:2212;-1:-1:-1;;;;;8920:2212:1:o;12496:324:23:-;12590:5;-1:-1:-1;;;;;12570:25:23;:16;12578:7;12570;:16::i;:::-;-1:-1:-1;;;;;12570:25:23;;12562:75;;;;-1:-1:-1;;;12562:75:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12648:23;12663:7;12648:14;:23::i;:::-;-1:-1:-1;;;;;12682:24:23;;;;;;:17;:24;;;;;:36;;:34;:36::i;:::-;12759:1;12728:20;;;:11;:20;;;;;;:33;;-1:-1:-1;;;;;;12728:33:23;;;12777:36;12740:7;;12759:1;-1:-1:-1;;;;;12777:36:23;;;;;12759:1;;12777:36;12496:324;;:::o;14554:1051::-;14675:4;14700:15;:2;-1:-1:-1;;;;;14700:13:23;;:15::i;:::-;14695:58;;-1:-1:-1;14738:4:23;14731:11;;14695:58;14822:12;14836:23;-1:-1:-1;;;;;14863:7:23;;-1:-1:-1;;;14966:12:23;:10;:12::i;:::-;14992:4;15010:7;15031:5;14871:175;;;;;;-1:-1:-1;;;;;14871:175:23;-1:-1:-1;;;;;14871:175:23;;;;;;-1:-1:-1;;;;;14871:175:23;-1:-1:-1;;;;;14871:175:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;14871:175:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14871:175:23;;;-1:-1:-1;;26:21;;;22:32;6:49;;14871:175:23;;;49:4:-1;25:18;;61:17;;14871:175:23;182:15:-1;-1:-1;;;;;;14871:175:23;;;179:29:-1;;;;160:49;;14863:184:23;;;14871:175;;14863:184;;-1:-1:-1;14863:184:23;;-1:-1:-1;25:18;-1:-1;14863:184:23;-1:-1:-1;14863:184:23;;-1:-1:-1;14863:184:23;;-1:-1:-1;25:18;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;14863:184:23;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;14821:226:23;;;;15062:7;15057:542;;15089:17;;:21;15085:376;;15254:10;15248:17;15314:15;15301:10;15297:2;15293:19;15286:44;15203:145;15386:60;;-1:-1:-1;;;15386:60:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15057:542;15491:13;15518:10;15507:32;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;15507:32:23;-1:-1:-1;;;;;;15561:26:23;-1:-1:-1;;;15561:26:23;;-1:-1:-1;15553:35:23;;-1:-1:-1;;;15553:35:23;543:331:10;599:9;;630:6;626:67;;-1:-1:-1;660:18:10;;-1:-1:-1;660:18:10;652:30;;626:67;712:5;;;716:1;712;:5;:1;732:5;;;;;:10;728:140;;-1:-1:-1;766:26:10;;-1:-1:-1;794:1:10;;-1:-1:-1;758:38:10;;728:140;835:18;;-1:-1:-1;855:1:10;-1:-1:-1;827:30:10;;789:210:14;969:12;410:4;969:23;;;789:210::o;1275:134:20:-;1333:7;1359:43;1363:1;1366;1359:43;;;;;;;;;;;;;;;;;:3;:43::i;1927:263:10:-;1998:9;2009:4;2026:14;2042:8;2054:13;2062:1;2065;2054:7;:13::i;:::-;2025:42;;-1:-1:-1;2025:42:10;-1:-1:-1;2090:18:10;2082:4;:26;;;;;;;;;2078:73;;-1:-1:-1;2132:4:10;-1:-1:-1;2138:1:10;;-1:-1:-1;2124:16:10;;2078:73;2168:15;2176:3;2181:1;2168:7;:15::i;772:503:13:-;833:9;844:10;;:::i;:::-;867:14;883:20;907:22;915:3;410:4:14;907:7:13;:22::i;:::-;866:63;;-1:-1:-1;866:63:13;-1:-1:-1;951:18:13;943:4;:26;;;;;;;;;939:90;;-1:-1:-1;999:18:13;;;;;;;;;-1:-1:-1;999:18:13;;993:4;;-1:-1:-1;999:18:13;-1:-1:-1;985:33:13;;939:90;1040:14;1056:13;1073:31;1081:15;1098:5;1073:7;:31::i;:::-;1039:65;;-1:-1:-1;1039:65:13;-1:-1:-1;1126:18:13;1118:4;:26;;;;;;;;;1114:90;;-1:-1:-1;1174:18:13;;;;;;;;;-1:-1:-1;1174:18:13;;1168:4;;-1:-1:-1;1174:18:13;-1:-1:-1;1160:33:13;;-1:-1:-1;;1160:33:13;1114:90;1242:25;;;;;;;;;;;;-1:-1:-1;;1242:25:13;;-1:-1:-1;772:503:13;-1:-1:-1;;;;;;772:503:13:o;3713:605::-;3793:9;3804:10;;:::i;:::-;4101:14;4117;4135:25;410:4:14;4153:6:13;4135:7;:25::i;:::-;4100:60;;-1:-1:-1;4100:60:13;-1:-1:-1;4182:18:13;4174:4;:26;;;;;;;;;4170:90;;-1:-1:-1;4230:18:13;;;;;;;;;-1:-1:-1;4230:18:13;;4224:4;;-1:-1:-1;4230:18:13;-1:-1:-1;4216:33:13;;4170:90;4276:35;4283:9;4294:7;:16;;;4276:6;:35::i;686:610:27:-;746:4;1207:20;;1052:66;1246:23;;;;;;:42;;-1:-1:-1;;1273:15:27;;;1238:51;-1:-1:-1;;686:610:27:o;1733:187:20:-;1819:7;1854:12;1846:6;;;;1838:29;;;;-1:-1:-1;;;1838:29:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;1838:29:20;-1:-1:-1;;;1889:5:20;;;1733:187::o;964:209:10:-;1020:9;;1051:6;1047:75;;-1:-1:-1;1081:26:10;;-1:-1:-1;1109:1:10;1073:38;;1047:75;1140:18;1164:1;1160;:5;;;;;;1132:34;;;;964:209;;;;;:::o;549:11762:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;549:11762:1;;;-1:-1:-1;549:11762:1;:::i;:::-;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;549:11762:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;
Swarm Source
bzzr://9005a9de716f4718928270bc21a6a99c31d236136ec6e7608e2a9a59a3b144e5
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.