Source Code
Overview
GLMR Balance
GLMR Value
$0.00View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Loading...
Loading
Contract Name:
QodaLens
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/IFixedRateMarket.sol";
import "./interfaces/IQodaLens.sol";
import "./interfaces/IQollateralManager.sol";
import "./interfaces/IQAdmin.sol";
import "./interfaces/IQPriceOracle.sol";
import "./libraries/Interest.sol";
import "./libraries/QTypes.sol";
import "./libraries/QTypesPeripheral.sol";
import "./libraries/Utils.sol";
contract QodaLens is Initializable, IQodaLens {
/// @notice Borrow side enum
uint8 private constant _SIDE_BORROW = 0;
/// @notice Lend side enum
uint8 private constant _SIDE_LEND = 1;
/// @notice PV enum
uint8 private constant _TYPE_PV = 0;
/// @notice FV enum
uint8 private constant _TYPE_FV = 1;
/// @notice Internal representation on null pointer for linked lists
uint64 private constant _NULL_POINTER = 0;
/// @notice Reserve storage gap so introduction of new parent class later on can be done via upgrade
uint256[50] __gap;
/// @notice Contract storing all global Qoda parameters
IQAdmin private _qAdmin;
/// @notice 0x0 null address for convenience
address constant NULL = address(0);
/// Note: Design decision: contracts are placed in constructor as Lens is
/// stateless. Lens can be redeployed in case of contract upgrade
function initialize(address qAdminAddress) public initializer {
_qAdmin = IQAdmin(qAdminAddress);
}
/** VIEW FUNCTIONS **/
/// @notice Gets the first N `Quote`s for a given `FixedRateMarket` and
/// `side`, filtering for only if the quoter has the requisite hypothetical
/// collateral ratio and allowance/balance for borrow and lend `Quote`s,
/// respectively.
/// For convenience, this function also returns the associated current
/// collateral ratio and underlying balance of the publisher for the `Quote`.
/// @param market Market to query
/// @param side 0 for borrow `Quote`s, 1 for lend `Quote`s
/// @param n Maximum number of `Quote`s to return
/// @return QTypes.Quote[], uint[] `collateralRatio`s, uint[] underlying balances
function takeNFilteredQuotes(
IFixedRateMarket market,
uint8 side,
uint n
) external view returns(QTypes.Quote[] memory, uint[] memory, uint[] memory) {
// Handle invalid `side` inputs
if(side != _SIDE_BORROW && side != _SIDE_LEND) {
revert("invalid side");
}
// Get QollateralManager for getting collateral ratio
IQollateralManager _qollateralManager = IQollateralManager(_qAdmin.qollateralManager());
// Size of `Quote`s linkedlist may be smaller than requested
n = Math.min(n, market.getNumQuotes(side));
// Initialize empty arrays to return
QTypes.Quote[] memory quotes = new QTypes.Quote[](n);
uint[] memory collateralRatios = new uint[](n);
uint[] memory underlyingBalances = new uint[](n);
// Get the head of the linked list
QTypes.Quote memory currQuote = market.getQuoteHead(side);
uint i = 0;
while(i < n && currQuote.id != _NULL_POINTER) {
// Hack to avoid "stack too deep" error - get necessary values from
// `_takeNFilteredQuotesHelper` function
// values[0] => amountPV
// values[1] => amountFV
// values[2] => hypothetical collateral ratio
// values[3] => protocol fee
// values[4] => underlying token balance
// values[5] => underlying token allowance
uint[] memory values = _takeNFilteredQuotesHelper(market, currQuote);
// Filter out borrow `Quote`s if user's hypothetical collateral ratio is
// less than the `initCollateralRatio` parameter
if(side == _SIDE_BORROW && values[2] < _qollateralManager.initCollateralRatio(currQuote.quoter)) {
currQuote = market.getQuote(side, currQuote.next);
continue;
}
// Filter out lend `Quote`s if user's current allowance or balance is
// less than the size they are lending (plus fees)
if(side == _SIDE_LEND && (values[0] + values[3] > values[5] || values[0] + values[3] > values[4])) {
currQuote = market.getQuote(side, currQuote.next);
continue;
}
// Current `Quote` passes the filter checks. Add data to the arrays
quotes[i] = currQuote;
collateralRatios[i] = _qollateralManager.collateralRatio(currQuote.quoter);
underlyingBalances[i] = values[4];
// Update the counter
i++;
// Go to the next `Quote`
currQuote = market.getQuote(side, currQuote.next);
}
// Correct actual length of dynamic array
assembly {
mstore(quotes, i)
mstore(collateralRatios, i)
mstore(underlyingBalances, i)
}
// Return the array
return (quotes, collateralRatios, underlyingBalances);
}
/// @notice Gets the first N `Quote`s for a given `FixedRateMarket` and `side`.
/// For convenience, this function also returns the associated current
/// collateral ratio and underlying balance of the publisher for the `Quote`.
/// @param market Market to query
/// @param side 0 for borrow `Quote`s, 1 for lend `Quote`s
/// @param n Maximum number of `Quote`s to return
/// @return QTypes.Quote[], uint[] `collateralRatio`s, uint[] underlying balances
function takeNQuotes(
IFixedRateMarket market,
uint8 side,
uint n
) external view returns(QTypes.Quote[] memory, uint[] memory, uint[] memory){
// Handle invalid `side` inputs
if(side != _SIDE_BORROW && side != _SIDE_LEND) {
revert("invalid side");
}
// Size of `Quote`s linkedlist may be smaller than requested
n = Math.min(n, market.getNumQuotes(side));
// Initialize empty arrays to return
QTypes.Quote[] memory quotes = new QTypes.Quote[](n);
uint[] memory collateralRatios = new uint[](n);
uint[] memory underlyingBalances = new uint[](n);
// Get the head of the linked list
QTypes.Quote memory currQuote = market.getQuoteHead(side);
// Get QollateralManager for getting collateral ratio
IQollateralManager _qollateralManager = IQollateralManager(_qAdmin.qollateralManager());
// Populate the arrays using the linkedlist pointers
for(uint i=0; i<n; i++) {
// Populate the `quotes` array
quotes[i] = currQuote;
address quoter = currQuote.quoter;
// Populate the `collateralRatios` array
uint collateralRatio = _qollateralManager.collateralRatio(quoter);
collateralRatios[i] = collateralRatio;
// Populate the `underlyingBalances` array
uint balance = IERC20(market.underlyingToken()).balanceOf(quoter);
underlyingBalances[i] = balance;
// Go to next `Quote`
currQuote = market.getQuote(side, currQuote.next);
}
return (quotes, collateralRatios, underlyingBalances);
}
function _takeMarkets() internal view returns (address[] memory) {
address[] memory assetAddresses = _qAdmin.allAssets();
// Get # markets for market array initialization
uint marketLength = 0;
for (uint i = 0; i < assetAddresses.length; i++) {
QTypes.Asset memory asset = _qAdmin.assets(IERC20(assetAddresses[i]));
marketLength += asset.maturities.length;
}
// Put unexpired markets into array, with length recorded in marketLength
address[] memory marketAddresses = new address[](marketLength);
marketLength = 0;
for (uint i = 0; i < assetAddresses.length; i++) {
IERC20 token = IERC20(assetAddresses[i]);
QTypes.Asset memory asset = _qAdmin.assets(token);
uint[] memory maturities = asset.maturities;
for (uint j = 0; j < maturities.length; j++) {
if (block.timestamp >= maturities[j]) {
continue;
}
address marketAddress = _qAdmin.fixedRateMarkets(token, maturities[j]);
if (!_qAdmin.isMarketEnabled(marketAddress)) {
continue;
}
marketAddresses[marketLength] = marketAddress;
marketLength++;
}
}
// Correct actual length of dynamic array
assembly {
mstore(marketAddresses, marketLength)
}
return marketAddresses;
}
/// @notice Gets all open quotes from all unexpired market for a given account
/// @param account Account for getting all open quotes
/// @return QTypesPeripheral.AccountQuote[] Related quotes for given account
function takeAccountQuotes(address account) external view returns (QTypesPeripheral.AccountQuote[] memory) {
address[] memory marketAddresses = _takeMarkets();
// Get # quotes for quote array initialization
uint quoteLength = 0;
for (uint i = 0; i < marketAddresses.length; i++) {
IFixedRateMarket market = IFixedRateMarket(marketAddresses[i]);
for (uint8 side = 0; side <= 1; side++) {
quoteLength += market.getAccountQuotes(side, account).length;
}
}
// Put quote into array, with length recorded in quoteLength
QTypesPeripheral.AccountQuote[] memory quotes = new QTypesPeripheral.AccountQuote[](quoteLength);
quoteLength = 0;
for (uint i = 0; i < marketAddresses.length; i++) {
IFixedRateMarket market = IFixedRateMarket(marketAddresses[i]);
for (uint8 side = 0; side <= 1; side++) {
uint64[] memory ids = market.getAccountQuotes(side, account);
for (uint j = 0; j < ids.length; j++) {
QTypes.Quote memory quote = market.getQuote(side, ids[j]);
quotes[quoteLength] = QTypesPeripheral.AccountQuote({
market: address(market),
id: ids[j],
side: side,
quoter: quote.quoter,
quoteType: quote.quoteType,
APR: quote.APR,
cashflow: quote.cashflow,
filled: quote.filled
});
quoteLength++;
}
}
}
return quotes;
}
/// @notice Convenience function to convert an array of `Quote` ids to
/// an array of the underlying `Quote` structs
/// @param market Market to query
/// @param side 0 for borrow `Quote`s, 1 for lend `Quote`s
/// @param quoteIds array of `Quote` ids to query
/// @return QTypes.Quote[] Ordered array of `Quote`s corresponding to `Quote` ids
function quoteIdsToQuotes(
IFixedRateMarket market,
uint8 side,
uint64[] calldata quoteIds
) external view returns(QTypes.Quote[] memory){
// Handle invalid `side` inputs
if(side != _SIDE_BORROW && side != _SIDE_LEND) {
revert("invalid side");
}
// Initialize empty `Quote`s array to return
QTypes.Quote[] memory quotes = new QTypes.Quote[](quoteIds.length);
// Populate the array using the `quoteId` pointers
for(uint i=0; i<quoteIds.length; i++) {
quotes[i] = market.getQuote(side, quoteIds[i]);
}
return quotes;
}
/// @notice Get the weighted average estimated APR for a requested market
/// order `size`. The estimated APR is the weighted average of the first N
/// `Quote`s APR until the full `size` is satisfied. The `size` can be in
/// either PV terms or FV terms. This function also returns the confirmed
/// filled amount in the case that the entire list of `Quote`s in the
/// orderbook is smaller than the requested size. It returns default (0,0) if
/// the orderbook is currently empty.
/// @param market Market to query
/// @param account Account to view estimated APR from
/// @param size Size requested by the user. Can be in either PV or FV terms
/// @param side 0 for borrow `Quote`s, 1 for lend `Quote`s
/// @param quoteType 0 for PV, 1 for FV
/// @return uint Estimated APR, scaled by 1e4, uint Confirmed filled size
function getEstimatedAPR(
IFixedRateMarket market,
address account,
uint size,
uint8 side,
uint8 quoteType
) external view returns(uint, uint){
// Handle invalid `side` inputs
if(side != _SIDE_BORROW && side != _SIDE_LEND) {
revert("invalid side");
}
// Handle invalid `quoteType` inputs
if(quoteType != _TYPE_PV && quoteType != _TYPE_FV) {
revert("invalid quote type");
}
// Get the current top of book
QTypes.Quote memory currQuote = market.getQuoteHead(side);
// Store the remaining size to be filled
uint remainingSize = size;
// Store the estimated APR weighted-avg numerator calculation
uint num = 0;
// Store the estimated APR weighted-avg denominator calculation
uint denom = 0;
// Loop until either the full size is satisfied or until the orderbook
// runs out of quotes
while(remainingSize != 0 && currQuote.id != _NULL_POINTER) {
// Ignore self `Quote`s in estimation calculations
if(currQuote.quoter == account) {
currQuote = market.getQuote(side, currQuote.next);
continue;
}
// Get the size of the current `Quote` in the orderbook
uint quoteSize = currQuote.cashflow;
// If the `quoteType` requested by user differs from the `quoteType`
// of the current order, we need to do a FV -> PV conversion
if(quoteType == _TYPE_PV && currQuote.quoteType == _TYPE_FV) {
quoteSize = Interest.FVToPV(
currQuote.APR,
currQuote.cashflow,
block.timestamp,
market.maturity(),
_qAdmin.MANTISSA_BPS()
);
}
// If the `quoteType` requested by user differs from the `quoteType`
// of the current order, we need to do a PV -> FV conversion
if(quoteType == _TYPE_FV && currQuote.quoteType == _TYPE_PV) {
quoteSize = Interest.PVToFV(
currQuote.APR,
currQuote.cashflow,
block.timestamp,
market.maturity(),
_qAdmin.MANTISSA_BPS()
);
}
uint currSize = Math.min(remainingSize, quoteSize);
// Update the running estimated APR weighted-avg numerator calculation
num += currSize * currQuote.APR;
// Update the runniing estimated APR weighted-avg denominator calculation
denom += currSize;
// Subtract the current `Quote` size from the remaining size to be filled
remainingSize = remainingSize - currSize;
// Move on to the next best `Quote`
currQuote = market.getQuote(side, currQuote.next);
}
if(denom == 0) {
// No orders in the orderbook, return default null values
return (0,0);
} else {
// The `estimatedAPR` is the weighted avg of `Quote` APRs by `Quote`
// sizes i.e., `num` divided by `denom`
uint estimatedAPR = num / denom;
return (estimatedAPR, size - remainingSize);
}
}
/// @notice Get an account's maximum available collateral user can withdraw in specified asset.
/// For example, what is the maximum amount of GLMR that an account can withdraw
/// while ensuring their account health continues to be acceptable?
/// Note: This function will return withdrawable amount that user has indeed collateralized, not amount that user can borrow
/// Note: User can only withdraw up to `initCollateralRatio` for their own protection against instant liquidations
/// @param account User account
/// @param withdrawToken Currency of collateral to withdraw
/// @return uint Maximum available collateral user can withdraw in specified asset
function hypotheticalMaxWithdraw(
address account,
address withdrawToken
) external view returns (uint) {
return _hypotheticalMaxWithdraw(account, withdrawToken);
}
/// @notice Get an account's maximum available borrow amount in a specific FixedRateMarket.
/// For example, what is the maximum amount of GLMRJUL22 that an account can borrow
/// while ensuring their account health continues to be acceptable?
/// Note: This function will return 0 if market to borrow is disabled
/// Note: This function will return creditLimit() if maximum amount allowed for one market exceeds creditLimit()
/// Note: User can only borrow up to `initCollateralRatio` for their own protection against instant liquidations
/// @param account User account
/// @param borrowMarket Address of the `FixedRateMarket` market to borrow
/// @return uint Maximum available amount user can borrow (in FV) without breaching `initCollateralRatio`
function hypotheticalMaxBorrowFV(
address account,
IFixedRateMarket borrowMarket
) external view returns (uint) {
IQollateralManager _qollateralManager = IQollateralManager(_qAdmin.qollateralManager());
return _qollateralManager.hypotheticalMaxBorrowFV(account, borrowMarket);
}
/// @notice Get an account's maximum value user can lend in specified market when protocol fee is factored in.
/// @param account User account
/// @param lendMarket Address of the `FixedRateMarket` market to lend
/// @return uint Maximum value user can lend in specified market with protocol fee considered
function hypotheticalMaxLendPV(
address account,
IFixedRateMarket lendMarket
) external view returns (uint) {
IERC20 underlying_ = lendMarket.underlyingToken();
uint balance = underlying_.balanceOf(account);
return lendMarket.hypotheticalMaxLendPV(balance);
}
/// @notice Get an account's minimum collateral to further deposit if user wants to borrow specified amount in a certain market.
/// For example, what is the minimum amount of USDC to deposit so that an account can borrow 100 DEV token from qDEVJUL22
/// while ensuring their account health continues to be acceptable?
/// @param account User account
/// @param collateralToken Currency to collateralize in
/// @param borrowMarket Address of the `FixedRateMarket` market to borrow
/// @param borrowAmountFV Amount to borrow in local ccy
/// @return uint Minimum collateral required to further deposit
function minimumCollateralRequired(
address account,
IERC20 collateralToken,
IFixedRateMarket borrowMarket,
uint borrowAmountFV
) external view returns (uint) {
IQollateralManager _qollateralManager = IQollateralManager(_qAdmin.qollateralManager());
IQPriceOracle _qPriceOracle = IQPriceOracle(_qAdmin.qPriceOracle());
uint initRatio = _qollateralManager.initCollateralRatio(account);
uint virtualCollateralValue = _qollateralManager.virtualCollateralValue(account);
uint virtualBorrowValue = _qollateralManager.hypotheticalVirtualBorrowValue(account, borrowMarket, borrowAmountFV, 0) + 1; // + 1 to avoid rounding problem
uint virtualUSD = Utils.roundUpDiv(initRatio * virtualBorrowValue, _qAdmin.MANTISSA_COLLATERAL_RATIO()) - virtualCollateralValue;
require(virtualUSD <= _qAdmin.creditLimit(account), "QodaLens: permitted amount exceeded for borrower");
uint realUSD = Utils.roundUpDiv(virtualUSD * _qAdmin.MANTISSA_FACTORS(), _qAdmin.collateralFactor(collateralToken));
uint realLocal = _qPriceOracle.USDToLocal(collateralToken, realUSD) + 1; // + 1 to avoid rounding problem
return realLocal;
}
function getAllMarketsByAsset(IERC20 token) public view returns (IFixedRateMarket[] memory) {
QTypes.Asset memory asset = _qAdmin.assets(token);
IFixedRateMarket[] memory fixedRateMarkets = new IFixedRateMarket[](asset.maturities.length);
for (uint i = 0; i < asset.maturities.length; i++) {
fixedRateMarkets[i] = IFixedRateMarket(_qAdmin.fixedRateMarkets(token, asset.maturities[i]));
}
return fixedRateMarkets;
}
function totalLoansTradedByMarket(IFixedRateMarket market) public view returns (uint) {
return totalUnredeemedLendsByMarket(market) + totalRedeemedLendsByMarket(market);
}
function totalRedeemedLendsByMarket(IFixedRateMarket market) public view returns (uint) {
return market.tokensRedeemedTotal();
}
function totalUnredeemedLendsByMarket(IFixedRateMarket market) public view returns (uint) {
return market.totalSupply();
}
function totalRepaidBorrowsByMarket(IFixedRateMarket market) public view returns (uint) {
IERC20 token = market.underlyingToken();
return token.balanceOf(address(market));
}
function totalUnrepaidBorrowsByMarket(IFixedRateMarket market) public view returns (uint) {
return totalLoansTradedByMarket(market) - totalRepaidBorrowsByMarket(market);
}
function totalLoansTradedByAsset(IERC20 token) public view returns (uint) {
IFixedRateMarket[] memory fixedRateMarkets = getAllMarketsByAsset(token);
uint totalLoansTraded = 0;
for (uint i = 0; i < fixedRateMarkets.length; i++) {
totalLoansTraded += totalLoansTradedByMarket(fixedRateMarkets[i]);
}
return totalLoansTraded;
}
function totalRedeemedLendsByAsset(IERC20 token) public view returns (uint) {
IFixedRateMarket[] memory fixedRateMarkets = getAllMarketsByAsset(token);
uint totalRedeemedLends = 0;
for (uint i = 0; i < fixedRateMarkets.length; i++) {
totalRedeemedLends += totalRedeemedLendsByMarket(fixedRateMarkets[i]);
}
return totalRedeemedLends;
}
function totalUnredeemedLendsByAsset(IERC20 token) public view returns (uint) {
return totalLoansTradedByAsset(token) - totalRedeemedLendsByAsset(token);
}
function totalRepaidBorrowsByAsset(IERC20 token) public view returns (uint) {
IFixedRateMarket[] memory fixedRateMarkets = getAllMarketsByAsset(token);
uint totalRepaidBorrows = 0;
for (uint i = 0; i < fixedRateMarkets.length; i++) {
totalRepaidBorrows += totalRepaidBorrowsByMarket(fixedRateMarkets[i]);
}
return totalRepaidBorrows;
}
function totalUnrepaidBorrowsByAsset(IERC20 token) public view returns (uint) {
return totalLoansTradedByAsset(token) - totalRepaidBorrowsByAsset(token);
}
function totalLoansTradedInUSD() public view returns (uint) {
IQPriceOracle _qPriceOracle = IQPriceOracle(_qAdmin.qPriceOracle());
address[] memory assets = _qAdmin.allAssets();
uint loansTradedUSD = 0;
for (uint i = 0; i < assets.length; i++) {
IERC20 asset = IERC20(assets[i]);
uint loansTradedByAsset = totalLoansTradedByAsset(asset);
loansTradedUSD += _qPriceOracle.localToUSD(asset, loansTradedByAsset);
}
return loansTradedUSD;
}
function totalRedeemedLendsInUSD() public view returns (uint) {
IQPriceOracle _qPriceOracle = IQPriceOracle(_qAdmin.qPriceOracle());
address[] memory assets = _qAdmin.allAssets();
uint redeemedLendsUSD = 0;
for (uint i = 0; i < assets.length; i++) {
IERC20 asset = IERC20(assets[i]);
uint redeemedLendsByAsset = totalRedeemedLendsByAsset(asset);
redeemedLendsUSD += _qPriceOracle.localToUSD(asset, redeemedLendsByAsset);
}
return redeemedLendsUSD;
}
function totalUnredeemedLendsInUSD() public view returns (uint) {
return totalLoansTradedInUSD() - totalRedeemedLendsInUSD();
}
function totalRepaidBorrowsInUSD() public view returns (uint) {
IQPriceOracle _qPriceOracle = IQPriceOracle(_qAdmin.qPriceOracle());
address[] memory assets = _qAdmin.allAssets();
uint repaidBorrows = 0;
for (uint i = 0; i < assets.length; i++) {
IERC20 asset = IERC20(assets[i]);
uint repaidBorrowsByAsset = totalRepaidBorrowsByAsset(asset);
repaidBorrows += _qPriceOracle.localToUSD(asset, repaidBorrowsByAsset);
}
return repaidBorrows;
}
function totalUnrepaidBorrowsInUSD() public view returns (uint) {
return totalLoansTradedInUSD() - totalRepaidBorrowsInUSD();
}
/// @notice Get the address of the `QollateralManager` contract
/// @return address Address of `QollateralManager` contract
function qollateralManager() external view returns(address){
return _qAdmin.qollateralManager();
}
/// @notice Get the address of the `QAdmin` contract
/// @return address Address of `QAdmin` contract
function qAdmin() external view returns(address){
return address(_qAdmin);
}
/// @notice Get the address of the `QPriceOracle` contract
/// @return address Address of `QPriceOracle` contract
function qPriceOracle() external view returns(address){
return _qAdmin.qPriceOracle();
}
/** INTERNAL FUNCTIONS **/
/// @notice Get an account's maximum available collateral user can withdraw in specified asset.
/// For example, what is the maximum amount of GLMR that an account can withdraw
/// while ensuring their account health continues to be acceptable?
/// Note: This function will return withdrawable amount that user has indeed collateralized, not amount that user can borrow
/// Note: User can only withdraw up to `initCollateralRatio` for their own protection against instant liquidations
/// @param account User account
/// @param withdrawToken Currency of collateral to withdraw
/// @return uint Maximum available collateral user can withdraw in specified asset
function _hypotheticalMaxWithdraw(
address account,
address withdrawToken
) internal view returns(uint) {
IQollateralManager _qollateralManager = IQollateralManager(_qAdmin.qollateralManager());
IQPriceOracle _qPriceOracle = IQPriceOracle(_qAdmin.qPriceOracle());
IERC20 withdrawERC20 = IERC20(withdrawToken);
QTypes.Asset memory asset = _qAdmin.assets(withdrawERC20);
uint currentRatio = _qollateralManager.collateralRatio(account);
uint minRatio = _qAdmin.initCollateralRatio(account);
uint collateralBalance = _qollateralManager.collateralBalance(account, withdrawERC20);
if (collateralBalance == 0 || currentRatio <= minRatio) {
return 0;
}
if (currentRatio >= _qAdmin.UINT_MAX()) {
return collateralBalance;
}
uint virtualBorrow = _qollateralManager.virtualBorrowValue(account);
uint virtualUSD = virtualBorrow * (currentRatio - minRatio) / _qAdmin.MANTISSA_COLLATERAL_RATIO();
uint realUSD = virtualUSD * _qAdmin.MANTISSA_FACTORS() / asset.collateralFactor;
uint valueLocal = _qPriceOracle.USDToLocal(withdrawERC20, realUSD);
return valueLocal <= collateralBalance ? valueLocal : collateralBalance;
}
/// @notice This is a hacky helper function that helps to avoid the
/// "stack too deep" compile error.
/// @param market Market to query
/// @param quote Quote to query
/// @return uint[] [amountPV, amountFV, hcr, fee, balance, allowance]
function _takeNFilteredQuotesHelper(
IFixedRateMarket market,
QTypes.Quote memory quote
) internal view returns(uint[] memory) {
// Get the PV of the remaining amount in the `Quote`
uint amountPV = market.getPV(
quote.quoteType,
quote.APR,
quote.cashflow - quote.filled,
block.timestamp,
market.maturity()
);
// Get the FV of the remaining amount in the `Quote`
uint amountFV = market.getFV(
quote.quoteType,
quote.APR,
quote.cashflow - quote.filled,
block.timestamp,
market.maturity()
);
// Get QollateralManager for hypothetical collateral ratio
IQollateralManager _qollateralManager = IQollateralManager(_qAdmin.qollateralManager());
// Get the user's hypothetical collateral ratio after `Quote` fill
uint hcr = _qollateralManager.hypotheticalCollateralRatio(
quote.quoter,
market.underlyingToken(),
0,
0,
market,
amountFV,
0
);
// Get the fee and user's current balance and allowance
uint fee = market.proratedProtocolFee(amountPV, block.timestamp);
uint balance = IERC20(market.underlyingToken()).balanceOf(quote.quoter);
uint allowance = IERC20(market.underlyingToken()).allowance(quote.quoter, address(market));
uint[] memory values = new uint[](6);
values[0] = amountPV;
values[1] = amountFV;
values[2] = hcr;
values[3] = fee;
values[4] = balance;
values[5] = allowance;
return values;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`.
// We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
// This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
// Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
// good first aproximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1;
uint256 x = a;
if (x >> 128 > 0) {
x >>= 128;
result <<= 64;
}
if (x >> 64 > 0) {
x >>= 64;
result <<= 32;
}
if (x >> 32 > 0) {
x >>= 32;
result <<= 16;
}
if (x >> 16 > 0) {
x >>= 16;
result <<= 8;
}
if (x >> 8 > 0) {
x >>= 8;
result <<= 4;
}
if (x >> 4 > 0) {
x >>= 4;
result <<= 2;
}
if (x >> 2 > 0) {
result <<= 1;
}
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
uint256 result = sqrt(a);
if (rounding == Rounding.Up && result * result < a) {
result += 1;
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/QTypes.sol";
interface IFixedRateMarket is IERC20Upgradeable, IERC20MetadataUpgradeable {
/// @notice Emitted when market order is created and loan can be created with one or more quotes
event ExecMarketOrder(
uint8 indexed quoteSide,
address indexed account,
uint totalExecutedPV,
uint totalExecutedFV
);
/// @notice Emitted when a borrower repays borrow.
/// Boolean flag `withQTokens`= true if repaid via qTokens, false otherwise.
event RepayBorrow(address indexed borrower, uint amount, bool withQTokens);
/// @notice Emitted when a borrower is liquidated
event LiquidateBorrow(
address indexed borrower,
address indexed liquidator,
uint amount,
address collateralTokenAddr,
uint reward
);
/// @notice Emitted when a borrower and lender are matched for a fixed rate loan
event FixedRateLoan(
uint8 indexed quoteSide,
address indexed borrower,
address indexed lender,
uint amountPV,
uint amountFV,
uint feeIncurred,
uint64 APR
);
/// @notice Emitted when an account redeems their qTokens
event RedeemQTokens(address indexed account, uint amount);
/// @notice Emitted when setting `_quoteManager`
event SetQuoteManager(address quoteManagerAddress);
/** ADMIN FUNCTIONS **/
/// @notice Call upon initialization after deploying `QuoteManager` contract
/// @param quoteManagerAddress Address of `QuoteManager` deployment
function _setQuoteManager(address quoteManagerAddress) external;
/** USER INTERFACE **/
/// @notice Creates a new `Quote` and adds it to the `OrderbookSide` linked list by side
/// @param side 0 for borrow `Quote`, 1 for lend `Quote`
/// @param quoteType 0 for PV+APR, 1 for FV+APR
/// @param APR In decimal form scaled by 1e4 (ex. 1052 = 10.52%)
/// @param cashflow Can be PV or FV depending on `quoteType`
function createQuote(uint8 side, uint8 quoteType, uint64 APR, uint cashflow) external;
/// @notice Analogue of market order to borrow against current lend `Quote`s.
/// Only fills at most up to `amountPV`, any unfilled amount is discarded.
/// @param amountPV The maximum amount to borrow
/// @param maxAPR Only accept `Quote`s up to specified APR. You may think of
/// this as a maximum slippage tolerance variable
function borrow(uint amountPV, uint64 maxAPR) external;
/// @notice Analogue of market order to borrow against current lend `Quote`s.
/// Only fills at most up to `amountPV`, any unfilled amount is discarded.
/// ETH will be sent to borrower
/// @param amountPV The maximum amount to borrow
/// @param maxAPR Only accept `Quote`s up to specified APR. You may think of
/// this as a maximum slippage tolerance variable
function borrowETH(uint amountPV, uint64 maxAPR) external;
/// @notice Analogue of market order to lend against current borrow `Quote`s.
/// Only fills at most up to `amountPV`, any unfilled amount is discarded.
/// @param amountPV The maximum amount to lend
/// @param minAPR Only accept `Quote`s up to specified APR. You may think of
/// this as a maximum slippage tolerance variable
function lend(uint amountPV, uint64 minAPR) external;
/// @notice Analogue of market order to lend against current borrow `Quote`s.
/// Only fills at most up to `msg.value`, any unfilled amount is discarded.
/// Excessive amount will be sent back to lender
/// Note that protocol fee should also be included as ETH sent in the function call
/// @param minAPR Only accept `Quote`s up to specified APR. You may think of
/// this as a maximum slippage tolerance variable
function lendETH(uint64 minAPR) external payable;
/// @notice Borrower will make repayments to the smart contract, which
/// holds the value in escrow until maturity to release to lenders.
/// @param amount Amount to repay
/// @return uint Remaining account borrow amount
function repayBorrow(uint amount) external returns(uint);
/// @notice Borrower will make repayments to the smart contract using ETH, which
/// holds the value in escrow until maturity to release to lenders.
/// @return uint Remaining account borrow amount
function repayBorrowWithETH() external payable returns(uint);
/// @notice Cancel `Quote` by id. Note this is a O(1) operation
/// since `OrderbookSide` uses hashmaps under the hood. However, it is
/// O(n) against the array of `Quote` ids by account so we should ensure
/// that array should not grow too large in practice.
/// @param side 0 for borrow `Quote`, 1 for lend `Quote`
/// @param id Id of the `Quote`
function cancelQuote(uint8 side, uint64 id) external;
/// @notice This function allows net lenders to redeem qTokens for the
/// underlying token. Redemptions may only be permitted after loan maturity
/// plus `_maturityGracePeriod`. The public interface redeems specified amount
/// of qToken from existing balance.
/// @param amount Amount of qTokens to redeem
/// @return uint Amount of qTokens redeemed
function redeemQTokensByRatio(uint amount) external returns(uint);
/// @notice This function allows net lenders to redeem qTokens for the
/// underlying token. Redemptions may only be permitted after loan maturity
/// plus `_maturityGracePeriod`. The public interface redeems the entire qToken
/// balance.
/// @return uint Amount of qTokens redeemed
function redeemAllQTokensByRatio() external returns(uint);
/// @notice This function allows net lenders to redeem qTokens for ETH.
/// Redemptions may only be permitted after loan maturity plus
/// `_maturityGracePeriod`. The public interface redeems specified amount
/// of qToken from existing balance.
/// @param amount Amount of qTokens to redeem
/// @return uint Amount of qTokens redeemed
function redeemQTokensByRatioWithETH(uint amount) external returns(uint);
/// @notice This function allows net lenders to redeem qTokens for ETH.
/// Redemptions may only be permitted after loan maturity plus
/// `_maturityGracePeriod`. The public interface redeems the entire qToken
/// balance.
/// @return uint Amount of qTokens redeemed
function redeemAllQTokensByRatioWithETH() external returns(uint);
/// @notice If an account is in danger of being underwater (i.e. collateralRatio < 1.0)
/// or has not repaid past maturity plus `_repaymentGracePeriod`, any user may
/// liquidate that account by paying back the loan on behalf of the account. In return,
/// the liquidator receives collateral belonging to the account equal in value to
/// the repayment amount in USD plus the liquidation incentive amount as a bonus.
/// @param borrower Address of account to liquidate
/// @param amount Amount to repay on behalf of account in the currency of the loan
/// @param collateralToken Liquidator's choice of which currency to be paid in
function liquidateBorrow(address borrower, uint amount, IERC20 collateralToken) external;
/** VIEW FUNCTIONS **/
/// @notice Get the address of the `QAdmin`
/// @return address
function qAdmin() external view returns(address);
/// @notice Get the address of the `QollateralManager`
/// @return address
function qollateralManager() external view returns(address);
/// @notice Get the address of the `QuoteManager`
/// @return address
function quoteManager() external view returns(address);
/// @notice Get the address of the ERC20 token which the loan will be denominated
/// @return IERC20
function underlyingToken() external view returns(IERC20);
/// @notice Get the UNIX timestamp (in seconds) when the market matures
/// @return uint
function maturity() external view returns(uint);
/// @notice Get the minimum quote size for this market
/// @return uint Minimum quote size, in PV terms, local currency
function minQuoteSize() external view returns(uint);
/// @notice Get the total balance of borrows by user
/// @param account Account to query
/// @return uint Borrows
function accountBorrows(address account) external view returns(uint);
/// @notice Get the linked list pointer top of book for `Quote` by side
/// @param side 0 for borrow `Quote`, 1 for lend `Quote`
/// @return uint64 id of top of book `Quote`
function getQuoteHeadId(uint8 side) external view returns(uint64);
/// @notice Get the top of book for `Quote` by side
/// @param side 0 for borrow `Quote`, 1 for lend `Quote`
/// @return QTypes.Quote head `Quote`
function getQuoteHead(uint8 side) external view returns(QTypes.Quote memory);
/// @notice Get the `Quote` for the given `side` and `id`
/// @param side 0 for borrow `Quote`, 1 for lend `Quote`
/// @param id Id of `Quote`
/// @return QTypes.Quote `Quote` associated with the id
function getQuote(uint8 side, uint64 id) external view returns(QTypes.Quote memory);
/// @notice Get all live `Quote` id's by `account` and `side`
/// @param side 0 for borrow `Quote`, 1 for lend `Quote`
/// @param account Account to query
/// @return uint[] Unsorted array of borrow `Quote` id's
function getAccountQuotes(uint8 side, address account) external view returns(uint64[] memory);
/// @notice Get the number of active `Quote`s by `side` in the orderbook
/// @param side 0 for borrow `Quote`, 1 for lend `Quote`
/// @return uint Number of `Quote`s
function getNumQuotes(uint8 side) external view returns(uint);
/// @notice Gets the `protocolFee` associated with this market
/// @return uint annualized protocol fee, scaled by 1e4
function protocolFee() external view returns(uint);
/// @notice Gets the `protocolFee` associated with this market, prorated by time till maturity
/// @param amount loan amount
/// @return uint prorated protocol fee in local currency
function proratedProtocolFee(uint amount) external view returns(uint);
/// @notice Gets the `protocolFee` associated with this market, prorated by time till maturity
/// @param amount loan amount
/// @param timestamp UNIX timestamp in seconds
/// @return uint prorated protocol fee in local currency
function proratedProtocolFee(uint amount, uint timestamp) external view returns(uint);
/// @notice Get amount of qTokens user can redeem based on current loan repayment ratio
/// @return uint amount of qTokens user can redeem
function redeemableQTokens() external view returns(uint);
/// @notice Get amount of qTokens user can redeem based on current loan repayment ratio
/// @param account Account to query
/// @return uint amount of qTokens user can redeem
function redeemableQTokens(address account) external view returns(uint);
/// @notice Gets the current `redemptionRatio` where owned qTokens can be redeemed up to
/// @return uint redemption ratio, capped and scaled by 1e18
function redemptionRatio() external view returns(uint);
/// @notice Tokens redeemed across all users so far
function tokensRedeemedTotal() external view returns(uint);
/// @notice Get total protocol fee accrued in this market so far, in local currency
/// @return uint accrued fee
function totalAccruedFees() external view returns(uint);
/// @notice Get the PV of a cashflow amount based on the `quoteType`
/// @param quoteType 0 for PV, 1 for FV
/// @param APR In decimal form scaled by 1e4 (ex. 10.52% = 1052)
/// @param sTime PV start time
/// @param eTime FV end time
/// @param amount Value to be PV'ed
/// @return uint PV of the `amount`
function getPV(
uint8 quoteType,
uint64 APR,
uint amount,
uint sTime,
uint eTime
) external view returns(uint);
/// @notice Get the FV of a cashflow amount based on the `quoteType`
/// @param quoteType 0 for PV, 1 for FV
/// @param APR In decimal form scaled by 1e4 (ex. 10.52% = 1052)
/// @param sTime PV start time
/// @param eTime FV end time
/// @param amount Value to be FV'ed
/// @return uint FV of the `amount`
function getFV(
uint8 quoteType,
uint64 APR,
uint amount,
uint sTime,
uint eTime
) external view returns(uint);
/// @notice Get maximum value user can lend with given amount when protocol fee is factored in.
/// Mantissa is added to reduce precision error during calculation
/// @param amount Lending amount with protocol fee factored in
/// @return uint Maximum value user can lend with protocol fee considered
function hypotheticalMaxLendPV(uint amount) external view returns (uint);
}//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "../libraries/QTypes.sol";
import "../libraries/QTypesPeripheral.sol";
import "./IFixedRateMarket.sol";
interface IQodaLens {
/// @notice Gets the first N `Quote`s for a given `FixedRateMarket` and
/// `side`, filtering for only if the quoter has the requisite hypothetical
/// collateral ratio and allowance/balance for borrow and lend `Quote`s,
/// respectively.
/// For convenience, this function also returns the associated current
/// collateral ratio and underlying balance of the publisher for the `Quote`.
/// @param market Market to query
/// @param side 0 for borrow `Quote`s, 1 for lend `Quote`s
/// @param n Maximum number of `Quote`s to return
/// @return QTypes.Quote[], uint[] `collateralRatio`s, uint[] underlying balances
function takeNFilteredQuotes(
IFixedRateMarket market,
uint8 side,
uint n
) external view returns(QTypes.Quote[] memory, uint[] memory, uint[] memory);
/// @notice Gets the first N `Quote`s for a given `FixedRateMarket` and `side`.
/// For convenience, this function also returns the associated current
/// collateral ratio and underlying balance of the publisher for the `Quote`.
/// @param market Market to query
/// @param side 0 for borrow `Quote`s, 1 for lend `Quote`s
/// @param n Maximum number of `Quote`s to return
/// @return QTypes.Quote[], uint[] `collateralRatio`s, uint[] underlying balances
function takeNQuotes(
IFixedRateMarket market,
uint8 side,
uint n
) external view returns(QTypes.Quote[] memory, uint[] memory, uint[] memory);
/// @notice Gets all open quotes from all unexpired market for a given account
/// @param account Account for getting all open quotes
/// @return QTypesPeripheral.AccountQuote[] Related quotes for given account
function takeAccountQuotes(address account) external view returns (QTypesPeripheral.AccountQuote[] memory);
/// @notice Convenience function to convert an array of `Quote` ids to
/// an array of the underlying `Quote` structs
/// @param market Market to query
/// @param side 0 for borrow `Quote`s, 1 for lend `Quote`s
/// @param quoteIds array of `Quote` ids to query
/// @return QTypes.Quote[] Ordered array of `Quote`s corresponding to `Quote` ids
function quoteIdsToQuotes(
IFixedRateMarket market,
uint8 side,
uint64[] calldata quoteIds
) external view returns(QTypes.Quote[] memory);
/// @notice Get the weighted average estimated APR for a requested market
/// order `size`. The estimated APR is the weighted average of the first N
/// `Quote`s APR until the full `size` is satisfied. The `size` can be in
/// either PV terms or FV terms. This function also returns the confirmed
/// filled amount in the case that the entire list of `Quote`s in the
/// orderbook is smaller than the requested size. It returns default (0,0) if
/// the orderbook is currently empty.
/// @param market Market to query
/// @param account Account to view estimated APR from
/// @param size Size requested by the user. Can be in either PV or FV terms
/// @param side 0 for borrow `Quote`s, 1 for lend `Quote`s
/// @param quoteType 0 for PV, 1 for FV
/// @return uint Estimated APR, scaled by 1e4, uint Confirmed filled size
function getEstimatedAPR(
IFixedRateMarket market,
address account,
uint size,
uint8 side,
uint8 quoteType
) external view returns(uint, uint);
/// @notice Get an account's maximum available collateral user can withdraw in specified asset.
/// For example, what is the maximum amount of GLMR that an account can withdraw
/// while ensuring their account health continues to be acceptable?
/// Note: This function will return withdrawable amount that user has indeed collateralized, not amount that user can borrow
/// Note: User can only withdraw up to `initCollateralRatio` for their own protection against instant liquidations
/// Note: Design decision: asset-enabled check not done as collateral can be disabled after
/// @param account User account
/// @param withdrawToken Currency of collateral to withdraw
/// @return uint Maximum available collateral user can withdraw in specified asset
function hypotheticalMaxWithdraw(address account, address withdrawToken) external view returns (uint);
/// @notice Get an account's maximum available borrow amount in a specific FixedRateMarket.
/// For example, what is the maximum amount of GLMRJUL22 that an account can borrow
/// while ensuring their account health continues to be acceptable?
/// Note: This function will return 0 if market to borrow is disabled
/// Note: This function will return creditLimit() if maximum amount allowed for one market exceeds creditLimit()
/// Note: User can only borrow up to `initCollateralRatio` for their own protection against instant liquidations
/// @param account User account
/// @param borrowMarket Address of the `FixedRateMarket` market to borrow
/// @return uint Maximum available amount user can borrow (in FV) without breaching `initCollateralRatio`
function hypotheticalMaxBorrowFV(address account, IFixedRateMarket borrowMarket) external view returns (uint);
/// @notice Get an account's maximum value user can lend in specified market when protocol fee is factored in.
/// @param account User account
/// @param lendMarket Address of the `FixedRateMarket` market to lend
/// @return uint Maximum value user can lend in specified market with protocol fee considered
function hypotheticalMaxLendPV(address account, IFixedRateMarket lendMarket) external view returns (uint);
/// @notice Get an account's minimum collateral to further deposit if user wants to borrow specified amount in a certain market.
/// For example, what is the minimum amount of USDC to deposit so that an account can borrow 100 DEV token from qDEVJUL22
/// while ensuring their account health continues to be acceptable?
/// @param account User account
/// @param collateralToken Currency to collateralize in
/// @param borrowMarket Address of the `FixedRateMarket` market to borrow
/// @param borrowAmount Amount to borrow in local ccy
/// @return uint Minimum collateral required to further deposit
function minimumCollateralRequired(
address account,
IERC20 collateralToken,
IFixedRateMarket borrowMarket,
uint borrowAmount
) external view returns (uint);
function getAllMarketsByAsset(IERC20 token) external view returns (IFixedRateMarket[] memory);
function totalLoansTradedByMarket(IFixedRateMarket market) external view returns (uint);
function totalRedeemedLendsByMarket(IFixedRateMarket market) external view returns (uint);
function totalUnredeemedLendsByMarket(IFixedRateMarket market) external view returns (uint);
function totalRepaidBorrowsByMarket(IFixedRateMarket market) external view returns (uint);
function totalUnrepaidBorrowsByMarket(IFixedRateMarket market) external view returns (uint);
function totalLoansTradedByAsset(IERC20 token) external view returns (uint);
function totalRedeemedLendsByAsset(IERC20 token) external view returns (uint);
function totalUnredeemedLendsByAsset(IERC20 token) external view returns (uint);
function totalRepaidBorrowsByAsset(IERC20 token) external view returns (uint);
function totalUnrepaidBorrowsByAsset(IERC20 token) external view returns (uint);
function totalLoansTradedInUSD() external view returns (uint);
function totalRedeemedLendsInUSD() external view returns (uint);
function totalUnredeemedLendsInUSD() external view returns (uint);
function totalRepaidBorrowsInUSD() external view returns (uint);
function totalUnrepaidBorrowsInUSD() external view returns (uint);
/// @notice Get the address of the `QollateralManager` contract
/// @return address Address of `QollateralManager` contract
function qollateralManager() external view returns(address);
/// @notice Get the address of the `QAdmin` contract
/// @return address Address of `QAdmin` contract
function qAdmin() external view returns(address);
/// @notice Get the address of the `QPriceOracle` contract
/// @return address Address of `QPriceOracle` contract
function qPriceOracle() external view returns(address);
}//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IFixedRateMarket.sol";
interface IQollateralManager {
/// @notice Emitted when an account deposits collateral into the contract
event DepositCollateral(address indexed account, address tokenAddress, uint amount);
/// @notice Emitted when an account withdraws collateral from the contract
event WithdrawCollateral(address indexed account, address tokenAddress, uint amount);
/// @notice Emitted when an account first interacts with the `Market`
event AddAccountMarket(address indexed account, address indexed market);
/// @notice Emitted when collateral is transferred from one account to another
event TransferCollateral(address indexed tokenAddress, address indexed from, address indexed to, uint amount);
/// @notice Constructor for upgradeable contracts
/// @param qAdminAddress_ Address of the `QAdmin` contract
/// @param qPriceOracleAddress_ Address of the `QPriceOracle` contract
function initialize(address qAdminAddress_, address qPriceOracleAddress_) external;
/** ADMIN/RESTRICTED FUNCTIONS **/
/// @notice Record when an account has either borrowed or lent into a
/// `FixedRateMarket`. This is necessary because we need to iterate
/// across all markets that an account has borrowed/lent to to calculate their
/// `borrowValue`. Only the `FixedRateMarket` contract itself may call
/// this function
/// @param account User account
/// @param market Address of the `FixedRateMarket` market
function _addAccountMarket(address account, IFixedRateMarket market) external;
/// @notice Transfer collateral balances from one account to another. Only
/// `FixedRateMarket` contracts can call this restricted function. This is used
/// for when a liquidator liquidates an account.
/// @param token ERC20 token
/// @param from Sender address
/// @param to Recipient address
/// @param amount Amount to transfer
function _transferCollateral(IERC20 token, address from, address to, uint amount) external;
/** USER INTERFACE **/
/// @notice Users call this to deposit collateral to fund their borrows
/// @param token ERC20 token
/// @param amount Amount to deposit (in local ccy)
/// @return uint New collateral balance
function depositCollateral(IERC20 token, uint amount) external returns(uint);
/// @notice Users call this to deposit collateral to fund their borrows, where their
/// collateral is automatically wrapped into MTokens for convenience so users can
/// automatically earn interest on their collateral.
/// @param underlying Underlying ERC20 token
/// @param amount Amount to deposit (in underlying local currency)
/// @return uint New collateral balance (in MToken balance)
function depositCollateralWithMTokenWrap(IERC20 underlying, uint amount) external returns(uint);
/// @notice Users call this to deposit collateral to fund their borrows, where their
/// collateral is automatically wrapped from ETH to WETH.
/// @return uint New collateral balance (in WETH balance)
function depositCollateralWithETH() external payable returns(uint);
/// @notice Users call this to deposit collateral to fund their borrows, where their
/// collateral is automatically wrapped from ETH into MTokens for convenience so users can
/// automatically earn interest on their collateral.
/// @return uint New collateral balance (in MToken balance)
function depositCollateralWithMTokenWrapWithETH() external payable returns(uint);
/// @notice Users call this to withdraw collateral
/// @param token ERC20 token
/// @param amount Amount to withdraw (in local ccy)
/// @return uint New collateral balance
function withdrawCollateral(IERC20 token, uint amount) external returns(uint);
/// @notice Users call this to withdraw mToken collateral, where their
/// collateral is automatically unwrapped into underlying tokens for
/// convenience.
/// @param mTokenAddress Yield-bearing token address
/// @param amount Amount to withdraw (in mToken local currency)
/// @return uint New collateral balance (in MToken balance)
function withdrawCollateralWithMTokenUnwrap(
address mTokenAddress,
uint amount
) external returns(uint);
/// @notice Users call this to withdraw ETH collateral, where their
/// collateral is automatically unwrapped from WETH for convenience.
/// @param amount Amount to withdraw (in WETH local currency)
/// @return uint New collateral balance (in WETH balance)
function withdrawCollateralWithETH(uint amount) external returns(uint);
/// @notice Users call this to withdraw mToken collateral, where their
/// collateral is automatically unwrapped into ETH for convenience.
/// @param amount Amount to withdraw (in WETH local currency)
/// @return uint New collateral balance (in MToken balance)
function withdrawCollateralWithMTokenWrapWithETH(uint amount) external returns(uint);
/** VIEW FUNCTIONS **/
/// @notice Get the address of the `QAdmin` contract
/// @return address Address of `QAdmin` contract
function qAdmin() external view returns(address);
/// @notice Get the address of the `QPriceOracle` contract
/// @return address Address of `QPriceOracle` contract
function qPriceOracle() external view returns(address);
/// @notice Get all enabled `Asset`s
/// @return address[] iterable list of enabled `Asset`s
function allAssets() external view returns(address[] memory);
/// @notice Gets the `CollateralFactor` associated with a ERC20 token
/// @param token ERC20 token
/// @return uint Collateral Factor, scaled by 1e8
function collateralFactor(IERC20 token) external view returns(uint);
/// @notice Gets the `MarketFactor` associated with a ERC20 token
/// @param token ERC20 token
/// @return uint Market Factor, scaled by 1e8
function marketFactor(IERC20 token) external view returns(uint);
/// @notice Return what the collateral ratio for an account would be
/// with a hypothetical collateral withdraw/deposit and/or token borrow/lend.
/// The collateral ratio is calculated as:
/// (`virtualCollateralValue` / `virtualBorrowValue`)
/// If the returned value falls below 1e8, the account can be liquidated
/// @param account User account
/// @param hypotheticalToken Currency of hypothetical withdraw / deposit
/// @param withdrawAmount Amount of hypothetical withdraw in local currency
/// @param depositAmount Amount of hypothetical deposit in local currency
/// @param hypotheticalMarket Market of hypothetical borrow
/// @param borrowAmount Amount of hypothetical borrow in local ccy
/// @param lendAmount Amount of hypothetical lend in local ccy
/// @return uint Hypothetical collateral ratio
function hypotheticalCollateralRatio(
address account,
IERC20 hypotheticalToken,
uint withdrawAmount,
uint depositAmount,
IFixedRateMarket hypotheticalMarket,
uint borrowAmount,
uint lendAmount
) external view returns(uint);
/// @notice Return the current collateral ratio for an account.
/// The collateral ratio is calculated as:
/// (`virtualCollateralValue` / `virtualBorrowValue`)
/// If the returned value falls below 1e8, the account can be liquidated
/// @param account User account
/// @return uint Collateral ratio
function collateralRatio(address account) external view returns(uint);
/// @notice Get the `collateralFactor` weighted value (in USD) of all the
/// collateral deposited for an account
/// @param account Account to query
/// @return uint Total value of account in USD, scaled to 1e18
function virtualCollateralValue(address account) external view returns(uint);
/// @notice Get the `collateralFactor` weighted value (in USD) for the tokens
/// deposited for an account
/// @param account Account to query
/// @param token ERC20 token
/// @return uint Value of token collateral of account in USD, scaled to 1e18
function virtualCollateralValueByToken(
address account,
IERC20 token
) external view returns(uint);
/// @notice Get the `marketFactor` weighted net borrows (i.e. borrows - lends)
/// in USD summed across all `Market`s participated in by the user
/// @param account Account to query
/// @return uint Borrow value of account in USD, scaled to 1e18
function virtualBorrowValue(address account) external view returns(uint);
/// @notice Get the `marketFactor` weighted net borrows (i.e. borrows - lends)
/// in USD for a particular `Market`
/// @param account Account to query
/// @param market `FixedRateMarket` contract
/// @return uint Borrow value of account in USD, scaled to 1e18
function virtualBorrowValueByMarket(
address account,
IFixedRateMarket market
) external view returns(uint);
/// @notice Return what the weighted total borrow value for an account would be with a hypothetical borrow
/// @param account Account to query
/// @param hypotheticalMarket Market of hypothetical borrow / lend
/// @param borrowAmount Amount of hypothetical borrow in local ccy
/// @param lendAmount Amount of hypothetical lend in local ccy
/// @return uint Borrow value of account in USD, scaled to 1e18
function hypotheticalVirtualBorrowValue(
address account,
IFixedRateMarket hypotheticalMarket,
uint borrowAmount,
uint lendAmount
) external view returns(uint);
/// @notice Get the unweighted value (in USD) of all the collateral deposited
/// for an account
/// @param account Account to query
/// @return uint Total value of account in USD, scaled to 1e18
function realCollateralValue(address account) external view returns(uint);
/// @notice Get the unweighted value (in USD) of the tokens deposited
/// for an account
/// @param account Account to query
/// @param token ERC20 token
/// @return uint Value of token collateral of account in USD, scaled to 1e18
function realCollateralValueByToken(
address account,
IERC20 token
) external view returns(uint);
/// @notice Get the unweighted current net value borrowed (i.e. borrows - lends)
/// in USD summed across all `Market`s participated in by the user
/// @param account Account to query
/// @return uint Borrow value of account in USD, scaled to 1e18
function realBorrowValue(address account) external view returns(uint);
/// @notice Get the unweighted current net value borrowed (i.e. borrows - lends)
/// in USD for a particular `Market`
/// @param account Account to query
/// @param market `FixedRateMarket` contract
/// @return uint Borrow value of account in USD, scaled to 1e18
function realBorrowValueByMarket(
address account,
IFixedRateMarket market
) external view returns(uint);
/// @notice Get an account's maximum available borrow amount in a specific FixedRateMarket.
/// For example, what is the maximum amount of GLMRJUL22 that an account can borrow
/// while ensuring their account health continues to be acceptable?
/// Note: This function will return 0 if market to borrow is disabled
/// Note: This function will return creditLimit() if maximum amount allowed for one market exceeds creditLimit()
/// Note: User can only borrow up to `initCollateralRatio` for their own protection against instant liquidations
/// @param account User account
/// @param borrowMarket Address of the `FixedRateMarket` market to borrow
/// @return uint Maximum available amount user can borrow (in FV) without breaching `initCollateralRatio`
function hypotheticalMaxBorrowFV(address account, IFixedRateMarket borrowMarket) external view returns(uint);
/// @notice Get the minimum collateral ratio. Scaled by 1e8.
/// @return uint Minimum collateral ratio
function minCollateralRatio() external view returns(uint);
/// @notice Get the minimum collateral ratio for a user account. Scaled by 1e8.
/// @param account User account
/// @return uint Minimum collateral ratio
function minCollateralRatio(address account) external view returns(uint);
/// @notice Get the initial collateral ratio. Scaled by 1e8
/// @return uint Initial collateral ratio
function initCollateralRatio() external view returns(uint);
/// @notice Get the initial collateral ratio for a user account. Scaled by 1e8
/// @param account User account
/// @return uint Initial collateral ratio
function initCollateralRatio(address account) external view returns(uint);
/// @notice Get the close factor. Scaled by 1e8
/// @return uint Close factor
function closeFactor() external view returns(uint);
/// @notice Get the liquidation incentive. Scaled by 1e8
/// @return uint Liquidation incentive
function liquidationIncentive() external view returns(uint);
/// @notice Use this for quick lookups of collateral balances by asset
/// @param account User account
/// @param token ERC20 token
/// @return uint Balance in local
function collateralBalance(address account, IERC20 token) external view returns(uint);
/// @notice Get iterable list of collateral addresses which an account has nonzero balance.
/// @param account User account
/// @return address[] Iterable list of ERC20 token addresses
function iterableCollateralAddresses(address account) external view returns(IERC20[] memory);
/// @notice Quick lookup of whether an account has a particular collateral
/// @param account User account
/// @param token ERC20 token addresses
/// @return bool True if account has collateralized with given ERC20 token, false otherwise
function accountCollateral(address account, IERC20 token) external view returns(bool);
/// @notice Get iterable list of all Markets which an account has participated
/// @param account User account
/// @return address[] Iterable list of `FixedRateLoanMarket` contract addresses
function iterableAccountMarkets(address account) external view returns(IFixedRateMarket[] memory);
/// @notice Quick lookup of whether an account has participated in a Market
/// @param account User account
/// @param market`FixedRateLoanMarket` contract
/// @return bool True if participated, false otherwise
function accountMarkets(address account, IFixedRateMarket market) external view returns(bool);
/// @notice Converts any local value into its value in USD using oracle feed price
/// @param token ERC20 token
/// @param amountLocal Amount denominated in terms of the ERC20 token
/// @return uint Amount in USD, scaled to 1e18
function localToUSD(IERC20 token, uint amountLocal) external view returns(uint);
/// @notice Converts any value in USD into its value in local using oracle feed price
/// @param token ERC20 token
/// @param valueUSD Amount in USD
/// @return uint Amount denominated in terms of the ERC20 token
function USDToLocal(IERC20 token, uint valueUSD) external view returns(uint);
}//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/QTypes.sol";
interface IQAdmin is IAccessControlUpgradeable {
/// @notice Emitted when a new FixedRateMarket is deployed
event CreateFixedRateMarket(address indexed marketAddress, address indexed tokenAddress, uint maturity);
/// @notice Emitted when a new `Asset` is added
event AddAsset(
address indexed tokenAddress,
bool isYieldBearing,
address oracleFeed,
uint collateralFactor,
uint marketFactor);
/// @notice Emitted when existing `Asset` is removed
event RemoveAsset(address indexed tokenAddress);
/// @notice Emitted when setting `_weth`
event SetWETH(address wethAddress);
/// @notice Emitted when setting `_qollateralManager`
event SetQollateralManager(address qollateralManagerAddress);
/// @notice Emitted when setting `_stakingEmissionsQontroller`
event SetStakingEmissionsQontroller(address stakingEmissionsQontrollerAddress);
/// @notice Emitted when setting `_tradingEmissionsQontroller`
event SetTradingEmissionsQontroller(address tradingEmissionsQontrollerAddress);
/// @notice Emitted when setting `_feeEmissionsQontroller`
event SetFeeEmissionsQontroller(address feeEmissionsQontrollerAddress);
/// @notice Emitted when setting `_veQoda`
event SetVeQoda(address veQodaAddress);
/// @notice Emitted when setting `_qodaLens`
event SetQodaLens(address qodaLensAddress);
/// @notice Emitted when setting `collateralFactor`
event SetCollateralFactor(address indexed tokenAddress, uint oldValue, uint newValue);
/// @notice Emitted when setting `marketFactor`
event SetMarketFactor(address indexed tokenAddress, uint oldValue, uint newValue);
/// @notice Emitted when setting `minQuoteSize`
event SetMinQuoteSize(address indexed tokenAddress, uint oldValue, uint newValue);
/// @notice Emitted when `_minCollateralRatioDefault` and `_initCollateralRatioDefault` get updated
event SetCollateralRatio(uint oldMinValue, uint oldInitValue, uint newMinValue, uint newInitValue);
/// @notice Emitted when `CreditFacility` gets updated
event SetCreditFacility(address account, bool oldEnabled, uint oldMinValue, uint oldInitValue, uint oldCreditValue, bool newEnabled, uint newMinValue, uint newInitValue, uint newCreditValue);
/// @notice Emitted when `_closeFactor` gets updated
event SetCloseFactor(uint oldValue, uint newValue);
/// @notice Emitted when `_repaymentGracePeriod` gets updated
event SetRepaymentGracePeriod(uint oldValue, uint newValue);
/// @notice Emitted when `_maturityGracePeriod` gets updated
event SetMaturityGracePeriod(uint oldValue, uint newValue);
/// @notice Emitted when `_liquidationIncentive` gets updated
event SetLiquidationIncentive(uint oldValue, uint newValue);
/// @notice Emitted when `_protocolFee` gets updated
event SetProtocolFee(uint oldValue, uint newValue);
/// @notice Emitted when pause state of all `FixedRateMarket` contract is changed
event SetMarketPaused(bool paused);
/// @notice Emitted when pause state of a particular contract is changed
event SetContractPaused(address contractAddr, bool paused);
/// @notice Emitted when pause state of a particular operation is changed
event SetOperationPaused(uint operationId, bool paused);
/** ADMIN FUNCTIONS **/
/// @notice Call upon initialization after deploying `QAdmin` contract
/// @param wethAddress Address of `WETH` contract of the network
function _setWETH(address wethAddress) external;
/// @notice Call upon initialization after deploying `QollateralManager` contract
/// @param qollateralManagerAddress Address of `QollateralManager` deployment
function _setQollateralManager(address qollateralManagerAddress) external;
/// @notice Call upon initialization after deploying `StakingEmissionsQontroller` contract
/// @param stakingEmissionsQontrollerAddress Address of `StakingEmissionsQontroller` deployment
function _setStakingEmissionsQontroller(address stakingEmissionsQontrollerAddress) external;
/// @notice Call upon initialization after deploying `TradingEmissionsQontroller` contract
/// @param tradingEmissionsQontrollerAddress Address of `TradingEmissionsQontroller` deployment
function _setTradingEmissionsQontroller(address tradingEmissionsQontrollerAddress) external;
/// @notice Call upon initialization after deploying `FeeEmissionsQontroller` contract
/// @param feeEmissionsQontrollerAddress Address of `FeeEmissionsQontroller` deployment
function _setFeeEmissionsQontroller(address feeEmissionsQontrollerAddress) external;
/// @notice Call upon initialization after deploying `veQoda` contract
/// @param veQodaAddress Address of `veQoda` deployment
function _setVeQoda(address veQodaAddress) external;
/// @notice Call upon initialization after deploying `QodaLens` contract
/// @param qodaLensAddress Address of `QodaLens` deployment
function _setQodaLens(address qodaLensAddress) external;
/// @notice Set credit facility for specified account
/// @param account_ account for credit facility adjustment
/// @param enabled_ If credit facility should be enabled
/// @param minCollateralRatio_ New minimum collateral ratio value
/// @param initCollateralRatio_ New initial collateral ratio value
/// @param creditLimit_ new credit limit in USD, scaled by 1e18
function _setCreditFacility(address account_, bool enabled_, uint minCollateralRatio_, uint initCollateralRatio_, uint creditLimit_) external;
/// @notice Admin function for adding new Assets. An Asset must be added before it
/// can be used as collateral or borrowed. Note: We can create functionality for
/// allowing borrows of a token but not using it as collateral by setting
/// `collateralFactor` to zero.
/// @param tokenAddress ERC20 token corresponding to the Asset
/// @param isYieldBearing True if token bears interest (eg aToken, cToken, mToken, etc)
/// @param underlying Address of the underlying token
/// @param oracleFeed Chainlink price feed address
/// @param collateralFactor 0.0 to 1.0 (scaled to 1e8) for discounting risky assets
/// @param marketFactor 0.0 to 1.0 (scaled to 1e8) for premium on risky borrows
function _addAsset(
address tokenAddress,
bool isYieldBearing,
address underlying,
address oracleFeed,
uint collateralFactor,
uint marketFactor
) external;
/// @notice Admin function for removing an asset
/// @param token ERC20 token corresponding to the Asset
function _removeAsset(IERC20 token) external;
/// @notice Adds a new `FixedRateMarket` contract into the internal mapping of
/// whitelisted market addresses
/// @param marketAddress New `FixedRateMarket` contract address
/// @param protocolFee_ Corresponding protocol fee in basis points
/// @param minQuoteSize_ Size in PV terms, local currency
function _addFixedRateMarket(
address marketAddress,
uint protocolFee_,
uint minQuoteSize_
) external;
/// @notice Update the `collateralFactor` for a given `Asset`
/// @param token ERC20 token corresponding to the Asset
/// @param collateralFactor 0.0 to 1.0 (scaled to 1e8) for discounting risky assets
function _setCollateralFactor(IERC20 token, uint collateralFactor) external;
/// @notice Update the `marketFactor` for a given `Asset`
/// @param token Address of the token corresponding to the Asset
/// @param marketFactor 0.0 to 1.0 (scaled to 1e8) for discounting risky assets
function _setMarketFactor(IERC20 token, uint marketFactor) external;
/// @notice Set the minimum quote size for a particular `FixedRateMarket`
/// @param marketAddress Address of the `FixedRateMarket` contract
/// @param minQuoteSize_ Size in PV terms, local currency
function _setMinQuoteSize(address marketAddress, uint minQuoteSize_) external;
/// @notice Set the global minimum and initial collateral ratio
/// @param minCollateralRatio_ New global minimum collateral ratio value
/// @param initCollateralRatio_ New global initial collateral ratio value
function _setCollateralRatio(uint minCollateralRatio_, uint initCollateralRatio_) external;
/// @notice Set the global close factor
/// @param closeFactor_ New close factor value
function _setCloseFactor(uint closeFactor_) external;
/// @notice Set the global repayment grace period
/// @param repaymentGracePeriod_ New repayment grace period
function _setRepaymentGracePeriod(uint repaymentGracePeriod_) external;
/// @notice Set the global maturity grace period
/// @param maturityGracePeriod_ New maturity grace period
function _setMaturityGracePeriod(uint maturityGracePeriod_) external;
/// @notice Set the global liquidation incetive
/// @param liquidationIncentive_ New liquidation incentive value
function _setLiquidationIncentive(uint liquidationIncentive_) external;
/// @notice Set the global annualized protocol fees for each market in basis points
/// @param marketAddress Address of the `FixedRateMarket` contract
/// @param protocolFee_ New protocol fee value (scaled to 1e4)
function _setProtocolFee(address marketAddress, uint protocolFee_) external;
/// @notice Set the global threshold in USD for protocol fee transfer
/// @param thresholdUSD_ New threshold USD value (scaled by 1e6)
function _setThresholdUSD(uint thresholdUSD_) external;
/// @notice Pause/unpause all markets for admin
/// @param paused Boolean to indicate if all markets should be paused
function _setMarketsPaused(bool paused) external;
/// @notice Pause/unpause specified list of contracts for admin
/// @param contractsAddr List of contract addresses to pause/unpause
/// @param paused Boolean to indicate if specified contract should be paused
function _setContractPaused(address[] memory contractsAddr, bool paused) external;
/// @notice Pause/unpause specified contract for admin
/// @param contractAddr Address of contract to pause/unpause
/// @param paused Boolean to indicate if specified contract should be paused
function _setContractPaused(address contractAddr, bool paused) external;
/// @notice Pause/unpause specified list of operations for admin
/// @param operationIds List of ids for operation to pause/unpause
/// @param paused Boolean to indicate if specified operation should be paused
function _setOperationPaused(uint[] memory operationIds, bool paused) external;
/// @notice Pause/unpause specified operation for admin
/// @param operationId Id for operation to pause/unpause
/// @param paused Boolean to indicate if specified operation should be paused
function _setOperationPaused(uint operationId, bool paused) external;
/** VIEW FUNCTIONS **/
function ADMIN_ROLE() external view returns(bytes32);
function MARKET_ROLE() external view returns(bytes32);
function MINTER_ROLE() external view returns(bytes32);
function VETOKEN_ROLE() external view returns(bytes32);
/// @notice Get the address of the `WETH` contract
function WETH() external view returns(address);
/// @notice Get the address of the `QollateralManager` contract
function qollateralManager() external view returns(address);
/// @notice Get the address of the `QPriceOracle` contract
function qPriceOracle() external view returns(address);
/// @notice Get the address of the `StakingEmissionsQontroller` contract
function stakingEmissionsQontroller() external view returns(address);
/// @notice Get the address of the `TradingEmissionsQontroller` contract
function tradingEmissionsQontroller() external view returns(address);
/// @notice Get the address of the `FeeEmissionsQontroller` contract
function feeEmissionsQontroller() external view returns(address);
/// @notice Get the address of the `veQoda` contract
function veQoda() external view returns(address);
/// @notice Get the address of the `QodaLens` contract
function qodaLens() external view returns(address);
/// @notice Get the credit limit with associated address, scaled by 1e18
function creditLimit(address account_) external view returns(uint);
/// @notice Gets the `Asset` mapped to the address of a ERC20 token
/// @param token ERC20 token
/// @return QTypes.Asset Associated `Asset`
function assets(IERC20 token) external view returns(QTypes.Asset memory);
/// @notice Get all enabled `Asset`s
/// @return address[] iterable list of enabled `Asset`s
function allAssets() external view returns(address[] memory);
/// @notice Gets the `oracleFeed` associated with a ERC20 token
/// @param token ERC20 token
/// @return address Address of the oracle feed
function oracleFeed(IERC20 token) external view returns(address);
/// @notice Gets the `CollateralFactor` associated with a ERC20 token
/// @param token ERC20 token
/// @return uint Collateral Factor, scaled by 1e8
function collateralFactor(IERC20 token) external view returns(uint);
/// @notice Gets the `MarketFactor` associated with a ERC20 token
/// @param token ERC20 token
/// @return uint Market Factor, scaled by 1e8
function marketFactor(IERC20 token) external view returns(uint);
/// @notice Gets the `maturities` associated with a ERC20 token
/// @param token ERC20 token
/// @return uint[] array of UNIX timestamps (in seconds) of the maturity dates
function maturities(IERC20 token) external view returns(uint[] memory);
/// @notice Get the MToken market corresponding to any underlying ERC20
/// tokenAddress => mTokenAddress
function underlyingToMToken(IERC20 token) external view returns(address);
/// @notice Gets the address of the `FixedRateMarket` contract
/// @param token ERC20 token
/// @param maturity UNIX timestamp of the maturity date
/// @return address Address of `FixedRateMarket` contract
function fixedRateMarkets(IERC20 token, uint maturity) external view returns(address);
/// @notice Check whether an address is a valid FixedRateMarket address.
/// Can be used for checks for inter-contract admin/restricted function call.
/// @param marketAddress Address of the `FixedRateMarket` contract
/// @return bool True if valid false otherwise
function isMarketEnabled(address marketAddress) external view returns(bool);
function minQuoteSize(address marketAddress) external view returns(uint);
function minCollateralRatio() external view returns(uint);
function minCollateralRatio(address account) external view returns(uint);
function initCollateralRatio() external view returns(uint);
function initCollateralRatio(address account) external view returns(uint);
function closeFactor() external view returns(uint);
function repaymentGracePeriod() external view returns(uint);
function maturityGracePeriod() external view returns(uint);
function liquidationIncentive() external view returns(uint);
/// @notice Annualized protocol fee in basis points, scaled by 1e4
function protocolFee(address marketAddress) external view returns(uint);
/// @notice threshold in USD where protocol fee from each market will be transferred into `FeeEmissionsQontroller`
/// once this amount is reached, scaled by 1e6
function thresholdUSD() external view returns(uint);
/// @notice Boolean to indicate if all markets are paused
function marketsPaused() external view returns(bool);
/// @notice Boolean to indicate if specified contract address is paused
function contractPaused(address contractAddr) external view returns(bool);
/// @notice Boolean to indicate if specified operation is paused
function operationPaused(uint operationId) external view returns(bool);
/// @notice Check if given combination of contract address and operation should be allowed
function isPaused(address contractAddr, uint operationId) external view returns(bool);
/// @notice 2**256 - 1
function UINT_MAX() external pure returns(uint);
/// @notice Generic mantissa corresponding to ETH decimals
function MANTISSA_DEFAULT() external pure returns(uint);
/// @notice Mantissa for USD
function MANTISSA_USD() external pure returns(uint);
/// @notice Mantissa for collateral ratio
function MANTISSA_COLLATERAL_RATIO() external pure returns(uint);
/// @notice `assetFactor` and `marketFactor` have up to 8 decimal places precision
function MANTISSA_FACTORS() external pure returns(uint);
/// @notice Basis points have 4 decimal place precision
function MANTISSA_BPS() external pure returns(uint);
/// @notice Staked Qoda has 6 decimal place precision
function MANTISSA_STAKING() external pure returns(uint);
/// @notice `collateralFactor` cannot be above 1.0
function MAX_COLLATERAL_FACTOR() external pure returns(uint);
/// @notice `marketFactor` cannot be above 1.0
function MAX_MARKET_FACTOR() external pure returns(uint);
/// @notice version number of this contract, will be bumped upon contractual change
function VERSION_NUMBER() external pure returns(string memory);
}//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IQPriceOracle {
/// @notice Converts any local value into its value in USD using oracle feed price
/// @param token ERC20 token
/// @param amountLocal Amount denominated in terms of the ERC20 token
/// @return uint Amount in USD
function localToUSD(IERC20 token, uint amountLocal) external view returns(uint);
/// @notice Converts any value in USD into its value in local using oracle feed price
/// @param token ERC20 token
/// @param valueUSD Amount in USD
/// @return uint Amount denominated in terms of the ERC20 token
function USDToLocal(IERC20 token, uint valueUSD) external view returns(uint);
/// @notice Convenience function for getting price feed from Chainlink oracle
/// @param oracleFeed Address of the chainlink oracle feed
/// @return answer uint256, decimals uint8
function priceFeed(address oracleFeed) external view returns(uint256, uint8);
/// @notice Get the address of the `QAdmin` contract
/// @return address Address of `QAdmin` contract
function qAdmin() external view returns(address);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
library Interest {
function PVToFV(
uint64 APR,
uint PV,
uint sTime,
uint eTime,
uint mantissaAPR
) internal pure returns(uint){
require(sTime < eTime, "invalid time interval");
// Seconds per 365-day year (60 * 60 * 24 * 365)
uint year = 31536000;
// elapsed time from now to maturity
uint elapsed = eTime - sTime;
uint interest = PV * APR * elapsed / mantissaAPR / year;
return PV + interest;
}
function FVToPV(
uint64 APR,
uint FV,
uint sTime,
uint eTime,
uint mantissaAPR
) internal pure returns(uint){
require(sTime < eTime, "invalid time interval");
// Seconds per 365-day year (60 * 60 * 24 * 365)
uint year = 31536000;
// elapsed time from now to maturity
uint elapsed = eTime - sTime;
uint num = FV * mantissaAPR * year;
uint denom = mantissaAPR * year + APR * elapsed;
return num / denom;
}
}//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
library QTypes {
/// @notice Contains all the details of an Asset. Assets must be defined
/// before they can be used as collateral.
/// @member isEnabled True if an asset is defined, false otherwise
/// @member isYieldBearing True if token bears interest (eg aToken, cToken, mToken, etc)
/// @member underlying Address of the underlying token
/// @member oracleFeed Address of the corresponding chainlink oracle feed
/// @member collateralFactor 0.0 to 1.0 (scaled to 1e8) for discounting risky assets
/// @member marketFactor 0.0 1.0 for premium on risky borrows
/// @member maturities Iterable storage for all enabled maturities
struct Asset {
bool isEnabled;
bool isYieldBearing;
address underlying;
address oracleFeed;
uint collateralFactor;
uint marketFactor;
uint[] maturities;
}
/// @notice Contains all the fields of a created Quote
/// @param id ID of the quote
/// @param next Next quote in the list
/// @param prev Previous quote in the list
/// @param quoter Account of the Quoter
/// @param quoteType 0 for PV+APR, 1 for FV+APR
/// @param APR In decimal form scaled by 1e4 (ex. 10.52% = 1052)
/// @param cashflow Can be PV or FV depending on `quoteType`
/// @param filled Amount quote has got filled partially
struct Quote {
uint64 id;
uint64 next;
uint64 prev;
address quoter;
uint8 quoteType;
uint64 APR;
uint cashflow;
uint filled;
}
/// @notice Contains all the configurations customizable to an address
/// @member enabled If config for an address is enabled. When enabled is false, credit limit is infinite even if value is 0
/// @member minCollateralRatio If collateral ratio falls below `_minCollateralRatio`, it is subject to liquidation. Scaled by 1e8
/// @member initCollateralRatio When initially taking a loan, collateral ratio must be higher than this. `initCollateralRatio` should always be higher than `minCollateralRatio`. Scaled by 1e8
/// @member creditLimit Allowed limit in virtual USD for each address to do uncollateralized borrow, scaled by 1e18
struct CreditFacility {
bool enabled;
uint minCollateralRatio;
uint initCollateralRatio;
uint creditLimit;
}
}//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
library QTypesPeripheral {
/// @notice Contains all the fields (market and side included) of a created Quote
/// @param market Address of the market
/// @param id ID of the quote
/// @param side 0 for borrow quote, 1 for lend quote
/// @param quoter Account of the Quoter
/// @param quoteType 0 for PV+APR, 1 for FV+APR
/// @param APR In decimal form scaled by 1e4 (ex. 10.52% = 1052)
/// @param cashflow Can be PV or FV depending on `quoteType`
/// @param filled Amount quote has got filled partially
struct AccountQuote {
address market;
uint64 id;
uint8 side;
address quoter;
uint8 quoteType;
uint64 APR;
uint cashflow;
uint filled;
}
}//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
library Utils {
function roundUpDiv(uint dividend, uint divider) internal pure returns(uint) {
uint adjustment = dividend % divider > 0? 1: 0;
return dividend / divider + adjustment;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getAllMarketsByAsset","outputs":[{"internalType":"contract IFixedRateMarket[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint8","name":"side","type":"uint8"},{"internalType":"uint8","name":"quoteType","type":"uint8"}],"name":"getEstimatedAPR","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract IFixedRateMarket","name":"borrowMarket","type":"address"}],"name":"hypotheticalMaxBorrowFV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract IFixedRateMarket","name":"lendMarket","type":"address"}],"name":"hypotheticalMaxLendPV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"withdrawToken","type":"address"}],"name":"hypotheticalMaxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"qAdminAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract IERC20","name":"collateralToken","type":"address"},{"internalType":"contract IFixedRateMarket","name":"borrowMarket","type":"address"},{"internalType":"uint256","name":"borrowAmountFV","type":"uint256"}],"name":"minimumCollateralRequired","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"qAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"qPriceOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"qollateralManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"},{"internalType":"uint8","name":"side","type":"uint8"},{"internalType":"uint64[]","name":"quoteIds","type":"uint64[]"}],"name":"quoteIdsToQuotes","outputs":[{"components":[{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint64","name":"next","type":"uint64"},{"internalType":"uint64","name":"prev","type":"uint64"},{"internalType":"address","name":"quoter","type":"address"},{"internalType":"uint8","name":"quoteType","type":"uint8"},{"internalType":"uint64","name":"APR","type":"uint64"},{"internalType":"uint256","name":"cashflow","type":"uint256"},{"internalType":"uint256","name":"filled","type":"uint256"}],"internalType":"struct QTypes.Quote[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"takeAccountQuotes","outputs":[{"components":[{"internalType":"address","name":"market","type":"address"},{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint8","name":"side","type":"uint8"},{"internalType":"address","name":"quoter","type":"address"},{"internalType":"uint8","name":"quoteType","type":"uint8"},{"internalType":"uint64","name":"APR","type":"uint64"},{"internalType":"uint256","name":"cashflow","type":"uint256"},{"internalType":"uint256","name":"filled","type":"uint256"}],"internalType":"struct QTypesPeripheral.AccountQuote[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"},{"internalType":"uint8","name":"side","type":"uint8"},{"internalType":"uint256","name":"n","type":"uint256"}],"name":"takeNFilteredQuotes","outputs":[{"components":[{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint64","name":"next","type":"uint64"},{"internalType":"uint64","name":"prev","type":"uint64"},{"internalType":"address","name":"quoter","type":"address"},{"internalType":"uint8","name":"quoteType","type":"uint8"},{"internalType":"uint64","name":"APR","type":"uint64"},{"internalType":"uint256","name":"cashflow","type":"uint256"},{"internalType":"uint256","name":"filled","type":"uint256"}],"internalType":"struct QTypes.Quote[]","name":"","type":"tuple[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"},{"internalType":"uint8","name":"side","type":"uint8"},{"internalType":"uint256","name":"n","type":"uint256"}],"name":"takeNQuotes","outputs":[{"components":[{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint64","name":"next","type":"uint64"},{"internalType":"uint64","name":"prev","type":"uint64"},{"internalType":"address","name":"quoter","type":"address"},{"internalType":"uint8","name":"quoteType","type":"uint8"},{"internalType":"uint64","name":"APR","type":"uint64"},{"internalType":"uint256","name":"cashflow","type":"uint256"},{"internalType":"uint256","name":"filled","type":"uint256"}],"internalType":"struct QTypes.Quote[]","name":"","type":"tuple[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"totalLoansTradedByAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"}],"name":"totalLoansTradedByMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLoansTradedInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"totalRedeemedLendsByAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"}],"name":"totalRedeemedLendsByMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRedeemedLendsInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"totalRepaidBorrowsByAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"}],"name":"totalRepaidBorrowsByMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRepaidBorrowsInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"totalUnredeemedLendsByAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"}],"name":"totalUnredeemedLendsByMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnredeemedLendsInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"totalUnrepaidBorrowsByAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFixedRateMarket","name":"market","type":"address"}],"name":"totalUnrepaidBorrowsByMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnrepaidBorrowsInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50614950806100206000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c80636e49106311610104578063a0ee9560116100a2578063ce40130811610071578063ce401308146103cd578063e933ccc6146103de578063ee2bdaf7146103f1578063f138cb201461040457600080fd5b8063a0ee95601461037d578063b431dafa14610385578063c4d66de8146103a5578063ce219949146103ba57600080fd5b806384129ae5116100de57806384129ae51461032757806392022a491461033a57806397d598a0146103625780639ce7ff271461037557600080fd5b80636e491063146102e157806370554649146102f45780637086ae9b1461031457600080fd5b806331442d61116101715780635f2ead681161014b5780635f2ead6814610288578063643b6748146102a85780636b10fcce146102bb5780636e10cc3e146102ce57600080fd5b806331442d61146102565780635247e78a1461025e5780635f2a9e221461028057600080fd5b80630d3af45f116101ad5780630d3af45f1461021557806319786f5a1461021d57806327317cdd14610230578063313ffb651461024357600080fd5b8063015c324f146101d4578063036b74fd146101ef5780630afaaa3414610202575b600080fd5b6101dc610424565b6040519081526020015b60405180910390f35b6101dc6101fd366004613f8f565b610445565b6101dc610210366004613fc8565b61045a565b6101dc6104bd565b6101dc61022b366004613fe5565b610684565b6101dc61023e366004613fc8565b610bc1565b6101dc610251366004613fc8565b610bdf565b6101dc610bfd565b61027161026c366004614045565b610dc4565b6040516101e693929190614158565b6101dc6112a7565b61029061146e565b6040516001600160a01b0390911681526020016101e6565b6101dc6102b6366004613f8f565b6114dc565b6101dc6102c9366004613fc8565b6115d4565b6101dc6102dc366004613fc8565b6115df565b6101dc6102ef366004613fc8565b6116b9565b61030761030236600461419b565b611714565b6040516101e6919061422f565b6101dc610322366004613fc8565b61188c565b610271610335366004614045565b6118f0565b61034d610348366004614242565b611ee2565b604080519283526020830191909152016101e6565b6101dc610370366004613fc8565b6123e0565b6101dc61243b565b610290612445565b610398610393366004613fc8565b61248f565b6040516101e691906142aa565b6103b86103b3366004613fc8565b61287a565b005b6101dc6103c8366004613fc8565b61299f565b6033546001600160a01b0316610290565b6101dc6103ec366004613fc8565b6129b3565b6101dc6103ff366004613f8f565b6129f3565b610417610412366004613fc8565b612b3d565b6040516101e6919061436a565b600061042e610bfd565b6104366112a7565b61044091906143cd565b905090565b60006104518383612cf5565b90505b92915050565b60008061046683612b3d565b90506000805b82518110156104b55761049783828151811061048a5761048a6143e0565b60200260200101516115df565b6104a190836143f6565b9150806104ad81614409565b91505061046c565b509392505050565b600080603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa158015610513573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105379190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b03166376d708d76040518163ffffffff1660e01b8152600401600060405180830381865afa15801561058e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105b691908101906144e0565b90506000805b82518110156104b55760008382815181106105d9576105d96143e0565b6020026020010151905060006105ee826123e0565b604051637dee6c4760e01b81526001600160a01b0384811660048301526024820183905291925090871690637dee6c4790604401602060405180830381865afa15801561063f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610663919061457e565b61066d90856143f6565b93505050808061067c90614409565b9150506105bc565b600080603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fe9190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa158015610755573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107799190614432565b604051639c4d1ff760e01b81526001600160a01b038981166004830152919250600091841690639c4d1ff790602401602060405180830381865afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e9919061457e565b6040516327b0c87760e21b81526001600160a01b038a81166004830152919250600091851690639ec321dc90602401602060405180830381865afa158015610835573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610859919061457e565b604051636014e63560e01b81526001600160a01b038b81166004830152898116602483015260448201899052600060648301819052929350861690636014e63590608401602060405180830381865afa1580156108ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108de919061457e565b6108e99060016143f6565b90506000826109776108fb8487614597565b603360009054906101000a90046001600160a01b03166001600160a01b0316638b2f81d66040518163ffffffff1660e01b8152600401602060405180830381865afa15801561094e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610972919061457e565b6132a3565b61098191906143cd565b6033546040516301f429f560e41b81526001600160a01b038e81166004830152929350911690631f429f5090602401602060405180830381865afa1580156109cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f1919061457e565b811115610a5e5760405162461bcd60e51b815260206004820152603060248201527f516f64614c656e733a207065726d697474656420616d6f756e7420657863656560448201526f3232b2103337b9103137b93937bbb2b960811b60648201526084015b60405180910390fd5b6000610b2e603360009054906101000a90046001600160a01b03166001600160a01b031663de01c9cb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ab6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ada919061457e565b610ae49084614597565b603354604051637de637af60e11b81526001600160a01b038f811660048301529091169063fbcc6f5e90602401602060405180830381865afa15801561094e573d6000803e3d6000fd5b604051632a72258160e01b81526001600160a01b038d8116600483015260248201839052919250600091881690632a72258190604401602060405180830381865afa158015610b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba5919061457e565b610bb09060016143f6565b9d9c50505050505050505050505050565b6000610bcc826129b3565b610bd58361188c565b61045491906143f6565b6000610bea8261045a565b610bf3836116b9565b61045491906143cd565b600080603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c779190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b03166376d708d76040518163ffffffff1660e01b8152600401600060405180830381865afa158015610cce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cf691908101906144e0565b90506000805b82518110156104b5576000838281518110610d1957610d196143e0565b602002602001015190506000610d2e8261045a565b604051637dee6c4760e01b81526001600160a01b0384811660048301526024820183905291925090871690637dee6c4790604401602060405180830381865afa158015610d7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da3919061457e565b610dad90856143f6565b935050508080610dbc90614409565b915050610cfc565b6060808060ff851615801590610dde575060ff8516600114155b15610dfb5760405162461bcd60e51b8152600401610a55906145ae565b60405163260122e360e01b815260ff86166004820152610e729085906001600160a01b0389169063260122e3906024015b602060405180830381865afa158015610e49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6d919061457e565b6132da565b93506000846001600160401b03811115610e8e57610e8e61444f565b604051908082528060200260200182016040528015610ec757816020015b610eb4613f33565b815260200190600190039081610eac5790505b5090506000856001600160401b03811115610ee457610ee461444f565b604051908082528060200260200182016040528015610f0d578160200160208202803683370190505b5090506000866001600160401b03811115610f2a57610f2a61444f565b604051908082528060200260200182016040528015610f53578160200160208202803683370190505b506040516342c806ed60e01b815260ff8a1660048201529091506000906001600160a01b038b16906342c806ed9060240161010060405180830381865afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc691906145ff565b90506000603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa15801561101d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110419190614432565b905060005b898110156112945782868281518110611061576110616143e0565b602090810291909101015260608301516040516332901d0b60e21b81526001600160a01b0380831660048301526000919085169063ca40742c90602401602060405180830381865afa1580156110bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110df919061457e565b9050808784815181106110f4576110f46143e0565b60200260200101818152505060008e6001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015611140573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111649190614432565b6040516370a0823160e01b81526001600160a01b03858116600483015291909116906370a0823190602401602060405180830381865afa1580156111ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d0919061457e565b9050808785815181106111e5576111e56143e0565b6020026020010181815250508e6001600160a01b031663eb0ca4558f88602001516040518363ffffffff1660e01b815260040161123a92919060ff9290921682526001600160401b0316602082015260400190565b61010060405180830381865afa158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c91906145ff565b9550505050808061128c90614409565b915050611046565b50939a9299509097509095505050505050565b600080603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113219190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b03166376d708d76040518163ffffffff1660e01b8152600401600060405180830381865afa158015611378573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113a091908101906144e0565b90506000805b82518110156104b55760008382815181106113c3576113c36143e0565b6020026020010151905060006113d8826116b9565b604051637dee6c4760e01b81526001600160a01b0384811660048301526024820183905291925090871690637dee6c4790604401602060405180830381865afa158015611429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144d919061457e565b61145790856143f6565b93505050808061146690614409565b9150506113a6565b60335460408051630be5d5ad60e31b815290516000926001600160a01b031691635f2ead689160048083019260209291908290030181865afa1580156114b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104409190614432565b600080603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa158015611532573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115569190614432565b604051630c876ce960e31b81526001600160a01b03868116600483015285811660248301529192509082169063643b674890604401602060405180830381865afa1580156115a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115cc919061457e565b949350505050565b6000610bea826123e0565b600080826001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015611620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116449190614432565b6040516370a0823160e01b81526001600160a01b038581166004830152919250908216906370a0823190602401602060405180830381865afa15801561168e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b2919061457e565b9392505050565b6000806116c583612b3d565b90506000805b82518110156104b5576116f68382815181106116e9576116e96143e0565b6020026020010151610bc1565b61170090836143f6565b91508061170c81614409565b9150506116cb565b606060ff84161580159061172c575060ff8416600114155b156117495760405162461bcd60e51b8152600401610a55906145ae565b6000826001600160401b038111156117635761176361444f565b60405190808252806020026020018201604052801561179c57816020015b611789613f33565b8152602001906001900390816117815790505b50905060005b8381101561188257866001600160a01b031663eb0ca455878787858181106117cc576117cc6143e0565b90506020020160208101906117e191906146bd565b6040516001600160e01b031960e085901b16815260ff90921660048301526001600160401b0316602482015260440161010060405180830381865afa15801561182e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185291906145ff565b828281518110611864576118646143e0565b6020026020010181905250808061187a90614409565b9150506117a2565b5095945050505050565b6000816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118cc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610454919061457e565b6060808060ff85161580159061190a575060ff8516600114155b156119275760405162461bcd60e51b8152600401610a55906145ae565b60335460408051630be5d5ad60e31b815290516000926001600160a01b031691635f2ead689160048083019260209291908290030181865afa158015611971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119959190614432565b60405163260122e360e01b815260ff881660048201529091506119cd9086906001600160a01b038a169063260122e390602401610e2c565b94506000856001600160401b038111156119e9576119e961444f565b604051908082528060200260200182016040528015611a2257816020015b611a0f613f33565b815260200190600190039081611a075790505b5090506000866001600160401b03811115611a3f57611a3f61444f565b604051908082528060200260200182016040528015611a68578160200160208202803683370190505b5090506000876001600160401b03811115611a8557611a8561444f565b604051908082528060200260200182016040528015611aae578160200160208202803683370190505b506040516342c806ed60e01b815260ff8b1660048201529091506000906001600160a01b038c16906342c806ed9060240161010060405180830381865afa158015611afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2191906145ff565b905060005b8981108015611b3e575081516001600160401b031615155b15611ec9576000611b4f8d846132f0565b905060ff8c16158015611bea57506060830151604051639c4d1ff760e01b81526001600160a01b03918216600482015290881690639c4d1ff790602401602060405180830381865afa158015611ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcd919061457e565b81600281518110611be057611be06143e0565b6020026020010151105b15611c7957602083015160405163eb0ca45560e01b815260ff8e1660048201526001600160401b0390911660248201526001600160a01b038e169063eb0ca455906044015b61010060405180830381865afa158015611c4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7191906145ff565b925050611b26565b60ff8c166001148015611d46575080600581518110611c9a57611c9a6143e0565b602002602001015181600381518110611cb557611cb56143e0565b602002602001015182600081518110611cd057611cd06143e0565b6020026020010151611ce291906143f6565b1180611d46575080600481518110611cfc57611cfc6143e0565b602002602001015181600381518110611d1757611d176143e0565b602002602001015182600081518110611d3257611d326143e0565b6020026020010151611d4491906143f6565b115b15611d8f57602083015160405163eb0ca45560e01b815260ff8e1660048201526001600160401b0390911660248201526001600160a01b038e169063eb0ca45590604401611c2f565b82868381518110611da257611da26143e0565b602090810291909101015260608301516040516332901d0b60e21b81526001600160a01b0391821660048201529088169063ca40742c90602401602060405180830381865afa158015611df9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1d919061457e565b858381518110611e2f57611e2f6143e0565b60200260200101818152505080600481518110611e4e57611e4e6143e0565b6020026020010151848381518110611e6857611e686143e0565b602090810291909101015281611e7d81614409565b9250508c6001600160a01b031663eb0ca4558d85602001516040518363ffffffff1660e01b8152600401611c2f92919060ff9290921682526001600160401b0316602082015260400190565b8085528084528252509199909850909650945050505050565b60008060ff841615801590611efb575060ff8416600114155b15611f185760405162461bcd60e51b8152600401610a55906145ae565b60ff831615801590611f2e575060ff8316600114155b15611f705760405162461bcd60e51b8152602060048201526012602482015271696e76616c69642071756f7465207479706560701b6044820152606401610a55565b6040516342c806ed60e01b815260ff851660048201526000906001600160a01b038916906342c806ed9060240161010060405180830381865afa158015611fbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fdf91906145ff565b9050856000805b8215801590611ffe575083516001600160401b031615155b1561239b57896001600160a01b031684606001516001600160a01b0316036120a857602084015160405163eb0ca45560e01b815260ff8a1660048201526001600160401b0390911660248201526001600160a01b038c169063eb0ca4559060440161010060405180830381865afa15801561207d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a191906145ff565b9350611fe6565b60c084015160ff88161580156120c55750608085015160ff166001145b156121b9576121b68560a001518660c00151428f6001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612116573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213a919061457e565b603360009054906101000a90046001600160a01b03166001600160a01b0316632d8dea9c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561218d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b1919061457e565b6139c7565b90505b60ff881660011480156121d15750608085015160ff16155b156122c5576122c28560a001518660c00151428f6001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612222573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612246919061457e565b603360009054906101000a90046001600160a01b03166001600160a01b0316632d8dea9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612299573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122bd919061457e565b613a7f565b90505b60006122d185836132da565b90508560a001516001600160401b0316816122ec9190614597565b6122f690856143f6565b935061230281846143f6565b925061230e81866143cd565b602087015160405163eb0ca45560e01b815260ff8d1660048201526001600160401b0390911660248201529095506001600160a01b038e169063eb0ca4559060440161010060405180830381865afa15801561236e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239291906145ff565b95505050611fe6565b806000036123b35760008095509550505050506123d6565b60006123bf82846146f0565b9050806123cc858c6143cd565b9650965050505050505b9550959350505050565b6000806123ec83612b3d565b90506000805b82518110156104b55761241d838281518110612410576124106143e0565b60200260200101516129b3565b61242790836143f6565b91508061243381614409565b9150506123f2565b600061042e6104bd565b6033546040805163050774ab60e51b815290516000926001600160a01b03169163a0ee95609160048083019260209291908290030181865afa1580156114b8573d6000803e3d6000fd5b6060600061249b613b2a565b90506000805b82518110156125815760008382815181106124be576124be6143e0565b6020026020010151905060005b60018160ff161161256c57604051630ca22cbb60e21b815260ff821660048201526001600160a01b038881166024830152831690633288b2ec90604401600060405180830381865afa158015612525573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261254d9190810190614704565b5161255890856143f6565b93508061256481614792565b9150506124cb565b5050808061257990614409565b9150506124a1565b506000816001600160401b0381111561259c5761259c61444f565b60405190808252806020026020018201604052801561260b57816020015b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282526000199092019101816125ba5790505b5090506000915060005b8351811015612871576000848281518110612632576126326143e0565b6020026020010151905060005b60018160ff161161285c57604051630ca22cbb60e21b815260ff821660048201526001600160a01b03898116602483015260009190841690633288b2ec90604401600060405180830381865afa15801561269d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126c59190810190614704565b905060005b8151811015612847576000846001600160a01b031663eb0ca455858585815181106126f7576126f76143e0565b60200260200101516040518363ffffffff1660e01b815260040161273392919060ff9290921682526001600160401b0316602082015260400190565b61010060405180830381865afa158015612751573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277591906145ff565b9050604051806101000160405280866001600160a01b031681526020018484815181106127a4576127a46143e0565b60200260200101516001600160401b031681526020018560ff16815260200182606001516001600160a01b03168152602001826080015160ff1681526020018260a001516001600160401b031681526020018260c0015181526020018260e0015181525087898151811061281a5761281a6143e0565b6020026020010181905250878061283090614409565b98505050808061283f90614409565b9150506126ca565b5050808061285490614792565b91505061263f565b5050808061286990614409565b915050612615565b50949350505050565b600054610100900460ff161580801561289a5750600054600160ff909116105b806128b45750303b1580156128b4575060005460ff166001145b6129175760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a55565b6000805460ff19166001179055801561293a576000805461ff0019166101001790555b603380546001600160a01b0319166001600160a01b038416179055801561299b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006129aa826115df565b610bf383610bc1565b6000816001600160a01b0316639c5bf6336040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118cc573d6000803e3d6000fd5b600080826001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a589190614432565b6040516370a0823160e01b81526001600160a01b0386811660048301529192506000918316906370a0823190602401602060405180830381865afa158015612aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac8919061457e565b604051630233c89b60e61b8152600481018290529091506001600160a01b03851690638cf226c090602401602060405180830381865afa158015612b10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b34919061457e565b95945050505050565b603354604051631e23703160e31b81526001600160a01b03838116600483015260609260009291169063f11b818890602401600060405180830381865afa158015612b8c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612bb49190810190614827565b905060008160c00151516001600160401b03811115612bd557612bd561444f565b604051908082528060200260200182016040528015612bfe578160200160208202803683370190505b50905060005b8260c00151518110156104b55760335460c084015180516001600160a01b03909216916349d649ea91889185908110612c3f57612c3f6143e0565b60200260200101516040518363ffffffff1660e01b8152600401612c789291906001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015612c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cb99190614432565b828281518110612ccb57612ccb6143e0565b6001600160a01b039092166020928302919091019091015280612ced81614409565b915050612c04565b600080603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6f9190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa158015612dc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dea9190614432565b603354604051631e23703160e31b81526001600160a01b0380881660048301529293508692600092169063f11b818890602401600060405180830381865afa158015612e3a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e629190810190614827565b6040516332901d0b60e21b81526001600160a01b03898116600483015291925060009186169063ca40742c90602401602060405180830381865afa158015612eae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ed2919061457e565b603354604051639c4d1ff760e01b81526001600160a01b038b8116600483015292935060009290911690639c4d1ff790602401602060405180830381865afa158015612f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f46919061457e565b60405163e7602b9d60e01b81526001600160a01b038b81166004830152868116602483015291925060009188169063e7602b9d90604401602060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe919061457e565b9050801580612fcd5750818311155b15612fe2576000975050505050505050610454565b603360009054906101000a90046001600160a01b03166001600160a01b031663782d2b536040518163ffffffff1660e01b8152600401602060405180830381865afa158015613035573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613059919061457e565b831061306d57965061045495505050505050565b6040516365abacad60e01b81526001600160a01b038b81166004830152600091908916906365abacad90602401602060405180830381865afa1580156130b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130db919061457e565b90506000603360009054906101000a90046001600160a01b03166001600160a01b0316638b2f81d66040518163ffffffff1660e01b8152600401602060405180830381865afa158015613132573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613156919061457e565b61316085876143cd565b61316a9084614597565b61317491906146f0565b905060008660800151603360009054906101000a90046001600160a01b03166001600160a01b031663de01c9cb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156131d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f4919061457e565b6131fe9084614597565b61320891906146f0565b604051632a72258160e01b81526001600160a01b038a81166004830152602482018390529192506000918b1690632a72258190604401602060405180830381865afa15801561325b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061327f919061457e565b90508481111561328f5784613291565b805b9e9d5050505050505050505050505050565b600080806132b184866148eb565b116132bd5760006132c0565b60015b60ff169050806132d084866146f0565b6115cc91906143f6565b60008183106132e95781610451565b5090919050565b60606000836001600160a01b0316631264bfbf84608001518560a001518660e001518760c0015161332191906143cd565b42896001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613360573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613384919061457e565b6040516001600160e01b031960e088901b16815260ff90951660048601526001600160401b03909316602485015260448401919091526064830152608482015260a401602060405180830381865afa1580156133e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613408919061457e565b90506000846001600160a01b0316638082a0b285608001518660a001518760e001518860c0015161343991906143cd565b428a6001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349c919061457e565b6040516001600160e01b031960e088901b16815260ff90951660048601526001600160401b03909316602485015260448401919091526064830152608482015260a401602060405180830381865afa1580156134fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613520919061457e565b90506000603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa158015613577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359b9190614432565b90506000816001600160a01b031663257041f38760600151896001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136159190614432565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152908216602482015260006044820181905260648201819052918b16608482015260a4810187905260c481019190915260e401602060405180830381865afa158015613688573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136ac919061457e565b6040516333f5419b60e01b8152600481018690524260248201529091506000906001600160a01b038916906333f5419b90604401602060405180830381865afa1580156136fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613721919061457e565b90506000886001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015613763573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137879190614432565b60608901516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156137d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f6919061457e565b90506000896001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015613838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061385c9190614432565b60608a0151604051636eb1769f60e11b81526001600160a01b0391821660048201528c8216602482015291169063dd62ed3e90604401602060405180830381865afa1580156138af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138d3919061457e565b60408051600680825260e08201909252919250600091906020820160c080368337019050509050878160008151811061390e5761390e6143e0565b602002602001018181525050868160018151811061392e5761392e6143e0565b602002602001018181525050848160028151811061394e5761394e6143e0565b602002602001018181525050838160038151811061396e5761396e6143e0565b602002602001018181525050828160048151811061398e5761398e6143e0565b60200260200101818152505081816005815181106139ae576139ae6143e0565b60209081029190910101529a9950505050505050505050565b6000828410613a105760405162461bcd60e51b81526020600482015260156024820152741a5b9d985b1a59081d1a5b59481a5b9d195c9d985b605a1b6044820152606401610a55565b6301e133806000613a2186866143cd565b9050600082613a30868a614597565b613a3a9190614597565b90506000613a51836001600160401b038c16614597565b613a5b8588614597565b613a6591906143f6565b9050613a7181836146f0565b9a9950505050505050505050565b6000828410613ac85760405162461bcd60e51b81526020600482015260156024820152741a5b9d985b1a59081d1a5b59481a5b9d195c9d985b605a1b6044820152606401610a55565b6301e133806000613ad986866143cd565b90506000828583613af36001600160401b038d168c614597565b613afd9190614597565b613b0791906146f0565b613b1191906146f0565b9050613b1d81896143f6565b9998505050505050505050565b60606000603360009054906101000a90046001600160a01b03166001600160a01b03166376d708d76040518163ffffffff1660e01b8152600401600060405180830381865afa158015613b81573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ba991908101906144e0565b90506000805b8251811015613c835760335483516000916001600160a01b03169063f11b818890869085908110613be257613be26143e0565b60200260200101516040518263ffffffff1660e01b8152600401613c1591906001600160a01b0391909116815260200190565b600060405180830381865afa158015613c32573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613c5a9190810190614827565b90508060c001515183613c6d91906143f6565b9250508080613c7b90614409565b915050613baf565b506000816001600160401b03811115613c9e57613c9e61444f565b604051908082528060200260200182016040528015613cc7578160200160208202803683370190505b5090506000915060005b8351811015613f29576000848281518110613cee57613cee6143e0565b6020908102919091010151603354604051631e23703160e31b81526001600160a01b0380841660048301529293506000929091169063f11b818890602401600060405180830381865afa158015613d49573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613d719190810190614827565b60c081015190915060005b8151811015613f1257818181518110613d9757613d976143e0565b6020026020010151421015613f005760335482516000916001600160a01b0316906349d649ea908790869086908110613dd257613dd26143e0565b60200260200101516040518363ffffffff1660e01b8152600401613e0b9291906001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015613e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e4c9190614432565b60335460405163bc9574ad60e01b81526001600160a01b03808416600483015292935091169063bc9574ad90602401602060405180830381865afa158015613e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ebc91906148ff565b613ec65750613f00565b80878981518110613ed957613ed96143e0565b6001600160a01b039092166020928302919091019091015287613efb81614409565b985050505b80613f0a81614409565b915050613d7c565b505050508080613f2190614409565b915050613cd1565b5090815292915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6001600160a01b0381168114613f8c57600080fd5b50565b60008060408385031215613fa257600080fd5b8235613fad81613f77565b91506020830135613fbd81613f77565b809150509250929050565b600060208284031215613fda57600080fd5b81356116b281613f77565b60008060008060808587031215613ffb57600080fd5b843561400681613f77565b9350602085013561401681613f77565b9250604085013561402681613f77565b9396929550929360600135925050565b60ff81168114613f8c57600080fd5b60008060006060848603121561405a57600080fd5b833561406581613f77565b9250602084013561407581614036565b929592945050506040919091013590565b600081518084526020808501945080840160005b8381101561411d57815180516001600160401b039081168952848201518116858a01526040808301518216908a01526060808301516001600160a01b0316908a015260808083015160ff16908a015260a0808301519091169089015260c0808201519089015260e09081015190880152610100909601959082019060010161409a565b509495945050505050565b600081518084526020808501945080840160005b8381101561411d5781518752958201959082019060010161413c565b60608152600061416b6060830186614086565b828103602084015261417d8186614128565b905082810360408401526141918185614128565b9695505050505050565b600080600080606085870312156141b157600080fd5b84356141bc81613f77565b935060208501356141cc81614036565b925060408501356001600160401b03808211156141e857600080fd5b818701915087601f8301126141fc57600080fd5b81358181111561420b57600080fd5b8860208260051b850101111561422057600080fd5b95989497505060200194505050565b6020815260006104516020830184614086565b600080600080600060a0868803121561425a57600080fd5b853561426581613f77565b9450602086013561427581613f77565b935060408601359250606086013561428c81614036565b9150608086013561429c81614036565b809150509295509295909350565b602080825282518282018190526000919060409081850190868401855b8281101561435d57815180516001600160a01b03168552868101516001600160401b0316878601528581015160ff1686860152606080820151614314828801826001600160a01b03169052565b505060808181015160ff169086015260a0808201516001600160401b03169086015260c0808201519086015260e0908101519085015261010090930192908501906001016142c7565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b818110156143ab5783516001600160a01b031683529284019291840191600101614386565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610454576104546143b7565b634e487b7160e01b600052603260045260246000fd5b80820180821115610454576104546143b7565b60006001820161441b5761441b6143b7565b5060010190565b805161442d81613f77565b919050565b60006020828403121561444457600080fd5b81516116b281613f77565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156144875761448761444f565b60405290565b604051601f8201601f191681016001600160401b03811182821017156144b5576144b561444f565b604052919050565b60006001600160401b038211156144d6576144d661444f565b5060051b60200190565b600060208083850312156144f357600080fd5b82516001600160401b0381111561450957600080fd5b8301601f8101851361451a57600080fd5b805161452d614528826144bd565b61448d565b81815260059190911b8201830190838101908783111561454c57600080fd5b928401925b8284101561457357835161456481613f77565b82529284019290840190614551565b979650505050505050565b60006020828403121561459057600080fd5b5051919050565b8082028115828204841417610454576104546143b7565b6020808252600c908201526b696e76616c6964207369646560a01b604082015260600190565b6001600160401b0381168114613f8c57600080fd5b805161442d816145d4565b805161442d81614036565b600061010080838503121561461357600080fd5b604051908101906001600160401b03821181831017156146355761463561444f565b8160405283519150614646826145d4565b818152614655602085016145e9565b6020820152614666604085016145e9565b604082015261467760608501614422565b6060820152614688608085016145f4565b608082015261469960a085016145e9565b60a082015260c084015160c082015260e084015160e0820152809250505092915050565b6000602082840312156146cf57600080fd5b81356116b2816145d4565b634e487b7160e01b600052601260045260246000fd5b6000826146ff576146ff6146da565b500490565b6000602080838503121561471757600080fd5b82516001600160401b0381111561472d57600080fd5b8301601f8101851361473e57600080fd5b805161474c614528826144bd565b81815260059190911b8201830190838101908783111561476b57600080fd5b928401925b82841015614573578351614783816145d4565b82529284019290840190614770565b600060ff821660ff81036147a8576147a86143b7565b60010192915050565b8051801515811461442d57600080fd5b600082601f8301126147d257600080fd5b815160206147e2614528836144bd565b82815260059290921b8401810191818101908684111561480157600080fd5b8286015b8481101561481c5780518352918301918301614805565b509695505050505050565b60006020828403121561483957600080fd5b81516001600160401b038082111561485057600080fd5b9083019060e0828603121561486457600080fd5b61486c614465565b614875836147b1565b8152614883602084016147b1565b602082015261489460408401614422565b60408201526148a560608401614422565b60608201526080830151608082015260a083015160a082015260c0830151828111156148d057600080fd5b6148dc878286016147c1565b60c08301525095945050505050565b6000826148fa576148fa6146da565b500690565b60006020828403121561491157600080fd5b610451826147b156fea26469706673582212204167f3c053f573e0d9bddf09e288ce33cac4b2bd704c375e1844bbdfad13d84264736f6c63430008120033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101cf5760003560e01c80636e49106311610104578063a0ee9560116100a2578063ce40130811610071578063ce401308146103cd578063e933ccc6146103de578063ee2bdaf7146103f1578063f138cb201461040457600080fd5b8063a0ee95601461037d578063b431dafa14610385578063c4d66de8146103a5578063ce219949146103ba57600080fd5b806384129ae5116100de57806384129ae51461032757806392022a491461033a57806397d598a0146103625780639ce7ff271461037557600080fd5b80636e491063146102e157806370554649146102f45780637086ae9b1461031457600080fd5b806331442d61116101715780635f2ead681161014b5780635f2ead6814610288578063643b6748146102a85780636b10fcce146102bb5780636e10cc3e146102ce57600080fd5b806331442d61146102565780635247e78a1461025e5780635f2a9e221461028057600080fd5b80630d3af45f116101ad5780630d3af45f1461021557806319786f5a1461021d57806327317cdd14610230578063313ffb651461024357600080fd5b8063015c324f146101d4578063036b74fd146101ef5780630afaaa3414610202575b600080fd5b6101dc610424565b6040519081526020015b60405180910390f35b6101dc6101fd366004613f8f565b610445565b6101dc610210366004613fc8565b61045a565b6101dc6104bd565b6101dc61022b366004613fe5565b610684565b6101dc61023e366004613fc8565b610bc1565b6101dc610251366004613fc8565b610bdf565b6101dc610bfd565b61027161026c366004614045565b610dc4565b6040516101e693929190614158565b6101dc6112a7565b61029061146e565b6040516001600160a01b0390911681526020016101e6565b6101dc6102b6366004613f8f565b6114dc565b6101dc6102c9366004613fc8565b6115d4565b6101dc6102dc366004613fc8565b6115df565b6101dc6102ef366004613fc8565b6116b9565b61030761030236600461419b565b611714565b6040516101e6919061422f565b6101dc610322366004613fc8565b61188c565b610271610335366004614045565b6118f0565b61034d610348366004614242565b611ee2565b604080519283526020830191909152016101e6565b6101dc610370366004613fc8565b6123e0565b6101dc61243b565b610290612445565b610398610393366004613fc8565b61248f565b6040516101e691906142aa565b6103b86103b3366004613fc8565b61287a565b005b6101dc6103c8366004613fc8565b61299f565b6033546001600160a01b0316610290565b6101dc6103ec366004613fc8565b6129b3565b6101dc6103ff366004613f8f565b6129f3565b610417610412366004613fc8565b612b3d565b6040516101e6919061436a565b600061042e610bfd565b6104366112a7565b61044091906143cd565b905090565b60006104518383612cf5565b90505b92915050565b60008061046683612b3d565b90506000805b82518110156104b55761049783828151811061048a5761048a6143e0565b60200260200101516115df565b6104a190836143f6565b9150806104ad81614409565b91505061046c565b509392505050565b600080603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa158015610513573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105379190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b03166376d708d76040518163ffffffff1660e01b8152600401600060405180830381865afa15801561058e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105b691908101906144e0565b90506000805b82518110156104b55760008382815181106105d9576105d96143e0565b6020026020010151905060006105ee826123e0565b604051637dee6c4760e01b81526001600160a01b0384811660048301526024820183905291925090871690637dee6c4790604401602060405180830381865afa15801561063f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610663919061457e565b61066d90856143f6565b93505050808061067c90614409565b9150506105bc565b600080603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fe9190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa158015610755573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107799190614432565b604051639c4d1ff760e01b81526001600160a01b038981166004830152919250600091841690639c4d1ff790602401602060405180830381865afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e9919061457e565b6040516327b0c87760e21b81526001600160a01b038a81166004830152919250600091851690639ec321dc90602401602060405180830381865afa158015610835573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610859919061457e565b604051636014e63560e01b81526001600160a01b038b81166004830152898116602483015260448201899052600060648301819052929350861690636014e63590608401602060405180830381865afa1580156108ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108de919061457e565b6108e99060016143f6565b90506000826109776108fb8487614597565b603360009054906101000a90046001600160a01b03166001600160a01b0316638b2f81d66040518163ffffffff1660e01b8152600401602060405180830381865afa15801561094e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610972919061457e565b6132a3565b61098191906143cd565b6033546040516301f429f560e41b81526001600160a01b038e81166004830152929350911690631f429f5090602401602060405180830381865afa1580156109cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f1919061457e565b811115610a5e5760405162461bcd60e51b815260206004820152603060248201527f516f64614c656e733a207065726d697474656420616d6f756e7420657863656560448201526f3232b2103337b9103137b93937bbb2b960811b60648201526084015b60405180910390fd5b6000610b2e603360009054906101000a90046001600160a01b03166001600160a01b031663de01c9cb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ab6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ada919061457e565b610ae49084614597565b603354604051637de637af60e11b81526001600160a01b038f811660048301529091169063fbcc6f5e90602401602060405180830381865afa15801561094e573d6000803e3d6000fd5b604051632a72258160e01b81526001600160a01b038d8116600483015260248201839052919250600091881690632a72258190604401602060405180830381865afa158015610b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba5919061457e565b610bb09060016143f6565b9d9c50505050505050505050505050565b6000610bcc826129b3565b610bd58361188c565b61045491906143f6565b6000610bea8261045a565b610bf3836116b9565b61045491906143cd565b600080603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c779190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b03166376d708d76040518163ffffffff1660e01b8152600401600060405180830381865afa158015610cce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cf691908101906144e0565b90506000805b82518110156104b5576000838281518110610d1957610d196143e0565b602002602001015190506000610d2e8261045a565b604051637dee6c4760e01b81526001600160a01b0384811660048301526024820183905291925090871690637dee6c4790604401602060405180830381865afa158015610d7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da3919061457e565b610dad90856143f6565b935050508080610dbc90614409565b915050610cfc565b6060808060ff851615801590610dde575060ff8516600114155b15610dfb5760405162461bcd60e51b8152600401610a55906145ae565b60405163260122e360e01b815260ff86166004820152610e729085906001600160a01b0389169063260122e3906024015b602060405180830381865afa158015610e49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6d919061457e565b6132da565b93506000846001600160401b03811115610e8e57610e8e61444f565b604051908082528060200260200182016040528015610ec757816020015b610eb4613f33565b815260200190600190039081610eac5790505b5090506000856001600160401b03811115610ee457610ee461444f565b604051908082528060200260200182016040528015610f0d578160200160208202803683370190505b5090506000866001600160401b03811115610f2a57610f2a61444f565b604051908082528060200260200182016040528015610f53578160200160208202803683370190505b506040516342c806ed60e01b815260ff8a1660048201529091506000906001600160a01b038b16906342c806ed9060240161010060405180830381865afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc691906145ff565b90506000603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa15801561101d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110419190614432565b905060005b898110156112945782868281518110611061576110616143e0565b602090810291909101015260608301516040516332901d0b60e21b81526001600160a01b0380831660048301526000919085169063ca40742c90602401602060405180830381865afa1580156110bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110df919061457e565b9050808784815181106110f4576110f46143e0565b60200260200101818152505060008e6001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015611140573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111649190614432565b6040516370a0823160e01b81526001600160a01b03858116600483015291909116906370a0823190602401602060405180830381865afa1580156111ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d0919061457e565b9050808785815181106111e5576111e56143e0565b6020026020010181815250508e6001600160a01b031663eb0ca4558f88602001516040518363ffffffff1660e01b815260040161123a92919060ff9290921682526001600160401b0316602082015260400190565b61010060405180830381865afa158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c91906145ff565b9550505050808061128c90614409565b915050611046565b50939a9299509097509095505050505050565b600080603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113219190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b03166376d708d76040518163ffffffff1660e01b8152600401600060405180830381865afa158015611378573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113a091908101906144e0565b90506000805b82518110156104b55760008382815181106113c3576113c36143e0565b6020026020010151905060006113d8826116b9565b604051637dee6c4760e01b81526001600160a01b0384811660048301526024820183905291925090871690637dee6c4790604401602060405180830381865afa158015611429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144d919061457e565b61145790856143f6565b93505050808061146690614409565b9150506113a6565b60335460408051630be5d5ad60e31b815290516000926001600160a01b031691635f2ead689160048083019260209291908290030181865afa1580156114b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104409190614432565b600080603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa158015611532573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115569190614432565b604051630c876ce960e31b81526001600160a01b03868116600483015285811660248301529192509082169063643b674890604401602060405180830381865afa1580156115a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115cc919061457e565b949350505050565b6000610bea826123e0565b600080826001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015611620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116449190614432565b6040516370a0823160e01b81526001600160a01b038581166004830152919250908216906370a0823190602401602060405180830381865afa15801561168e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b2919061457e565b9392505050565b6000806116c583612b3d565b90506000805b82518110156104b5576116f68382815181106116e9576116e96143e0565b6020026020010151610bc1565b61170090836143f6565b91508061170c81614409565b9150506116cb565b606060ff84161580159061172c575060ff8416600114155b156117495760405162461bcd60e51b8152600401610a55906145ae565b6000826001600160401b038111156117635761176361444f565b60405190808252806020026020018201604052801561179c57816020015b611789613f33565b8152602001906001900390816117815790505b50905060005b8381101561188257866001600160a01b031663eb0ca455878787858181106117cc576117cc6143e0565b90506020020160208101906117e191906146bd565b6040516001600160e01b031960e085901b16815260ff90921660048301526001600160401b0316602482015260440161010060405180830381865afa15801561182e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185291906145ff565b828281518110611864576118646143e0565b6020026020010181905250808061187a90614409565b9150506117a2565b5095945050505050565b6000816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118cc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610454919061457e565b6060808060ff85161580159061190a575060ff8516600114155b156119275760405162461bcd60e51b8152600401610a55906145ae565b60335460408051630be5d5ad60e31b815290516000926001600160a01b031691635f2ead689160048083019260209291908290030181865afa158015611971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119959190614432565b60405163260122e360e01b815260ff881660048201529091506119cd9086906001600160a01b038a169063260122e390602401610e2c565b94506000856001600160401b038111156119e9576119e961444f565b604051908082528060200260200182016040528015611a2257816020015b611a0f613f33565b815260200190600190039081611a075790505b5090506000866001600160401b03811115611a3f57611a3f61444f565b604051908082528060200260200182016040528015611a68578160200160208202803683370190505b5090506000876001600160401b03811115611a8557611a8561444f565b604051908082528060200260200182016040528015611aae578160200160208202803683370190505b506040516342c806ed60e01b815260ff8b1660048201529091506000906001600160a01b038c16906342c806ed9060240161010060405180830381865afa158015611afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2191906145ff565b905060005b8981108015611b3e575081516001600160401b031615155b15611ec9576000611b4f8d846132f0565b905060ff8c16158015611bea57506060830151604051639c4d1ff760e01b81526001600160a01b03918216600482015290881690639c4d1ff790602401602060405180830381865afa158015611ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcd919061457e565b81600281518110611be057611be06143e0565b6020026020010151105b15611c7957602083015160405163eb0ca45560e01b815260ff8e1660048201526001600160401b0390911660248201526001600160a01b038e169063eb0ca455906044015b61010060405180830381865afa158015611c4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7191906145ff565b925050611b26565b60ff8c166001148015611d46575080600581518110611c9a57611c9a6143e0565b602002602001015181600381518110611cb557611cb56143e0565b602002602001015182600081518110611cd057611cd06143e0565b6020026020010151611ce291906143f6565b1180611d46575080600481518110611cfc57611cfc6143e0565b602002602001015181600381518110611d1757611d176143e0565b602002602001015182600081518110611d3257611d326143e0565b6020026020010151611d4491906143f6565b115b15611d8f57602083015160405163eb0ca45560e01b815260ff8e1660048201526001600160401b0390911660248201526001600160a01b038e169063eb0ca45590604401611c2f565b82868381518110611da257611da26143e0565b602090810291909101015260608301516040516332901d0b60e21b81526001600160a01b0391821660048201529088169063ca40742c90602401602060405180830381865afa158015611df9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1d919061457e565b858381518110611e2f57611e2f6143e0565b60200260200101818152505080600481518110611e4e57611e4e6143e0565b6020026020010151848381518110611e6857611e686143e0565b602090810291909101015281611e7d81614409565b9250508c6001600160a01b031663eb0ca4558d85602001516040518363ffffffff1660e01b8152600401611c2f92919060ff9290921682526001600160401b0316602082015260400190565b8085528084528252509199909850909650945050505050565b60008060ff841615801590611efb575060ff8416600114155b15611f185760405162461bcd60e51b8152600401610a55906145ae565b60ff831615801590611f2e575060ff8316600114155b15611f705760405162461bcd60e51b8152602060048201526012602482015271696e76616c69642071756f7465207479706560701b6044820152606401610a55565b6040516342c806ed60e01b815260ff851660048201526000906001600160a01b038916906342c806ed9060240161010060405180830381865afa158015611fbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fdf91906145ff565b9050856000805b8215801590611ffe575083516001600160401b031615155b1561239b57896001600160a01b031684606001516001600160a01b0316036120a857602084015160405163eb0ca45560e01b815260ff8a1660048201526001600160401b0390911660248201526001600160a01b038c169063eb0ca4559060440161010060405180830381865afa15801561207d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a191906145ff565b9350611fe6565b60c084015160ff88161580156120c55750608085015160ff166001145b156121b9576121b68560a001518660c00151428f6001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612116573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213a919061457e565b603360009054906101000a90046001600160a01b03166001600160a01b0316632d8dea9c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561218d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b1919061457e565b6139c7565b90505b60ff881660011480156121d15750608085015160ff16155b156122c5576122c28560a001518660c00151428f6001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612222573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612246919061457e565b603360009054906101000a90046001600160a01b03166001600160a01b0316632d8dea9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612299573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122bd919061457e565b613a7f565b90505b60006122d185836132da565b90508560a001516001600160401b0316816122ec9190614597565b6122f690856143f6565b935061230281846143f6565b925061230e81866143cd565b602087015160405163eb0ca45560e01b815260ff8d1660048201526001600160401b0390911660248201529095506001600160a01b038e169063eb0ca4559060440161010060405180830381865afa15801561236e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239291906145ff565b95505050611fe6565b806000036123b35760008095509550505050506123d6565b60006123bf82846146f0565b9050806123cc858c6143cd565b9650965050505050505b9550959350505050565b6000806123ec83612b3d565b90506000805b82518110156104b55761241d838281518110612410576124106143e0565b60200260200101516129b3565b61242790836143f6565b91508061243381614409565b9150506123f2565b600061042e6104bd565b6033546040805163050774ab60e51b815290516000926001600160a01b03169163a0ee95609160048083019260209291908290030181865afa1580156114b8573d6000803e3d6000fd5b6060600061249b613b2a565b90506000805b82518110156125815760008382815181106124be576124be6143e0565b6020026020010151905060005b60018160ff161161256c57604051630ca22cbb60e21b815260ff821660048201526001600160a01b038881166024830152831690633288b2ec90604401600060405180830381865afa158015612525573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261254d9190810190614704565b5161255890856143f6565b93508061256481614792565b9150506124cb565b5050808061257990614409565b9150506124a1565b506000816001600160401b0381111561259c5761259c61444f565b60405190808252806020026020018201604052801561260b57816020015b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282526000199092019101816125ba5790505b5090506000915060005b8351811015612871576000848281518110612632576126326143e0565b6020026020010151905060005b60018160ff161161285c57604051630ca22cbb60e21b815260ff821660048201526001600160a01b03898116602483015260009190841690633288b2ec90604401600060405180830381865afa15801561269d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126c59190810190614704565b905060005b8151811015612847576000846001600160a01b031663eb0ca455858585815181106126f7576126f76143e0565b60200260200101516040518363ffffffff1660e01b815260040161273392919060ff9290921682526001600160401b0316602082015260400190565b61010060405180830381865afa158015612751573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277591906145ff565b9050604051806101000160405280866001600160a01b031681526020018484815181106127a4576127a46143e0565b60200260200101516001600160401b031681526020018560ff16815260200182606001516001600160a01b03168152602001826080015160ff1681526020018260a001516001600160401b031681526020018260c0015181526020018260e0015181525087898151811061281a5761281a6143e0565b6020026020010181905250878061283090614409565b98505050808061283f90614409565b9150506126ca565b5050808061285490614792565b91505061263f565b5050808061286990614409565b915050612615565b50949350505050565b600054610100900460ff161580801561289a5750600054600160ff909116105b806128b45750303b1580156128b4575060005460ff166001145b6129175760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a55565b6000805460ff19166001179055801561293a576000805461ff0019166101001790555b603380546001600160a01b0319166001600160a01b038416179055801561299b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006129aa826115df565b610bf383610bc1565b6000816001600160a01b0316639c5bf6336040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118cc573d6000803e3d6000fd5b600080826001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a589190614432565b6040516370a0823160e01b81526001600160a01b0386811660048301529192506000918316906370a0823190602401602060405180830381865afa158015612aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac8919061457e565b604051630233c89b60e61b8152600481018290529091506001600160a01b03851690638cf226c090602401602060405180830381865afa158015612b10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b34919061457e565b95945050505050565b603354604051631e23703160e31b81526001600160a01b03838116600483015260609260009291169063f11b818890602401600060405180830381865afa158015612b8c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612bb49190810190614827565b905060008160c00151516001600160401b03811115612bd557612bd561444f565b604051908082528060200260200182016040528015612bfe578160200160208202803683370190505b50905060005b8260c00151518110156104b55760335460c084015180516001600160a01b03909216916349d649ea91889185908110612c3f57612c3f6143e0565b60200260200101516040518363ffffffff1660e01b8152600401612c789291906001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015612c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cb99190614432565b828281518110612ccb57612ccb6143e0565b6001600160a01b039092166020928302919091019091015280612ced81614409565b915050612c04565b600080603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6f9190614432565b90506000603360009054906101000a90046001600160a01b03166001600160a01b031663a0ee95606040518163ffffffff1660e01b8152600401602060405180830381865afa158015612dc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dea9190614432565b603354604051631e23703160e31b81526001600160a01b0380881660048301529293508692600092169063f11b818890602401600060405180830381865afa158015612e3a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e629190810190614827565b6040516332901d0b60e21b81526001600160a01b03898116600483015291925060009186169063ca40742c90602401602060405180830381865afa158015612eae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ed2919061457e565b603354604051639c4d1ff760e01b81526001600160a01b038b8116600483015292935060009290911690639c4d1ff790602401602060405180830381865afa158015612f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f46919061457e565b60405163e7602b9d60e01b81526001600160a01b038b81166004830152868116602483015291925060009188169063e7602b9d90604401602060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe919061457e565b9050801580612fcd5750818311155b15612fe2576000975050505050505050610454565b603360009054906101000a90046001600160a01b03166001600160a01b031663782d2b536040518163ffffffff1660e01b8152600401602060405180830381865afa158015613035573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613059919061457e565b831061306d57965061045495505050505050565b6040516365abacad60e01b81526001600160a01b038b81166004830152600091908916906365abacad90602401602060405180830381865afa1580156130b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130db919061457e565b90506000603360009054906101000a90046001600160a01b03166001600160a01b0316638b2f81d66040518163ffffffff1660e01b8152600401602060405180830381865afa158015613132573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613156919061457e565b61316085876143cd565b61316a9084614597565b61317491906146f0565b905060008660800151603360009054906101000a90046001600160a01b03166001600160a01b031663de01c9cb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156131d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f4919061457e565b6131fe9084614597565b61320891906146f0565b604051632a72258160e01b81526001600160a01b038a81166004830152602482018390529192506000918b1690632a72258190604401602060405180830381865afa15801561325b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061327f919061457e565b90508481111561328f5784613291565b805b9e9d5050505050505050505050505050565b600080806132b184866148eb565b116132bd5760006132c0565b60015b60ff169050806132d084866146f0565b6115cc91906143f6565b60008183106132e95781610451565b5090919050565b60606000836001600160a01b0316631264bfbf84608001518560a001518660e001518760c0015161332191906143cd565b42896001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613360573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613384919061457e565b6040516001600160e01b031960e088901b16815260ff90951660048601526001600160401b03909316602485015260448401919091526064830152608482015260a401602060405180830381865afa1580156133e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613408919061457e565b90506000846001600160a01b0316638082a0b285608001518660a001518760e001518860c0015161343991906143cd565b428a6001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349c919061457e565b6040516001600160e01b031960e088901b16815260ff90951660048601526001600160401b03909316602485015260448401919091526064830152608482015260a401602060405180830381865afa1580156134fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613520919061457e565b90506000603360009054906101000a90046001600160a01b03166001600160a01b0316635f2ead686040518163ffffffff1660e01b8152600401602060405180830381865afa158015613577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359b9190614432565b90506000816001600160a01b031663257041f38760600151896001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136159190614432565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152908216602482015260006044820181905260648201819052918b16608482015260a4810187905260c481019190915260e401602060405180830381865afa158015613688573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136ac919061457e565b6040516333f5419b60e01b8152600481018690524260248201529091506000906001600160a01b038916906333f5419b90604401602060405180830381865afa1580156136fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613721919061457e565b90506000886001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015613763573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137879190614432565b60608901516040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156137d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f6919061457e565b90506000896001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015613838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061385c9190614432565b60608a0151604051636eb1769f60e11b81526001600160a01b0391821660048201528c8216602482015291169063dd62ed3e90604401602060405180830381865afa1580156138af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138d3919061457e565b60408051600680825260e08201909252919250600091906020820160c080368337019050509050878160008151811061390e5761390e6143e0565b602002602001018181525050868160018151811061392e5761392e6143e0565b602002602001018181525050848160028151811061394e5761394e6143e0565b602002602001018181525050838160038151811061396e5761396e6143e0565b602002602001018181525050828160048151811061398e5761398e6143e0565b60200260200101818152505081816005815181106139ae576139ae6143e0565b60209081029190910101529a9950505050505050505050565b6000828410613a105760405162461bcd60e51b81526020600482015260156024820152741a5b9d985b1a59081d1a5b59481a5b9d195c9d985b605a1b6044820152606401610a55565b6301e133806000613a2186866143cd565b9050600082613a30868a614597565b613a3a9190614597565b90506000613a51836001600160401b038c16614597565b613a5b8588614597565b613a6591906143f6565b9050613a7181836146f0565b9a9950505050505050505050565b6000828410613ac85760405162461bcd60e51b81526020600482015260156024820152741a5b9d985b1a59081d1a5b59481a5b9d195c9d985b605a1b6044820152606401610a55565b6301e133806000613ad986866143cd565b90506000828583613af36001600160401b038d168c614597565b613afd9190614597565b613b0791906146f0565b613b1191906146f0565b9050613b1d81896143f6565b9998505050505050505050565b60606000603360009054906101000a90046001600160a01b03166001600160a01b03166376d708d76040518163ffffffff1660e01b8152600401600060405180830381865afa158015613b81573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ba991908101906144e0565b90506000805b8251811015613c835760335483516000916001600160a01b03169063f11b818890869085908110613be257613be26143e0565b60200260200101516040518263ffffffff1660e01b8152600401613c1591906001600160a01b0391909116815260200190565b600060405180830381865afa158015613c32573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613c5a9190810190614827565b90508060c001515183613c6d91906143f6565b9250508080613c7b90614409565b915050613baf565b506000816001600160401b03811115613c9e57613c9e61444f565b604051908082528060200260200182016040528015613cc7578160200160208202803683370190505b5090506000915060005b8351811015613f29576000848281518110613cee57613cee6143e0565b6020908102919091010151603354604051631e23703160e31b81526001600160a01b0380841660048301529293506000929091169063f11b818890602401600060405180830381865afa158015613d49573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613d719190810190614827565b60c081015190915060005b8151811015613f1257818181518110613d9757613d976143e0565b6020026020010151421015613f005760335482516000916001600160a01b0316906349d649ea908790869086908110613dd257613dd26143e0565b60200260200101516040518363ffffffff1660e01b8152600401613e0b9291906001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015613e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e4c9190614432565b60335460405163bc9574ad60e01b81526001600160a01b03808416600483015292935091169063bc9574ad90602401602060405180830381865afa158015613e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ebc91906148ff565b613ec65750613f00565b80878981518110613ed957613ed96143e0565b6001600160a01b039092166020928302919091019091015287613efb81614409565b985050505b80613f0a81614409565b915050613d7c565b505050508080613f2190614409565b915050613cd1565b5090815292915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6001600160a01b0381168114613f8c57600080fd5b50565b60008060408385031215613fa257600080fd5b8235613fad81613f77565b91506020830135613fbd81613f77565b809150509250929050565b600060208284031215613fda57600080fd5b81356116b281613f77565b60008060008060808587031215613ffb57600080fd5b843561400681613f77565b9350602085013561401681613f77565b9250604085013561402681613f77565b9396929550929360600135925050565b60ff81168114613f8c57600080fd5b60008060006060848603121561405a57600080fd5b833561406581613f77565b9250602084013561407581614036565b929592945050506040919091013590565b600081518084526020808501945080840160005b8381101561411d57815180516001600160401b039081168952848201518116858a01526040808301518216908a01526060808301516001600160a01b0316908a015260808083015160ff16908a015260a0808301519091169089015260c0808201519089015260e09081015190880152610100909601959082019060010161409a565b509495945050505050565b600081518084526020808501945080840160005b8381101561411d5781518752958201959082019060010161413c565b60608152600061416b6060830186614086565b828103602084015261417d8186614128565b905082810360408401526141918185614128565b9695505050505050565b600080600080606085870312156141b157600080fd5b84356141bc81613f77565b935060208501356141cc81614036565b925060408501356001600160401b03808211156141e857600080fd5b818701915087601f8301126141fc57600080fd5b81358181111561420b57600080fd5b8860208260051b850101111561422057600080fd5b95989497505060200194505050565b6020815260006104516020830184614086565b600080600080600060a0868803121561425a57600080fd5b853561426581613f77565b9450602086013561427581613f77565b935060408601359250606086013561428c81614036565b9150608086013561429c81614036565b809150509295509295909350565b602080825282518282018190526000919060409081850190868401855b8281101561435d57815180516001600160a01b03168552868101516001600160401b0316878601528581015160ff1686860152606080820151614314828801826001600160a01b03169052565b505060808181015160ff169086015260a0808201516001600160401b03169086015260c0808201519086015260e0908101519085015261010090930192908501906001016142c7565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b818110156143ab5783516001600160a01b031683529284019291840191600101614386565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610454576104546143b7565b634e487b7160e01b600052603260045260246000fd5b80820180821115610454576104546143b7565b60006001820161441b5761441b6143b7565b5060010190565b805161442d81613f77565b919050565b60006020828403121561444457600080fd5b81516116b281613f77565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156144875761448761444f565b60405290565b604051601f8201601f191681016001600160401b03811182821017156144b5576144b561444f565b604052919050565b60006001600160401b038211156144d6576144d661444f565b5060051b60200190565b600060208083850312156144f357600080fd5b82516001600160401b0381111561450957600080fd5b8301601f8101851361451a57600080fd5b805161452d614528826144bd565b61448d565b81815260059190911b8201830190838101908783111561454c57600080fd5b928401925b8284101561457357835161456481613f77565b82529284019290840190614551565b979650505050505050565b60006020828403121561459057600080fd5b5051919050565b8082028115828204841417610454576104546143b7565b6020808252600c908201526b696e76616c6964207369646560a01b604082015260600190565b6001600160401b0381168114613f8c57600080fd5b805161442d816145d4565b805161442d81614036565b600061010080838503121561461357600080fd5b604051908101906001600160401b03821181831017156146355761463561444f565b8160405283519150614646826145d4565b818152614655602085016145e9565b6020820152614666604085016145e9565b604082015261467760608501614422565b6060820152614688608085016145f4565b608082015261469960a085016145e9565b60a082015260c084015160c082015260e084015160e0820152809250505092915050565b6000602082840312156146cf57600080fd5b81356116b2816145d4565b634e487b7160e01b600052601260045260246000fd5b6000826146ff576146ff6146da565b500490565b6000602080838503121561471757600080fd5b82516001600160401b0381111561472d57600080fd5b8301601f8101851361473e57600080fd5b805161474c614528826144bd565b81815260059190911b8201830190838101908783111561476b57600080fd5b928401925b82841015614573578351614783816145d4565b82529284019290840190614770565b600060ff821660ff81036147a8576147a86143b7565b60010192915050565b8051801515811461442d57600080fd5b600082601f8301126147d257600080fd5b815160206147e2614528836144bd565b82815260059290921b8401810191818101908684111561480157600080fd5b8286015b8481101561481c5780518352918301918301614805565b509695505050505050565b60006020828403121561483957600080fd5b81516001600160401b038082111561485057600080fd5b9083019060e0828603121561486457600080fd5b61486c614465565b614875836147b1565b8152614883602084016147b1565b602082015261489460408401614422565b60408201526148a560608401614422565b60608201526080830151608082015260a083015160a082015260c0830151828111156148d057600080fd5b6148dc878286016147c1565b60c08301525095945050505050565b6000826148fa576148fa6146da565b500690565b60006020828403121561491157600080fd5b610451826147b156fea26469706673582212204167f3c053f573e0d9bddf09e288ce33cac4b2bd704c375e1844bbdfad13d84264736f6c63430008120033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in GLMR
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.