There are reports that this address was used in a Phishing scam. Please exercise caution when interacting with it. Reported by GoPlusSecurity.
Fake_Phishing288813
Source Code
Phish / Hack
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 293 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Redeem Underlyin... | 12507630 | 1740 days ago | IN | 0 ETH | 0.00470238 | ||||
| Redeem Underlyin... | 12228913 | 1783 days ago | IN | 0 ETH | 0.01014147 | ||||
| Redeem Underlyin... | 11728917 | 1860 days ago | IN | 0 ETH | 0.01149396 | ||||
| Redeem Underlyin... | 11725505 | 1860 days ago | IN | 0 ETH | 0.01689264 | ||||
| Redeem Underlyin... | 11724499 | 1860 days ago | IN | 0 ETH | 0.0099266 | ||||
| Redeem Underlyin... | 11724391 | 1860 days ago | IN | 0 ETH | 0.01044906 | ||||
| Borrow | 11718252 | 1861 days ago | IN | 0 ETH | 0.01053726 | ||||
| Borrow | 11718244 | 1861 days ago | IN | 0 ETH | 0.01930464 | ||||
| Borrow | 11713914 | 1862 days ago | IN | 0 ETH | 0.02574043 | ||||
| Repay Borrow | 11706552 | 1863 days ago | IN | 0 ETH | 0.01471524 | ||||
| Redeem Underlyin... | 11694981 | 1865 days ago | IN | 0 ETH | 0.00898502 | ||||
| Repay Borrow | 11693716 | 1865 days ago | IN | 0 ETH | 0.0080859 | ||||
| Repay Borrow | 11693640 | 1865 days ago | IN | 0 ETH | 0.01095874 | ||||
| Repay Borrow | 11687836 | 1866 days ago | IN | 0 ETH | 0.01115854 | ||||
| Repay Borrow | 11687778 | 1866 days ago | IN | 0 ETH | 0.01414032 | ||||
| Redeem Underlyin... | 11687312 | 1866 days ago | IN | 0 ETH | 0.02196526 | ||||
| Repay Borrow | 11687138 | 1866 days ago | IN | 0 ETH | 0.02394412 | ||||
| Repay Borrow | 11687106 | 1866 days ago | IN | 0 ETH | 0.01594376 | ||||
| Repay Borrow | 11687082 | 1866 days ago | IN | 0 ETH | 0.01307713 | ||||
| Redeem Underlyin... | 11398071 | 1911 days ago | IN | 0 ETH | 0.00350829 | ||||
| Redeem Underlyin... | 11368114 | 1915 days ago | IN | 0 ETH | 0.00634644 | ||||
| Redeem Underlyin... | 11368052 | 1915 days ago | IN | 0 ETH | 0.01068966 | ||||
| Redeem Underlyin... | 11339142 | 1920 days ago | IN | 0 ETH | 0.00353901 | ||||
| Redeem Underlyin... | 11339123 | 1920 days ago | IN | 0 ETH | 0.00451573 | ||||
| Redeem Underlyin... | 11273772 | 1930 days ago | IN | 0 ETH | 0.00646912 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
|||
|---|---|---|---|---|---|---|---|---|
| Balance Of | 23317997 | 173 days ago | 0 ETH | |||||
| Total Supply | 23317997 | 173 days ago | 0 ETH | |||||
| Total Borrows | 23317997 | 173 days ago | 0 ETH | |||||
| Borrow Index | 23317997 | 173 days ago | 0 ETH | |||||
| Balance Of | 21205571 | 469 days ago | 0 ETH | |||||
| Total Supply | 21205571 | 469 days ago | 0 ETH | |||||
| Borrow Balance S... | 21205571 | 469 days ago | 0 ETH | |||||
| Total Borrows | 21205571 | 469 days ago | 0 ETH | |||||
| Borrow Index | 21205571 | 469 days ago | 0 ETH | |||||
| Balance Of | 20253671 | 601 days ago | 0 ETH | |||||
| Total Supply | 20253671 | 601 days ago | 0 ETH | |||||
| Borrow Balance S... | 20253671 | 601 days ago | 0 ETH | |||||
| Total Borrows | 20253671 | 601 days ago | 0 ETH | |||||
| Borrow Index | 20253671 | 601 days ago | 0 ETH | |||||
| Balance Of | 20153819 | 615 days ago | 0 ETH | |||||
| Total Supply | 20153819 | 615 days ago | 0 ETH | |||||
| Borrow Balance S... | 20153819 | 615 days ago | 0 ETH | |||||
| Total Borrows | 20153819 | 615 days ago | 0 ETH | |||||
| Borrow Index | 20153819 | 615 days ago | 0 ETH | |||||
| Balance Of | 17672293 | 963 days ago | 0 ETH | |||||
| Total Supply | 17672293 | 963 days ago | 0 ETH | |||||
| Borrow Balance S... | 17672293 | 963 days ago | 0 ETH | |||||
| Total Borrows | 17672293 | 963 days ago | 0 ETH | |||||
| Borrow Index | 17672293 | 963 days ago | 0 ETH | |||||
| Balance Of | 15273962 | 1305 days ago | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
CErc20
Compiler Version
v0.5.17+commit.d19bba13
Contract Source Code (Solidity Multiple files format)
pragma solidity ^0.5.16;
import "./CToken.sol";
/**
* @title Compound's CErc20 Contract
* @notice CTokens which wrap an EIP-20 underlying
* @author Compound
*/
contract CErc20 is CToken, CErc20Interface {
constructor() public {
admin = msg.sender;
}
/**
* @notice Initialize the new money market
* @param underlying_ The address of the underlying asset
* @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_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
*/
function initialize(address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_) public {
// CToken initialize does the bulk of the work
super.initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);
// Set underlying and sanity check it
underlying = underlying_;
EIP20Interface(underlying).totalSupply();
}
/*** User Interface ***/
/**
* @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
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function mint(uint mintAmount) external returns (uint) {
(uint err,) = mintInternal(mintAmount);
return err;
}
/**
* @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
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeem(uint redeemTokens) external returns (uint) {
return redeemInternal(redeemTokens);
}
/**
* @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 redeem
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlying(uint redeemAmount) external returns (uint) {
return redeemUnderlyingInternal(redeemAmount);
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrow(uint borrowAmount) external returns (uint) {
return borrowInternal(borrowAmount);
}
/**
* @notice Sender repays their own borrow
* @param repayAmount The amount to repay
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrow(uint repayAmount) external returns (uint) {
(uint err,) = repayBorrowInternal(repayAmount);
return err;
}
/**
* @notice Sender repays a borrow belonging to borrower
* @param borrower the account with the debt being payed off
* @param repayAmount The amount to repay
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint) {
(uint err,) = repayBorrowBehalfInternal(borrower, repayAmount);
return err;
}
/**
* @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 repayAmount The amount of the underlying borrowed asset to repay
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint) {
(uint err,) = liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);
return err;
}
/**
* @notice The sender adds to reserves.
* @param addAmount The amount fo underlying token to add as reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _addReserves(uint addAmount) external returns (uint) {
return _addReservesInternal(addAmount);
}
/*** 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 tokens owned by this contract
*/
function getCashPrior() internal view returns (uint) {
EIP20Interface token = EIP20Interface(underlying);
return token.balanceOf(address(this));
}
/**
* @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.
* This will revert due to insufficient balance or insufficient allowance.
* This function returns the actual amount received,
* which may be less than `amount` if there is a fee attached to the transfer.
*
* Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
* See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
function doTransferIn(address from, uint amount) internal returns (uint) {
EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this));
token.transferFrom(from, address(this), amount);
bool success;
assembly {
switch returndatasize()
case 0 { // This is a non-standard ERC-20
success := not(0) // set success to true
}
case 32 { // This is a compliant ERC-20
returndatacopy(0, 0, 32)
success := mload(0) // Set `success = returndata` of external call
}
default { // This is an excessively non-compliant ERC-20, revert.
revert(0, 0)
}
}
require(success, "TOKEN_TRANSFER_IN_FAILED");
// Calculate the amount that was *actually* transferred
uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this));
require(balanceAfter >= balanceBefore, "TOKEN_TRANSFER_IN_OVERFLOW");
return balanceAfter - balanceBefore; // underflow already checked above, just subtract
}
/**
* @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory
* error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to
* insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified
* it is >= amount, this should not revert in normal conditions.
*
* Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
* See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
function doTransferOut(address payable to, uint amount) internal {
EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
token.transfer(to, amount);
bool success;
assembly {
switch returndatasize()
case 0 { // This is a non-standard ERC-20
success := not(0) // set success to true
}
case 32 { // This is a complaint ERC-20
returndatacopy(0, 0, 32)
success := mload(0) // Set `success = returndata` of external call
}
default { // This is an excessively non-compliant ERC-20, revert.
revert(0, 0)
}
}
require(success, "TOKEN_TRANSFER_OUT_FAILED");
}
}
pragma solidity ^0.5.16;
/**
* @title Careful Math
* @author Compound
* @notice Derived from OpenZeppelin's SafeMath library
* https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol
*/
contract CarefulMath {
/**
* @dev Possible error codes that we can return
*/
enum MathError {
NO_ERROR,
DIVISION_BY_ZERO,
INTEGER_OVERFLOW,
INTEGER_UNDERFLOW
}
/**
* @dev Multiplies two numbers, returns an error on overflow.
*/
function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (a == 0) {
return (MathError.NO_ERROR, 0);
}
uint c = a * b;
if (c / a != b) {
return (MathError.INTEGER_OVERFLOW, 0);
} else {
return (MathError.NO_ERROR, c);
}
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (b == 0) {
return (MathError.DIVISION_BY_ZERO, 0);
}
return (MathError.NO_ERROR, a / b);
}
/**
* @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
*/
function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (b <= a) {
return (MathError.NO_ERROR, a - b);
} else {
return (MathError.INTEGER_UNDERFLOW, 0);
}
}
/**
* @dev Adds two numbers, returns an error on overflow.
*/
function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
uint c = a + b;
if (c >= a) {
return (MathError.NO_ERROR, c);
} else {
return (MathError.INTEGER_OVERFLOW, 0);
}
}
/**
* @dev add a and b and then subtract c
*/
function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {
(MathError err0, uint sum) = addUInt(a, b);
if (err0 != MathError.NO_ERROR) {
return (err0, 0);
}
return subUInt(sum, c);
}
}pragma solidity ^0.5.16;
import "./CErc20Delegate.sol";
/**
* @title Compound's CDai Contract
* @notice CToken which wraps Multi-Collateral DAI
* @author Compound
*/
contract CDaiDelegate is CErc20Delegate {
/**
* @notice DAI adapter address
*/
address public daiJoinAddress;
/**
* @notice DAI Savings Rate (DSR) pot address
*/
address public potAddress;
/**
* @notice DAI vat address
*/
address public vatAddress;
/**
* @notice Delegate interface to become the implementation
* @param data The encoded arguments for becoming
*/
function _becomeImplementation(bytes memory data) public {
require(msg.sender == admin, "only the admin may initialize the implementation");
(address daiJoinAddress_, address potAddress_) = abi.decode(data, (address, address));
return _becomeImplementation(daiJoinAddress_, potAddress_);
}
/**
* @notice Explicit interface to become the implementation
* @param daiJoinAddress_ DAI adapter address
* @param potAddress_ DAI Savings Rate (DSR) pot address
*/
function _becomeImplementation(address daiJoinAddress_, address potAddress_) internal {
// Get dai and vat and sanity check the underlying
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress_);
PotLike pot = PotLike(potAddress_);
GemLike dai = daiJoin.dai();
VatLike vat = daiJoin.vat();
require(address(dai) == underlying, "DAI must be the same as underlying");
// Remember the relevant addresses
daiJoinAddress = daiJoinAddress_;
potAddress = potAddress_;
vatAddress = address(vat);
// Approve moving our DAI into the vat through daiJoin
dai.approve(daiJoinAddress, uint(-1));
// Approve the pot to transfer our funds within the vat
vat.hope(potAddress);
vat.hope(daiJoinAddress);
// Accumulate DSR interest -- must do this in order to doTransferIn
pot.drip();
// Transfer all cash in (doTransferIn does this regardless of amount)
doTransferIn(address(this), 0);
}
/**
* @notice Delegate interface to resign the implementation
*/
function _resignImplementation() public {
require(msg.sender == admin, "only the admin may abandon the implementation");
// Transfer all cash out of the DSR - note that this relies on self-transfer
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
PotLike pot = PotLike(potAddress);
VatLike vat = VatLike(vatAddress);
// Accumulate interest
pot.drip();
// Calculate the total amount in the pot, and move it out
uint pie = pot.pie(address(this));
pot.exit(pie);
// Checks the actual balance of DAI in the vat after the pot exit
uint bal = vat.dai(address(this));
// Remove our whole balance
daiJoin.exit(address(this), bal / RAY);
}
/*** CToken Overrides ***/
/**
* @notice Accrues DSR then 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() public returns (uint) {
// Accumulate DSR interest
PotLike(potAddress).drip();
// Accumulate CToken interest
return super.accrueInterest();
}
/*** 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 tokens owned by this contract
*/
function getCashPrior() internal view returns (uint) {
PotLike pot = PotLike(potAddress);
uint pie = pot.pie(address(this));
return mul(pot.chi(), pie) / RAY;
}
/**
* @notice Transfer the underlying to this contract and sweep into DSR pot
* @param from Address to transfer funds from
* @param amount Amount of underlying to transfer
* @return The actual amount that is transferred
*/
function doTransferIn(address from, uint amount) internal returns (uint) {
// Perform the EIP-20 transfer in
EIP20Interface token = EIP20Interface(underlying);
require(token.transferFrom(from, address(this), amount), "unexpected EIP-20 transfer in return");
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
GemLike dai = GemLike(underlying);
PotLike pot = PotLike(potAddress);
VatLike vat = VatLike(vatAddress);
// Convert all our DAI to internal DAI in the vat
daiJoin.join(address(this), dai.balanceOf(address(this)));
// Checks the actual balance of DAI in the vat after the join
uint bal = vat.dai(address(this));
// Calculate the percentage increase to th pot for the entire vat, and move it in
// Note: We may leave a tiny bit of DAI in the vat...but we do the whole thing every time
uint pie = bal / pot.chi();
pot.join(pie);
return amount;
}
/**
* @notice Transfer the underlying from this contract, after sweeping out of DSR pot
* @param to Address to transfer funds to
* @param amount Amount of underlying to transfer
*/
function doTransferOut(address payable to, uint amount) internal {
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
PotLike pot = PotLike(potAddress);
// Calculate the percentage decrease from the pot, and move that much out
// Note: Use a slightly larger pie size to ensure that we get at least amount in the vat
uint pie = add(mul(amount, RAY) / pot.chi(), 1);
pot.exit(pie);
daiJoin.exit(to, amount);
}
/*** Maker Internals ***/
uint256 constant RAY = 10 ** 27;
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, "add-overflow");
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, "mul-overflow");
}
}
/*** Maker Interfaces ***/
interface PotLike {
function chi() external view returns (uint);
function pie(address) external view returns (uint);
function drip() external returns (uint);
function join(uint) external;
function exit(uint) external;
}
interface GemLike {
function approve(address, uint) external;
function balanceOf(address) external view returns (uint);
function transferFrom(address, address, uint) external returns (bool);
}
interface VatLike {
function dai(address) external view returns (uint);
function hope(address) external;
}
interface DaiJoinLike {
function vat() external returns (VatLike);
function dai() external returns (GemLike);
function join(address, uint) external payable;
function exit(address, uint) external;
}
pragma solidity ^0.5.16;
import "./CErc20.sol";
/**
* @title Compound's CErc20Delegate Contract
* @notice CTokens which wrap an EIP-20 underlying and are delegated to
* @author Compound
*/
contract CErc20Delegate is CErc20, CDelegateInterface {
/**
* @notice Construct an empty delegate
*/
constructor() public {}
/**
* @notice Called by the delegator on a delegate to initialize it for duty
* @param data The encoded bytes data for any initialization
*/
function _becomeImplementation(bytes memory data) public {
// Shh -- currently unused
data;
// Shh -- we don't ever want this hook to be marked pure
if (false) {
implementation = address(0);
}
require(msg.sender == admin, "only the admin may call _becomeImplementation");
}
/**
* @notice Called by the delegator on a delegate to forfeit its responsibility
*/
function _resignImplementation() public {
// Shh -- we don't ever want this hook to be marked pure
if (false) {
implementation = address(0);
}
require(msg.sender == admin, "only the admin may call _resignImplementation");
}
}
pragma solidity ^0.5.16;
import "./CTokenInterfaces.sol";
/**
* @title Compound's CErc20Delegator Contract
* @notice CTokens which wrap an EIP-20 underlying and delegate to an implementation
* @author Compound
*/
contract CErc20Delegator is CTokenInterface, CErc20Interface, CDelegatorInterface {
/**
* @notice Construct a new money market
* @param underlying_ The address of the underlying asset
* @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_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
* @param admin_ Address of the administrator of this token
* @param implementation_ The address of the implementation the contract delegates to
* @param becomeImplementationData The encoded args for becomeImplementation
*/
constructor(address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address payable admin_,
address implementation_,
bytes memory becomeImplementationData) public {
// Creator of the contract is admin during initialization
admin = msg.sender;
// First delegate gets to initialize the delegator (i.e. storage contract)
delegateTo(implementation_, abi.encodeWithSignature("initialize(address,address,address,uint256,string,string,uint8)",
underlying_,
comptroller_,
interestRateModel_,
initialExchangeRateMantissa_,
name_,
symbol_,
decimals_));
// New implementations always get set via the settor (post-initialize)
_setImplementation(implementation_, false, becomeImplementationData);
// Set the proper admin now that initialization is done
admin = admin_;
}
/**
* @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) public {
require(msg.sender == admin, "CErc20Delegator::_setImplementation: Caller must be admin");
if (allowResign) {
delegateToImplementation(abi.encodeWithSignature("_resignImplementation()"));
}
address oldImplementation = implementation;
implementation = implementation_;
delegateToImplementation(abi.encodeWithSignature("_becomeImplementation(bytes)", becomeImplementationData));
emit NewImplementation(oldImplementation, implementation);
}
/**
* @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
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function mint(uint mintAmount) external returns (uint) {
mintAmount; // Shh
delegateAndReturn();
}
/**
* @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
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeem(uint redeemTokens) external returns (uint) {
redeemTokens; // Shh
delegateAndReturn();
}
/**
* @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 redeem
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlying(uint redeemAmount) external returns (uint) {
redeemAmount; // Shh
delegateAndReturn();
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrow(uint borrowAmount) external returns (uint) {
borrowAmount; // Shh
delegateAndReturn();
}
/**
* @notice Sender repays their own borrow
* @param repayAmount The amount to repay
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrow(uint repayAmount) external returns (uint) {
repayAmount; // Shh
delegateAndReturn();
}
/**
* @notice Sender repays a borrow belonging to borrower
* @param borrower the account with the debt being payed off
* @param repayAmount The amount to repay
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint) {
borrower; repayAmount; // Shh
delegateAndReturn();
}
/**
* @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
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint) {
borrower; repayAmount; cTokenCollateral; // Shh
delegateAndReturn();
}
/**
* @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, uint amount) external returns (bool) {
dst; amount; // Shh
delegateAndReturn();
}
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(address src, address dst, uint256 amount) external returns (bool) {
src; dst; amount; // Shh
delegateAndReturn();
}
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) external returns (bool) {
spender; amount; // Shh
delegateAndReturn();
}
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(address owner, address spender) external view returns (uint) {
owner; spender; // Shh
delegateToViewAndReturn();
}
/**
* @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) external view returns (uint) {
owner; // Shh
delegateToViewAndReturn();
}
/**
* @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) external returns (uint) {
owner; // Shh
delegateAndReturn();
}
/**
* @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) external view returns (uint, uint, uint, uint) {
account; // Shh
delegateToViewAndReturn();
}
/**
* @notice Returns the current per-block borrow interest rate for this cToken
* @return The borrow interest rate per block, scaled by 1e18
*/
function borrowRatePerBlock() external view returns (uint) {
delegateToViewAndReturn();
}
/**
* @notice Returns the current per-block supply interest rate for this cToken
* @return The supply interest rate per block, scaled by 1e18
*/
function supplyRatePerBlock() external view returns (uint) {
delegateToViewAndReturn();
}
/**
* @notice Returns the current total borrows plus accrued interest
* @return The total borrows with interest
*/
function totalBorrowsCurrent() external returns (uint) {
delegateAndReturn();
}
/**
* @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) external returns (uint) {
account; // Shh
delegateAndReturn();
}
/**
* @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) public view returns (uint) {
account; // Shh
delegateToViewAndReturn();
}
/**
* @notice Accrue interest then return the up-to-date exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateCurrent() public returns (uint) {
delegateAndReturn();
}
/**
* @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() public view returns (uint) {
delegateToViewAndReturn();
}
/**
* @notice Get cash balance of this cToken in the underlying asset
* @return The quantity of underlying asset owned by this contract
*/
function getCash() external view returns (uint) {
delegateToViewAndReturn();
}
/**
* @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() public returns (uint) {
delegateAndReturn();
}
/**
* @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) external returns (uint) {
liquidator; borrower; seizeTokens; // Shh
delegateAndReturn();
}
/*** 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) external returns (uint) {
newPendingAdmin; // Shh
delegateAndReturn();
}
/**
* @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) public returns (uint) {
newComptroller; // Shh
delegateAndReturn();
}
/**
* @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) external returns (uint) {
newReserveFactorMantissa; // Shh
delegateAndReturn();
}
/**
* @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() external returns (uint) {
delegateAndReturn();
}
/**
* @notice Accrues interest and adds reserves by transferring from admin
* @param addAmount Amount of reserves to add
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _addReserves(uint addAmount) external returns (uint) {
addAmount; // Shh
delegateAndReturn();
}
/**
* @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) external returns (uint) {
reduceAmount; // Shh
delegateAndReturn();
}
/**
* @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) public returns (uint) {
newInterestRateModel; // Shh
delegateAndReturn();
}
/**
* @notice Internal method to delegate execution to another contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* @param callee The contract to delegatecall
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateTo(address callee, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returnData) = callee.delegatecall(data);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize)
}
}
return returnData;
}
/**
* @notice Delegates execution to the implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateToImplementation(bytes memory data) public returns (bytes memory) {
return delegateTo(implementation, data);
}
/**
* @notice Delegates execution to an implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {
(bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", data));
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize)
}
}
return abi.decode(returnData, (bytes));
}
function delegateToViewAndReturn() private view returns (bytes memory) {
(bool success, ) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", 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(add(free_mem_ptr, 0x40), returndatasize) }
}
}
function delegateAndReturn() private returns (bytes memory) {
(bool success, ) = implementation.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) }
}
}
/**
* @notice Delegates execution to an implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
*/
function () external payable {
require(msg.value == 0,"CErc20Delegator:fallback: cannot send value to fallback");
// delegate all other functions to current implementation
delegateAndReturn();
}
}
pragma solidity ^0.5.16;
import "./CErc20.sol";
/**
* @title Compound's CErc20Immutable Contract
* @notice CTokens which wrap an EIP-20 underlying and are immutable
* @author Compound
*/
contract CErc20Immutable is CErc20 {
/**
* @notice Construct a new money market
* @param underlying_ The address of the underlying asset
* @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_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
* @param admin_ Address of the administrator of this token
*/
constructor(address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address payable admin_) public {
// Creator of the contract is admin during initialization
admin = msg.sender;
// Initialize the market
initialize(underlying_, comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);
// Set the proper admin now that initialization is done
admin = admin_;
}
}
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
contract Cheese {
/// @notice EIP-20 token name for this token
string public constant name = "Cheese";
/// @notice EIP-20 token symbol for this token
string public constant symbol = "CHEESE";
/// @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 == uint(-1)) {
amount = uint96(-1);
} 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 != uint96(-1)) {
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(now <= 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 pure returns (uint) {
uint256 chainId;
assembly { chainId := chainid() }
return chainId;
}
}
pragma solidity ^0.5.16;
import "./CToken.sol";
import "./ErrorReporter.sol";
import "./Exponential.sol";
import "./PriceOracle.sol";
import "./ComptrollerInterface.sol";
import "./ComptrollerStorage.sol";
import "./Unitroller.sol";
import "./Cheese.sol";
/**
* @title Compound's Comptroller Contract
* @author Compound
*/
contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerErrorReporter, Exponential {
/// @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 maxAssets is changed by admin
event NewMaxAssets(uint oldMaxAssets, uint newMaxAssets);
/// @notice Emitted when price oracle is changed
event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);
/// @notice Emitted when pause guardian is changed
event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);
/// @notice Emitted when an action is paused globally
event ActionPaused(string action, bool pauseState);
/// @notice Emitted when an action is paused on a market
event MarketActionPaused(CToken cToken, string action, bool pauseState);
/// @notice Emitted when market comped status is changed
event MarketComped(CToken cToken, bool isComped);
/// @notice Emitted when COMP rate is changed
event NewCompRate(uint oldCompRate, uint newCompRate);
/// @notice Emitted when a new COMP speed is calculated for a market
event CompSpeedUpdated(CToken indexed cToken, uint newSpeed, uint totalUtility, uint utility);
/// @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 The threshold above which the flywheel transfers COMP, in wei
//uint public constant compClaimThreshold = 0.001e18;
uint public constant compClaimThreshold = 1e18;
/// @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
// liquidationIncentiveMantissa must be no less than this value
uint internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0
// liquidationIncentiveMantissa must be no greater than this value
uint internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5
constructor() public {
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) 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;
}
if (accountAssets[borrower].length >= maxAssets) {
// no space, cannot join
return Error.TOO_MANY_ASSETS;
}
// survived the gauntlet, add to list
// NOTE: we store these somewhat redundantly as a significant optimization
// this avoids having to iterate through the list for the most common use cases
// that is, only when we need to perform liquidity checks
// and not whenever we want to check if an account is in a particular market
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) 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.length--;
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) 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, false);
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) 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) 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, false);
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) 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) 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);
}
(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, false);
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) 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) 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, false);
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) 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) external returns (uint) {
// Shh - currently unused
liquidator;
if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {
return uint(Error.MARKET_NOT_LISTED);
}
/* 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 borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);
(MathError mathErr, uint maxClose) = mulScalarTruncate(Exp({mantissa : closeFactorMantissa}), borrowBalance);
if (mathErr != MathError.NO_ERROR) {
return uint(Error.MATH_ERROR);
}
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) 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) 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, false);
distributeSupplierComp(cTokenCollateral, liquidator, false);
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) 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) 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, false);
distributeSupplierComp(cToken, dst, false);
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) 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(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(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;
MathError mErr;
// 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)
(mErr, vars.tokensToDenom) = mulExp3(vars.collateralFactor, vars.exchangeRate, vars.oraclePrice);
if (mErr != MathError.NO_ERROR) {
return (Error.MATH_ERROR, 0, 0);
}
// sumCollateral += tokensToDenom * cTokenBalance
(mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);
if (mErr != MathError.NO_ERROR) {
return (Error.MATH_ERROR, 0, 0);
}
// sumBorrowPlusEffects += oraclePrice * borrowBalance
(mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);
if (mErr != MathError.NO_ERROR) {
return (Error.MATH_ERROR, 0, 0);
}
// Calculate effects of interacting with cTokenModify
if (asset == cTokenModify) {
// redeem effect
// sumBorrowPlusEffects += tokensToDenom * redeemTokens
(mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects);
if (mErr != MathError.NO_ERROR) {
return (Error.MATH_ERROR, 0, 0);
}
// borrow effect
// sumBorrowPlusEffects += oraclePrice * borrowAmount
(mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);
if (mErr != MathError.NO_ERROR) {
return (Error.MATH_ERROR, 0, 0);
}
}
}
// 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) 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;
MathError mathErr;
(mathErr, numerator) = mulExp(liquidationIncentiveMantissa, priceBorrowedMantissa);
if (mathErr != MathError.NO_ERROR) {
return (uint(Error.MATH_ERROR), 0);
}
(mathErr, denominator) = mulExp(priceCollateralMantissa, exchangeRateMantissa);
if (mathErr != MathError.NO_ERROR) {
return (uint(Error.MATH_ERROR), 0);
}
(mathErr, ratio) = divExp(numerator, denominator);
if (mathErr != MathError.NO_ERROR) {
return (uint(Error.MATH_ERROR), 0);
}
(mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);
if (mathErr != MathError.NO_ERROR) {
return (uint(Error.MATH_ERROR), 0);
}
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. (See ErrorReporter for details)
*/
function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) {
// Check caller is admin
if (msg.sender != admin) {
return fail(Error.UNAUTHORIZED, FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK);
}
Exp memory newCloseFactorExp = Exp({mantissa : newCloseFactorMantissa});
Exp memory lowLimit = Exp({mantissa : closeFactorMinMantissa});
if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {
return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);
}
Exp memory highLimit = Exp({mantissa : closeFactorMaxMantissa});
if (lessThanExp(highLimit, newCloseFactorExp)) {
return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);
}
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 maxAssets which controls how many markets can be entered
* @dev Admin function to set maxAssets
* @param newMaxAssets New max assets
* @return uint 0=success, otherwise a failure. (See ErrorReporter for details)
*/
function _setMaxAssets(uint newMaxAssets) external returns (uint) {
// Check caller is admin
if (msg.sender != admin) {
return fail(Error.UNAUTHORIZED, FailureInfo.SET_MAX_ASSETS_OWNER_CHECK);
}
uint oldMaxAssets = maxAssets;
maxAssets = newMaxAssets;
emit NewMaxAssets(oldMaxAssets, newMaxAssets);
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);
}
// Check de-scaled min <= newLiquidationIncentive <= max
Exp memory newLiquidationIncentive = Exp({mantissa : newLiquidationIncentiveMantissa});
Exp memory minLiquidationIncentive = Exp({mantissa : liquidationIncentiveMinMantissa});
if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {
return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);
}
Exp memory maxLiquidationIncentive = Exp({mantissa : liquidationIncentiveMaxMantissa});
if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {
return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);
}
// 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
markets[address(cToken)] = Market({isListed : true, isComped : true, collateralFactorMantissa : 0});
_addMarketInternal(address(cToken));
borrowGuardianPaused[address(cToken)] = true;
//stage 1, not allow borrow
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));
}
/**
* @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 MarketActionPaused(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 MarketActionPaused(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 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 Recalculate and update COMP speeds for all COMP markets
*/
function refreshCompSpeeds() public {
require(msg.sender == tx.origin, "only externally owned accounts may refresh speeds");
refreshCompSpeedsInternal();
}
function refreshCompSpeedsInternal() internal {
CToken[] memory allMarkets_ = allMarkets;
for (uint i = 0; i < allMarkets_.length; i++) {
CToken cToken = allMarkets_[i];
Exp memory borrowIndex = Exp({mantissa : cToken.borrowIndex()});
updateCompSupplyIndex(address(cToken));
updateCompBorrowIndex(address(cToken), borrowIndex);
}
Exp memory borrowTotalUtility = Exp({mantissa : 0});
uint borrowAssetCount = 0;
Exp memory borrowAverageUtility = Exp({mantissa : 0});
//calculate Borrow asset totalUtility
if (miningRule == 1) {//mining by borrow
for (uint i = 0; i < allMarkets_.length; i++) {
CToken cToken = allMarkets_[i];
if (markets[address(cToken)].isComped && !borrowGuardianPaused[address(cToken)]) {
Exp memory assetPrice = Exp({mantissa : oracle.getUnderlyingPrice(cToken)});
Exp memory utility = mul_(assetPrice, cToken.totalBorrows());
borrowTotalUtility = add_(borrowTotalUtility, utility);
borrowAssetCount++;
}
}
if (borrowAssetCount > 0) {
borrowAverageUtility = div_(borrowTotalUtility, borrowAssetCount);
}
}
Exp memory totalUtility = Exp({mantissa : 0});
Exp[] memory utilities = new Exp[](allMarkets_.length);
for (uint i = 0; i < allMarkets_.length; i++) {
CToken cToken = allMarkets_[i];
if (markets[address(cToken)].isComped) {
Exp memory utility;
uint buff = miningBuff[address(cToken)];
Exp memory price = Exp({mantissa : oracle.getUnderlyingPrice(cToken)});
if (buff == 0) buff = 1;
if (miningRule == 0) {//mining by supply
//supply * exchange rate = asset balance
Exp memory supply = Exp({mantissa: cToken.totalSupply()});
//Exp memory exchangeRate = Exp({mantissa: cToken.exchangeRateStored()});
uint assetBalance = mul_(cToken.exchangeRateStored(), supply); // div e18
//usd price * balance = utility
Exp memory realUtility = Exp({mantissa: mul_(assetBalance, price.mantissa)});
utility = mul_(realUtility, buff); //buff
} else if (miningRule == 1) {//mining by borrow
if (borrowGuardianPaused[address(cToken)]) {
//averageUtility with in price
utility = mul_(borrowAverageUtility, buff);
} else {
Exp memory realUtility = mul_(price, cToken.totalBorrows());
utility = mul_(realUtility, buff);
}
} else {//can't support
revert();
}
utilities[i] = utility;
totalUtility = add_(totalUtility, utility);
}
}
for (uint i = 0; i < allMarkets_.length; i++) {
CToken cToken = allMarkets[i];
uint newSpeed = totalUtility.mantissa > 0 ? mul_(compRate, div_(utilities[i], totalUtility)) : 0;
compSpeeds[address(cToken)] = newSpeed;
emit CompSpeedUpdated(cToken, newSpeed, totalUtility.mantissa, utilities[i].mantissa);
}
}
/**
* @notice Accrue COMP to the market by updating the supply index
* @param cToken The market whose supply index to update
*/
function updateCompSupplyIndex(address cToken) internal {
CompMarketState storage supplyState = compSupplyState[cToken];
uint supplySpeed = compSpeeds[cToken];
uint blockNumber = getBlockNumber();
uint deltaBlocks = sub_(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});
Double memory index = add_(Double({mantissa : supplyState.index}), ratio);
compSupplyState[cToken] = CompMarketState({
index : safe224(index.mantissa, "new index exceeds 224 bits"),
block : safe32(blockNumber, "block number exceeds 32 bits")
});
} else if (deltaBlocks > 0) {
supplyState.block = safe32(blockNumber, "block number exceeds 32 bits");
}
}
/**
* @notice Accrue COMP to the market by updating the borrow index
* @param cToken The market whose borrow index to update
*/
function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) internal {
CompMarketState storage borrowState = compBorrowState[cToken];
uint borrowSpeed = compSpeeds[cToken];
uint blockNumber = getBlockNumber();
uint deltaBlocks = sub_(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});
Double memory index = add_(Double({mantissa : borrowState.index}), ratio);
compBorrowState[cToken] = CompMarketState({
index : safe224(index.mantissa, "new index exceeds 224 bits"),
block : safe32(blockNumber, "block number exceeds 32 bits")
});
} else if (deltaBlocks > 0) {
borrowState.block = safe32(blockNumber, "block number exceeds 32 bits");
}
}
/**
* @notice Calculate 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, bool distributeAll) internal {
CompMarketState storage supplyState = compSupplyState[cToken];
Double memory supplyIndex = Double({mantissa : supplyState.index});
Double memory supplierIndex = Double({mantissa : compSupplierIndex[cToken][supplier]});
compSupplierIndex[cToken][supplier] = supplyIndex.mantissa;
if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) {
supplierIndex.mantissa = compInitialIndex;
}
Double memory deltaIndex = sub_(supplyIndex, supplierIndex);
uint supplierTokens = CToken(cToken).balanceOf(supplier);
uint supplierDelta = mul_(supplierTokens, deltaIndex);
uint supplierAccrued = add_(compAccrued[supplier], supplierDelta);
compAccrued[supplier] = transferComp(supplier, supplierAccrued, distributeAll ? 0 : compClaimThreshold);
emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex.mantissa);
}
/**
* @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, bool distributeAll) internal {
CompMarketState storage borrowState = compBorrowState[cToken];
Double memory borrowIndex = Double({mantissa : borrowState.index});
Double memory borrowerIndex = Double({mantissa : compBorrowerIndex[cToken][borrower]});
compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;
if (borrowerIndex.mantissa > 0) {
Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);
uint borrowerAmount = div_(CToken(cToken).borrowBalanceStored(borrower), marketBorrowIndex);
uint borrowerDelta = mul_(borrowerAmount, deltaIndex);
uint borrowerAccrued = add_(compAccrued[borrower], borrowerDelta);
compAccrued[borrower] = transferComp(borrower, borrowerAccrued, distributeAll ? 0 : compClaimThreshold);
emit DistributedBorrowerComp(CToken(cToken), borrower, borrowerDelta, borrowIndex.mantissa);
}
}
/**
* @notice Transfer COMP to the user, if they are above the threshold
* @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 userAccrued The amount of COMP to (possibly) transfer
* @return The amount of COMP which was NOT transferred to the user
*/
function transferComp(address user, uint userAccrued, uint threshold) internal returns (uint) {
if (userAccrued >= threshold && userAccrued > 0) {
Cheese cheese = Cheese(getCheeseAddress());
uint cheeseRemaining = cheese.balanceOf(address(this));
if (userAccrued <= cheeseRemaining) {
cheese.transfer(user, userAccrued);
return 0;
}
}
return userAccrued;
}
/**
* @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, true);
}
}
if (suppliers == true) {
updateCompSupplyIndex(address(cToken));
for (uint j = 0; j < holders.length; j++) {
distributeSupplierComp(address(cToken), holders[j], true);
}
}
}
}
/*** Comp Distribution Admin ***/
/**
* @notice Set the amount of COMP distributed per block
* @param compRate_ The amount of COMP wei per block to distribute
*/
function _setCompRate(uint compRate_) public {
require(adminOrInitializing(), "only admin can change comp rate");
uint oldRate = compRate;
compRate = compRate_;
emit NewCompRate(oldRate, compRate_);
refreshCompSpeedsInternal();
}
/**
* @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel
* @param cTokens The addresses of the markets to add
*/
function _addCompMarkets(address[] memory cTokens) public {
require(adminOrInitializing(), "only admin can add comp market");
for (uint i = 0; i < cTokens.length; i++) {
_addCompMarketInternal(cTokens[i]);
}
refreshCompSpeedsInternal();
}
function _addCompMarketInternal(address cToken) internal {
Market storage market = markets[cToken];
require(market.isListed == true, "comp market is not listed");
require(market.isComped == false, "comp market already added");
market.isComped = true;
emit MarketComped(CToken(cToken), true);
if (compSupplyState[cToken].index == 0 && compSupplyState[cToken].block == 0) {
compSupplyState[cToken] = CompMarketState({
index : compInitialIndex,
block : safe32(getBlockNumber(), "block number exceeds 32 bits")
});
}
if (compBorrowState[cToken].index == 0 && compBorrowState[cToken].block == 0) {
compBorrowState[cToken] = CompMarketState({
index : compInitialIndex,
block : safe32(getBlockNumber(), "block number exceeds 32 bits")
});
}
}
/**
* @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel
* @param cToken The address of the market to drop
*/
function _dropCompMarket(address cToken) public {
require(msg.sender == admin, "only admin can drop comp market");
Market storage market = markets[cToken];
require(market.isComped == true, "market is not a comp market");
market.isComped = false;
emit MarketComped(CToken(cToken), false);
refreshCompSpeedsInternal();
}
function _setMiningBuff(address cToken, uint buff) public {
require(adminOrInitializing(), "only admin can change cheese rate");
miningBuff[cToken] = buff;
}
function _changeMiningRule() public {
if (msg.sender != admin || miningRule != 0) {
return;
}
/*
require(adminOrInitializing(), "only admin can set mining rule");
require(miningRule == 0, "only change mining rule from 0 to 1");
*/
miningRule = 1;
}
/**
* @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;
}
function getBlockNumber() public view returns (uint) {
return block.number;
}
/**
* @notice Return the address of the COMP token
* @return The address of COMP
*/
function getCheeseAddress() public view returns (address) {
return 0xB6Ab412EacEb551d62f8eC63a1d2F30c01e3A2C0;
}
}
pragma solidity ^0.5.16;
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) external returns (uint[] memory);
function exitMarket(address cToken) external returns (uint);
/*** Policy Hooks ***/
function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint);
function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external;
function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint);
function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external;
function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint);
function borrowVerify(address cToken, address borrower, uint borrowAmount) external;
function repayBorrowAllowed(
address cToken,
address payer,
address borrower,
uint repayAmount) external returns (uint);
function repayBorrowVerify(
address cToken,
address payer,
address borrower,
uint repayAmount,
uint borrowerIndex) external;
function liquidateBorrowAllowed(
address cTokenBorrowed,
address cTokenCollateral,
address liquidator,
address borrower,
uint repayAmount) external returns (uint);
function liquidateBorrowVerify(
address cTokenBorrowed,
address cTokenCollateral,
address liquidator,
address borrower,
uint repayAmount,
uint seizeTokens) external;
function seizeAllowed(
address cTokenCollateral,
address cTokenBorrowed,
address liquidator,
address borrower,
uint seizeTokens) external returns (uint);
function seizeVerify(
address cTokenCollateral,
address cTokenBorrowed,
address liquidator,
address borrower,
uint seizeTokens) external;
function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint);
function transferVerify(address cToken, address src, address dst, uint transferTokens) external;
/*** Liquidity/Liquidation Calculations ***/
function liquidateCalculateSeizeTokens(
address cTokenBorrowed,
address cTokenCollateral,
uint repayAmount) external view returns (uint, uint);
}
pragma solidity ^0.5.16;
import "./CToken.sol";
import "./PriceOracle.sol";
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 {
/// @notice Whether or not this market is listed
bool isListed;
/**
* @notice 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;
/// @notice Per-market mapping of "accounts in this asset"
mapping(address => bool) accountMembership;
/// @notice 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 {
/// @notice The market's last updated compBorrowIndex or compSupplyIndex
uint224 index;
/// @notice 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 mining cheese rule, 0 - minting by supply, 1 - minting by borrow
uint public miningRule;
/// @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;
/// @notice The mining CHEESE Buff
mapping(address => uint) public miningBuff;
}
pragma solidity ^0.5.16;
import "./ComptrollerInterface.sol";
import "./CTokenInterfaces.sol";
import "./ErrorReporter.sol";
import "./Exponential.sol";
import "./EIP20Interface.sol";
import "./EIP20NonStandardInterface.sol";
import "./InterestRateModel.sol";
/**
* @title Compound's CToken Contract
* @notice Abstract base for CTokens
* @author Compound
*/
contract CToken is CTokenInterface, Exponential, 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 == uint(Error.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 == uint(Error.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 Whether or not the transfer succeeded
*/
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) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.TRANSFER_COMPTROLLER_REJECTION, allowed);
}
/* Do not allow self-transfers */
if (src == dst) {
return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);
}
/* Get the allowance, infinite for the account owner */
uint startingAllowance = 0;
if (spender == src) {
startingAllowance = uint(-1);
} else {
startingAllowance = transferAllowances[src][spender];
}
/* Do the calculations, checking for {under,over}flow */
MathError mathErr;
uint allowanceNew;
uint srcTokensNew;
uint dstTokensNew;
(mathErr, allowanceNew) = subUInt(startingAllowance, tokens);
if (mathErr != MathError.NO_ERROR) {
return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED);
}
(mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens);
if (mathErr != MathError.NO_ERROR) {
return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH);
}
(mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens);
if (mathErr != MathError.NO_ERROR) {
return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
accountTokens[src] = srcTokensNew;
accountTokens[dst] = dstTokensNew;
/* Eat some of the allowance (if necessary) */
if (startingAllowance != uint(-1)) {
transferAllowances[src][spender] = allowanceNew;
}
/* We emit a Transfer event */
emit Transfer(src, dst, tokens);
comptroller.transferVerify(address(this), src, dst, tokens);
return uint(Error.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) external nonReentrant returns (bool) {
return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.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) external nonReentrant returns (bool) {
return transferTokens(msg.sender, src, dst, amount) == uint(Error.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 (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) 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) 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) 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) external returns (uint) {
Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});
(MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);
require(mErr == MathError.NO_ERROR, "balance could not be calculated");
return balance;
}
/**
* @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) external view returns (uint, uint, uint, uint) {
uint cTokenBalance = accountTokens[account];
uint borrowBalance;
uint exchangeRateMantissa;
MathError mErr;
(mErr, borrowBalance) = borrowBalanceStoredInternal(account);
if (mErr != MathError.NO_ERROR) {
return (uint(Error.MATH_ERROR), 0, 0, 0);
}
(mErr, exchangeRateMantissa) = exchangeRateStoredInternal();
if (mErr != MathError.NO_ERROR) {
return (uint(Error.MATH_ERROR), 0, 0, 0);
}
return (uint(Error.NO_ERROR), cTokenBalance, borrowBalance, exchangeRateMantissa);
}
/**
* @dev Function to simply retrieve block number
* This exists mainly for inheriting test contracts to stub this result.
*/
function getBlockNumber() internal view returns (uint) {
return block.number;
}
/**
* @notice Returns the current per-block borrow interest rate for this cToken
* @return The borrow interest rate per block, scaled by 1e18
*/
function borrowRatePerBlock() 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() 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() external nonReentrant returns (uint) {
require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
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) external nonReentrant returns (uint) {
require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
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) public view returns (uint) {
(MathError err, uint result) = borrowBalanceStoredInternal(account);
require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed");
return result;
}
/**
* @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 (MathError, uint) {
/* Note: we do not assert that the market is up to date */
MathError mathErr;
uint principalTimesIndex;
uint result;
/* Get borrowBalance and borrowIndex */
BorrowSnapshot storage borrowSnapshot = accountBorrows[account];
/* If borrowBalance = 0 then borrowIndex is likely also 0.
* Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
*/
if (borrowSnapshot.principal == 0) {
return (MathError.NO_ERROR, 0);
}
/* Calculate new borrow balance using the interest index:
* recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex
*/
(mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex);
if (mathErr != MathError.NO_ERROR) {
return (mathErr, 0);
}
(mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex);
if (mathErr != MathError.NO_ERROR) {
return (mathErr, 0);
}
return (MathError.NO_ERROR, result);
}
/**
* @notice Accrue interest then return the up-to-date exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateCurrent() public nonReentrant returns (uint) {
require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
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() public view returns (uint) {
(MathError err, uint result) = exchangeRateStoredInternal();
require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed");
return result;
}
/**
* @notice Calculates the exchange rate from the underlying to the CToken
* @dev This function does not accrue interest before calculating the exchange rate
* @return (error code, calculated exchange rate scaled by 1e18)
*/
function exchangeRateStoredInternal() internal view returns (MathError, uint) {
uint _totalSupply = totalSupply;
if (_totalSupply == 0) {
/*
* If there are no tokens minted:
* exchangeRate = initialExchangeRate
*/
return (MathError.NO_ERROR, initialExchangeRateMantissa);
} else {
/*
* Otherwise:
* exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
*/
uint totalCash = getCashPrior();
uint cashPlusBorrowsMinusReserves;
Exp memory exchangeRate;
MathError mathErr;
(mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);
if (mathErr != MathError.NO_ERROR) {
return (mathErr, 0);
}
(mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);
if (mathErr != MathError.NO_ERROR) {
return (mathErr, 0);
}
return (MathError.NO_ERROR, exchangeRate.mantissa);
}
}
/**
* @notice Get cash balance of this cToken in the underlying asset
* @return The quantity of underlying asset owned by this contract
*/
function getCash() 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() public returns (uint) {
/* Remember the initial block number */
uint currentBlockNumber = getBlockNumber();
uint accrualBlockNumberPrior = accrualBlockNumber;
/* Short-circuit accumulating 0 interest */
if (accrualBlockNumberPrior == currentBlockNumber) {
return uint(Error.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 */
(MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);
require(mathErr == MathError.NO_ERROR, "could not calculate block delta");
/*
* Calculate the interest accumulated into borrows and reserves and the new index:
* simpleInterestFactor = borrowRate * blockDelta
* interestAccumulated = simpleInterestFactor * totalBorrows
* totalBorrowsNew = interestAccumulated + totalBorrows
* totalReservesNew = interestAccumulated * reserveFactor + totalReserves
* borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
*/
Exp memory simpleInterestFactor;
uint interestAccumulated;
uint totalBorrowsNew;
uint totalReservesNew;
uint borrowIndexNew;
(mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), blockDelta);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr));
}
(mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, borrowsPrior);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr));
}
(mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr));
}
(mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr));
}
(mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr));
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/* We write the previously calculated values into storage */
accrualBlockNumber = currentBlockNumber;
borrowIndex = borrowIndexNew;
totalBorrows = totalBorrowsNew;
totalReserves = totalReservesNew;
/* We emit an AccrueInterest event */
emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);
return uint(Error.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
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
*/
function mintInternal(uint mintAmount) internal nonReentrant returns (uint, uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
return (fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), 0);
}
// mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to
return mintFresh(msg.sender, mintAmount);
}
struct MintLocalVars {
Error err;
MathError mathErr;
uint exchangeRateMantissa;
uint mintTokens;
uint totalSupplyNew;
uint accountTokensNew;
uint actualMintAmount;
}
/**
* @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
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
*/
function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {
/* Fail if mint not allowed */
uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);
if (allowed != 0) {
return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed), 0);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), 0);
}
MintLocalVars memory vars;
(vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
if (vars.mathErr != MathError.NO_ERROR) {
return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);
}
/////////////////////////
// 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.
*/
vars.actualMintAmount = doTransferIn(minter, mintAmount);
/*
* We get the current exchange rate and calculate the number of cTokens to be minted:
* mintTokens = actualMintAmount / exchangeRate
*/
(vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));
require(vars.mathErr == MathError.NO_ERROR, "MINT_EXCHANGE_CALCULATION_FAILED");
/*
* We calculate the new total supply of cTokens and minter token balance, checking for overflow:
* totalSupplyNew = totalSupply + mintTokens
* accountTokensNew = accountTokens[minter] + mintTokens
*/
(vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);
require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED");
(vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);
require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED");
/* We write previously calculated values into storage */
totalSupply = vars.totalSupplyNew;
accountTokens[minter] = vars.accountTokensNew;
/* We emit a Mint event, and a Transfer event */
emit Mint(minter, vars.actualMintAmount, vars.mintTokens);
emit Transfer(address(this), minter, vars.mintTokens);
/* We call the defense hook */
comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens);
return (uint(Error.NO_ERROR), vars.actualMintAmount);
}
/**
* @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
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
}
// redeemFresh emits redeem-specific logs on errors, so we don't need to
return redeemFresh(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
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
}
// redeemFresh emits redeem-specific logs on errors, so we don't need to
return redeemFresh(msg.sender, 0, redeemAmount);
}
struct RedeemLocalVars {
Error err;
MathError mathErr;
uint exchangeRateMantissa;
uint redeemTokens;
uint redeemAmount;
uint totalSupplyNew;
uint accountTokensNew;
}
/**
* @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)
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {
require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");
RedeemLocalVars memory vars;
/* exchangeRate = invoke Exchange Rate Stored() */
(vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));
}
/* If redeemTokensIn > 0: */
if (redeemTokensIn > 0) {
/*
* We calculate the exchange rate and the amount of underlying to be redeemed:
* redeemTokens = redeemTokensIn
* redeemAmount = redeemTokensIn x exchangeRateCurrent
*/
vars.redeemTokens = redeemTokensIn;
(vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));
}
} else {
/*
* We get the current exchange rate and calculate the amount to be redeemed:
* redeemTokens = redeemAmountIn / exchangeRate
* redeemAmount = redeemAmountIn
*/
(vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));
}
vars.redeemAmount = redeemAmountIn;
}
/* Fail if redeem not allowed */
uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens);
if (allowed != 0) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDEEM_FRESHNESS_CHECK);
}
/*
* We calculate the new total supply and redeemer balance, checking for underflow:
* totalSupplyNew = totalSupply - redeemTokens
* accountTokensNew = accountTokens[redeemer] - redeemTokens
*/
(vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));
}
(vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
}
/* Fail gracefully if protocol has insufficient cash */
if (getCashPrior() < vars.redeemAmount) {
return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We invoke doTransferOut for the redeemer and the redeemAmount.
* Note: The 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, vars.redeemAmount);
/* We write previously calculated values into storage */
totalSupply = vars.totalSupplyNew;
accountTokens[redeemer] = vars.accountTokensNew;
/* We emit a Transfer event, and a Redeem event */
emit Transfer(redeemer, address(this), vars.redeemTokens);
emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);
/* We call the defense hook */
comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens);
return uint(Error.NO_ERROR);
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrowInternal(uint borrowAmount) internal nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
return fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);
}
// borrowFresh emits borrow-specific logs on errors, so we don't need to
return borrowFresh(msg.sender, borrowAmount);
}
struct BorrowLocalVars {
MathError mathErr;
uint accountBorrows;
uint accountBorrowsNew;
uint totalBorrowsNew;
}
/**
* @notice Users borrow assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
/* Fail if borrow not allowed */
uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount);
if (allowed != 0) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.BORROW_COMPTROLLER_REJECTION, allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK);
}
/* Fail gracefully if protocol has insufficient underlying cash */
if (getCashPrior() < borrowAmount) {
return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE);
}
BorrowLocalVars memory vars;
/*
* We calculate the new borrower and total borrow balances, failing on overflow:
* accountBorrowsNew = accountBorrows + borrowAmount
* totalBorrowsNew = totalBorrows + borrowAmount
*/
(vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
}
(vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, borrowAmount);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
}
(vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, borrowAmount);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* 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 write the previously calculated values into storage */
accountBorrows[borrower].principal = vars.accountBorrowsNew;
accountBorrows[borrower].interestIndex = borrowIndex;
totalBorrows = vars.totalBorrowsNew;
/* We emit a Borrow event */
emit Borrow(borrower, borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);
/* We call the defense hook */
comptroller.borrowVerify(address(this), borrower, borrowAmount);
return uint(Error.NO_ERROR);
}
/**
* @notice Sender repays their own borrow
* @param repayAmount The amount to repay
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function repayBorrowInternal(uint repayAmount) internal nonReentrant returns (uint, uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
return (fail(Error(error), FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED), 0);
}
// repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
return 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
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant returns (uint, uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
return (fail(Error(error), FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED), 0);
}
// repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
return repayBorrowFresh(msg.sender, borrower, repayAmount);
}
struct RepayBorrowLocalVars {
Error err;
MathError mathErr;
uint repayAmount;
uint borrowerIndex;
uint accountBorrows;
uint accountBorrowsNew;
uint totalBorrowsNew;
uint actualRepayAmount;
}
/**
* @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 undelrying tokens being returned
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint, uint) {
/* Fail if repayBorrow not allowed */
uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount);
if (allowed != 0) {
return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, allowed), 0);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.REPAY_BORROW_FRESHNESS_CHECK), 0);
}
RepayBorrowLocalVars memory vars;
/* We remember the original borrowerIndex for verification purposes */
vars.borrowerIndex = accountBorrows[borrower].interestIndex;
/* We fetch the amount the borrower owes, with accumulated interest */
(vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
if (vars.mathErr != MathError.NO_ERROR) {
return (failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0);
}
/* If repayAmount == -1, repayAmount = accountBorrows */
if (repayAmount == uint(-1)) {
vars.repayAmount = vars.accountBorrows;
} else {
vars.repayAmount = 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.
*/
vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);
/*
* We calculate the new borrower and total borrow balances, failing on underflow:
* accountBorrowsNew = accountBorrows - actualRepayAmount
* totalBorrowsNew = totalBorrows - actualRepayAmount
*/
(vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.actualRepayAmount);
require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED");
(vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.actualRepayAmount);
require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED");
/* We write the previously calculated values into storage */
accountBorrows[borrower].principal = vars.accountBorrowsNew;
accountBorrows[borrower].interestIndex = borrowIndex;
totalBorrows = vars.totalBorrowsNew;
/* We emit a RepayBorrow event */
emit RepayBorrow(payer, borrower, vars.actualRepayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);
/* We call the defense hook */
comptroller.repayBorrowVerify(address(this), payer, borrower, vars.actualRepayAmount, vars.borrowerIndex);
return (uint(Error.NO_ERROR), vars.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
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function liquidateBorrowInternal(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal nonReentrant returns (uint, uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED), 0);
}
error = cTokenCollateral.accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED), 0);
}
// liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to
return 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
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal returns (uint, uint) {
/* Fail if liquidate not allowed */
uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount);
if (allowed != 0) {
return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, allowed), 0);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_FRESHNESS_CHECK), 0);
}
/* Verify cTokenCollateral market's block number equals current block number */
if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK), 0);
}
/* Fail if borrower = liquidator */
if (borrower == liquidator) {
return (fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER), 0);
}
/* Fail if repayAmount = 0 */
if (repayAmount == 0) {
return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO), 0);
}
/* Fail if repayAmount = -1 */
if (repayAmount == uint(-1)) {
return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX), 0);
}
/* Fail if repayBorrow fails */
(uint repayBorrowError, uint actualRepayAmount) = repayBorrowFresh(liquidator, borrower, repayAmount);
if (repayBorrowError != uint(Error.NO_ERROR)) {
return (fail(Error(repayBorrowError), FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED), 0);
}
/////////////////////////
// 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 == uint(Error.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
uint seizeError;
if (address(cTokenCollateral) == address(this)) {
seizeError = seizeInternal(address(this), liquidator, borrower, seizeTokens);
} else {
seizeError = cTokenCollateral.seize(liquidator, borrower, seizeTokens);
}
/* Revert if seize tokens fails (since we cannot be sure of side effects) */
require(seizeError == uint(Error.NO_ERROR), "token seizure failed");
/* We emit a LiquidateBorrow event */
emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens);
/* We call the defense hook */
comptroller.liquidateBorrowVerify(address(this), address(cTokenCollateral), liquidator, borrower, actualRepayAmount, seizeTokens);
return (uint(Error.NO_ERROR), actualRepayAmount);
}
/**
* @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) external nonReentrant returns (uint) {
return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);
}
/**
* @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
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal returns (uint) {
/* Fail if seize not allowed */
uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);
if (allowed != 0) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed);
}
/* Fail if borrower = liquidator */
if (borrower == liquidator) {
return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER);
}
MathError mathErr;
uint borrowerTokensNew;
uint liquidatorTokensNew;
/*
* We calculate the new borrower and liquidator token balances, failing on underflow/overflow:
* borrowerTokensNew = accountTokens[borrower] - seizeTokens
* liquidatorTokensNew = accountTokens[liquidator] + seizeTokens
*/
(mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr));
}
(mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr));
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/* We write the previously calculated values into storage */
accountTokens[borrower] = borrowerTokensNew;
accountTokens[liquidator] = liquidatorTokensNew;
/* Emit a Transfer event */
emit Transfer(borrower, liquidator, seizeTokens);
/* We call the defense hook */
comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens);
return uint(Error.NO_ERROR);
}
/*** 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) external 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() external 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);
}
/**
* @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) public returns (uint) {
// Check caller is admin
if (msg.sender != admin) {
return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);
}
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 uint(Error.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) external nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed.
return fail(Error(error), FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED);
}
// _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) {
return fail(Error.UNAUTHORIZED, FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK);
}
// Verify market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK);
}
// Check newReserveFactor ≤ maxReserveFactor
if (newReserveFactorMantissa > reserveFactorMaxMantissa) {
return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK);
}
uint oldReserveFactorMantissa = reserveFactorMantissa;
reserveFactorMantissa = newReserveFactorMantissa;
emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);
return uint(Error.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) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed.
return fail(Error(error), FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED);
}
// _addReservesFresh emits reserve-addition-specific logs on errors, so we don't need to.
(error, ) = _addReservesFresh(addAmount);
return 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()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.ADD_RESERVES_FRESH_CHECK), 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;
/* Revert on overflow */
require(totalReservesNew >= totalReserves, "add reserves unexpected overflow");
// 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 (uint(Error.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) external nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed.
return fail(Error(error), FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED);
}
// _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to.
return _reduceReservesFresh(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) {
return fail(Error.UNAUTHORIZED, FailureInfo.REDUCE_RESERVES_ADMIN_CHECK);
}
// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK);
}
// Fail gracefully if protocol has insufficient underlying cash
if (getCashPrior() < reduceAmount) {
return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE);
}
// Check reduceAmount ≤ reserves[n] (totalReserves)
if (reduceAmount > totalReserves) {
return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
totalReservesNew = totalReserves - reduceAmount;
// We checked reduceAmount <= totalReserves above, so this should never revert.
require(totalReservesNew <= totalReserves, "reduce reserves unexpected underflow");
// 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 uint(Error.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) public returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed
return fail(Error(error), FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED);
}
// _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) {
return fail(Error.UNAUTHORIZED, FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK);
}
// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK);
}
// 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 uint(Error.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() 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) internal returns (uint);
/**
* @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather 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) 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
}
}
pragma solidity ^0.5.16;
import "./ComptrollerInterface.sol";
import "./InterestRateModel.sol";
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;
/**
* @notice Maximum borrow rate that can ever be applied (.0005% / block)
*/
uint internal constant borrowRateMaxMantissa = 0.0005e16;
/**
* @notice 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;
/**
* @notice 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;
/**
* @notice Official record of token balances for each account
*/
mapping (address => uint) internal accountTokens;
/**
* @notice 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;
}
/**
* @notice Mapping of account addresses to outstanding borrow balances
*/
mapping(address => BorrowSnapshot) internal accountBorrows;
}
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);
/**
* @notice Failure event
*/
event Failure(uint error, uint info, uint detail);
/*** User Interface ***/
function transfer(address dst, uint amount) external returns (bool);
function transferFrom(address src, address dst, uint amount) external returns (bool);
function approve(address spender, uint amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function balanceOfUnderlying(address owner) external returns (uint);
function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint);
function borrowRatePerBlock() external view returns (uint);
function supplyRatePerBlock() external view returns (uint);
function totalBorrowsCurrent() external returns (uint);
function borrowBalanceCurrent(address account) external returns (uint);
function borrowBalanceStored(address account) public view returns (uint);
function exchangeRateCurrent() public returns (uint);
function exchangeRateStored() public view returns (uint);
function getCash() external view returns (uint);
function accrueInterest() public returns (uint);
function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint);
/*** Admin Functions ***/
function _setPendingAdmin(address payable newPendingAdmin) external returns (uint);
function _acceptAdmin() external returns (uint);
function _setComptroller(ComptrollerInterface newComptroller) public returns (uint);
function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint);
function _reduceReserves(uint reduceAmount) external returns (uint);
function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint);
}
contract CErc20Storage {
/**
* @notice Underlying asset for this CToken
*/
address public underlying;
}
contract CErc20Interface is CErc20Storage {
/*** User Interface ***/
function mint(uint mintAmount) external returns (uint);
function redeem(uint redeemTokens) external returns (uint);
function redeemUnderlying(uint redeemAmount) external returns (uint);
function borrow(uint borrowAmount) external returns (uint);
function repayBorrow(uint repayAmount) external returns (uint);
function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint);
function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint);
/*** Admin Functions ***/
function _addReserves(uint addAmount) external returns (uint);
}
contract CDelegationStorage {
/**
* @notice Implementation address for this contract
*/
address public implementation;
}
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) public;
}
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) public;
/**
* @notice Called by the delegator on a delegate to forfeit its responsibility
*/
function _resignImplementation() public;
}
pragma solidity ^0.5.16;
/**
* @title ERC 20 Token Standard Interface
* https://eips.ethereum.org/EIPS/eip-20
*/
interface EIP20Interface {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
/**
* @notice Get the total number of tokens in circulation
* @return The supply of tokens
*/
function totalSupply() external view returns (uint256);
/**
* @notice Gets the balance of the specified address
* @param owner The address from which the balance will be retrieved
* @return The balance
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint256 amount) external returns (bool success);
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(address src, address dst, uint256 amount) external returns (bool success);
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) external returns (bool success);
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(address owner, address spender) external view returns (uint256 remaining);
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
}
pragma solidity ^0.5.16;
/**
* @title EIP20NonStandardInterface
* @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
* See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
interface EIP20NonStandardInterface {
/**
* @notice Get the total number of tokens in circulation
* @return The supply of tokens
*/
function totalSupply() external view returns (uint256);
/**
* @notice Gets the balance of the specified address
* @param owner The address from which the balance will be retrieved
* @return The balance
*/
function balanceOf(address owner) external view returns (uint256 balance);
///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
*/
function transfer(address dst, uint256 amount) external;
///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
*/
function transferFrom(address src, address dst, uint256 amount) external;
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) external returns (bool success);
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent
*/
function allowance(address owner, address spender) external view returns (uint256 remaining);
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
}
pragma solidity ^0.5.16;
contract ComptrollerErrorReporter {
enum Error {
NO_ERROR, //0
UNAUTHORIZED, //1
COMPTROLLER_MISMATCH, //2
INSUFFICIENT_SHORTFALL, //3
INSUFFICIENT_LIQUIDITY, //4
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 {
enum Error {
NO_ERROR, //0
UNAUTHORIZED, //1
BAD_INPUT, //2
COMPTROLLER_REJECTION, //3
COMPTROLLER_CALCULATION_ERROR,
INTEREST_RATE_MODEL_ERROR,
INVALID_ACCOUNT_PAIR,
INVALID_CLOSE_AMOUNT_REQUESTED,
INVALID_COLLATERAL_FACTOR,
MATH_ERROR,
MARKET_NOT_FRESH,
MARKET_NOT_LISTED,
TOKEN_INSUFFICIENT_ALLOWANCE,
TOKEN_INSUFFICIENT_BALANCE,
TOKEN_INSUFFICIENT_CASH,
TOKEN_TRANSFER_IN_FAILED,
TOKEN_TRANSFER_OUT_FAILED
}
/*
* Note: FailureInfo (but not Error) is kept in alphabetical order
* This is because FailureInfo grows significantly faster, and
* the order of Error has some meaning, while the order of FailureInfo
* is entirely arbitrary.
*/
enum FailureInfo {
ACCEPT_ADMIN_PENDING_ADMIN_CHECK, //0
ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, //1
ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, //2
ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, //3
ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, //4
ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, //5
ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, //6
BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, //7
BORROW_ACCRUE_INTEREST_FAILED, //8
BORROW_CASH_NOT_AVAILABLE, //9
BORROW_FRESHNESS_CHECK, //10
BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, //11
BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, //12
BORROW_MARKET_NOT_LISTED, //13
BORROW_COMPTROLLER_REJECTION, //14
LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,
LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,
LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,
LIQUIDATE_COMPTROLLER_REJECTION,
LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,
LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,
LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,
LIQUIDATE_FRESHNESS_CHECK,
LIQUIDATE_LIQUIDATOR_IS_BORROWER,
LIQUIDATE_REPAY_BORROW_FRESH_FAILED,
LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,
LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,
LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,
LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,
LIQUIDATE_SEIZE_TOO_MUCH,
MINT_ACCRUE_INTEREST_FAILED,
MINT_COMPTROLLER_REJECTION,
MINT_EXCHANGE_CALCULATION_FAILED,
MINT_EXCHANGE_RATE_READ_FAILED,
MINT_FRESHNESS_CHECK,
MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
MINT_TRANSFER_IN_FAILED,
MINT_TRANSFER_IN_NOT_POSSIBLE,
REDEEM_ACCRUE_INTEREST_FAILED,
REDEEM_COMPTROLLER_REJECTION,
REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,
REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,
REDEEM_EXCHANGE_RATE_READ_FAILED,
REDEEM_FRESHNESS_CHECK,
REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
REDEEM_TRANSFER_OUT_NOT_POSSIBLE,
REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,
REDUCE_RESERVES_ADMIN_CHECK,
REDUCE_RESERVES_CASH_NOT_AVAILABLE,
REDUCE_RESERVES_FRESH_CHECK,
REDUCE_RESERVES_VALIDATION,
REPAY_BEHALF_ACCRUE_INTEREST_FAILED,
REPAY_BORROW_ACCRUE_INTEREST_FAILED,
REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_COMPTROLLER_REJECTION,
REPAY_BORROW_FRESHNESS_CHECK,
REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,
SET_COLLATERAL_FACTOR_OWNER_CHECK,
SET_COLLATERAL_FACTOR_VALIDATION,
SET_COMPTROLLER_OWNER_CHECK,
SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED,
SET_INTEREST_RATE_MODEL_FRESH_CHECK,
SET_INTEREST_RATE_MODEL_OWNER_CHECK,
SET_MAX_ASSETS_OWNER_CHECK,
SET_ORACLE_MARKET_NOT_LISTED,
SET_PENDING_ADMIN_OWNER_CHECK,
SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,
SET_RESERVE_FACTOR_ADMIN_CHECK,
SET_RESERVE_FACTOR_FRESH_CHECK,
SET_RESERVE_FACTOR_BOUNDS_CHECK,
TRANSFER_COMPTROLLER_REJECTION,
TRANSFER_NOT_ALLOWED,
TRANSFER_NOT_ENOUGH,
TRANSFER_TOO_MUCH,
ADD_RESERVES_ACCRUE_INTEREST_FAILED,
ADD_RESERVES_FRESH_CHECK,
ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE
}
/**
* @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
* contract-specific code that enables us to report opaque error codes from upgradeable contracts.
**/
event Failure(uint error, uint info, uint detail);
/**
* @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
*/
function fail(Error err, FailureInfo info) internal returns (uint) {
emit Failure(uint(err), uint(info), 0);
return uint(err);
}
/**
* @dev use this when reporting an opaque error from an upgradeable collaborator contract
*/
function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
emit Failure(uint(err), uint(info), opaqueError);
return uint(err);
}
}pragma solidity ^0.5.16;
import "./CarefulMath.sol";
/**
* @title Exponential module for storing fixed-precision decimals
* @author Compound
* @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
* Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
* `Exp({mantissa: 5100000000000000000})`.
*/
contract Exponential is CarefulMath {
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 Creates an exponential from numerator and denominator values.
* Note: Returns an error if (`num` * 10e18) > MAX_INT,
* or if `denom` is zero.
*/
function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {
(MathError err0, uint scaledNumerator) = mulUInt(num, expScale);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
(MathError err1, uint rational) = divUInt(scaledNumerator, denom);
if (err1 != MathError.NO_ERROR) {
return (err1, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: rational}));
}
/**
* @dev Adds two exponentials, returning a new exponential.
*/
function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError error, uint result) = addUInt(a.mantissa, b.mantissa);
return (error, Exp({mantissa: result}));
}
/**
* @dev Subtracts two exponentials, returning a new exponential.
*/
function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError error, uint result) = subUInt(a.mantissa, b.mantissa);
return (error, Exp({mantissa: result}));
}
/**
* @dev Multiply an Exp by a scalar, returning a new Exp.
*/
function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
(MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));
}
/**
* @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
*/
function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {
(MathError err, Exp memory product) = mulScalar(a, scalar);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return (MathError.NO_ERROR, truncate(product));
}
/**
* @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
*/
function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {
(MathError err, Exp memory product) = mulScalar(a, scalar);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return addUInt(truncate(product), addend);
}
/**
* @dev Divide an Exp by a scalar, returning a new Exp.
*/
function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
(MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));
}
/**
* @dev Divide a scalar by an Exp, returning a new Exp.
*/
function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {
/*
We are doing this as:
getExp(mulUInt(expScale, scalar), divisor.mantissa)
How it works:
Exp = a / b;
Scalar = s;
`s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
*/
(MathError err0, uint numerator) = mulUInt(expScale, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return getExp(numerator, divisor.mantissa);
}
/**
* @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.
*/
function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {
(MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return (MathError.NO_ERROR, truncate(fraction));
}
/**
* @dev Multiplies two exponentials, returning a new exponential.
*/
function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
// We add half the scale before dividing so that we get rounding instead of truncation.
// See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
// Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
(MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);
if (err1 != MathError.NO_ERROR) {
return (err1, Exp({mantissa: 0}));
}
(MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);
// The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
assert(err2 == MathError.NO_ERROR);
return (MathError.NO_ERROR, Exp({mantissa: product}));
}
/**
* @dev Multiplies two exponentials given their mantissas, returning a new exponential.
*/
function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {
return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));
}
/**
* @dev Multiplies three exponentials, returning a new exponential.
*/
function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {
(MathError err, Exp memory ab) = mulExp(a, b);
if (err != MathError.NO_ERROR) {
return (err, ab);
}
return mulExp(ab, c);
}
/**
* @dev Divides two exponentials, returning a new exponential.
* (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
* which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
*/
function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
return getExp(a.mantissa, b.mantissa);
}
/**
* @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 Checks if first Exp is less than second Exp.
*/
function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa < right.mantissa;
}
/**
* @dev Checks if left Exp <= right Exp.
*/
function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa <= right.mantissa;
}
/**
* @dev Checks if left Exp > right Exp.
*/
function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa > right.mantissa;
}
/**
* @dev returns true if Exp is exactly zero
*/
function isZeroExp(Exp memory value) pure internal returns (bool) {
return value.mantissa == 0;
}
function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {
require(n < 2**224, errorMessage);
return uint224(n);
}
function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {
require(n < 2**32, errorMessage);
return uint32(n);
}
function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
return Exp({mantissa: add_(a.mantissa, b.mantissa)});
}
function add_(Double memory a, Double memory b) pure internal returns (Double memory) {
return Double({mantissa: add_(a.mantissa, b.mantissa)});
}
function add_(uint a, uint b) pure internal returns (uint) {
return add_(a, b, "addition overflow");
}
function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
uint c = a + b;
require(c >= a, errorMessage);
return c;
}
function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
}
function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {
return Double({mantissa: sub_(a.mantissa, b.mantissa)});
}
function sub_(uint a, uint b) pure internal returns (uint) {
return sub_(a, b, "subtraction underflow");
}
function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
require(b <= a, errorMessage);
return a - b;
}
function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
}
function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {
return Exp({mantissa: mul_(a.mantissa, b)});
}
function mul_(uint a, Exp memory b) pure internal returns (uint) {
return mul_(a, b.mantissa) / expScale;
}
function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {
return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
}
function mul_(Double memory a, uint b) pure internal returns (Double memory) {
return Double({mantissa: mul_(a.mantissa, b)});
}
function mul_(uint a, Double memory b) pure internal returns (uint) {
return mul_(a, b.mantissa) / doubleScale;
}
function mul_(uint a, uint b) pure internal returns (uint) {
return mul_(a, b, "multiplication overflow");
}
function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
if (a == 0 || b == 0) {
return 0;
}
uint c = a * b;
require(c / a == b, errorMessage);
return c;
}
function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
}
function div_(Exp memory a, uint b) pure internal returns (Exp memory) {
return Exp({mantissa: div_(a.mantissa, b)});
}
function div_(uint a, Exp memory b) pure internal returns (uint) {
return div_(mul_(a, expScale), b.mantissa);
}
function div_(Double memory a, Double memory b) pure internal returns (Double memory) {
return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
}
function div_(Double memory a, uint b) pure internal returns (Double memory) {
return Double({mantissa: div_(a.mantissa, b)});
}
function div_(uint a, Double memory b) pure internal returns (uint) {
return div_(mul_(a, doubleScale), b.mantissa);
}
function div_(uint a, uint b) pure internal returns (uint) {
return div_(a, b, "divide by zero");
}
function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
require(b > 0, errorMessage);
return a / b;
}
function fraction(uint a, uint b) pure internal returns (Double memory) {
return Double({mantissa: div_(mul_(a, doubleScale), b)});
}
}
pragma solidity ^0.5.16;
/**
* @title Compound's InterestRateModel Interface
* @author Compound
*/
contract InterestRateModel {
/// @notice Indicator that this is an InterestRateModel contract (for inspection)
bool public constant isInterestRateModel = true;
/**
* @notice Calculates the current borrow interest rate per block
* @param cash The total amount of cash the market has
* @param borrows The total amount of borrows the market has outstanding
* @param reserves The total amnount of reserves the market has
* @return The borrow rate per block (as a percentage, and scaled by 1e18)
*/
function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint);
/**
* @notice Calculates the current supply interest rate per block
* @param cash The total amount of cash the market has
* @param borrows The total amount of borrows the market has outstanding
* @param reserves The total amnount of reserves the market has
* @param reserveFactorMantissa The current reserve factor the market has
* @return The supply rate per block (as a percentage, and scaled by 1e18)
*/
function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint);
}
pragma solidity ^0.5.16;
import "./CToken.sol";
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 sToken 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 sToken) external view returns (uint);
}
pragma solidity ^0.5.16;
// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol
// Subject to the MIT license.
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, errorMessage);
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot underflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction underflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot underflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, errorMessage);
return c;
}
/**
* @dev Returns the integer division of two unsigned integers.
* Reverts on division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers.
* Reverts with custom message on division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
pragma solidity ^0.5.16;
import "./ErrorReporter.sol";
import "./ComptrollerStorage.sol";
/**
* @title ComptrollerCore
* @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`.
* CTokens should reference this contract as their comptroller.
*/
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.
*/
function () 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 Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ComptrollerInterface","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":false,"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"addAmount","type":"uint256"}],"name":"_addReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"_setComptroller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"contract CTokenInterface","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowBehalf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5060038054610100600160a81b0319163361010002179055614f35806100376000396000f3fe608060405234801561001057600080fd5b50600436106102a05760003560e01c80638f840ddd11610167578063c37f68e2116100ce578063f3fdb15a11610087578063f3fdb15a146109ef578063f5e3c462146109f7578063f851a44014610a2d578063f8f9da2814610a35578063fca7820b14610a3d578063fe9c44ae14610a5a576102a0565b8063c37f68e21461090d578063c5ebeaec14610959578063db006a7514610976578063dd62ed3e14610993578063e9c714f2146109c1578063f2b3abbd146109c9576102a0565b8063a9059cbb11610120578063a9059cbb1461086d578063aa5af0fd14610899578063ae9d70b0146108a1578063b2a02ff1146108a9578063b71d1a0c146108df578063bd6d894d14610905576102a0565b80638f840ddd146106c457806395d89b41146106cc57806395dd9193146106d457806399d8c1b4146106fa578063a0712d6814610848578063a6afed9514610865576102a0565b80633af9e6691161020b578063601a0bf1116101c4578063601a0bf11461064c5780636c540baf146106695780636f307dc31461067157806370a082311461067957806373acee981461069f578063852a12e3146106a7576102a0565b80633af9e669146105cb5780633b1d21a2146105f15780633e941010146105f95780634576b5db1461061657806347bd37181461063c5780635fe3b56714610644576102a0565b8063182df0f51161025d578063182df0f5146103c75780631a31d465146103cf57806323b872dd146105275780632608f8181461055d5780632678224714610589578063313ce567146105ad576102a0565b806306fdde03146102a5578063095ea7b3146103225780630e75270214610362578063173b99041461039157806317bfdfbc1461039957806318160ddd146103bf575b600080fd5b6102ad610a62565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102e75781810151838201526020016102cf565b50505050905090810190601f1680156103145780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61034e6004803603604081101561033857600080fd5b506001600160a01b038135169060200135610aef565b604080519115158252519081900360200190f35b61037f6004803603602081101561037857600080fd5b5035610b5c565b60408051918252519081900360200190f35b61037f610b72565b61037f600480360360208110156103af57600080fd5b50356001600160a01b0316610b78565b61037f610c38565b61037f610c3e565b610525600480360360e08110156103e557600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561042757600080fd5b82018360208201111561043957600080fd5b803590602001918460018302840111600160201b8311171561045a57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156104ac57600080fd5b8201836020820111156104be57600080fd5b803590602001918460018302840111600160201b831117156104df57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295505050903560ff169150610ca19050565b005b61034e6004803603606081101561053d57600080fd5b506001600160a01b03813581169160208101359091169060400135610d40565b61037f6004803603604081101561057357600080fd5b506001600160a01b038135169060200135610db2565b610591610dc8565b604080516001600160a01b039092168252519081900360200190f35b6105b5610dd7565b6040805160ff9092168252519081900360200190f35b61037f600480360360208110156105e157600080fd5b50356001600160a01b0316610de0565b61037f610e96565b61037f6004803603602081101561060f57600080fd5b5035610ea5565b61037f6004803603602081101561062c57600080fd5b50356001600160a01b0316610eb0565b61037f611005565b61059161100b565b61037f6004803603602081101561066257600080fd5b503561101a565b61037f6110b5565b6105916110bb565b61037f6004803603602081101561068f57600080fd5b50356001600160a01b03166110ca565b61037f6110e5565b61037f600480360360208110156106bd57600080fd5b503561119b565b61037f6111a6565b6102ad6111ac565b61037f600480360360208110156106ea57600080fd5b50356001600160a01b0316611204565b610525600480360360c081101561071057600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561074a57600080fd5b82018360208201111561075c57600080fd5b803590602001918460018302840111600160201b8311171561077d57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156107cf57600080fd5b8201836020820111156107e157600080fd5b803590602001918460018302840111600160201b8311171561080257600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295505050903560ff1691506112619050565b61037f6004803603602081101561085e57600080fd5b5035611448565b61037f611454565b61034e6004803603604081101561088357600080fd5b506001600160a01b0381351690602001356117ac565b61037f61181d565b61037f611823565b61037f600480360360608110156108bf57600080fd5b506001600160a01b038135811691602081013590911690604001356118c2565b61037f600480360360208110156108f557600080fd5b50356001600160a01b0316611933565b61037f6119bf565b6109336004803603602081101561092357600080fd5b50356001600160a01b0316611a7b565b604080519485526020850193909352838301919091526060830152519081900360800190f35b61037f6004803603602081101561096f57600080fd5b5035611b10565b61037f6004803603602081101561098c57600080fd5b5035611b1b565b61037f600480360360408110156109a957600080fd5b506001600160a01b0381358116916020013516611b26565b61037f611b51565b61037f600480360360208110156109df57600080fd5b50356001600160a01b0316611c54565b610591611c8e565b61037f60048036036060811015610a0d57600080fd5b506001600160a01b03813581169160208101359160409091013516611c9d565b610591611cb5565b61037f611cc9565b61037f60048036036020811015610a5357600080fd5b5035611d2d565b61034e611dab565b60018054604080516020600284861615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ae75780601f10610abc57610100808354040283529160200191610ae7565b820191906000526020600020905b815481529060010190602001808311610aca57829003601f168201915b505050505081565b336000818152600f602090815260408083206001600160a01b03871680855290835281842086905581518681529151939493909284927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a360019150505b92915050565b600080610b6883611db0565b509150505b919050565b60085481565b6000805460ff16610bbd576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155610bcf611454565b14610c1a576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b610c2382611204565b90505b6000805460ff19166001179055919050565b600d5481565b6000806000610c4b611e59565b90925090506000826003811115610c5e57fe5b14610c9a5760405162461bcd60e51b8152600401808060200182810382526035815260200180614e4c6035913960400191505060405180910390fd5b9150505b90565b610caf868686868686611261565b601180546001600160a01b0319166001600160a01b038981169190911791829055604080516318160ddd60e01b8152905192909116916318160ddd91600480820192602092909190829003018186803b158015610d0b57600080fd5b505afa158015610d1f573d6000803e3d6000fd5b505050506040513d6020811015610d3557600080fd5b505050505050505050565b6000805460ff16610d85576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155610d9b33868686611f08565b1490506000805460ff191660011790559392505050565b600080610dbf8484612216565b50949350505050565b6004546001600160a01b031681565b60035460ff1681565b6000610dea614b3a565b6040518060200160405280610dfd6119bf565b90526001600160a01b0384166000908152600e6020526040812054919250908190610e299084906122c1565b90925090506000826003811115610e3c57fe5b14610e8e576040805162461bcd60e51b815260206004820152601f60248201527f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400604482015290519081900360640190fd5b949350505050565b6000610ea0612315565b905090565b6000610b5682612395565b60035460009061010090046001600160a01b03163314610edd57610ed66001603f612429565b9050610b6d565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b158015610f2257600080fd5b505afa158015610f36573d6000803e3d6000fd5b505050506040513d6020811015610f4c57600080fd5b5051610f9f576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160005b9392505050565b600b5481565b6005546001600160a01b031681565b6000805460ff1661105f576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611071611454565b905080156110975761108f81601081111561108857fe5b6030612429565b915050610c26565b6110a08361248f565b9150506000805460ff19166001179055919050565b60095481565b6011546001600160a01b031681565b6001600160a01b03166000908152600e602052604090205490565b6000805460ff1661112a576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561113c611454565b14611187576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b50600b546000805460ff1916600117905590565b6000610b56826125c2565b600c5481565b6002805460408051602060018416156101000260001901909316849004601f81018490048402820184019092528181529291830182828015610ae75780601f10610abc57610100808354040283529160200191610ae7565b600080600061121284612643565b9092509050600082600381111561122557fe5b14610ffe5760405162461bcd60e51b8152600401808060200182810382526037815260200180614d576037913960400191505060405180910390fd5b60035461010090046001600160a01b031633146112af5760405162461bcd60e51b8152600401808060200182810382526024815260200180614c936024913960400191505060405180910390fd5b6009541580156112bf5750600a54155b6112fa5760405162461bcd60e51b8152600401808060200182810382526023815260200180614cb76023913960400191505060405180910390fd5b60078490558361133b5760405162461bcd60e51b8152600401808060200182810382526030815260200180614cda6030913960400191505060405180910390fd5b600061134687610eb0565b9050801561139b576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b6113a36126f7565b600955670de0b6b3a7640000600a556113bb866126fb565b905080156113fa5760405162461bcd60e51b8152600401808060200182810382526022815260200180614d0a6022913960400191505060405180910390fd5b835161140d906001906020870190614b4d565b508251611421906002906020860190614b4d565b50506003805460ff90921660ff199283161790556000805490911660011790555050505050565b600080610b6883612870565b60008061145f6126f7565b6009549091508082141561147857600092505050610c9e565b6000611482612315565b600b54600c54600a54600654604080516315f2405360e01b815260048101879052602481018690526044810185905290519596509394929391926000926001600160a01b03909216916315f24053916064808301926020929190829003018186803b1580156114f057600080fd5b505afa158015611504573d6000803e3d6000fd5b505050506040513d602081101561151a57600080fd5b5051905065048c27395000811115611579576040805162461bcd60e51b815260206004820152601c60248201527f626f72726f772072617465206973206162737572646c79206869676800000000604482015290519081900360640190fd5b60008061158689896128f1565b9092509050600082600381111561159957fe5b146115eb576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b6115f3614b3a565b60008060008061161160405180602001604052808a81525087612914565b9097509450600087600381111561162457fe5b14611656576116416009600689600381111561163c57fe5b61297c565b9e505050505050505050505050505050610c9e565b611660858c6122c1565b9097509350600087600381111561167357fe5b1461168b576116416009600189600381111561163c57fe5b611695848c6129e2565b909750925060008760038111156116a857fe5b146116c0576116416009600489600381111561163c57fe5b6116db6040518060200160405280600854815250858c612a08565b909750915060008760038111156116ee57fe5b14611706576116416009600589600381111561163c57fe5b611711858a8b612a08565b9097509050600087600381111561172457fe5b1461173c576116416009600389600381111561163c57fe5b60098e9055600a819055600b839055600c829055604080518d8152602081018690528082018390526060810185905290517f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049181900360800190a160009e50505050505050505050505050505090565b6000805460ff166117f1576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561180733338686611f08565b1490506000805460ff1916600117905592915050565b600a5481565b6006546000906001600160a01b031663b816881661183f612315565b600b54600c546008546040518563ffffffff1660e01b81526004018085815260200184815260200183815260200182815260200194505050505060206040518083038186803b15801561189157600080fd5b505afa1580156118a5573d6000803e3d6000fd5b505050506040513d60208110156118bb57600080fd5b5051905090565b6000805460ff16611907576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916905561191d33858585612a64565b90506000805460ff191660011790559392505050565b60035460009061010090046001600160a01b0316331461195957610ed660016045612429565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610ffe565b6000805460ff16611a04576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611a16611454565b14611a61576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b611a69610c3e565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600e6020526040812054819081908190818080611aa689612643565b935090506000816003811115611ab857fe5b14611ad65760095b975060009650869550859450611b099350505050565b611ade611e59565b925090506000816003811115611af057fe5b14611afc576009611ac0565b5060009650919450925090505b9193509193565b6000610b5682612cca565b6000610b5682612d49565b6001600160a01b039182166000908152600f6020908152604080832093909416825291909152205490565b6004546000906001600160a01b031633141580611b6c575033155b15611b8457611b7d60016000612429565b9050610c9e565b60038054600480546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401528351909391927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600454604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a160009250505090565b600080611c5f611454565b90508015611c8557611c7d816010811115611c7657fe5b6040612429565b915050610b6d565b610ffe836126fb565b6006546001600160a01b031681565b600080611cab858585612dc3565b5095945050505050565b60035461010090046001600160a01b031681565b6006546000906001600160a01b03166315f24053611ce5612315565b600b54600c546040518463ffffffff1660e01b815260040180848152602001838152602001828152602001935050505060206040518083038186803b15801561189157600080fd5b6000805460ff16611d72576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611d84611454565b90508015611da25761108f816010811115611d9b57fe5b6046612429565b6110a083612ef5565b600181565b60008054819060ff16611df7576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611e09611454565b90508015611e3457611e27816010811115611e2057fe5b6036612429565b925060009150611e459050565b611e3f333386612f9d565b92509250505b6000805460ff191660011790559092909150565b600d54600090819080611e7457505060075460009150611f04565b6000611e7e612315565b90506000611e8a614b3a565b6000611e9b84600b54600c54613382565b935090506000816003811115611ead57fe5b14611ec257955060009450611f049350505050565b611ecc83866133c0565b925090506000816003811115611ede57fe5b14611ef357955060009450611f049350505050565b5051600095509350611f0492505050565b9091565b600554604080516317b9b84b60e31b81523060048201526001600160a01b03868116602483015285811660448301526064820185905291516000938493169163bdcdc25891608480830192602092919082900301818787803b158015611f6d57600080fd5b505af1158015611f81573d6000803e3d6000fd5b505050506040513d6020811015611f9757600080fd5b505190508015611fb657611fae6003604a8361297c565b915050610e8e565b836001600160a01b0316856001600160a01b03161415611fdc57611fae6002604b612429565b60006001600160a01b038781169087161415611ffb5750600019612023565b506001600160a01b038086166000908152600f60209081526040808320938a16835292905220545b60008060008061203385896128f1565b9094509250600084600381111561204657fe5b14612064576120576009604b612429565b9650505050505050610e8e565b6001600160a01b038a166000908152600e602052604090205461208790896128f1565b9094509150600084600381111561209a57fe5b146120ab576120576009604c612429565b6001600160a01b0389166000908152600e60205260409020546120ce90896129e2565b909450905060008460038111156120e157fe5b146120f2576120576009604d612429565b6001600160a01b03808b166000908152600e6020526040808220859055918b16815220819055600019851461214a576001600160a01b03808b166000908152600f60209081526040808320938f168352929052208390555b886001600160a01b03168a6001600160a01b0316600080516020614dc88339815191528a6040518082815260200191505060405180910390a36005546040805163352b4a3f60e11b81523060048201526001600160a01b038d811660248301528c81166044830152606482018c905291519190921691636a56947e91608480830192600092919082900301818387803b1580156121e657600080fd5b505af11580156121fa573d6000803e3d6000fd5b5060009250612207915050565b9b9a5050505050505050505050565b60008054819060ff1661225d576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561226f611454565b9050801561229a5761228d81601081111561228657fe5b6035612429565b9250600091506122ab9050565b6122a5338686612f9d565b92509250505b6000805460ff1916600117905590939092509050565b60008060006122ce614b3a565b6122d88686612914565b909250905060008260038111156122eb57fe5b146122fc575091506000905061230e565b600061230782613470565b9350935050505b9250929050565b601154604080516370a0823160e01b815230600482015290516000926001600160a01b03169182916370a0823191602480820192602092909190829003018186803b15801561236357600080fd5b505afa158015612377573d6000803e3d6000fd5b505050506040513d602081101561238d57600080fd5b505191505090565b6000805460ff166123da576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556123ec611454565b9050801561240a5761108f81601081111561240357fe5b604e612429565b6124138361347f565b509150506000805460ff19166001179055919050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601081111561245857fe5b83605081111561246457fe5b604080519283526020830191909152600082820152519081900360600190a1826010811115610ffe57fe5b600354600090819061010090046001600160a01b031633146124b757611c7d60016031612429565b6124bf6126f7565b600954146124d357611c7d600a6033612429565b826124dc612315565b10156124ee57611c7d600e6032612429565b600c5483111561250457611c7d60026034612429565b50600c548281039081111561254a5760405162461bcd60e51b8152600401808060200182810382526024815260200180614edd6024913960400191505060405180910390fd5b600c81905560035461256a9061010090046001600160a01b031684613567565b600354604080516101009092046001600160a01b0316825260208201859052818101839052517f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e916060908290030190a16000610ffe565b6000805460ff16612607576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612619611454565b905080156126375761108f81601081111561263057fe5b6027612429565b6110a03360008561365e565b6001600160a01b03811660009081526010602052604081208054829182918291829161267a5750600094508493506126f292505050565b61268a8160000154600a54613b25565b9094509250600084600381111561269d57fe5b146126b25750919350600092506126f2915050565b6126c0838260010154613b64565b909450915060008460038111156126d357fe5b146126e85750919350600092506126f2915050565b5060009450925050505b915091565b4390565b600354600090819061010090046001600160a01b0316331461272357611c7d60016042612429565b61272b6126f7565b6009541461273f57611c7d600a6041612429565b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561279057600080fd5b505afa1580156127a4573d6000803e3d6000fd5b505050506040513d60208110156127ba57600080fd5b505161280d576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600680546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a16000610ffe565b60008054819060ff166128b7576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556128c9611454565b905080156128e757611e278160108111156128e057fe5b601e612429565b611e3f3385613b8f565b60008083831161290857506000905081830361230e565b5060039050600061230e565b600061291e614b3a565b60008061292f866000015186613b25565b9092509050600082600381111561294257fe5b146129615750604080516020810190915260008152909250905061230e565b60408051602081019091529081526000969095509350505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460108111156129ab57fe5b8460508111156129b757fe5b604080519283526020830191909152818101859052519081900360600190a1836010811115610e8e57fe5b6000808383018481106129fa5760009250905061230e565b50600291506000905061230e565b6000806000612a15614b3a565b612a1f8787612914565b90925090506000826003811115612a3257fe5b14612a435750915060009050612a5c565b612a55612a4f82613470565b866129e2565b9350935050505b935093915050565b6005546040805163d02f735160e01b81523060048201526001600160a01b038781166024830152868116604483015285811660648301526084820185905291516000938493169163d02f73519160a480830192602092919082900301818787803b158015612ad157600080fd5b505af1158015612ae5573d6000803e3d6000fd5b505050506040513d6020811015612afb57600080fd5b505190508015612b1257611fae6003601b8361297c565b846001600160a01b0316846001600160a01b03161415612b3857611fae6006601c612429565b6001600160a01b0384166000908152600e602052604081205481908190612b5f90876128f1565b90935091506000836003811115612b7257fe5b14612b9557612b8a6009601a85600381111561163c57fe5b945050505050610e8e565b6001600160a01b0388166000908152600e6020526040902054612bb890876129e2565b90935090506000836003811115612bcb57fe5b14612be357612b8a6009601985600381111561163c57fe5b6001600160a01b038088166000818152600e60209081526040808320879055938c168083529184902085905583518a815293519193600080516020614dc8833981519152929081900390910190a360055460408051636d35bf9160e01b81523060048201526001600160a01b038c811660248301528b811660448301528a81166064830152608482018a905291519190921691636d35bf919160a480830192600092919082900301818387803b158015612c9c57600080fd5b505af1158015612cb0573d6000803e3d6000fd5b5060009250612cbd915050565b9998505050505050505050565b6000805460ff16612d0f576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612d21611454565b90508015612d3f5761108f816010811115612d3857fe5b6008612429565b6110a03384613fee565b6000805460ff16612d8e576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612da0611454565b90508015612db75761108f81601081111561263057fe5b6110a03384600061365e565b60008054819060ff16612e0a576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612e1c611454565b90508015612e4757612e3a816010811115612e3357fe5b600f612429565b925060009150612ede9050565b836001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e8257600080fd5b505af1158015612e96573d6000803e3d6000fd5b505050506040513d6020811015612eac57600080fd5b505190508015612ecc57612e3a816010811115612ec557fe5b6010612429565b612ed8338787876142fc565b92509250505b6000805460ff191660011790559094909350915050565b60035460009061010090046001600160a01b03163314612f1b57610ed660016047612429565b612f236126f7565b60095414612f3757610ed6600a6048612429565b670de0b6b3a7640000821115612f5357610ed660026049612429565b6008805490839055604080518281526020810185905281517faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460929181900390910190a16000610ffe565b60055460408051631200453160e11b81523060048201526001600160a01b0386811660248301528581166044830152606482018590529151600093849384939116916324008a629160848082019260209290919082900301818787803b15801561300657600080fd5b505af115801561301a573d6000803e3d6000fd5b505050506040513d602081101561303057600080fd5b50519050801561305457613047600360388361297c565b925060009150612a5c9050565b61305c6126f7565b6009541461307057613047600a6039612429565b613078614bcb565b6001600160a01b03861660009081526010602052604090206001015460608201526130a286612643565b60808301819052602083018260038111156130b957fe5b60038111156130c457fe5b90525060009050816020015160038111156130db57fe5b14613105576130f7600960378360200151600381111561163c57fe5b935060009250612a5c915050565b60001985141561311e5760808101516040820152613126565b604081018590525b61313487826040015161487f565b60e082018190526080820151613149916128f1565b60a083018190526020830182600381111561316057fe5b600381111561316b57fe5b905250600090508160200151600381111561318257fe5b146131be5760405162461bcd60e51b815260040180806020018281038252603a815260200180614d8e603a913960400191505060405180910390fd5b6131ce600b548260e001516128f1565b60c08301819052602083018260038111156131e557fe5b60038111156131f057fe5b905250600090508160200151600381111561320757fe5b146132435760405162461bcd60e51b8152600401808060200182810382526031815260200180614de86031913960400191505060405180910390fd5b60a080820180516001600160a01b03808a16600081815260106020908152604091829020948555600a5460019095019490945560c0870151600b81905560e088015195518251948f16855294840192909252828101949094526060820192909252608081019190915290517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1929181900390910190a160055460e0820151606083015160408051631ededc9160e01b81523060048201526001600160a01b038c811660248301528b8116604483015260648201949094526084810192909252519190921691631ededc919160a480830192600092919082900301818387803b15801561334e57600080fd5b505af1158015613362573d6000803e3d6000fd5b506000925061336f915050565b8160e00151935093505050935093915050565b60008060008061339287876129e2565b909250905060008260038111156133a557fe5b146133b65750915060009050612a5c565b612a5581866128f1565b60006133ca614b3a565b6000806133df86670de0b6b3a7640000613b25565b909250905060008260038111156133f257fe5b146134115750604080516020810190915260008152909250905061230e565b60008061341e8388613b64565b9092509050600082600381111561343157fe5b146134535750604080516020810190915260008152909450925061230e915050565b604080516020810190915290815260009890975095505050505050565b51670de0b6b3a7640000900490565b60008060008061348d6126f7565b600954146134ac576134a1600a604f612429565b935091506126f29050565b6134b6338661487f565b905080600c54019150600c54821015613516576040805162461bcd60e51b815260206004820181905260248201527f61646420726573657276657320756e6578706563746564206f766572666c6f77604482015290519081900360640190fd5b600c829055604080513381526020810183905280820184905290517fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc59181900360600190a160009350915050915091565b6011546040805163a9059cbb60e01b81526001600160a01b0385811660048301526024820185905291519190921691829163a9059cbb9160448082019260009290919082900301818387803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b5050505060003d600081146135ef57602081146135f957600080fd5b6000199150613605565b60206000803e60005191505b5080613658576040805162461bcd60e51b815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b50505050565b600082158061366b575081155b6136a65760405162461bcd60e51b8152600401808060200182810382526034815260200180614ea96034913960400191505060405180910390fd5b6136ae614c11565b6136b6611e59565b60408301819052602083018260038111156136cd57fe5b60038111156136d857fe5b90525060009050816020015160038111156136ef57fe5b146137135761370b6009602b8360200151600381111561163c57fe5b915050610ffe565b831561379457606081018490526040805160208101825290820151815261373a90856122c1565b608083018190526020830182600381111561375157fe5b600381111561375c57fe5b905250600090508160200151600381111561377357fe5b1461378f5761370b600960298360200151600381111561163c57fe5b61380d565b6137b08360405180602001604052808460400151815250614ac9565b60608301819052602083018260038111156137c757fe5b60038111156137d257fe5b90525060009050816020015160038111156137e957fe5b146138055761370b6009602a8360200151600381111561163c57fe5b608081018390525b60055460608201516040805163eabe7d9160e01b81523060048201526001600160a01b03898116602483015260448201939093529051600093929092169163eabe7d919160648082019260209290919082900301818787803b15801561387257600080fd5b505af1158015613886573d6000803e3d6000fd5b505050506040513d602081101561389c57600080fd5b5051905080156138bc576138b3600360288361297c565b92505050610ffe565b6138c46126f7565b600954146138d8576138b3600a602c612429565b6138e8600d5483606001516128f1565b60a08401819052602084018260038111156138ff57fe5b600381111561390a57fe5b905250600090508260200151600381111561392157fe5b1461393d576138b36009602e8460200151600381111561163c57fe5b6001600160a01b0386166000908152600e6020526040902054606083015161396591906128f1565b60c084018190526020840182600381111561397c57fe5b600381111561398757fe5b905250600090508260200151600381111561399e57fe5b146139ba576138b36009602d8460200151600381111561163c57fe5b81608001516139c7612315565b10156139d9576138b3600e602f612429565b6139e7868360800151613567565b60a0820151600d5560c08201516001600160a01b0387166000818152600e6020908152604091829020939093556060850151815190815290513093600080516020614dc8833981519152928290030190a36080820151606080840151604080516001600160a01b038b168152602081019490945283810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a9299281900390910190a160055460808301516060840151604080516351dff98960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916351dff98991608480830192600092919082900301818387803b158015613afa57600080fd5b505af1158015613b0e573d6000803e3d6000fd5b5060009250613b1b915050565b9695505050505050565b60008083613b385750600090508061230e565b83830283858281613b4557fe5b0414613b595750600291506000905061230e565b60009250905061230e565b60008082613b78575060019050600061230e565b6000838581613b8357fe5b04915091509250929050565b60055460408051634ef4c3e160e01b81523060048201526001600160a01b03858116602483015260448201859052915160009384938493911691634ef4c3e19160648082019260209290919082900301818787803b158015613bf057600080fd5b505af1158015613c04573d6000803e3d6000fd5b505050506040513d6020811015613c1a57600080fd5b505190508015613c3e57613c316003601f8361297c565b92506000915061230e9050565b613c466126f7565b60095414613c5a57613c31600a6022612429565b613c62614c11565b613c6a611e59565b6040830181905260208301826003811115613c8157fe5b6003811115613c8c57fe5b9052506000905081602001516003811115613ca357fe5b14613ccd57613cbf600960218360200151600381111561163c57fe5b93506000925061230e915050565b613cd7868661487f565b60c0820181905260408051602081018252908301518152613cf89190614ac9565b6060830181905260208301826003811115613d0f57fe5b6003811115613d1a57fe5b9052506000905081602001516003811115613d3157fe5b14613d83576040805162461bcd60e51b815260206004820181905260248201527f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544604482015290519081900360640190fd5b613d93600d5482606001516129e2565b6080830181905260208301826003811115613daa57fe5b6003811115613db557fe5b9052506000905081602001516003811115613dcc57fe5b14613e085760405162461bcd60e51b8152600401808060200182810382526028815260200180614e816028913960400191505060405180910390fd5b6001600160a01b0386166000908152600e60205260409020546060820151613e3091906129e2565b60a0830181905260208301826003811115613e4757fe5b6003811115613e5257fe5b9052506000905081602001516003811115613e6957fe5b14613ea55760405162461bcd60e51b815260040180806020018281038252602b815260200180614d2c602b913960400191505060405180910390fd5b6080810151600d5560a08101516001600160a01b0387166000818152600e60209081526040918290209390935560c084015160608086015183519485529484019190915282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160a01b038816913091600080516020614dc88339815191529181900360200190a360055460c08201516060830151604080516341c728b960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916341c728b991608480830192600092919082900301818387803b158015613fbb57600080fd5b505af1158015613fcf573d6000803e3d6000fd5b5060009250613fdc915050565b8160c001519350935050509250929050565b6005546040805163368f515360e21b81523060048201526001600160a01b0385811660248301526044820185905291516000938493169163da3d454c91606480830192602092919082900301818787803b15801561404b57600080fd5b505af115801561405f573d6000803e3d6000fd5b505050506040513d602081101561407557600080fd5b5051905080156140945761408c6003600e8361297c565b915050610b56565b61409c6126f7565b600954146140af5761408c600a80612429565b826140b8612315565b10156140ca5761408c600e6009612429565b6140d2614c4f565b6140db85612643565b60208301819052828260038111156140ef57fe5b60038111156140fa57fe5b905250600090508151600381111561410e57fe5b146141335761412a600960078360000151600381111561163c57fe5b92505050610b56565b6141418160200151856129e2565b604083018190528282600381111561415557fe5b600381111561416057fe5b905250600090508151600381111561417457fe5b146141905761412a6009600c8360000151600381111561163c57fe5b61419c600b54856129e2565b60608301819052828260038111156141b057fe5b60038111156141bb57fe5b90525060009050815160038111156141cf57fe5b146141eb5761412a6009600b8360000151600381111561163c57fe5b6141f58585613567565b604080820180516001600160a01b03881660008181526010602090815290859020928355600a54600190930192909255606080860151600b81905593518551928352928201899052818501929092529081019190915290517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab809181900360800190a160055460408051635c77860560e01b81523060048201526001600160a01b0388811660248301526044820188905291519190921691635c77860591606480830192600092919082900301818387803b1580156142d257600080fd5b505af11580156142e6573d6000803e3d6000fd5b50600092506142f3915050565b95945050505050565b60055460408051632fe3f38f60e11b81523060048201526001600160a01b0384811660248301528781166044830152868116606483015260848201869052915160009384938493911691635fc7e71e9160a48082019260209290919082900301818787803b15801561436d57600080fd5b505af1158015614381573d6000803e3d6000fd5b505050506040513d602081101561439757600080fd5b5051905080156143bb576143ae600360128361297c565b9250600091506148769050565b6143c36126f7565b600954146143d7576143ae600a6016612429565b6143df6126f7565b846001600160a01b0316636c540baf6040518163ffffffff1660e01b815260040160206040518083038186803b15801561441857600080fd5b505afa15801561442c573d6000803e3d6000fd5b505050506040513d602081101561444257600080fd5b505114614455576143ae600a6011612429565b866001600160a01b0316866001600160a01b0316141561447b576143ae60066017612429565b8461448c576143ae60076015612429565b6000198514156144a2576143ae60076014612429565b6000806144b0898989612f9d565b909250905081156144e0576144d18260108111156144ca57fe5b6018612429565b94506000935061487692505050565b6005546040805163c488847b60e01b81523060048201526001600160a01b038981166024830152604482018590528251600094859492169263c488847b926064808301939192829003018186803b15801561453a57600080fd5b505afa15801561454e573d6000803e3d6000fd5b505050506040513d604081101561456457600080fd5b508051602090910151909250905081156145af5760405162461bcd60e51b8152600401808060200182810382526033815260200180614e196033913960400191505060405180910390fd5b80886001600160a01b03166370a082318c6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561460657600080fd5b505afa15801561461a573d6000803e3d6000fd5b505050506040513d602081101561463057600080fd5b50511015614685576040805162461bcd60e51b815260206004820152601860248201527f4c49515549444154455f5345495a455f544f4f5f4d5543480000000000000000604482015290519081900360640190fd5b60006001600160a01b0389163014156146ab576146a4308d8d85612a64565b9050614735565b6040805163b2a02ff160e01b81526001600160a01b038e811660048301528d81166024830152604482018590529151918b169163b2a02ff1916064808201926020929091908290030181600087803b15801561470657600080fd5b505af115801561471a573d6000803e3d6000fd5b505050506040513d602081101561473057600080fd5b505190505b801561477f576040805162461bcd60e51b81526020600482015260146024820152731d1bdad95b881cd95a5e9d5c994819985a5b195960621b604482015290519081900360640190fd5b604080516001600160a01b03808f168252808e1660208301528183018790528b1660608201526080810184905290517f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb529181900360a00190a1600554604080516347ef3b3b60e01b81523060048201526001600160a01b038c811660248301528f811660448301528e811660648301526084820188905260a48201869052915191909216916347ef3b3b9160c480830192600092919082900301818387803b15801561484a57600080fd5b505af115801561485e573d6000803e3d6000fd5b506000925061486b915050565b975092955050505050505b94509492505050565b601154604080516370a0823160e01b815230600482015290516000926001600160a01b031691839183916370a08231916024808301926020929190829003018186803b1580156148ce57600080fd5b505afa1580156148e2573d6000803e3d6000fd5b505050506040513d60208110156148f857600080fd5b5051604080516323b872dd60e01b81526001600160a01b038881166004830152306024830152604482018890529151929350908416916323b872dd9160648082019260009290919082900301818387803b15801561495557600080fd5b505af1158015614969573d6000803e3d6000fd5b5050505060003d60008114614985576020811461498f57600080fd5b600019915061499b565b60206000803e60005191505b50806149ee576040805162461bcd60e51b815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b601154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015614a3957600080fd5b505afa158015614a4d573d6000803e3d6000fd5b505050506040513d6020811015614a6357600080fd5b5051905082811015614abc576040805162461bcd60e51b815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b6000806000614ad6614b3a565b6122d886866000614ae5614b3a565b600080614afa670de0b6b3a764000087613b25565b90925090506000826003811115614b0d57fe5b14614b2c5750604080516020810190915260008152909250905061230e565b6123078186600001516133c0565b6040518060200160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614b8e57805160ff1916838001178555614bbb565b82800160010185558215614bbb579182015b82811115614bbb578251825591602001919060010190614ba0565b50614bc7929150614c78565b5090565b6040805161010081019091528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604080516080810190915280600081526020016000815260200160008152602001600081525090565b610c9e91905b80821115614bc75760008155600101614c7e56fe6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e73657474696e6720696e7465726573742072617465206d6f64656c206661696c65644d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4154494f4e5f4641494c4544626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e636553746f726564496e7465726e616c206661696c656452455041595f424f52524f575f4e45575f4143434f554e545f424f52524f575f42414c414e43455f43414c43554c4154494f4e5f4641494c4544ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef52455041595f424f52524f575f4e45575f544f54414c5f42414c414e43455f43414c43554c4154494f4e5f4641494c45444c49515549444154455f434f4d5054524f4c4c45525f43414c43554c4154455f414d4f554e545f5345495a455f4641494c454465786368616e67655261746553746f7265643a2065786368616e67655261746553746f726564496e7465726e616c206661696c65644d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f4e5f4641494c45446f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726f72656475636520726573657276657320756e657870656374656420756e646572666c6f77a265627a7a7231582025fba71478c63f62af5c57c35cb91b96c8d75f7099759f3953426dbbef43562064736f6c63430005110032
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102a05760003560e01c80638f840ddd11610167578063c37f68e2116100ce578063f3fdb15a11610087578063f3fdb15a146109ef578063f5e3c462146109f7578063f851a44014610a2d578063f8f9da2814610a35578063fca7820b14610a3d578063fe9c44ae14610a5a576102a0565b8063c37f68e21461090d578063c5ebeaec14610959578063db006a7514610976578063dd62ed3e14610993578063e9c714f2146109c1578063f2b3abbd146109c9576102a0565b8063a9059cbb11610120578063a9059cbb1461086d578063aa5af0fd14610899578063ae9d70b0146108a1578063b2a02ff1146108a9578063b71d1a0c146108df578063bd6d894d14610905576102a0565b80638f840ddd146106c457806395d89b41146106cc57806395dd9193146106d457806399d8c1b4146106fa578063a0712d6814610848578063a6afed9514610865576102a0565b80633af9e6691161020b578063601a0bf1116101c4578063601a0bf11461064c5780636c540baf146106695780636f307dc31461067157806370a082311461067957806373acee981461069f578063852a12e3146106a7576102a0565b80633af9e669146105cb5780633b1d21a2146105f15780633e941010146105f95780634576b5db1461061657806347bd37181461063c5780635fe3b56714610644576102a0565b8063182df0f51161025d578063182df0f5146103c75780631a31d465146103cf57806323b872dd146105275780632608f8181461055d5780632678224714610589578063313ce567146105ad576102a0565b806306fdde03146102a5578063095ea7b3146103225780630e75270214610362578063173b99041461039157806317bfdfbc1461039957806318160ddd146103bf575b600080fd5b6102ad610a62565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102e75781810151838201526020016102cf565b50505050905090810190601f1680156103145780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61034e6004803603604081101561033857600080fd5b506001600160a01b038135169060200135610aef565b604080519115158252519081900360200190f35b61037f6004803603602081101561037857600080fd5b5035610b5c565b60408051918252519081900360200190f35b61037f610b72565b61037f600480360360208110156103af57600080fd5b50356001600160a01b0316610b78565b61037f610c38565b61037f610c3e565b610525600480360360e08110156103e557600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561042757600080fd5b82018360208201111561043957600080fd5b803590602001918460018302840111600160201b8311171561045a57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156104ac57600080fd5b8201836020820111156104be57600080fd5b803590602001918460018302840111600160201b831117156104df57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295505050903560ff169150610ca19050565b005b61034e6004803603606081101561053d57600080fd5b506001600160a01b03813581169160208101359091169060400135610d40565b61037f6004803603604081101561057357600080fd5b506001600160a01b038135169060200135610db2565b610591610dc8565b604080516001600160a01b039092168252519081900360200190f35b6105b5610dd7565b6040805160ff9092168252519081900360200190f35b61037f600480360360208110156105e157600080fd5b50356001600160a01b0316610de0565b61037f610e96565b61037f6004803603602081101561060f57600080fd5b5035610ea5565b61037f6004803603602081101561062c57600080fd5b50356001600160a01b0316610eb0565b61037f611005565b61059161100b565b61037f6004803603602081101561066257600080fd5b503561101a565b61037f6110b5565b6105916110bb565b61037f6004803603602081101561068f57600080fd5b50356001600160a01b03166110ca565b61037f6110e5565b61037f600480360360208110156106bd57600080fd5b503561119b565b61037f6111a6565b6102ad6111ac565b61037f600480360360208110156106ea57600080fd5b50356001600160a01b0316611204565b610525600480360360c081101561071057600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561074a57600080fd5b82018360208201111561075c57600080fd5b803590602001918460018302840111600160201b8311171561077d57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156107cf57600080fd5b8201836020820111156107e157600080fd5b803590602001918460018302840111600160201b8311171561080257600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295505050903560ff1691506112619050565b61037f6004803603602081101561085e57600080fd5b5035611448565b61037f611454565b61034e6004803603604081101561088357600080fd5b506001600160a01b0381351690602001356117ac565b61037f61181d565b61037f611823565b61037f600480360360608110156108bf57600080fd5b506001600160a01b038135811691602081013590911690604001356118c2565b61037f600480360360208110156108f557600080fd5b50356001600160a01b0316611933565b61037f6119bf565b6109336004803603602081101561092357600080fd5b50356001600160a01b0316611a7b565b604080519485526020850193909352838301919091526060830152519081900360800190f35b61037f6004803603602081101561096f57600080fd5b5035611b10565b61037f6004803603602081101561098c57600080fd5b5035611b1b565b61037f600480360360408110156109a957600080fd5b506001600160a01b0381358116916020013516611b26565b61037f611b51565b61037f600480360360208110156109df57600080fd5b50356001600160a01b0316611c54565b610591611c8e565b61037f60048036036060811015610a0d57600080fd5b506001600160a01b03813581169160208101359160409091013516611c9d565b610591611cb5565b61037f611cc9565b61037f60048036036020811015610a5357600080fd5b5035611d2d565b61034e611dab565b60018054604080516020600284861615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ae75780601f10610abc57610100808354040283529160200191610ae7565b820191906000526020600020905b815481529060010190602001808311610aca57829003601f168201915b505050505081565b336000818152600f602090815260408083206001600160a01b03871680855290835281842086905581518681529151939493909284927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a360019150505b92915050565b600080610b6883611db0565b509150505b919050565b60085481565b6000805460ff16610bbd576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155610bcf611454565b14610c1a576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b610c2382611204565b90505b6000805460ff19166001179055919050565b600d5481565b6000806000610c4b611e59565b90925090506000826003811115610c5e57fe5b14610c9a5760405162461bcd60e51b8152600401808060200182810382526035815260200180614e4c6035913960400191505060405180910390fd5b9150505b90565b610caf868686868686611261565b601180546001600160a01b0319166001600160a01b038981169190911791829055604080516318160ddd60e01b8152905192909116916318160ddd91600480820192602092909190829003018186803b158015610d0b57600080fd5b505afa158015610d1f573d6000803e3d6000fd5b505050506040513d6020811015610d3557600080fd5b505050505050505050565b6000805460ff16610d85576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155610d9b33868686611f08565b1490506000805460ff191660011790559392505050565b600080610dbf8484612216565b50949350505050565b6004546001600160a01b031681565b60035460ff1681565b6000610dea614b3a565b6040518060200160405280610dfd6119bf565b90526001600160a01b0384166000908152600e6020526040812054919250908190610e299084906122c1565b90925090506000826003811115610e3c57fe5b14610e8e576040805162461bcd60e51b815260206004820152601f60248201527f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400604482015290519081900360640190fd5b949350505050565b6000610ea0612315565b905090565b6000610b5682612395565b60035460009061010090046001600160a01b03163314610edd57610ed66001603f612429565b9050610b6d565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b158015610f2257600080fd5b505afa158015610f36573d6000803e3d6000fd5b505050506040513d6020811015610f4c57600080fd5b5051610f9f576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160005b9392505050565b600b5481565b6005546001600160a01b031681565b6000805460ff1661105f576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611071611454565b905080156110975761108f81601081111561108857fe5b6030612429565b915050610c26565b6110a08361248f565b9150506000805460ff19166001179055919050565b60095481565b6011546001600160a01b031681565b6001600160a01b03166000908152600e602052604090205490565b6000805460ff1661112a576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561113c611454565b14611187576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b50600b546000805460ff1916600117905590565b6000610b56826125c2565b600c5481565b6002805460408051602060018416156101000260001901909316849004601f81018490048402820184019092528181529291830182828015610ae75780601f10610abc57610100808354040283529160200191610ae7565b600080600061121284612643565b9092509050600082600381111561122557fe5b14610ffe5760405162461bcd60e51b8152600401808060200182810382526037815260200180614d576037913960400191505060405180910390fd5b60035461010090046001600160a01b031633146112af5760405162461bcd60e51b8152600401808060200182810382526024815260200180614c936024913960400191505060405180910390fd5b6009541580156112bf5750600a54155b6112fa5760405162461bcd60e51b8152600401808060200182810382526023815260200180614cb76023913960400191505060405180910390fd5b60078490558361133b5760405162461bcd60e51b8152600401808060200182810382526030815260200180614cda6030913960400191505060405180910390fd5b600061134687610eb0565b9050801561139b576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b6113a36126f7565b600955670de0b6b3a7640000600a556113bb866126fb565b905080156113fa5760405162461bcd60e51b8152600401808060200182810382526022815260200180614d0a6022913960400191505060405180910390fd5b835161140d906001906020870190614b4d565b508251611421906002906020860190614b4d565b50506003805460ff90921660ff199283161790556000805490911660011790555050505050565b600080610b6883612870565b60008061145f6126f7565b6009549091508082141561147857600092505050610c9e565b6000611482612315565b600b54600c54600a54600654604080516315f2405360e01b815260048101879052602481018690526044810185905290519596509394929391926000926001600160a01b03909216916315f24053916064808301926020929190829003018186803b1580156114f057600080fd5b505afa158015611504573d6000803e3d6000fd5b505050506040513d602081101561151a57600080fd5b5051905065048c27395000811115611579576040805162461bcd60e51b815260206004820152601c60248201527f626f72726f772072617465206973206162737572646c79206869676800000000604482015290519081900360640190fd5b60008061158689896128f1565b9092509050600082600381111561159957fe5b146115eb576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b6115f3614b3a565b60008060008061161160405180602001604052808a81525087612914565b9097509450600087600381111561162457fe5b14611656576116416009600689600381111561163c57fe5b61297c565b9e505050505050505050505050505050610c9e565b611660858c6122c1565b9097509350600087600381111561167357fe5b1461168b576116416009600189600381111561163c57fe5b611695848c6129e2565b909750925060008760038111156116a857fe5b146116c0576116416009600489600381111561163c57fe5b6116db6040518060200160405280600854815250858c612a08565b909750915060008760038111156116ee57fe5b14611706576116416009600589600381111561163c57fe5b611711858a8b612a08565b9097509050600087600381111561172457fe5b1461173c576116416009600389600381111561163c57fe5b60098e9055600a819055600b839055600c829055604080518d8152602081018690528082018390526060810185905290517f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049181900360800190a160009e50505050505050505050505050505090565b6000805460ff166117f1576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561180733338686611f08565b1490506000805460ff1916600117905592915050565b600a5481565b6006546000906001600160a01b031663b816881661183f612315565b600b54600c546008546040518563ffffffff1660e01b81526004018085815260200184815260200183815260200182815260200194505050505060206040518083038186803b15801561189157600080fd5b505afa1580156118a5573d6000803e3d6000fd5b505050506040513d60208110156118bb57600080fd5b5051905090565b6000805460ff16611907576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916905561191d33858585612a64565b90506000805460ff191660011790559392505050565b60035460009061010090046001600160a01b0316331461195957610ed660016045612429565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610ffe565b6000805460ff16611a04576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611a16611454565b14611a61576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b611a69610c3e565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600e6020526040812054819081908190818080611aa689612643565b935090506000816003811115611ab857fe5b14611ad65760095b975060009650869550859450611b099350505050565b611ade611e59565b925090506000816003811115611af057fe5b14611afc576009611ac0565b5060009650919450925090505b9193509193565b6000610b5682612cca565b6000610b5682612d49565b6001600160a01b039182166000908152600f6020908152604080832093909416825291909152205490565b6004546000906001600160a01b031633141580611b6c575033155b15611b8457611b7d60016000612429565b9050610c9e565b60038054600480546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401528351909391927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600454604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a160009250505090565b600080611c5f611454565b90508015611c8557611c7d816010811115611c7657fe5b6040612429565b915050610b6d565b610ffe836126fb565b6006546001600160a01b031681565b600080611cab858585612dc3565b5095945050505050565b60035461010090046001600160a01b031681565b6006546000906001600160a01b03166315f24053611ce5612315565b600b54600c546040518463ffffffff1660e01b815260040180848152602001838152602001828152602001935050505060206040518083038186803b15801561189157600080fd5b6000805460ff16611d72576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611d84611454565b90508015611da25761108f816010811115611d9b57fe5b6046612429565b6110a083612ef5565b600181565b60008054819060ff16611df7576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611e09611454565b90508015611e3457611e27816010811115611e2057fe5b6036612429565b925060009150611e459050565b611e3f333386612f9d565b92509250505b6000805460ff191660011790559092909150565b600d54600090819080611e7457505060075460009150611f04565b6000611e7e612315565b90506000611e8a614b3a565b6000611e9b84600b54600c54613382565b935090506000816003811115611ead57fe5b14611ec257955060009450611f049350505050565b611ecc83866133c0565b925090506000816003811115611ede57fe5b14611ef357955060009450611f049350505050565b5051600095509350611f0492505050565b9091565b600554604080516317b9b84b60e31b81523060048201526001600160a01b03868116602483015285811660448301526064820185905291516000938493169163bdcdc25891608480830192602092919082900301818787803b158015611f6d57600080fd5b505af1158015611f81573d6000803e3d6000fd5b505050506040513d6020811015611f9757600080fd5b505190508015611fb657611fae6003604a8361297c565b915050610e8e565b836001600160a01b0316856001600160a01b03161415611fdc57611fae6002604b612429565b60006001600160a01b038781169087161415611ffb5750600019612023565b506001600160a01b038086166000908152600f60209081526040808320938a16835292905220545b60008060008061203385896128f1565b9094509250600084600381111561204657fe5b14612064576120576009604b612429565b9650505050505050610e8e565b6001600160a01b038a166000908152600e602052604090205461208790896128f1565b9094509150600084600381111561209a57fe5b146120ab576120576009604c612429565b6001600160a01b0389166000908152600e60205260409020546120ce90896129e2565b909450905060008460038111156120e157fe5b146120f2576120576009604d612429565b6001600160a01b03808b166000908152600e6020526040808220859055918b16815220819055600019851461214a576001600160a01b03808b166000908152600f60209081526040808320938f168352929052208390555b886001600160a01b03168a6001600160a01b0316600080516020614dc88339815191528a6040518082815260200191505060405180910390a36005546040805163352b4a3f60e11b81523060048201526001600160a01b038d811660248301528c81166044830152606482018c905291519190921691636a56947e91608480830192600092919082900301818387803b1580156121e657600080fd5b505af11580156121fa573d6000803e3d6000fd5b5060009250612207915050565b9b9a5050505050505050505050565b60008054819060ff1661225d576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561226f611454565b9050801561229a5761228d81601081111561228657fe5b6035612429565b9250600091506122ab9050565b6122a5338686612f9d565b92509250505b6000805460ff1916600117905590939092509050565b60008060006122ce614b3a565b6122d88686612914565b909250905060008260038111156122eb57fe5b146122fc575091506000905061230e565b600061230782613470565b9350935050505b9250929050565b601154604080516370a0823160e01b815230600482015290516000926001600160a01b03169182916370a0823191602480820192602092909190829003018186803b15801561236357600080fd5b505afa158015612377573d6000803e3d6000fd5b505050506040513d602081101561238d57600080fd5b505191505090565b6000805460ff166123da576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556123ec611454565b9050801561240a5761108f81601081111561240357fe5b604e612429565b6124138361347f565b509150506000805460ff19166001179055919050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601081111561245857fe5b83605081111561246457fe5b604080519283526020830191909152600082820152519081900360600190a1826010811115610ffe57fe5b600354600090819061010090046001600160a01b031633146124b757611c7d60016031612429565b6124bf6126f7565b600954146124d357611c7d600a6033612429565b826124dc612315565b10156124ee57611c7d600e6032612429565b600c5483111561250457611c7d60026034612429565b50600c548281039081111561254a5760405162461bcd60e51b8152600401808060200182810382526024815260200180614edd6024913960400191505060405180910390fd5b600c81905560035461256a9061010090046001600160a01b031684613567565b600354604080516101009092046001600160a01b0316825260208201859052818101839052517f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e916060908290030190a16000610ffe565b6000805460ff16612607576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612619611454565b905080156126375761108f81601081111561263057fe5b6027612429565b6110a03360008561365e565b6001600160a01b03811660009081526010602052604081208054829182918291829161267a5750600094508493506126f292505050565b61268a8160000154600a54613b25565b9094509250600084600381111561269d57fe5b146126b25750919350600092506126f2915050565b6126c0838260010154613b64565b909450915060008460038111156126d357fe5b146126e85750919350600092506126f2915050565b5060009450925050505b915091565b4390565b600354600090819061010090046001600160a01b0316331461272357611c7d60016042612429565b61272b6126f7565b6009541461273f57611c7d600a6041612429565b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561279057600080fd5b505afa1580156127a4573d6000803e3d6000fd5b505050506040513d60208110156127ba57600080fd5b505161280d576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600680546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a16000610ffe565b60008054819060ff166128b7576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556128c9611454565b905080156128e757611e278160108111156128e057fe5b601e612429565b611e3f3385613b8f565b60008083831161290857506000905081830361230e565b5060039050600061230e565b600061291e614b3a565b60008061292f866000015186613b25565b9092509050600082600381111561294257fe5b146129615750604080516020810190915260008152909250905061230e565b60408051602081019091529081526000969095509350505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08460108111156129ab57fe5b8460508111156129b757fe5b604080519283526020830191909152818101859052519081900360600190a1836010811115610e8e57fe5b6000808383018481106129fa5760009250905061230e565b50600291506000905061230e565b6000806000612a15614b3a565b612a1f8787612914565b90925090506000826003811115612a3257fe5b14612a435750915060009050612a5c565b612a55612a4f82613470565b866129e2565b9350935050505b935093915050565b6005546040805163d02f735160e01b81523060048201526001600160a01b038781166024830152868116604483015285811660648301526084820185905291516000938493169163d02f73519160a480830192602092919082900301818787803b158015612ad157600080fd5b505af1158015612ae5573d6000803e3d6000fd5b505050506040513d6020811015612afb57600080fd5b505190508015612b1257611fae6003601b8361297c565b846001600160a01b0316846001600160a01b03161415612b3857611fae6006601c612429565b6001600160a01b0384166000908152600e602052604081205481908190612b5f90876128f1565b90935091506000836003811115612b7257fe5b14612b9557612b8a6009601a85600381111561163c57fe5b945050505050610e8e565b6001600160a01b0388166000908152600e6020526040902054612bb890876129e2565b90935090506000836003811115612bcb57fe5b14612be357612b8a6009601985600381111561163c57fe5b6001600160a01b038088166000818152600e60209081526040808320879055938c168083529184902085905583518a815293519193600080516020614dc8833981519152929081900390910190a360055460408051636d35bf9160e01b81523060048201526001600160a01b038c811660248301528b811660448301528a81166064830152608482018a905291519190921691636d35bf919160a480830192600092919082900301818387803b158015612c9c57600080fd5b505af1158015612cb0573d6000803e3d6000fd5b5060009250612cbd915050565b9998505050505050505050565b6000805460ff16612d0f576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612d21611454565b90508015612d3f5761108f816010811115612d3857fe5b6008612429565b6110a03384613fee565b6000805460ff16612d8e576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612da0611454565b90508015612db75761108f81601081111561263057fe5b6110a03384600061365e565b60008054819060ff16612e0a576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612e1c611454565b90508015612e4757612e3a816010811115612e3357fe5b600f612429565b925060009150612ede9050565b836001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e8257600080fd5b505af1158015612e96573d6000803e3d6000fd5b505050506040513d6020811015612eac57600080fd5b505190508015612ecc57612e3a816010811115612ec557fe5b6010612429565b612ed8338787876142fc565b92509250505b6000805460ff191660011790559094909350915050565b60035460009061010090046001600160a01b03163314612f1b57610ed660016047612429565b612f236126f7565b60095414612f3757610ed6600a6048612429565b670de0b6b3a7640000821115612f5357610ed660026049612429565b6008805490839055604080518281526020810185905281517faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460929181900390910190a16000610ffe565b60055460408051631200453160e11b81523060048201526001600160a01b0386811660248301528581166044830152606482018590529151600093849384939116916324008a629160848082019260209290919082900301818787803b15801561300657600080fd5b505af115801561301a573d6000803e3d6000fd5b505050506040513d602081101561303057600080fd5b50519050801561305457613047600360388361297c565b925060009150612a5c9050565b61305c6126f7565b6009541461307057613047600a6039612429565b613078614bcb565b6001600160a01b03861660009081526010602052604090206001015460608201526130a286612643565b60808301819052602083018260038111156130b957fe5b60038111156130c457fe5b90525060009050816020015160038111156130db57fe5b14613105576130f7600960378360200151600381111561163c57fe5b935060009250612a5c915050565b60001985141561311e5760808101516040820152613126565b604081018590525b61313487826040015161487f565b60e082018190526080820151613149916128f1565b60a083018190526020830182600381111561316057fe5b600381111561316b57fe5b905250600090508160200151600381111561318257fe5b146131be5760405162461bcd60e51b815260040180806020018281038252603a815260200180614d8e603a913960400191505060405180910390fd5b6131ce600b548260e001516128f1565b60c08301819052602083018260038111156131e557fe5b60038111156131f057fe5b905250600090508160200151600381111561320757fe5b146132435760405162461bcd60e51b8152600401808060200182810382526031815260200180614de86031913960400191505060405180910390fd5b60a080820180516001600160a01b03808a16600081815260106020908152604091829020948555600a5460019095019490945560c0870151600b81905560e088015195518251948f16855294840192909252828101949094526060820192909252608081019190915290517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1929181900390910190a160055460e0820151606083015160408051631ededc9160e01b81523060048201526001600160a01b038c811660248301528b8116604483015260648201949094526084810192909252519190921691631ededc919160a480830192600092919082900301818387803b15801561334e57600080fd5b505af1158015613362573d6000803e3d6000fd5b506000925061336f915050565b8160e00151935093505050935093915050565b60008060008061339287876129e2565b909250905060008260038111156133a557fe5b146133b65750915060009050612a5c565b612a5581866128f1565b60006133ca614b3a565b6000806133df86670de0b6b3a7640000613b25565b909250905060008260038111156133f257fe5b146134115750604080516020810190915260008152909250905061230e565b60008061341e8388613b64565b9092509050600082600381111561343157fe5b146134535750604080516020810190915260008152909450925061230e915050565b604080516020810190915290815260009890975095505050505050565b51670de0b6b3a7640000900490565b60008060008061348d6126f7565b600954146134ac576134a1600a604f612429565b935091506126f29050565b6134b6338661487f565b905080600c54019150600c54821015613516576040805162461bcd60e51b815260206004820181905260248201527f61646420726573657276657320756e6578706563746564206f766572666c6f77604482015290519081900360640190fd5b600c829055604080513381526020810183905280820184905290517fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc59181900360600190a160009350915050915091565b6011546040805163a9059cbb60e01b81526001600160a01b0385811660048301526024820185905291519190921691829163a9059cbb9160448082019260009290919082900301818387803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b5050505060003d600081146135ef57602081146135f957600080fd5b6000199150613605565b60206000803e60005191505b5080613658576040805162461bcd60e51b815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b50505050565b600082158061366b575081155b6136a65760405162461bcd60e51b8152600401808060200182810382526034815260200180614ea96034913960400191505060405180910390fd5b6136ae614c11565b6136b6611e59565b60408301819052602083018260038111156136cd57fe5b60038111156136d857fe5b90525060009050816020015160038111156136ef57fe5b146137135761370b6009602b8360200151600381111561163c57fe5b915050610ffe565b831561379457606081018490526040805160208101825290820151815261373a90856122c1565b608083018190526020830182600381111561375157fe5b600381111561375c57fe5b905250600090508160200151600381111561377357fe5b1461378f5761370b600960298360200151600381111561163c57fe5b61380d565b6137b08360405180602001604052808460400151815250614ac9565b60608301819052602083018260038111156137c757fe5b60038111156137d257fe5b90525060009050816020015160038111156137e957fe5b146138055761370b6009602a8360200151600381111561163c57fe5b608081018390525b60055460608201516040805163eabe7d9160e01b81523060048201526001600160a01b03898116602483015260448201939093529051600093929092169163eabe7d919160648082019260209290919082900301818787803b15801561387257600080fd5b505af1158015613886573d6000803e3d6000fd5b505050506040513d602081101561389c57600080fd5b5051905080156138bc576138b3600360288361297c565b92505050610ffe565b6138c46126f7565b600954146138d8576138b3600a602c612429565b6138e8600d5483606001516128f1565b60a08401819052602084018260038111156138ff57fe5b600381111561390a57fe5b905250600090508260200151600381111561392157fe5b1461393d576138b36009602e8460200151600381111561163c57fe5b6001600160a01b0386166000908152600e6020526040902054606083015161396591906128f1565b60c084018190526020840182600381111561397c57fe5b600381111561398757fe5b905250600090508260200151600381111561399e57fe5b146139ba576138b36009602d8460200151600381111561163c57fe5b81608001516139c7612315565b10156139d9576138b3600e602f612429565b6139e7868360800151613567565b60a0820151600d5560c08201516001600160a01b0387166000818152600e6020908152604091829020939093556060850151815190815290513093600080516020614dc8833981519152928290030190a36080820151606080840151604080516001600160a01b038b168152602081019490945283810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a9299281900390910190a160055460808301516060840151604080516351dff98960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916351dff98991608480830192600092919082900301818387803b158015613afa57600080fd5b505af1158015613b0e573d6000803e3d6000fd5b5060009250613b1b915050565b9695505050505050565b60008083613b385750600090508061230e565b83830283858281613b4557fe5b0414613b595750600291506000905061230e565b60009250905061230e565b60008082613b78575060019050600061230e565b6000838581613b8357fe5b04915091509250929050565b60055460408051634ef4c3e160e01b81523060048201526001600160a01b03858116602483015260448201859052915160009384938493911691634ef4c3e19160648082019260209290919082900301818787803b158015613bf057600080fd5b505af1158015613c04573d6000803e3d6000fd5b505050506040513d6020811015613c1a57600080fd5b505190508015613c3e57613c316003601f8361297c565b92506000915061230e9050565b613c466126f7565b60095414613c5a57613c31600a6022612429565b613c62614c11565b613c6a611e59565b6040830181905260208301826003811115613c8157fe5b6003811115613c8c57fe5b9052506000905081602001516003811115613ca357fe5b14613ccd57613cbf600960218360200151600381111561163c57fe5b93506000925061230e915050565b613cd7868661487f565b60c0820181905260408051602081018252908301518152613cf89190614ac9565b6060830181905260208301826003811115613d0f57fe5b6003811115613d1a57fe5b9052506000905081602001516003811115613d3157fe5b14613d83576040805162461bcd60e51b815260206004820181905260248201527f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544604482015290519081900360640190fd5b613d93600d5482606001516129e2565b6080830181905260208301826003811115613daa57fe5b6003811115613db557fe5b9052506000905081602001516003811115613dcc57fe5b14613e085760405162461bcd60e51b8152600401808060200182810382526028815260200180614e816028913960400191505060405180910390fd5b6001600160a01b0386166000908152600e60205260409020546060820151613e3091906129e2565b60a0830181905260208301826003811115613e4757fe5b6003811115613e5257fe5b9052506000905081602001516003811115613e6957fe5b14613ea55760405162461bcd60e51b815260040180806020018281038252602b815260200180614d2c602b913960400191505060405180910390fd5b6080810151600d5560a08101516001600160a01b0387166000818152600e60209081526040918290209390935560c084015160608086015183519485529484019190915282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160a01b038816913091600080516020614dc88339815191529181900360200190a360055460c08201516060830151604080516341c728b960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916341c728b991608480830192600092919082900301818387803b158015613fbb57600080fd5b505af1158015613fcf573d6000803e3d6000fd5b5060009250613fdc915050565b8160c001519350935050509250929050565b6005546040805163368f515360e21b81523060048201526001600160a01b0385811660248301526044820185905291516000938493169163da3d454c91606480830192602092919082900301818787803b15801561404b57600080fd5b505af115801561405f573d6000803e3d6000fd5b505050506040513d602081101561407557600080fd5b5051905080156140945761408c6003600e8361297c565b915050610b56565b61409c6126f7565b600954146140af5761408c600a80612429565b826140b8612315565b10156140ca5761408c600e6009612429565b6140d2614c4f565b6140db85612643565b60208301819052828260038111156140ef57fe5b60038111156140fa57fe5b905250600090508151600381111561410e57fe5b146141335761412a600960078360000151600381111561163c57fe5b92505050610b56565b6141418160200151856129e2565b604083018190528282600381111561415557fe5b600381111561416057fe5b905250600090508151600381111561417457fe5b146141905761412a6009600c8360000151600381111561163c57fe5b61419c600b54856129e2565b60608301819052828260038111156141b057fe5b60038111156141bb57fe5b90525060009050815160038111156141cf57fe5b146141eb5761412a6009600b8360000151600381111561163c57fe5b6141f58585613567565b604080820180516001600160a01b03881660008181526010602090815290859020928355600a54600190930192909255606080860151600b81905593518551928352928201899052818501929092529081019190915290517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab809181900360800190a160055460408051635c77860560e01b81523060048201526001600160a01b0388811660248301526044820188905291519190921691635c77860591606480830192600092919082900301818387803b1580156142d257600080fd5b505af11580156142e6573d6000803e3d6000fd5b50600092506142f3915050565b95945050505050565b60055460408051632fe3f38f60e11b81523060048201526001600160a01b0384811660248301528781166044830152868116606483015260848201869052915160009384938493911691635fc7e71e9160a48082019260209290919082900301818787803b15801561436d57600080fd5b505af1158015614381573d6000803e3d6000fd5b505050506040513d602081101561439757600080fd5b5051905080156143bb576143ae600360128361297c565b9250600091506148769050565b6143c36126f7565b600954146143d7576143ae600a6016612429565b6143df6126f7565b846001600160a01b0316636c540baf6040518163ffffffff1660e01b815260040160206040518083038186803b15801561441857600080fd5b505afa15801561442c573d6000803e3d6000fd5b505050506040513d602081101561444257600080fd5b505114614455576143ae600a6011612429565b866001600160a01b0316866001600160a01b0316141561447b576143ae60066017612429565b8461448c576143ae60076015612429565b6000198514156144a2576143ae60076014612429565b6000806144b0898989612f9d565b909250905081156144e0576144d18260108111156144ca57fe5b6018612429565b94506000935061487692505050565b6005546040805163c488847b60e01b81523060048201526001600160a01b038981166024830152604482018590528251600094859492169263c488847b926064808301939192829003018186803b15801561453a57600080fd5b505afa15801561454e573d6000803e3d6000fd5b505050506040513d604081101561456457600080fd5b508051602090910151909250905081156145af5760405162461bcd60e51b8152600401808060200182810382526033815260200180614e196033913960400191505060405180910390fd5b80886001600160a01b03166370a082318c6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561460657600080fd5b505afa15801561461a573d6000803e3d6000fd5b505050506040513d602081101561463057600080fd5b50511015614685576040805162461bcd60e51b815260206004820152601860248201527f4c49515549444154455f5345495a455f544f4f5f4d5543480000000000000000604482015290519081900360640190fd5b60006001600160a01b0389163014156146ab576146a4308d8d85612a64565b9050614735565b6040805163b2a02ff160e01b81526001600160a01b038e811660048301528d81166024830152604482018590529151918b169163b2a02ff1916064808201926020929091908290030181600087803b15801561470657600080fd5b505af115801561471a573d6000803e3d6000fd5b505050506040513d602081101561473057600080fd5b505190505b801561477f576040805162461bcd60e51b81526020600482015260146024820152731d1bdad95b881cd95a5e9d5c994819985a5b195960621b604482015290519081900360640190fd5b604080516001600160a01b03808f168252808e1660208301528183018790528b1660608201526080810184905290517f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb529181900360a00190a1600554604080516347ef3b3b60e01b81523060048201526001600160a01b038c811660248301528f811660448301528e811660648301526084820188905260a48201869052915191909216916347ef3b3b9160c480830192600092919082900301818387803b15801561484a57600080fd5b505af115801561485e573d6000803e3d6000fd5b506000925061486b915050565b975092955050505050505b94509492505050565b601154604080516370a0823160e01b815230600482015290516000926001600160a01b031691839183916370a08231916024808301926020929190829003018186803b1580156148ce57600080fd5b505afa1580156148e2573d6000803e3d6000fd5b505050506040513d60208110156148f857600080fd5b5051604080516323b872dd60e01b81526001600160a01b038881166004830152306024830152604482018890529151929350908416916323b872dd9160648082019260009290919082900301818387803b15801561495557600080fd5b505af1158015614969573d6000803e3d6000fd5b5050505060003d60008114614985576020811461498f57600080fd5b600019915061499b565b60206000803e60005191505b50806149ee576040805162461bcd60e51b815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b601154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015614a3957600080fd5b505afa158015614a4d573d6000803e3d6000fd5b505050506040513d6020811015614a6357600080fd5b5051905082811015614abc576040805162461bcd60e51b815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b6000806000614ad6614b3a565b6122d886866000614ae5614b3a565b600080614afa670de0b6b3a764000087613b25565b90925090506000826003811115614b0d57fe5b14614b2c5750604080516020810190915260008152909250905061230e565b6123078186600001516133c0565b6040518060200160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614b8e57805160ff1916838001178555614bbb565b82800160010185558215614bbb579182015b82811115614bbb578251825591602001919060010190614ba0565b50614bc7929150614c78565b5090565b6040805161010081019091528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604080516080810190915280600081526020016000815260200160008152602001600081525090565b610c9e91905b80821115614bc75760008155600101614c7e56fe6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e73657474696e6720696e7465726573742072617465206d6f64656c206661696c65644d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4154494f4e5f4641494c4544626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e636553746f726564496e7465726e616c206661696c656452455041595f424f52524f575f4e45575f4143434f554e545f424f52524f575f42414c414e43455f43414c43554c4154494f4e5f4641494c4544ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef52455041595f424f52524f575f4e45575f544f54414c5f42414c414e43455f43414c43554c4154494f4e5f4641494c45444c49515549444154455f434f4d5054524f4c4c45525f43414c43554c4154455f414d4f554e545f5345495a455f4641494c454465786368616e67655261746553746f7265643a2065786368616e67655261746553746f726564496e7465726e616c206661696c65644d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f4e5f4641494c45446f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726f72656475636520726573657276657320756e657870656374656420756e646572666c6f77a265627a7a7231582025fba71478c63f62af5c57c35cb91b96c8d75f7099759f3953426dbbef43562064736f6c63430005110032
Deployed Bytecode Sourcemap
166:8889:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;166:8889:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;289:18:6;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;289:18:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6365:232:5;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;6365:232:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;3463:146:1;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3463:146:1;;:::i;:::-;;;;;;;;;;;;;;;;1541:33:6;;;:::i;10511:221:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10511:221:5;-1:-1:-1;;;;;10511:221:5;;:::i;2161:23:6:-;;;:::i;13289:257:5:-;;;:::i;776:671:1:-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;776:671:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;776:671:1;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;776:671:1;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;776:671:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;776:671:1;;;;;;;;-1:-1:-1;776:671:1;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;776:671:1;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;776:671:1;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;776:671:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;776:671:1;;-1:-1:-1;;;776:671:1;;;;;-1:-1:-1;776:671:1;;-1:-1:-1;776:671:1:i;:::-;;5712:193:5;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;5712:193:5;;;;;;;;;;;;;;;;;:::i;3889:186:1:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;3889:186:1;;;;;;;;:::i;985:35:6:-;;;:::i;:::-;;;;-1:-1:-1;;;;;985:35:6;;;;;;;;;;;;;;475:21;;;:::i;:::-;;;;;;;;;;;;;;;;;;;7601:349:5;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7601:349:5;-1:-1:-1;;;;;7601:349:5;;:::i;15123:86::-;;;:::i;5008:117:1:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5008:117:1;;:::i;52391:718:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;52391:718:5;-1:-1:-1;;;;;52391:718:5;;:::i;1935:24:6:-;;;:::i;1106:39::-;;;:::i;58218:563:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;58218:563:5;;:::i;1659:30:6:-;;;:::i;7679:25::-;;;:::i;7243:110:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7243:110:5;-1:-1:-1;;;;;7243:110:5;;:::i;10038:189::-;;;:::i;2759:131:1:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2759:131:1;;:::i;2060:25:6:-;;;:::i;380:20::-;;;:::i;10934:283:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10934:283:5;-1:-1:-1;;;;;10934:283:5;;:::i;871:1498::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;871:1498:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;871:1498:5;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;871:1498:5;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;871:1498:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;871:1498:5;;;;;;;;-1:-1:-1;871:1498:5;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;871:1498:5;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;871:1498:5;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;871:1498:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;871:1498:5;;-1:-1:-1;;;871:1498:5;;;;;-1:-1:-1;871:1498:5;;-1:-1:-1;871:1498:5:i;1827:130:1:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1827:130:1;;:::i;15450:3774:5:-;;;:::i;5231:183::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;5231:183:5;;;;;;;;:::i;1805:23:6:-;;;:::i;9716:182:5:-;;;:::i;47163:192::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;47163:192:5;;;;;;;;;;;;;;;;;:::i;50549:631::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;50549:631:5;-1:-1:-1;;;;;50549:631:5;;:::i;12851:195::-;;;:::i;8288:685::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;8288:685:5;-1:-1:-1;;;;;8288:685:5;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3151:111:1;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3151:111:1;;:::i;2300:::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2300:111:1;;:::i;6919:141:5:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;6919:141:5;;;;;;;;;;:::i;51451:722::-;;;:::i;61117:625::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;61117:625:5;-1:-1:-1;;;;;61117:625:5;;:::i;1242:42:6:-;;;:::i;4547:234:1:-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;4547:234:1;;;;;;;;;;;;;;;;;:::i;879:28:6:-;;;:::i;9387:159:5:-;;;:::i;53405:599::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;53405:599:5;;:::i;3155:36:6:-;;;:::i;289:18::-;;;;;;;;;;;;;;;-1:-1:-1;;289:18:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;6365:232:5:-;6463:10;6433:4;6483:23;;;:18;:23;;;;;;;;-1:-1:-1;;;;;6483:32:5;;;;;;;;;;;:41;;;6539:30;;;;;;;6433:4;;6463:10;6483:32;;6463:10;;6539:30;;;;;;;;;;;6586:4;6579:11;;;6365:232;;;;;:::o;3463:146:1:-;3520:4;3537:8;3550:32;3570:11;3550:19;:32::i;:::-;-1:-1:-1;3536:46:1;-1:-1:-1;;3463:146:1;;;;:::o;1541:33:6:-;;;;:::o;10511:221:5:-;10589:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;10613:16;:14;:16::i;:::-;:40;10605:75;;;;;-1:-1:-1;;;10605:75:5;;;;;;;;;;;;-1:-1:-1;;;10605:75:5;;;;;;;;;;;;;;;10697:28;10717:7;10697:19;:28::i;:::-;10690:35;;64636:1;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;10511:221;;-1:-1:-1;10511:221:5:o;2161:23:6:-;;;;:::o;13289:257:5:-;13340:4;13357:13;13372:11;13387:28;:26;:28::i;:::-;13356:59;;-1:-1:-1;13356:59:5;-1:-1:-1;13440:18:5;13433:3;:25;;;;;;;;;13425:91;;;;-1:-1:-1;;;13425:91:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13533:6;-1:-1:-1;;13289:257:5;;:::o;776:671:1:-;1202:107;1219:12;1233:18;1253:28;1283:5;1290:7;1299:9;1202:16;:107::i;:::-;1366:10;:24;;-1:-1:-1;;;;;;1366:24:1;-1:-1:-1;;;;;1366:24:1;;;;;;;;;;;1400:40;;;-1:-1:-1;;;1400:40:1;;;;1415:10;;;;;1400:38;;:40;;;;;;;;;;;;;;;1415:10;1400:40;;;5:2:-1;;;;30:1;27;20:12;5:2;1400:40:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1400:40:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;;;776:671:1:o;5712:193:5:-;5807:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;5830:44;5845:10;5857:3;5862;5867:6;5830:14;:44::i;:::-;:68;5823:75;;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;5712:193;;-1:-1:-1;;;5712:193:5:o;3889:186:1:-;3970:4;3987:8;4000:48;4026:8;4036:11;4000:25;:48::i;:::-;-1:-1:-1;3986:62:1;3889:186;-1:-1:-1;;;;3889:186:1:o;985:35:6:-;;;-1:-1:-1;;;;;985:35:6;;:::o;475:21::-;;;;;;:::o;7601:349:5:-;7663:4;7679:23;;:::i;:::-;7705:38;;;;;;;;7720:21;:19;:21::i;:::-;7705:38;;-1:-1:-1;;;;;7818:20:5;;7754:14;7818:20;;;:13;:20;;;;;;7679:64;;-1:-1:-1;7754:14:5;;;7786:53;;7679:64;;7786:17;:53::i;:::-;7753:86;;-1:-1:-1;7753:86:5;-1:-1:-1;7865:18:5;7857:4;:26;;;;;;;;;7849:70;;;;;-1:-1:-1;;;7849:70:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;7936:7;7601:349;-1:-1:-1;;;;7601:349:5:o;15123:86::-;15165:4;15188:14;:12;:14::i;:::-;15181:21;;15123:86;:::o;5008:117:1:-;5064:4;5087:31;5108:9;5087:20;:31::i;52391:718:5:-;52536:5;;52469:4;;52536:5;;;-1:-1:-1;;;;;52536:5:5;52522:10;:19;52518:122;;52564:65;52569:18;52589:39;52564:4;:65::i;:::-;52557:72;;;;52518:122;52688:11;;52783:30;;;-1:-1:-1;;;52783:30:5;;;;-1:-1:-1;;;;;52688:11:5;;;;52783:28;;;;;:30;;;;;;;;;;;;;;:28;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;52783:30:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;52783:30:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;52783:30:5;52775:71;;;;;-1:-1:-1;;;52775:71:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;52911:11;:28;;-1:-1:-1;;;;;;52911:28:5;-1:-1:-1;;;;;52911:28:5;;;;;;;;;53018:46;;;;;;;;;;;;;;;;;;;;;;;;;;;53087:14;53082:20;53075:27;52391:718;-1:-1:-1;;;52391:718:5:o;1935:24:6:-;;;;:::o;1106:39::-;;;-1:-1:-1;;;;;1106:39:6;;:::o;58218:563:5:-;58293:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;58322:16;:14;:16::i;:::-;58309:29;-1:-1:-1;58352:29:5;;58348:274;;58541:70;58552:5;58546:12;;;;;;;;58560:50;58541:4;:70::i;:::-;58534:77;;;;;58348:274;58740:34;58761:12;58740:20;:34::i;:::-;58733:41;;;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;58218:563;;-1:-1:-1;58218:563:5:o;1659:30:6:-;;;;:::o;7679:25::-;;;-1:-1:-1;;;;;7679:25:6;;:::o;7243:110:5:-;-1:-1:-1;;;;;7326:20:5;7300:7;7326:20;;;:13;:20;;;;;;;7243:110::o;10038:189::-;10100:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;10124:16;:14;:16::i;:::-;:40;10116:75;;;;;-1:-1:-1;;;10116:75:5;;;;;;;;;;;;-1:-1:-1;;;10116:75:5;;;;;;;;;;;;;;;-1:-1:-1;10208:12:5;;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;10038:189;:::o;2759:131:1:-;2822:4;2845:38;2870:12;2845:24;:38::i;2060:25:6:-;;;;:::o;380:20::-;;;;;;;;;;;;;;-1:-1:-1;;380:20:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10934:283:5;11001:4;11018:13;11033:11;11048:36;11076:7;11048:27;:36::i;:::-;11017:67;;-1:-1:-1;11017:67:5;-1:-1:-1;11109:18:5;11102:3;:25;;;;;;;;;11094:93;;;;-1:-1:-1;;;11094:93:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;871:1498;1219:5;;;;;-1:-1:-1;;;;;1219:5:5;1205:10;:19;1197:68;;;;-1:-1:-1;;;1197:68:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1283:18;;:23;:43;;;;-1:-1:-1;1310:11:5;;:16;1283:43;1275:91;;;;-1:-1:-1;;;1275:91:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1414:27;:58;;;1490:31;1482:92;;;;-1:-1:-1;;;1482:92:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1616:8;1627:29;1643:12;1627:15;:29::i;:::-;1616:40;-1:-1:-1;1674:27:5;;1666:66;;;;;-1:-1:-1;;;1666:66:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;1869:16;:14;:16::i;:::-;1848:18;:37;447:4:15;1895:11:5;:25;2017:46;2044:18;2017:26;:46::i;:::-;2011:52;-1:-1:-1;2081:27:5;;2073:74;;;;-1:-1:-1;;;2073:74:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2158:12;;;;:4;;:12;;;;;:::i;:::-;-1:-1:-1;2180:16:5;;;;:6;;:16;;;;;:::i;:::-;-1:-1:-1;;2206:8:5;:20;;;;;;-1:-1:-1;;2206:20:5;;;;;;:8;2344:18;;;;;2206:20;2344:18;;;-1:-1:-1;;;;;871:1498:5:o;1827:130:1:-;1876:4;1893:8;1906:24;1919:10;1906:12;:24::i;15450:3774:5:-;15492:4;15556:23;15582:16;:14;:16::i;:::-;15639:18;;15556:42;;-1:-1:-1;15724:45:5;;;15720:103;;;15797:14;15785:27;;;;;;15720:103;15887:14;15904;:12;:14::i;:::-;15948:12;;15991:13;;16038:11;;16143:17;;:71;;;-1:-1:-1;;;16143:71:5;;;;;;;;;;;;;;;;;;;;;;15887:31;;-1:-1:-1;15948:12:5;;15991:13;;16038:11;;15928:17;;-1:-1:-1;;;;;16143:17:5;;;;:31;;:71;;;;;;;;;;;;;;:17;:71;;;5:2:-1;;;;30:1;27;20:12;5:2;16143:71:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16143:71:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;16143:71:5;;-1:-1:-1;644:9:6;16232:43:5;;;16224:84;;;;;-1:-1:-1;;;16224:84:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;16396:17;16415:15;16434:52;16442:18;16462:23;16434:7;:52::i;:::-;16395:91;;-1:-1:-1;16395:91:5;-1:-1:-1;16515:18:5;16504:7;:29;;;;;;;;;16496:73;;;;;-1:-1:-1;;;16496:73:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;17050:31;;:::i;:::-;17091:24;17125:20;17155:21;17186:19;17250:58;17260:35;;;;;;;;17275:18;17260:35;;;17297:10;17250:9;:58::i;:::-;17216:92;;-1:-1:-1;17216:92:5;-1:-1:-1;17333:18:5;17322:7;:29;;;;;;;;;17318:181;;17374:114;17385:16;17403:69;17479:7;17474:13;;;;;;;;17374:10;:114::i;:::-;17367:121;;;;;;;;;;;;;;;;;;17318:181;17542:53;17560:20;17582:12;17542:17;:53::i;:::-;17509:86;;-1:-1:-1;17509:86:5;-1:-1:-1;17620:18:5;17609:7;:29;;;;;;;;;17605:179;;17661:112;17672:16;17690:67;17764:7;17759:13;;;;;;;17605:179;17823:42;17831:19;17852:12;17823:7;:42::i;:::-;17794:71;;-1:-1:-1;17794:71:5;-1:-1:-1;17890:18:5;17879:7;:29;;;;;;;;;17875:176;;17931:109;17942:16;17960:64;18031:7;18026:13;;;;;;;17875:176;18091:100;18116:38;;;;;;;;18131:21;;18116:38;;;18156:19;18177:13;18091:24;:100::i;:::-;18061:130;;-1:-1:-1;18061:130:5;-1:-1:-1;18216:18:5;18205:7;:29;;;;;;;;;18201:177;;18257:110;18268:16;18286:65;18358:7;18353:13;;;;;;;18201:177;18416:82;18441:20;18463:16;18481;18416:24;:82::i;:::-;18388:110;;-1:-1:-1;18388:110:5;-1:-1:-1;18523:18:5;18512:7;:29;;;;;;;;;18508:175;;18564:108;18575:16;18593:63;18663:7;18658:13;;;;;;;18508:175;18879:18;:39;;;18928:11;:28;;;18966:12;:30;;;19006:13;:32;;;19100:79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19202:14;19190:27;;;;;;;;;;;;;;;;15450:3774;:::o;5231:183::-;5309:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;5332:51;5347:10;5359;5371:3;5376:6;5332:14;:51::i;:::-;:75;5325:82;;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;5231:183;;-1:-1:-1;;5231:183:5:o;1805:23:6:-;;;;:::o;9716:182:5:-;9792:17;;9769:4;;-1:-1:-1;;;;;9792:17:5;:31;9824:14;:12;:14::i;:::-;9840:12;;9854:13;;9869:21;;9792:99;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9792:99:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9792:99:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9792:99:5;;-1:-1:-1;9716:182:5;:::o;47163:192::-;47265:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;47288:60;47302:10;47314;47326:8;47336:11;47288:13;:60::i;:::-;47281:67;;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;47163:192;;-1:-1:-1;;;47163:192:5:o;50549:631::-;50692:5;;50626:4;;50692:5;;;-1:-1:-1;;;;;50692:5:5;50678:10;:19;50674:124;;50720:67;50725:18;50745:41;50720:4;:67::i;50674:124::-;50894:12;;;-1:-1:-1;;;;;50974:30:5;;;-1:-1:-1;;;;;;50974:30:5;;;;;;;51086:49;;;50894:12;;;;51086:49;;;;;;;;;;;;;;;;;;;;;;;51158:14;51153:20;;12851:195;12911:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;12935:16;:14;:16::i;:::-;:40;12927:75;;;;;-1:-1:-1;;;12927:75:5;;;;;;;;;;;;-1:-1:-1;;;12927:75:5;;;;;;;;;;;;;;;13019:20;:18;:20::i;:::-;13012:27;;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;12851:195;:::o;8288:685::-;-1:-1:-1;;;;;8411:22:5;;8356:4;8411:22;;;:13;:22;;;;;;8356:4;;;;;;;;;8556:36;8425:7;8556:27;:36::i;:::-;8532:60;-1:-1:-1;8532:60:5;-1:-1:-1;8614:18:5;8606:4;:26;;;;;;;;;8602:97;;8661:16;8656:22;8648:40;-1:-1:-1;8680:1:5;;-1:-1:-1;8680:1:5;;-1:-1:-1;8680:1:5;;-1:-1:-1;8648:40:5;;-1:-1:-1;;;;8648:40:5;8602:97;8740:28;:26;:28::i;:::-;8709:59;-1:-1:-1;8709:59:5;-1:-1:-1;8790:18:5;8782:4;:26;;;;;;;;;8778:97;;8837:16;8832:22;;8778:97;-1:-1:-1;8898:14:5;;-1:-1:-1;8915:13:5;;-1:-1:-1;8930:13:5;-1:-1:-1;8930:13:5;-1:-1:-1;8288:685:5;;;;;;:::o;3151:111:1:-;3204:4;3227:28;3242:12;3227:14;:28::i;2300:111::-;2353:4;2376:28;2391:12;2376:14;:28::i;6919:141:5:-;-1:-1:-1;;;;;7019:25:5;;;6993:7;7019:25;;;:18;:25;;;;;;;;:34;;;;;;;;;;;;;6919:141::o;51451:722::-;51599:12;;51493:4;;-1:-1:-1;;;;;51599:12:5;51585:10;:26;;;:54;;-1:-1:-1;51615:10:5;:24;51585:54;51581:162;;;51662:70;51667:18;51687:44;51662:4;:70::i;:::-;51655:77;;;;51581:162;51824:5;;;51865:12;;;-1:-1:-1;;;;;51865:12:5;;;51824:5;51935:20;;;-1:-1:-1;;;;;;51935:20:5;;;;;;;-1:-1:-1;;;;;;52001:25:5;;;;;;52042;;;51824:5;;;;;;52042:25;;;52061:5;;;;;52042:25;;;;;;51824:5;;51865:12;;52042:25;;;;;;;;;52115:12;;52082:46;;;-1:-1:-1;;;;;52082:46:5;;;;;52115:12;;;52082:46;;;;;;;;;;;;;;;;52151:14;52139:27;;;;51451:722;:::o;61117:625::-;61204:4;61220:10;61233:16;:14;:16::i;:::-;61220:29;-1:-1:-1;61263:29:5;;61259:295;;61465:78;61476:5;61470:12;;;;;;;;61484:58;61465:4;:78::i;:::-;61458:85;;;;;61259:295;61687:48;61714:20;61687:26;:48::i;1242:42:6:-;;;-1:-1:-1;;;;;1242:42:6;;:::o;4547:234:1:-;4660:4;4677:8;4690:64;4714:8;4724:11;4737:16;4690:23;:64::i;:::-;-1:-1:-1;4676:78:1;4547:234;-1:-1:-1;;;;;4547:234:1:o;879:28:6:-;;;;;;-1:-1:-1;;;;;879:28:6;;:::o;9387:159:5:-;9463:17;;9440:4;;-1:-1:-1;;;;;9463:17:5;:31;9495:14;:12;:14::i;:::-;9511:12;;9525:13;;9463:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;53405:599:5;53494:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;53523:16;:14;:16::i;:::-;53510:29;-1:-1:-1;53553:29:5;;53549:283;;53748:73;53759:5;53753:12;;;;;;;;53767:53;53748:4;:73::i;53549:283::-;53949:48;53972:24;53949:22;:48::i;3155:36:6:-;3187:4;3155:36;:::o;35499:564:5:-;35577:4;64571:11;;35577:4;;64571:11;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;35612:16;:14;:16::i;:::-;35599:29;-1:-1:-1;35642:29:5;;35638:257;;35813:67;35824:5;35818:12;;;;;;;;35832:47;35813:4;:67::i;:::-;35805:79;-1:-1:-1;35882:1:5;;-1:-1:-1;35805:79:5;;-1:-1:-1;35805:79:5;35638:257;36003:53;36020:10;36032;36044:11;36003:16;:53::i;:::-;35996:60;;;;;64636:1;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;35499:564;;;;-1:-1:-1;35499:564:5:o;13803:1156::-;13911:11;;13864:9;;;;13936:17;13932:1021;;-1:-1:-1;;14125:27:5;;14105:18;;-1:-1:-1;14097:56:5;;13932:1021;14329:14;14346;:12;:14::i;:::-;14329:31;;14374:33;14421:23;;:::i;:::-;14458:17;14532:54;14547:9;14558:12;;14572:13;;14532:14;:54::i;:::-;14490:96;-1:-1:-1;14490:96:5;-1:-1:-1;14615:18:5;14604:7;:29;;;;;;;;;14600:87;;14661:7;-1:-1:-1;14670:1:5;;-1:-1:-1;14653:19:5;;-1:-1:-1;;;;14653:19:5;14600:87;14727:50;14734:28;14764:12;14727:6;:50::i;:::-;14701:76;-1:-1:-1;14701:76:5;-1:-1:-1;14806:18:5;14795:7;:29;;;;;;;;;14791:87;;14852:7;-1:-1:-1;14861:1:5;;-1:-1:-1;14844:19:5;;-1:-1:-1;;;;14844:19:5;14791:87;-1:-1:-1;14920:21:5;14900:18;;-1:-1:-1;14920:21:5;-1:-1:-1;14892:50:5;;-1:-1:-1;;;14892:50:5;13803:1156;;;:::o;2821:2157::-;2993:11;;:60;;;-1:-1:-1;;;2993:60:5;;3029:4;2993:60;;;;-1:-1:-1;;;;;2993:60:5;;;;;;;;;;;;;;;;;;;;;;2919:4;;;;2993:11;;:27;;:60;;;;;;;;;;;;;;2919:4;2993:11;:60;;;5:2:-1;;;;30:1;27;20:12;5:2;2993:60:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2993:60:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2993:60:5;;-1:-1:-1;3067:12:5;;3063:142;;3102:92;3113:27;3142:42;3186:7;3102:10;:92::i;:::-;3095:99;;;;;3063:142;3268:3;-1:-1:-1;;;;;3261:10:5;:3;-1:-1:-1;;;;;3261:10:5;;3257:103;;;3294:55;3299:15;3316:32;3294:4;:55::i;3257:103::-;3434:22;-1:-1:-1;;;;;3474:14:5;;;;;;;3470:156;;;-1:-1:-1;;;3470:156:5;;;-1:-1:-1;;;;;;3583:23:5;;;;;;;:18;:23;;;;;;;;:32;;;;;;;;;;3470:156;3701:17;3728;3755;3782;3836:34;3844:17;3863:6;3836:7;:34::i;:::-;3810:60;;-1:-1:-1;3810:60:5;-1:-1:-1;3895:18:5;3884:7;:29;;;;;;;;;3880:123;;3936:56;3941:16;3959:32;3936:4;:56::i;:::-;3929:63;;;;;;;;;;3880:123;-1:-1:-1;;;;;4047:18:5;;;;;;:13;:18;;;;;;4039:35;;4067:6;4039:7;:35::i;:::-;4013:61;;-1:-1:-1;4013:61:5;-1:-1:-1;4099:18:5;4088:7;:29;;;;;;;;;4084:122;;4140:55;4145:16;4163:31;4140:4;:55::i;4084:122::-;-1:-1:-1;;;;;4250:18:5;;;;;;:13;:18;;;;;;4242:35;;4270:6;4242:7;:35::i;:::-;4216:61;;-1:-1:-1;4216:61:5;-1:-1:-1;4302:18:5;4291:7;:29;;;;;;;;;4287:120;;4343:53;4348:16;4366:29;4343:4;:53::i;4287:120::-;-1:-1:-1;;;;;4534:18:5;;;;;;;:13;:18;;;;;;:33;;;4577:18;;;;;;:33;;;-1:-1:-1;;4680:29:5;;4676:107;;-1:-1:-1;;;;;4725:23:5;;;;;;;:18;:23;;;;;;;;:32;;;;;;;;;:47;;;4676:107;4851:3;-1:-1:-1;;;;;4837:26:5;4846:3;-1:-1:-1;;;;;4837:26:5;-1:-1:-1;;;;;;;;;;;4856:6:5;4837:26;;;;;;;;;;;;;;;;;;4874:11;;:59;;;-1:-1:-1;;;4874:59:5;;4909:4;4874:59;;;;-1:-1:-1;;;;;4874:59:5;;;;;;;;;;;;;;;;;;;;;;:11;;;;;:26;;:59;;;;;:11;;:59;;;;;;;:11;;:59;;;5:2:-1;;;;30:1;27;20:12;5:2;4874:59:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;4956:14:5;;-1:-1:-1;4951:20:5;;-1:-1:-1;;4951:20:5;;4944:27;2821:2157;-1:-1:-1;;;;;;;;;;;2821:2157:5:o;36388:586::-;36490:4;64571:11;;36490:4;;64571:11;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;36525:16;:14;:16::i;:::-;36512:29;-1:-1:-1;36555:29:5;;36551:257;;36726:67;36737:5;36731:12;;;;;;;;36745:47;36726:4;:67::i;:::-;36718:79;-1:-1:-1;36795:1:5;;-1:-1:-1;36718:79:5;;-1:-1:-1;36718:79:5;36551:257;36916:51;36933:10;36945:8;36955:11;36916:16;:51::i;:::-;36909:58;;;;;64636:1;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;36388:586;;;;-1:-1:-1;36388:586:5;-1:-1:-1;36388:586:5:o;2536:306:15:-;2613:9;2624:4;2641:13;2656:18;;:::i;:::-;2678:20;2688:1;2691:6;2678:9;:20::i;:::-;2640:58;;-1:-1:-1;2640:58:15;-1:-1:-1;2719:18:15;2712:3;:25;;;;;;;;;2708:71;;-1:-1:-1;2761:3:15;-1:-1:-1;2766:1:15;;-1:-1:-1;2753:15:15;;2708:71;2797:18;2817:17;2826:7;2817:8;:17::i;:::-;2789:46;;;;;;2536:306;;;;;;:::o;5384:166:1:-;5485:10;;5513:30;;;-1:-1:-1;;;5513:30:1;;5537:4;5513:30;;;;;;5431:4;;-1:-1:-1;;;;;5485:10:1;;;;5513:15;;:30;;;;;;;;;;;;;;;5485:10;5513:30;;;5:2:-1;;;;30:1;27;20:12;5:2;5513:30:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5513:30:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5513:30:1;;-1:-1:-1;;5384:166:1;:::o;55465:580:5:-;55542:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;55571:16;:14;:16::i;:::-;55558:29;-1:-1:-1;55601:29:5;;55597:271;;55790:67;55801:5;55795:12;;;;;;;;55809:47;55790:4;:67::i;55597:271::-;55988:28;56006:9;55988:17;:28::i;:::-;-1:-1:-1;55976:40:5;-1:-1:-1;;64647:11:5;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;55465:580;;-1:-1:-1;55465:580:5:o;7334:149:14:-;7395:4;7416:33;7429:3;7424:9;;;;;;;;7440:4;7435:10;;;;;;;;7416:33;;;;;;;;;;;;;7447:1;7416:33;;;;;;;;;;;;;7472:3;7467:9;;;;;;;59050:1706:5;59256:5;;59117:4;;;;59256:5;;;-1:-1:-1;;;;;59256:5:5;59242:10;:19;59238:122;;59284:65;59289:18;59309:39;59284:4;:65::i;59238:122::-;59483:16;:14;:16::i;:::-;59461:18;;:38;59457:145;;59522:69;59527:22;59551:39;59522:4;:69::i;59457:145::-;59705:12;59688:14;:12;:14::i;:::-;:29;59684:150;;;59740:83;59745:29;59776:46;59740:4;:83::i;59684:150::-;59925:13;;59910:12;:28;59906:127;;;59961:61;59966:15;59983:38;59961:4;:61::i;59906:127::-;-1:-1:-1;60179:13:5;;:28;;;;60313:33;;;60305:82;;;;-1:-1:-1;;;60305:82:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60458:13;:32;;;60621:5;;60607:34;;60621:5;;;-1:-1:-1;;;;;60621:5:5;60628:12;60607:13;:34::i;:::-;60673:5;;60657:54;;;60673:5;;;;-1:-1:-1;;;;;60673:5:5;60657:54;;;;;;;;;;;;;;;;;;;;;;;;;60734:14;60729:20;;25190:529;25274:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;25303:16;:14;:16::i;:::-;25290:29;-1:-1:-1;25333:29:5;;25329:246;;25503:61;25514:5;25508:12;;;;;;;;25522:41;25503:4;:61::i;25329:246::-;25672:40;25684:10;25696:1;25699:12;25672:11;:40::i;11464:1238::-;-1:-1:-1;;;;;11806:23:5;;11541:9;11806:23;;;:14;:23;;;;;12030:24;;11541:9;;;;;;;;12026:90;;-1:-1:-1;12083:18:5;;-1:-1:-1;12083:18:5;;-1:-1:-1;12075:30:5;;-1:-1:-1;;;12075:30:5;12026:90;12338:46;12346:14;:24;;;12372:11;;12338:7;:46::i;:::-;12305:79;;-1:-1:-1;12305:79:5;-1:-1:-1;12409:18:5;12398:7;:29;;;;;;;;;12394:79;;-1:-1:-1;12451:7:5;;-1:-1:-1;12460:1:5;;-1:-1:-1;12443:19:5;;-1:-1:-1;;12443:19:5;12394:79;12503:58;12511:19;12532:14;:28;;;12503:7;:58::i;:::-;12483:78;;-1:-1:-1;12483:78:5;-1:-1:-1;12586:18:5;12575:7;:29;;;;;;;;;12571:79;;-1:-1:-1;12628:7:5;;-1:-1:-1;12637:1:5;;-1:-1:-1;12620:19:5;;-1:-1:-1;;12620:19:5;12571:79;-1:-1:-1;12668:18:5;;-1:-1:-1;12688:6:5;-1:-1:-1;;;11464:1238:5;;;;:::o;9126:91::-;9198:12;9126:91;:::o;62064:1271::-;62358:5;;62158:4;;;;62358:5;;;-1:-1:-1;;;;;62358:5:5;62344:10;:19;62340:130;;62386:73;62391:18;62411:47;62386:4;:73::i;62340:130::-;62593:16;:14;:16::i;:::-;62571:18;;:38;62567:153;;62632:77;62637:22;62661:47;62632:4;:77::i;62567:153::-;62811:17;;;;;;;;;-1:-1:-1;;;;;62811:17:5;62788:40;;62928:20;-1:-1:-1;;;;;62928:40:5;;:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;62928:42:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;62928:42:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;62928:42:5;62920:83;;;;;-1:-1:-1;;;62920:83:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;63077:17;:40;;-1:-1:-1;;;;;;63077:40:5;-1:-1:-1;;;;;63077:40:5;;;;;;;;;63220:70;;;;;;;;;;;;;;;;;;;;;;;;;;;63313:14;63308:20;;19614:539;19684:4;64571:11;;19684:4;;64571:11;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;19719:16;:14;:16::i;:::-;19706:29;-1:-1:-1;19749:29:5;;19745:249;;19920:59;19931:5;19925:12;;;;;;;;19939:39;19920:4;:59::i;19745:249::-;20113:33;20123:10;20135;20113:9;:33::i;1303:230:7:-;1359:9;1370:4;1395:1;1390;:6;1386:141;;-1:-1:-1;1420:18:7;;-1:-1:-1;1440:5:7;;;1412:34;;1386:141;-1:-1:-1;1485:27:7;;-1:-1:-1;1514:1:7;1477:39;;2082:346:15;2151:9;2162:10;;:::i;:::-;2185:14;2201:19;2224:27;2232:1;:10;;;2244:6;2224:7;:27::i;:::-;2184:67;;-1:-1:-1;2184:67:15;-1:-1:-1;2273:18:15;2265:4;:26;;;;;;;;;2261:90;;-1:-1:-1;2321:18:15;;;;;;;;;-1:-1:-1;2321:18:15;;2315:4;;-1:-1:-1;2321:18:15;-1:-1:-1;2307:33:15;;2261:90;2389:31;;;;;;;;;;;;-1:-1:-1;;2389:31:15;;-1:-1:-1;2082:346:15;-1:-1:-1;;;;2082:346:15:o;7601:183:14:-;7686:4;7707:43;7720:3;7715:9;;;;;;;;7731:4;7726:10;;;;;;;;7707:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;7773:3;7768:9;;;;;;;1613:250:7;1669:9;;1705:5;;;1725:6;;;1721:136;;1755:18;;-1:-1:-1;1775:1:7;-1:-1:-1;1747:30:7;;1721:136;-1:-1:-1;1816:26:7;;-1:-1:-1;1844:1:7;;-1:-1:-1;1808:38:7;;2982:321:15;3079:9;3090:4;3107:13;3122:18;;:::i;:::-;3144:20;3154:1;3157:6;3144:9;:20::i;:::-;3106:58;;-1:-1:-1;3106:58:15;-1:-1:-1;3185:18:15;3178:3;:25;;;;;;;;;3174:71;;-1:-1:-1;3227:3:15;-1:-1:-1;3232:1:15;;-1:-1:-1;3219:15:15;;3174:71;3262:34;3270:17;3279:7;3270:8;:17::i;:::-;3289:6;3262:7;:34::i;:::-;3255:41;;;;;;2982:321;;;;;;;:::o;48018:2093:5:-;48207:11;;:87;;;-1:-1:-1;;;48207:87:5;;48240:4;48207:87;;;;-1:-1:-1;;;;;48207:87:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48136:4;;;;48207:11;;:24;;:87;;;;;;;;;;;;;;48136:4;48207:11;:87;;;5:2:-1;;;;30:1;27;20:12;5:2;48207:87:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;48207:87:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;48207:87:5;;-1:-1:-1;48308:12:5;;48304:149;;48343:99;48354:27;48383:49;48434:7;48343:10;:99::i;48304:149::-;48523:10;-1:-1:-1;;;;;48511:22:5;:8;-1:-1:-1;;;;;48511:22:5;;48507:144;;;48556:84;48561:26;48589:50;48556:4;:84::i;48507:144::-;-1:-1:-1;;;;;49064:23:5;;48661:17;49064:23;;;:13;:23;;;;;;48661:17;;;;49056:45;;49089:11;49056:7;:45::i;:::-;49025:76;;-1:-1:-1;49025:76:5;-1:-1:-1;49126:18:5;49115:7;:29;;;;;;;;;49111:164;;49167:97;49178:16;49196:52;49255:7;49250:13;;;;;;;49167:97;49160:104;;;;;;;;49111:164;-1:-1:-1;;;;;49326:25:5;;;;;;:13;:25;;;;;;49318:47;;49353:11;49318:7;:47::i;:::-;49285:80;;-1:-1:-1;49285:80:5;-1:-1:-1;49390:18:5;49379:7;:29;;;;;;;;;49375:164;;49431:97;49442:16;49460:52;49519:7;49514:13;;;;;;;49375:164;-1:-1:-1;;;;;49735:23:5;;;;;;;:13;:23;;;;;;;;:43;;;49788:25;;;;;;;;;;:47;;;49887:43;;;;;;;49788:25;;-1:-1:-1;;;;;;;;;;;49887:43:5;;;;;;;;;;49980:11;;:86;;;-1:-1:-1;;;49980:86:5;;50012:4;49980:86;;;;-1:-1:-1;;;;;49980:86:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:11;;;;;:23;;:86;;;;;:11;;:86;;;;;;;:11;;:86;;;5:2:-1;;;;30:1;27;20:12;5:2;49980:86:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;50089:14:5;;-1:-1:-1;50084:20:5;;-1:-1:-1;;50084:20:5;;50077:27;48018:2093;-1:-1:-1;;;;;;;;;48018:2093:5:o;31353:516::-;31427:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;31456:16;:14;:16::i;:::-;31443:29;-1:-1:-1;31486:29:5;;31482:246;;31656:61;31667:5;31661:12;;;;;;;;31675:41;31656:4;:61::i;31482:246::-;31825:37;31837:10;31849:12;31825:11;:37::i;24299:519::-;24373:4;64571:11;;;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;24402:16;:14;:16::i;:::-;24389:29;-1:-1:-1;24432:29:5;;24428:246;;24602:61;24613:5;24607:12;;;;;;;24428:246;24771:40;24783:10;24795:12;24809:1;24771:11;:40::i;41519:979::-;41653:4;64571:11;;41653:4;;64571:11;;64563:34;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;-1:-1:-1;;;64563:34:5;;;;;;;;;;;;;;;64621:5;64607:19;;-1:-1:-1;;64607:19:5;;;41688:16;:14;:16::i;:::-;41675:29;-1:-1:-1;41718:29:5;;41714:266;;41894:71;41905:5;41899:12;;;;;;;;41913:51;41894:4;:71::i;:::-;41886:83;-1:-1:-1;41967:1:5;;-1:-1:-1;41886:83:5;;-1:-1:-1;41886:83:5;41714:266;41998:16;-1:-1:-1;;;;;41998:31:5;;:33;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41998:33:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;41998:33:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;41998:33:5;;-1:-1:-1;42045:29:5;;42041:270;;42221:75;42232:5;42226:12;;;;;;;;42240:55;42221:4;:75::i;42041:270::-;42418:73;42439:10;42451:8;42461:11;42474:16;42418:20;:73::i;:::-;42411:80;;;;;64636:1;64647:11;:18;;-1:-1:-1;;64647:18:5;64661:4;64647:18;;;41519:979;;;;-1:-1:-1;41519:979:5;-1:-1:-1;;41519:979:5:o;54265:951::-;54413:5;;54346:4;;54413:5;;;-1:-1:-1;;;;;54413:5:5;54399:10;:19;54395:125;;54441:68;54446:18;54466:42;54441:4;:68::i;54395:125::-;54624:16;:14;:16::i;:::-;54602:18;;:38;54598:148;;54663:72;54668:22;54692:42;54663:4;:72::i;54598:148::-;805:4:6;54815:24:5;:51;54811:155;;;54889:66;54894:15;54911:43;54889:4;:66::i;54811:155::-;55008:21;;;55039:48;;;;55103:68;;;;;;;;;;;;;;;;;;;;;;;;;55194:14;55189:20;;37659:3343;37837:11;;:75;;;-1:-1:-1;;;37837:75:5;;37876:4;37837:75;;;;-1:-1:-1;;;;;37837:75:5;;;;;;;;;;;;;;;;;;;;;;37754:4;;;;;;37837:11;;;:30;;:75;;;;;;;;;;;;;;;37754:4;37837:11;:75;;;5:2:-1;;;;30:1;27;20:12;5:2;37837:75:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;37837:75:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;37837:75:5;;-1:-1:-1;37926:12:5;;37922:151;;37962:96;37973:27;38002:46;38050:7;37962:10;:96::i;:::-;37954:108;-1:-1:-1;38060:1:5;;-1:-1:-1;37954:108:5;;-1:-1:-1;37954:108:5;37922:151;38180:16;:14;:16::i;:::-;38158:18;;:38;38154:151;;38220:70;38225:22;38249:40;38220:4;:70::i;38154:151::-;38315:32;;:::i;:::-;-1:-1:-1;;;;;38458:24:5;;;;;;:14;:24;;;;;:38;;;38437:18;;;:59;38624:37;38473:8;38624:27;:37::i;:::-;38601:19;;;38586:75;;;38587:12;;;38586:75;;;;;;;;;;;;;;;;;;;-1:-1:-1;38691:18:5;;-1:-1:-1;38675:4:5;:12;;;:34;;;;;;;;;38671:190;;38733:113;38744:16;38762:63;38832:4;:12;;;38827:18;;;;;;;38733:113;38725:125;-1:-1:-1;38848:1:5;;-1:-1:-1;38725:125:5;;-1:-1:-1;;38725:125:5;38671:190;-1:-1:-1;;38940:11:5;:23;38936:153;;;38998:19;;;;38979:16;;;:38;38936:153;;;39048:16;;;:30;;;38936:153;39674:37;39687:5;39694:4;:16;;;39674:12;:37::i;:::-;39649:22;;;:62;;;40014:19;;;;40006:52;;:7;:52::i;:::-;39980:22;;;39965:93;;;39966:12;;;39965:93;;;;;;;;;;;;;;;;;;;-1:-1:-1;40092:18:5;;-1:-1:-1;40076:4:5;:12;;;:34;;;;;;;;;40068:105;;;;-1:-1:-1;;;40068:105:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40223:45;40231:12;;40245:4;:22;;;40223:7;:45::i;:::-;40199:20;;;40184:84;;;40185:12;;;40184:84;;;;;;;;;;;;;;;;;;;-1:-1:-1;40302:18:5;;-1:-1:-1;40286:4:5;:12;;;:34;;;;;;;;;40278:96;;;;-1:-1:-1;;;40278:96:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40491:22;;;;;;-1:-1:-1;;;;;40454:24:5;;;;;;;:14;:24;;;;;;;;;:59;;;40564:11;;40523:38;;;;:52;;;;40600:20;;;;40585:12;:35;;;40707:22;;;;40731;;40678:98;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40826:11;;40888:22;;;;40912:18;;;;40826:105;;;-1:-1:-1;;;40826:105:5;;40864:4;40826:105;;;;-1:-1:-1;;;;;40826:105:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:11;;;;;:29;;:105;;;;;:11;;:105;;;;;;;:11;;:105;;;5:2:-1;;;;30:1;27;20:12;5:2;40826:105:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;40955:14:5;;-1:-1:-1;40950:20:5;;-1:-1:-1;;40950:20:5;;40972:4;:22;;;40942:53;;;;;;37659:3343;;;;;;:::o;1927:263:7:-;1998:9;2009:4;2026:14;2042:8;2054:13;2062:1;2065;2054:7;:13::i;:::-;2025:42;;-1:-1:-1;2025:42:7;-1:-1:-1;2090:18:7;2082:4;:26;;;;;;;;;2078:73;;-1:-1:-1;2132:4:7;-1:-1:-1;2138:1:7;;-1:-1:-1;2124:16:7;;2078:73;2168:15;2176:3;2181:1;2168:7;:15::i;876:503:15:-;937:9;948:10;;:::i;:::-;971:14;987:20;1011:22;1019:3;447:4;1011:7;:22::i;:::-;970:63;;-1:-1:-1;970:63:15;-1:-1:-1;1055:18:15;1047:4;:26;;;;;;;;;1043:90;;-1:-1:-1;1103:18:15;;;;;;;;;-1:-1:-1;1103:18:15;;1097:4;;-1:-1:-1;1103:18:15;-1:-1:-1;1089:33:15;;1043:90;1144:14;1160:13;1177:31;1185:15;1202:5;1177:7;:31::i;:::-;1143:65;;-1:-1:-1;1143:65:15;-1:-1:-1;1230:18:15;1222:4;:26;;;;;;;;;1218:90;;-1:-1:-1;1278:18:15;;;;;;;;;-1:-1:-1;1278:18:15;;1272:4;;-1:-1:-1;1278:18:15;-1:-1:-1;1264:33:15;;-1:-1:-1;;1264:33:15;1218:90;1346:25;;;;;;;;;;;;-1:-1:-1;;1346:25:15;;-1:-1:-1;876:503:15;-1:-1:-1;;;;;;876:503:15:o;7228:210::-;7408:12;447:4;7408:23;;;7228:210::o;56377:1594:5:-;56438:4;56444;56503:21;56534:20;56678:16;:14;:16::i;:::-;56656:18;;:38;56652:161;;56718:66;56723:22;56747:36;56718:4;:66::i;:::-;56710:92;-1:-1:-1;56786:15:5;-1:-1:-1;56710:92:5;;-1:-1:-1;56710:92:5;56652:161;57388:35;57401:10;57413:9;57388:12;:35::i;:::-;57370:53;;57469:15;57453:13;;:31;57434:50;;57556:13;;57536:16;:33;;57528:78;;;;;-1:-1:-1;;;57528:78:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57680:13;:32;;;57798:60;;;57812:10;57798:60;;;;;;;;;;;;;;;;;;;;;;;;;57931:14;57918:46;-1:-1:-1;57948:15:5;-1:-1:-1;;56377:1594:5;;;:::o;8168:885:1:-;8303:10;;8324:26;;;-1:-1:-1;;;8324:26:1;;-1:-1:-1;;;;;8324:26:1;;;;;;;;;;;;;;;8303:10;;;;;;;8324:14;;:26;;;;;8243:31;;8324:26;;;;;;;;8243:31;8303:10;8324:26;;;5:2:-1;;;;30:1;27;20:12;5:2;8324:26:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;8324:26:1;;;;8361:12;8413:16;8451:1;8446:150;;;;8618:2;8613:216;;;;8962:1;8959;8952:12;8446:150;-1:-1:-1;;8540:6:1;-1:-1:-1;8446:150:1;;8613:216;8714:2;8711:1;8708;8693:24;8755:1;8749:8;8738:19;;8406:576;;9009:7;9001:45;;;;;-1:-1:-1;;;9001:45:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;8168:885;;;;:::o;26588:4504:5:-;26695:4;26719:19;;;:42;;-1:-1:-1;26742:19:5;;26719:42;26711:107;;;;-1:-1:-1;;;26711:107:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26829:27;;:::i;:::-;26970:28;:26;:28::i;:::-;26941:25;;;26926:72;;;26927:12;;;26926:72;;;;;;;;;;;;;;;;;;;-1:-1:-1;27028:18:5;;-1:-1:-1;27012:4:5;:12;;;:34;;;;;;;;;27008:166;;27069:94;27080:16;27098:44;27149:4;:12;;;27144:18;;;;;;;27069:94;27062:101;;;;;27008:166;27225:18;;27221:1265;;27495:17;;;:34;;;27598:42;;;;;;;;27613:25;;;;27598:42;;27580:77;;27515:14;27580:17;:77::i;:::-;27559:17;;;27544:113;;;27545:12;;;27544:113;;;;;;;;;;;;;;;;;;;-1:-1:-1;27691:18:5;;-1:-1:-1;27675:4:5;:12;;;:34;;;;;;;;;27671:183;;27736:103;27747:16;27765:53;27825:4;:12;;;27820:18;;;;;;;27671:183;27221:1265;;;28148:82;28171:14;28187:42;;;;;;;;28202:4;:25;;;28187:42;;;28148:22;:82::i;:::-;28127:17;;;28112:118;;;28113:12;;;28112:118;;;;;;;;;;;;;;;;;;;-1:-1:-1;28264:18:5;;-1:-1:-1;28248:4:5;:12;;;:34;;;;;;;;;28244:183;;28309:103;28320:16;28338:53;28398:4;:12;;;28393:18;;;;;;;28244:183;28441:17;;;:34;;;27221:1265;28552:11;;28603:17;;;;28552:69;;;-1:-1:-1;;;28552:69:5;;28586:4;28552:69;;;;-1:-1:-1;;;;;28552:69:5;;;;;;;;;;;;;;;;28537:12;;28552:11;;;;;:25;;:69;;;;;;;;;;;;;;;28537:12;28552:11;:69;;;5:2:-1;;;;30:1;27;20:12;5:2;28552:69:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;28552:69:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28552:69:5;;-1:-1:-1;28635:12:5;;28631:140;;28670:90;28681:27;28710:40;28752:7;28670:10;:90::i;:::-;28663:97;;;;;;28631:140;28878:16;:14;:16::i;:::-;28856:18;;:38;28852:140;;28917:64;28922:22;28946:34;28917:4;:64::i;28852:140::-;29280:39;29288:11;;29301:4;:17;;;29280:7;:39::i;:::-;29257:19;;;29242:77;;;29243:12;;;29242:77;;;;;;;;;;;;;;;;;;;-1:-1:-1;29349:18:5;;-1:-1:-1;29333:4:5;:12;;;:34;;;;;;;;;29329:176;;29390:104;29401:16;29419:54;29480:4;:12;;;29475:18;;;;;;;29329:176;-1:-1:-1;;;;;29563:23:5;;;;;;:13;:23;;;;;;29588:17;;;;29555:51;;29563:23;29555:7;:51::i;:::-;29530:21;;;29515:91;;;29516:12;;;29515:91;;;;;;;;;;;;;;;;;;;-1:-1:-1;29636:18:5;;-1:-1:-1;29620:4:5;:12;;;:34;;;;;;;;;29616:179;;29677:107;29688:16;29706:57;29770:4;:12;;;29765:18;;;;;;;29616:179;29890:4;:17;;;29873:14;:12;:14::i;:::-;:34;29869:153;;;29930:81;29935:29;29966:44;29930:4;:81::i;29869:153::-;30506:42;30520:8;30530:4;:17;;;30506:13;:42::i;:::-;30638:19;;;;30624:11;:33;30693:21;;;;-1:-1:-1;;;;;30667:23:5;;;;;;:13;:23;;;;;;;;;:47;;;;30823:17;;;;30789:52;;;;;;;30816:4;;-1:-1:-1;;;;;;;;;;;30789:52:5;;;;;;;30873:17;;;;30892;;;;;30856:54;;;-1:-1:-1;;;;;30856:54:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30960:11;;31010:17;;;;31029;;;;30960:87;;;-1:-1:-1;;;30960:87:5;;30993:4;30960:87;;;;-1:-1:-1;;;;;30960:87:5;;;;;;;;;;;;;;;;;;;;;;:11;;;;;:24;;:87;;;;;:11;;:87;;;;;;;:11;;:87;;;5:2:-1;;;;30:1;27;20:12;5:2;30960:87:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;31070:14:5;;-1:-1:-1;31065:20:5;;-1:-1:-1;;31065:20:5;;31058:27;26588:4504;-1:-1:-1;;;;;;26588:4504:5:o;543:331:7:-;599:9;;630:6;626:67;;-1:-1:-1;660:18:7;;-1:-1:-1;660:18:7;652:30;;626:67;712:5;;;716:1;712;:5;:1;732:5;;;;;:10;728:140;;-1:-1:-1;766:26:7;;-1:-1:-1;794:1:7;;-1:-1:-1;758:38:7;;728:140;835:18;;-1:-1:-1;855:1:7;-1:-1:-1;827:30:7;;964:209;1020:9;;1051:6;1047:75;;-1:-1:-1;1081:26:7;;-1:-1:-1;1109:1:7;1073:38;;1047:75;1140:18;1164:1;1160;:5;;;;;;1132:34;;;;964:209;;;;;:::o;20844:3112:5:-;20990:11;;:58;;;-1:-1:-1;;;20990:58:5;;21022:4;20990:58;;;;-1:-1:-1;;;;;20990:58:5;;;;;;;;;;;;;;;20914:4;;;;;;20990:11;;;:23;;:58;;;;;;;;;;;;;;;20914:4;20990:11;:58;;;5:2:-1;;;;30:1;27;20:12;5:2;20990:58:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;20990:58:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;20990:58:5;;-1:-1:-1;21062:12:5;;21058:143;;21098:88;21109:27;21138:38;21178:7;21098:10;:88::i;:::-;21090:100;-1:-1:-1;21188:1:5;;-1:-1:-1;21090:100:5;;-1:-1:-1;21090:100:5;21058:143;21308:16;:14;:16::i;:::-;21286:18;;:38;21282:143;;21348:62;21353:22;21377:32;21348:4;:62::i;21282:143::-;21435:25;;:::i;:::-;21515:28;:26;:28::i;:::-;21486:25;;;21471:72;;;21472:12;;;21471:72;;;;;;;;;;;;;;;;;;;-1:-1:-1;21573:18:5;;-1:-1:-1;21557:4:5;:12;;;:34;;;;;;;;;21553:169;;21615:92;21626:16;21644:42;21693:4;:12;;;21688:18;;;;;;;21615:92;21607:104;-1:-1:-1;21709:1:5;;-1:-1:-1;21607:104:5;;-1:-1:-1;;21607:104:5;21553:169;22340:32;22353:6;22361:10;22340:12;:32::i;:::-;22316:21;;;:56;;;22638:42;;;;;;;;22653:25;;;;22638:42;;22592:89;;22316:56;22592:22;:89::i;:::-;22573:15;;;22558:123;;;22559:12;;;22558:123;;;;;;;;;;;;;;;;;;;-1:-1:-1;22715:18:5;;-1:-1:-1;22699:4:5;:12;;;:34;;;;;;;;;22691:79;;;;;-1:-1:-1;;;22691:79:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23067:37;23075:11;;23088:4;:15;;;23067:7;:37::i;:::-;23044:19;;;23029:75;;;23030:12;;;23029:75;;;;;;;;;;;;;;;;;;;-1:-1:-1;23138:18:5;;-1:-1:-1;23122:4:5;:12;;;:34;;;;;;;;;23114:87;;;;-1:-1:-1;;;23114:87:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;23260:21:5;;;;;;:13;:21;;;;;;23283:15;;;;23252:47;;23260:21;23252:7;:47::i;:::-;23227:21;;;23212:87;;;23213:12;;;23212:87;;;;;;;;;;;;;;;;;;;-1:-1:-1;23333:18:5;;-1:-1:-1;23317:4:5;:12;;;:34;;;;;;;;;23309:90;;;;-1:-1:-1;;;23309:90:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23489:19;;;;23475:11;:33;23542:21;;;;-1:-1:-1;;;;;23518:21:5;;;;;;:13;:21;;;;;;;;;:45;;;;23649:21;;;;23672:15;;;;;23636:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23735:15;;;;23703:48;;;;;;;-1:-1:-1;;;;;23703:48:5;;;23720:4;;-1:-1:-1;;;;;;;;;;;23703:48:5;;;;;;;;23801:11;;23847:21;;;;23870:15;;;;23801:85;;;-1:-1:-1;;;23801:85:5;;23832:4;23801:85;;;;-1:-1:-1;;;;;23801:85:5;;;;;;;;;;;;;;;;;;;;;;:11;;;;;:22;;:85;;;;;:11;;:85;;;;;;;:11;;:85;;;5:2:-1;;;;30:1;27;20:12;5:2;23801:85:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;23910:14:5;;-1:-1:-1;23905:20:5;;-1:-1:-1;;23905:20:5;;23927:4;:21;;;23897:52;;;;;;20844:3112;;;;;:::o;32282:2971::-;32438:11;;:64;;;-1:-1:-1;;;32438:64:5;;32472:4;32438:64;;;;-1:-1:-1;;;;;32438:64:5;;;;;;;;;;;;;;;32366:4;;;;32438:11;;:25;;:64;;;;;;;;;;;;;;32366:4;32438:11;:64;;;5:2:-1;;;;30:1;27;20:12;5:2;32438:64:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;32438:64:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;32438:64:5;;-1:-1:-1;32516:12:5;;32512:140;;32551:90;32562:27;32591:40;32633:7;32551:10;:90::i;:::-;32544:97;;;;;32512:140;32759:16;:14;:16::i;:::-;32737:18;;:38;32733:140;;32798:64;32803:22;32827:34;32798:4;:64::i;32733:140::-;32979:12;32962:14;:12;:14::i;:::-;:29;32958:141;;;33014:74;33019:29;33050:37;33014:4;:74::i;32958:141::-;33109:27;;:::i;:::-;33417:37;33445:8;33417:27;:37::i;:::-;33394:19;;;33379:75;;;33380:4;33379:75;;;;;;;;;;;;;;;;;;;-1:-1:-1;33484:18:5;;-1:-1:-1;33468:12:5;;:34;;;;;;;;;33464:179;;33525:107;33536:16;33554:57;33618:4;:12;;;33613:18;;;;;;;33525:107;33518:114;;;;;;33464:179;33694:42;33702:4;:19;;;33723:12;33694:7;:42::i;:::-;33668:22;;;33653:83;;;33654:4;33653:83;;;;;;;;;;;;;;;;;;;-1:-1:-1;33766:18:5;;-1:-1:-1;33750:12:5;;:34;;;;;;;;;33746:186;;33807:114;33818:16;33836:64;33907:4;:12;;;33902:18;;;;;;;33746:186;33981:35;33989:12;;34003;33981:7;:35::i;:::-;33957:20;;;33942:74;;;33943:4;33942:74;;;;;;;;;;;;;;;;;;;-1:-1:-1;34046:18:5;;-1:-1:-1;34030:12:5;;:34;;;;;;;;;34026:177;;34087:105;34098:16;34116:55;34178:4;:12;;;34173:18;;;;;;;34026:177;34683:37;34697:8;34707:12;34683:13;:37::i;:::-;34837:22;;;;;;-1:-1:-1;;;;;34800:24:5;;;;;;:14;:24;;;;;;;;:59;;;34910:11;;34869:38;;;;:52;;;;34946:20;;;;;34931:12;:35;;;35050:22;;35019:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35145:11;;:63;;;-1:-1:-1;;;35145:63:5;;35178:4;35145:63;;;;-1:-1:-1;;;;;35145:63:5;;;;;;;;;;;;;;;:11;;;;;:24;;:63;;;;;:11;;:63;;;;;;;:11;;:63;;;5:2:-1;;;;30:1;27;20:12;5:2;35145:63:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;35231:14:5;;-1:-1:-1;35226:20:5;;-1:-1:-1;;35226:20:5;;35219:27;32282:2971;-1:-1:-1;;;;;32282:2971:5:o;43099:3514::-;43318:11;;:111;;;-1:-1:-1;;;43318:111:5;;43361:4;43318:111;;;;-1:-1:-1;;;;;43318:111:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43237:4;;;;;;43318:11;;;:34;;:111;;;;;;;;;;;;;;;43237:4;43318:11;:111;;;5:2:-1;;;;30:1;27;20:12;5:2;43318:111:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43318:111:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43318:111:5;;-1:-1:-1;43443:12:5;;43439:148;;43479:93;43490:27;43519:43;43564:7;43479:10;:93::i;:::-;43471:105;-1:-1:-1;43574:1:5;;-1:-1:-1;43471:105:5;;-1:-1:-1;43471:105:5;43439:148;43694:16;:14;:16::i;:::-;43672:18;;:38;43668:148;;43734:67;43739:22;43763:37;43734:4;:67::i;43668:148::-;43959:16;:14;:16::i;:::-;43918;-1:-1:-1;;;;;43918:35:5;;:37;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43918:37:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43918:37:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43918:37:5;:57;43914:178;;43999:78;44004:22;44028:48;43999:4;:78::i;43914:178::-;44162:10;-1:-1:-1;;;;;44150:22:5;:8;-1:-1:-1;;;;;44150:22:5;;44146:143;;;44196:78;44201:26;44229:44;44196:4;:78::i;44146:143::-;44341:16;44337:145;;44381:86;44386:36;44424:42;44381:4;:86::i;44337:145::-;-1:-1:-1;;44535:11:5;:23;44531:156;;;44582:90;44587:36;44625:46;44582:4;:90::i;44531:156::-;44739:21;44762:22;44788:51;44805:10;44817:8;44827:11;44788:16;:51::i;:::-;44738:101;;-1:-1:-1;44738:101:5;-1:-1:-1;44853:40:5;;44849:161;;44917:78;44928:16;44922:23;;;;;;;;44947:47;44917:4;:78::i;:::-;44909:90;-1:-1:-1;44997:1:5;;-1:-1:-1;44909:90:5;;-1:-1:-1;;;44909:90:5;44849:161;45260:11;;:102;;;-1:-1:-1;;;45260:102:5;;45310:4;45260:102;;;;-1:-1:-1;;;;;45260:102:5;;;;;;;;;;;;;;;45217:21;;;;45260:11;;;:41;;:102;;;;;;;;;;;;:11;:102;;;5:2:-1;;;;30:1;27;20:12;5:2;45260:102:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;45260:102:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;45260:102:5;;;;;;;;;-1:-1:-1;45260:102:5;-1:-1:-1;45380:40:5;;45372:104;;;;-1:-1:-1;;;45372:104:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45607:11;45567:16;-1:-1:-1;;;;;45567:26:5;;45594:8;45567:36;;;;;;;;;;;;;-1:-1:-1;;;;;45567:36:5;-1:-1:-1;;;;;45567:36:5;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;45567:36:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;45567:36:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;45567:36:5;:51;;45559:88;;;;;-1:-1:-1;;;45559:88:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;45773:15;-1:-1:-1;;;;;45802:42:5;;45839:4;45802:42;45798:250;;;45873:63;45895:4;45902:10;45914:8;45924:11;45873:13;:63::i;:::-;45860:76;;45798:250;;;45980:57;;;-1:-1:-1;;;45980:57:5;;-1:-1:-1;;;;;45980:57:5;;;;;;;;;;;;;;;;;;;;;;:22;;;;;;:57;;;;;;;;;;;;;;;-1:-1:-1;45980:22:5;:57;;;5:2:-1;;;;30:1;27;20:12;5:2;45980:57:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;45980:57:5;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;45980:57:5;;-1:-1:-1;45798:250:5;46151:34;;46143:67;;;;;-1:-1:-1;;;46143:67:5;;;;;;;;;;;;-1:-1:-1;;;46143:67:5;;;;;;;;;;;;;;;46272:96;;;-1:-1:-1;;;;;46272:96:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46418:11;;:129;;;-1:-1:-1;;;46418:129:5;;46460:4;46418:129;;;;-1:-1:-1;;;;;46418:129:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:11;;;;;:33;;:129;;;;;:11;;:129;;;;;;;:11;;:129;;;5:2:-1;;;;30:1;27;20:12;5:2;46418:129:5;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;46571:14:5;;-1:-1:-1;46566:20:5;;-1:-1:-1;;46566:20:5;;46558:48;-1:-1:-1;46588:17:5;;-1:-1:-1;;;;;;43099:3514:5;;;;;;;;:::o;6156:1319:1:-;6299:10;;6341:51;;;-1:-1:-1;;;6341:51:1;;6386:4;6341:51;;;;;;6223:4;;-1:-1:-1;;;;;6299:10:1;;6223:4;;6299:10;;6341:36;;:51;;;;;;;;;;;;;;6299:10;6341:51;;;5:2:-1;;;;30:1;27;20:12;5:2;6341:51:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;6341:51:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6341:51:1;6402:47;;;-1:-1:-1;;;6402:47:1;;-1:-1:-1;;;;;6402:47:1;;;;;;;6435:4;6402:47;;;;;;;;;;;;6341:51;;-1:-1:-1;6402:18:1;;;;;;:47;;;;;-1:-1:-1;;6402:47:1;;;;;;;;-1:-1:-1;6402:18:1;:47;;;5:2:-1;;;;30:1;27;20:12;5:2;6402:47:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;6402:47:1;;;;6460:12;6512:16;6550:1;6545:151;;;;6718:2;6713:217;;;;7064:1;7061;7054:12;6545:151;-1:-1:-1;;6640:6:1;-1:-1:-1;6545:151:1;;6713:217;6815:2;6812:1;6809;6794:24;6856:1;6850:8;6839:19;;6505:579;;7111:7;7103:44;;;;;-1:-1:-1;;;7103:44:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;7257:10;;7242:51;;;-1:-1:-1;;;7242:51:1;;7287:4;7242:51;;;;;;7222:17;;-1:-1:-1;;;;;7257:10:1;;7242:36;;:51;;;;;;;;;;;;;;7257:10;7242:51;;;5:2:-1;;;;30:1;27;20:12;5:2;7242:51:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;7242:51:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7242:51:1;;-1:-1:-1;7311:29:1;;;;7303:68;;;;;-1:-1:-1;;;7303:68:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;7388:28;;;;;6156:1319;-1:-1:-1;;;;;6156:1319:1:o;4528:330:15:-;4616:9;4627:4;4644:13;4659:19;;:::i;:::-;4682:31;4697:6;4705:7;3897:9;3908:10;;:::i;:::-;4205:14;4221;4239:25;447:4;4257:6;4239:7;:25::i;:::-;4204:60;;-1:-1:-1;4204:60:15;-1:-1:-1;4286:18:15;4278:4;:26;;;;;;;;;4274:90;;-1:-1:-1;4334:18:15;;;;;;;;;-1:-1:-1;4334:18:15;;4328:4;;-1:-1:-1;4334:18:15;-1:-1:-1;4320:33:15;;4274:90;4380:35;4387:9;4398:7;:16;;;4380:6;:35::i;166:8889:1:-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;166:8889:1;;;-1:-1:-1;166:8889:1;:::i;:::-;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;166:8889:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;166:8889:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;166:8889:1;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.