Overview
BTT Balance
0 BTT
BTT Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 10 from a total of 10 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Enter Markets | 14334612 | 753 days ago | IN | 0 BTT | 7.7019 | ||||
Enter Markets | 14334520 | 753 days ago | IN | 0 BTT | 7.7019 | ||||
Enter Markets | 14334462 | 753 days ago | IN | 0 BTT | 7.7019 | ||||
Enter Markets | 14334351 | 753 days ago | IN | 0 BTT | 7.7019 | ||||
Enter Markets | 14334337 | 753 days ago | IN | 0 BTT | 7.7019 | ||||
Enter Markets | 14331986 | 753 days ago | IN | 0 BTT | 7.6983 | ||||
Enter Markets | 14331908 | 753 days ago | IN | 0 BTT | 7.6983 | ||||
Enter Markets | 14331586 | 753 days ago | IN | 0 BTT | 7.7019 | ||||
Enter Markets | 14331567 | 753 days ago | IN | 0 BTT | 7.7019 | ||||
_become | 14069932 | 759 days ago | IN | 0 BTT | 12.9591 |
Loading...
Loading
Contract Name:
Comptroller
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity)
/** *Submitted for verification at bttcscan.com on 2022-11-14 */ // Sources flattened with hardhat v2.10.1 https://hardhat.org // File contracts/ComptrollerInterface.sol // SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; abstract contract ComptrollerInterface { /// @notice Indicator that this is a Comptroller contract (for inspection) bool public constant isComptroller = true; /*** Assets You Are In ***/ function enterMarkets(address[] calldata cTokens) virtual external returns (uint[] memory); function exitMarket(address cToken) virtual external returns (uint); /*** Policy Hooks ***/ function mintAllowed(address cToken, address minter, uint mintAmount) virtual external returns (uint); function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) virtual external; function redeemAllowed(address cToken, address redeemer, uint redeemTokens) virtual external returns (uint); function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) virtual external; function borrowAllowed(address cToken, address borrower, uint borrowAmount) virtual external returns (uint); function borrowVerify(address cToken, address borrower, uint borrowAmount) virtual external; function repayBorrowAllowed( address cToken, address payer, address borrower, uint repayAmount) virtual external returns (uint); function repayBorrowVerify( address cToken, address payer, address borrower, uint repayAmount, uint borrowerIndex) virtual external; function liquidateBorrowAllowed( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint repayAmount) virtual external returns (uint); function liquidateBorrowVerify( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint repayAmount, uint seizeTokens) virtual external; function seizeAllowed( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint seizeTokens) virtual external returns (uint); function seizeVerify( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint seizeTokens) virtual external; function transferAllowed(address cToken, address src, address dst, uint transferTokens) virtual external returns (uint); function transferVerify(address cToken, address src, address dst, uint transferTokens) virtual external; /*** Liquidity/Liquidation Calculations ***/ function liquidateCalculateSeizeTokens( address cTokenBorrowed, address cTokenCollateral, uint repayAmount) virtual external view returns (uint, uint); } abstract 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) virtual 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) virtual external view returns (uint); } 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 balance 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 success 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 remaining 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); } contract ComptrollerErrorReporter { enum Error { NO_ERROR, UNAUTHORIZED, COMPTROLLER_MISMATCH, INSUFFICIENT_SHORTFALL, INSUFFICIENT_LIQUIDITY, INVALID_CLOSE_FACTOR, INVALID_COLLATERAL_FACTOR, INVALID_LIQUIDATION_INCENTIVE, MARKET_NOT_ENTERED, // no longer possible MARKET_NOT_LISTED, MARKET_ALREADY_LISTED, MATH_ERROR, NONZERO_BORROW_BALANCE, PRICE_ERROR, REJECTION, SNAPSHOT_ERROR, TOO_MANY_ASSETS, TOO_MUCH_REPAY } 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 { uint public constant NO_ERROR = 0; // support legacy return codes error TransferComptrollerRejection(uint256 errorCode); error TransferNotAllowed(); error TransferNotEnough(); error TransferTooMuch(); error MintComptrollerRejection(uint256 errorCode); error MintFreshnessCheck(); error RedeemComptrollerRejection(uint256 errorCode); error RedeemFreshnessCheck(); error RedeemTransferOutNotPossible(); error BorrowComptrollerRejection(uint256 errorCode); error BorrowFreshnessCheck(); error BorrowCashNotAvailable(); error RepayBorrowComptrollerRejection(uint256 errorCode); error RepayBorrowFreshnessCheck(); error LiquidateComptrollerRejection(uint256 errorCode); error LiquidateFreshnessCheck(); error LiquidateCollateralFreshnessCheck(); error LiquidateAccrueBorrowInterestFailed(uint256 errorCode); error LiquidateAccrueCollateralInterestFailed(uint256 errorCode); error LiquidateLiquidatorIsBorrower(); error LiquidateCloseAmountIsZero(); error LiquidateCloseAmountIsUintMax(); error LiquidateRepayBorrowFreshFailed(uint256 errorCode); error LiquidateSeizeComptrollerRejection(uint256 errorCode); error LiquidateSeizeLiquidatorIsBorrower(); error AcceptAdminPendingAdminCheck(); error SetComptrollerOwnerCheck(); error SetPendingAdminOwnerCheck(); error SetReserveFactorAdminCheck(); error SetReserveFactorFreshCheck(); error SetReserveFactorBoundsCheck(); error AddReservesFactorFreshCheck(uint256 actualAddAmount); error ReduceReservesAdminCheck(); error ReduceReservesFreshCheck(); error ReduceReservesCashNotAvailable(); error ReduceReservesCashValidation(); error SetInterestRateModelOwnerCheck(); error SetInterestRateModelFreshCheck(); } contract CTokenStorage { /** * @dev Guard variable for re-entrancy checks */ bool internal _notEntered; /** * @notice EIP-20 token name for this token */ string public name; /** * @notice EIP-20 token symbol for this token */ string public symbol; /** * @notice EIP-20 token decimals for this token */ uint8 public decimals; // Maximum borrow rate that can ever be applied (.0005% / block) uint internal constant borrowRateMaxMantissa = 0.0005e16; // Maximum fraction of interest that can be set aside for reserves uint internal constant reserveFactorMaxMantissa = 1e18; /** * @notice Administrator for this contract */ address payable public admin; /** * @notice Pending administrator for this contract */ address payable public pendingAdmin; /** * @notice Contract which oversees inter-cToken operations */ ComptrollerInterface public comptroller; /** * @notice Model which tells what the current interest rate should be */ InterestRateModel public interestRateModel; // Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) uint internal initialExchangeRateMantissa; /** * @notice Fraction of interest currently set aside for reserves */ uint public reserveFactorMantissa; /** * @notice Block number that interest was last accrued at */ uint public accrualBlockNumber; /** * @notice Accumulator of the total earned interest rate since the opening of the market */ uint public borrowIndex; /** * @notice Total amount of outstanding borrows of the underlying in this market */ uint public totalBorrows; /** * @notice Total amount of reserves of the underlying held in this market */ uint public totalReserves; /** * @notice Total number of tokens in circulation */ uint public totalSupply; // Official record of token balances for each account mapping (address => uint) internal accountTokens; // Approved token transfer amounts on behalf of others mapping (address => mapping (address => uint)) internal transferAllowances; /** * @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; } // Mapping of account addresses to outstanding borrow balances mapping(address => BorrowSnapshot) internal accountBorrows; /** * @notice Share of seized collateral that is added to reserves */ uint public constant protocolSeizeShareMantissa = 2.8e16; //2.8% } abstract contract CTokenInterface is CTokenStorage { /** * @notice Indicator that this is a CToken contract (for inspection) */ bool public constant isCToken = true; /*** Market Events ***/ /** * @notice Event emitted when interest is accrued */ event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows); /** * @notice Event emitted when tokens are minted */ event Mint(address minter, uint mintAmount, uint mintTokens); /** * @notice Event emitted when tokens are redeemed */ event Redeem(address redeemer, uint redeemAmount, uint redeemTokens); /** * @notice Event emitted when underlying is borrowed */ event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows); /** * @notice Event emitted when a borrow is repaid */ event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows); /** * @notice Event emitted when a borrow is liquidated */ event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens); /*** Admin Events ***/ /** * @notice Event emitted when pendingAdmin is changed */ event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); /** * @notice Event emitted when pendingAdmin is accepted, which means admin is updated */ event NewAdmin(address oldAdmin, address newAdmin); /** * @notice Event emitted when comptroller is changed */ event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller); /** * @notice Event emitted when interestRateModel is changed */ event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel); /** * @notice Event emitted when the reserve factor is changed */ event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa); /** * @notice Event emitted when the reserves are added */ event ReservesAdded(address benefactor, uint addAmount, uint newTotalReserves); /** * @notice Event emitted when the reserves are reduced */ event ReservesReduced(address admin, uint reduceAmount, uint newTotalReserves); /** * @notice EIP20 Transfer event */ event Transfer(address indexed from, address indexed to, uint amount); /** * @notice EIP20 Approval event */ event Approval(address indexed owner, address indexed spender, uint amount); /*** User Interface ***/ function transfer(address dst, uint amount) virtual external returns (bool); function transferFrom(address src, address dst, uint amount) virtual external returns (bool); function approve(address spender, uint amount) virtual external returns (bool); function allowance(address owner, address spender) virtual external view returns (uint); function balanceOf(address owner) virtual external view returns (uint); function balanceOfUnderlying(address owner) virtual external returns (uint); function getAccountSnapshot(address account) virtual external view returns (uint, uint, uint, uint); function borrowRatePerBlock() virtual external view returns (uint); function supplyRatePerBlock() virtual external view returns (uint); function totalBorrowsCurrent() virtual external returns (uint); function borrowBalanceCurrent(address account) virtual external returns (uint); function borrowBalanceStored(address account) virtual external view returns (uint); function exchangeRateCurrent() virtual external returns (uint); function exchangeRateStored() virtual external view returns (uint); function getCash() virtual external view returns (uint); function accrueInterest() virtual external returns (uint); function seize(address liquidator, address borrower, uint seizeTokens) virtual external returns (uint); /*** Admin Functions ***/ function _setPendingAdmin(address payable newPendingAdmin) virtual external returns (uint); function _acceptAdmin() virtual external returns (uint); function _setComptroller(ComptrollerInterface newComptroller) virtual external returns (uint); function _setReserveFactor(uint newReserveFactorMantissa) virtual external returns (uint); function _reduceReserves(uint reduceAmount) virtual external returns (uint); function _setInterestRateModel(InterestRateModel newInterestRateModel) virtual external returns (uint); } contract CErc20Storage { /** * @notice Underlying asset for this CToken */ address public underlying; } abstract contract CErc20Interface is CErc20Storage { /*** User Interface ***/ function mint(uint mintAmount) virtual external returns (uint); function redeem(uint redeemTokens) virtual external returns (uint); function redeemUnderlying(uint redeemAmount) virtual external returns (uint); function borrow(uint borrowAmount) virtual external returns (uint); function repayBorrow(uint repayAmount) virtual external returns (uint); function repayBorrowBehalf(address borrower, uint repayAmount) virtual external returns (uint); function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) virtual external returns (uint); function sweepToken(EIP20NonStandardInterface token) virtual external; /*** Admin Functions ***/ function _addReserves(uint addAmount) virtual external returns (uint); } contract CDelegationStorage { /** * @notice Implementation address for this contract */ address public implementation; } abstract contract CDelegatorInterface is CDelegationStorage { /** * @notice Emitted when implementation is changed */ event NewImplementation(address oldImplementation, address newImplementation); /** * @notice Called by the admin to update the implementation of the delegator * @param implementation_ The address of the new implementation for delegation * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation */ function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) virtual external; } abstract contract CDelegateInterface is CDelegationStorage { /** * @notice Called by the delegator on a delegate to initialize it for duty * @dev Should revert if any issues arise which make it unfit for delegation * @param data The encoded bytes data for any initialization */ function _becomeImplementation(bytes memory data) virtual external; /** * @notice Called by the delegator on a delegate to forfeit its responsibility */ function _resignImplementation() virtual external; } 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 balance 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 success 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 success 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 success 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 remaining 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); } 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 a + b; } 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 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 a * b; } 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 a / b; } function fraction(uint a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a, doubleScale), b)}); } } abstract contract CToken is CTokenInterface, ExponentialNoError, TokenErrorReporter { /** * @notice Initialize the money market * @param comptroller_ The address of the Comptroller * @param interestRateModel_ The address of the interest rate model * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param name_ EIP-20 name of this token * @param symbol_ EIP-20 symbol of this token * @param decimals_ EIP-20 decimal precision of this token */ function initialize(ComptrollerInterface comptroller_, InterestRateModel interestRateModel_, uint initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_) public { require(msg.sender == admin, "only admin may initialize the market"); require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once"); // Set initial exchange rate initialExchangeRateMantissa = initialExchangeRateMantissa_; require(initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero."); // Set the comptroller uint err = _setComptroller(comptroller_); require(err == NO_ERROR, "setting comptroller failed"); // Initialize block number and borrow index (block number mocks depend on comptroller being set) accrualBlockNumber = getBlockNumber(); borrowIndex = mantissaOne; // Set the interest rate model (depends on block number / borrow index) err = _setInterestRateModelFresh(interestRateModel_); require(err == NO_ERROR, "setting interest rate model failed"); name = name_; symbol = symbol_; decimals = decimals_; // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund) _notEntered = true; } /** * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` * @dev Called by both `transfer` and `transferFrom` internally * @param spender The address of the account performing the transfer * @param src The address of the source account * @param dst The address of the destination account * @param tokens The number of tokens to transfer * @return 0 if the transfer succeeded, else revert */ function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) { /* Fail if transfer not allowed */ uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens); if (allowed != 0) { revert TransferComptrollerRejection(allowed); } /* Do not allow self-transfers */ if (src == dst) { revert TransferNotAllowed(); } /* Get the allowance, infinite for the account owner */ uint startingAllowance = 0; if (spender == src) { startingAllowance = type(uint).max; } else { startingAllowance = transferAllowances[src][spender]; } /* Do the calculations, checking for {under,over}flow */ uint allowanceNew = startingAllowance - tokens; uint srcTokensNew = accountTokens[src] - tokens; uint dstTokensNew = accountTokens[dst] + tokens; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) accountTokens[src] = srcTokensNew; accountTokens[dst] = dstTokensNew; /* Eat some of the allowance (if necessary) */ if (startingAllowance != type(uint).max) { transferAllowances[src][spender] = allowanceNew; } /* We emit a Transfer event */ emit Transfer(src, dst, tokens); // unused function // comptroller.transferVerify(address(this), src, dst, tokens); return NO_ERROR; } /** * @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) override external nonReentrant returns (bool) { return transferTokens(msg.sender, msg.sender, dst, amount) == NO_ERROR; } /** * @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) override external nonReentrant returns (bool) { return transferTokens(msg.sender, src, dst, amount) == NO_ERROR; } /** * @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 (uint256.max means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint256 amount) override external returns (bool) { address src = msg.sender; transferAllowances[src][spender] = amount; emit Approval(src, spender, amount); return true; } /** * @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) override external view returns (uint256) { return transferAllowances[owner][spender]; } /** * @notice Get the token balance of the `owner` * @param owner The address of the account to query * @return The number of tokens owned by `owner` */ function balanceOf(address owner) override external view returns (uint256) { return accountTokens[owner]; } /** * @notice Get the underlying balance of the `owner` * @dev This also accrues interest in a transaction * @param owner The address of the account to query * @return The amount of underlying owned by `owner` */ function balanceOfUnderlying(address owner) override external returns (uint) { Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()}); return mul_ScalarTruncate(exchangeRate, accountTokens[owner]); } /** * @notice Get a snapshot of the account's balances, and the cached exchange rate * @dev This is used by comptroller to more efficiently perform liquidity checks. * @param account Address of the account to snapshot * @return (possible error, token balance, borrow balance, exchange rate mantissa) */ function getAccountSnapshot(address account) override external view returns (uint, uint, uint, uint) { return ( NO_ERROR, accountTokens[account], borrowBalanceStoredInternal(account), exchangeRateStoredInternal() ); } /** * @dev Function to simply retrieve block number * This exists mainly for inheriting test contracts to stub this result. */ function getBlockNumber() virtual internal view returns (uint) { return block.number; } /** * @notice Returns the current per-block borrow interest rate for this cToken * @return The borrow interest rate per block, scaled by 1e18 */ function borrowRatePerBlock() override external view returns (uint) { return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); } /** * @notice Returns the current per-block supply interest rate for this cToken * @return The supply interest rate per block, scaled by 1e18 */ function supplyRatePerBlock() override external view returns (uint) { return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa); } /** * @notice Returns the current total borrows plus accrued interest * @return The total borrows with interest */ function totalBorrowsCurrent() override external nonReentrant returns (uint) { accrueInterest(); return totalBorrows; } /** * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex * @param account The address whose balance should be calculated after updating borrowIndex * @return The calculated balance */ function borrowBalanceCurrent(address account) override external nonReentrant returns (uint) { accrueInterest(); return borrowBalanceStored(account); } /** * @notice Return the borrow balance of account based on stored data * @param account The address whose balance should be calculated * @return The calculated balance */ function borrowBalanceStored(address account) override public view returns (uint) { return borrowBalanceStoredInternal(account); } /** * @notice Return the borrow balance of account based on stored data * @param account The address whose balance should be calculated * @return (error code, the calculated balance or 0 if error code is non-zero) */ function borrowBalanceStoredInternal(address account) internal view returns (uint) { /* Get borrowBalance and borrowIndex */ BorrowSnapshot storage borrowSnapshot = accountBorrows[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 0; } /* Calculate new borrow balance using the interest index: * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex */ uint principalTimesIndex = borrowSnapshot.principal * borrowIndex; return principalTimesIndex / borrowSnapshot.interestIndex; } /** * @notice Accrue interest then return the up-to-date exchange rate * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateCurrent() override public nonReentrant returns (uint) { accrueInterest(); return exchangeRateStored(); } /** * @notice Calculates the exchange rate from the underlying to the CToken * @dev This function does not accrue interest before calculating the exchange rate * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateStored() override public view returns (uint) { return exchangeRateStoredInternal(); } /** * @notice Calculates the exchange rate from the underlying to the CToken * @dev This function does not accrue interest before calculating the exchange rate * @return calculated exchange rate scaled by 1e18 */ function exchangeRateStoredInternal() virtual internal view returns (uint) { uint _totalSupply = totalSupply; if (_totalSupply == 0) { /* * If there are no tokens minted: * exchangeRate = initialExchangeRate */ return initialExchangeRateMantissa; } else { /* * Otherwise: * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint totalCash = getCashPrior(); uint cashPlusBorrowsMinusReserves = totalCash + totalBorrows - totalReserves; uint exchangeRate = cashPlusBorrowsMinusReserves * expScale / _totalSupply; return exchangeRate; } } /** * @notice Get cash balance of this cToken in the underlying asset * @return The quantity of underlying asset owned by this contract */ function getCash() override external view returns (uint) { return getCashPrior(); } /** * @notice Applies accrued interest to total borrows and reserves * @dev This calculates interest accrued from the last checkpointed block * up to the current block and writes new checkpoint to storage. */ function accrueInterest() virtual override public returns (uint) { /* Remember the initial block number */ uint currentBlockNumber = getBlockNumber(); uint accrualBlockNumberPrior = accrualBlockNumber; /* Short-circuit accumulating 0 interest */ if (accrualBlockNumberPrior == currentBlockNumber) { return NO_ERROR; } /* Read the previous values out of storage */ uint cashPrior = getCashPrior(); uint borrowsPrior = totalBorrows; uint reservesPrior = totalReserves; uint borrowIndexPrior = borrowIndex; /* Calculate the current borrow interest rate */ uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior); require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high"); /* Calculate the number of blocks elapsed since the last accrual */ uint blockDelta = currentBlockNumber - accrualBlockNumberPrior; /* * 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 = mul_(Exp({mantissa: borrowRateMantissa}), blockDelta); uint interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior); uint totalBorrowsNew = interestAccumulated + borrowsPrior; uint totalReservesNew = mul_ScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior); uint borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We write the previously calculated values into storage */ accrualBlockNumber = currentBlockNumber; borrowIndex = borrowIndexNew; totalBorrows = totalBorrowsNew; totalReserves = totalReservesNew; /* We emit an AccrueInterest event */ emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew); return NO_ERROR; } /** * @notice Sender supplies assets into the market and receives cTokens in exchange * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param mintAmount The amount of the underlying asset to supply */ function mintInternal(uint mintAmount) internal nonReentrant { accrueInterest(); // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to mintFresh(msg.sender, mintAmount); } /** * @notice User supplies assets into the market and receives cTokens in exchange * @dev Assumes interest has already been accrued up to the current block * @param minter The address of the account which is supplying the assets * @param mintAmount The amount of the underlying asset to supply */ function mintFresh(address minter, uint mintAmount) internal { /* Fail if mint not allowed */ uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount); if (allowed != 0) { revert MintComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert MintFreshnessCheck(); } Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()}); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call `doTransferIn` for the minter and the mintAmount. * Note: The cToken must handle variations between ERC-20 and ETH underlying. * `doTransferIn` reverts if anything goes wrong, since we can't be sure if * side-effects occurred. The function returns the amount actually transferred, * in case of a fee. On success, the cToken holds an additional `actualMintAmount` * of cash. */ uint actualMintAmount = doTransferIn(minter, mintAmount); /* * We get the current exchange rate and calculate the number of cTokens to be minted: * mintTokens = actualMintAmount / exchangeRate */ uint mintTokens = div_(actualMintAmount, exchangeRate); /* * We calculate the new total supply of cTokens and minter token balance, checking for overflow: * totalSupplyNew = totalSupply + mintTokens * accountTokensNew = accountTokens[minter] + mintTokens * And write them into storage */ totalSupply = totalSupply + mintTokens; accountTokens[minter] = accountTokens[minter] + mintTokens; /* We emit a Mint event, and a Transfer event */ emit Mint(minter, actualMintAmount, mintTokens); emit Transfer(address(this), minter, mintTokens); /* We call the defense hook */ // unused function // comptroller.mintVerify(address(this), minter, actualMintAmount, mintTokens); } /** * @notice Sender redeems cTokens in exchange for the underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemTokens The number of cTokens to redeem into underlying */ function redeemInternal(uint redeemTokens) internal nonReentrant { accrueInterest(); // redeemFresh emits redeem-specific logs on errors, so we don't need to redeemFresh(payable(msg.sender), redeemTokens, 0); } /** * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemAmount The amount of underlying to receive from redeeming cTokens */ function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant { accrueInterest(); // redeemFresh emits redeem-specific logs on errors, so we don't need to redeemFresh(payable(msg.sender), 0, redeemAmount); } /** * @notice User redeems cTokens in exchange for the underlying asset * @dev Assumes interest has already been accrued up to the current block * @param redeemer The address of the account which is redeeming the tokens * @param redeemTokensIn The number of cTokens 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 cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero) */ function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal { require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero"); /* exchangeRate = invoke Exchange Rate Stored() */ Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal() }); uint redeemTokens; uint redeemAmount; /* 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 */ redeemTokens = redeemTokensIn; redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokensIn); } else { /* * We get the current exchange rate and calculate the amount to be redeemed: * redeemTokens = redeemAmountIn / exchangeRate * redeemAmount = redeemAmountIn */ redeemTokens = div_(redeemAmountIn, exchangeRate); redeemAmount = redeemAmountIn; } /* Fail if redeem not allowed */ uint allowed = comptroller.redeemAllowed(address(this), redeemer, redeemTokens); if (allowed != 0) { revert RedeemComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert RedeemFreshnessCheck(); } /* Fail gracefully if protocol has insufficient cash */ if (getCashPrior() < redeemAmount) { revert RedeemTransferOutNotPossible(); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We write the previously calculated values into storage. * Note: Avoid token reentrancy attacks by writing reduced supply before external transfer. */ totalSupply = totalSupply - redeemTokens; accountTokens[redeemer] = accountTokens[redeemer] - redeemTokens; /* * We invoke doTransferOut for the redeemer and the redeemAmount. * Note: The cToken must handle variations between ERC-20 and ETH underlying. * On success, the cToken has redeemAmount less of cash. * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ doTransferOut(redeemer, redeemAmount); /* We emit a Transfer event, and a Redeem event */ emit Transfer(redeemer, address(this), redeemTokens); emit Redeem(redeemer, redeemAmount, redeemTokens); /* We call the defense hook */ comptroller.redeemVerify(address(this), redeemer, redeemAmount, redeemTokens); } /** * @notice Sender borrows assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow */ function borrowInternal(uint borrowAmount) internal nonReentrant { accrueInterest(); // borrowFresh emits borrow-specific logs on errors, so we don't need to borrowFresh(payable(msg.sender), borrowAmount); } /** * @notice Users borrow assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow */ function borrowFresh(address payable borrower, uint borrowAmount) internal { /* Fail if borrow not allowed */ uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount); if (allowed != 0) { revert BorrowComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert BorrowFreshnessCheck(); } /* Fail gracefully if protocol has insufficient underlying cash */ if (getCashPrior() < borrowAmount) { revert BorrowCashNotAvailable(); } /* * We calculate the new borrower and total borrow balances, failing on overflow: * accountBorrowNew = accountBorrow + borrowAmount * totalBorrowsNew = totalBorrows + borrowAmount */ uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower); uint accountBorrowsNew = accountBorrowsPrev + borrowAmount; uint totalBorrowsNew = totalBorrows + borrowAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We write the previously calculated values into storage. * Note: Avoid token reentrancy attacks by writing increased borrow before external transfer. `*/ accountBorrows[borrower].principal = accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = totalBorrowsNew; /* * We invoke doTransferOut for the borrower and the borrowAmount. * Note: The cToken must handle variations between ERC-20 and ETH underlying. * On success, the cToken borrowAmount less of cash. * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ doTransferOut(borrower, borrowAmount); /* We emit a Borrow event */ emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew); } /** * @notice Sender repays their own borrow * @param repayAmount The amount to repay, or -1 for the full outstanding amount */ function repayBorrowInternal(uint repayAmount) internal nonReentrant { accrueInterest(); // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to repayBorrowFresh(msg.sender, msg.sender, repayAmount); } /** * @notice Sender repays a borrow belonging to borrower * @param borrower the account with the debt being payed off * @param repayAmount The amount to repay, or -1 for the full outstanding amount */ function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant { accrueInterest(); // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to repayBorrowFresh(msg.sender, borrower, repayAmount); } /** * @notice Borrows are repaid by another user (possibly the borrower). * @param payer the account paying off the borrow * @param borrower the account with the debt being payed off * @param repayAmount the amount of underlying tokens being returned, or -1 for the full outstanding amount * @return (uint) the actual repayment amount. */ function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint) { /* Fail if repayBorrow not allowed */ uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount); if (allowed != 0) { revert RepayBorrowComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert RepayBorrowFreshnessCheck(); } /* We fetch the amount the borrower owes, with accumulated interest */ uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower); /* If repayAmount == -1, repayAmount = accountBorrows */ uint repayAmountFinal = repayAmount == type(uint).max ? accountBorrowsPrev : repayAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call doTransferIn for the payer and the repayAmount * Note: The cToken must handle variations between ERC-20 and ETH underlying. * On success, the cToken holds an additional repayAmount of cash. * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred. * it returns the amount actually transferred, in case of a fee. */ uint actualRepayAmount = doTransferIn(payer, repayAmountFinal); /* * We calculate the new borrower and total borrow balances, failing on underflow: * accountBorrowsNew = accountBorrows - actualRepayAmount * totalBorrowsNew = totalBorrows - actualRepayAmount */ uint accountBorrowsNew = accountBorrowsPrev - actualRepayAmount; uint totalBorrowsNew = totalBorrows - actualRepayAmount; /* We write the previously calculated values into storage */ accountBorrows[borrower].principal = accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = totalBorrowsNew; /* We emit a RepayBorrow event */ emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew); return actualRepayAmount; } /** * @notice The sender liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @param borrower The borrower of this cToken to be liquidated * @param cTokenCollateral The market in which to seize collateral from the borrower * @param repayAmount The amount of the underlying borrowed asset to repay */ function liquidateBorrowInternal(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal nonReentrant { accrueInterest(); uint error = cTokenCollateral.accrueInterest(); if (error != NO_ERROR) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed revert LiquidateAccrueCollateralInterestFailed(error); } // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral); } /** * @notice The liquidator liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @param borrower The borrower of this cToken to be liquidated * @param liquidator The address repaying the borrow and seizing collateral * @param cTokenCollateral The market in which to seize collateral from the borrower * @param repayAmount The amount of the underlying borrowed asset to repay */ function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal { /* Fail if liquidate not allowed */ uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount); if (allowed != 0) { revert LiquidateComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert LiquidateFreshnessCheck(); } /* Verify cTokenCollateral market's block number equals current block number */ if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { revert LiquidateCollateralFreshnessCheck(); } /* Fail if borrower = liquidator */ if (borrower == liquidator) { revert LiquidateLiquidatorIsBorrower(); } /* Fail if repayAmount = 0 */ if (repayAmount == 0) { revert LiquidateCloseAmountIsZero(); } /* Fail if repayAmount = -1 */ if (repayAmount == type(uint).max) { revert LiquidateCloseAmountIsUintMax(); } /* Fail if repayBorrow fails */ uint actualRepayAmount = repayBorrowFresh(liquidator, borrower, repayAmount); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We calculate the number of collateral tokens that will be seized */ (uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(cTokenCollateral), actualRepayAmount); require(amountSeizeError == NO_ERROR, "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED"); /* Revert if borrower collateral token balance < seizeTokens */ require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "LIQUIDATE_SEIZE_TOO_MUCH"); // If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call if (address(cTokenCollateral) == address(this)) { seizeInternal(address(this), liquidator, borrower, seizeTokens); } else { require(cTokenCollateral.seize(liquidator, borrower, seizeTokens) == NO_ERROR, "token seizure failed"); } /* We emit a LiquidateBorrow event */ emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens); } /** * @notice Transfers collateral tokens (this market) to the liquidator. * @dev Will fail unless called by another cToken during the process of liquidation. * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. * @param liquidator The account receiving seized collateral * @param borrower The account having collateral seized * @param seizeTokens The number of cTokens to seize * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function seize(address liquidator, address borrower, uint seizeTokens) override external nonReentrant returns (uint) { seizeInternal(msg.sender, liquidator, borrower, seizeTokens); return NO_ERROR; } /** * @notice Transfers collateral tokens (this market) to the liquidator. * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) * @param liquidator The account receiving seized collateral * @param borrower The account having collateral seized * @param seizeTokens The number of cTokens to seize */ function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal { /* Fail if seize not allowed */ uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens); if (allowed != 0) { revert LiquidateSeizeComptrollerRejection(allowed); } /* Fail if borrower = liquidator */ if (borrower == liquidator) { revert LiquidateSeizeLiquidatorIsBorrower(); } /* * We calculate the new borrower and liquidator token balances, failing on underflow/overflow: * borrowerTokensNew = accountTokens[borrower] - seizeTokens * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens */ uint protocolSeizeTokens = mul_(seizeTokens, Exp({mantissa: protocolSeizeShareMantissa})); uint liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens; Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()}); uint protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens); uint totalReservesNew = totalReserves + protocolSeizeAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We write the calculated values into storage */ totalReserves = totalReservesNew; totalSupply = totalSupply - protocolSeizeTokens; accountTokens[borrower] = accountTokens[borrower] - seizeTokens; accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens; /* Emit a Transfer event */ emit Transfer(borrower, liquidator, liquidatorSeizeTokens); emit Transfer(borrower, address(this), protocolSeizeTokens); emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew); } /*** Admin Functions ***/ /** * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setPendingAdmin(address payable newPendingAdmin) override external returns (uint) { // Check caller = admin if (msg.sender != admin) { revert SetPendingAdminOwnerCheck(); } // Save current value, if any, for inclusion in log address oldPendingAdmin = pendingAdmin; // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); return NO_ERROR; } /** * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin * @dev Admin function for pending admin to accept role and update admin * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _acceptAdmin() override external returns (uint) { // Check caller is pendingAdmin and pendingAdmin ≠ address(0) if (msg.sender != pendingAdmin || msg.sender == address(0)) { revert AcceptAdminPendingAdminCheck(); } // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = payable(address(0)); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); return NO_ERROR; } /** * @notice Sets a new comptroller for the market * @dev Admin function to set a new comptroller * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setComptroller(ComptrollerInterface newComptroller) override public returns (uint) { // Check caller is admin if (msg.sender != admin) { revert SetComptrollerOwnerCheck(); } ComptrollerInterface oldComptroller = comptroller; // Ensure invoke comptroller.isComptroller() returns true require(newComptroller.isComptroller(), "marker method returned false"); // Set market's comptroller to newComptroller comptroller = newComptroller; // Emit NewComptroller(oldComptroller, newComptroller) emit NewComptroller(oldComptroller, newComptroller); return NO_ERROR; } /** * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh * @dev Admin function to accrue interest and set a new reserve factor * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setReserveFactor(uint newReserveFactorMantissa) override external nonReentrant returns (uint) { accrueInterest(); // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to. return _setReserveFactorFresh(newReserveFactorMantissa); } /** * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) * @dev Admin function to set a new reserve factor * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) { // Check caller is admin if (msg.sender != admin) { revert SetReserveFactorAdminCheck(); } // Verify market's block number equals current block number if (accrualBlockNumber != getBlockNumber()) { revert SetReserveFactorFreshCheck(); } // Check newReserveFactor ≤ maxReserveFactor if (newReserveFactorMantissa > reserveFactorMaxMantissa) { revert SetReserveFactorBoundsCheck(); } uint oldReserveFactorMantissa = reserveFactorMantissa; reserveFactorMantissa = newReserveFactorMantissa; emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa); return NO_ERROR; } /** * @notice Accrues interest and reduces reserves by transferring from msg.sender * @param addAmount Amount of addition to reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _addReservesInternal(uint addAmount) internal nonReentrant returns (uint) { accrueInterest(); // _addReservesFresh emits reserve-addition-specific logs on errors, so we don't need to. _addReservesFresh(addAmount); return NO_ERROR; } /** * @notice Add reserves by transferring from caller * @dev Requires fresh interest accrual * @param addAmount Amount of addition to reserves * @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees */ function _addReservesFresh(uint addAmount) internal returns (uint, uint) { // totalReserves + actualAddAmount uint totalReservesNew; uint actualAddAmount; // We fail gracefully unless market's block number equals current block number if (accrualBlockNumber != getBlockNumber()) { revert AddReservesFactorFreshCheck(actualAddAmount); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call doTransferIn for the caller and the addAmount * Note: The cToken must handle variations between ERC-20 and ETH underlying. * On success, the cToken holds an additional addAmount of cash. * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred. * it returns the amount actually transferred, in case of a fee. */ actualAddAmount = doTransferIn(msg.sender, addAmount); totalReservesNew = totalReserves + actualAddAmount; // Store reserves[n+1] = reserves[n] + actualAddAmount totalReserves = totalReservesNew; /* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */ emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); /* Return (NO_ERROR, actualAddAmount) */ return (NO_ERROR, actualAddAmount); } /** * @notice Accrues interest and reduces reserves by transferring to admin * @param reduceAmount Amount of reduction to reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _reduceReserves(uint reduceAmount) override external nonReentrant returns (uint) { accrueInterest(); // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to. return _reduceReservesFresh(reduceAmount); } /** * @notice Reduces reserves by transferring to admin * @dev Requires fresh interest accrual * @param reduceAmount Amount of reduction to reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _reduceReservesFresh(uint reduceAmount) internal returns (uint) { // totalReserves - reduceAmount uint totalReservesNew; // Check caller is admin if (msg.sender != admin) { revert ReduceReservesAdminCheck(); } // We fail gracefully unless market's block number equals current block number if (accrualBlockNumber != getBlockNumber()) { revert ReduceReservesFreshCheck(); } // Fail gracefully if protocol has insufficient underlying cash if (getCashPrior() < reduceAmount) { revert ReduceReservesCashNotAvailable(); } // Check reduceAmount ≤ reserves[n] (totalReserves) if (reduceAmount > totalReserves) { revert ReduceReservesCashValidation(); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) totalReservesNew = totalReserves - reduceAmount; // Store reserves[n+1] = reserves[n] - reduceAmount totalReserves = totalReservesNew; // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. doTransferOut(admin, reduceAmount); emit ReservesReduced(admin, reduceAmount, totalReservesNew); return NO_ERROR; } /** * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh * @dev Admin function to accrue interest and update the 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) override public returns (uint) { accrueInterest(); // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to. return _setInterestRateModelFresh(newInterestRateModel); } /** * @notice updates the interest rate model (*requires fresh interest accrual) * @dev Admin function to update the 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 _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) { // Used to store old model for use in the event that is emitted on success InterestRateModel oldInterestRateModel; // Check caller is admin if (msg.sender != admin) { revert SetInterestRateModelOwnerCheck(); } // We fail gracefully unless market's block number equals current block number if (accrualBlockNumber != getBlockNumber()) { revert SetInterestRateModelFreshCheck(); } // Track the market's current interest rate model oldInterestRateModel = interestRateModel; // Ensure invoke newInterestRateModel.isInterestRateModel() returns true require(newInterestRateModel.isInterestRateModel(), "marker method returned false"); // Set the interest rate model to newInterestRateModel interestRateModel = newInterestRateModel; // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel) emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel); return NO_ERROR; } /*** Safe Token ***/ /** * @notice Gets balance of this contract in terms of the underlying * @dev This excludes the value of the current message, if any * @return The quantity of underlying owned by this contract */ function getCashPrior() virtual internal view returns (uint); /** * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. * This may revert due to insufficient balance or insufficient allowance. */ function doTransferIn(address from, uint amount) virtual internal returns (uint); /** * @dev Performs a transfer out, ideally returning an explanatory error code upon failure rather than reverting. * 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. */ function doTransferOut(address payable to, uint amount) virtual internal; /*** 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 } } abstract contract PriceOracle { /// @notice Indicator that this is a PriceOracle contract (for inspection) bool public constant isPriceOracle = true; /** * @notice Get the underlying price of a cToken asset * @param cToken The cToken to get the underlying price of * @return The underlying asset price mantissa (scaled by 1e18). * Zero means the price is unavailable. */ function getUnderlyingPrice(CToken cToken) virtual external view returns (uint); } contract UnitrollerAdminStorage { /** * @notice Administrator for this contract */ address public admin; /** * @notice Pending administrator for this contract */ address public pendingAdmin; /** * @notice Active brains of Unitroller */ address public comptrollerImplementation; /** * @notice Pending brains of Unitroller */ address public pendingComptrollerImplementation; } contract ComptrollerV1Storage is UnitrollerAdminStorage { /** * @notice Oracle which gives the price of any given asset */ PriceOracle public oracle; /** * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow */ uint public closeFactorMantissa; /** * @notice Multiplier representing the discount on collateral that a liquidator receives */ uint public liquidationIncentiveMantissa; /** * @notice Max number of assets a single account can participate in (borrow or use as collateral) */ uint public maxAssets; /** * @notice Per-account mapping of "assets you are in", capped by maxAssets */ mapping(address => CToken[]) public accountAssets; } contract ComptrollerV2Storage is ComptrollerV1Storage { struct Market { // Whether or not this market is listed bool isListed; // Multiplier representing the most one can borrow against their collateral in this market. // For instance, 0.9 to allow borrowing 90% of collateral value. // Must be between 0 and 1, and stored as a mantissa. uint collateralFactorMantissa; // Per-market mapping of "accounts in this asset" mapping(address => bool) accountMembership; // Whether or not this market receives COMP bool isComped; } /** * @notice Official mapping of cTokens -> Market metadata * @dev Used e.g. to determine if a market is supported */ mapping(address => Market) public markets; /** * @notice The Pause Guardian can pause certain actions as a safety mechanism. * Actions which allow users to remove their own assets cannot be paused. * Liquidation / seizing / transfer can only be paused globally, not by market. */ address public pauseGuardian; bool public _mintGuardianPaused; bool public _borrowGuardianPaused; bool public transferGuardianPaused; bool public seizeGuardianPaused; mapping(address => bool) public mintGuardianPaused; mapping(address => bool) public borrowGuardianPaused; } contract ComptrollerV3Storage is ComptrollerV2Storage { struct CompMarketState { // The market's last updated compBorrowIndex or compSupplyIndex uint224 index; // The block number the index was last updated at uint32 block; } /// @notice A list of all markets CToken[] public allMarkets; /// @notice The rate at which the flywheel distributes COMP, per block uint public compRate; /// @notice The portion of compRate that each market currently receives mapping(address => uint) public compSpeeds; /// @notice The COMP market supply state for each market mapping(address => CompMarketState) public compSupplyState; /// @notice The COMP market borrow state for each market mapping(address => CompMarketState) public compBorrowState; /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP mapping(address => mapping(address => uint)) public compSupplierIndex; /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP mapping(address => mapping(address => uint)) public compBorrowerIndex; /// @notice The COMP accrued but not yet transferred to each user mapping(address => uint) public compAccrued; } contract ComptrollerV4Storage is ComptrollerV3Storage { // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. address public borrowCapGuardian; // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. mapping(address => uint) public borrowCaps; } contract ComptrollerV5Storage is ComptrollerV4Storage { /// @notice The portion of COMP that each contributor receives per block mapping(address => uint) public compContributorSpeeds; /// @notice Last block at which a contributor's COMP rewards have been allocated mapping(address => uint) public lastContributorBlock; } contract ComptrollerV6Storage is ComptrollerV5Storage { /// @notice The rate at which comp is distributed to the corresponding borrow market (per block) mapping(address => uint) public compBorrowSpeeds; /// @notice The rate at which comp is distributed to the corresponding supply market (per block) mapping(address => uint) public compSupplySpeeds; } contract ComptrollerV7Storage is ComptrollerV6Storage { /// @notice Flag indicating whether the function to fix COMP accruals has been executed (RE: proposal 62 bug) bool public proposal65FixExecuted; /// @notice Accounting storage mapping account addresses to how much COMP they owe the protocol. mapping(address => uint) public compReceivable; } contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { /** * @notice Emitted when pendingComptrollerImplementation is changed */ event NewPendingImplementation(address oldPendingImplementation, address newPendingImplementation); /** * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated */ event NewImplementation(address oldImplementation, address newImplementation); /** * @notice Emitted when pendingAdmin is changed */ event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); /** * @notice Emitted when pendingAdmin is accepted, which means admin is updated */ event NewAdmin(address oldAdmin, address newAdmin); constructor() public { // Set admin to caller admin = msg.sender; } /*** Admin Functions ***/ function _setPendingImplementation(address newPendingImplementation) public returns (uint) { if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK); } address oldPendingImplementation = pendingComptrollerImplementation; pendingComptrollerImplementation = newPendingImplementation; emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation); return uint(Error.NO_ERROR); } /** * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation * @dev Admin function for new implementation to accept it's role as implementation * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _acceptImplementation() public returns (uint) { // Check caller is pendingImplementation and pendingImplementation ≠ address(0) if (msg.sender != pendingComptrollerImplementation || pendingComptrollerImplementation == address(0)) { return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK); } // Save current values for inclusion in log address oldImplementation = comptrollerImplementation; address oldPendingImplementation = pendingComptrollerImplementation; comptrollerImplementation = pendingComptrollerImplementation; pendingComptrollerImplementation = address(0); emit NewImplementation(oldImplementation, comptrollerImplementation); emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation); return uint(Error.NO_ERROR); } /** * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setPendingAdmin(address newPendingAdmin) public returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK); } // Save current value, if any, for inclusion in log address oldPendingAdmin = pendingAdmin; // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); return uint(Error.NO_ERROR); } /** * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin * @dev Admin function for pending admin to accept role and update admin * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _acceptAdmin() public returns (uint) { // Check caller is pendingAdmin and pendingAdmin ≠ address(0) if (msg.sender != pendingAdmin || msg.sender == address(0)) { return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK); } // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = address(0); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); return uint(Error.NO_ERROR); } /** * @dev Delegates execution to an implementation contract. * It returns to the external caller whatever the implementation returns * or forwards reverts. */ fallback() payable external { // delegate all other functions to current implementation (bool success, ) = comptrollerImplementation.delegatecall(msg.data); assembly { let free_mem_ptr := mload(0x40) returndatacopy(free_mem_ptr, 0, returndatasize()) switch success case 0 { revert(free_mem_ptr, returndatasize()) } default { return(free_mem_ptr, returndatasize()) } } } } contract Comp { /// @notice EIP-20 token name for this token string public constant name = "Compound"; /// @notice EIP-20 token symbol for this token string public constant symbol = "COMP"; /// @notice EIP-20 token decimals for this token uint8 public constant decimals = 18; /// @notice Total number of tokens in circulation uint public constant totalSupply = 10000000e18; // 10 million Comp /// @notice Allowance amounts on behalf of others mapping (address => mapping (address => uint96)) internal allowances; /// @notice Official record of token balances for each account mapping (address => uint96) internal balances; /// @notice A record of each accounts delegate mapping (address => address) public delegates; /// @notice A checkpoint for marking number of votes from a given block struct Checkpoint { uint32 fromBlock; uint96 votes; } /// @notice A record of votes checkpoints for each account, by index mapping (address => mapping (uint32 => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping (address => uint32) public numCheckpoints; /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); /// @notice A record of states for signing / validating signatures mapping (address => uint) public nonces; /// @notice An event thats emitted when an account changes its delegate event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /// @notice An event thats emitted when a delegate account's vote balance changes event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance); /// @notice The standard EIP-20 transfer event event Transfer(address indexed from, address indexed to, uint256 amount); /// @notice The standard EIP-20 approval event event Approval(address indexed owner, address indexed spender, uint256 amount); /** * @notice Construct a new Comp token * @param account The initial account to grant all the tokens */ constructor(address account) public { balances[account] = uint96(totalSupply); emit Transfer(address(0), account, totalSupply); } /** * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` * @param account The address of the account holding the funds * @param spender The address of the account spending the funds * @return The number of tokens approved */ function allowance(address account, address spender) external view returns (uint) { return allowances[account][spender]; } /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint rawAmount) external returns (bool) { uint96 amount; if (rawAmount == type(uint).max) { amount = type(uint96).max; } else { amount = safe96(rawAmount, "Comp::approve: amount exceeds 96 bits"); } allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } /** * @notice Get the number of tokens held by the `account` * @param account The address of the account to get the balance of * @return The number of tokens held */ function balanceOf(address account) external view returns (uint) { return balances[account]; } /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer(address dst, uint rawAmount) external returns (bool) { uint96 amount = safe96(rawAmount, "Comp::transfer: amount exceeds 96 bits"); _transferTokens(msg.sender, dst, amount); return true; } /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom(address src, address dst, uint rawAmount) external returns (bool) { address spender = msg.sender; uint96 spenderAllowance = allowances[src][spender]; uint96 amount = safe96(rawAmount, "Comp::approve: amount exceeds 96 bits"); if (spender != src && spenderAllowance != type(uint96).max) { uint96 newAllowance = sub96(spenderAllowance, amount, "Comp::transferFrom: transfer amount exceeds spender allowance"); allowances[src][spender] = newAllowance; emit Approval(src, spender, newAllowance); } _transferTokens(src, dst, amount); return true; } /** * @notice Delegate votes from `msg.sender` to `delegatee` * @param delegatee The address to delegate votes to */ function delegate(address delegatee) public { return _delegate(msg.sender, delegatee); } /** * @notice Delegates votes from signatory to `delegatee` * @param delegatee The address to delegate votes to * @param nonce The contract state required to match the signature * @param expiry The time at which to expire the signature * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public { bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))); bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), "Comp::delegateBySig: invalid signature"); require(nonce == nonces[signatory]++, "Comp::delegateBySig: invalid nonce"); require(block.timestamp <= expiry, "Comp::delegateBySig: signature expired"); return _delegate(signatory, delegatee); } /** * @notice Gets the current votes balance for `account` * @param account The address to get votes balance * @return The number of current votes for `account` */ function getCurrentVotes(address account) external view returns (uint96) { uint32 nCheckpoints = numCheckpoints[account]; return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; } /** * @notice Determine the prior number of votes for an account as of a block number * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. * @param account The address of the account to check * @param blockNumber The block number to get the vote balance at * @return The number of votes the account had as of the given block */ function getPriorVotes(address account, uint blockNumber) public view returns (uint96) { require(blockNumber < block.number, "Comp::getPriorVotes: not yet determined"); uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { return checkpoints[account][nCheckpoints - 1].votes; } // Next check implicit zero balance if (checkpoints[account][0].fromBlock > blockNumber) { return 0; } uint32 lower = 0; uint32 upper = nCheckpoints - 1; while (upper > lower) { uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint memory cp = checkpoints[account][center]; if (cp.fromBlock == blockNumber) { return cp.votes; } else if (cp.fromBlock < blockNumber) { lower = center; } else { upper = center - 1; } } return checkpoints[account][lower].votes; } function _delegate(address delegator, address delegatee) internal { address currentDelegate = delegates[delegator]; uint96 delegatorBalance = balances[delegator]; delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); _moveDelegates(currentDelegate, delegatee, delegatorBalance); } function _transferTokens(address src, address dst, uint96 amount) internal { require(src != address(0), "Comp::_transferTokens: cannot transfer from the zero address"); require(dst != address(0), "Comp::_transferTokens: cannot transfer to the zero address"); balances[src] = sub96(balances[src], amount, "Comp::_transferTokens: transfer amount exceeds balance"); balances[dst] = add96(balances[dst], amount, "Comp::_transferTokens: transfer amount overflows"); emit Transfer(src, dst, amount); _moveDelegates(delegates[src], delegates[dst], amount); } function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal { if (srcRep != dstRep && amount > 0) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0; uint96 srcRepNew = sub96(srcRepOld, amount, "Comp::_moveVotes: vote amount underflows"); _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0; uint96 dstRepNew = add96(dstRepOld, amount, "Comp::_moveVotes: vote amount overflows"); _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); } } } function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal { uint32 blockNumber = safe32(block.number, "Comp::_writeCheckpoint: block number exceeds 32 bits"); if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) { checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; } else { checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes); numCheckpoints[delegatee] = nCheckpoints + 1; } emit DelegateVotesChanged(delegatee, oldVotes, newVotes); } function safe32(uint n, string memory errorMessage) internal pure returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function safe96(uint n, string memory errorMessage) internal pure returns (uint96) { require(n < 2**96, errorMessage); return uint96(n); } function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { uint96 c = a + b; require(c >= a, errorMessage); return c; } function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { require(b <= a, errorMessage); return a - b; } function getChainId() internal view returns (uint) { uint256 chainId; assembly { chainId := chainid() } return chainId; } } contract Comptroller is ComptrollerV7Storage, ComptrollerInterface, ComptrollerErrorReporter, ExponentialNoError { /// @notice Emitted when an admin supports a market event MarketListed(CToken cToken); /// @notice Emitted when an account enters a market event MarketEntered(CToken cToken, address account); /// @notice Emitted when an account exits a market event MarketExited(CToken cToken, address account); /// @notice Emitted when close factor is changed by admin event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa); /// @notice Emitted when a collateral factor is changed by admin event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa); /// @notice Emitted when liquidation incentive is changed by admin event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa); /// @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(CToken cToken, string action, bool pauseState); /// @notice Emitted when a new borrow-side COMP speed is calculated for a market event CompBorrowSpeedUpdated(CToken indexed cToken, uint newSpeed); /// @notice Emitted when a new supply-side COMP speed is calculated for a market event CompSupplySpeedUpdated(CToken indexed cToken, uint newSpeed); /// @notice Emitted when a new COMP speed is set for a contributor event ContributorCompSpeedUpdated(address indexed contributor, uint newSpeed); /// @notice Emitted when COMP is distributed to a supplier event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex); /// @notice Emitted when COMP is distributed to a borrower event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex); /// @notice Emitted when borrow cap for a cToken is changed event NewBorrowCap(CToken indexed cToken, uint newBorrowCap); /// @notice Emitted when borrow cap guardian is changed event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian); /// @notice Emitted when COMP is granted by admin event CompGranted(address recipient, uint amount); /// @notice Emitted when COMP accrued for a user has been manually adjusted. event CompAccruedAdjusted(address indexed user, uint oldCompAccrued, uint newCompAccrued); /// @notice Emitted when COMP receivable for a user has been updated. event CompReceivableUpdated(address indexed user, uint oldCompReceivable, uint newCompReceivable); /// @notice The initial COMP index for a market uint224 public constant compInitialIndex = 1e36; // closeFactorMantissa must be strictly greater than this value uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05 // closeFactorMantissa must not exceed this value uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 // No collateralFactorMantissa may exceed this value uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 constructor() { admin = msg.sender; } /*** Assets You Are In ***/ /** * @notice Returns the assets an account has entered * @param account The address of the account to pull assets for * @return A dynamic list with the assets the account has entered */ function getAssetsIn(address account) external view returns (CToken[] memory) { CToken[] memory assetsIn = accountAssets[account]; return assetsIn; } /** * @notice Returns whether the given account is entered in the given asset * @param account The address of the account to check * @param cToken The cToken to check * @return True if the account is in the asset, otherwise false. */ function checkMembership(address account, CToken cToken) external view returns (bool) { return markets[address(cToken)].accountMembership[account]; } /** * @notice Add assets to be included in account liquidity calculation * @param cTokens The list of addresses of the cToken markets to be enabled * @return Success indicator for whether each corresponding market was entered */ function enterMarkets(address[] memory cTokens) override public returns (uint[] memory) { uint len = cTokens.length; uint[] memory results = new uint[](len); for (uint i = 0; i < len; i++) { CToken cToken = CToken(cTokens[i]); results[i] = uint(addToMarketInternal(cToken, msg.sender)); } return results; } /** * @notice Add the market to the borrower's "assets in" for liquidity calculations * @param cToken The market to enter * @param borrower The address of the account to modify * @return Success indicator for whether the market was entered */ function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) { Market storage marketToJoin = markets[address(cToken)]; if (!marketToJoin.isListed) { // market is not listed, cannot join return Error.MARKET_NOT_LISTED; } if (marketToJoin.accountMembership[borrower] == true) { // already joined return Error.NO_ERROR; } // survived the gauntlet, add to list // NOTE: we store these somewhat redundantly as a significant optimization // this avoids having to iterate through the list for the most common use cases // that is, only when we need to perform liquidity checks // and not whenever we want to check if an account is in a particular market marketToJoin.accountMembership[borrower] = true; accountAssets[borrower].push(cToken); emit MarketEntered(cToken, borrower); return Error.NO_ERROR; } /** * @notice Removes asset from sender's account liquidity calculation * @dev Sender must not have an outstanding borrow balance in the asset, * or be providing necessary collateral for an outstanding borrow. * @param cTokenAddress The address of the asset to be removed * @return Whether or not the account successfully exited the market */ function exitMarket(address cTokenAddress) override external returns (uint) { CToken cToken = CToken(cTokenAddress); /* Get sender tokensHeld and amountOwed underlying from the cToken */ (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender); require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code /* Fail if the sender has a borrow balance */ if (amountOwed != 0) { return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED); } /* Fail if the sender is not permitted to redeem all of their tokens */ uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld); if (allowed != 0) { return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed); } Market storage marketToExit = markets[address(cToken)]; /* Return true if the sender is not already ‘in’ the market */ if (!marketToExit.accountMembership[msg.sender]) { return uint(Error.NO_ERROR); } /* Set cToken account membership to false */ delete marketToExit.accountMembership[msg.sender]; /* Delete cToken from the account’s list of assets */ // load into memory for faster iteration CToken[] memory userAssetList = accountAssets[msg.sender]; uint len = userAssetList.length; uint assetIndex = len; for (uint i = 0; i < len; i++) { if (userAssetList[i] == cToken) { assetIndex = i; break; } } // We *must* have found the asset in the list or our redundant data structure is broken assert(assetIndex < len); // copy last item in list to location of item to be removed, reduce length by 1 CToken[] storage storedList = accountAssets[msg.sender]; storedList[assetIndex] = storedList[storedList.length - 1]; storedList.pop(); emit MarketExited(cToken, msg.sender); return uint(Error.NO_ERROR); } /*** Policy Hooks ***/ /** * @notice Checks if the account should be allowed to mint tokens in the given market * @param cToken The market to verify the mint against * @param minter The account which would get the minted tokens * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function mintAllowed(address cToken, address minter, uint mintAmount) override external returns (uint) { // Pausing is a very serious situation - we revert to sound the alarms require(!mintGuardianPaused[cToken], "mint is paused"); // Shh - currently unused minter; mintAmount; if (!markets[cToken].isListed) { return uint(Error.MARKET_NOT_LISTED); } // Keep the flywheel moving updateCompSupplyIndex(cToken); distributeSupplierComp(cToken, minter); return uint(Error.NO_ERROR); } /** * @notice Validates mint and reverts on rejection. May emit logs. * @param cToken Asset being minted * @param minter The address minting the tokens * @param actualMintAmount The amount of the underlying asset being minted * @param mintTokens The number of tokens being minted */ function mintVerify(address cToken, address minter, uint actualMintAmount, uint mintTokens) override external { // Shh - currently unused cToken; minter; actualMintAmount; mintTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the account should be allowed to redeem tokens in the given market * @param cToken The market to verify the redeem against * @param redeemer The account which would redeem the tokens * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function redeemAllowed(address cToken, address redeemer, uint redeemTokens) override external returns (uint) { uint allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens); if (allowed != uint(Error.NO_ERROR)) { return allowed; } // Keep the flywheel moving updateCompSupplyIndex(cToken); distributeSupplierComp(cToken, redeemer); return uint(Error.NO_ERROR); } function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) { if (!markets[cToken].isListed) { return uint(Error.MARKET_NOT_LISTED); } /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ if (!markets[cToken].accountMembership[redeemer]) { return uint(Error.NO_ERROR); } /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall > 0) { return uint(Error.INSUFFICIENT_LIQUIDITY); } return uint(Error.NO_ERROR); } /** * @notice Validates redeem and reverts on rejection. May emit logs. * @param cToken Asset being redeemed * @param redeemer The address redeeming the tokens * @param redeemAmount The amount of the underlying asset being redeemed * @param redeemTokens The number of tokens being redeemed */ function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) override external { // Shh - currently unused cToken; redeemer; // Require tokens is zero or amount is also zero if (redeemTokens == 0 && redeemAmount > 0) { revert("redeemTokens zero"); } } /** * @notice Checks if the account should be allowed to borrow the underlying asset of the given market * @param cToken The market to verify the borrow against * @param borrower The account which would borrow the asset * @param borrowAmount The amount of underlying the account would borrow * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function borrowAllowed(address cToken, address borrower, uint borrowAmount) override external returns (uint) { // Pausing is a very serious situation - we revert to sound the alarms require(!borrowGuardianPaused[cToken], "borrow is paused"); if (!markets[cToken].isListed) { return uint(Error.MARKET_NOT_LISTED); } if (!markets[cToken].accountMembership[borrower]) { // only cTokens may call borrowAllowed if borrower not in market require(msg.sender == cToken, "sender must be cToken"); // attempt to add borrower to the market Error err = addToMarketInternal(CToken(msg.sender), borrower); if (err != Error.NO_ERROR) { return uint(err); } // it should be impossible to break the important invariant assert(markets[cToken].accountMembership[borrower]); } if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { return uint(Error.PRICE_ERROR); } uint borrowCap = borrowCaps[cToken]; // Borrow cap of 0 corresponds to unlimited borrowing if (borrowCap != 0) { uint totalBorrows = CToken(cToken).totalBorrows(); uint nextTotalBorrows = add_(totalBorrows, borrowAmount); require(nextTotalBorrows < borrowCap, "market borrow cap reached"); } (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall > 0) { return uint(Error.INSUFFICIENT_LIQUIDITY); } // Keep the flywheel moving Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); updateCompBorrowIndex(cToken, borrowIndex); distributeBorrowerComp(cToken, borrower, borrowIndex); return uint(Error.NO_ERROR); } /** * @notice Validates borrow and reverts on rejection. May emit logs. * @param cToken Asset whose underlying is being borrowed * @param borrower The address borrowing the underlying * @param borrowAmount The amount of the underlying asset requested to borrow */ function borrowVerify(address cToken, address borrower, uint borrowAmount) override external { // Shh - currently unused cToken; borrower; borrowAmount; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the account should be allowed to repay a borrow in the given market * @param cToken The market to verify the repay against * @param payer The account which would repay the asset * @param borrower The account which would borrowed the asset * @param repayAmount The amount of the underlying asset the account would repay * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function repayBorrowAllowed( address cToken, address payer, address borrower, uint repayAmount) override external returns (uint) { // Shh - currently unused payer; borrower; repayAmount; if (!markets[cToken].isListed) { return uint(Error.MARKET_NOT_LISTED); } // Keep the flywheel moving Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()}); updateCompBorrowIndex(cToken, borrowIndex); distributeBorrowerComp(cToken, borrower, borrowIndex); return uint(Error.NO_ERROR); } /** * @notice Validates repayBorrow and reverts on rejection. May emit logs. * @param cToken Asset being repaid * @param payer The address repaying the borrow * @param borrower The address of the borrower * @param actualRepayAmount The amount of underlying being repaid */ function repayBorrowVerify( address cToken, address payer, address borrower, uint actualRepayAmount, uint borrowerIndex) override external { // Shh - currently unused cToken; payer; borrower; actualRepayAmount; borrowerIndex; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the liquidation should be allowed to occur * @param cTokenBorrowed Asset which was borrowed by the borrower * @param cTokenCollateral Asset which was used as collateral and will be seized * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param repayAmount The amount of underlying being repaid */ function liquidateBorrowAllowed( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint repayAmount) override external returns (uint) { // Shh - currently unused liquidator; if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) { return uint(Error.MARKET_NOT_LISTED); } uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower); /* allow accounts to be liquidated if the market is deprecated */ if (isDeprecated(CToken(cTokenBorrowed))) { require(borrowBalance >= repayAmount, "Can not repay more than the total borrow"); } else { /* The borrower must have shortfall in order to be liquidatable */ (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall == 0) { return uint(Error.INSUFFICIENT_SHORTFALL); } /* The liquidator may not repay more than what is allowed by the closeFactor */ uint maxClose = mul_ScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance); if (repayAmount > maxClose) { return uint(Error.TOO_MUCH_REPAY); } } return uint(Error.NO_ERROR); } /** * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. * @param cTokenBorrowed Asset which was borrowed by the borrower * @param cTokenCollateral Asset which was used as collateral and will be seized * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param actualRepayAmount The amount of underlying being repaid */ function liquidateBorrowVerify( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint actualRepayAmount, uint seizeTokens) override external { // Shh - currently unused cTokenBorrowed; cTokenCollateral; liquidator; borrower; actualRepayAmount; seizeTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the seizing of assets should be allowed to occur * @param cTokenCollateral Asset which was used as collateral and will be seized * @param cTokenBorrowed Asset which was borrowed by the borrower * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param seizeTokens The number of collateral tokens to seize */ function seizeAllowed( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint seizeTokens) override external returns (uint) { // Pausing is a very serious situation - we revert to sound the alarms require(!seizeGuardianPaused, "seize is paused"); // Shh - currently unused seizeTokens; if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) { return uint(Error.MARKET_NOT_LISTED); } if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) { return uint(Error.COMPTROLLER_MISMATCH); } // Keep the flywheel moving updateCompSupplyIndex(cTokenCollateral); distributeSupplierComp(cTokenCollateral, borrower); distributeSupplierComp(cTokenCollateral, liquidator); return uint(Error.NO_ERROR); } /** * @notice Validates seize and reverts on rejection. May emit logs. * @param cTokenCollateral Asset which was used as collateral and will be seized * @param cTokenBorrowed Asset which was borrowed by the borrower * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param seizeTokens The number of collateral tokens to seize */ function seizeVerify( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint seizeTokens) override external { // Shh - currently unused cTokenCollateral; cTokenBorrowed; liquidator; borrower; seizeTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the account should be allowed to transfer tokens in the given market * @param cToken The market to verify the transfer against * @param src The account which sources the tokens * @param dst The account which receives the tokens * @param transferTokens The number of cTokens to transfer * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function transferAllowed(address cToken, address src, address dst, uint transferTokens) override external returns (uint) { // Pausing is a very serious situation - we revert to sound the alarms require(!transferGuardianPaused, "transfer is paused"); // Currently the only consideration is whether or not // the src is allowed to redeem this many tokens uint allowed = redeemAllowedInternal(cToken, src, transferTokens); if (allowed != uint(Error.NO_ERROR)) { return allowed; } // Keep the flywheel moving updateCompSupplyIndex(cToken); distributeSupplierComp(cToken, src); distributeSupplierComp(cToken, dst); return uint(Error.NO_ERROR); } /** * @notice Validates transfer and reverts on rejection. May emit logs. * @param cToken Asset being transferred * @param src The account which sources the tokens * @param dst The account which receives the tokens * @param transferTokens The number of cTokens to transfer */ function transferVerify(address cToken, address src, address dst, uint transferTokens) override external { // Shh - currently unused cToken; src; dst; transferTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /*** Liquidity/Liquidation Calculations ***/ /** * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. * Note that `cTokenBalance` is the number of cTokens the account owns in the market, * whereas `borrowBalance` is the amount of underlying that the account has borrowed. */ struct AccountLiquidityLocalVars { uint sumCollateral; uint sumBorrowPlusEffects; uint cTokenBalance; uint borrowBalance; uint exchangeRateMantissa; uint oraclePriceMantissa; Exp collateralFactor; Exp exchangeRate; Exp oraclePrice; Exp tokensToDenom; } /** * @notice Determine the current account liquidity wrt collateral requirements * @return (possible error code (semi-opaque), account liquidity in excess of collateral requirements, * account shortfall below collateral requirements) */ function getAccountLiquidity(address account) public view returns (uint, uint, uint) { (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(address(0)), 0, 0); return (uint(err), liquidity, shortfall); } /** * @notice Determine the current account liquidity wrt collateral requirements * @return (possible error code, account liquidity in excess of collateral requirements, * account shortfall below collateral requirements) */ function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) { return getHypotheticalAccountLiquidityInternal(account, CToken(address(0)), 0, 0); } /** * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed * @param cTokenModify The market to hypothetically redeem/borrow in * @param account The account to determine liquidity for * @param redeemTokens The number of tokens to hypothetically redeem * @param borrowAmount The amount of underlying to hypothetically borrow * @return (possible error code (semi-opaque), hypothetical account liquidity in excess of collateral requirements, * hypothetical account shortfall below collateral requirements) */ function getHypotheticalAccountLiquidity( address account, address cTokenModify, uint redeemTokens, uint borrowAmount) public view returns (uint, uint, uint) { (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount); return (uint(err), liquidity, shortfall); } /** * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed * @param cTokenModify The market to hypothetically redeem/borrow in * @param account The account to determine liquidity for * @param redeemTokens The number of tokens to hypothetically redeem * @param borrowAmount The amount of underlying to hypothetically borrow * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, * without calculating accumulated interest. * @return (possible error code, hypothetical account liquidity in excess of collateral requirements, * hypothetical account shortfall below collateral requirements) */ function getHypotheticalAccountLiquidityInternal( address account, CToken cTokenModify, uint redeemTokens, uint borrowAmount) internal view returns (Error, uint, uint) { AccountLiquidityLocalVars memory vars; // Holds all our calculation results uint oErr; // For each asset the account is in CToken[] memory assets = accountAssets[account]; for (uint i = 0; i < assets.length; i++) { CToken asset = assets[i]; // Read the balances and exchange rate from the cToken (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account); if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades return (Error.SNAPSHOT_ERROR, 0, 0); } vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa}); vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); // Get the normalized price of the asset vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); if (vars.oraclePriceMantissa == 0) { return (Error.PRICE_ERROR, 0, 0); } vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); // Pre-compute a conversion factor from tokens -> ether (normalized price value) vars.tokensToDenom = mul_(mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice); // sumCollateral += tokensToDenom * cTokenBalance vars.sumCollateral = mul_ScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral); // sumBorrowPlusEffects += oraclePrice * borrowBalance vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects); // Calculate effects of interacting with cTokenModify if (asset == cTokenModify) { // redeem effect // sumBorrowPlusEffects += tokensToDenom * redeemTokens vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects); // borrow effect // sumBorrowPlusEffects += oraclePrice * borrowAmount vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects); } } // These are safe, as the underflow condition is checked first if (vars.sumCollateral > vars.sumBorrowPlusEffects) { return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0); } else { return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral); } } /** * @notice Calculate number of tokens of collateral asset to seize given an underlying amount * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) * @param cTokenBorrowed The address of the borrowed cToken * @param cTokenCollateral The address of the collateral cToken * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) */ function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount) override external view returns (uint, uint) { /* Read oracle prices for borrowed and collateral markets */ uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed)); uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral)); if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { return (uint(Error.PRICE_ERROR), 0); } /* * Get the exchange rate and calculate the number of collateral tokens to seize: * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral * seizeTokens = seizeAmount / exchangeRate * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) */ uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error uint seizeTokens; Exp memory numerator; Exp memory denominator; Exp memory ratio; numerator = mul_(Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa})); denominator = mul_(Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa})); ratio = div_(numerator, denominator); seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount); return (uint(Error.NO_ERROR), seizeTokens); } /*** Admin Functions ***/ /** * @notice Sets a new price oracle for the comptroller * @dev Admin function to set a new price oracle * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setPriceOracle(PriceOracle newOracle) public returns (uint) { // Check caller is admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK); } // Track the old oracle for the comptroller PriceOracle oldOracle = oracle; // Set comptroller's oracle to newOracle oracle = newOracle; // Emit NewPriceOracle(oldOracle, newOracle) emit NewPriceOracle(oldOracle, newOracle); return uint(Error.NO_ERROR); } /** * @notice Sets the closeFactor used when liquidating borrows * @dev Admin function to set closeFactor * @param newCloseFactorMantissa New close factor, scaled by 1e18 * @return uint 0=success, otherwise a failure */ function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) { // Check caller is admin require(msg.sender == admin, "only admin can set close factor"); uint oldCloseFactorMantissa = closeFactorMantissa; closeFactorMantissa = newCloseFactorMantissa; emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); return uint(Error.NO_ERROR); } /** * @notice Sets the collateralFactor for a market * @dev Admin function to set per-market collateralFactor * @param cToken The market to set the factor on * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) */ function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint) { // Check caller is admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK); } // Verify market is listed Market storage market = markets[address(cToken)]; if (!market.isListed) { return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS); } Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa}); // Check collateral factor <= 0.9 Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); if (lessThanExp(highLimit, newCollateralFactorExp)) { return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION); } // If collateral factor != 0, fail if price == 0 if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) { return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE); } // Set market's collateral factor to new collateral factor, remember old value uint oldCollateralFactorMantissa = market.collateralFactorMantissa; market.collateralFactorMantissa = newCollateralFactorMantissa; // Emit event with asset, old collateral factor, and new collateral factor emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa); return uint(Error.NO_ERROR); } /** * @notice Sets liquidationIncentive * @dev Admin function to set liquidationIncentive * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) */ function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) { // Check caller is admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK); } // Save current value for use in log uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; // Set liquidation incentive to new incentive liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; // Emit event with old incentive, new incentive emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa); return uint(Error.NO_ERROR); } /** * @notice Add the market to the markets mapping and set it as listed * @dev Admin function to set isListed and add support for the market * @param cToken The address of the market (token) to list * @return uint 0=success, otherwise a failure. (See enum Error for details) */ function _supportMarket(CToken cToken) external returns (uint) { if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK); } if (markets[address(cToken)].isListed) { return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS); } cToken.isCToken(); // Sanity check to make sure its really a CToken // Note that isComped is not in active use anymore Market storage newMarket = markets[address(cToken)]; newMarket.isListed = true; newMarket.isComped = false; newMarket.collateralFactorMantissa = 0; _addMarketInternal(address(cToken)); _initializeMarket(address(cToken)); emit MarketListed(cToken); return uint(Error.NO_ERROR); } function _addMarketInternal(address cToken) internal { for (uint i = 0; i < allMarkets.length; i ++) { require(allMarkets[i] != CToken(cToken), "market already added"); } allMarkets.push(CToken(cToken)); } function _initializeMarket(address cToken) internal { uint32 blockNumber = safe32(getBlockNumber(), "block number exceeds 32 bits"); CompMarketState storage supplyState = compSupplyState[cToken]; CompMarketState storage borrowState = compBorrowState[cToken]; /* * Update market state indices */ if (supplyState.index == 0) { // Initialize supply state index with default value supplyState.index = compInitialIndex; } if (borrowState.index == 0) { // Initialize borrow state index with default value borrowState.index = compInitialIndex; } /* * Update market state block numbers */ supplyState.block = borrowState.block = blockNumber; } /** * @notice Set the given borrow caps for the given cToken markets. Borrowing that brings total borrows to or above borrow cap will revert. * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing. * @param cTokens The addresses of the markets (tokens) to change the borrow caps for * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing. */ function _setMarketBorrowCaps(CToken[] calldata cTokens, uint[] calldata newBorrowCaps) external { require(msg.sender == admin || msg.sender == borrowCapGuardian, "only admin or borrow cap guardian can set borrow caps"); uint numMarkets = cTokens.length; uint numBorrowCaps = newBorrowCaps.length; require(numMarkets != 0 && numMarkets == numBorrowCaps, "invalid input"); for(uint i = 0; i < numMarkets; i++) { borrowCaps[address(cTokens[i])] = newBorrowCaps[i]; emit NewBorrowCap(cTokens[i], newBorrowCaps[i]); } } /** * @notice Admin function to change the Borrow Cap Guardian * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian */ function _setBorrowCapGuardian(address newBorrowCapGuardian) external { require(msg.sender == admin, "only admin can set borrow cap guardian"); // Save current value for inclusion in log address oldBorrowCapGuardian = borrowCapGuardian; // Store borrowCapGuardian with value newBorrowCapGuardian borrowCapGuardian = newBorrowCapGuardian; // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian) emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian); } /** * @notice Admin function to change the Pause Guardian * @param newPauseGuardian The address of the new Pause Guardian * @return uint 0=success, otherwise a failure. (See enum Error for details) */ function _setPauseGuardian(address newPauseGuardian) public returns (uint) { if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK); } // Save current value for inclusion in log address oldPauseGuardian = pauseGuardian; // Store pauseGuardian with value newPauseGuardian pauseGuardian = newPauseGuardian; // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); return uint(Error.NO_ERROR); } function _setMintPaused(CToken cToken, bool state) public returns (bool) { require(markets[address(cToken)].isListed, "cannot pause a market that is not listed"); require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause"); require(msg.sender == admin || state == true, "only admin can unpause"); mintGuardianPaused[address(cToken)] = state; emit ActionPaused(cToken, "Mint", state); return state; } function _setBorrowPaused(CToken cToken, bool state) public returns (bool) { require(markets[address(cToken)].isListed, "cannot pause a market that is not listed"); require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause"); require(msg.sender == admin || state == true, "only admin can unpause"); borrowGuardianPaused[address(cToken)] = state; emit ActionPaused(cToken, "Borrow", state); return state; } function _setTransferPaused(bool state) public returns (bool) { require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause"); require(msg.sender == admin || state == true, "only admin can unpause"); transferGuardianPaused = state; emit ActionPaused("Transfer", state); return state; } function _setSeizePaused(bool state) public returns (bool) { require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause"); require(msg.sender == admin || state == true, "only admin can unpause"); seizeGuardianPaused = state; emit ActionPaused("Seize", state); return state; } function _become(Unitroller unitroller) public { require(msg.sender == unitroller.admin(), "only unitroller admin can change brains"); require(unitroller._acceptImplementation() == 0, "change not authorized"); } /// @notice Delete this function after proposal 65 is executed function fixBadAccruals(address[] calldata affectedUsers, uint[] calldata amounts) external { require(msg.sender == admin, "Only admin can call this function"); // Only the timelock can call this function require(!proposal65FixExecuted, "Already executed this one-off function"); // Require that this function is only called once require(affectedUsers.length == amounts.length, "Invalid input"); // Loop variables address user; uint currentAccrual; uint amountToSubtract; uint newAccrual; // Iterate through all affected users for (uint i = 0; i < affectedUsers.length; ++i) { user = affectedUsers[i]; currentAccrual = compAccrued[user]; amountToSubtract = amounts[i]; // The case where the user has claimed and received an incorrect amount of COMP. // The user has less currently accrued than the amount they incorrectly received. if (amountToSubtract > currentAccrual) { // Amount of COMP the user owes the protocol uint accountReceivable = amountToSubtract - currentAccrual; // Underflow safe since amountToSubtract > currentAccrual uint oldReceivable = compReceivable[user]; uint newReceivable = add_(oldReceivable, accountReceivable); // Accounting: record the COMP debt for the user compReceivable[user] = newReceivable; emit CompReceivableUpdated(user, oldReceivable, newReceivable); amountToSubtract = currentAccrual; } if (amountToSubtract > 0) { // Subtract the bad accrual amount from what they have accrued. // Users will keep whatever they have correctly accrued. compAccrued[user] = newAccrual = sub_(currentAccrual, amountToSubtract); emit CompAccruedAdjusted(user, currentAccrual, newAccrual); } } proposal65FixExecuted = true; // Makes it so that this function cannot be called again } /** * @notice Checks caller is admin, or this contract is becoming the new implementation */ function adminOrInitializing() internal view returns (bool) { return msg.sender == admin || msg.sender == comptrollerImplementation; } /*** Comp Distribution ***/ /** * @notice Set COMP speed for a single market * @param cToken The market whose COMP speed to update * @param supplySpeed New supply-side COMP speed for market * @param borrowSpeed New borrow-side COMP speed for market */ function setCompSpeedInternal(CToken cToken, uint supplySpeed, uint borrowSpeed) internal { Market storage market = markets[address(cToken)]; require(market.isListed, "comp market is not listed"); if (compSupplySpeeds[address(cToken)] != supplySpeed) { // Supply speed updated so let's update supply state to ensure that // 1. COMP accrued properly for the old speed, and // 2. COMP accrued at the new speed starts after this block. updateCompSupplyIndex(address(cToken)); // Update speed and emit event compSupplySpeeds[address(cToken)] = supplySpeed; emit CompSupplySpeedUpdated(cToken, supplySpeed); } if (compBorrowSpeeds[address(cToken)] != borrowSpeed) { // Borrow speed updated so let's update borrow state to ensure that // 1. COMP accrued properly for the old speed, and // 2. COMP accrued at the new speed starts after this block. Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); updateCompBorrowIndex(address(cToken), borrowIndex); // Update speed and emit event compBorrowSpeeds[address(cToken)] = borrowSpeed; emit CompBorrowSpeedUpdated(cToken, borrowSpeed); } } /** * @notice Accrue COMP to the market by updating the supply index * @param cToken The market whose supply index to update * @dev Index is a cumulative sum of the COMP per cToken accrued. */ function updateCompSupplyIndex(address cToken) internal { CompMarketState storage supplyState = compSupplyState[cToken]; uint supplySpeed = compSupplySpeeds[cToken]; uint32 blockNumber = safe32(getBlockNumber(), "block number exceeds 32 bits"); uint deltaBlocks = sub_(uint(blockNumber), uint(supplyState.block)); if (deltaBlocks > 0 && supplySpeed > 0) { uint supplyTokens = CToken(cToken).totalSupply(); uint compAccrued = mul_(deltaBlocks, supplySpeed); Double memory ratio = supplyTokens > 0 ? fraction(compAccrued, supplyTokens) : Double({mantissa: 0}); supplyState.index = safe224(add_(Double({mantissa: supplyState.index}), ratio).mantissa, "new index exceeds 224 bits"); supplyState.block = blockNumber; } else if (deltaBlocks > 0) { supplyState.block = blockNumber; } } /** * @notice Accrue COMP to the market by updating the borrow index * @param cToken The market whose borrow index to update * @dev Index is a cumulative sum of the COMP per cToken accrued. */ function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) internal { CompMarketState storage borrowState = compBorrowState[cToken]; uint borrowSpeed = compBorrowSpeeds[cToken]; uint32 blockNumber = safe32(getBlockNumber(), "block number exceeds 32 bits"); uint deltaBlocks = sub_(uint(blockNumber), uint(borrowState.block)); if (deltaBlocks > 0 && borrowSpeed > 0) { uint borrowAmount = div_(CToken(cToken).totalBorrows(), marketBorrowIndex); uint compAccrued = mul_(deltaBlocks, borrowSpeed); Double memory ratio = borrowAmount > 0 ? fraction(compAccrued, borrowAmount) : Double({mantissa: 0}); borrowState.index = safe224(add_(Double({mantissa: borrowState.index}), ratio).mantissa, "new index exceeds 224 bits"); borrowState.block = blockNumber; } else if (deltaBlocks > 0) { borrowState.block = blockNumber; } } /** * @notice Calculate COMP accrued by a supplier and possibly transfer it to them * @param cToken The market in which the supplier is interacting * @param supplier The address of the supplier to distribute COMP to */ function distributeSupplierComp(address cToken, address supplier) internal { // TODO: Don't distribute supplier COMP if the user is not in the supplier market. // This check should be as gas efficient as possible as distributeSupplierComp is called in many places. // - We really don't want to call an external contract as that's quite expensive. CompMarketState storage supplyState = compSupplyState[cToken]; uint supplyIndex = supplyState.index; uint supplierIndex = compSupplierIndex[cToken][supplier]; // Update supplier's index to the current index since we are distributing accrued COMP compSupplierIndex[cToken][supplier] = supplyIndex; if (supplierIndex == 0 && supplyIndex >= compInitialIndex) { // Covers the case where users supplied tokens before the market's supply state index was set. // Rewards the user with COMP accrued from the start of when supplier rewards were first // set for the market. supplierIndex = compInitialIndex; } // Calculate change in the cumulative sum of the COMP per cToken accrued Double memory deltaIndex = Double({mantissa: sub_(supplyIndex, supplierIndex)}); uint supplierTokens = CToken(cToken).balanceOf(supplier); // Calculate COMP accrued: cTokenAmount * accruedPerCToken uint supplierDelta = mul_(supplierTokens, deltaIndex); uint supplierAccrued = add_(compAccrued[supplier], supplierDelta); compAccrued[supplier] = supplierAccrued; emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex); } /** * @notice Calculate COMP accrued by a borrower and possibly transfer it to them * @dev Borrowers will not begin to accrue until after the first interaction with the protocol. * @param cToken The market in which the borrower is interacting * @param borrower The address of the borrower to distribute COMP to */ function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex) internal { // TODO: Don't distribute supplier COMP if the user is not in the borrower market. // This check should be as gas efficient as possible as distributeBorrowerComp is called in many places. // - We really don't want to call an external contract as that's quite expensive. CompMarketState storage borrowState = compBorrowState[cToken]; uint borrowIndex = borrowState.index; uint borrowerIndex = compBorrowerIndex[cToken][borrower]; // Update borrowers's index to the current index since we are distributing accrued COMP compBorrowerIndex[cToken][borrower] = borrowIndex; if (borrowerIndex == 0 && borrowIndex >= compInitialIndex) { // Covers the case where users borrowed tokens before the market's borrow state index was set. // Rewards the user with COMP accrued from the start of when borrower rewards were first // set for the market. borrowerIndex = compInitialIndex; } // Calculate change in the cumulative sum of the COMP per borrowed unit accrued Double memory deltaIndex = Double({mantissa: sub_(borrowIndex, borrowerIndex)}); uint borrowerAmount = div_(CToken(cToken).borrowBalanceStored(borrower), marketBorrowIndex); // Calculate COMP accrued: cTokenAmount * accruedPerBorrowedUnit uint borrowerDelta = mul_(borrowerAmount, deltaIndex); uint borrowerAccrued = add_(compAccrued[borrower], borrowerDelta); compAccrued[borrower] = borrowerAccrued; emit DistributedBorrowerComp(CToken(cToken), borrower, borrowerDelta, borrowIndex); } /** * @notice Calculate additional accrued COMP for a contributor since last accrual * @param contributor The address to calculate contributor rewards for */ function updateContributorRewards(address contributor) public { uint compSpeed = compContributorSpeeds[contributor]; uint blockNumber = getBlockNumber(); uint deltaBlocks = sub_(blockNumber, lastContributorBlock[contributor]); if (deltaBlocks > 0 && compSpeed > 0) { uint newAccrued = mul_(deltaBlocks, compSpeed); uint contributorAccrued = add_(compAccrued[contributor], newAccrued); compAccrued[contributor] = contributorAccrued; lastContributorBlock[contributor] = blockNumber; } } /** * @notice Claim all the comp accrued by holder in all markets * @param holder The address to claim COMP for */ function claimComp(address holder) public { return claimComp(holder, allMarkets); } /** * @notice Claim all the comp accrued by holder in the specified markets * @param holder The address to claim COMP for * @param cTokens The list of markets to claim COMP in */ function claimComp(address holder, CToken[] memory cTokens) public { address[] memory holders = new address[](1); holders[0] = holder; claimComp(holders, cTokens, true, true); } /** * @notice Claim all comp accrued by the holders * @param holders The addresses to claim COMP for * @param cTokens The list of markets to claim COMP in * @param borrowers Whether or not to claim COMP earned by borrowing * @param suppliers Whether or not to claim COMP earned by supplying */ function claimComp(address[] memory holders, CToken[] memory cTokens, bool borrowers, bool suppliers) public { for (uint i = 0; i < cTokens.length; i++) { CToken cToken = cTokens[i]; require(markets[address(cToken)].isListed, "market must be listed"); if (borrowers == true) { Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()}); updateCompBorrowIndex(address(cToken), borrowIndex); for (uint j = 0; j < holders.length; j++) { distributeBorrowerComp(address(cToken), holders[j], borrowIndex); } } if (suppliers == true) { updateCompSupplyIndex(address(cToken)); for (uint j = 0; j < holders.length; j++) { distributeSupplierComp(address(cToken), holders[j]); } } } for (uint j = 0; j < holders.length; j++) { compAccrued[holders[j]] = grantCompInternal(holders[j], compAccrued[holders[j]]); } } /** * @notice Transfer COMP to the user * @dev Note: If there is not enough COMP, we do not perform the transfer all. * @param user The address of the user to transfer COMP to * @param amount The amount of COMP to (possibly) transfer * @return The amount of COMP which was NOT transferred to the user */ function grantCompInternal(address user, uint amount) internal returns (uint) { Comp comp = Comp(getCompAddress()); uint compRemaining = comp.balanceOf(address(this)); if (amount > 0 && amount <= compRemaining) { comp.transfer(user, amount); return 0; } return amount; } /*** Comp Distribution Admin ***/ /** * @notice Transfer COMP to the recipient * @dev Note: If there is not enough COMP, we do not perform the transfer all. * @param recipient The address of the recipient to transfer COMP to * @param amount The amount of COMP to (possibly) transfer */ function _grantComp(address recipient, uint amount) public { require(adminOrInitializing(), "only admin can grant comp"); uint amountLeft = grantCompInternal(recipient, amount); require(amountLeft == 0, "insufficient comp for grant"); emit CompGranted(recipient, amount); } /** * @notice Set COMP borrow and supply speeds for the specified markets. * @param cTokens The markets whose COMP speed to update. * @param supplySpeeds New supply-side COMP speed for the corresponding market. * @param borrowSpeeds New borrow-side COMP speed for the corresponding market. */ function _setCompSpeeds(CToken[] memory cTokens, uint[] memory supplySpeeds, uint[] memory borrowSpeeds) public { require(adminOrInitializing(), "only admin can set comp speed"); uint numTokens = cTokens.length; require(numTokens == supplySpeeds.length && numTokens == borrowSpeeds.length, "Comptroller::_setCompSpeeds invalid input"); for (uint i = 0; i < numTokens; ++i) { setCompSpeedInternal(cTokens[i], supplySpeeds[i], borrowSpeeds[i]); } } /** * @notice Set COMP speed for a single contributor * @param contributor The contributor whose COMP speed to update * @param compSpeed New COMP speed for contributor */ function _setContributorCompSpeed(address contributor, uint compSpeed) public { require(adminOrInitializing(), "only admin can set comp speed"); // note that COMP speed could be set to 0 to halt liquidity rewards for a contributor updateContributorRewards(contributor); if (compSpeed == 0) { // release storage delete lastContributorBlock[contributor]; } else { lastContributorBlock[contributor] = getBlockNumber(); } compContributorSpeeds[contributor] = compSpeed; emit ContributorCompSpeedUpdated(contributor, compSpeed); } /** * @notice Return all of the markets * @dev The automatic getter may be used to access an individual market. * @return The list of market addresses */ function getAllMarkets() public view returns (CToken[] memory) { return allMarkets; } /** * @notice Returns true if the given cToken market has been deprecated * @dev All borrows in a deprecated cToken market can be immediately liquidated * @param cToken The market to check if deprecated */ function isDeprecated(CToken cToken) public view returns (bool) { return markets[address(cToken)].collateralFactorMantissa == 0 && borrowGuardianPaused[address(cToken)] == true && cToken.reserveFactorMantissa() == 1e18 ; } function getBlockNumber() virtual public view returns (uint) { return block.number; } /** * @notice Return the address of the COMP token * @return The address of COMP */ function getCompAddress() virtual public view returns (address) { return 0xd7878b71eAc29080559491D16419Ca97cfcFfD3a; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCompAccrued","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCompAccrued","type":"uint256"}],"name":"CompAccruedAdjusted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"CompBorrowSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CompGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCompReceivable","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCompReceivable","type":"uint256"}],"name":"CompReceivableUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"CompSupplySpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"ContributorCompSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"compDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"compBorrowIndex","type":"uint256"}],"name":"DistributedBorrowerComp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":true,"internalType":"address","name":"supplier","type":"address"},{"indexed":false,"internalType":"uint256","name":"compDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"compSupplyIndex","type":"uint256"}],"name":"DistributedSupplierComp","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":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"MarketListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newBorrowCap","type":"uint256"}],"name":"NewBorrowCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldBorrowCapGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"NewBorrowCapGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCloseFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"NewCloseFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CToken","name":"cToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCollateralFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"NewCollateralFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidationIncentiveMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"NewLiquidationIncentive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPauseGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"NewPauseGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract PriceOracle","name":"oldPriceOracle","type":"address"},{"indexed":false,"internalType":"contract PriceOracle","name":"newPriceOracle","type":"address"}],"name":"NewPriceOracle","type":"event"},{"inputs":[{"internalType":"contract Unitroller","name":"unitroller","type":"address"}],"name":"_become","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"_grantComp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"_setBorrowCapGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"_setBorrowPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"_setCloseFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"_setCollateralFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"},{"internalType":"uint256[]","name":"supplySpeeds","type":"uint256[]"},{"internalType":"uint256[]","name":"borrowSpeeds","type":"uint256[]"}],"name":"_setCompSpeeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"},{"internalType":"uint256","name":"compSpeed","type":"uint256"}],"name":"_setContributorCompSpeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"_setLiquidationIncentive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"},{"internalType":"uint256[]","name":"newBorrowCaps","type":"uint256[]"}],"name":"_setMarketBorrowCaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"_setMintPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"_setPauseGuardian","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract PriceOracle","name":"newOracle","type":"address"}],"name":"_setPriceOracle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"_setSeizePaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"_setTransferPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"_supportMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountAssets","outputs":[{"internalType":"contract CToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allMarkets","outputs":[{"internalType":"contract CToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowCapGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"}],"name":"claimComp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"holders","type":"address[]"},{"internalType":"contract CToken[]","name":"cTokens","type":"address[]"},{"internalType":"bool","name":"borrowers","type":"bool"},{"internalType":"bool","name":"suppliers","type":"bool"}],"name":"claimComp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"claimComp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closeFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compBorrowSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compBorrowState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"compBorrowerIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compContributorSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compInitialIndex","outputs":[{"internalType":"uint224","name":"","type":"uint224"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compReceivable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"compSupplierIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compSupplySpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"compSupplyState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"cTokens","type":"address[]"}],"name":"enterMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenAddress","type":"address"}],"name":"exitMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"affectedUsers","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"fixBadAccruals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"contract CToken[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAssetsIn","outputs":[{"internalType":"contract CToken[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCompAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"cTokenModify","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"getHypotheticalAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isComptroller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract CToken","name":"cToken","type":"address"}],"name":"isDeprecated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastContributorBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"liquidateBorrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateCalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationIncentiveMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"markets","outputs":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint256","name":"collateralFactorMantissa","type":"uint256"},{"internalType":"bool","name":"isComped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mintAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"actualMintAmount","type":"uint256"},{"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"mintVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract PriceOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingComptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposal65FixExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"borrowerIndex","type":"uint256"}],"name":"repayBorrowVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"seizeGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenCollateral","type":"address"},{"internalType":"address","name":"cTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"updateContributorRewards","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50600080546001600160a01b0319163317905561543b806100326000396000f3fe608060405234801561001057600080fd5b506004361061048a5760003560e01c8063731f0c2b11610262578063b21be7fd11610151578063dce15449116100ce578063e9af029211610092578063e9af029214610c04578063eabe7d9114610c17578063ede4edd014610c2a578063f00a7a9214610c3d578063f4a433c014610c4a578063f851a44014610c6a57600080fd5b8063dce1544914610bae578063dcfbc0c714610bc1578063e4028eee14610bd4578063e6653f3d14610be7578063e875544614610bfb57600080fd5b8063c488847b11610115578063c488847b14610b15578063ca0af04314610b3d578063cc7ebdc414610b68578063d02f735114610b88578063da3d454c14610b9b57600080fd5b8063b21be7fd14610a84578063bb82aa5e14610aaf578063bdcdc25814610ac2578063bea6b8b814610ad5578063c299823814610af557600080fd5b806394b2294b116101df578063a8b43948116101a3578063a8b4394814610a2c578063aa90075414610a3f578063abfceffc14610a48578063ac0b0bb714610a68578063b0772d0b14610a7c57600080fd5b806394b2294b146109a9578063986ab838146109b25780639d1b5a0a146109d2578063a76b3fda146109ec578063a7f0e231146109ff57600080fd5b80638c57804e116102265780638c57804e146108b75780638e8f294b146108ef5780638ebf636414610942578063929fe9a11461095557806394543c151461099657600080fd5b8063731f0c2b1461083a578063741b25251461085d5780637dc0d1d01461087057806385b7beb81461088357806387f76303146108a357600080fd5b80634a5844321161037e5780635ec88c79116102fb5780636a56947e116102bf5780636a56947e1461077f5780636aa875b51461078d5780636b79c38d146107ad5780636d154ea5146108095780636d35bf911461082c57600080fd5b80635ec88c79146107205780635f5af1aa146107335780635fc7e71e14610746578063607ef6c1146107595780636810dfa61461076c57600080fd5b806351dff9891161034257806351dff989146106c157806352d84d1e146106d457806355ee1fe1146106e7578063598ee1cb146106fa5780635c7786051461070d57600080fd5b80634a584432146106445780634ada90af146106645780634e79238f1461066d5780634ef4c3e11461069b5780634fd42e17146106ae57600080fd5b8063267822471161040c5780633bcf7ec1116103d05780633bcf7ec1146105ed5780633c94786f1461060057806341c728b91461061457806342cbb15c1461062857806347ef3b3b1461062e57600080fd5b8063267822471461058e57806327efe3cb146105a15780632d70db78146105b4578063317b0b77146105c7578063391957d7146105da57600080fd5b80631d7b33d7116104535780631d7b33d7146104fa5780631ededc911461052857806321af45691461053d57806324008a621461056857806324a3d6221461057b57600080fd5b80627e3dd21461048f57806316b95e8f146104ac57806318c882a5146104c15780631c3db2e0146104d45780631d504dc6146104e7575b600080fd5b610497600181565b60405190151581526020015b60405180910390f35b6104bf6104ba366004614a3c565b610c7d565b005b6104976104cf366004614acb565b610f26565b6104bf6104e2366004614be3565b61105f565b6104bf6104f5366004614c33565b6110c2565b61051a610508366004614c33565b600f6020526000908152604090205481565b6040519081526020016104a3565b6104bf610536366004614c50565b5050505050565b601554610550906001600160a01b031681565b6040516001600160a01b0390911681526020016104a3565b61051a610576366004614cab565b611240565b600a54610550906001600160a01b031681565b600154610550906001600160a01b031681565b6104bf6105af366004614cfc565b6112fe565b6104976105c2366004614d28565b6113f5565b61051a6105d5366004614d45565b6114e5565b6104bf6105e8366004614c33565b61158c565b6104976105fb366004614acb565b611656565b600a5461049790600160a01b900460ff1681565b6104bf610622366004614d5e565b50505050565b4361051a565b6104bf61063c366004614da4565b505050505050565b61051a610652366004614c33565b60166020526000908152604090205481565b61051a60065481565b61068061067b366004614d5e565b611780565b604080519384526020840192909252908201526060016104a3565b61051a6106a9366004614e12565b6117c0565b61051a6106bc366004614d45565b611861565b6104bf6106cf366004614d5e565b6118be565b6105506106e2366004614d45565b61190d565b61051a6106f5366004614c33565b611937565b6104bf610708366004614cfc565b6119b0565b6104bf61071b366004614e12565b505050565b61068061072e366004614c33565b611aa4565b61051a610741366004614c33565b611adf565b61051a610754366004614e53565b611b58565b6104bf610767366004614a3c565b611d27565b6104bf61077a366004614f1b565b611f05565b6104bf610622366004614cab565b61051a61079b366004614c33565b601a6020526000908152604090205481565b6107e56107bb366004614c33565b6010602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b604080516001600160e01b03909316835263ffffffff9091166020830152016104a3565b610497610817366004614c33565b600c6020526000908152604090205460ff1681565b6104bf610536366004614e53565b610497610848366004614c33565b600b6020526000908152604090205460ff1681565b6104bf61086b366004614c33565b61218f565b600454610550906001600160a01b031681565b61051a610891366004614c33565b601c6020526000908152604090205481565b600a5461049790600160b01b900460ff1681565b6107e56108c5366004614c33565b6011602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b6109236108fd366004614c33565b60096020526000908152604090208054600182015460039092015460ff91821692911683565b60408051931515845260208401929092521515908201526060016104a3565b610497610950366004614d28565b61223b565b610497610963366004614fa4565b6001600160a01b038082166000908152600960209081526040808320938616835260029093019052205460ff1692915050565b6104976109a4366004614c33565b612322565b61051a60075481565b61051a6109c0366004614c33565b60176020526000908152604090205481565b73d7878b71eac29080559491d16419ca97cfcffd3a610550565b61051a6109fa366004614c33565b6123e1565b610a146a0c097ce7bc90715b34b9f160241b81565b6040516001600160e01b0390911681526020016104a3565b6104bf610a3a36600461502d565b612513565b61051a600e5481565b610a5b610a56366004614c33565b612648565b6040516104a391906150b5565b600a5461049790600160b81b900460ff1681565b610a5b6126be565b61051a610a92366004614fa4565b601260209081526000928352604080842090915290825290205481565b600254610550906001600160a01b031681565b61051a610ad0366004614cab565b612720565b61051a610ae3366004614c33565b60186020526000908152604090205481565b610b08610b03366004615102565b6127ab565b6040516104a39190615137565b610b28610b23366004614e12565b612873565b604080519283526020830191909152016104a3565b61051a610b4b366004614fa4565b601360209081526000928352604080842090915290825290205481565b61051a610b76366004614c33565b60146020526000908152604090205481565b61051a610b96366004614e53565b612a91565b61051a610ba9366004614e12565b612c38565b610550610bbc366004614cfc565b613008565b600354610550906001600160a01b031681565b61051a610be2366004614cfc565b613040565b600a5461049790600160a81b900460ff1681565b61051a60055481565b6104bf610c12366004614c33565b6131d2565b61051a610c25366004614e12565b613236565b61051a610c38366004614c33565b613271565b601b546104979060ff1681565b61051a610c58366004614c33565b60196020526000908152604090205481565b600054610550906001600160a01b031681565b6000546001600160a01b03163314610ce65760405162461bcd60e51b815260206004820152602160248201527f4f6e6c792061646d696e2063616e2063616c6c20746869732066756e6374696f6044820152603760f91b60648201526084015b60405180910390fd5b601b5460ff1615610d485760405162461bcd60e51b815260206004820152602660248201527f416c72656164792065786563757465642074686973206f6e652d6f66662066756044820152653731ba34b7b760d11b6064820152608401610cdd565b828114610d875760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606401610cdd565b60008060008060005b87811015610f0e57888882818110610daa57610daa61516f565b9050602002016020810190610dbf9190614c33565b6001600160a01b0381166000908152601460205260409020549095509350868682818110610def57610def61516f565b90506020020135925083831115610e93576000610e0c858561519b565b6001600160a01b0387166000908152601c6020526040812054919250610e3282846135d7565b6001600160a01b0389166000818152601c6020908152604091829020849055815186815290810184905292935090917f17fea09d9a7ca41b2f9f9118f18f44848a62e9c70d55dd4385131eb2cf1b7e47910160405180910390a28695505050505b8215610efe57610ea384846135e3565b6001600160a01b038616600081815260146020908152604091829020849055815188815290810184905292945090917f4a5c134e28b537a76546993ea37f3b60d9190476df7356d3842aa40902e20f04910160405180910390a25b610f07816151b2565b9050610d90565b5050601b805460ff1916600117905550505050505050565b6001600160a01b03821660009081526009602052604081205460ff16610f5e5760405162461bcd60e51b8152600401610cdd906151cd565b600a546001600160a01b0316331480610f8157506000546001600160a01b031633145b610f9d5760405162461bcd60e51b8152600401610cdd90615215565b6000546001600160a01b0316331480610fb857506001821515145b610fd45760405162461bcd60e51b8152600401610cdd9061525c565b6001600160a01b0383166000818152600c6020908152604091829020805460ff19168615159081179091558251938452606091840182905260069184019190915265426f72726f7760d01b6080840152908201527f71aec636243f9709bb0007ae15e9afb8150ab01716d75fd7573be5cc096e03b09060a0015b60405180910390a150805b92915050565b6040805160018082528183019092526000916020808301908036833701905050905082816000815181106110955761109561516f565b60200260200101906001600160a01b031690816001600160a01b03168152505061071b8183600180611f05565b806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611100573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611124919061528c565b6001600160a01b0316336001600160a01b0316146111945760405162461bcd60e51b815260206004820152602760248201527f6f6e6c7920756e6974726f6c6c65722061646d696e2063616e206368616e676560448201526620627261696e7360c81b6064820152608401610cdd565b806001600160a01b031663c1e803346040518163ffffffff1660e01b81526004016020604051808303816000875af11580156111d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f891906152a9565b1561123d5760405162461bcd60e51b815260206004820152601560248201527418da185b99d9481b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610cdd565b50565b6001600160a01b03841660009081526009602052604081205460ff16611268575060096112f6565b60006040518060200160405280876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d791906152a9565b905290506112e586826135ef565b6112f08685836137e2565b60009150505b949350505050565b611306613962565b6113525760405162461bcd60e51b815260206004820152601960248201527f6f6e6c792061646d696e2063616e206772616e7420636f6d70000000000000006044820152606401610cdd565b600061135e838361398b565b905080156113ae5760405162461bcd60e51b815260206004820152601b60248201527f696e73756666696369656e7420636f6d7020666f72206772616e7400000000006044820152606401610cdd565b604080516001600160a01b0385168152602081018490527f98b2f82a3a07f223a0be64b3d0f47711c64dccd1feafb94aa28156b38cd9695c910160405180910390a1505050565b600a546000906001600160a01b031633148061141b57506000546001600160a01b031633145b6114375760405162461bcd60e51b8152600401610cdd90615215565b6000546001600160a01b031633148061145257506001821515145b61146e5760405162461bcd60e51b8152600401610cdd9061525c565b600a8054831515600160b81b0260ff60b81b199091161790556040517fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de0906114d99084906040808252600590820152645365697a6560d81b6060820152901515602082015260800190565b60405180910390a15090565b600080546001600160a01b031633146115405760405162461bcd60e51b815260206004820152601f60248201527f6f6e6c792061646d696e2063616e2073657420636c6f736520666163746f72006044820152606401610cdd565b600580549083905560408051828152602081018590527f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd991015b60405180910390a160005b9392505050565b6000546001600160a01b031633146115f55760405162461bcd60e51b815260206004820152602660248201527f6f6e6c792061646d696e2063616e2073657420626f72726f772063617020677560448201526530b93234b0b760d11b6064820152608401610cdd565b601580546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527feda98690e518e9a05f8ec6837663e188211b2da8f4906648b323f2c1d4434e29910160405180910390a15050565b6001600160a01b03821660009081526009602052604081205460ff1661168e5760405162461bcd60e51b8152600401610cdd906151cd565b600a546001600160a01b03163314806116b157506000546001600160a01b031633145b6116cd5760405162461bcd60e51b8152600401610cdd90615215565b6000546001600160a01b03163314806116e857506001821515145b6117045760405162461bcd60e51b8152600401610cdd9061525c565b6001600160a01b0383166000818152600b6020908152604091829020805460ff19168615159081179091558251938452606091840182905260049184019190915263135a5b9d60e21b6080840152908201527f71aec636243f9709bb0007ae15e9afb8150ab01716d75fd7573be5cc096e03b09060a00161104e565b6000806000806000806117958a8a8a8a613ab0565b9250925092508260118111156117ad576117ad6152c2565b95509093509150505b9450945094915050565b6001600160a01b0383166000908152600b602052604081205460ff161561181a5760405162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b6044820152606401610cdd565b6001600160a01b03841660009081526009602052604090205460ff166118445760095b9050611585565b61184d84613dde565b6118578484613f56565b6000949350505050565b600080546001600160a01b03163314611880576110596001600b6140f4565b600680549083905560408051828152602081018590527faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316910161157a565b801580156118cc5750600082115b156106225760405162461bcd60e51b815260206004820152601160248201527072656465656d546f6b656e73207a65726f60781b6044820152606401610cdd565b600d818154811061191d57600080fd5b6000918252602090912001546001600160a01b0316905081565b600080546001600160a01b0316331461195657611059600160106140f4565b600480546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22910161157a565b6119b8613962565b611a045760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c792061646d696e2063616e2073657420636f6d702073706565640000006044820152606401610cdd565b611a0d8261218f565b80611a30576001600160a01b038216600090815260186020526040812055611a4b565b436001600160a01b0383166000908152601860205260409020555b6001600160a01b03821660008181526017602052604090819020839055517f386537fa92edc3319af95f1f904dcf1900021e4f3f4e08169a577a09076e66b390611a989084815260200190565b60405180910390a25050565b600080600080600080611abb876000806000613ab0565b925092509250826011811115611ad357611ad36152c2565b97919650945092505050565b600080546001600160a01b03163314611afe57611059600160136140f4565b600a80546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f0613b6ee6a04f0d09f390e4d9318894b9f6ac7fd83897cd8d18896ba579c401e910161157a565b6001600160a01b03851660009081526009602052604081205460ff161580611b9957506001600160a01b03851660009081526009602052604090205460ff16155b15611ba85760095b9050611d1e565b6040516395dd919360e01b81526001600160a01b038481166004830152600091908816906395dd919390602401602060405180830381865afa158015611bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1691906152a9565b9050611c2187612322565b15611c8c5782811015611c875760405162461bcd60e51b815260206004820152602860248201527f43616e206e6f74207265706179206d6f7265207468616e2074686520746f74616044820152676c20626f72726f7760c01b6064820152608401610cdd565b611d18565b600080611c988661416d565b91935090915060009050826011811115611cb457611cb46152c2565b14611cd557816011811115611ccb57611ccb6152c2565b9350505050611d1e565b80611ce1576003611ccb565b6000611cfd60405180602001604052806005548152508561418d565b905080861115611d14576011945050505050611d1e565b5050505b60009150505b95945050505050565b6000546001600160a01b0316331480611d4a57506015546001600160a01b031633145b611db45760405162461bcd60e51b815260206004820152603560248201527f6f6e6c792061646d696e206f7220626f72726f772063617020677561726469616044820152746e2063616e2073657420626f72726f77206361707360581b6064820152608401610cdd565b82818115801590611dc457508082145b611e005760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081a5b9c1d5d609a1b6044820152606401610cdd565b60005b82811015611efc57848482818110611e1d57611e1d61516f565b9050602002013560166000898985818110611e3a57611e3a61516f565b9050602002016020810190611e4f9190614c33565b6001600160a01b03168152602081019190915260400160002055868682818110611e7b57611e7b61516f565b9050602002016020810190611e909190614c33565b6001600160a01b03167f6f1951b2aad10f3fc81b86d91105b413a5b3f847a34bbc5ce1904201b14438f6868684818110611ecc57611ecc61516f565b90506020020135604051611ee291815260200190565b60405180910390a280611ef4816151b2565b915050611e03565b50505050505050565b60005b83518110156120cc576000848281518110611f2557611f2561516f565b6020908102919091018101516001600160a01b0381166000908152600990925260409091205490915060ff16611f955760405162461bcd60e51b81526020600482015260156024820152741b585c9ad95d081b5d5cdd081899481b1a5cdd1959605a1b6044820152606401610cdd565b600184151514156120625760006040518060200160405280836001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611feb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200f91906152a9565b9052905061201d82826135ef565b60005b875181101561205f5761204d8389838151811061203f5761203f61516f565b6020026020010151846137e2565b80612057816151b2565b915050612020565b50505b600183151514156120b95761207681613dde565b60005b86518110156120b7576120a5828883815181106120985761209861516f565b6020026020010151613f56565b806120af816151b2565b915050612079565b505b50806120c4816151b2565b915050611f08565b5060005b84518110156105365761213a8582815181106120ee576120ee61516f565b60200260200101516014600088858151811061210c5761210c61516f565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205461398b565b601460008784815181106121505761215061516f565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020819055508080612187906151b2565b9150506120d0565b6001600160a01b0381166000908152601760209081526040808320546018909252822054909143916121c29083906135e3565b90506000811180156121d45750600083115b156106225760006121e582856141a5565b6001600160a01b0386166000908152601460205260408120549192509061220c90836135d7565b6001600160a01b0387166000908152601460209081526040808320939093556018905220849055505050505050565b600a546000906001600160a01b031633148061226157506000546001600160a01b031633145b61227d5760405162461bcd60e51b8152600401610cdd90615215565b6000546001600160a01b031633148061229857506001821515145b6122b45760405162461bcd60e51b8152600401610cdd9061525c565b600a8054831515600160b01b0260ff60b01b199091161790556040517fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de0906114d99084906040808252600890820152672a3930b739b332b960c11b6060820152901515602082015260800190565b6001600160a01b03811660009081526009602052604081206001015415801561236857506001600160a01b0382166000908152600c602052604090205460ff1615156001145b80156110595750816001600160a01b031663173b99046040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d191906152a9565b670de0b6b3a76400001492915050565b600080546001600160a01b0316331461240057611059600160126140f4565b6001600160a01b03821660009081526009602052604090205460ff161561242d57611059600a60116140f4565b816001600160a01b031663fe9c44ae6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561246b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248f91906152d8565b506001600160a01b03821660009081526009602052604081208054600160ff19918216811783556003830180549092169091558101919091556124d1836141b1565b6124da8361429a565b6040516001600160a01b03841681527fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f9060200161157a565b61251b613962565b6125675760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c792061646d696e2063616e2073657420636f6d702073706565640000006044820152606401610cdd565b82518251811480156125795750815181145b6125d75760405162461bcd60e51b815260206004820152602960248201527f436f6d7074726f6c6c65723a3a5f736574436f6d7053706565647320696e76616044820152681b1a59081a5b9c1d5d60ba1b6064820152608401610cdd565b60005b81811015610536576126388582815181106125f7576125f761516f565b60200260200101518583815181106126115761261161516f565b602002602001015185848151811061262b5761262b61516f565b6020026020010151614356565b612641816151b2565b90506125da565b6001600160a01b03811660009081526008602090815260408083208054825181850281018501909352808352606094938301828280156126b157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612693575b5093979650505050505050565b6060600d80548060200260200160405190810160405280929190818152602001828054801561271657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116126f8575b5050505050905090565b600a54600090600160b01b900460ff16156127725760405162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b6044820152606401610cdd565b600061277f868685614535565b9050801561278e5790506112f6565b61279786613dde565b6127a18686613f56565b6112f08685613f56565b805160609060008167ffffffffffffffff8111156127cb576127cb614b04565b6040519080825280602002602001820160405280156127f4578160200160208202803683370190505b50905060005b8281101561286b5760008582815181106128165761281661516f565b6020026020010151905061282a81336145ed565b601181111561283b5761283b6152c2565b83838151811061284d5761284d61516f565b60209081029190910101525080612863816151b2565b9150506127fa565b509392505050565b6004805460405163fc57d4df60e01b81526001600160a01b03868116938201939093526000928392839291169063fc57d4df90602401602060405180830381865afa1580156128c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ea91906152a9565b6004805460405163fc57d4df60e01b81526001600160a01b038981169382019390935292935060009291169063fc57d4df90602401602060405180830381865afa15801561293c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296091906152a9565b905081158061296d575080155b1561298157600d6000935093505050612a89565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e591906152a9565b905060006129ff6040518060200160405280600081525090565b604080516020808201835260008083528351808301855290815283518083018552600654815284519283019094528882529192612a3b916146e2565b9250612a636040518060200160405280888152506040518060200160405280888152506146e2565b9150612a6f838361472a565b9050612a7b818b61418d565b600099509750505050505050505b935093915050565b600a54600090600160b81b900460ff1615612ae05760405162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b6044820152606401610cdd565b6001600160a01b03861660009081526009602052604090205460ff161580612b2157506001600160a01b03851660009081526009602052604090205460ff16155b15612b2d576009611ba1565b846001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8f919061528c565b6001600160a01b0316866001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bfa919061528c565b6001600160a01b031614612c0f576002611ba1565b612c1886613dde565b612c228684613f56565b612c2c8685613f56565b60009695505050505050565b6001600160a01b0383166000908152600c602052604081205460ff1615612c945760405162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b6044820152606401610cdd565b6001600160a01b03841660009081526009602052604090205460ff16612cbb57600961183d565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff16612db857336001600160a01b03851614612d3c5760405162461bcd60e51b815260206004820152601560248201527439b2b73232b91036bab9ba1031329031aa37b5b2b760591b6044820152606401610cdd565b6000612d4833856145ed565b90506000816011811115612d5e57612d5e6152c2565b14612d7d57806011811115612d7557612d756152c2565b915050611585565b6001600160a01b038086166000908152600960209081526040808320938816835260029093019052205460ff16612db657612db66152f5565b505b6004805460405163fc57d4df60e01b81526001600160a01b038781169382019390935291169063fc57d4df90602401602060405180830381865afa158015612e04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e2891906152a9565b612e3357600d61183d565b6001600160a01b0384166000908152601660205260409020548015612f18576000856001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eb691906152a9565b90506000612ec482866135d7565b9050828110612f155760405162461bcd60e51b815260206004820152601960248201527f6d61726b657420626f72726f77206361702072656163686564000000000000006044820152606401610cdd565b50505b600080612f288688600088613ab0565b91935090915060009050826011811115612f4457612f446152c2565b14612f6557816011811115612f5b57612f5b6152c2565b9350505050611585565b8015612f72576004612f5b565b60006040518060200160405280896001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe191906152a9565b90529050612fef88826135ef565b612ffa8888836137e2565b600098975050505050505050565b6008602052816000526040600020818154811061302457600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080546001600160a01b031633146130665761305f600160066140f4565b9050611059565b6001600160a01b0383166000908152600960205260409020805460ff1661309b57613093600960076140f4565b915050611059565b60408051602080820183528582528251908101909252670c7d713b49da00008252906130c981835190511090565b156130e4576130da600660086140f4565b9350505050611059565b841580159061316057506004805460405163fc57d4df60e01b81526001600160a01b038981169382019390935291169063fc57d4df90602401602060405180830381865afa15801561313a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315e91906152a9565b155b15613171576130da600d60096140f4565b60018301805490869055604080516001600160a01b0389168152602081018390529081018790527f70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc59060600160405180910390a16000979650505050505050565b61123d81600d80548060200260200160405190810160405280929190818152602001828054801561322c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161320e575b505050505061105f565b600080613244858585614535565b90508015613253579050611585565b61325c85613dde565b6132668585613f56565b600095945050505050565b6040516361bfb47160e11b815233600482015260009082908290819081906001600160a01b0385169063c37f68e290602401608060405180830381865afa1580156132c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e4919061530b565b50925092509250826000146133495760405162461bcd60e51b815260206004820152602560248201527f657869744d61726b65743a206765744163636f756e74536e617073686f742066604482015264185a5b195960da1b6064820152608401610cdd565b80156133655761335b600c60026140f4565b9695505050505050565b6000613372873385614535565b9050801561339257613387600e600383614764565b979650505050505050565b6001600160a01b0385166000908152600960209081526040808320338452600281019092529091205460ff166133d057600098975050505050505050565b3360009081526002820160209081526040808320805460ff19169055600882528083208054825181850281018501909352808352919290919083018282801561344257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613424575b5050835193945083925060009150505b828110156134a757896001600160a01b03168482815181106134765761347661516f565b60200260200101516001600160a01b03161415613495578091506134a7565b8061349f816151b2565b915050613452565b508181106134b7576134b76152f5565b336000908152600860205260409020805481906134d69060019061519b565b815481106134e6576134e661516f565b9060005260206000200160009054906101000a90046001600160a01b03168183815481106135165761351661516f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508080548061355457613554615341565b600082815260209020810160001990810180546001600160a01b03191690550190556040517fe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d906135bd908c9033906001600160a01b0392831681529116602082015260400190565b60405180910390a160009c9b505050505050505050505050565b60006115858284615357565b6000611585828461519b565b6001600160a01b038216600090815260116020908152604080832060199092528220549091613654435b6040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506147dc565b83549091506000906136769063ffffffff80851691600160e01b9004166135e3565b90506000811180156136885750600083115b156137b75760006136fa876001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f491906152a9565b8761480c565b9050600061370883866141a5565b905060008083116137285760405180602001604052806000815250613732565b613732828461482a565b604080516020810190915288546001600160e01b031681529091506137959061375b9083614865565b5160408051808201909152601a81527f6e657720696e64657820657863656564732032323420626974730000000000006020820152614891565b6001600160e01b0316600160e01b63ffffffff8716021787555061063c915050565b801561063c57835463ffffffff8316600160e01b026001600160e01b03909116178455505050505050565b6001600160a01b03838116600090815260116020908152604080832080546013845282852095881685529490925290912080546001600160e01b039093169081905590918015801561384257506a0c097ce7bc90715b34b9f160241b8210155b1561385857506a0c097ce7bc90715b34b9f160241b5b6000604051806020016040528061386f85856135e3565b90526040516395dd919360e01b81526001600160a01b0388811660048301529192506000916138c291908a16906395dd919390602401602060405180830381865afa1580156136d0573d6000803e3d6000fd5b905060006138d082846148b8565b6001600160a01b038916600090815260146020526040812054919250906138f790836135d7565b6001600160a01b038a811660008181526014602090815260409182902085905581518781529081018b90529394509092918d16917f1fc3ecc087d8d2d15e23d0032af5a47059c3892d003d8e139fdcb6bb327c99a6910160405180910390a350505050505050505050565b600080546001600160a01b031633148061398657506002546001600160a01b031633145b905090565b60008073d7878b71eac29080559491d16419ca97cfcffd3a6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156139ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a1191906152a9565b9050600084118015613a235750808411155b15613aa75760405163a9059cbb60e01b81526001600160a01b0386811660048301526024820186905283169063a9059cbb906044016020604051808303816000875af1158015613a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9b91906152d8565b50600092505050611059565b50919392505050565b6000806000613abd61494e565b6001600160a01b038816600090815260086020908152604080832080548251818502810185019093528083528493830182828015613b2457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613b06575b5050505050905060005b8151811015613d88576000828281518110613b4b57613b4b61516f565b60209081029190910101516040516361bfb47160e11b81526001600160a01b038e811660048301529192509082169063c37f68e290602401608060405180830381865afa158015613ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc4919061530b565b60808901526060880152604087015293508315613bf057600f60008097509750975050505050506117b6565b60408051602080820183526001600160a01b0384811660008181526009845285902060010154845260c08a01939093528351808301855260808a0151815260e08a015260048054855163fc57d4df60e01b815291820194909452935192169263fc57d4df92602480830193928290030181865afa158015613c75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9991906152a9565b60a08601819052613cb957600d60008097509750975050505050506117b6565b604080516020810190915260a0860151815261010086015260c085015160e0860151613cf391613ce8916146e2565b8661010001516146e2565b610120860181905260408601518651613d0d9291906148e1565b855261010085015160608601516020870151613d2a9291906148e1565b60208601526001600160a01b03818116908c161415613d7557613d578561012001518b87602001516148e1565b60208601819052610100860151613d6f918b906148e1565b60208601525b5080613d80816151b2565b915050613b2e565b50602083015183511115613db95760208301518351600091613da99161519b565b60009550955095505050506117b6565b60008084600001518560200151613dd0919061519b565b9550955095505050506117b6565b6001600160a01b0381166000908152601060209081526040808320601a9092528220549091613e0c43613619565b8354909150600090613e2e9063ffffffff80851691600160e01b9004166135e3565b9050600081118015613e405750600083115b15613f2c576000856001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ea991906152a9565b90506000613eb783866141a5565b90506000808311613ed75760405180602001604052806000815250613ee1565b613ee1828461482a565b604080516020810190915288546001600160e01b03168152909150613f0a9061375b9083614865565b6001600160e01b0316600160e01b63ffffffff87160217875550610536915050565b801561053657835463ffffffff8316600160e01b026001600160e01b039091161784555050505050565b6001600160a01b03828116600090815260106020908152604080832080546012845282852095871685529490925290912080546001600160e01b0390931690819055909180158015613fb657506a0c097ce7bc90715b34b9f160241b8210155b15613fcc57506a0c097ce7bc90715b34b9f160241b5b60006040518060200160405280613fe385856135e3565b90526040516370a0823160e01b81526001600160a01b0387811660048301529192506000918816906370a0823190602401602060405180830381865afa158015614031573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061405591906152a9565b9050600061406382846148b8565b6001600160a01b0388166000908152601460205260408120549192509061408a90836135d7565b6001600160a01b0389811660008181526014602090815260409182902085905581518781529081018b90529394509092918c16917f2caecd17d02f56fa897705dcc740da2d237c373f70686f4e0d9bd3bf0400ea7a910160405180910390a3505050505050505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0836011811115614129576141296152c2565b83601381111561413b5761413b6152c2565b60408051928352602083019190915260009082015260600160405180910390a1826011811115611585576115856152c2565b6000806000614180846000806000613ab0565b9250925092509193909250565b60008061419a8484614902565b90506112f68161492a565b6000611585828461536f565b60005b600d5481101561424757816001600160a01b0316600d82815481106141db576141db61516f565b6000918252602090912001546001600160a01b031614156142355760405162461bcd60e51b81526020600482015260146024820152731b585c9ad95d08185b1c9958591e48185919195960621b6044820152606401610cdd565b8061423f816151b2565b9150506141b4565b50600d80546001810182556000919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b0319166001600160a01b0392909216919091179055565b60006142a543613619565b6001600160a01b03831660009081526010602090815260408083206011909252909120815492935090916001600160e01b03166142fb5781546001600160e01b0319166a0c097ce7bc90715b34b9f160241b1782555b80546001600160e01b03166143295780546001600160e01b0319166a0c097ce7bc90715b34b9f160241b1781555b805463ffffffff909316600160e01b026001600160e01b0393841681179091558154909216909117905550565b6001600160a01b0383166000908152600960205260409020805460ff166143bf5760405162461bcd60e51b815260206004820152601960248201527f636f6d70206d61726b6574206973206e6f74206c6973746564000000000000006044820152606401610cdd565b6001600160a01b0384166000908152601a6020526040902054831461443d576143e784613dde565b6001600160a01b0384166000818152601a602052604090819020859055517fdeafccd0c0b768b2529f7dcbbe58e155d6023059150b7490ed4535cc3744b92d906144349086815260200190565b60405180910390a25b6001600160a01b03841660009081526019602052604090205482146106225760006040518060200160405280866001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144cb91906152a9565b905290506144d985826135ef565b6001600160a01b03851660008181526019602052604090819020859055517f20af8e791cc98f74b2d7a391c80980ca8e5aebf3d4060bf581997b6acae2e537906145269086815260200190565b60405180910390a25050505050565b6001600160a01b03831660009081526009602052604081205460ff1661455c57600961183d565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff1661459457600061183d565b6000806145a48587866000613ab0565b919350909150600090508260118111156145c0576145c06152c2565b146145e0578160118111156145d7576145d76152c2565b92505050611585565b8015612c2c5760046145d7565b6001600160a01b0382166000908152600960205260408120805460ff16614618576009915050611059565b6001600160a01b038316600090815260028201602052604090205460ff1615156001141561464a576000915050611059565b6001600160a01b03838116600081815260028401602090815260408083208054600160ff199091168117909155600883528184208054918201815584529282902090920180546001600160a01b031916948916948517905581519384528301919091527f3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5910160405180910390a15060009392505050565b6040805160208101909152600081526040518060200160405280670de0b6b3a7640000614717866000015186600001516141a5565b614721919061538e565b90529392505050565b604080516020810190915260008152604051806020016040528061472161475d8660000151670de0b6b3a76400006141a5565b8551614942565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0846011811115614799576147996152c2565b8460138111156147ab576147ab6152c2565b604080519283526020830191909152810184905260600160405180910390a18360118111156112f6576112f66152c2565b60008164010000000084106148045760405162461bcd60e51b8152600401610cdd91906153b0565b509192915050565b600061158561482384670de0b6b3a76400006141a5565b8351614942565b604080516020810190915260008152604051806020016040528061472161485f866a0c097ce7bc90715b34b9f160241b6141a5565b85614942565b6040805160208101909152600081526040518060200160405280614721856000015185600001516135d7565b600081600160e01b84106148045760405162461bcd60e51b8152600401610cdd91906153b0565b60006a0c097ce7bc90715b34b9f160241b6148d78484600001516141a5565b611585919061538e565b6000806148ee8585614902565b9050611d1e6148fc8261492a565b846135d7565b60408051602081019091526000815260405180602001604052806147218560000151856141a5565b805160009061105990670de0b6b3a76400009061538e565b6000611585828461538e565b60405180610140016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200161499a6040518060200160405280600081525090565b81526020016149b56040518060200160405280600081525090565b81526020016149d06040518060200160405280600081525090565b81526020016149eb6040518060200160405280600081525090565b905290565b60008083601f840112614a0257600080fd5b50813567ffffffffffffffff811115614a1a57600080fd5b6020830191508360208260051b8501011115614a3557600080fd5b9250929050565b60008060008060408587031215614a5257600080fd5b843567ffffffffffffffff80821115614a6a57600080fd5b614a76888389016149f0565b90965094506020870135915080821115614a8f57600080fd5b50614a9c878288016149f0565b95989497509550505050565b6001600160a01b038116811461123d57600080fd5b801515811461123d57600080fd5b60008060408385031215614ade57600080fd5b8235614ae981614aa8565b91506020830135614af981614abd565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b4357614b43614b04565b604052919050565b600067ffffffffffffffff821115614b6557614b65614b04565b5060051b60200190565b600082601f830112614b8057600080fd5b81356020614b95614b9083614b4b565b614b1a565b82815260059290921b84018101918181019086841115614bb457600080fd5b8286015b84811015614bd8578035614bcb81614aa8565b8352918301918301614bb8565b509695505050505050565b60008060408385031215614bf657600080fd5b8235614c0181614aa8565b9150602083013567ffffffffffffffff811115614c1d57600080fd5b614c2985828601614b6f565b9150509250929050565b600060208284031215614c4557600080fd5b813561158581614aa8565b600080600080600060a08688031215614c6857600080fd5b8535614c7381614aa8565b94506020860135614c8381614aa8565b93506040860135614c9381614aa8565b94979396509394606081013594506080013592915050565b60008060008060808587031215614cc157600080fd5b8435614ccc81614aa8565b93506020850135614cdc81614aa8565b92506040850135614cec81614aa8565b9396929550929360600135925050565b60008060408385031215614d0f57600080fd5b8235614d1a81614aa8565b946020939093013593505050565b600060208284031215614d3a57600080fd5b813561158581614abd565b600060208284031215614d5757600080fd5b5035919050565b60008060008060808587031215614d7457600080fd5b8435614d7f81614aa8565b93506020850135614d8f81614aa8565b93969395505050506040820135916060013590565b60008060008060008060c08789031215614dbd57600080fd5b8635614dc881614aa8565b95506020870135614dd881614aa8565b94506040870135614de881614aa8565b93506060870135614df881614aa8565b9598949750929560808101359460a0909101359350915050565b600080600060608486031215614e2757600080fd5b8335614e3281614aa8565b92506020840135614e4281614aa8565b929592945050506040919091013590565b600080600080600060a08688031215614e6b57600080fd5b8535614e7681614aa8565b94506020860135614e8681614aa8565b93506040860135614e9681614aa8565b92506060860135614ea681614aa8565b949793965091946080013592915050565b600082601f830112614ec857600080fd5b81356020614ed8614b9083614b4b565b82815260059290921b84018101918181019086841115614ef757600080fd5b8286015b84811015614bd8578035614f0e81614aa8565b8352918301918301614efb565b60008060008060808587031215614f3157600080fd5b843567ffffffffffffffff80821115614f4957600080fd5b614f5588838901614eb7565b95506020870135915080821115614f6b57600080fd5b50614f7887828801614b6f565b9350506040850135614f8981614abd565b91506060850135614f9981614abd565b939692955090935050565b60008060408385031215614fb757600080fd5b8235614fc281614aa8565b91506020830135614af981614aa8565b600082601f830112614fe357600080fd5b81356020614ff3614b9083614b4b565b82815260059290921b8401810191818101908684111561501257600080fd5b8286015b84811015614bd85780358352918301918301615016565b60008060006060848603121561504257600080fd5b833567ffffffffffffffff8082111561505a57600080fd5b61506687838801614b6f565b9450602086013591508082111561507c57600080fd5b61508887838801614fd2565b9350604086013591508082111561509e57600080fd5b506150ab86828701614fd2565b9150509250925092565b6020808252825182820181905260009190848201906040850190845b818110156150f65783516001600160a01b0316835292840192918401916001016150d1565b50909695505050505050565b60006020828403121561511457600080fd5b813567ffffffffffffffff81111561512b57600080fd5b6112f684828501614eb7565b6020808252825182820181905260009190848201906040850190845b818110156150f657835183529284019291840191600101615153565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000828210156151ad576151ad615185565b500390565b60006000198214156151c6576151c6615185565b5060010190565b60208082526028908201527f63616e6e6f742070617573652061206d61726b65742074686174206973206e6f6040820152671d081b1a5cdd195960c21b606082015260800190565b60208082526027908201527f6f6e6c7920706175736520677561726469616e20616e642061646d696e2063616040820152666e20706175736560c81b606082015260800190565b6020808252601690820152756f6e6c792061646d696e2063616e20756e706175736560501b604082015260600190565b60006020828403121561529e57600080fd5b815161158581614aa8565b6000602082840312156152bb57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b6000602082840312156152ea57600080fd5b815161158581614abd565b634e487b7160e01b600052600160045260246000fd5b6000806000806080858703121561532157600080fd5b505082516020840151604085015160609095015191969095509092509050565b634e487b7160e01b600052603160045260246000fd5b6000821982111561536a5761536a615185565b500190565b600081600019048311821515161561538957615389615185565b500290565b6000826153ab57634e487b7160e01b600052601260045260246000fd5b500490565b600060208083528351808285015260005b818110156153dd578581018301518582016040015282016153c1565b818111156153ef576000604083870101525b50601f01601f191692909201604001939250505056fea2646970667358221220628f7ffeec06ca6b439f1f282877aabfb1cc6c3e0ed99c98d622f59ef9cdaac964736f6c634300080a0033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061048a5760003560e01c8063731f0c2b11610262578063b21be7fd11610151578063dce15449116100ce578063e9af029211610092578063e9af029214610c04578063eabe7d9114610c17578063ede4edd014610c2a578063f00a7a9214610c3d578063f4a433c014610c4a578063f851a44014610c6a57600080fd5b8063dce1544914610bae578063dcfbc0c714610bc1578063e4028eee14610bd4578063e6653f3d14610be7578063e875544614610bfb57600080fd5b8063c488847b11610115578063c488847b14610b15578063ca0af04314610b3d578063cc7ebdc414610b68578063d02f735114610b88578063da3d454c14610b9b57600080fd5b8063b21be7fd14610a84578063bb82aa5e14610aaf578063bdcdc25814610ac2578063bea6b8b814610ad5578063c299823814610af557600080fd5b806394b2294b116101df578063a8b43948116101a3578063a8b4394814610a2c578063aa90075414610a3f578063abfceffc14610a48578063ac0b0bb714610a68578063b0772d0b14610a7c57600080fd5b806394b2294b146109a9578063986ab838146109b25780639d1b5a0a146109d2578063a76b3fda146109ec578063a7f0e231146109ff57600080fd5b80638c57804e116102265780638c57804e146108b75780638e8f294b146108ef5780638ebf636414610942578063929fe9a11461095557806394543c151461099657600080fd5b8063731f0c2b1461083a578063741b25251461085d5780637dc0d1d01461087057806385b7beb81461088357806387f76303146108a357600080fd5b80634a5844321161037e5780635ec88c79116102fb5780636a56947e116102bf5780636a56947e1461077f5780636aa875b51461078d5780636b79c38d146107ad5780636d154ea5146108095780636d35bf911461082c57600080fd5b80635ec88c79146107205780635f5af1aa146107335780635fc7e71e14610746578063607ef6c1146107595780636810dfa61461076c57600080fd5b806351dff9891161034257806351dff989146106c157806352d84d1e146106d457806355ee1fe1146106e7578063598ee1cb146106fa5780635c7786051461070d57600080fd5b80634a584432146106445780634ada90af146106645780634e79238f1461066d5780634ef4c3e11461069b5780634fd42e17146106ae57600080fd5b8063267822471161040c5780633bcf7ec1116103d05780633bcf7ec1146105ed5780633c94786f1461060057806341c728b91461061457806342cbb15c1461062857806347ef3b3b1461062e57600080fd5b8063267822471461058e57806327efe3cb146105a15780632d70db78146105b4578063317b0b77146105c7578063391957d7146105da57600080fd5b80631d7b33d7116104535780631d7b33d7146104fa5780631ededc911461052857806321af45691461053d57806324008a621461056857806324a3d6221461057b57600080fd5b80627e3dd21461048f57806316b95e8f146104ac57806318c882a5146104c15780631c3db2e0146104d45780631d504dc6146104e7575b600080fd5b610497600181565b60405190151581526020015b60405180910390f35b6104bf6104ba366004614a3c565b610c7d565b005b6104976104cf366004614acb565b610f26565b6104bf6104e2366004614be3565b61105f565b6104bf6104f5366004614c33565b6110c2565b61051a610508366004614c33565b600f6020526000908152604090205481565b6040519081526020016104a3565b6104bf610536366004614c50565b5050505050565b601554610550906001600160a01b031681565b6040516001600160a01b0390911681526020016104a3565b61051a610576366004614cab565b611240565b600a54610550906001600160a01b031681565b600154610550906001600160a01b031681565b6104bf6105af366004614cfc565b6112fe565b6104976105c2366004614d28565b6113f5565b61051a6105d5366004614d45565b6114e5565b6104bf6105e8366004614c33565b61158c565b6104976105fb366004614acb565b611656565b600a5461049790600160a01b900460ff1681565b6104bf610622366004614d5e565b50505050565b4361051a565b6104bf61063c366004614da4565b505050505050565b61051a610652366004614c33565b60166020526000908152604090205481565b61051a60065481565b61068061067b366004614d5e565b611780565b604080519384526020840192909252908201526060016104a3565b61051a6106a9366004614e12565b6117c0565b61051a6106bc366004614d45565b611861565b6104bf6106cf366004614d5e565b6118be565b6105506106e2366004614d45565b61190d565b61051a6106f5366004614c33565b611937565b6104bf610708366004614cfc565b6119b0565b6104bf61071b366004614e12565b505050565b61068061072e366004614c33565b611aa4565b61051a610741366004614c33565b611adf565b61051a610754366004614e53565b611b58565b6104bf610767366004614a3c565b611d27565b6104bf61077a366004614f1b565b611f05565b6104bf610622366004614cab565b61051a61079b366004614c33565b601a6020526000908152604090205481565b6107e56107bb366004614c33565b6010602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b604080516001600160e01b03909316835263ffffffff9091166020830152016104a3565b610497610817366004614c33565b600c6020526000908152604090205460ff1681565b6104bf610536366004614e53565b610497610848366004614c33565b600b6020526000908152604090205460ff1681565b6104bf61086b366004614c33565b61218f565b600454610550906001600160a01b031681565b61051a610891366004614c33565b601c6020526000908152604090205481565b600a5461049790600160b01b900460ff1681565b6107e56108c5366004614c33565b6011602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b6109236108fd366004614c33565b60096020526000908152604090208054600182015460039092015460ff91821692911683565b60408051931515845260208401929092521515908201526060016104a3565b610497610950366004614d28565b61223b565b610497610963366004614fa4565b6001600160a01b038082166000908152600960209081526040808320938616835260029093019052205460ff1692915050565b6104976109a4366004614c33565b612322565b61051a60075481565b61051a6109c0366004614c33565b60176020526000908152604090205481565b73d7878b71eac29080559491d16419ca97cfcffd3a610550565b61051a6109fa366004614c33565b6123e1565b610a146a0c097ce7bc90715b34b9f160241b81565b6040516001600160e01b0390911681526020016104a3565b6104bf610a3a36600461502d565b612513565b61051a600e5481565b610a5b610a56366004614c33565b612648565b6040516104a391906150b5565b600a5461049790600160b81b900460ff1681565b610a5b6126be565b61051a610a92366004614fa4565b601260209081526000928352604080842090915290825290205481565b600254610550906001600160a01b031681565b61051a610ad0366004614cab565b612720565b61051a610ae3366004614c33565b60186020526000908152604090205481565b610b08610b03366004615102565b6127ab565b6040516104a39190615137565b610b28610b23366004614e12565b612873565b604080519283526020830191909152016104a3565b61051a610b4b366004614fa4565b601360209081526000928352604080842090915290825290205481565b61051a610b76366004614c33565b60146020526000908152604090205481565b61051a610b96366004614e53565b612a91565b61051a610ba9366004614e12565b612c38565b610550610bbc366004614cfc565b613008565b600354610550906001600160a01b031681565b61051a610be2366004614cfc565b613040565b600a5461049790600160a81b900460ff1681565b61051a60055481565b6104bf610c12366004614c33565b6131d2565b61051a610c25366004614e12565b613236565b61051a610c38366004614c33565b613271565b601b546104979060ff1681565b61051a610c58366004614c33565b60196020526000908152604090205481565b600054610550906001600160a01b031681565b6000546001600160a01b03163314610ce65760405162461bcd60e51b815260206004820152602160248201527f4f6e6c792061646d696e2063616e2063616c6c20746869732066756e6374696f6044820152603760f91b60648201526084015b60405180910390fd5b601b5460ff1615610d485760405162461bcd60e51b815260206004820152602660248201527f416c72656164792065786563757465642074686973206f6e652d6f66662066756044820152653731ba34b7b760d11b6064820152608401610cdd565b828114610d875760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606401610cdd565b60008060008060005b87811015610f0e57888882818110610daa57610daa61516f565b9050602002016020810190610dbf9190614c33565b6001600160a01b0381166000908152601460205260409020549095509350868682818110610def57610def61516f565b90506020020135925083831115610e93576000610e0c858561519b565b6001600160a01b0387166000908152601c6020526040812054919250610e3282846135d7565b6001600160a01b0389166000818152601c6020908152604091829020849055815186815290810184905292935090917f17fea09d9a7ca41b2f9f9118f18f44848a62e9c70d55dd4385131eb2cf1b7e47910160405180910390a28695505050505b8215610efe57610ea384846135e3565b6001600160a01b038616600081815260146020908152604091829020849055815188815290810184905292945090917f4a5c134e28b537a76546993ea37f3b60d9190476df7356d3842aa40902e20f04910160405180910390a25b610f07816151b2565b9050610d90565b5050601b805460ff1916600117905550505050505050565b6001600160a01b03821660009081526009602052604081205460ff16610f5e5760405162461bcd60e51b8152600401610cdd906151cd565b600a546001600160a01b0316331480610f8157506000546001600160a01b031633145b610f9d5760405162461bcd60e51b8152600401610cdd90615215565b6000546001600160a01b0316331480610fb857506001821515145b610fd45760405162461bcd60e51b8152600401610cdd9061525c565b6001600160a01b0383166000818152600c6020908152604091829020805460ff19168615159081179091558251938452606091840182905260069184019190915265426f72726f7760d01b6080840152908201527f71aec636243f9709bb0007ae15e9afb8150ab01716d75fd7573be5cc096e03b09060a0015b60405180910390a150805b92915050565b6040805160018082528183019092526000916020808301908036833701905050905082816000815181106110955761109561516f565b60200260200101906001600160a01b031690816001600160a01b03168152505061071b8183600180611f05565b806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611100573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611124919061528c565b6001600160a01b0316336001600160a01b0316146111945760405162461bcd60e51b815260206004820152602760248201527f6f6e6c7920756e6974726f6c6c65722061646d696e2063616e206368616e676560448201526620627261696e7360c81b6064820152608401610cdd565b806001600160a01b031663c1e803346040518163ffffffff1660e01b81526004016020604051808303816000875af11580156111d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f891906152a9565b1561123d5760405162461bcd60e51b815260206004820152601560248201527418da185b99d9481b9bdd08185d5d1a1bdc9a5e9959605a1b6044820152606401610cdd565b50565b6001600160a01b03841660009081526009602052604081205460ff16611268575060096112f6565b60006040518060200160405280876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d791906152a9565b905290506112e586826135ef565b6112f08685836137e2565b60009150505b949350505050565b611306613962565b6113525760405162461bcd60e51b815260206004820152601960248201527f6f6e6c792061646d696e2063616e206772616e7420636f6d70000000000000006044820152606401610cdd565b600061135e838361398b565b905080156113ae5760405162461bcd60e51b815260206004820152601b60248201527f696e73756666696369656e7420636f6d7020666f72206772616e7400000000006044820152606401610cdd565b604080516001600160a01b0385168152602081018490527f98b2f82a3a07f223a0be64b3d0f47711c64dccd1feafb94aa28156b38cd9695c910160405180910390a1505050565b600a546000906001600160a01b031633148061141b57506000546001600160a01b031633145b6114375760405162461bcd60e51b8152600401610cdd90615215565b6000546001600160a01b031633148061145257506001821515145b61146e5760405162461bcd60e51b8152600401610cdd9061525c565b600a8054831515600160b81b0260ff60b81b199091161790556040517fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de0906114d99084906040808252600590820152645365697a6560d81b6060820152901515602082015260800190565b60405180910390a15090565b600080546001600160a01b031633146115405760405162461bcd60e51b815260206004820152601f60248201527f6f6e6c792061646d696e2063616e2073657420636c6f736520666163746f72006044820152606401610cdd565b600580549083905560408051828152602081018590527f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd991015b60405180910390a160005b9392505050565b6000546001600160a01b031633146115f55760405162461bcd60e51b815260206004820152602660248201527f6f6e6c792061646d696e2063616e2073657420626f72726f772063617020677560448201526530b93234b0b760d11b6064820152608401610cdd565b601580546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527feda98690e518e9a05f8ec6837663e188211b2da8f4906648b323f2c1d4434e29910160405180910390a15050565b6001600160a01b03821660009081526009602052604081205460ff1661168e5760405162461bcd60e51b8152600401610cdd906151cd565b600a546001600160a01b03163314806116b157506000546001600160a01b031633145b6116cd5760405162461bcd60e51b8152600401610cdd90615215565b6000546001600160a01b03163314806116e857506001821515145b6117045760405162461bcd60e51b8152600401610cdd9061525c565b6001600160a01b0383166000818152600b6020908152604091829020805460ff19168615159081179091558251938452606091840182905260049184019190915263135a5b9d60e21b6080840152908201527f71aec636243f9709bb0007ae15e9afb8150ab01716d75fd7573be5cc096e03b09060a00161104e565b6000806000806000806117958a8a8a8a613ab0565b9250925092508260118111156117ad576117ad6152c2565b95509093509150505b9450945094915050565b6001600160a01b0383166000908152600b602052604081205460ff161561181a5760405162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b6044820152606401610cdd565b6001600160a01b03841660009081526009602052604090205460ff166118445760095b9050611585565b61184d84613dde565b6118578484613f56565b6000949350505050565b600080546001600160a01b03163314611880576110596001600b6140f4565b600680549083905560408051828152602081018590527faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316910161157a565b801580156118cc5750600082115b156106225760405162461bcd60e51b815260206004820152601160248201527072656465656d546f6b656e73207a65726f60781b6044820152606401610cdd565b600d818154811061191d57600080fd5b6000918252602090912001546001600160a01b0316905081565b600080546001600160a01b0316331461195657611059600160106140f4565b600480546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22910161157a565b6119b8613962565b611a045760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c792061646d696e2063616e2073657420636f6d702073706565640000006044820152606401610cdd565b611a0d8261218f565b80611a30576001600160a01b038216600090815260186020526040812055611a4b565b436001600160a01b0383166000908152601860205260409020555b6001600160a01b03821660008181526017602052604090819020839055517f386537fa92edc3319af95f1f904dcf1900021e4f3f4e08169a577a09076e66b390611a989084815260200190565b60405180910390a25050565b600080600080600080611abb876000806000613ab0565b925092509250826011811115611ad357611ad36152c2565b97919650945092505050565b600080546001600160a01b03163314611afe57611059600160136140f4565b600a80546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527f0613b6ee6a04f0d09f390e4d9318894b9f6ac7fd83897cd8d18896ba579c401e910161157a565b6001600160a01b03851660009081526009602052604081205460ff161580611b9957506001600160a01b03851660009081526009602052604090205460ff16155b15611ba85760095b9050611d1e565b6040516395dd919360e01b81526001600160a01b038481166004830152600091908816906395dd919390602401602060405180830381865afa158015611bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1691906152a9565b9050611c2187612322565b15611c8c5782811015611c875760405162461bcd60e51b815260206004820152602860248201527f43616e206e6f74207265706179206d6f7265207468616e2074686520746f74616044820152676c20626f72726f7760c01b6064820152608401610cdd565b611d18565b600080611c988661416d565b91935090915060009050826011811115611cb457611cb46152c2565b14611cd557816011811115611ccb57611ccb6152c2565b9350505050611d1e565b80611ce1576003611ccb565b6000611cfd60405180602001604052806005548152508561418d565b905080861115611d14576011945050505050611d1e565b5050505b60009150505b95945050505050565b6000546001600160a01b0316331480611d4a57506015546001600160a01b031633145b611db45760405162461bcd60e51b815260206004820152603560248201527f6f6e6c792061646d696e206f7220626f72726f772063617020677561726469616044820152746e2063616e2073657420626f72726f77206361707360581b6064820152608401610cdd565b82818115801590611dc457508082145b611e005760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081a5b9c1d5d609a1b6044820152606401610cdd565b60005b82811015611efc57848482818110611e1d57611e1d61516f565b9050602002013560166000898985818110611e3a57611e3a61516f565b9050602002016020810190611e4f9190614c33565b6001600160a01b03168152602081019190915260400160002055868682818110611e7b57611e7b61516f565b9050602002016020810190611e909190614c33565b6001600160a01b03167f6f1951b2aad10f3fc81b86d91105b413a5b3f847a34bbc5ce1904201b14438f6868684818110611ecc57611ecc61516f565b90506020020135604051611ee291815260200190565b60405180910390a280611ef4816151b2565b915050611e03565b50505050505050565b60005b83518110156120cc576000848281518110611f2557611f2561516f565b6020908102919091018101516001600160a01b0381166000908152600990925260409091205490915060ff16611f955760405162461bcd60e51b81526020600482015260156024820152741b585c9ad95d081b5d5cdd081899481b1a5cdd1959605a1b6044820152606401610cdd565b600184151514156120625760006040518060200160405280836001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611feb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200f91906152a9565b9052905061201d82826135ef565b60005b875181101561205f5761204d8389838151811061203f5761203f61516f565b6020026020010151846137e2565b80612057816151b2565b915050612020565b50505b600183151514156120b95761207681613dde565b60005b86518110156120b7576120a5828883815181106120985761209861516f565b6020026020010151613f56565b806120af816151b2565b915050612079565b505b50806120c4816151b2565b915050611f08565b5060005b84518110156105365761213a8582815181106120ee576120ee61516f565b60200260200101516014600088858151811061210c5761210c61516f565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205461398b565b601460008784815181106121505761215061516f565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020819055508080612187906151b2565b9150506120d0565b6001600160a01b0381166000908152601760209081526040808320546018909252822054909143916121c29083906135e3565b90506000811180156121d45750600083115b156106225760006121e582856141a5565b6001600160a01b0386166000908152601460205260408120549192509061220c90836135d7565b6001600160a01b0387166000908152601460209081526040808320939093556018905220849055505050505050565b600a546000906001600160a01b031633148061226157506000546001600160a01b031633145b61227d5760405162461bcd60e51b8152600401610cdd90615215565b6000546001600160a01b031633148061229857506001821515145b6122b45760405162461bcd60e51b8152600401610cdd9061525c565b600a8054831515600160b01b0260ff60b01b199091161790556040517fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de0906114d99084906040808252600890820152672a3930b739b332b960c11b6060820152901515602082015260800190565b6001600160a01b03811660009081526009602052604081206001015415801561236857506001600160a01b0382166000908152600c602052604090205460ff1615156001145b80156110595750816001600160a01b031663173b99046040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d191906152a9565b670de0b6b3a76400001492915050565b600080546001600160a01b0316331461240057611059600160126140f4565b6001600160a01b03821660009081526009602052604090205460ff161561242d57611059600a60116140f4565b816001600160a01b031663fe9c44ae6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561246b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248f91906152d8565b506001600160a01b03821660009081526009602052604081208054600160ff19918216811783556003830180549092169091558101919091556124d1836141b1565b6124da8361429a565b6040516001600160a01b03841681527fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f9060200161157a565b61251b613962565b6125675760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c792061646d696e2063616e2073657420636f6d702073706565640000006044820152606401610cdd565b82518251811480156125795750815181145b6125d75760405162461bcd60e51b815260206004820152602960248201527f436f6d7074726f6c6c65723a3a5f736574436f6d7053706565647320696e76616044820152681b1a59081a5b9c1d5d60ba1b6064820152608401610cdd565b60005b81811015610536576126388582815181106125f7576125f761516f565b60200260200101518583815181106126115761261161516f565b602002602001015185848151811061262b5761262b61516f565b6020026020010151614356565b612641816151b2565b90506125da565b6001600160a01b03811660009081526008602090815260408083208054825181850281018501909352808352606094938301828280156126b157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612693575b5093979650505050505050565b6060600d80548060200260200160405190810160405280929190818152602001828054801561271657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116126f8575b5050505050905090565b600a54600090600160b01b900460ff16156127725760405162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b6044820152606401610cdd565b600061277f868685614535565b9050801561278e5790506112f6565b61279786613dde565b6127a18686613f56565b6112f08685613f56565b805160609060008167ffffffffffffffff8111156127cb576127cb614b04565b6040519080825280602002602001820160405280156127f4578160200160208202803683370190505b50905060005b8281101561286b5760008582815181106128165761281661516f565b6020026020010151905061282a81336145ed565b601181111561283b5761283b6152c2565b83838151811061284d5761284d61516f565b60209081029190910101525080612863816151b2565b9150506127fa565b509392505050565b6004805460405163fc57d4df60e01b81526001600160a01b03868116938201939093526000928392839291169063fc57d4df90602401602060405180830381865afa1580156128c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ea91906152a9565b6004805460405163fc57d4df60e01b81526001600160a01b038981169382019390935292935060009291169063fc57d4df90602401602060405180830381865afa15801561293c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296091906152a9565b905081158061296d575080155b1561298157600d6000935093505050612a89565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e591906152a9565b905060006129ff6040518060200160405280600081525090565b604080516020808201835260008083528351808301855290815283518083018552600654815284519283019094528882529192612a3b916146e2565b9250612a636040518060200160405280888152506040518060200160405280888152506146e2565b9150612a6f838361472a565b9050612a7b818b61418d565b600099509750505050505050505b935093915050565b600a54600090600160b81b900460ff1615612ae05760405162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b6044820152606401610cdd565b6001600160a01b03861660009081526009602052604090205460ff161580612b2157506001600160a01b03851660009081526009602052604090205460ff16155b15612b2d576009611ba1565b846001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8f919061528c565b6001600160a01b0316866001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bfa919061528c565b6001600160a01b031614612c0f576002611ba1565b612c1886613dde565b612c228684613f56565b612c2c8685613f56565b60009695505050505050565b6001600160a01b0383166000908152600c602052604081205460ff1615612c945760405162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b6044820152606401610cdd565b6001600160a01b03841660009081526009602052604090205460ff16612cbb57600961183d565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff16612db857336001600160a01b03851614612d3c5760405162461bcd60e51b815260206004820152601560248201527439b2b73232b91036bab9ba1031329031aa37b5b2b760591b6044820152606401610cdd565b6000612d4833856145ed565b90506000816011811115612d5e57612d5e6152c2565b14612d7d57806011811115612d7557612d756152c2565b915050611585565b6001600160a01b038086166000908152600960209081526040808320938816835260029093019052205460ff16612db657612db66152f5565b505b6004805460405163fc57d4df60e01b81526001600160a01b038781169382019390935291169063fc57d4df90602401602060405180830381865afa158015612e04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e2891906152a9565b612e3357600d61183d565b6001600160a01b0384166000908152601660205260409020548015612f18576000856001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eb691906152a9565b90506000612ec482866135d7565b9050828110612f155760405162461bcd60e51b815260206004820152601960248201527f6d61726b657420626f72726f77206361702072656163686564000000000000006044820152606401610cdd565b50505b600080612f288688600088613ab0565b91935090915060009050826011811115612f4457612f446152c2565b14612f6557816011811115612f5b57612f5b6152c2565b9350505050611585565b8015612f72576004612f5b565b60006040518060200160405280896001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe191906152a9565b90529050612fef88826135ef565b612ffa8888836137e2565b600098975050505050505050565b6008602052816000526040600020818154811061302457600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080546001600160a01b031633146130665761305f600160066140f4565b9050611059565b6001600160a01b0383166000908152600960205260409020805460ff1661309b57613093600960076140f4565b915050611059565b60408051602080820183528582528251908101909252670c7d713b49da00008252906130c981835190511090565b156130e4576130da600660086140f4565b9350505050611059565b841580159061316057506004805460405163fc57d4df60e01b81526001600160a01b038981169382019390935291169063fc57d4df90602401602060405180830381865afa15801561313a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315e91906152a9565b155b15613171576130da600d60096140f4565b60018301805490869055604080516001600160a01b0389168152602081018390529081018790527f70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc59060600160405180910390a16000979650505050505050565b61123d81600d80548060200260200160405190810160405280929190818152602001828054801561322c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161320e575b505050505061105f565b600080613244858585614535565b90508015613253579050611585565b61325c85613dde565b6132668585613f56565b600095945050505050565b6040516361bfb47160e11b815233600482015260009082908290819081906001600160a01b0385169063c37f68e290602401608060405180830381865afa1580156132c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e4919061530b565b50925092509250826000146133495760405162461bcd60e51b815260206004820152602560248201527f657869744d61726b65743a206765744163636f756e74536e617073686f742066604482015264185a5b195960da1b6064820152608401610cdd565b80156133655761335b600c60026140f4565b9695505050505050565b6000613372873385614535565b9050801561339257613387600e600383614764565b979650505050505050565b6001600160a01b0385166000908152600960209081526040808320338452600281019092529091205460ff166133d057600098975050505050505050565b3360009081526002820160209081526040808320805460ff19169055600882528083208054825181850281018501909352808352919290919083018282801561344257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613424575b5050835193945083925060009150505b828110156134a757896001600160a01b03168482815181106134765761347661516f565b60200260200101516001600160a01b03161415613495578091506134a7565b8061349f816151b2565b915050613452565b508181106134b7576134b76152f5565b336000908152600860205260409020805481906134d69060019061519b565b815481106134e6576134e661516f565b9060005260206000200160009054906101000a90046001600160a01b03168183815481106135165761351661516f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508080548061355457613554615341565b600082815260209020810160001990810180546001600160a01b03191690550190556040517fe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d906135bd908c9033906001600160a01b0392831681529116602082015260400190565b60405180910390a160009c9b505050505050505050505050565b60006115858284615357565b6000611585828461519b565b6001600160a01b038216600090815260116020908152604080832060199092528220549091613654435b6040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506147dc565b83549091506000906136769063ffffffff80851691600160e01b9004166135e3565b90506000811180156136885750600083115b156137b75760006136fa876001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f491906152a9565b8761480c565b9050600061370883866141a5565b905060008083116137285760405180602001604052806000815250613732565b613732828461482a565b604080516020810190915288546001600160e01b031681529091506137959061375b9083614865565b5160408051808201909152601a81527f6e657720696e64657820657863656564732032323420626974730000000000006020820152614891565b6001600160e01b0316600160e01b63ffffffff8716021787555061063c915050565b801561063c57835463ffffffff8316600160e01b026001600160e01b03909116178455505050505050565b6001600160a01b03838116600090815260116020908152604080832080546013845282852095881685529490925290912080546001600160e01b039093169081905590918015801561384257506a0c097ce7bc90715b34b9f160241b8210155b1561385857506a0c097ce7bc90715b34b9f160241b5b6000604051806020016040528061386f85856135e3565b90526040516395dd919360e01b81526001600160a01b0388811660048301529192506000916138c291908a16906395dd919390602401602060405180830381865afa1580156136d0573d6000803e3d6000fd5b905060006138d082846148b8565b6001600160a01b038916600090815260146020526040812054919250906138f790836135d7565b6001600160a01b038a811660008181526014602090815260409182902085905581518781529081018b90529394509092918d16917f1fc3ecc087d8d2d15e23d0032af5a47059c3892d003d8e139fdcb6bb327c99a6910160405180910390a350505050505050505050565b600080546001600160a01b031633148061398657506002546001600160a01b031633145b905090565b60008073d7878b71eac29080559491d16419ca97cfcffd3a6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156139ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a1191906152a9565b9050600084118015613a235750808411155b15613aa75760405163a9059cbb60e01b81526001600160a01b0386811660048301526024820186905283169063a9059cbb906044016020604051808303816000875af1158015613a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9b91906152d8565b50600092505050611059565b50919392505050565b6000806000613abd61494e565b6001600160a01b038816600090815260086020908152604080832080548251818502810185019093528083528493830182828015613b2457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613b06575b5050505050905060005b8151811015613d88576000828281518110613b4b57613b4b61516f565b60209081029190910101516040516361bfb47160e11b81526001600160a01b038e811660048301529192509082169063c37f68e290602401608060405180830381865afa158015613ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc4919061530b565b60808901526060880152604087015293508315613bf057600f60008097509750975050505050506117b6565b60408051602080820183526001600160a01b0384811660008181526009845285902060010154845260c08a01939093528351808301855260808a0151815260e08a015260048054855163fc57d4df60e01b815291820194909452935192169263fc57d4df92602480830193928290030181865afa158015613c75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9991906152a9565b60a08601819052613cb957600d60008097509750975050505050506117b6565b604080516020810190915260a0860151815261010086015260c085015160e0860151613cf391613ce8916146e2565b8661010001516146e2565b610120860181905260408601518651613d0d9291906148e1565b855261010085015160608601516020870151613d2a9291906148e1565b60208601526001600160a01b03818116908c161415613d7557613d578561012001518b87602001516148e1565b60208601819052610100860151613d6f918b906148e1565b60208601525b5080613d80816151b2565b915050613b2e565b50602083015183511115613db95760208301518351600091613da99161519b565b60009550955095505050506117b6565b60008084600001518560200151613dd0919061519b565b9550955095505050506117b6565b6001600160a01b0381166000908152601060209081526040808320601a9092528220549091613e0c43613619565b8354909150600090613e2e9063ffffffff80851691600160e01b9004166135e3565b9050600081118015613e405750600083115b15613f2c576000856001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ea991906152a9565b90506000613eb783866141a5565b90506000808311613ed75760405180602001604052806000815250613ee1565b613ee1828461482a565b604080516020810190915288546001600160e01b03168152909150613f0a9061375b9083614865565b6001600160e01b0316600160e01b63ffffffff87160217875550610536915050565b801561053657835463ffffffff8316600160e01b026001600160e01b039091161784555050505050565b6001600160a01b03828116600090815260106020908152604080832080546012845282852095871685529490925290912080546001600160e01b0390931690819055909180158015613fb657506a0c097ce7bc90715b34b9f160241b8210155b15613fcc57506a0c097ce7bc90715b34b9f160241b5b60006040518060200160405280613fe385856135e3565b90526040516370a0823160e01b81526001600160a01b0387811660048301529192506000918816906370a0823190602401602060405180830381865afa158015614031573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061405591906152a9565b9050600061406382846148b8565b6001600160a01b0388166000908152601460205260408120549192509061408a90836135d7565b6001600160a01b0389811660008181526014602090815260409182902085905581518781529081018b90529394509092918c16917f2caecd17d02f56fa897705dcc740da2d237c373f70686f4e0d9bd3bf0400ea7a910160405180910390a3505050505050505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0836011811115614129576141296152c2565b83601381111561413b5761413b6152c2565b60408051928352602083019190915260009082015260600160405180910390a1826011811115611585576115856152c2565b6000806000614180846000806000613ab0565b9250925092509193909250565b60008061419a8484614902565b90506112f68161492a565b6000611585828461536f565b60005b600d5481101561424757816001600160a01b0316600d82815481106141db576141db61516f565b6000918252602090912001546001600160a01b031614156142355760405162461bcd60e51b81526020600482015260146024820152731b585c9ad95d08185b1c9958591e48185919195960621b6044820152606401610cdd565b8061423f816151b2565b9150506141b4565b50600d80546001810182556000919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b0319166001600160a01b0392909216919091179055565b60006142a543613619565b6001600160a01b03831660009081526010602090815260408083206011909252909120815492935090916001600160e01b03166142fb5781546001600160e01b0319166a0c097ce7bc90715b34b9f160241b1782555b80546001600160e01b03166143295780546001600160e01b0319166a0c097ce7bc90715b34b9f160241b1781555b805463ffffffff909316600160e01b026001600160e01b0393841681179091558154909216909117905550565b6001600160a01b0383166000908152600960205260409020805460ff166143bf5760405162461bcd60e51b815260206004820152601960248201527f636f6d70206d61726b6574206973206e6f74206c6973746564000000000000006044820152606401610cdd565b6001600160a01b0384166000908152601a6020526040902054831461443d576143e784613dde565b6001600160a01b0384166000818152601a602052604090819020859055517fdeafccd0c0b768b2529f7dcbbe58e155d6023059150b7490ed4535cc3744b92d906144349086815260200190565b60405180910390a25b6001600160a01b03841660009081526019602052604090205482146106225760006040518060200160405280866001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156144a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144cb91906152a9565b905290506144d985826135ef565b6001600160a01b03851660008181526019602052604090819020859055517f20af8e791cc98f74b2d7a391c80980ca8e5aebf3d4060bf581997b6acae2e537906145269086815260200190565b60405180910390a25050505050565b6001600160a01b03831660009081526009602052604081205460ff1661455c57600961183d565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff1661459457600061183d565b6000806145a48587866000613ab0565b919350909150600090508260118111156145c0576145c06152c2565b146145e0578160118111156145d7576145d76152c2565b92505050611585565b8015612c2c5760046145d7565b6001600160a01b0382166000908152600960205260408120805460ff16614618576009915050611059565b6001600160a01b038316600090815260028201602052604090205460ff1615156001141561464a576000915050611059565b6001600160a01b03838116600081815260028401602090815260408083208054600160ff199091168117909155600883528184208054918201815584529282902090920180546001600160a01b031916948916948517905581519384528301919091527f3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5910160405180910390a15060009392505050565b6040805160208101909152600081526040518060200160405280670de0b6b3a7640000614717866000015186600001516141a5565b614721919061538e565b90529392505050565b604080516020810190915260008152604051806020016040528061472161475d8660000151670de0b6b3a76400006141a5565b8551614942565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0846011811115614799576147996152c2565b8460138111156147ab576147ab6152c2565b604080519283526020830191909152810184905260600160405180910390a18360118111156112f6576112f66152c2565b60008164010000000084106148045760405162461bcd60e51b8152600401610cdd91906153b0565b509192915050565b600061158561482384670de0b6b3a76400006141a5565b8351614942565b604080516020810190915260008152604051806020016040528061472161485f866a0c097ce7bc90715b34b9f160241b6141a5565b85614942565b6040805160208101909152600081526040518060200160405280614721856000015185600001516135d7565b600081600160e01b84106148045760405162461bcd60e51b8152600401610cdd91906153b0565b60006a0c097ce7bc90715b34b9f160241b6148d78484600001516141a5565b611585919061538e565b6000806148ee8585614902565b9050611d1e6148fc8261492a565b846135d7565b60408051602081019091526000815260405180602001604052806147218560000151856141a5565b805160009061105990670de0b6b3a76400009061538e565b6000611585828461538e565b60405180610140016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200161499a6040518060200160405280600081525090565b81526020016149b56040518060200160405280600081525090565b81526020016149d06040518060200160405280600081525090565b81526020016149eb6040518060200160405280600081525090565b905290565b60008083601f840112614a0257600080fd5b50813567ffffffffffffffff811115614a1a57600080fd5b6020830191508360208260051b8501011115614a3557600080fd5b9250929050565b60008060008060408587031215614a5257600080fd5b843567ffffffffffffffff80821115614a6a57600080fd5b614a76888389016149f0565b90965094506020870135915080821115614a8f57600080fd5b50614a9c878288016149f0565b95989497509550505050565b6001600160a01b038116811461123d57600080fd5b801515811461123d57600080fd5b60008060408385031215614ade57600080fd5b8235614ae981614aa8565b91506020830135614af981614abd565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b4357614b43614b04565b604052919050565b600067ffffffffffffffff821115614b6557614b65614b04565b5060051b60200190565b600082601f830112614b8057600080fd5b81356020614b95614b9083614b4b565b614b1a565b82815260059290921b84018101918181019086841115614bb457600080fd5b8286015b84811015614bd8578035614bcb81614aa8565b8352918301918301614bb8565b509695505050505050565b60008060408385031215614bf657600080fd5b8235614c0181614aa8565b9150602083013567ffffffffffffffff811115614c1d57600080fd5b614c2985828601614b6f565b9150509250929050565b600060208284031215614c4557600080fd5b813561158581614aa8565b600080600080600060a08688031215614c6857600080fd5b8535614c7381614aa8565b94506020860135614c8381614aa8565b93506040860135614c9381614aa8565b94979396509394606081013594506080013592915050565b60008060008060808587031215614cc157600080fd5b8435614ccc81614aa8565b93506020850135614cdc81614aa8565b92506040850135614cec81614aa8565b9396929550929360600135925050565b60008060408385031215614d0f57600080fd5b8235614d1a81614aa8565b946020939093013593505050565b600060208284031215614d3a57600080fd5b813561158581614abd565b600060208284031215614d5757600080fd5b5035919050565b60008060008060808587031215614d7457600080fd5b8435614d7f81614aa8565b93506020850135614d8f81614aa8565b93969395505050506040820135916060013590565b60008060008060008060c08789031215614dbd57600080fd5b8635614dc881614aa8565b95506020870135614dd881614aa8565b94506040870135614de881614aa8565b93506060870135614df881614aa8565b9598949750929560808101359460a0909101359350915050565b600080600060608486031215614e2757600080fd5b8335614e3281614aa8565b92506020840135614e4281614aa8565b929592945050506040919091013590565b600080600080600060a08688031215614e6b57600080fd5b8535614e7681614aa8565b94506020860135614e8681614aa8565b93506040860135614e9681614aa8565b92506060860135614ea681614aa8565b949793965091946080013592915050565b600082601f830112614ec857600080fd5b81356020614ed8614b9083614b4b565b82815260059290921b84018101918181019086841115614ef757600080fd5b8286015b84811015614bd8578035614f0e81614aa8565b8352918301918301614efb565b60008060008060808587031215614f3157600080fd5b843567ffffffffffffffff80821115614f4957600080fd5b614f5588838901614eb7565b95506020870135915080821115614f6b57600080fd5b50614f7887828801614b6f565b9350506040850135614f8981614abd565b91506060850135614f9981614abd565b939692955090935050565b60008060408385031215614fb757600080fd5b8235614fc281614aa8565b91506020830135614af981614aa8565b600082601f830112614fe357600080fd5b81356020614ff3614b9083614b4b565b82815260059290921b8401810191818101908684111561501257600080fd5b8286015b84811015614bd85780358352918301918301615016565b60008060006060848603121561504257600080fd5b833567ffffffffffffffff8082111561505a57600080fd5b61506687838801614b6f565b9450602086013591508082111561507c57600080fd5b61508887838801614fd2565b9350604086013591508082111561509e57600080fd5b506150ab86828701614fd2565b9150509250925092565b6020808252825182820181905260009190848201906040850190845b818110156150f65783516001600160a01b0316835292840192918401916001016150d1565b50909695505050505050565b60006020828403121561511457600080fd5b813567ffffffffffffffff81111561512b57600080fd5b6112f684828501614eb7565b6020808252825182820181905260009190848201906040850190845b818110156150f657835183529284019291840191600101615153565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000828210156151ad576151ad615185565b500390565b60006000198214156151c6576151c6615185565b5060010190565b60208082526028908201527f63616e6e6f742070617573652061206d61726b65742074686174206973206e6f6040820152671d081b1a5cdd195960c21b606082015260800190565b60208082526027908201527f6f6e6c7920706175736520677561726469616e20616e642061646d696e2063616040820152666e20706175736560c81b606082015260800190565b6020808252601690820152756f6e6c792061646d696e2063616e20756e706175736560501b604082015260600190565b60006020828403121561529e57600080fd5b815161158581614aa8565b6000602082840312156152bb57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b6000602082840312156152ea57600080fd5b815161158581614abd565b634e487b7160e01b600052600160045260246000fd5b6000806000806080858703121561532157600080fd5b505082516020840151604085015160609095015191969095509092509050565b634e487b7160e01b600052603160045260246000fd5b6000821982111561536a5761536a615185565b500190565b600081600019048311821515161561538957615389615185565b500290565b6000826153ab57634e487b7160e01b600052601260045260246000fd5b500490565b600060208083528351808285015260005b818110156153dd578581018301518582016040015282016153c1565b818111156153ef576000604083870101525b50601f01601f191692909201604001939250505056fea2646970667358221220628f7ffeec06ca6b439f1f282877aabfb1cc6c3e0ed99c98d622f59ef9cdaac964736f6c634300080a0033
Deployed Bytecode Sourcemap
103895:63637:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;307:41;;344:4;307:41;;;;;179:14:1;;172:22;154:41;;142:2;127:18;307:41:0;;;;;;;;149878:2158;;;;;;:::i;:::-;;:::i;:::-;;148288:509;;;;;;:::i;:::-;;:::i;161657:209::-;;;;;;:::i;:::-;;:::i;149568:234::-;;;;;;:::i;:::-;;:::i;83181:42::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;4611:25:1;;;4599:2;4584:18;83181:42:0;4465:177:1;121837:467:0;;;;;;:::i;:::-;;;;;;;84207:32;;;;;-1:-1:-1;;;;;84207:32:0;;;;;;-1:-1:-1;;;;;5507:32:1;;;5489:51;;5477:2;5462:18;84207:32:0;5343:203:1;120867:648:0;;;;;;:::i;:::-;;:::i;82335:28::-;;;;;-1:-1:-1;;;;;82335:28:0;;;80169:27;;;;;-1:-1:-1;;;;;80169:27:0;;;164342:314;;;;;;:::i;:::-;;:::i;149191:369::-;;;;;;:::i;:::-;;:::i;139314:423::-;;;;;;:::i;:::-;;:::i;146367:557::-;;;;;;:::i;:::-;;:::i;147777:503::-;;;;;;:::i;:::-;;:::i;82370:31::-;;;;;-1:-1:-1;;;82370:31:0;;;;;;114405:371;;;;;;:::i;:::-;;;;;;167183:99;167262:12;167183:99;;124720:555;;;;;;:::i;:::-;;;;;;;;84386:42;;;;;;:::i;:::-;;;;;;;;;;;;;;80876:40;;;;;;131980:408;;;;;;:::i;:::-;;:::i;:::-;;;;8531:25:1;;;8587:2;8572:18;;8565:34;;;;8615:18;;;8608:34;8519:2;8504:18;131980:408:0;8329:319:1;113468:605:0;;;;;;:::i;:::-;;:::i;142051:742::-;;;;;;:::i;:::-;;:::i;116902:358::-;;;;;;:::i;:::-;;:::i;82964:26::-;;;;;;:::i;:::-;;:::i;138474:572::-;;;;;;:::i;:::-;;:::i;165713:645::-;;;;;;:::i;:::-;;:::i;120039:331::-;;;;;;:::i;:::-;161724:142;161657:209;;;130583:277;;;;;;:::i;:::-;;:::i;147162:607::-;;;;;;:::i;:::-;;:::i;122758:1488::-;;;;;;:::i;:::-;;:::i;145594:603::-;;;;;;:::i;:::-;;:::i;162209:1098::-;;;;;;:::i;:::-;;:::i;129229:354::-;;;;;;:::i;85105:48::-;;;;;;:::i;:::-;;;;;;;;;;;;;;83294:58;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;83294:58:0;;;-1:-1:-1;;;83294:58:0;;;;;;;;;;-1:-1:-1;;;;;13039:32:1;;;13021:51;;13120:10;13108:23;;;13103:2;13088:18;;13081:51;12994:18;83294:58:0;12849:289:1;82584:52:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;127180:484;;;;;;:::i;82527:50::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;160610:588;;;;;;:::i;:::-;;:::i;80577:25::-;;;;;-1:-1:-1;;;;;80577:25:0;;;85481:46;;;;;;:::i;:::-;;;;;;;;;;;;;;82448:34;;;;;-1:-1:-1;;;82448:34:0;;;;;;83423:58;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;83423:58:0;;;-1:-1:-1;;;83423:58:0;;;;;;82015:41;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13586:14:1;;13579:22;13561:41;;13633:2;13618:18;;13611:34;;;;13688:14;13681:22;13661:18;;;13654:50;13549:2;13534:18;82015:41:0;13371:339:1;148805:378:0;;;;;;:::i;:::-;;:::i;108292:163::-;;;;;;:::i;:::-;-1:-1:-1;;;;;108396:24:0;;;108372:4;108396:24;;;:7;:24;;;;;;;;:51;;;;;:42;;;;:51;;;;;;108292:163;;;;;166891:284;;;;;;:::i;:::-;;:::i;81046:21::-;;;;;;84575:53;;;;;;:::i;:::-;;;;;;;;;;;;;;167397:132;167479:42;167397:132;;143120:853;;;;;;:::i;:::-;;:::i;107076:47::-;;-1:-1:-1;;;107076:47:0;;;;;-1:-1:-1;;;;;14578:32:1;;;14560:51;;14548:2;14533:18;107076:47:0;14414:203:1;164992:513:0;;;;;;:::i;:::-;;:::i;83075:20::-;;;;;;107841:174;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;82489:31::-;;;;;-1:-1:-1;;;82489:31:0;;;;;;166549:99;;;:::i;83601:69::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;80265:40;;;;;-1:-1:-1;;;;;80265:40:0;;;128131:773;;;;;;:::i;:::-;;:::i;84723:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;108721:388;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;136646:1563::-;;;;;;:::i;:::-;;:::i;:::-;;;;18397:25:1;;;18453:2;18438:18;;18431:34;;;;18370:18;136646:1563:0;18223:248:1;83790:69:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;83939:43;;;;;;:::i;:::-;;;;;;;;;;;;;;125738:981;;;;;;:::i;:::-;;:::i;117701:2031::-;;;;;;:::i;:::-;;:::i;81174:49::-;;;;;;:::i;:::-;;:::i;80375:47::-;;;;;-1:-1:-1;;;;;80375:47:0;;;140111:1639;;;;;;:::i;:::-;;:::i;82408:33::-;;;;;-1:-1:-1;;;82408:33:0;;;;;;80724:31;;;;;;161344:97;;;;;;:::i;:::-;;:::i;115227:454::-;;;;;;:::i;:::-;;:::i;110806:2183::-;;;;;;:::i;:::-;;:::i;85337:33::-;;;;;;;;;84946:48;;;;;;:::i;:::-;;;;;;;;;;;;;;80068:20;;;;;-1:-1:-1;;;;;80068:20:0;;;149878:2158;150003:5;;-1:-1:-1;;;;;150003:5:0;149989:10;:19;149981:65;;;;-1:-1:-1;;;149981:65:0;;19021:2:1;149981:65:0;;;19003:21:1;19060:2;19040:18;;;19033:30;19099:34;19079:18;;;19072:62;-1:-1:-1;;;19150:18:1;;;19143:31;19191:19;;149981:65:0;;;;;;;;;150110:21;;;;150109:22;150101:73;;;;-1:-1:-1;;;150101:73:0;;19423:2:1;150101:73:0;;;19405:21:1;19462:2;19442:18;;;19435:30;19501:34;19481:18;;;19474:62;-1:-1:-1;;;19552:18:1;;;19545:36;19598:19;;150101:73:0;19221:402:1;150101:73:0;150243:38;;;150235:64;;;;-1:-1:-1;;;150235:64:0;;19830:2:1;150235:64:0;;;19812:21:1;19869:2;19849:18;;;19842:30;-1:-1:-1;;;19888:18:1;;;19881:43;19941:18;;150235:64:0;19628:337:1;150235:64:0;150339:12;150362:19;150392:21;150424:15;150504:6;150499:1432;150516:24;;;150499:1432;;;150569:13;;150583:1;150569:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;150617:17:0;;;;;;:11;:17;;;;;;150562:23;;-1:-1:-1;150617:17:0;-1:-1:-1;150670:7:0;;150678:1;150670:10;;;;;;;:::i;:::-;;;;;;;150651:29;;150909:14;150890:16;:33;150886:652;;;151006:22;151031:33;151050:14;151031:16;:33;:::i;:::-;-1:-1:-1;;;;;151164:20:0;;151143:18;151164:20;;;:14;:20;;;;;;151006:58;;-1:-1:-1;151224:38:0;151164:20;151006:58;151224:4;:38::i;:::-;-1:-1:-1;;;;;151349:20:0;;;;;;:14;:20;;;;;;;;;:36;;;151411:57;;18397:25:1;;;18438:18;;;18431:34;;;151349:36:0;;-1:-1:-1;151349:20:0;;151411:57;;18370:18:1;151411:57:0;;;;;;;151508:14;151489:33;;150925:613;;;150886:652;151558:20;;151554:366;;151787:38;151792:14;151808:16;151787:4;:38::i;:::-;-1:-1:-1;;;;;151754:17:0;;;;;;:11;:17;;;;;;;;;:71;;;151851:53;;18397:25:1;;;18438:18;;;18431:34;;;151754:71:0;;-1:-1:-1;151754:17:0;;151851:53;;18370:18:1;151851:53:0;;;;;;;151554:366;150542:3;;;:::i;:::-;;;150499:1432;;;-1:-1:-1;;151943:21:0;:28;;-1:-1:-1;;151943:28:0;151967:4;151943:28;;;-1:-1:-1;;;;;;;149878:2158:0:o;148288:509::-;-1:-1:-1;;;;;148382:24:0;;148357:4;148382:24;;;:7;:24;;;;;:33;;;148374:86;;;;-1:-1:-1;;;148374:86:0;;;;;;;:::i;:::-;148493:13;;-1:-1:-1;;;;;148493:13:0;148479:10;:27;;:50;;-1:-1:-1;148524:5:0;;-1:-1:-1;;;;;148524:5:0;148510:10;:19;148479:50;148471:102;;;;-1:-1:-1;;;148471:102:0;;;;;;;:::i;:::-;148606:5;;-1:-1:-1;;;;;148606:5:0;148592:10;:19;;:36;;-1:-1:-1;148624:4:0;148615:13;;;;148592:36;148584:71;;;;-1:-1:-1;;;148584:71:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;148668:37:0;;;;;;:20;:37;;;;;;;;;:45;;-1:-1:-1;;148668:45:0;;;;;;;;;;148729:37;;21921:51:1;;;22008:2;21988:18;;;21981:30;;;22047:1;22027:18;;;22020:29;;;;-1:-1:-1;;;22080:3:1;22065:19;;22058:37;22147:18;;;22140:50;148729:37:0;;21959:3:1;22112:19;148729:37:0;;;;;;;;-1:-1:-1;148784:5:0;148288:509;;;;;:::o;161657:209::-;161762:16;;;161776:1;161762:16;;;;;;;;;161735:24;;161762:16;;;;;;;;;;;-1:-1:-1;161762:16:0;161735:43;;161802:6;161789:7;161797:1;161789:10;;;;;;;;:::i;:::-;;;;;;:19;-1:-1:-1;;;;;161789:19:0;;;-1:-1:-1;;;;;161789:19:0;;;;;161819:39;161829:7;161838;161847:4;161853;161819:9;:39::i;149568:234::-;149648:10;-1:-1:-1;;;;;149648:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;149634:32:0;:10;-1:-1:-1;;;;;149634:32:0;;149626:84;;;;-1:-1:-1;;;149626:84:0;;22667:2:1;149626:84:0;;;22649:21:1;22706:2;22686:18;;;22679:30;22745:34;22725:18;;;22718:62;-1:-1:-1;;;22796:18:1;;;22789:37;22843:19;;149626:84:0;22465:403:1;149626:84:0;149729:10;-1:-1:-1;;;;;149729:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:39;149721:73;;;;-1:-1:-1;;;149721:73:0;;23264:2:1;149721:73:0;;;23246:21:1;23303:2;23283:18;;;23276:30;-1:-1:-1;;;23322:18:1;;;23315:51;23383:18;;149721:73:0;23062:345:1;149721:73:0;149568:234;:::o;120867:648::-;-1:-1:-1;;;;;121142:15:0;;121026:4;121142:15;;;:7;:15;;;;;:24;;;121137:94;;-1:-1:-1;121195:23:0;121183:36;;121137:94;121280:22;121305:45;;;;;;;;121327:6;-1:-1:-1;;;;;121320:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121305:45;;121280:70;-1:-1:-1;121361:42:0;121383:6;121280:70;121361:21;:42::i;:::-;121414:53;121437:6;121445:8;121455:11;121414:22;:53::i;:::-;121492:14;121480:27;;;120867:648;;;;;;;:::o;164342:314::-;164420:21;:19;:21::i;:::-;164412:59;;;;-1:-1:-1;;;164412:59:0;;23746:2:1;164412:59:0;;;23728:21:1;23785:2;23765:18;;;23758:30;23824:27;23804:18;;;23797:55;23869:18;;164412:59:0;23544:349:1;164412:59:0;164482:15;164500:36;164518:9;164529:6;164500:17;:36::i;:::-;164482:54;-1:-1:-1;164555:15:0;;164547:55;;;;-1:-1:-1;;;164547:55:0;;24100:2:1;164547:55:0;;;24082:21:1;24139:2;24119:18;;;24112:30;24178:29;24158:18;;;24151:57;24225:18;;164547:55:0;23898:351:1;164547:55:0;164618:30;;;-1:-1:-1;;;;;24446:32:1;;24428:51;;24510:2;24495:18;;24488:34;;;164618:30:0;;24401:18:1;164618:30:0;;;;;;;164401:255;164342:314;;:::o;149191:369::-;149283:13;;149244:4;;-1:-1:-1;;;;;149283:13:0;149269:10;:27;;:50;;-1:-1:-1;149314:5:0;;-1:-1:-1;;;;;149314:5:0;149300:10;:19;149269:50;149261:102;;;;-1:-1:-1;;;149261:102:0;;;;;;;:::i;:::-;149396:5;;-1:-1:-1;;;;;149396:5:0;149382:10;:19;;:36;;-1:-1:-1;149414:4:0;149405:13;;;;149382:36;149374:71;;;;-1:-1:-1;;;149374:71:0;;;;;;;:::i;:::-;149458:19;:27;;;;;-1:-1:-1;;;149458:27:0;-1:-1:-1;;;;149458:27:0;;;;;;149501:28;;;;;;149480:5;;24757:2:1;24739:21;;;24796:1;24776:18;;;24769:29;-1:-1:-1;;;24829:2:1;24814:18;;24807:35;24923:14;;24916:22;24909:4;24894:20;;24887:52;24874:3;24859:19;;24533:412;149501:28:0;;;;;;;;-1:-1:-1;149547:5:0;149191:369::o;139314:423::-;139386:4;139456:5;;-1:-1:-1;;;;;139456:5:0;139442:10;:19;139434:63;;;;-1:-1:-1;;;139434:63:0;;25152:2:1;139434:63:0;;;25134:21:1;25191:2;25171:18;;;25164:30;25230:33;25210:18;;;25203:61;25281:18;;139434:63:0;24950:355:1;139434:63:0;139540:19;;;139570:44;;;;139630:59;;;18397:25:1;;;18453:2;18438:18;;18431:34;;;139630:59:0;;18370:18:1;139630:59:0;;;;;;;;139714:14;139709:20;139702:27;139314:423;-1:-1:-1;;;139314:423:0:o;146367:557::-;146470:5;;-1:-1:-1;;;;;146470:5:0;146456:10;:19;146448:70;;;;-1:-1:-1;;;146448:70:0;;25512:2:1;146448:70:0;;;25494:21:1;25551:2;25531:18;;;25524:30;25590:34;25570:18;;;25563:62;-1:-1:-1;;;25641:18:1;;;25634:36;25687:19;;146448:70:0;25310:402:1;146448:70:0;146614:17;;;-1:-1:-1;;;;;146712:40:0;;;-1:-1:-1;;;;;;146712:40:0;;;;;;;146852:64;;;146614:17;;;;25929:34:1;;;25994:2;25979:18;;25972:43;;;;146852:64:0;;25864:18:1;146852:64:0;;;;;;;146437:487;146367:557;:::o;147777:503::-;-1:-1:-1;;;;;147869:24:0;;147844:4;147869:24;;;:7;:24;;;;;:33;;;147861:86;;;;-1:-1:-1;;;147861:86:0;;;;;;;:::i;:::-;147980:13;;-1:-1:-1;;;;;147980:13:0;147966:10;:27;;:50;;-1:-1:-1;148011:5:0;;-1:-1:-1;;;;;148011:5:0;147997:10;:19;147966:50;147958:102;;;;-1:-1:-1;;;147958:102:0;;;;;;;:::i;:::-;148093:5;;-1:-1:-1;;;;;148093:5:0;148079:10;:19;;:36;;-1:-1:-1;148111:4:0;148102:13;;;;148079:36;148071:71;;;;-1:-1:-1;;;148071:71:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;148155:35:0;;;;;;:18;:35;;;;;;;;;:43;;-1:-1:-1;;148155:43:0;;;;;;;;;;148214:35;;26275:51:1;;;26362:2;26342:18;;;26335:30;;;26401:1;26381:18;;;26374:29;;;;-1:-1:-1;;;26434:3:1;26419:19;;26412:35;26499:18;;;26492:50;148214:35:0;;26313:3:1;26464:19;148214:35:0;26026:522:1;131980:408:0;132156:4;132162;132168;132186:9;132197:14;132213;132231:98;132271:7;132287:12;132302;132316;132231:39;:98::i;:::-;132185:144;;;;;;132353:3;132348:9;;;;;;;;:::i;:::-;132340:40;-1:-1:-1;132359:9:0;;-1:-1:-1;132370:9:0;-1:-1:-1;;131980:408:0;;;;;;;;;:::o;113468:605::-;-1:-1:-1;;;;;113671:26:0;;113565:4;113671:26;;;:18;:26;;;;;;;;113670:27;113662:54;;;;-1:-1:-1;;;113662:54:0;;26755:2:1;113662:54:0;;;26737:21:1;26794:2;26774:18;;;26767:30;-1:-1:-1;;;26813:18:1;;;26806:44;26867:18;;113662:54:0;26553:338:1;113662:54:0;-1:-1:-1;;;;;113809:15:0;;;;;;:7;:15;;;;;:24;;;113804:94;;113862:23;113857:29;113850:36;;;;113804:94;113947:29;113969:6;113947:21;:29::i;:::-;113987:38;114010:6;114018;113987:22;:38::i;:::-;114050:14;114038:27;113468:605;-1:-1:-1;;;;113468:605:0:o;142051:742::-;142141:4;142210:5;;-1:-1:-1;;;;;142210:5:0;142196:10;:19;142192:134;;142239:75;142244:18;142264:49;142239:4;:75::i;142192:134::-;142423:28;;;142519:62;;;;142656:89;;;18397:25:1;;;18453:2;18438:18;;18431:34;;;142656:89:0;;18370:18:1;142656:89:0;18223:248:1;116902:358:0;117160:17;;:37;;;;;117196:1;117181:12;:16;117160:37;117156:97;;;117214:27;;-1:-1:-1;;;117214:27:0;;27098:2:1;117214:27:0;;;27080:21:1;27137:2;27117:18;;;27110:30;-1:-1:-1;;;27156:18:1;;;27149:47;27213:18;;117214:27:0;26896:341:1;82964:26:0;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;82964:26:0;;-1:-1:-1;82964:26:0;:::o;138474:572::-;138538:4;138607:5;;-1:-1:-1;;;;;138607:5:0;138593:10;:19;138589:125;;138636:66;138641:18;138661:40;138636:4;:66::i;138589:125::-;138803:6;;;-1:-1:-1;;;;;138872:18:0;;;-1:-1:-1;;;;;;138872:18:0;;;;;;;138962:36;;;138803:6;;;;25929:34:1;;;25994:2;25979:18;;25972:43;;;;138962:36:0;;25864:18:1;138962:36:0;25717:304:1;165713:645:0;165810:21;:19;:21::i;:::-;165802:63;;;;-1:-1:-1;;;165802:63:0;;27793:2:1;165802:63:0;;;27775:21:1;27832:2;27812:18;;;27805:30;27871:31;27851:18;;;27844:59;27920:18;;165802:63:0;27591:353:1;165802:63:0;165973:37;165998:11;165973:24;:37::i;:::-;166025:14;166021:204;;-1:-1:-1;;;;;166095:33:0;;;;;;:20;:33;;;;;166088:40;166021:204;;;167262:12;-1:-1:-1;;;;;166161:33:0;;;;;;:20;:33;;;;;:52;166021:204;-1:-1:-1;;;;;166235:34:0;;;;;;:21;:34;;;;;;;:46;;;166299:51;;;;;166272:9;4611:25:1;;4599:2;4584:18;;4465:177;166299:51:0;;;;;;;;165713:645;;:::o;130583:277::-;130650:4;130656;130662;130680:9;130691:14;130707;130725:74;130765:7;130789:1;130794;130797;130725:39;:74::i;:::-;130679:120;;;;;;130825:3;130820:9;;;;;;;;:::i;:::-;130812:40;130831:9;;-1:-1:-1;130831:9:0;-1:-1:-1;130583:277:0;-1:-1:-1;;;130583:277:0:o;147162:607::-;147231:4;147266:5;;-1:-1:-1;;;;;147266:5:0;147252:10;:19;147248:127;;147295:68;147300:18;147320:42;147295:4;:68::i;147248:127::-;147466:13;;;-1:-1:-1;;;;;147552:32:0;;;-1:-1:-1;;;;;;147552:32:0;;;;;;;147672:49;;;147466:13;;;;25929:34:1;;;25994:2;25979:18;;25972:43;;;;147672:49:0;;25864:18:1;147672:49:0;25717:304:1;122758:1488:0;-1:-1:-1;;;;;123049:23:0;;122969:4;123049:23;;;:7;:23;;;;;:32;;;123048:33;;:72;;-1:-1:-1;;;;;;123086:25:0;;;;;;:7;:25;;;;;:34;;;123085:35;123048:72;123044:141;;;123149:23;123144:29;123137:36;;;;123044:141;123218:52;;-1:-1:-1;;;123218:52:0;;-1:-1:-1;;;;;5507:32:1;;;123218:52:0;;;5489:51:1;123197:18:0;;123218:42;;;;;;5462:18:1;;123218:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123197:73;;123362:36;123382:14;123362:12;:36::i;:::-;123358:843;;;123440:11;123423:13;:28;;123415:81;;;;-1:-1:-1;;;123415:81:0;;28151:2:1;123415:81:0;;;28133:21:1;28190:2;28170:18;;;28163:30;28229:34;28209:18;;;28202:62;-1:-1:-1;;;28280:18:1;;;28273:38;28328:19;;123415:81:0;27949:404:1;123415:81:0;123358:843;;;123610:9;123623:14;123641:37;123669:8;123641:27;:37::i;:::-;123609:69;;-1:-1:-1;123609:69:0;;-1:-1:-1;123704:14:0;;-1:-1:-1;123697:3:0;:21;;;;;;;;:::i;:::-;;123693:78;;123751:3;123746:9;;;;;;;;:::i;:::-;123739:16;;;;;;;123693:78;123791:14;123787:96;;123838:28;123833:34;;123787:96;123992:13;124008:71;124027:36;;;;;;;;124042:19;;124027:36;;;124065:13;124008:18;:71::i;:::-;123992:87;;124112:8;124098:11;:22;124094:96;;;124153:20;124141:33;;;;;;;;124094:96;123514:687;;;123358:843;124223:14;124211:27;;;122758:1488;;;;;;;;:::o;145594:603::-;145721:5;;-1:-1:-1;;;;;145721:5:0;145707:10;:19;;:54;;-1:-1:-1;145744:17:0;;-1:-1:-1;;;;;145744:17:0;145730:10;:31;145707:54;145699:120;;;;-1:-1:-1;;;145699:120:0;;28560:2:1;145699:120:0;;;28542:21:1;28599:2;28579:18;;;28572:30;28638:34;28618:18;;;28611:62;-1:-1:-1;;;28689:18:1;;;28682:51;28750:19;;145699:120:0;28358:417:1;145699:120:0;145850:7;145896:13;145937:15;;;;;:46;;;145970:13;145956:10;:27;145937:46;145929:72;;;;-1:-1:-1;;;145929:72:0;;28982:2:1;145929:72:0;;;28964:21:1;29021:2;29001:18;;;28994:30;-1:-1:-1;;;29040:18:1;;;29033:43;29093:18;;145929:72:0;28780:337:1;145929:72:0;146018:6;146014:176;146034:10;146030:1;:14;146014:176;;;146100:13;;146114:1;146100:16;;;;;;;:::i;:::-;;;;;;;146066:10;:31;146085:7;;146093:1;146085:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;146066:31:0;;;;;;;;;;;;-1:-1:-1;146066:31:0;:50;146149:7;;146157:1;146149:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;146136:42:0;;146161:13;;146175:1;146161:16;;;;;;;:::i;:::-;;;;;;;146136:42;;;;4611:25:1;;4599:2;4584:18;;4465:177;146136:42:0;;;;;;;;146046:3;;;;:::i;:::-;;;;146014:176;;;;145691:506;;145594:603;;;;:::o;162209:1098::-;162334:6;162329:812;162350:7;:14;162346:1;:18;162329:812;;;162386:13;162402:7;162410:1;162402:10;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;162435:24:0;;;;;;:7;:24;;;;;;;:33;162402:10;;-1:-1:-1;162435:33:0;;162427:67;;;;-1:-1:-1;;;162427:67:0;;29324:2:1;162427:67:0;;;29306:21:1;29363:2;29343:18;;;29336:30;-1:-1:-1;;;29382:18:1;;;29375:51;29443:18;;162427:67:0;29122:345:1;162427:67:0;162526:4;162513:17;;;;162509:357;;;162551:22;162576:37;;;;;;;;162591:6;-1:-1:-1;;;;;162591:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;162576:37;;162551:62;-1:-1:-1;162632:51:0;162662:6;162551:62;162632:21;:51::i;:::-;162707:6;162702:149;162723:7;:14;162719:1;:18;162702:149;;;162767:64;162798:6;162807:7;162815:1;162807:10;;;;;;;;:::i;:::-;;;;;;;162819:11;162767:22;:64::i;:::-;162739:3;;;;:::i;:::-;;;;162702:149;;;;162532:334;162509:357;162897:4;162884:17;;;;162880:250;;;162922:38;162952:6;162922:21;:38::i;:::-;162984:6;162979:136;163000:7;:14;162996:1;:18;162979:136;;;163044:51;163075:6;163084:7;163092:1;163084:10;;;;;;;;:::i;:::-;;;;;;;163044:22;:51::i;:::-;163016:3;;;;:::i;:::-;;;;162979:136;;;;162880:250;-1:-1:-1;162366:3:0;;;;:::i;:::-;;;;162329:812;;;;163156:6;163151:149;163172:7;:14;163168:1;:18;163151:149;;;163234:54;163252:7;163260:1;163252:10;;;;;;;;:::i;:::-;;;;;;;163264:11;:23;163276:7;163284:1;163276:10;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;163264:23:0;-1:-1:-1;;;;;163264:23:0;;;;;;;;;;;;;163234:17;:54::i;:::-;163208:11;:23;163220:7;163228:1;163220:10;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;163208:23:0;-1:-1:-1;;;;;163208:23:0;;;;;;;;;;;;:80;;;;163188:3;;;;;:::i;:::-;;;;163151:149;;160610:588;-1:-1:-1;;;;;160700:34:0;;160683:14;160700:34;;;:21;:34;;;;;;;;;160828:20;:33;;;;;;160700:34;;167262:12;;160810:52;;167262:12;;160810:4;:52::i;:::-;160791:71;;160891:1;160877:11;:15;:32;;;;;160908:1;160896:9;:13;160877:32;160873:318;;;160926:15;160944:28;160949:11;160962:9;160944:4;:28::i;:::-;-1:-1:-1;;;;;161018:24:0;;160987:23;161018:24;;;:11;:24;;;;;;160926:46;;-1:-1:-1;160987:23:0;161013:42;;160926:46;161013:4;:42::i;:::-;-1:-1:-1;;;;;161072:24:0;;;;;;:11;:24;;;;;;;;:45;;;;161132:20;:33;;;:47;;;-1:-1:-1;;160672:526:0;;;160610:588;:::o;148805:378::-;148900:13;;148861:4;;-1:-1:-1;;;;;148900:13:0;148886:10;:27;;:50;;-1:-1:-1;148931:5:0;;-1:-1:-1;;;;;148931:5:0;148917:10;:19;148886:50;148878:102;;;;-1:-1:-1;;;148878:102:0;;;;;;;:::i;:::-;149013:5;;-1:-1:-1;;;;;149013:5:0;148999:10;:19;;:36;;-1:-1:-1;149031:4:0;149022:13;;;;148999:36;148991:71;;;;-1:-1:-1;;;148991:71:0;;;;;;;:::i;:::-;149075:22;:30;;;;;-1:-1:-1;;;149075:30:0;-1:-1:-1;;;;149075:30:0;;;;;;149121:31;;;;;;149100:5;;29696:2:1;29678:21;;;29735:1;29715:18;;;29708:29;-1:-1:-1;;;29768:2:1;29753:18;;29746:38;29865:14;;29858:22;29851:4;29836:20;;29829:52;29816:3;29801:19;;29472:415;166891:284:0;-1:-1:-1;;;;;166986:24:0;;166949:4;166986:24;;;:7;:24;;;;;:49;;;:54;:116;;;;-1:-1:-1;;;;;;167057:37:0;;;;;;:20;:37;;;;;;;;:45;;:37;:45;166986:116;:171;;;;;167119:6;-1:-1:-1;;;;;167119:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;167153:4;167119:38;166966:191;166891:284;-1:-1:-1;;166891:284:0:o;143120:853::-;143177:4;143212:5;;-1:-1:-1;;;;;143212:5:0;143198:10;:19;143194:123;;143241:64;143246:18;143266:38;143241:4;:64::i;143194:123::-;-1:-1:-1;;;;;143333:24:0;;;;;;:7;:24;;;;;:33;;;143329:141;;;143390:68;143395:27;143424:33;143390:4;:68::i;143329:141::-;143482:6;-1:-1:-1;;;;;143482:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;;143648:24:0;;143621;143648;;;:7;:24;;;;;143683:25;;143704:4;-1:-1:-1;;143683:25:0;;;;;;;143719:18;;;:26;;;;;;;;143756:34;;:38;;;;143807:35;143648:24;143807:18;:35::i;:::-;143853:34;143879:6;143853:17;:34::i;:::-;143905:20;;-1:-1:-1;;;;;5507:32:1;;5489:51;;143905:20:0;;5477:2:1;5462:18;143905:20:0;5343:203:1;164992:513:0;165123:21;:19;:21::i;:::-;165115:63;;;;-1:-1:-1;;;165115:63:0;;27793:2:1;165115:63:0;;;27775:21:1;27832:2;27812:18;;;27805:30;27871:31;27851:18;;;27844:59;27920:18;;165115:63:0;27591:353:1;165115:63:0;165208:14;;165254:19;;165241:32;;:68;;;;;165290:12;:19;165277:9;:32;165241:68;165233:122;;;;-1:-1:-1;;;165233:122:0;;30344:2:1;165233:122:0;;;30326:21:1;30383:2;30363:18;;;30356:30;30422:34;30402:18;;;30395:62;-1:-1:-1;;;30473:18:1;;;30466:39;30522:19;;165233:122:0;30142:405:1;165233:122:0;165373:6;165368:130;165389:9;165385:1;:13;165368:130;;;165420:66;165441:7;165449:1;165441:10;;;;;;;;:::i;:::-;;;;;;;165453:12;165466:1;165453:15;;;;;;;;:::i;:::-;;;;;;;165470:12;165483:1;165470:15;;;;;;;;:::i;:::-;;;;;;;165420:20;:66::i;:::-;165400:3;;;:::i;:::-;;;165368:130;;107841:174;-1:-1:-1;;;;;107957:22:0;;107930:24;107957:22;;;:13;:22;;;;;;;;107930:49;;;;;;;;;;;;;;;;;107902:15;;107930:24;:49;;107957:22;107930:49;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;107930:49:0;;;;;;;;;;;;;;;;-1:-1:-1;107930:49:0;;107841:174;-1:-1:-1;;;;;;;107841:174:0:o;166549:99::-;166595:15;166630:10;166623:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;166623:17:0;;;;;;;;;;;;;;;;;;;;;;;166549:99;:::o;128131:773::-;128352:22;;128246:4;;-1:-1:-1;;;128352:22:0;;;;128351:23;128343:54;;;;-1:-1:-1;;;128343:54:0;;30754:2:1;128343:54:0;;;30736:21:1;30793:2;30773:18;;;30766:30;-1:-1:-1;;;30812:18:1;;;30805:48;30870:18;;128343:54:0;30552:342:1;128343:54:0;128532:12;128547:50;128569:6;128577:3;128582:14;128547:21;:50::i;:::-;128532:65;-1:-1:-1;128612:31:0;;128608:78;;128667:7;-1:-1:-1;128660:14:0;;128608:78;128735:29;128757:6;128735:21;:29::i;:::-;128775:35;128798:6;128806:3;128775:22;:35::i;:::-;128821;128844:6;128852:3;128821:22;:35::i;108721:388::-;108831:14;;108794:13;;108820:8;108831:14;108882:15;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;108882:15:0;;108858:39;;108913:6;108908:167;108929:3;108925:1;:7;108908:167;;;108954:13;108977:7;108985:1;108977:10;;;;;;;;:::i;:::-;;;;;;;108954:34;;109023:39;109043:6;109051:10;109023:19;:39::i;:::-;109018:45;;;;;;;;:::i;:::-;109005:7;109013:1;109005:10;;;;;;;;:::i;:::-;;;;;;;;;;:58;-1:-1:-1;108934:3:0;;;;:::i;:::-;;;;108908:167;;;-1:-1:-1;109094:7:0;108721:388;-1:-1:-1;;;108721:388:0:o;136646:1563::-;136913:6;;;:49;;-1:-1:-1;;;136913:49:0;;-1:-1:-1;;;;;5507:32:1;;;136913:49:0;;;5489:51:1;;;;136791:4:0;;;;;;136913:6;;;:25;;5462:18:1;;136913:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;137004:6;;;:51;;-1:-1:-1;;;137004:51:0;;-1:-1:-1;;;;;5507:32:1;;;137004:51:0;;;5489::1;;;;136884:78:0;;-1:-1:-1;136973:28:0;;137004:6;;;:25;;5462:18:1;;137004:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;136973:82;-1:-1:-1;137070:26:0;;;:58;;-1:-1:-1;137100:28:0;;137070:58;137066:126;;;137158:17;137178:1;137145:35;;;;;;;;137066:126;137585:25;137620:16;-1:-1:-1;;;;;137613:43:0;;:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;137585:73;;137695:16;137722:20;-1:-1:-1;;;;;;;;;;;;;;137722:20:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;137832:45:0;;;;;;;137847:28;;137832:45;;137879:38;;;;;;;;;;;-1:-1:-1;;137827:91:0;;:4;:91::i;:::-;137815:103;;137943:85;137948:40;;;;;;;;137963:23;137948:40;;;137990:37;;;;;;;;138005:20;137990:37;;;137943:4;:85::i;:::-;137929:99;;138047:28;138052:9;138063:11;138047:4;:28::i;:::-;138039:36;;138102:44;138121:5;138128:17;138102:18;:44::i;:::-;138172:14;;-1:-1:-1;138088:58:0;-1:-1:-1;;;;;;;;136646:1563:0;;;;;;;:::o;125738:981::-;126045:19;;125939:4;;-1:-1:-1;;;126045:19:0;;;;126044:20;126036:48;;;;-1:-1:-1;;;126036:48:0;;31101:2:1;126036:48:0;;;31083:21:1;31140:2;31120:18;;;31113:30;-1:-1:-1;;;31159:18:1;;;31152:45;31214:18;;126036:48:0;30899:339:1;126036:48:0;-1:-1:-1;;;;;126161:25:0;;;;;;:7;:25;;;;;:34;;;126160:35;;:72;;-1:-1:-1;;;;;;126200:23:0;;;;;;:7;:23;;;;;:32;;;126199:33;126160:72;126156:141;;;126261:23;126256:29;;126156:141;126362:14;-1:-1:-1;;;;;126355:34:0;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;126313:78:0;126320:16;-1:-1:-1;;;;;126313:36:0;;:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;126313:78:0;;126309:150;;126420:26;126415:32;;126309:150;126508:39;126530:16;126508:21;:39::i;:::-;126558:50;126581:16;126599:8;126558:22;:50::i;:::-;126619:52;126642:16;126660:10;126619:22;:52::i;:::-;126696:14;126684:27;125738:981;-1:-1:-1;;;;;;125738:981:0:o;117701:2031::-;-1:-1:-1;;;;;117910:28:0;;117804:4;117910:28;;;:20;:28;;;;;;;;117909:29;117901:58;;;;-1:-1:-1;;;117901:58:0;;31737:2:1;117901:58:0;;;31719:21:1;31776:2;31756:18;;;31749:30;-1:-1:-1;;;31795:18:1;;;31788:46;31851:18;;117901:58:0;31535:340:1;117901:58:0;-1:-1:-1;;;;;117977:15:0;;;;;;:7;:15;;;;;:24;;;117972:94;;118030:23;118025:29;;117972:94;-1:-1:-1;;;;;118083:15:0;;;;;;;:7;:15;;;;;;;;:43;;;;;:33;;;;:43;;;;;;118078:574;;118229:10;-1:-1:-1;;;;;118229:20:0;;;118221:54;;;;-1:-1:-1;;;118221:54:0;;32082:2:1;118221:54:0;;;32064:21:1;32121:2;32101:18;;;32094:30;-1:-1:-1;;;32140:18:1;;;32133:51;32201:18;;118221:54:0;31880:345:1;118221:54:0;118346:9;118358:49;118385:10;118398:8;118358:19;:49::i;:::-;118346:61;-1:-1:-1;118433:14:0;118426:3;:21;;;;;;;;:::i;:::-;;118422:78;;118480:3;118475:9;;;;;;;;:::i;:::-;118468:16;;;;;118422:78;-1:-1:-1;;;;;118596:15:0;;;;;;;:7;:15;;;;;;;;:43;;;;;:33;;;;:43;;;;;;118589:51;;;;:::i;:::-;118128:524;118078:574;118668:6;;;:41;;-1:-1:-1;;;118668:41:0;;-1:-1:-1;;;;;5507:32:1;;;118668:41:0;;;5489:51:1;;;;118668:6:0;;;:25;;5462:18:1;;118668:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;118664:109;;118743:17;118738:23;;118664:109;-1:-1:-1;;;;;118804:18:0;;118787:14;118804:18;;;:10;:18;;;;;;118900:14;;118896:248;;118931:17;118958:6;-1:-1:-1;;;;;118951:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;118931:49;;118995:21;119019:32;119024:12;119038;119019:4;:32::i;:::-;118995:56;;119093:9;119074:16;:28;119066:66;;;;-1:-1:-1;;;119066:66:0;;32564:2:1;119066:66:0;;;32546:21:1;32603:2;32583:18;;;32576:30;32642:27;32622:18;;;32615:55;32687:18;;119066:66:0;32362:349:1;119066:66:0;118916:228;;118896:248;119157:9;119170:14;119188:82;119228:8;119245:6;119254:1;119257:12;119188:39;:82::i;:::-;119156:114;;-1:-1:-1;119156:114:0;;-1:-1:-1;119292:14:0;;-1:-1:-1;119285:3:0;:21;;;;;;;;:::i;:::-;;119281:70;;119335:3;119330:9;;;;;;;;:::i;:::-;119323:16;;;;;;;119281:70;119365:13;;119361:87;;119407:28;119402:34;;119361:87;119497:22;119522:45;;;;;;;;119544:6;-1:-1:-1;;;;;119537:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;119522:45;;119497:70;-1:-1:-1;119578:42:0;119600:6;119497:70;119578:21;:42::i;:::-;119631:53;119654:6;119662:8;119672:11;119631:22;:53::i;:::-;119709:14;119697:27;117701:2031;-1:-1:-1;;;;;;;;117701:2031:0:o;81174:49::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81174:49:0;;-1:-1:-1;81174:49:0;;-1:-1:-1;81174:49:0:o;140111:1639::-;140208:4;140277:5;;-1:-1:-1;;;;;140277:5:0;140263:10;:19;140259:130;;140306:71;140311:18;140331:45;140306:4;:71::i;:::-;140299:78;;;;140259:130;-1:-1:-1;;;;;140461:24:0;;140437:21;140461:24;;;:7;:24;;;;;140501:15;;;;140496:130;;140540:74;140545:23;140570:43;140540:4;:74::i;:::-;140533:81;;;;;140496:130;140674:44;;;;;;;;;;;;140797;;;;;;;;107509:6;140797:44;;140674;140856:46;140797:44;140674;25467:14;25451:13;;:30;;25348:141;140856:46;140852:169;;;140926:83;140931:31;140964:44;140926:4;:83::i;:::-;140919:90;;;;;;;140852:169;141095:32;;;;;:74;;-1:-1:-1;141131:6:0;;;:33;;-1:-1:-1;;;141131:33:0;;-1:-1:-1;;;;;5507:32:1;;;141131:33:0;;;5489:51:1;;;;141131:6:0;;;:25;;5462:18:1;;141131:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:38;141095:74;141091:186;;;141193:72;141198:17;141217:47;141193:4;:72::i;141091:186::-;141412:31;;;;;141454:61;;;;141617:85;;;-1:-1:-1;;;;;32951:32:1;;32933:51;;33015:2;33000:18;;32993:34;;;33043:18;;;33036:34;;;141617:85:0;;32921:2:1;32906:18;141617:85:0;;;;;;;141727:14;141715:27;140111:1639;-1:-1:-1;;;;;;;140111:1639:0:o;161344:97::-;161404:29;161414:6;161422:10;161404:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;161404:29:0;;;;;;;;;;;;;;;;;;;;;:9;:29::i;115227:454::-;115330:4;115347:12;115362:53;115384:6;115392:8;115402:12;115362:21;:53::i;:::-;115347:68;-1:-1:-1;115430:31:0;;115426:78;;115485:7;-1:-1:-1;115478:14:0;;115426:78;115553:29;115575:6;115553:21;:29::i;:::-;115593:40;115616:6;115624:8;115593:22;:40::i;:::-;115658:14;115646:27;115227:454;-1:-1:-1;;;;;115227:454:0:o;110806:2183::-;111070:37;;-1:-1:-1;;;111070:37:0;;111096:10;111070:37;;;5489:51:1;110876:4:0;;110916:13;;110876:4;;;;;;-1:-1:-1;;;;;111070:25:0;;;;;5462:18:1;;111070:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;111020:87;;;;;;;111126:4;111134:1;111126:9;111118:59;;;;-1:-1:-1;;;111118:59:0;;33656:2:1;111118:59:0;;;33638:21:1;33695:2;33675:18;;;33668:30;33734:34;33714:18;;;33707:62;-1:-1:-1;;;33785:18:1;;;33778:35;33830:19;;111118:59:0;33454:401:1;111118:59:0;111275:15;;111271:127;;111314:72;111319:28;111349:36;111314:4;:72::i;:::-;111307:79;110806:2183;-1:-1:-1;;;;;;110806:2183:0:o;111271:127::-;111491:12;111506:60;111528:13;111543:10;111555;111506:21;:60::i;:::-;111491:75;-1:-1:-1;111581:12:0;;111577:123;;111617:71;111628:15;111645:33;111680:7;111617:10;:71::i;:::-;111610:78;110806:2183;-1:-1:-1;;;;;;;110806:2183:0:o;111577:123::-;-1:-1:-1;;;;;111742:24:0;;111712:27;111742:24;;;:7;:24;;;;;;;;111891:10;111860:42;;:30;;;:42;;;;;;;;;111855:103;;111931:14;111919:27;110806:2183;-1:-1:-1;;;;;;;;110806:2183:0:o;111855:103::-;112062:10;112031:42;;;;:30;;;:42;;;;;;;;112024:49;;-1:-1:-1;;112024:49:0;;;112233:13;:25;;;;;112201:57;;;;;;;;;;;;;;;;;;;112233:25;;112201:57;;;112233:25;112201:57;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;112201:57:0;;;;;;;;;;;;;;;;-1:-1:-1;;112280:20:0;;112201:57;;-1:-1:-1;112280:20:0;;-1:-1:-1;112269:8:0;;-1:-1:-1;;112343:162:0;112364:3;112360:1;:7;112343:162;;;112413:6;-1:-1:-1;;;;;112393:26:0;:13;112407:1;112393:16;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;112393:26:0;;112389:105;;;112453:1;112440:14;;112473:5;;112389:105;112369:3;;;;:::i;:::-;;;;112343:162;;;;112634:3;112621:10;:16;112614:24;;;;:::i;:::-;112784:10;112740:27;112770:25;;;:13;:25;;;;;112842:17;;112770:25;;112842:21;;112862:1;;112842:21;:::i;:::-;112831:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;112831:33:0;112806:10;112817;112806:22;;;;;;;;:::i;:::-;;;;;;;;;:58;;;;;-1:-1:-1;;;;;112806:58:0;;;;;-1:-1:-1;;;;;112806:58:0;;;;;;112875:10;:16;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;112875:16:0;;;;;-1:-1:-1;;;;;;112875:16:0;;;;;;112909:32;;;;;;112922:6;;112930:10;;-1:-1:-1;;;;;25947:15:1;;;25929:34;;25999:15;;25994:2;25979:18;;25972:43;25879:2;25864:18;;25717:304;112909:32:0;;;;;;;;112966:14;112954:27;110806:2183;-1:-1:-1;;;;;;;;;;;;110806:2183:0:o;26785:90::-;26838:4;26862:5;26866:1;26862;:5;:::i;27207:90::-;27260:4;27284:5;27288:1;27284;:5;:::i;155345:980::-;-1:-1:-1;;;;;155480:23:0;;155442:35;155480:23;;;:15;:23;;;;;;;;155533:16;:24;;;;;;155480:23;;155589:56;167262:12;155596:16;155589:56;;;;;;;;;;;;;;;;;:6;:56::i;:::-;155704:17;;155568:77;;-1:-1:-1;155656:16:0;;155675:48;;155680:17;;;;;-1:-1:-1;;;155704:17:0;;;155675:4;:48::i;:::-;155656:67;;155752:1;155738:11;:15;:34;;;;;155771:1;155757:11;:15;155738:34;155734:584;;;155789:17;155809:54;155821:6;-1:-1:-1;;;;;155814:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;155845:17;155809:4;:54::i;:::-;155789:74;;155878:16;155897:30;155902:11;155915;155897:4;:30::i;:::-;155878:49;;155942:19;155979:1;155964:12;:16;:78;;156021:21;;;;;;;;156039:1;156021:21;;;155964:78;;;155983:35;155992:11;156005:12;155983:8;:35::i;:::-;156090:37;;;;;;;;;156108:17;;-1:-1:-1;;;;;156108:17:0;156090:37;;155942:100;;-1:-1:-1;156077:98:0;;156085:50;;155942:100;156085:4;:50::i;:::-;:59;156077:98;;;;;;;;;;;;;;;;;:7;:98::i;:::-;-1:-1:-1;;;;;156057:118:0;-1:-1:-1;;;156190:31:0;;;;;;;-1:-1:-1;155734:584:0;;-1:-1:-1;;155734:584:0;;156243:15;;156239:79;;156275:31;;;;;-1:-1:-1;;;156275:31:0;-1:-1:-1;;;;;156275:31:0;;;;;;155431:894;;;;155345:980;;:::o;158640:1781::-;-1:-1:-1;;;;;159093:23:0;;;159055:35;159093:23;;;:15;:23;;;;;;;;159146:17;;159195;:25;;;;;:35;;;;;;;;;;;;;;-1:-1:-1;;;;;159146:17:0;;;159340:49;;;;159093:23;;159406:18;;:53;;;;-1:-1:-1;;;;159428:31:0;;;159406:53;159402:364;;;-1:-1:-1;;;;159402:364:0;159867:24;159894:52;;;;;;;;159912:32;159917:11;159930:13;159912:4;:32::i;:::-;159894:52;;159986:44;;-1:-1:-1;;;159986:44:0;;-1:-1:-1;;;;;5507:32:1;;;159986:44:0;;;5489:51:1;159867:79:0;;-1:-1:-1;159959:19:0;;159981:69;;159986:34;;;;;;5462:18:1;;159986:44:0;;;;;;;;;;;;;;;;;;;;;;159981:69;159959:91;;160137:18;160158:32;160163:14;160179:10;160158:4;:32::i;:::-;-1:-1:-1;;;;;160231:21:0;;160203:20;160231:21;;;:11;:21;;;;;;160137:53;;-1:-1:-1;160203:20:0;160226:42;;160137:53;160226:4;:42::i;:::-;-1:-1:-1;;;;;160279:21:0;;;;;;;:11;:21;;;;;;;;;:39;;;160336:77;;18397:25:1;;;18438:18;;;18431:34;;;160279:39:0;;-1:-1:-1;160279:21:0;;160336:77;;;;;;18370:18:1;160336:77:0;;;;;;;158745:1676;;;;;;;158640:1781;;;:::o;152154:148::-;152208:4;152246:5;;-1:-1:-1;;;;;152246:5:0;152232:10;:19;;:62;;-1:-1:-1;152269:25:0;;-1:-1:-1;;;;;152269:25:0;152255:10;:39;152232:62;152225:69;;152154:148;:::o;163660:346::-;163732:4;;167479:42;163815:29;;-1:-1:-1;;;163815:29:0;;163838:4;163815:29;;;5489:51:1;163749:34:0;;-1:-1:-1;163794:18:0;;-1:-1:-1;;;;;163815:14:0;;;;;5462:18:1;;163815:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;163794:50;;163868:1;163859:6;:10;:37;;;;;163883:13;163873:6;:23;;163859:37;163855:120;;;163913:27;;-1:-1:-1;;;163913:27:0;;-1:-1:-1;;;;;24446:32:1;;;163913:27:0;;;24428:51:1;24495:18;;;24488:34;;;163913:13:0;;;;;24401:18:1;;163913:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;163962:1;163955:8;;;;;;163855:120;-1:-1:-1;163992:6:0;;163660:346;-1:-1:-1;;;163660:346:0:o;133167:2941::-;133352:5;133359:4;133365;133384:37;;:::i;:::-;-1:-1:-1;;;;;133561:22:0;;133469:9;133561:22;;;:13;:22;;;;;;;;133536:47;;;;;;;;;;;;;;;;;133469:9;;133536:47;;133561:22;133536:47;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;133536:47:0;;;;;;;;;;;;;;;;;;;;;;;133599:6;133594:2163;133615:6;:13;133611:1;:17;133594:2163;;;133650:12;133665:6;133672:1;133665:9;;;;;;;;:::i;:::-;;;;;;;;;;;133835:33;;-1:-1:-1;;;133835:33:0;;-1:-1:-1;;;;;5507:32:1;;;133835:33:0;;;5489:51:1;133665:9:0;;-1:-1:-1;133835:24:0;;;;;;5462:18:1;;133835:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;133806:25;;;133759:109;133786:18;;;133759:109;133766:18;;;133759:109;;-1:-1:-1;133887:9:0;;133883:166;;134006:20;134028:1;134031;133998:35;;;;;;;;;;;;;133883:166;134087:65;;;;;;;;;-1:-1:-1;;;;;134102:23:0;;;-1:-1:-1;134102:23:0;;;:7;:23;;;;;:48;;;134087:65;;134063:21;;;:89;;;;134187:42;;;;;;;-1:-1:-1;;;134202:25:0;134187:42;;134167:17;;;:62;134327:6;;;:32;;-1:-1:-1;;;134327:32:0;;;;;5489:51:1;;;;134327:32:0;;:6;;;:25;;5462:18:1;;;;;134087:65:0;134327:32;;;;;:6;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;134300:24;;;:59;;;134374:102;;134436:17;134455:1;134458;134428:32;;;;;;;;;;;;;134374:102;134509:41;;;;;;;;;134524:24;;;;134509:41;;134490:16;;;:60;134692:21;;;;134715:17;;;;134682:70;;134687:46;;:4;:46::i;:::-;134735:4;:16;;;134682:4;:70::i;:::-;134661:18;;;:91;;;134899:18;;;;134919;;134853:85;;134661:91;134899:18;134853:25;:85::i;:::-;134832:106;;135077:16;;;;135095:18;;;;135115:25;;;;135051:90;;135077:16;135095:18;135051:25;:90::i;:::-;135023:25;;;:118;-1:-1:-1;;;;;135229:21:0;;;;;;;135225:521;;;135406:86;135432:4;:18;;;135452:12;135466:4;:25;;;135406;:86::i;:::-;135378:25;;;:114;;;135672:16;;;;135646:84;;135690:12;;135646:25;:84::i;:::-;135618:25;;;:112;135225:521;-1:-1:-1;133630:3:0;;;;:::i;:::-;;;;133594:2163;;;-1:-1:-1;135866:25:0;;;;135845:18;;:46;135841:260;;;135953:25;;;;135932:18;;135916:14;;135932:46;;;:::i;:::-;135980:1;135908:74;;;;;;;;;;;135841:260;136023:14;136039:1;136070:4;:18;;;136042:4;:25;;;:46;;;;:::i;:::-;136015:74;;;;;;;;;;;154191:924;-1:-1:-1;;;;;154296:23:0;;154258:35;154296:23;;;:15;:23;;;;;;;;154349:16;:24;;;;;;154296:23;;154405:56;167262:12;154412:16;167183:99;154405:56;154520:17;;154384:77;;-1:-1:-1;154472:16:0;;154491:48;;154496:17;;;;;-1:-1:-1;;;154520:17:0;;;154491:4;:48::i;:::-;154472:67;;154568:1;154554:11;:15;:34;;;;;154587:1;154573:11;:15;154554:34;154550:558;;;154605:17;154632:6;-1:-1:-1;;;;;154625:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;154605:48;;154668:16;154687:30;154692:11;154705;154687:4;:30::i;:::-;154668:49;;154732:19;154769:1;154754:12;:16;:78;;154811:21;;;;;;;;154829:1;154811:21;;;154754:78;;;154773:35;154782:11;154795:12;154773:8;:35::i;:::-;154880:37;;;;;;;;;154898:17;;-1:-1:-1;;;;;154898:17:0;154880:37;;154732:100;;-1:-1:-1;154867:98:0;;154875:50;;154732:100;154875:4;:50::i;154867:98::-;-1:-1:-1;;;;;154847:118:0;-1:-1:-1;;;154980:31:0;;;;;;;-1:-1:-1;154550:558:0;;-1:-1:-1;;154550:558:0;;155033:15;;155029:79;;155065:31;;;;;-1:-1:-1;;;155065:31:0;-1:-1:-1;;;;;155065:31:0;;;;;;154247:868;;;;154191:924;:::o;156581:1702::-;-1:-1:-1;;;;;157004:23:0;;;156966:35;157004:23;;;:15;:23;;;;;;;;157057:17;;157106;:25;;;;;:35;;;;;;;;;;;;;;-1:-1:-1;;;;;157057:17:0;;;157250:49;;;;157004:23;;157316:18;;:53;;;;-1:-1:-1;;;;157338:31:0;;;157316:53;157312:364;;;-1:-1:-1;;;;157312:364:0;157770:24;157797:52;;;;;;;;157815:32;157820:11;157833:13;157815:4;:32::i;:::-;157797:52;;157884:34;;-1:-1:-1;;;157884:34:0;;-1:-1:-1;;;;;5507:32:1;;;157884:34:0;;;5489:51:1;157770:79:0;;-1:-1:-1;157862:19:0;;157884:24;;;;;5462:18:1;;157884:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;157862:56;;157999:18;158020:32;158025:14;158041:10;158020:4;:32::i;:::-;-1:-1:-1;;;;;158093:21:0;;158065:20;158093:21;;;:11;:21;;;;;;157999:53;;-1:-1:-1;158065:20:0;158088:42;;157999:53;158088:4;:42::i;:::-;-1:-1:-1;;;;;158141:21:0;;;;;;;:11;:21;;;;;;;;;:39;;;158198:77;;18397:25:1;;;18438:18;;;18431:34;;;158141:39:0;;-1:-1:-1;158141:21:0;;158198:77;;;;;;18370:18:1;158198:77:0;;;;;;;156656:1627;;;;;;;156581:1702;;:::o;8679:153::-;8740:4;8762:33;8775:3;8770:9;;;;;;;;:::i;:::-;8786:4;8781:10;;;;;;;;:::i;:::-;8762:33;;;8531:25:1;;;8587:2;8572:18;;8565:34;;;;8793:1:0;8615:18:1;;;8608:34;8519:2;8504:18;8762:33:0;;;;;;;8820:3;8815:9;;;;;;;;:::i;131147:196::-;131224:5;131231:4;131237;131261:74;131301:7;131325:1;131330;131333;131261:39;:74::i;:::-;131254:81;;;;;;131147:196;;;;;:::o;24737:174::-;24815:4;24832:18;24853:15;24858:1;24861:6;24853:4;:15::i;:::-;24832:36;;24886:17;24895:7;24886:8;:17::i;28209:90::-;28262:4;28286:5;28290:1;28286;:5;:::i;143981:250::-;144050:6;144045:137;144066:10;:17;144062:21;;144045:137;;;144138:6;-1:-1:-1;;;;;144114:31:0;:10;144125:1;144114:13;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;144114:13:0;:31;;144106:64;;;;-1:-1:-1;;;144106:64:0;;35156:2:1;144106:64:0;;;35138:21:1;35195:2;35175:18;;;35168:30;-1:-1:-1;;;35214:18:1;;;35207:50;35274:18;;144106:64:0;34954:344:1;144106:64:0;144085:4;;;;:::i;:::-;;;;144045:137;;;-1:-1:-1;144192:10:0;:31;;;;;;;-1:-1:-1;144192:31:0;;;;;;;;-1:-1:-1;;;;;;144192:31:0;-1:-1:-1;;;;;144192:31:0;;;;;;;;;;143981:250::o;144239:831::-;144302:18;144323:56;167262:12;144330:16;167183:99;144323:56;-1:-1:-1;;;;;144430:23:0;;144392:35;144430:23;;;:15;:23;;;;;;;;144502:15;:23;;;;;;144607:17;;144302:77;;-1:-1:-1;144430:23:0;;-1:-1:-1;;;;;144607:17:0;144603:156;;144711:36;;-1:-1:-1;;;;;;144711:36:0;-1:-1:-1;;;144711:36:0;;;144603:156;144775:17;;-1:-1:-1;;;;;144775:17:0;144771:156;;144879:36;;-1:-1:-1;;;;;;144879:36:0;-1:-1:-1;;;144879:36:0;;;144771:156;145031:31;;;;;;-1:-1:-1;;;145031:31:0;-1:-1:-1;;;;;145031:31:0;;;;;;;;145011:51;;;;;;;;;;-1:-1:-1;144239:831:0:o;152604:1357::-;-1:-1:-1;;;;;152729:24:0;;152705:21;152729:24;;;:7;:24;;;;;152772:15;;;;152764:53;;;;-1:-1:-1;;;152764:53:0;;35505:2:1;152764:53:0;;;35487:21:1;35544:2;35524:18;;;35517:30;35583:27;35563:18;;;35556:55;35628:18;;152764:53:0;35303:349:1;152764:53:0;-1:-1:-1;;;;;152834:33:0;;;;;;:16;:33;;;;;;:48;;152830:511;;153120:38;153150:6;153120:21;:38::i;:::-;-1:-1:-1;;;;;153219:33:0;;;;;;:16;:33;;;;;;;:47;;;153286:43;;;;;153255:11;4611:25:1;;4599:2;4584:18;;4465:177;153286:43:0;;;;;;;;152830:511;-1:-1:-1;;;;;153357:33:0;;;;;;:16;:33;;;;;;:48;;153353:601;;153643:22;153668:37;;;;;;;;153683:6;-1:-1:-1;;;;;153683:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;153668:37;;153643:62;-1:-1:-1;153720:51:0;153750:6;153643:62;153720:21;:51::i;:::-;-1:-1:-1;;;;;153832:33:0;;;;;;:16;:33;;;;;;;:47;;;153899:43;;;;;153868:11;4611:25:1;;4599:2;4584:18;;4465:177;153899:43:0;;;;;;;;153407:547;152694:1267;152604:1357;;;:::o;115689:871::-;-1:-1:-1;;;;;115818:15:0;;115796:4;115818:15;;;:7;:15;;;;;:24;;;115813:94;;115871:23;115866:29;;115813:94;-1:-1:-1;;;;;116018:15:0;;;;;;;:7;:15;;;;;;;;:43;;;;;:33;;;;:43;;;;;;116013:104;;116090:14;116085:20;;116013:104;116222:9;116235:14;116253:82;116293:8;116310:6;116319:12;116333:1;116253:39;:82::i;:::-;116221:114;;-1:-1:-1;116221:114:0;;-1:-1:-1;116357:14:0;;-1:-1:-1;116350:3:0;:21;;;;;;;;:::i;:::-;;116346:70;;116400:3;116395:9;;;;;;;;:::i;:::-;116388:16;;;;;;116346:70;116430:13;;116426:87;;116472:28;116467:34;;109395:1018;-1:-1:-1;;;;;109523:24:0;;109475:5;109523:24;;;:7;:24;;;;;109565:21;;;;109560:135;;109660:23;109653:30;;;;;109560:135;-1:-1:-1;;;;;109711:40:0;;;;;;:30;;;:40;;;;;;;;:48;;:40;:48;109707:133;;;109814:14;109807:21;;;;;109707:133;-1:-1:-1;;;;;110228:40:0;;;;;;;:30;;;:40;;;;;;;;:47;;110271:4;-1:-1:-1;;110228:47:0;;;;;;;;110286:13;:23;;;;;:36;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;110286:36:0;;;;;;;;;110340:31;;25929:34:1;;;25979:18;;25972:43;;;;110340:31:0;;25864:18:1;110340:31:0;;;;;;;-1:-1:-1;110391:14:0;;109395:1018;-1:-1:-1;;;109395:1018:0:o;27305:159::-;-1:-1:-1;;;;;;;;;;;;27400:56:0;;;;;;;;24015:4;27415:28;27420:1;:10;;;27432:1;:10;;;27415:4;:28::i;:::-;:39;;;;:::i;:::-;27400:56;;27393:63;27305:159;-1:-1:-1;;;27305:159:0:o;28307:164::-;-1:-1:-1;;;;;;;;;;;;28402:61:0;;;;;;;;28417:44;28422:26;28427:1;:10;;;24015:4;28422;:26::i;:::-;28450:10;;28417:4;:44::i;8955:187::-;9040:4;9062:43;9075:3;9070:9;;;;;;;;:::i;:::-;9086:4;9081:10;;;;;;;;:::i;:::-;9062:43;;;8531:25:1;;;8587:2;8572:18;;8565:34;;;;8615:18;;8608:34;;;8519:2;8504:18;9062:43:0;;;;;;;9130:3;9125:9;;;;;;;;:::i;26292:161::-;26367:6;26405:12;26398:5;26394:9;;26386:32;;;;-1:-1:-1;;;26386:32:0;;;;;;;;:::i;:::-;-1:-1:-1;26443:1:0;;26292:161;-1:-1:-1;;26292:161:0:o;28620:126::-;28679:4;28703:35;28708:17;28713:1;24015:4;28708;:17::i;:::-;28727:10;;28703:4;:35::i;29329:147::-;-1:-1:-1;;;;;;;;;;;;29419:49:0;;;;;;;;29437:29;29442:20;29447:1;-1:-1:-1;;;29442:4:0;:20::i;:::-;29464:1;29437:4;:29::i;26617:160::-;-1:-1:-1;;;;;;;;;;;;26721:48:0;;;;;;;;26739:28;26744:1;:10;;;26756:1;:10;;;26739:4;:28::i;26119:165::-;26195:7;26235:12;-1:-1:-1;;;26223:10:0;;26215:33;;;;-1:-1:-1;;;26215:33:0;;;;;;;;:::i;28074:127::-;28136:4;-1:-1:-1;;;28160:19:0;28165:1;28168;:10;;;28160:4;:19::i;:::-;:33;;;;:::i;25056:208::-;25154:4;25171:18;25192:15;25197:1;25200:6;25192:4;:15::i;:::-;25171:36;;25225:31;25230:17;25239:7;25230:8;:17::i;:::-;25249:6;25225:4;:31::i;27472:133::-;-1:-1:-1;;;;;;;;;;;;27561:36:0;;;;;;;;27576:19;27581:1;:10;;;27593:1;27576:4;:19::i;24411:213::-;24593:12;;24468:4;;24593:23;;24015:4;;24593:23;:::i;29231:90::-;29284:4;29308:5;29312:1;29308;:5;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;206:367:1:-;269:8;279:6;333:3;326:4;318:6;314:17;310:27;300:55;;351:1;348;341:12;300:55;-1:-1:-1;374:20:1;;417:18;406:30;;403:50;;;449:1;446;439:12;403:50;486:4;478:6;474:17;462:29;;546:3;539:4;529:6;526:1;522:14;514:6;510:27;506:38;503:47;500:67;;;563:1;560;553:12;500:67;206:367;;;;;:::o;578:773::-;700:6;708;716;724;777:2;765:9;756:7;752:23;748:32;745:52;;;793:1;790;783:12;745:52;833:9;820:23;862:18;903:2;895:6;892:14;889:34;;;919:1;916;909:12;889:34;958:70;1020:7;1011:6;1000:9;996:22;958:70;:::i;:::-;1047:8;;-1:-1:-1;932:96:1;-1:-1:-1;1135:2:1;1120:18;;1107:32;;-1:-1:-1;1151:16:1;;;1148:36;;;1180:1;1177;1170:12;1148:36;;1219:72;1283:7;1272:8;1261:9;1257:24;1219:72;:::i;:::-;578:773;;;;-1:-1:-1;1310:8:1;-1:-1:-1;;;;578:773:1:o;1356:139::-;-1:-1:-1;;;;;1439:31:1;;1429:42;;1419:70;;1485:1;1482;1475:12;1500:118;1586:5;1579:13;1572:21;1565:5;1562:32;1552:60;;1608:1;1605;1598:12;1623:405;1703:6;1711;1764:2;1752:9;1743:7;1739:23;1735:32;1732:52;;;1780:1;1777;1770:12;1732:52;1819:9;1806:23;1838:39;1871:5;1838:39;:::i;:::-;1896:5;-1:-1:-1;1953:2:1;1938:18;;1925:32;1966:30;1925:32;1966:30;:::i;:::-;2015:7;2005:17;;;1623:405;;;;;:::o;2033:127::-;2094:10;2089:3;2085:20;2082:1;2075:31;2125:4;2122:1;2115:15;2149:4;2146:1;2139:15;2165:275;2236:2;2230:9;2301:2;2282:13;;-1:-1:-1;;2278:27:1;2266:40;;2336:18;2321:34;;2357:22;;;2318:62;2315:88;;;2383:18;;:::i;:::-;2419:2;2412:22;2165:275;;-1:-1:-1;2165:275:1:o;2445:191::-;2513:4;2546:18;2538:6;2535:30;2532:56;;;2568:18;;:::i;:::-;-1:-1:-1;2613:1:1;2609:14;2625:4;2605:25;;2445:191::o;2641:761::-;2703:5;2756:3;2749:4;2741:6;2737:17;2733:27;2723:55;;2774:1;2771;2764:12;2723:55;2810:6;2797:20;2836:4;2860:68;2876:51;2924:2;2876:51;:::i;:::-;2860:68;:::i;:::-;2962:15;;;3048:1;3044:10;;;;3032:23;;3028:32;;;2993:12;;;;3072:15;;;3069:35;;;3100:1;3097;3090:12;3069:35;3136:2;3128:6;3124:15;3148:225;3164:6;3159:3;3156:15;3148:225;;;3244:3;3231:17;3261:39;3294:5;3261:39;:::i;:::-;3313:18;;3351:12;;;;3181;;3148:225;;;-1:-1:-1;3391:5:1;2641:761;-1:-1:-1;;;;;;2641:761:1:o;3407:514::-;3515:6;3523;3576:2;3564:9;3555:7;3551:23;3547:32;3544:52;;;3592:1;3589;3582:12;3544:52;3631:9;3618:23;3650:39;3683:5;3650:39;:::i;:::-;3708:5;-1:-1:-1;3764:2:1;3749:18;;3736:32;3791:18;3780:30;;3777:50;;;3823:1;3820;3813:12;3777:50;3846:69;3907:7;3898:6;3887:9;3883:22;3846:69;:::i;:::-;3836:79;;;3407:514;;;;;:::o;3926:274::-;4004:6;4057:2;4045:9;4036:7;4032:23;4028:32;4025:52;;;4073:1;4070;4063:12;4025:52;4112:9;4099:23;4131:39;4164:5;4131:39;:::i;4647:691::-;4742:6;4750;4758;4766;4774;4827:3;4815:9;4806:7;4802:23;4798:33;4795:53;;;4844:1;4841;4834:12;4795:53;4883:9;4870:23;4902:39;4935:5;4902:39;:::i;:::-;4960:5;-1:-1:-1;5017:2:1;5002:18;;4989:32;5030:41;4989:32;5030:41;:::i;:::-;5090:7;-1:-1:-1;5149:2:1;5134:18;;5121:32;5162:41;5121:32;5162:41;:::i;:::-;4647:691;;;;-1:-1:-1;5222:7:1;;5276:2;5261:18;;5248:32;;-1:-1:-1;5327:3:1;5312:19;5299:33;;4647:691;-1:-1:-1;;4647:691:1:o;5551:622::-;5637:6;5645;5653;5661;5714:3;5702:9;5693:7;5689:23;5685:33;5682:53;;;5731:1;5728;5721:12;5682:53;5770:9;5757:23;5789:39;5822:5;5789:39;:::i;:::-;5847:5;-1:-1:-1;5904:2:1;5889:18;;5876:32;5917:41;5876:32;5917:41;:::i;:::-;5977:7;-1:-1:-1;6036:2:1;6021:18;;6008:32;6049:41;6008:32;6049:41;:::i;:::-;5551:622;;;;-1:-1:-1;6109:7:1;;6163:2;6148:18;6135:32;;-1:-1:-1;;5551:622:1:o;6178:323::-;6246:6;6254;6307:2;6295:9;6286:7;6282:23;6278:32;6275:52;;;6323:1;6320;6313:12;6275:52;6362:9;6349:23;6381:39;6414:5;6381:39;:::i;:::-;6439:5;6491:2;6476:18;;;;6463:32;;-1:-1:-1;;;6178:323:1:o;6506:241::-;6562:6;6615:2;6603:9;6594:7;6590:23;6586:32;6583:52;;;6631:1;6628;6621:12;6583:52;6670:9;6657:23;6689:28;6711:5;6689:28;:::i;6752:180::-;6811:6;6864:2;6852:9;6843:7;6839:23;6835:32;6832:52;;;6880:1;6877;6870:12;6832:52;-1:-1:-1;6903:23:1;;6752:180;-1:-1:-1;6752:180:1:o;6937:541::-;7023:6;7031;7039;7047;7100:3;7088:9;7079:7;7075:23;7071:33;7068:53;;;7117:1;7114;7107:12;7068:53;7156:9;7143:23;7175:39;7208:5;7175:39;:::i;:::-;7233:5;-1:-1:-1;7290:2:1;7275:18;;7262:32;7303:41;7262:32;7303:41;:::i;:::-;6937:541;;7363:7;;-1:-1:-1;;;;7417:2:1;7402:18;;7389:32;;7468:2;7453:18;7440:32;;6937:541::o;7483:841::-;7587:6;7595;7603;7611;7619;7627;7680:3;7668:9;7659:7;7655:23;7651:33;7648:53;;;7697:1;7694;7687:12;7648:53;7736:9;7723:23;7755:39;7788:5;7755:39;:::i;:::-;7813:5;-1:-1:-1;7870:2:1;7855:18;;7842:32;7883:41;7842:32;7883:41;:::i;:::-;7943:7;-1:-1:-1;8002:2:1;7987:18;;7974:32;8015:41;7974:32;8015:41;:::i;:::-;8075:7;-1:-1:-1;8134:2:1;8119:18;;8106:32;8147:41;8106:32;8147:41;:::i;:::-;7483:841;;;;-1:-1:-1;7483:841:1;;8261:3;8246:19;;8233:33;;8313:3;8298:19;;;8285:33;;-1:-1:-1;7483:841:1;-1:-1:-1;;7483:841:1:o;8653:472::-;8730:6;8738;8746;8799:2;8787:9;8778:7;8774:23;8770:32;8767:52;;;8815:1;8812;8805:12;8767:52;8854:9;8841:23;8873:39;8906:5;8873:39;:::i;:::-;8931:5;-1:-1:-1;8988:2:1;8973:18;;8960:32;9001:41;8960:32;9001:41;:::i;:::-;8653:472;;9061:7;;-1:-1:-1;;;9115:2:1;9100:18;;;;9087:32;;8653:472::o;9633:772::-;9728:6;9736;9744;9752;9760;9813:3;9801:9;9792:7;9788:23;9784:33;9781:53;;;9830:1;9827;9820:12;9781:53;9869:9;9856:23;9888:39;9921:5;9888:39;:::i;:::-;9946:5;-1:-1:-1;10003:2:1;9988:18;;9975:32;10016:41;9975:32;10016:41;:::i;:::-;10076:7;-1:-1:-1;10135:2:1;10120:18;;10107:32;10148:41;10107:32;10148:41;:::i;:::-;10208:7;-1:-1:-1;10267:2:1;10252:18;;10239:32;10280:41;10239:32;10280:41;:::i;:::-;9633:772;;;;-1:-1:-1;9633:772:1;;10394:3;10379:19;10366:33;;9633:772;-1:-1:-1;;9633:772:1:o;11203:753::-;11257:5;11310:3;11303:4;11295:6;11291:17;11287:27;11277:55;;11328:1;11325;11318:12;11277:55;11364:6;11351:20;11390:4;11414:68;11430:51;11478:2;11430:51;:::i;11414:68::-;11516:15;;;11602:1;11598:10;;;;11586:23;;11582:32;;;11547:12;;;;11626:15;;;11623:35;;;11654:1;11651;11644:12;11623:35;11690:2;11682:6;11678:15;11702:225;11718:6;11713:3;11710:15;11702:225;;;11798:3;11785:17;11815:39;11848:5;11815:39;:::i;:::-;11867:18;;11905:12;;;;11735;;11702:225;;11961:883;12106:6;12114;12122;12130;12183:3;12171:9;12162:7;12158:23;12154:33;12151:53;;;12200:1;12197;12190:12;12151:53;12240:9;12227:23;12269:18;12310:2;12302:6;12299:14;12296:34;;;12326:1;12323;12316:12;12296:34;12349:61;12402:7;12393:6;12382:9;12378:22;12349:61;:::i;:::-;12339:71;;12463:2;12452:9;12448:18;12435:32;12419:48;;12492:2;12482:8;12479:16;12476:36;;;12508:1;12505;12498:12;12476:36;;12531:71;12594:7;12583:8;12572:9;12568:24;12531:71;:::i;:::-;12521:81;;;12652:2;12641:9;12637:18;12624:32;12665:28;12687:5;12665:28;:::i;:::-;12712:5;-1:-1:-1;12769:2:1;12754:18;;12741:32;12782:30;12741:32;12782:30;:::i;:::-;11961:883;;;;-1:-1:-1;11961:883:1;;-1:-1:-1;;11961:883:1:o;13715:419::-;13798:6;13806;13859:2;13847:9;13838:7;13834:23;13830:32;13827:52;;;13875:1;13872;13865:12;13827:52;13914:9;13901:23;13933:39;13966:5;13933:39;:::i;:::-;13991:5;-1:-1:-1;14048:2:1;14033:18;;14020:32;14061:41;14020:32;14061:41;:::i;14622:670::-;14676:5;14729:3;14722:4;14714:6;14710:17;14706:27;14696:55;;14747:1;14744;14737:12;14696:55;14783:6;14770:20;14809:4;14833:68;14849:51;14897:2;14849:51;:::i;14833:68::-;14935:15;;;15021:1;15017:10;;;;15005:23;;15001:32;;;14966:12;;;;15045:15;;;15042:35;;;15073:1;15070;15063:12;15042:35;15109:2;15101:6;15097:15;15121:142;15137:6;15132:3;15129:15;15121:142;;;15203:17;;15191:30;;15241:12;;;;15154;;15121:142;;15297:844;15464:6;15472;15480;15533:2;15521:9;15512:7;15508:23;15504:32;15501:52;;;15549:1;15546;15539:12;15501:52;15589:9;15576:23;15618:18;15659:2;15651:6;15648:14;15645:34;;;15675:1;15672;15665:12;15645:34;15698:69;15759:7;15750:6;15739:9;15735:22;15698:69;:::i;:::-;15688:79;;15820:2;15809:9;15805:18;15792:32;15776:48;;15849:2;15839:8;15836:16;15833:36;;;15865:1;15862;15855:12;15833:36;15888:63;15943:7;15932:8;15921:9;15917:24;15888:63;:::i;:::-;15878:73;;16004:2;15993:9;15989:18;15976:32;15960:48;;16033:2;16023:8;16020:16;16017:36;;;16049:1;16046;16039:12;16017:36;;16072:63;16127:7;16116:8;16105:9;16101:24;16072:63;:::i;:::-;16062:73;;;15297:844;;;;;:::o;16146:673::-;16332:2;16384:21;;;16454:13;;16357:18;;;16476:22;;;16303:4;;16332:2;16555:15;;;;16529:2;16514:18;;;16303:4;16598:195;16612:6;16609:1;16606:13;16598:195;;;16677:13;;-1:-1:-1;;;;;16673:39:1;16661:52;;16768:15;;;;16733:12;;;;16709:1;16627:9;16598:195;;;-1:-1:-1;16810:3:1;;16146:673;-1:-1:-1;;;;;;16146:673:1:o;17233:348::-;17317:6;17370:2;17358:9;17349:7;17345:23;17341:32;17338:52;;;17386:1;17383;17376:12;17338:52;17426:9;17413:23;17459:18;17451:6;17448:30;17445:50;;;17491:1;17488;17481:12;17445:50;17514:61;17567:7;17558:6;17547:9;17543:22;17514:61;:::i;17586:632::-;17757:2;17809:21;;;17879:13;;17782:18;;;17901:22;;;17728:4;;17757:2;17980:15;;;;17954:2;17939:18;;;17728:4;18023:169;18037:6;18034:1;18031:13;18023:169;;;18098:13;;18086:26;;18167:15;;;;18132:12;;;;18059:1;18052:9;18023:169;;19970:127;20031:10;20026:3;20022:20;20019:1;20012:31;20062:4;20059:1;20052:15;20086:4;20083:1;20076:15;20102:127;20163:10;20158:3;20154:20;20151:1;20144:31;20194:4;20191:1;20184:15;20218:4;20215:1;20208:15;20234:125;20274:4;20302:1;20299;20296:8;20293:34;;;20307:18;;:::i;:::-;-1:-1:-1;20344:9:1;;20234:125::o;20364:135::-;20403:3;-1:-1:-1;;20424:17:1;;20421:43;;;20444:18;;:::i;:::-;-1:-1:-1;20491:1:1;20480:13;;20364:135::o;20504:404::-;20706:2;20688:21;;;20745:2;20725:18;;;20718:30;20784:34;20779:2;20764:18;;20757:62;-1:-1:-1;;;20850:2:1;20835:18;;20828:38;20898:3;20883:19;;20504:404::o;20913:403::-;21115:2;21097:21;;;21154:2;21134:18;;;21127:30;21193:34;21188:2;21173:18;;21166:62;-1:-1:-1;;;21259:2:1;21244:18;;21237:37;21306:3;21291:19;;20913:403::o;21321:346::-;21523:2;21505:21;;;21562:2;21542:18;;;21535:30;-1:-1:-1;;;21596:2:1;21581:18;;21574:52;21658:2;21643:18;;21321:346::o;22201:259::-;22271:6;22324:2;22312:9;22303:7;22299:23;22295:32;22292:52;;;22340:1;22337;22330:12;22292:52;22372:9;22366:16;22391:39;22424:5;22391:39;:::i;22873:184::-;22943:6;22996:2;22984:9;22975:7;22971:23;22967:32;22964:52;;;23012:1;23009;23002:12;22964:52;-1:-1:-1;23035:16:1;;22873:184;-1:-1:-1;22873:184:1:o;23412:127::-;23473:10;23468:3;23464:20;23461:1;23454:31;23504:4;23501:1;23494:15;23528:4;23525:1;23518:15;29892:245;29959:6;30012:2;30000:9;29991:7;29987:23;29983:32;29980:52;;;30028:1;30025;30018:12;29980:52;30060:9;30054:16;30079:28;30101:5;30079:28;:::i;32230:127::-;32291:10;32286:3;32282:20;32279:1;32272:31;32322:4;32319:1;32312:15;32346:4;32343:1;32336:15;33081:368;33178:6;33186;33194;33202;33255:3;33243:9;33234:7;33230:23;33226:33;33223:53;;;33272:1;33269;33262:12;33223:53;-1:-1:-1;;33295:16:1;;33351:2;33336:18;;33330:25;33395:2;33380:18;;33374:25;33439:2;33424:18;;;33418:25;33295:16;;33330:25;;-1:-1:-1;33418:25:1;;-1:-1:-1;33081:368:1;-1:-1:-1;33081:368:1:o;33860:127::-;33921:10;33916:3;33912:20;33909:1;33902:31;33952:4;33949:1;33942:15;33976:4;33973:1;33966:15;34316:128;34356:3;34387:1;34383:6;34380:1;34377:13;34374:39;;;34393:18;;:::i;:::-;-1:-1:-1;34429:9:1;;34316:128::o;34781:168::-;34821:7;34887:1;34883;34879:6;34875:14;34872:1;34869:21;34864:1;34857:9;34850:17;34846:45;34843:71;;;34894:18;;:::i;:::-;-1:-1:-1;34934:9:1;;34781:168::o;35657:217::-;35697:1;35723;35713:132;;35767:10;35762:3;35758:20;35755:1;35748:31;35802:4;35799:1;35792:15;35830:4;35827:1;35820:15;35713:132;-1:-1:-1;35859:9:1;;35657:217::o;35879:597::-;35991:4;36020:2;36049;36038:9;36031:21;36081:6;36075:13;36124:6;36119:2;36108:9;36104:18;36097:34;36149:1;36159:140;36173:6;36170:1;36167:13;36159:140;;;36268:14;;;36264:23;;36258:30;36234:17;;;36253:2;36230:26;36223:66;36188:10;;36159:140;;;36317:6;36314:1;36311:13;36308:91;;;36387:1;36382:2;36373:6;36362:9;36358:22;36354:31;36347:42;36308:91;-1:-1:-1;36460:2:1;36439:15;-1:-1:-1;;36435:29:1;36420:45;;;;36467:2;36416:54;;35879:597;-1:-1:-1;;;35879:597:1:o
Swarm Source
ipfs://628f7ffeec06ca6b439f1f282877aabfb1cc6c3e0ed99c98d622f59ef9cdaac9
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.