Overview
GLMR Balance
GLMR Value
$0.13 (@ $0.02/GLMR)More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 270 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| _reduce Reserves | 4041681 | 927 days ago | IN | 0 GLMR | 0.01707727 | ||||
| Mint | 4041667 | 927 days ago | IN | 37.5 GLMR | 0.01823652 | ||||
| _reduce Reserves | 4040717 | 927 days ago | IN | 0 GLMR | 0.01131621 | ||||
| Borrow | 4030215 | 928 days ago | IN | 0 GLMR | 0.060831 | ||||
| Borrow | 4030110 | 928 days ago | IN | 0 GLMR | 0.04306633 | ||||
| Redeem | 3495522 | 1004 days ago | IN | 0 GLMR | 0.0360378 | ||||
| Redeem | 1580600 | 1278 days ago | IN | 0 GLMR | 0.00996202 | ||||
| Borrow | 1566999 | 1280 days ago | IN | 0 GLMR | 0.03380386 | ||||
| Redeem | 1528142 | 1285 days ago | IN | 0 GLMR | 0.0206518 | ||||
| Redeem Underlyin... | 1528120 | 1286 days ago | IN | 0 GLMR | 0.0234333 | ||||
| Redeem Underlyin... | 1324372 | 1315 days ago | IN | 0 GLMR | 0.0234333 | ||||
| Redeem Underlyin... | 1324365 | 1315 days ago | IN | 0 GLMR | 0.0234333 | ||||
| Redeem Underlyin... | 1301158 | 1319 days ago | IN | 0 GLMR | 0.0237294 | ||||
| Mint | 1301151 | 1319 days ago | IN | 700 GLMR | 0.0115546 | ||||
| Redeem Underlyin... | 1301138 | 1319 days ago | IN | 0 GLMR | 0.0237294 | ||||
| Redeem Underlyin... | 1301131 | 1319 days ago | IN | 0 GLMR | 0.04033998 | ||||
| Redeem Underlyin... | 1301115 | 1319 days ago | IN | 0 GLMR | 0.03983661 | ||||
| Redeem Underlyin... | 1300967 | 1319 days ago | IN | 0 GLMR | 0.03983457 | ||||
| Redeem Underlyin... | 1300958 | 1319 days ago | IN | 0 GLMR | 0.0234333 | ||||
| Redeem Underlyin... | 1300946 | 1319 days ago | IN | 0 GLMR | 0.0234333 | ||||
| Borrow | 1293355 | 1320 days ago | IN | 0 GLMR | 0.16763142 | ||||
| Borrow | 1291507 | 1320 days ago | IN | 0 GLMR | 0.0231016 | ||||
| Borrow | 1291266 | 1320 days ago | IN | 0 GLMR | 0.1553574 | ||||
| Borrow | 1290003 | 1321 days ago | IN | 0 GLMR | 0.15534948 | ||||
| Borrow | 1289967 | 1321 days ago | IN | 0 GLMR | 0.1553574 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 1567010 | 1280 days ago | 67.00090058 GLMR | ||||
| 1423221 | 1301 days ago | 3,234.25448337 GLMR | ||||
| 1304521 | 1318 days ago | 601.1408866 GLMR | ||||
| 1298123 | 1319 days ago | 150.8 GLMR | ||||
| 1298093 | 1319 days ago | 3,850 GLMR | ||||
| 1293361 | 1320 days ago | 20,000.00903921 GLMR | ||||
| 1291897 | 1320 days ago | 10,000.34523343 GLMR | ||||
| 1290830 | 1320 days ago | 7,526.65999999 GLMR | ||||
| 1290799 | 1320 days ago | 16,476 GLMR | ||||
| 1287295 | 1321 days ago | 10,023 GLMR | ||||
| 1284564 | 1321 days ago | 21,980 GLMR | ||||
| 1280854 | 1322 days ago | 25,998 GLMR | ||||
| 1278553 | 1322 days ago | 19,047 GLMR | ||||
| 1277538 | 1322 days ago | 10,000 GLMR | ||||
| 1275035 | 1323 days ago | 11,960 GLMR | ||||
| 1273654 | 1323 days ago | 22,624 GLMR | ||||
| 1271996 | 1323 days ago | 12,000 GLMR | ||||
| 1268019 | 1324 days ago | 2,500 GLMR | ||||
| 1267331 | 1324 days ago | 14,000 GLMR | ||||
| 1266515 | 1324 days ago | 155 GLMR | ||||
| 1266181 | 1324 days ago | 16,990 GLMR | ||||
| 1266167 | 1324 days ago | 12,202 GLMR | ||||
| 1265905 | 1324 days ago | 5,392.73918495 GLMR | ||||
| 1264005 | 1324 days ago | 12,800 GLMR | ||||
| 1262902 | 1325 days ago | 13,000 GLMR |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ONativeDelegator
Compiler Version
v0.5.16+commit.9c3226ce
Contract Source Code (Solidity)
/**
*Submitted for verification at moonbeam.moonscan.io on 2022-02-04
*/
pragma solidity ^0.5.16;
/**
* @title Compound's InterestRateModel Interface
* @author Compound
*/
contract InterestRateModel {
/// @notice Indicator that this is an InterestRateModel contract (for inspection)
bool public constant isInterestRateModel = true;
/**
* @notice Calculates the current borrow interest rate per block
* @param cash The total amount of cash the market has
* @param borrows The total amount of borrows the market has outstanding
* @param reserves The total amount of reserves the market has
* @return The borrow rate per block (as a percentage, and scaled by 1e18)
*/
function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint);
/**
* @notice Calculates the current supply interest rate per block
* @param cash The total amount of cash the market has
* @param borrows The total amount of borrows the market has outstanding
* @param reserves The total amount of reserves the market has
* @param reserveFactorMantissa The current reserve factor the market has
* @return The supply rate per block (as a percentage, and scaled by 1e18)
*/
function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint);
}
contract ComptrollerErrorReporter {
enum Error {
NO_ERROR,
UNAUTHORIZED,
COMPTROLLER_MISMATCH,
INSUFFICIENT_SHORTFALL,
INSUFFICIENT_LIQUIDITY,
INVALID_CLOSE_FACTOR,
INVALID_COLLATERAL_FACTOR,
INVALID_LIQUIDATION_INCENTIVE,
MARKET_NOT_ENTERED, // no longer possible
MARKET_NOT_LISTED,
MARKET_ALREADY_LISTED,
MATH_ERROR,
NONZERO_BORROW_BALANCE,
PRICE_ERROR,
REJECTION,
SNAPSHOT_ERROR,
TOO_MANY_ASSETS,
TOO_MUCH_REPAY,
// OLA_ADDITIONS : All Enums from here
NOT_IN_MARKET,
TOO_LITTLE_BORROW,
IN_FRESH_LIQUIDATION_LIMITED_PERIOD,
INVALID_LIQUIDATION_FACTOR,
BORROWED_AGAINST_FAILED,
TOTAL_BORROWED_AGAINST_TOO_HIGH,
TOO_MUCH_COLLATERAL_ACTIVATION,
// V0.02
NOT_APPROVED_TO_MINT,
NOT_APPROVED_TO_BORROW
}
enum FailureInfo {
ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
EXIT_MARKET_BALANCE_OWED,
EXIT_MARKET_REJECTION,
SET_CLOSE_FACTOR_OWNER_CHECK,
SET_CLOSE_FACTOR_VALIDATION,
SET_COLLATERAL_FACTOR_OWNER_CHECK,
SET_COLLATERAL_FACTOR_NO_EXISTS,
SET_COLLATERAL_FACTOR_VALIDATION,
SET_COLLATERAL_FACTOR_WITHOUT_PRICE,
SET_IMPLEMENTATION_OWNER_CHECK,
SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,
SET_LIQUIDATION_INCENTIVE_VALIDATION,
SET_MAX_ASSETS_OWNER_CHECK,
SET_PENDING_ADMIN_OWNER_CHECK,
SET_PENDING_IMPLEMENTATION_OWNER_CHECK,
SET_PRICE_ORACLE_OWNER_CHECK,
SUPPORT_MARKET_EXISTS,
SUPPORT_MARKET_OWNER_CHECK,
SET_PAUSE_GUARDIAN_OWNER_CHECK,
// OLA_ADDITIONS : All Enums from here
SET_LIQUIDATION_INCENTIVE_NO_EXISTS,
SET_LIQUIDATION_INCENTIVE_WITHOUT_PRICE,
SET_LIQUIDATION_FACTOR_OWNER_CHECK,
SET_LIQUIDATION_FACTOR_NO_EXISTS,
SET_LIQUIDATION_FACTOR_VALIDATION,
SET_LIQUIDATION_FACTOR_WITHOUT_PRICE,
SET_LIQUIDATION_FACTOR_LOWER_THAN_COLLATERAL_FACTOR,
SET_LIQUIDATION_FACTOR_LOWER_THAN_EXISTING_FACTOR,
SET_COLLATERAL_FACTOR_HIGHER_THAN_LIQUIDATION_FACTOR,
SET_RAIN_MAKER_OWNER_CHECK,
ENTER_MARKET_NOT_ALLOWED,
UPDATE_LN_VERSION_ADMIN_OWNER_CHECK,
// V0.002
SET_BOUNCER_OWNER_CHECK,
SET_LIMIT_MINTING_OWNER_CHECK,
SET_LIMIT_BORROWING_OWNER_CHECK,
SET_MIN_BORROW_AMOUNT_USD_OWNER_CHECK,
SUPPORT_NEW_MARKET_OWNER_CHECK,
SUPPORT_NEW_MARKET_COMBINATION_CHECK
}
/**
* @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
* contract-specific code that enables us to report opaque error codes from upgradeable contracts.
**/
event Failure(uint error, uint info, uint detail);
/**
* @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
*/
function fail(Error err, FailureInfo info) internal returns (uint) {
emit Failure(uint(err), uint(info), 0);
return uint(err);
}
/**
* @dev use this when reporting an opaque error from an upgradeable collaborator contract
*/
function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
emit Failure(uint(err), uint(info), opaqueError);
return uint(err);
}
}
contract TokenErrorReporter {
enum Error {
NO_ERROR,
UNAUTHORIZED,
BAD_INPUT,
COMPTROLLER_REJECTION,
COMPTROLLER_CALCULATION_ERROR,
INTEREST_RATE_MODEL_ERROR,
INVALID_ACCOUNT_PAIR,
INVALID_CLOSE_AMOUNT_REQUESTED,
INVALID_COLLATERAL_FACTOR,
MATH_ERROR,
MARKET_NOT_FRESH,
MARKET_NOT_LISTED,
TOKEN_INSUFFICIENT_ALLOWANCE,
TOKEN_INSUFFICIENT_BALANCE,
TOKEN_INSUFFICIENT_CASH,
TOKEN_TRANSFER_IN_FAILED,
TOKEN_TRANSFER_OUT_FAILED,
// OLA_ADDITIONS : All Enums from here
BAD_SYSTEM_PARAMS
}
/*
* Notice: FailureInfo (but not Error) is kept in alphabetical order
* This is because FailureInfo grows significantly faster, and
* the order of Error has some meaning, while the order of FailureInfo
* is entirely arbitrary.
*/
enum FailureInfo {
ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,
ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED,
ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,
ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,
ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,
ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,
BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
BORROW_ACCRUE_INTEREST_FAILED,
BORROW_CASH_NOT_AVAILABLE,
BORROW_FRESHNESS_CHECK,
BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
BORROW_MARKET_NOT_LISTED,
BORROW_COMPTROLLER_REJECTION,
LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,
LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,
LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,
LIQUIDATE_COMPTROLLER_REJECTION,
LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,
LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,
LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,
LIQUIDATE_FRESHNESS_CHECK,
LIQUIDATE_LIQUIDATOR_IS_BORROWER,
LIQUIDATE_REPAY_BORROW_FRESH_FAILED,
LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,
LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,
LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,
LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,
LIQUIDATE_SEIZE_TOO_MUCH,
MINT_ACCRUE_INTEREST_FAILED,
MINT_COMPTROLLER_REJECTION,
MINT_EXCHANGE_CALCULATION_FAILED,
MINT_EXCHANGE_RATE_READ_FAILED,
MINT_FRESHNESS_CHECK,
MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
MINT_TRANSFER_IN_FAILED,
MINT_TRANSFER_IN_NOT_POSSIBLE,
REDEEM_ACCRUE_INTEREST_FAILED,
REDEEM_COMPTROLLER_REJECTION,
REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,
REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,
REDEEM_EXCHANGE_RATE_READ_FAILED,
REDEEM_FRESHNESS_CHECK,
REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
REDEEM_TRANSFER_OUT_NOT_POSSIBLE,
REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,
REDUCE_RESERVES_ADMIN_CHECK,
REDUCE_RESERVES_CASH_NOT_AVAILABLE,
REDUCE_RESERVES_FRESH_CHECK,
REDUCE_RESERVES_VALIDATION,
REPAY_BEHALF_ACCRUE_INTEREST_FAILED,
REPAY_BORROW_ACCRUE_INTEREST_FAILED,
REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_COMPTROLLER_REJECTION,
REPAY_BORROW_FRESHNESS_CHECK,
REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,
SET_COLLATERAL_FACTOR_OWNER_CHECK,
SET_COLLATERAL_FACTOR_VALIDATION,
SET_COMPTROLLER_OWNER_CHECK,
SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED,
SET_INTEREST_RATE_MODEL_FRESH_CHECK,
SET_INTEREST_RATE_MODEL_OWNER_CHECK,
SET_MAX_ASSETS_OWNER_CHECK,
SET_ORACLE_MARKET_NOT_LISTED,
SET_PENDING_ADMIN_OWNER_CHECK,
SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,
SET_RESERVE_FACTOR_ADMIN_CHECK,
SET_RESERVE_FACTOR_FRESH_CHECK,
SET_RESERVE_FACTOR_BOUNDS_CHECK,
TRANSFER_COMPTROLLER_REJECTION,
TRANSFER_NOT_ALLOWED,
TRANSFER_NOT_ENOUGH,
TRANSFER_TOO_MUCH,
ADD_RESERVES_ACCRUE_INTEREST_FAILED,
ADD_RESERVES_FRESH_CHECK,
ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE,
// OLA_ADDITIONS : All Enums from here
REDUCE_RESERVES_OLA_PART_CALCULATION_FAILED
}
/**
* @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
* contract-specific code that enables us to report opaque error codes from upgradeable contracts.
**/
event Failure(uint error, uint info, uint detail);
/**
* @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
*/
function fail(Error err, FailureInfo info) internal returns (uint) {
emit Failure(uint(err), uint(info), 0);
return uint(err);
}
/**
* @dev use this when reporting an opaque error from an upgradeable collaborator contract
*/
function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
emit Failure(uint(err), uint(info), opaqueError);
return uint(err);
}
}
/**
* @title Careful Math
* @author Compound
* @notice Derived from OpenZeppelin's SafeMath library
* https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol
*/
contract CarefulMath {
/**
* @dev Possible error codes that we can return
*/
enum MathError {
NO_ERROR,
DIVISION_BY_ZERO,
INTEGER_OVERFLOW,
INTEGER_UNDERFLOW
}
/**
* @dev Multiplies two numbers, returns an error on overflow.
*/
function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (a == 0) {
return (MathError.NO_ERROR, 0);
}
uint c = a * b;
if (c / a != b) {
return (MathError.INTEGER_OVERFLOW, 0);
} else {
return (MathError.NO_ERROR, c);
}
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (b == 0) {
return (MathError.DIVISION_BY_ZERO, 0);
}
return (MathError.NO_ERROR, a / b);
}
/**
* @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
*/
function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (b <= a) {
return (MathError.NO_ERROR, a - b);
} else {
return (MathError.INTEGER_UNDERFLOW, 0);
}
}
/**
* @dev Adds two numbers, returns an error on overflow.
*/
function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
uint c = a + b;
if (c >= a) {
return (MathError.NO_ERROR, c);
} else {
return (MathError.INTEGER_OVERFLOW, 0);
}
}
/**
* @dev add a and b and then subtract c
*/
function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {
(MathError err0, uint sum) = addUInt(a, b);
if (err0 != MathError.NO_ERROR) {
return (err0, 0);
}
return subUInt(sum, c);
}
}
/**
* @title Exponential module for storing fixed-precision decimals
* @author Compound
* @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
* Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
* `Exp({mantissa: 5100000000000000000})`.
*/
contract ExponentialNoError {
uint constant expScale = 1e18;
uint constant doubleScale = 1e36;
uint constant halfExpScale = expScale/2;
uint constant mantissaOne = expScale;
struct Exp {
uint mantissa;
}
struct Double {
uint mantissa;
}
/**
* @dev Truncates the given exp to a whole number value.
* For example, truncate(Exp{mantissa: 15 * expScale}) = 15
*/
function truncate(Exp memory exp) pure internal returns (uint) {
// Note: We are not using careful Math here as we're performing a division that cannot fail
return exp.mantissa / expScale;
}
/**
* @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
*/
function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {
Exp memory product = mul_(a, scalar);
return truncate(product);
}
/**
* @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
*/
function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {
Exp memory product = mul_(a, scalar);
return add_(truncate(product), addend);
}
/**
* @dev Checks if first Exp is less than second Exp.
*/
function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa < right.mantissa;
}
/**
* @dev Checks if left Exp <= right Exp.
*/
function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa <= right.mantissa;
}
/**
* @dev Checks if left Exp > right Exp.
*/
function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
return left.mantissa > right.mantissa;
}
/**
* @dev returns true if Exp is exactly zero
*/
function isZeroExp(Exp memory value) pure internal returns (bool) {
return value.mantissa == 0;
}
function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {
require(n < 2**224, errorMessage);
return uint224(n);
}
function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {
require(n < 2**32, errorMessage);
return uint32(n);
}
function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
return Exp({mantissa: add_(a.mantissa, b.mantissa)});
}
function add_(Double memory a, Double memory b) pure internal returns (Double memory) {
return Double({mantissa: add_(a.mantissa, b.mantissa)});
}
function add_(uint a, uint b) pure internal returns (uint) {
return add_(a, b, "addition overflow");
}
function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
uint c = a + b;
require(c >= a, errorMessage);
return c;
}
function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
}
function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {
return Double({mantissa: sub_(a.mantissa, b.mantissa)});
}
function sub_(uint a, uint b) pure internal returns (uint) {
return sub_(a, b, "subtraction underflow");
}
function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
require(b <= a, errorMessage);
return a - b;
}
function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
}
function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {
return Exp({mantissa: mul_(a.mantissa, b)});
}
function mul_(uint a, Exp memory b) pure internal returns (uint) {
return mul_(a, b.mantissa) / expScale;
}
function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {
return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
}
function mul_(Double memory a, uint b) pure internal returns (Double memory) {
return Double({mantissa: mul_(a.mantissa, b)});
}
function mul_(uint a, Double memory b) pure internal returns (uint) {
return mul_(a, b.mantissa) / doubleScale;
}
function mul_(uint a, uint b) pure internal returns (uint) {
return mul_(a, b, "multiplication overflow");
}
function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
if (a == 0 || b == 0) {
return 0;
}
uint c = a * b;
require(c / a == b, errorMessage);
return c;
}
function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
}
function div_(Exp memory a, uint b) pure internal returns (Exp memory) {
return Exp({mantissa: div_(a.mantissa, b)});
}
function div_(uint a, Exp memory b) pure internal returns (uint) {
return div_(mul_(a, expScale), b.mantissa);
}
function div_(Double memory a, Double memory b) pure internal returns (Double memory) {
return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
}
function div_(Double memory a, uint b) pure internal returns (Double memory) {
return Double({mantissa: div_(a.mantissa, b)});
}
function div_(uint a, Double memory b) pure internal returns (uint) {
return div_(mul_(a, doubleScale), b.mantissa);
}
function div_(uint a, uint b) pure internal returns (uint) {
return div_(a, b, "divide by zero");
}
function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
require(b > 0, errorMessage);
return a / b;
}
function fraction(uint a, uint b) pure internal returns (Double memory) {
return Double({mantissa: div_(mul_(a, doubleScale), b)});
}
}
/**
* @title Exponential module for storing fixed-precision decimals
* @author Compound
* @dev Legacy contract for compatibility reasons with existing contracts that still use MathError
* @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
* Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
* `Exp({mantissa: 5100000000000000000})`.
*/
contract Exponential is CarefulMath, ExponentialNoError {
/**
* @dev Creates an exponential from numerator and denominator values.
* Note: Returns an error if (`num` * 10e18) > MAX_INT,
* or if `denom` is zero.
*/
function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {
(MathError err0, uint scaledNumerator) = mulUInt(num, expScale);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
(MathError err1, uint rational) = divUInt(scaledNumerator, denom);
if (err1 != MathError.NO_ERROR) {
return (err1, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: rational}));
}
/**
* @dev Adds two exponentials, returning a new exponential.
*/
function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError error, uint result) = addUInt(a.mantissa, b.mantissa);
return (error, Exp({mantissa: result}));
}
/**
* @dev Subtracts two exponentials, returning a new exponential.
*/
function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError error, uint result) = subUInt(a.mantissa, b.mantissa);
return (error, Exp({mantissa: result}));
}
/**
* @dev Multiply an Exp by a scalar, returning a new Exp.
*/
function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
(MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));
}
/**
* @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
*/
function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {
(MathError err, Exp memory product) = mulScalar(a, scalar);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return (MathError.NO_ERROR, truncate(product));
}
/**
* @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
*/
function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {
(MathError err, Exp memory product) = mulScalar(a, scalar);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return addUInt(truncate(product), addend);
}
/**
* @dev Divide an Exp by a scalar, returning a new Exp.
*/
function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
(MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));
}
/**
* @dev Divide a scalar by an Exp, returning a new Exp.
*/
function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {
/*
We are doing this as:
getExp(mulUInt(expScale, scalar), divisor.mantissa)
How it works:
Exp = a / b;
Scalar = s;
`s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
*/
(MathError err0, uint numerator) = mulUInt(expScale, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return getExp(numerator, divisor.mantissa);
}
/**
* @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.
*/
function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {
(MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
if (err != MathError.NO_ERROR) {
return (err, 0);
}
return (MathError.NO_ERROR, truncate(fraction));
}
/**
* @dev Multiplies two exponentials, returning a new exponential.
*/
function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
(MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
// We add half the scale before dividing so that we get rounding instead of truncation.
// See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
// Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
(MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);
if (err1 != MathError.NO_ERROR) {
return (err1, Exp({mantissa: 0}));
}
(MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);
// The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
assert(err2 == MathError.NO_ERROR);
return (MathError.NO_ERROR, Exp({mantissa: product}));
}
/**
* @dev Multiplies two exponentials given their mantissas, returning a new exponential.
*/
function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {
return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));
}
/**
* @dev Multiplies three exponentials, returning a new exponential.
*/
function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {
(MathError err, Exp memory ab) = mulExp(a, b);
if (err != MathError.NO_ERROR) {
return (err, ab);
}
return mulExp(ab, c);
}
/**
* @dev Divides two exponentials, returning a new exponential.
* (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
* which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
*/
function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
return getExp(a.mantissa, b.mantissa);
}
}
/**
* @title ERC 20 Token Standard Interface
* https://eips.ethereum.org/EIPS/eip-20
*/
interface EIP20Interface {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
/**
* @notice Get the total number of tokens in circulation
* @return The supply of tokens
*/
function totalSupply() external view returns (uint256);
/**
* @notice Gets the balance of the specified address
* @param owner The address from which the balance will be retrieved
* @return The balance
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint256 amount) external returns (bool success);
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(address src, address dst, uint256 amount) external returns (bool success);
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) external returns (bool success);
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(address owner, address spender) external view returns (uint256 remaining);
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
}
interface RegistryForOToken {
function isSupportedInterestRateModel(address interestRateModel) external returns (bool);
function olaBankAddress() external view returns (address payable);
function blocksBased() external view returns (bool);
}
interface ComptrollerForOToken {
function adminBankAddress() external view returns (address payable);
}
contract ComptrollerInterface {
/// @notice Indicator that this is a Comptroller contract (for inspection)
bool public constant isComptroller = true;
/*** OLA_ADDITIONS : registry getter ***/
/*** Registry ***/
function getRegistry() external view returns (address);
/*** Assets supported by the Comptroller ***/
function getAllMarkets() public view returns (CToken[] memory);
/*** OLA_ADDITIONS : peripheral checkers ***/
/*** Peripherals ***/
function hasRainMaker() view public returns (bool);
function hasBouncer() view public returns (bool);
/*** Assets You Are In ***/
function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);
function exitMarket(address cToken) external returns (uint);
/*** Policy Hooks ***/
function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint);
function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external;
function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint);
function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external;
function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint);
function borrowVerify(address cToken, address borrower, uint borrowAmount) external;
function repayBorrowAllowed(
address cToken,
address payer,
address borrower,
uint repayAmount) external returns (uint);
function repayBorrowVerify(
address cToken,
address payer,
address borrower,
uint repayAmount,
uint borrowerIndex) external;
function liquidateBorrowAllowed(
address cTokenBorrowed,
address cTokenCollateral,
address liquidator,
address borrower,
uint repayAmount) external returns (uint);
function liquidateBorrowVerify(
address cTokenBorrowed,
address cTokenCollateral,
address liquidator,
address borrower,
uint repayAmount,
uint seizeTokens) external;
function seizeAllowed(
address cTokenCollateral,
address cTokenBorrowed,
address liquidator,
address borrower,
uint seizeTokens) external returns (uint);
function seizeVerify(
address cTokenCollateral,
address cTokenBorrowed,
address liquidator,
address borrower,
uint seizeTokens) external;
function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint);
function transferVerify(address cToken, address src, address dst, uint transferTokens) external;
/*** Liquidity/Liquidation Calculations ***/
function liquidateCalculateSeizeTokens(
address cTokenBorrowed,
address cTokenCollateral,
uint repayAmount) external view returns (uint, uint);
}
/**
* @title EIP20NonStandardInterface
* @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
* See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
interface EIP20NonStandardInterface {
/**
* @notice Get the total number of tokens in circulation
* @return The supply of tokens
*/
function totalSupply() external view returns (uint256);
/**
* @notice Gets the balance of the specified address
* @param owner The address from which the balance will be retrieved
* @return The balance
*/
function balanceOf(address owner) external view returns (uint256 balance);
///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
*/
function transfer(address dst, uint256 amount) external;
///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
*/
function transferFrom(address src, address dst, uint256 amount) external;
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) external returns (bool success);
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent
*/
function allowance(address owner, address spender) external view returns (uint256 remaining);
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
}
/**
* OLA_ADDITIONS : This base admin storage.
*/
contract CTokenAdminStorage {
/**
* @notice Administrator for this contract
*/
address payable public admin;
/**
* @notice Pending administrator for this contract
*/
address payable public pendingAdmin;
/**
* @notice Contract which oversees inter-cToken operations
*/
ComptrollerInterface public comptroller;
/**
* @notice Implementation address for this contract
*/
address public implementation;
// OLA_ADDITIONS : Contract hash name
bytes32 public contractNameHash;
}
/**
* @notice DO NOT ADD ANY MORE STORAGE VARIABLES HERE (add them to their respective type storage)
*/
contract CTokenStorage is CTokenAdminStorage {
/**
* @dev Guard variable for re-entrancy checks
*/
bool internal _notEntered;
/**
* @notice EIP-20 token name for this token
*/
string public name;
/**
* @notice EIP-20 token symbol for this token
*/
string public symbol;
/**
* @notice EIP-20 token decimals for this token
*/
uint8 public decimals;
/**
* @notice Underlying asset for this CToken
*/
address public underlying;
// @notice Indicates if the calculations should be blocks or time based
bool public blocksBased;
/**
* @notice Model which tells what the current interest rate should be
*/
InterestRateModel public interestRateModel;
/**
* @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)
*/
uint internal initialExchangeRateMantissa;
/**
* @notice Fraction of interest currently set aside for reserves
*/
uint public reserveFactorMantissa;
/**
* @notice Block number that interest was last accrued at
*/
uint public accrualBlockNumber;
/**
* @notice Block number that interest was last accrued at
*/
uint public accrualBlockTimestamp;
/**
* @notice Accumulator of the total earned interest rate since the opening of the market
*/
uint public borrowIndex;
/**
* @notice Total amount of outstanding borrows of the underlying in this market
*/
uint public totalBorrows;
/**
* OLA_ADDITIONS : Removed option to 'add reserves' as it makes no sense when reducing reserves
* sends a part to Ola Bank.
* @notice Total amount of reserves of the underlying held in this market
*/
uint public totalReserves;
/**
* @notice Total number of tokens in circulation
*/
uint public totalSupply;
/**
* @notice Official record of token balances for each account
*/
mapping (address => uint) internal accountTokens;
/**
* @notice Approved token transfer amounts on behalf of others
*/
mapping (address => mapping (address => uint)) internal transferAllowances;
/**
* @notice Container for borrow balance information
* @member principal Total balance (with accrued interest), after applying the most recent balance-changing action
* @member interestIndex Global borrowIndex as of the most recent balance-changing action
*/
struct BorrowSnapshot {
uint principal;
uint interestIndex;
}
/**
* @notice Mapping of account addresses to outstanding borrow balances
*/
mapping(address => BorrowSnapshot) internal accountBorrows;
// IMPORTANT : DO NOT ADD ANY MORE STORAGE VARIABLES HERE (add them to their respective type storage)
}
contract CTokenDelegatorInterface {
/*** Implementation Events ***/
/**
* @notice Emitted when implementation is changed
*/
event NewImplementation(address indexed oldImplementation, address indexed newImplementation);
/**
* @notice Emitted when implementation is not changed under a system version update
*/
event ImplementationDidNotChange(address indexed implementation);
/*** Implementation functions ***/
// OLA_ADDITIONS : Update implementation from the Registry
function updateImplementationFromRegistry(bool allowResign, bytes calldata becomeImplementationData) external returns (bool);
}
contract CTokenInterface {
// OLA_ADDITIONS : "Underlying field"
address constant public nativeCoinUnderlying = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
/**
* OLA_ADDITIONS : This field
* @notice This value is hard coded to 0.5 (50% for the Ola ecosystem and the LeN owner each)
*/
uint constant public olaReserveFactorMantissa = 0.5e18;
/**
* @notice Indicator that this is a CToken contract (for inspection)
*/
bool public constant isCToken = true;
/**
* @notice Maximum borrow rate that can ever be applied (.0005% / block)
*/
uint internal constant borrowRateMaxMantissa = 0.0005e16;
/**
* @notice Maximum fraction of interest that can be set aside for reserves
*/
uint internal constant reserveFactorMaxMantissa = 0.3e18;
/**
* OLA_ADDITIONS : This value
* @notice Minimum fraction of interest that can be set aside for reserves
*/
uint internal constant reserveFactorMinMantissa = 0.05e18;
/*** Market Events ***/
/**
* @notice Event emitted when interest is accrued
*/
event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows);
/**
* @notice Event emitted when tokens are minted
*/
event Mint(address minter, uint mintAmount, uint mintTokens);
/**
* @notice Event emitted when tokens are redeemed
*/
event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);
/**
* @notice Event emitted when underlying is borrowed
*/
event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows);
/**
* @notice Event emitted when a borrow is repaid
*/
event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows);
/**
* @notice Event emitted when a borrow is liquidated
*/
event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens);
/*** Admin Events ***/
/**
* @notice Event emitted when pendingAdmin is changed
*/
event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);
/**
* @notice Event emitted when pendingAdmin is accepted, which means admin is updated
*/
event NewAdmin(address oldAdmin, address newAdmin);
/**
* @notice Event emitted when Comptroller is changed
*/
event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);
/**
* @notice Event emitted when interestRateModel is changed
*/
event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel);
/**
* @notice Event emitted when the reserve factor is changed
*/
event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa);
// TODO : Change to 'adminBank'
/**
* @notice Event emitted when the reserves are reduced
*/
event ReservesReduced(address admin, uint adminPart, address olaBank, uint olaPart, uint newTotalReserves);
/**
* @notice EIP20 Transfer event
*/
event Transfer(address indexed from, address indexed to, uint amount);
/**
* @notice EIP20 Approval event
*/
event Approval(address indexed owner, address indexed spender, uint amount);
/**
* @notice Failure event
*/
event Failure(uint error, uint info, uint detail);
/*** User Interface ***/
function transfer(address dst, uint amount) external returns (bool);
function transferFrom(address src, address dst, uint amount) external returns (bool);
function approve(address spender, uint amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function balanceOfUnderlying(address owner) external returns (uint);
function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint);
function borrowBalanceStored(address account) public view returns (uint);
function exchangeRateStored() public view returns (uint);
function getAccrualBlockNumber() external view returns (uint);
function accrueInterest() public returns (uint);
function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint);
/*** Admin Functions ***/
function _setPendingAdmin(address payable newPendingAdmin) external returns (uint);
function _acceptAdmin() external returns (uint);
function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint);
function _reduceReserves(uint reduceAmount) external returns (uint);
function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint);
}
/**
* View functions that are not used by the core contracts.
*/
contract CTokenViewInterface {
/*** View Interface ***/
function borrowRatePerBlock() external view returns (uint);
function supplyRatePerBlock() external view returns (uint);
function totalBorrowsCurrent() external returns (uint);
/**
* @notice Used by the Maximilion
*/
function borrowBalanceCurrent(address account) external returns (uint);
function exchangeRateCurrent() public returns (uint);
function getCash() external view returns (uint);
}
contract CErc20Interface {
/*** User Interface ***/
function mint(uint mintAmount) external returns (uint);
function redeem(uint redeemTokens) external returns (uint);
function redeemUnderlying(uint redeemAmount) external returns (uint);
function borrow(uint borrowAmount) external returns (uint);
function repayBorrow(uint repayAmount) external returns (uint);
function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint);
function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint);
function sweepToken(EIP20NonStandardInterface token) external;
}
contract CErc20StorageV0_01 {}
contract CErc20StorageV0_02 is CErc20StorageV0_01 {}
contract ONativeInterface {
/*** User Interface ***/
function mint() external payable;
function redeem(uint redeemTokens) external returns (uint);
function redeemUnderlying(uint redeemAmount) external returns (uint);
function borrow(uint borrowAmount) external returns (uint);
function repayBorrow() external payable;
function repayBorrowBehalf(address borrower) external payable;
function liquidateBorrow(address borrower, CTokenInterface cTokenCollateral) external payable;
function sweepToken(EIP20NonStandardInterface token) external;
}
contract CEtherStorageV0_01 {}
contract CEtherStorageV0_02 is CEtherStorageV0_01 {}
contract CDelegateInterface {
/**
* @notice Called by the delegator on a delegate to initialize it for duty
* @dev Should revert if any issues arise which make it unfit for delegation
* @param data The encoded bytes data for any initialization
*/
function _becomeImplementation(bytes memory data) public;
/**
* @notice Called by the delegator on a delegate to forfeit its responsibility
*/
function _resignImplementation() public;
}
contract OTokenCompoundingDepositStorage {
}
contract OTokenCompoundingDepositStorageV0_05 is OTokenCompoundingDepositStorage {
}
contract CLPStakingStorageV0_05 {
/**
* @notice The token that is distributed via the farm
*/
address public rewardToken;
/**
* @notice The farm contract
*/
address public farmAddress;
/**
* @notice The pool id in the farm
*/
uint public pid;
/**
* @notice The market's last updated staking index
*/
uint public marketStakingIndex;
/// @notice The Reward Token index for each supplier as of the last time they accrued rewards
mapping(address => uint) public supplierStakingIndex;
/// @notice The Reward Token accrued but not yet transferred to each supplier
mapping(address => uint) public rewardsAccrued;
}
contract CLPStakingInterfaceV0_05 {
/**
* @notice Event emitted when rewards-interest is accrued
*/
event AccrueRewardsInterest(uint oldStakingIndex, uint newStakingIndex, uint oldReserves, uint newReserves);
event DistributeSupplierRewards(address supplier, uint supplierDelta, uint marketStakignIndex);
}
interface RegistryForODelegator {
function getImplementationForLn(address lnUnitroller, bytes32 contractNameHash) external returns (address);
}
/**
* @title Ola's ODelegator Contract
* @notice OTokens which delegate to an implementation
* @author Ola
*/
contract ODelegator is CTokenAdminStorage, CTokenDelegatorInterface {
/**
* @notice Called by the Comptroller (most of the time) or by the admin (only via the constructor) to update the
* implementation of the delegator
* @param implementation_ The address of the new implementation for delegation
* @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
* @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
*/
function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) internal {
if (allowResign) {
delegateToImplementation(abi.encodeWithSignature("_resignImplementation()"));
}
// Basic sanity
require(CToken(implementation_).isCToken(), "Not CTokens");
address oldImplementation = implementation;
implementation = implementation_;
delegateToImplementation(abi.encodeWithSignature("_becomeImplementation(bytes)", becomeImplementationData));
emit NewImplementation(oldImplementation, implementation);
}
/**
* @notice Internal method to delegate execution to another contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* @param callee The contract to delegatecall
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateTo(address callee, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returnData) = callee.delegatecall(data);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize)
}
}
return returnData;
}
/**
* @notice Delegates execution to the implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateToImplementation(bytes memory data) public returns (bytes memory) {
return delegateTo(implementation, data);
}
/**
* @notice Delegates execution to an implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {
(bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", data));
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize)
}
}
return abi.decode(returnData, (bytes));
}
function updateImplementationFromRegistry(bool allowResign, bytes calldata becomeImplementationData) external returns (bool) {
require(msg.sender == address(comptroller), "Not comptroller");
address implementationToSet = RegistryForODelegator(comptroller.getRegistry()).getImplementationForLn(address(comptroller), contractNameHash);
require(implementationToSet != address(0), "No implementation");
if (implementationToSet != implementation) {
// New implementations always get set via the setter (post-initialize)
_setImplementation(implementationToSet, allowResign, becomeImplementationData);
} else {
emit ImplementationDidNotChange(implementation);
}
return true;
}
/**
* @notice Delegates execution to an implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
*/
function () external payable {
require(msg.value == 0,"ODelegator:fallback: cannot send value to fallback");
// delegate all other functions to current implementation
(bool success, ) = implementation.delegatecall(msg.data);
assembly {
let free_mem_ptr := mload(0x40)
returndatacopy(free_mem_ptr, 0, returndatasize)
switch success
case 0 { revert(free_mem_ptr, returndatasize) }
default { return(free_mem_ptr, returndatasize) }
}
}
}
/**
* @title Ola's ONativeDelegator Contract
* @notice OTokens which wrap a native coin underlying and delegate to an implementation
* @author Ola
*/
contract ONativeDelegator is ODelegator, CTokenInterface, ONativeInterface {
// OLA_ADDITIONS : This contract name hash
bytes32 constant public ONativeDelegatorContractHash = keccak256("ONativeDelegator");
/**
* @notice Construct a new money market
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
* @param name_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
* @param admin_ Address of the administrator of this token
* @param becomeImplementationData The encoded args for becomeImplementation
*/
constructor(ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address payable admin_,
bytes memory becomeImplementationData) public {
// Creator of the contract is admin during initialization
admin = msg.sender;
// Initialize name hash
contractNameHash = ONativeDelegatorContractHash;
address oNativeImplementation = RegistryForODelegator(comptroller_.getRegistry()).getImplementationForLn(address(comptroller_), ONativeDelegatorContractHash);
// First delegate gets to initialize the delegator (i.e. storage contract)
delegateTo(oNativeImplementation, abi.encodeWithSignature("initialize(address,address,uint256,string,string,uint8)",
comptroller_,
interestRateModel_,
initialExchangeRateMantissa_,
name_,
symbol_,
decimals_));
// New implementations always get set via the setter (post-initialize)
_setImplementation(oNativeImplementation, false, becomeImplementationData);
// Set the proper admin now that initialization is done
admin = admin_;
}
/**
* @notice Sender supplies assets into the market and receives OTokens in exchange
* @dev Reverts upon any failure
*/
function mint() external payable {
delegateToImplementation(abi.encodeWithSignature("mint()"));
}
/**
* @notice Sender redeems cTokens in exchange for the underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemTokens The number of cTokens to redeem into underlying
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeem(uint redeemTokens) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("redeem(uint256)", redeemTokens));
return abi.decode(data, (uint));
}
/**
* @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemAmount The amount of underlying to redeem
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlying(uint redeemAmount) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("redeemUnderlying(uint256)", redeemAmount));
return abi.decode(data, (uint));
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrow(uint borrowAmount) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("borrow(uint256)", borrowAmount));
return abi.decode(data, (uint));
}
/**
* @notice Sender repays their own borrow
* @dev Reverts upon any failure
*/
function repayBorrow() external payable {
delegateToImplementation(abi.encodeWithSignature("repayBorrow()"));
}
/**
* @notice Sender repays a borrow belonging to borrower
* @dev Reverts upon any failure
* @param borrower the account with the debt being payed off
*/
function repayBorrowBehalf(address borrower) external payable {
delegateToImplementation(abi.encodeWithSignature("repayBorrowBehalf(address)", borrower));
}
/**
* @notice The sender liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @dev Reverts upon any failure
* @param borrower The borrower of this cToken to be liquidated
* @param cTokenCollateral The market in which to seize collateral from the borrower
*/
function liquidateBorrow(address borrower, CTokenInterface cTokenCollateral) external payable {
delegateToImplementation(abi.encodeWithSignature("liquidateBorrow(address,address)", borrower, cTokenCollateral));
}
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint amount) external returns (bool) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("transfer(address,uint256)", dst, amount));
return abi.decode(data, (bool));
}
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(address src, address dst, uint256 amount) external returns (bool) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("transferFrom(address,address,uint256)", src, dst, amount));
return abi.decode(data, (bool));
}
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) external returns (bool) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("approve(address,uint256)", spender, amount));
return abi.decode(data, (bool));
}
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(address owner, address spender) external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("allowance(address,address)", owner, spender));
return abi.decode(data, (uint));
}
/**
* @notice Get the token balance of the `owner`
* @param owner The address of the account to query
* @return The number of tokens owned by `owner`
*/
function balanceOf(address owner) external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("balanceOf(address)", owner));
return abi.decode(data, (uint));
}
/**
* @notice Get the underlying balance of the `owner`
* @dev This also accrues interest in a transaction
* @param owner The address of the account to query
* @return The amount of underlying owned by `owner`
*/
function balanceOfUnderlying(address owner) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("balanceOfUnderlying(address)", owner));
return abi.decode(data, (uint));
}
/**
* @notice Get a snapshot of the account's balances, and the cached exchange rate
* @dev This is used by Comptroller to more efficiently perform liquidity checks.
* @param account Address of the account to snapshot
* @return (possible error, token balance, borrow balance, exchange rate mantissa)
*/
function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("getAccountSnapshot(address)", account));
return abi.decode(data, (uint, uint, uint, uint));
}
/**
* @notice Returns the current per-block borrow interest rate for this cToken
* @return The borrow interest rate per block, scaled by 1e18
*/
function borrowRatePerBlock() external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("borrowRatePerBlock()"));
return abi.decode(data, (uint));
}
/**
* @notice Returns the current per-block supply interest rate for this cToken
* @return The supply interest rate per block, scaled by 1e18
*/
function supplyRatePerBlock() external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("supplyRatePerBlock()"));
return abi.decode(data, (uint));
}
/**
* @notice Returns the current total borrows plus accrued interest
* @return The total borrows with interest
*/
function totalBorrowsCurrent() external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("totalBorrowsCurrent()"));
return abi.decode(data, (uint));
}
/**
* @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
* @param account The address whose balance should be calculated after updating borrowIndex
* @return The calculated balance
*/
function borrowBalanceCurrent(address account) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("borrowBalanceCurrent(address)", account));
return abi.decode(data, (uint));
}
/**
* @notice Return the borrow balance of account based on stored data
* @param account The address whose balance should be calculated
* @return The calculated balance
*/
function borrowBalanceStored(address account) public view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("borrowBalanceStored(address)", account));
return abi.decode(data, (uint));
}
/**
* @notice Accrue interest then return the up-to-date exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateCurrent() public returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("exchangeRateCurrent()"));
return abi.decode(data, (uint));
}
/**
* @notice Calculates the exchange rate from the underlying to the CToken
* @dev This function does not accrue interest before calculating the exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateStored() public view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("exchangeRateStored()"));
return abi.decode(data, (uint));
}
/**
* @notice Get cash balance of this cToken in the underlying asset
* @return The quantity of underlying asset owned by this contract
*/
function getCash() external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("getCash()"));
return abi.decode(data, (uint));
}
/**
* @notice Get the accrual block number of this cToken
* @return The accrual block number
*/
function getAccrualBlockNumber() external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("getAccrualBlockNumber()"));
return abi.decode(data, (uint));
}
/**
* @notice Applies accrued interest to total borrows and reserves.
* @dev This calculates interest accrued from the last checkpointed block
* up to the current block and writes new checkpoint to storage.
*/
function accrueInterest() public returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("accrueInterest()"));
return abi.decode(data, (uint));
}
/**
* @notice Transfers collateral tokens (this market) to the liquidator.
* @dev Will fail unless called by another cToken during the process of liquidation.
* Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.
* @param liquidator The account receiving seized collateral
* @param borrower The account having collateral seized
* @param seizeTokens The number of cTokens to seize
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("seize(address,address,uint256)", liquidator, borrower, seizeTokens));
return abi.decode(data, (uint));
}
/**
* @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (Timelock)
* @param token The address of the ERC-20 token to sweep
*/
function sweepToken(EIP20NonStandardInterface token) external {
delegateToImplementation(abi.encodeWithSignature("sweepToken(address)", token));
}
/*** Admin Functions ***/
/**
* @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @param newPendingAdmin New pending admin.
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setPendingAdmin(address)", newPendingAdmin));
return abi.decode(data, (uint));
}
/**
* @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
* @dev Admin function to accrue interest and set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setReserveFactor(uint256)", newReserveFactorMantissa));
return abi.decode(data, (uint));
}
/**
* @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
* @dev Admin function for pending admin to accept role and update admin
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _acceptAdmin() external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_acceptAdmin()"));
return abi.decode(data, (uint));
}
/**
* @notice Accrues interest and reduces reserves by transferring to admin
* @param reduceAmount Amount of reduction to reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _reduceReserves(uint reduceAmount) external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_reduceReserves(uint256)", reduceAmount));
return abi.decode(data, (uint));
}
/**
* @notice Accrues interest and updates the interest rate model using _setInterestRateModelFresh
* @dev Admin function to accrue interest and update the interest rate model
* @param newInterestRateModel the new interest rate model to use
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setInterestRateModel(address)", newInterestRateModel));
return abi.decode(data, (uint));
}
}
/**
* @title Compound's CToken Contract
* @notice Abstract base for CTokens
* @author Compound
*/
contract CToken is CTokenStorage, CTokenInterface, CTokenViewInterface, Exponential, TokenErrorReporter {
/**
* @notice Initialize the money market
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
* @param name_ EIP-20 name of this token
* @param symbol_ EIP-20 symbol of this token
* @param decimals_ EIP-20 decimal precision of this token
*/
function initialize(ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_) public {
require(msg.sender == admin, "only admin may initialize the market");
require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once");
// Set initial exchange rate
initialExchangeRateMantissa = initialExchangeRateMantissa_;
require(initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero.");
// Set the Comptroller
uint err = _setComptroller(comptroller_);
require(err == uint(Error.NO_ERROR), "setting comptroller failed");
// Initialize block number and borrow index (block number mocks depend on Comptroller being set)
accrualBlockNumber = getBlockNumber();
accrualBlockTimestamp = getBlockTimestamp();
borrowIndex = mantissaOne;
// Set the calculation based flag from the ministry
RegistryForOToken ministry = RegistryForOToken(comptroller.getRegistry());
blocksBased = ministry.blocksBased();
// Set the interest rate model (depends on block number / borrow index)
err = _setInterestRateModelFresh(interestRateModel_);
require(err == uint(Error.NO_ERROR), "setting interest rate model failed");
name = name_;
symbol = symbol_;
decimals = decimals_;
// The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)
_notEntered = true;
}
/**
* @notice Transfer `tokens` tokens from `src` to `dst` by `spender`
* @dev Called by both `transfer` and `transferFrom` internally
* @param spender The address of the account performing the transfer
* @param src The address of the source account
* @param dst The address of the destination account
* @param tokens The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) {
/* Fail if transfer not allowed */
uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens);
if (allowed != 0) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.TRANSFER_COMPTROLLER_REJECTION, allowed);
}
/* Do not allow self-transfers */
if (src == dst) {
return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);
}
/* Get the allowance, infinite for the account owner */
uint startingAllowance = 0;
if (spender == src) {
startingAllowance = uint(-1);
} else {
startingAllowance = transferAllowances[src][spender];
}
/* Do the calculations, checking for {under,over}flow */
MathError mathErr;
uint allowanceNew;
uint srcTokensNew;
uint dstTokensNew;
(mathErr, allowanceNew) = subUInt(startingAllowance, tokens);
if (mathErr != MathError.NO_ERROR) {
return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED);
}
(mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens);
if (mathErr != MathError.NO_ERROR) {
return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH);
}
(mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens);
if (mathErr != MathError.NO_ERROR) {
return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
accountTokens[src] = srcTokensNew;
accountTokens[dst] = dstTokensNew;
/* Eat some of the allowance (if necessary) */
if (startingAllowance != uint(-1)) {
transferAllowances[src][spender] = allowanceNew;
}
/* We emit a Transfer event */
emit Transfer(src, dst, tokens);
// unused function
comptroller.transferVerify(address(this), src, dst, tokens);
return uint(Error.NO_ERROR);
}
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint256 amount) external nonReentrant returns (bool) {
return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.NO_ERROR);
}
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(address src, address dst, uint256 amount) external nonReentrant returns (bool) {
return transferTokens(msg.sender, src, dst, amount) == uint(Error.NO_ERROR);
}
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) external returns (bool) {
address src = msg.sender;
transferAllowances[src][spender] = amount;
emit Approval(src, spender, amount);
return true;
}
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(address owner, address spender) external view returns (uint256) {
return transferAllowances[owner][spender];
}
/**
* @notice Get the token balance of the `owner`
* @param owner The address of the account to query
* @return The number of tokens owned by `owner`
*/
function balanceOf(address owner) external view returns (uint256) {
return accountTokens[owner];
}
/**
* @notice Get the underlying balance of the `owner`
* @dev This also accrues interest in a transaction
* @param owner The address of the account to query
* @return The amount of underlying owned by `owner`
*/
function balanceOfUnderlying(address owner) external returns (uint) {
Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});
(MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);
require(mErr == MathError.NO_ERROR, "balance could not be calculated");
return balance;
}
/**
* @notice Get a snapshot of the account's balances, and the cached exchange rate
* @dev This is used by Comptroller to more efficiently perform liquidity checks.
* @param account Address of the account to snapshot
* @return (possible error, token balance, borrow balance, exchange rate mantissa)
*/
function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {
uint cTokenBalance = accountTokens[account];
uint borrowBalance;
uint exchangeRateMantissa;
MathError mErr;
(mErr, borrowBalance) = borrowBalanceStoredInternal(account);
if (mErr != MathError.NO_ERROR) {
return (uint(Error.MATH_ERROR), 0, 0, 0);
}
(mErr, exchangeRateMantissa) = exchangeRateStoredInternal();
if (mErr != MathError.NO_ERROR) {
return (uint(Error.MATH_ERROR), 0, 0, 0);
}
return (uint(Error.NO_ERROR), cTokenBalance, borrowBalance, exchangeRateMantissa);
}
/**
* @dev Function to simply retrieve block number
* This exists mainly for inheriting test contracts to stub this result.
*/
function getBlockNumber() internal view returns (uint) {
return block.number;
}
/**
* @dev Function to simply retrieve block timestamp
* This exists mainly for inheriting test contracts to stub this result.
*/
function getBlockTimestamp() internal view returns (uint) {
return block.timestamp;
}
/**
* @notice Returns the current per-block borrow interest rate for this cToken
* @return The borrow interest rate per block, scaled by 1e18
*/
function borrowRatePerBlock() external view returns (uint) {
return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);
}
/**
* @notice Returns the current per-block supply interest rate for this cToken
* @return The supply interest rate per block, scaled by 1e18
*/
function supplyRatePerBlock() external view returns (uint) {
return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);
}
/**
* @notice Returns the current total borrows plus accrued interest
* @return The total borrows with interest
*/
function totalBorrowsCurrent() external nonReentrant returns (uint) {
require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
return totalBorrows;
}
/**
* @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
* @param account The address whose balance should be calculated after updating borrowIndex
* @return The calculated balance
*/
function borrowBalanceCurrent(address account) external nonReentrant returns (uint) {
require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
return borrowBalanceStored(account);
}
/**
* @notice Return the borrow balance of account based on stored data
* @param account The address whose balance should be calculated
* @return The calculated balance
*/
function borrowBalanceStored(address account) public view returns (uint) {
(MathError err, uint result) = borrowBalanceStoredInternal(account);
require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed");
return result;
}
/**
* @notice Return the borrow balance of account based on stored data
* @param account The address whose balance should be calculated
* @return (error code, the calculated balance or 0 if error code is non-zero)
*/
function borrowBalanceStoredInternal(address account) internal view returns (MathError, uint) {
/* Note: we do not assert that the market is up to date */
MathError mathErr;
uint principalTimesIndex;
uint result;
/* Get borrowBalance and borrowIndex */
BorrowSnapshot storage borrowSnapshot = accountBorrows[account];
/* If borrowBalance = 0 then borrowIndex is likely also 0.
* Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
*/
if (borrowSnapshot.principal == 0) {
return (MathError.NO_ERROR, 0);
}
/* Calculate new borrow balance using the interest index:
* recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex
*/
(mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex);
if (mathErr != MathError.NO_ERROR) {
return (mathErr, 0);
}
(mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex);
if (mathErr != MathError.NO_ERROR) {
return (mathErr, 0);
}
return (MathError.NO_ERROR, result);
}
/**
* @notice Accrue interest then return the up-to-date exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateCurrent() public nonReentrant returns (uint) {
require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
return exchangeRateStored();
}
/**
* @notice Calculates the exchange rate from the underlying to the CToken
* @dev This function does not accrue interest before calculating the exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateStored() public view returns (uint) {
(MathError err, uint result) = exchangeRateStoredInternal();
require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed");
return result;
}
/**
* @notice Calculates the exchange rate from the underlying to the CToken
* @dev This function does not accrue interest before calculating the exchange rate
* @return (error code, calculated exchange rate scaled by 1e18)
*/
function exchangeRateStoredInternal() internal view returns (MathError, uint) {
uint _totalSupply = totalSupply;
if (_totalSupply == 0) {
/*
* If there are no tokens minted:
* exchangeRate = initialExchangeRate
*/
return (MathError.NO_ERROR, initialExchangeRateMantissa);
} else {
/*
* Otherwise:
* exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
*/
uint totalCash = getCashPrior();
uint cashPlusBorrowsMinusReserves;
Exp memory exchangeRate;
MathError mathErr;
(mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);
if (mathErr != MathError.NO_ERROR) {
return (mathErr, 0);
}
(mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);
if (mathErr != MathError.NO_ERROR) {
return (mathErr, 0);
}
return (MathError.NO_ERROR, exchangeRate.mantissa);
}
}
/**
* @notice Get cash balance of this cToken in the underlying asset
* @return The quantity of underlying asset owned by this contract
*/
function getCash() external view returns (uint) {
return getCashPrior();
}
/**
* @notice Get the accrual block number of this cToken
* @return The accrual block number
*/
function getAccrualBlockNumber() external view returns (uint) {
return accrualBlockNumber;
}
/**
* @notice Applies accrued interest to total borrows and reserves
* @dev This calculates interest accrued from the last checkpointed block
* up to the current block and writes new checkpoint to storage.
*/
function accrueInterest() public returns (uint) {
/* Remember the initial block number */
uint currentBlockNumber = getBlockNumber();
uint accrualBlockNumberPrior = accrualBlockNumber;
uint currentBlockTimestamp = getBlockTimestamp();
/* Short-circuit accumulating 0 interest */
if (accrualBlockNumberPrior == currentBlockNumber) {
return uint(Error.NO_ERROR);
}
// OLA_ADDITIONS : Distinction between time and block based calculations
/* Calculate the number of blocks elapsed since the last accrual */
MathError mathErr;
uint delta;
if (blocksBased) {
(mathErr, delta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);
} else {
// This variable is defined here due to solidity limits
uint accrualBlockTimestampPrior = accrualBlockTimestamp;
/* Short-circuit accumulating 0 interest on time based chains + extra safety for weird timestamps */
if (currentBlockTimestamp <= accrualBlockTimestampPrior) {
return uint(Error.NO_ERROR);
}
(mathErr, delta) = subUInt(currentBlockTimestamp, accrualBlockTimestampPrior);
}
require(mathErr == MathError.NO_ERROR, "could not calculate delta");
/* Read the previous values out of storage */
uint cashPrior = getCashPrior();
uint borrowsPrior = totalBorrows;
uint reservesPrior = totalReserves;
uint borrowIndexPrior = borrowIndex;
/* Calculate the current borrow interest rate */
uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);
require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high");
/*
* Calculate the interest accumulated into borrows and reserves and the new index:
* simpleInterestFactor = borrowRate * delta
* interestAccumulated = simpleInterestFactor * totalBorrows
* totalBorrowsNew = interestAccumulated + totalBorrows
* totalReservesNew = interestAccumulated * reserveFactor + totalReserves
* borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
*/
Exp memory simpleInterestFactor;
uint interestAccumulated;
uint totalBorrowsNew;
uint totalReservesNew;
uint borrowIndexNew;
(mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), delta);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr));
}
(mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, borrowsPrior);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr));
}
(mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr));
}
(mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr));
}
(mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr));
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/* We write the previously calculated values into storage */
accrualBlockNumber = currentBlockNumber;
accrualBlockTimestamp = currentBlockTimestamp;
borrowIndex = borrowIndexNew;
totalBorrows = totalBorrowsNew;
totalReserves = totalReservesNew;
/* We emit an AccrueInterest event */
emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);
return uint(Error.NO_ERROR);
}
/**
* @notice Sender supplies assets into the market and receives cTokens in exchange
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param mintAmount The amount of the underlying asset to supply
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
*/
function mintInternal(uint mintAmount) internal nonReentrant returns (uint, uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
return (fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), 0);
}
// mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to
return mintFresh(msg.sender, mintAmount);
}
struct MintLocalVars {
Error err;
MathError mathErr;
uint exchangeRateMantissa;
uint mintTokens;
uint totalSupplyNew;
uint accountTokensNew;
uint actualMintAmount;
}
/**
* @notice User supplies assets into the market and receives cTokens in exchange
* @dev Assumes interest has already been accrued up to the current block
* @param minter The address of the account which is supplying the assets
* @param mintAmount The amount of the underlying asset to supply
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
*/
function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {
/* Fail if mint not allowed */
uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);
if (allowed != 0) {
return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed), 0);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), 0);
}
MintLocalVars memory vars;
(vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
if (vars.mathErr != MathError.NO_ERROR) {
return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We call `doTransferIn` for the minter and the mintAmount.
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* `doTransferIn` reverts if anything goes wrong, since we can't be sure if
* side-effects occurred. The function returns the amount actually transferred,
* in case of a fee. On success, the cToken holds an additional `actualMintAmount`
* of cash.
*/
vars.actualMintAmount = doTransferIn(minter, mintAmount);
/*
* We get the current exchange rate and calculate the number of cTokens to be minted:
* mintTokens = actualMintAmount / exchangeRate
*/
(vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));
require(vars.mathErr == MathError.NO_ERROR, "MINT_EXCHANGE_CALCULATION_FAILED");
/*
* We calculate the new total supply of cTokens and minter token balance, checking for overflow:
* totalSupplyNew = totalSupply + mintTokens
* accountTokensNew = accountTokens[minter] + mintTokens
*/
(vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);
require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED");
(vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);
require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED");
/* We write previously calculated values into storage */
totalSupply = vars.totalSupplyNew;
accountTokens[minter] = vars.accountTokensNew;
/* We emit a Mint event, and a Transfer event */
emit Mint(minter, vars.actualMintAmount, vars.mintTokens);
emit Transfer(address(this), minter, vars.mintTokens);
/* We call the defense hook */
// unused function
comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens);
return (uint(Error.NO_ERROR), vars.actualMintAmount);
}
/**
* @notice Sender redeems cTokens in exchange for the underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemTokens The number of cTokens to redeem into underlying
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
}
// redeemFresh emits redeem-specific logs on errors, so we don't need to
return redeemFresh(msg.sender, redeemTokens, 0);
}
/**
* @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemAmount The amount of underlying to receive from redeeming cTokens
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
}
// redeemFresh emits redeem-specific logs on errors, so we don't need to
return redeemFresh(msg.sender, 0, redeemAmount);
}
struct RedeemLocalVars {
Error err;
MathError mathErr;
uint exchangeRateMantissa;
uint redeemTokens;
uint redeemAmount;
uint totalSupplyNew;
uint accountTokensNew;
}
/**
* @notice User redeems cTokens in exchange for the underlying asset
* @dev Assumes interest has already been accrued up to the current block
* @param redeemer The address of the account which is redeeming the tokens
* @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
* @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {
require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");
RedeemLocalVars memory vars;
/* exchangeRate = invoke Exchange Rate Stored() */
(vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));
}
/* If redeemTokensIn > 0: */
if (redeemTokensIn > 0) {
/*
* We calculate the exchange rate and the amount of underlying to be redeemed:
* redeemTokens = redeemTokensIn
* redeemAmount = redeemTokensIn x exchangeRateCurrent
*/
vars.redeemTokens = redeemTokensIn;
(vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));
}
} else {
/*
* We get the current exchange rate and calculate the amount to be redeemed:
* redeemTokens = redeemAmountIn / exchangeRate
* redeemAmount = redeemAmountIn
*/
(vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));
}
vars.redeemAmount = redeemAmountIn;
}
/* Fail if redeem not allowed */
uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens);
if (allowed != 0) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDEEM_FRESHNESS_CHECK);
}
/*
* We calculate the new total supply and redeemer balance, checking for underflow:
* totalSupplyNew = totalSupply - redeemTokens
* accountTokensNew = accountTokens[redeemer] - redeemTokens
*/
(vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));
}
(vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
}
/* Fail gracefully if protocol has insufficient cash */
if (getCashPrior() < vars.redeemAmount) {
return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We invoke doTransferOut for the redeemer and the redeemAmount.
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* On success, the cToken has redeemAmount less of cash.
* doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
*/
doTransferOut(redeemer, vars.redeemAmount);
/* We write previously calculated values into storage */
totalSupply = vars.totalSupplyNew;
accountTokens[redeemer] = vars.accountTokensNew;
/* We emit a Transfer event, and a Redeem event */
emit Transfer(redeemer, address(this), vars.redeemTokens);
emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);
/* We call the defense hook */
comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens);
return uint(Error.NO_ERROR);
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrowInternal(uint borrowAmount) internal nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
return fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);
}
// borrowFresh emits borrow-specific logs on errors, so we don't need to
return borrowFresh(msg.sender, borrowAmount);
}
struct BorrowLocalVars {
MathError mathErr;
uint accountBorrows;
uint accountBorrowsNew;
uint totalBorrowsNew;
}
/**
* @notice Users borrow assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
/* Fail if borrow not allowed */
uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount);
if (allowed != 0) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.BORROW_COMPTROLLER_REJECTION, allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK);
}
/* Fail gracefully if protocol has insufficient underlying cash */
if (getCashPrior() < borrowAmount) {
return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE);
}
BorrowLocalVars memory vars;
/*
* We calculate the new borrower and total borrow balances, failing on overflow:
* accountBorrowsNew = accountBorrows + borrowAmount
* totalBorrowsNew = totalBorrows + borrowAmount
*/
(vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
}
(vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, borrowAmount);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
}
(vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, borrowAmount);
if (vars.mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We invoke doTransferOut for the borrower and the borrowAmount.
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* On success, the cToken borrowAmount less of cash.
* doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
*/
doTransferOut(borrower, borrowAmount);
/* We write the previously calculated values into storage */
accountBorrows[borrower].principal = vars.accountBorrowsNew;
accountBorrows[borrower].interestIndex = borrowIndex;
totalBorrows = vars.totalBorrowsNew;
/* We emit a Borrow event */
emit Borrow(borrower, borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);
/* We call the defense hook */
// unused function
// Comptroller.borrowVerify(address(this), borrower, borrowAmount);
return uint(Error.NO_ERROR);
}
/**
* @notice Sender repays their own borrow
* @param repayAmount The amount to repay
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function repayBorrowInternal(uint repayAmount) internal nonReentrant returns (uint, uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
return (fail(Error(error), FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED), 0);
}
// repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
return repayBorrowFresh(msg.sender, msg.sender, repayAmount);
}
/**
* @notice Sender repays a borrow belonging to borrower
* @param borrower the account with the debt being payed off
* @param repayAmount The amount to repay
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant returns (uint, uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
return (fail(Error(error), FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED), 0);
}
// repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
return repayBorrowFresh(msg.sender, borrower, repayAmount);
}
struct RepayBorrowLocalVars {
Error err;
MathError mathErr;
uint repayAmount;
uint borrowerIndex;
uint accountBorrows;
uint accountBorrowsNew;
uint totalBorrowsNew;
uint actualRepayAmount;
}
/**
* @notice Borrows are repaid by another user (possibly the borrower).
* @param payer the account paying off the borrow
* @param borrower the account with the debt being payed off
* @param repayAmount the amount of undelrying tokens being returned
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint, uint) {
/* Fail if repayBorrow not allowed */
uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount);
if (allowed != 0) {
return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, allowed), 0);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.REPAY_BORROW_FRESHNESS_CHECK), 0);
}
RepayBorrowLocalVars memory vars;
/* We remember the original borrowerIndex for verification purposes */
vars.borrowerIndex = accountBorrows[borrower].interestIndex;
/* We fetch the amount the borrower owes, with accumulated interest */
(vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
if (vars.mathErr != MathError.NO_ERROR) {
return (failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0);
}
/* If repayAmount == -1, repayAmount = accountBorrows */
if (repayAmount == uint(-1)) {
vars.repayAmount = vars.accountBorrows;
} else {
vars.repayAmount = repayAmount;
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We call doTransferIn for the payer and the repayAmount
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* On success, the cToken holds an additional repayAmount of cash.
* doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
* it returns the amount actually transferred, in case of a fee.
*/
vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);
/*
* We calculate the new borrower and total borrow balances, failing on underflow:
* accountBorrowsNew = accountBorrows - actualRepayAmount
* totalBorrowsNew = totalBorrows - actualRepayAmount
*/
(vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.actualRepayAmount);
require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED");
(vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.actualRepayAmount);
require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED");
/* We write the previously calculated values into storage */
accountBorrows[borrower].principal = vars.accountBorrowsNew;
accountBorrows[borrower].interestIndex = borrowIndex;
totalBorrows = vars.totalBorrowsNew;
/* We emit a RepayBorrow event */
emit RepayBorrow(payer, borrower, vars.actualRepayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);
/* We call the defense hook */
// unused function
// Comptroller.repayBorrowVerify(address(this), payer, borrower, vars.actualRepayAmount, vars.borrowerIndex);
return (uint(Error.NO_ERROR), vars.actualRepayAmount);
}
/**
* @notice The sender liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @param borrower The borrower of this cToken to be liquidated
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @param repayAmount The amount of the underlying borrowed asset to repay
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function liquidateBorrowInternal(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal nonReentrant returns (uint, uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED), 0);
}
error = cTokenCollateral.accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED), 0);
}
// liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to
return liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral);
}
/**
* @notice The liquidator liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @param borrower The borrower of this cToken to be liquidated
* @param liquidator The address repaying the borrow and seizing collateral
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @param repayAmount The amount of the underlying borrowed asset to repay
* @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
*/
function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal returns (uint, uint) {
/* Fail if liquidate not allowed */
uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount);
if (allowed != 0) {
return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, allowed), 0);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_FRESHNESS_CHECK), 0);
}
/* Verify cTokenCollateral market's block number equals current block number */
if (cTokenCollateral.getAccrualBlockNumber() != getBlockNumber()) {
return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK), 0);
}
/* Fail if borrower = liquidator */
if (borrower == liquidator) {
return (fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER), 0);
}
/* Fail if repayAmount = 0 */
if (repayAmount == 0) {
return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO), 0);
}
/* Fail if repayAmount = -1 */
if (repayAmount == uint(-1)) {
return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX), 0);
}
/* Fail if repayBorrow fails */
(uint repayBorrowError, uint actualRepayAmount) = repayBorrowFresh(liquidator, borrower, repayAmount);
if (repayBorrowError != uint(Error.NO_ERROR)) {
return (fail(Error(repayBorrowError), FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED), 0);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/* We calculate the number of collateral tokens that will be seized */
(uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(cTokenCollateral), actualRepayAmount);
require(amountSeizeError == uint(Error.NO_ERROR), "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");
/* Revert if borrower collateral token balance < seizeTokens */
require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "LIQUIDATE_SEIZE_TOO_MUCH");
// If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call
uint seizeError;
if (address(cTokenCollateral) == address(this)) {
seizeError = seizeInternal(address(this), liquidator, borrower, seizeTokens);
} else {
seizeError = cTokenCollateral.seize(liquidator, borrower, seizeTokens);
}
/* Revert if seize tokens fails (since we cannot be sure of side effects) */
require(seizeError == uint(Error.NO_ERROR), "token seizure failed");
/* We emit a LiquidateBorrow event */
emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens);
/* We call the defense hook */
// unused function
// Comptroller.liquidateBorrowVerify(address(this), address(cTokenCollateral), liquidator, borrower, actualRepayAmount, seizeTokens);
return (uint(Error.NO_ERROR), actualRepayAmount);
}
/**
* @notice Transfers collateral tokens (this market) to the liquidator.
* @dev Will fail unless called by another cToken during the process of liquidation.
* Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.
* @param liquidator The account receiving seized collateral
* @param borrower The account having collateral seized
* @param seizeTokens The number of cTokens to seize
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) {
return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);
}
/**
* @notice Transfers collateral tokens (this market) to the liquidator.
* @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken.
* Its absolutely critical to use msg.sender as the seizer cToken and not a parameter.
* @param seizerToken The contract seizing the collateral (i.e. borrowed cToken)
* @param liquidator The account receiving seized collateral
* @param borrower The account having collateral seized
* @param seizeTokens The number of cTokens to seize
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal returns (uint) {
/* Fail if seize not allowed */
uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);
if (allowed != 0) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed);
}
/* Fail if borrower = liquidator */
if (borrower == liquidator) {
return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER);
}
MathError mathErr;
uint borrowerTokensNew;
uint liquidatorTokensNew;
/*
* We calculate the new borrower and liquidator token balances, failing on underflow/overflow:
* borrowerTokensNew = accountTokens[borrower] - seizeTokens
* liquidatorTokensNew = accountTokens[liquidator] + seizeTokens
*/
(mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr));
}
(mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr));
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/* We write the previously calculated values into storage */
accountTokens[borrower] = borrowerTokensNew;
accountTokens[liquidator] = liquidatorTokensNew;
/* Emit a Transfer event */
emit Transfer(borrower, liquidator, seizeTokens);
/* We call the defense hook */
// Transfer verify is required here due to tokens being transferred, and have to keep the
// ACC accounting in check
// This works, because the 'borrower' has to be in this market. and so, the active collateral usage can either remain unchanged
// (if the liquidator is also in the market) or reduce (if the liquidator is not in the market)
comptroller.transferVerify(address(this), borrower, liquidator, seizeTokens);
/* We call the defense hook */
// unused function
// Comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens);
return uint(Error.NO_ERROR);
}
/*** Admin Functions ***/
/**
* @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @param newPendingAdmin New pending admin.
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {
// Check caller = admin
if (msg.sender != admin) {
return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);
}
// Save current value, if any, for inclusion in log
address oldPendingAdmin = pendingAdmin;
// Store pendingAdmin with value newPendingAdmin
pendingAdmin = newPendingAdmin;
// Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);
return uint(Error.NO_ERROR);
}
/**
* @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
* @dev Admin function for pending admin to accept role and update admin
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _acceptAdmin() external returns (uint) {
// Check caller is pendingAdmin and pendingAdmin ≠ address(0)
if (msg.sender != pendingAdmin || msg.sender == address(0)) {
return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);
}
// Save current values for inclusion in log
address oldAdmin = admin;
address oldPendingAdmin = pendingAdmin;
// Store admin with value pendingAdmin
admin = pendingAdmin;
// Clear the pending value
pendingAdmin = address(0);
emit NewAdmin(oldAdmin, admin);
emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);
return uint(Error.NO_ERROR);
}
/**
* OLA_ADDITIONS : Made internal and removes Admin check.
* @notice Sets a new Comptroller for the market
* @dev Admin function to set a new Comptroller
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setComptroller(ComptrollerInterface newComptroller) internal returns (uint) {
ComptrollerInterface oldComptroller = comptroller;
// Ensure invoke Comptroller.isComptroller() returns true
require(newComptroller.isComptroller(), "marker method returned false");
// Set market's Comptroller to newComptroller
comptroller = newComptroller;
// Emit NewComptroller(oldComptroller, newComptroller)
emit NewComptroller(oldComptroller, newComptroller);
return uint(Error.NO_ERROR);
}
/**
* @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
* @dev Admin function to accrue interest and set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed.
return fail(Error(error), FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED);
}
// _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to.
return _setReserveFactorFresh(newReserveFactorMantissa);
}
/**
* @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)
* @dev Admin function to set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {
// Check caller is admin
if (msg.sender != admin) {
return fail(Error.UNAUTHORIZED, FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK);
}
// Verify market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK);
}
// Check newReserveFactor ≤ maxReserveFactor
if (newReserveFactorMantissa > reserveFactorMaxMantissa) {
return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK);
}
// OLA_ADDITIONS :This constraint
// Check newReserveFactor >= minReserveFactor
if (newReserveFactorMantissa < reserveFactorMinMantissa) {
return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK);
}
uint oldReserveFactorMantissa = reserveFactorMantissa;
reserveFactorMantissa = newReserveFactorMantissa;
emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);
return uint(Error.NO_ERROR);
}
/**
* @notice Accrues interest and reduces reserves by transferring to admin
* @param reduceAmount Amount of reduction to reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _reduceReserves(uint reduceAmount) external nonReentrant returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed.
return fail(Error(error), FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED);
}
// _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to.
return _reduceReservesFresh(reduceAmount);
}
/**
* @notice Reduces reserves by transferring to the LeN admin and to Ola bank their respective shares
* @dev Requires fresh interest accrual
* @param reduceAmount Amount of reduction to reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _reduceReservesFresh(uint reduceAmount) internal returns (uint) {
// totalReserves - reduceAmount
uint totalReservesNew;
// OLA_ADDITIONS : Allowing anyone to reduce reserves
// Check caller is admin
// if (msg.sender != admin) {
// return fail(Error.UNAUTHORIZED, FailureInfo.REDUCE_RESERVES_ADMIN_CHECK);
// }
// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK);
}
// Fail gracefully if protocol has insufficient underlying cash
if (getCashPrior() < reduceAmount) {
return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE);
}
// Check reduceAmount ≤ reserves[n] (totalReserves)
if (reduceAmount > totalReserves) {
return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);
}
// OLA_ADDITIONS : Dividing the reduced amount between the Admin and Ola (+validations)
// Important to notice that we have added Math calculations to this function.
// Where as before, it only used pre-calculated numbers.
MathError mathErr;
uint adminPart;
uint olaPart;
uint olaReserveFactor = fetchOlaReserveFactorMantissa();
address payable olaBankAddress = fetchOlaBankAddress();
address payable adminBankAddress = fetchAdminBankAddress();
// Calculate olaPart
(mathErr, olaPart) = mulScalarTruncate(Exp({mantissa: olaReserveFactor}), reduceAmount);
if (mathErr != MathError.NO_ERROR) {
return failOpaque(Error.MATH_ERROR, FailureInfo.REDUCE_RESERVES_OLA_PART_CALCULATION_FAILED, uint(mathErr));
}
// Sanity check, should never be a problem in a well parameterized system
if (olaPart >= reduceAmount) {
return fail(Error.BAD_SYSTEM_PARAMS, FailureInfo.REDUCE_RESERVES_OLA_PART_CALCULATION_FAILED);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
// Calculate admin part
adminPart = reduceAmount - olaPart;
// We checked olaPart < reduceAmount above, so this should never revert.
require(adminPart < reduceAmount, "reduce reserves unexpected adminPart underflow");
totalReservesNew = totalReserves - reduceAmount;
// We checked reduceAmount <= totalReserves above, so this should never revert.
require(totalReservesNew <= totalReserves, "reduce reserves unexpected underflow");
// Store reserves[n+1] = reserves[n] - reduceAmount
totalReserves = totalReservesNew;
// OLA_ADDITIONS : Transfer reserves to both admin and Ola bank addresses
// doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
doTransferOut(adminBankAddress, adminPart);
doTransferOut(olaBankAddress, olaPart);
emit ReservesReduced(adminBankAddress, adminPart, olaBankAddress, olaPart, totalReservesNew);
return uint(Error.NO_ERROR);
}
/**
* @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh
* @dev Admin function to accrue interest and update the interest rate model
* @param newInterestRateModel the new interest rate model to use
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) {
uint error = accrueInterest();
if (error != uint(Error.NO_ERROR)) {
// accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed
return fail(Error(error), FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED);
}
// _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to.
return _setInterestRateModelFresh(newInterestRateModel);
}
/**
* @notice updates the interest rate model (*requires fresh interest accrual)
* @dev Admin function to update the interest rate model
* @param newInterestRateModel the new interest rate model to use
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) {
// Used to store old model for use in the event that is emitted on success
InterestRateModel oldInterestRateModel;
// Check caller is admin
if (msg.sender != admin) {
return fail(Error.UNAUTHORIZED, FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK);
}
// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK);
}
// Ensure interest rate model is an approved contracts
RegistryForOToken registry = RegistryForOToken(comptroller.getRegistry());
require(registry.isSupportedInterestRateModel(address(newInterestRateModel)), "Unapproved interest rate model");
// Track the market's current interest rate model
oldInterestRateModel = interestRateModel;
// Ensure invoke newInterestRateModel.isInterestRateModel() returns true
require(newInterestRateModel.isInterestRateModel(), "marker method returned false");
// Set the interest rate model to newInterestRateModel
interestRateModel = newInterestRateModel;
// Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)
emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);
return uint(Error.NO_ERROR);
}
/*** Safe Token ***/
/**
* @notice Gets balance of this contract in terms of the underlying
* @dev This excludes the value of the current message, if any
* @return The quantity of underlying owned by this contract
*/
function getCashPrior() internal view returns (uint);
/**
* @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.
* This may revert due to insufficient balance or insufficient allowance.
*/
function doTransferIn(address from, uint amount) internal returns (uint);
/**
* @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting.
* If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.
* If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.
*/
function doTransferOut(address payable to, uint amount) internal;
/**
* OLA_ADDITIONS: This function
* @dev Returns the ola reserves factor.
*/
function fetchOlaReserveFactorMantissa() internal pure returns (uint) {
return olaReserveFactorMantissa;
}
/**
* OLA_ADDITIONS: This function
* @dev Fetches the ola bank address.
*/
function fetchOlaBankAddress() internal returns (address payable) {
return RegistryForOToken(comptroller.getRegistry()).olaBankAddress();
}
/**
* OLA_ADDITIONS: This function
* @dev Fetches the admin bank address.
*/
function fetchAdminBankAddress() internal view returns (address payable) {
return ComptrollerForOToken(address(comptroller)).adminBankAddress();
}
/*** Reentrancy Guard ***/
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
*/
modifier nonReentrant() {
require(_notEntered, "re-entered");
_notEntered = false;
_;
_notEntered = true; // get a gas-refund post-Istanbul
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"},{"internalType":"bytes","name":"becomeImplementationData","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"ImplementationDidNotChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ComptrollerInterface","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"}],"name":"NewImplementation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"adminPart","type":"uint256"},{"indexed":false,"internalType":"address","name":"olaBank","type":"address"},{"indexed":false,"internalType":"uint256","name":"olaPart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"ONativeDelegatorContractHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contractNameHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"delegateToImplementation","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"delegateToViewImplementation","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAccrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"contract CTokenInterface","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"mint","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"nativeCoinUnderlying","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"olaReserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"repayBorrow","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"repayBorrowBehalf","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract EIP20NonStandardInterface","name":"token","type":"address"}],"name":"sweepToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bool","name":"allowResign","type":"bool"},{"internalType":"bytes","name":"becomeImplementationData","type":"bytes"}],"name":"updateImplementationFromRegistry","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b50604051620025543803806200255483398181016040526101008110156200003857600080fd5b8151602083015160408085015160608601805192519496939591949391820192846401000000008211156200006c57600080fd5b9083019060208201858111156200008257600080fd5b82516401000000008111828201881017156200009d57600080fd5b82525081516020918201929091019080838360005b83811015620000cc578181015183820152602001620000b2565b50505050905090810190601f168015620000fa5780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200011e57600080fd5b9083019060208201858111156200013457600080fd5b82516401000000008111828201881017156200014f57600080fd5b82525081516020918201929091019080838360005b838110156200017e57818101518382015260200162000164565b50505050905090810190601f168015620001ac5780820380516001836020036101000a031916815260200191505b50604081815260208301519083015160609093018051919593949293929184640100000000821115620001de57600080fd5b908301906020820185811115620001f457600080fd5b82516401000000008111828201881017156200020f57600080fd5b82525081516020918201929091019080838360005b838110156200023e57818101518382015260200162000224565b50505050905090810190601f1680156200026c5780820380516001836020036101000a031916815260200191505b506040818152600080546001600160a01b031916331781556f27a730ba34bb32a232b632b3b0ba37b960811b835281519283900360100183206004908155635ab1bd5360e01b845291519095506001600160a01b038e169450635ab1bd5393508183019260209290829003018186803b158015620002e957600080fd5b505afa158015620002fe573d6000803e3d6000fd5b505050506040513d60208110156200031557600080fd5b5051604080516f27a730ba34bb32a232b632b3b0ba37b960811b81528151908190036010018120635fa4cae760e01b82526001600160a01b038d81166004840152602483019190915291519190921691635fa4cae79160448083019260209291908290030181600087803b1580156200038d57600080fd5b505af1158015620003a2573d6000803e3d6000fd5b505050506040513d6020811015620003b957600080fd5b50516040516001600160a01b03808c1660248301908152908b166044830152606482018a905260ff871660c483015260c060848301908152895160e48401528951939450620005179385938e938e938e938e938e938e939092909160a481019161010490910190602088019080838360005b83811015620004455781810151838201526020016200042b565b50505050905090810190601f168015620004735780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015620004a85781810151838201526020016200048e565b50505050905090810190601f168015620004d65780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03908116632676306d60e21b179091529099506200055e16975050505050505050565b506200052f816000846001600160e01b036200062516565b5050600080546001600160a01b0319166001600160a01b03929092169190911790555062000851945050505050565b606060006060846001600160a01b0316846040518082805190602001908083835b60208310620005a05780518252601f1990920191602091820191016200057f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811462000602576040519150601f19603f3d011682016040523d82523d6000602084013e62000607565b606091505b509150915060008214156200061d573d60208201fd5b949350505050565b811562000667576040805160048152602481019091526020810180516001600160e01b0390811663153ab50560e01b179091526200066591906200082716565b505b826001600160a01b031663fe9c44ae6040518163ffffffff1660e01b815260040160206040518083038186803b158015620006a157600080fd5b505afa158015620006b6573d6000803e3d6000fd5b505050506040513d6020811015620006cd57600080fd5b50516200070f576040805162461bcd60e51b815260206004820152600b60248201526a4e6f742043546f6b656e7360a81b604482015290519081900360640190fd5b600380546001600160a01b038581166001600160a01b03198316179092556040516020602482018181528551604484015285519490931693620007e5938693909283926064909201919085019080838360005b838110156200077c57818101518382015260200162000762565b50505050905090810190601f168015620007aa5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03908116630adccee560e31b179091529093506200082716915050565b506003546040516001600160a01b03918216918316907fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a90600090a350505050565b6003546060906200084b906001600160a01b0316836001600160e01b036200055e16565b92915050565b611cf380620008616000396000f3fe60806040526004361061025c5760003560e01c80638694505611610144578063c37f68e2116100b6578063e9c714f21161007a578063e9c714f214610aab578063f2b3abbd14610ac0578063f851a44014610af3578063f8f9da2814610b08578063fca7820b14610b1d578063fe9c44ae14610b475761025c565b8063c37f68e21461099d578063c5ebeaec146109f6578063db006a7514610a20578063dd62ed3e14610a4a578063e597461914610a855761025c565b8063aae40a2a11610108578063aae40a2a1461084b578063ae9d70b014610879578063b2a02ff11461088e578063b71d1a0c146108d1578063bc3246d914610904578063bd6d894d146109885761025c565b806386945056146107a057806395dd9193146107b5578063991754d2146107e8578063a6afed95146107fd578063a9059cbb146108125761025c565b80633b1d21a2116101dd5780635fe3b567116101a15780635fe3b567146106da578063601a0bf1146106ef57806370a0823114610719578063721db5b11461074c57806373acee9814610761578063852a12e3146107765761025c565b80633b1d21a2146105e25780634487152f146105f7578063469ab1e3146106a85780634e4d9fea146106bd5780635c60da1b146106c55761025c565b80631be19560116102245780631be19560146104f357806323b872dd1461052657806326782247146105695780632f7034981461059a5780633af9e669146105af5761025c565b80630933c1ed1461031c578063095ea7b3146104425780631249c58b1461048f57806317bfdfbc14610499578063182df0f5146104de575b34156102995760405162461bcd60e51b8152600401808060200182810382526032815260200180611c8d6032913960400191505060405180910390fd5b6003546040516000916001600160a01b031690829036908083838082843760405192019450600093509091505080830381855af49150503d80600081146102fc576040519150601f19603f3d011682016040523d82523d6000602084013e610301565b606091505b505090506040513d6000823e818015610318573d82f35b3d82fd5b34801561032857600080fd5b506103cd6004803603602081101561033f57600080fd5b810190602081018135600160201b81111561035957600080fd5b82018360208201111561036b57600080fd5b803590602001918460018302840111600160201b8311171561038c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610b5c945050505050565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104075781810151838201526020016103ef565b50505050905090810190601f1680156104345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561044e57600080fd5b5061047b6004803603604081101561046557600080fd5b506001600160a01b038135169060200135610b7b565b604080519115158252519081900360200190f35b610497610bf2565b005b3480156104a557600080fd5b506104cc600480360360208110156104bc57600080fd5b50356001600160a01b0316610c27565b60408051918252519081900360200190f35b3480156104ea57600080fd5b506104cc610c99565b3480156104ff57600080fd5b506104976004803603602081101561051657600080fd5b50356001600160a01b0316610cf0565b34801561053257600080fd5b5061047b6004803603606081101561054957600080fd5b506001600160a01b03813581169160208101359091169060400135610d3f565b34801561057557600080fd5b5061057e610dbf565b604080516001600160a01b039092168252519081900360200190f35b3480156105a657600080fd5b5061057e610dce565b3480156105bb57600080fd5b506104cc600480360360208110156105d257600080fd5b50356001600160a01b0316610de6565b3480156105ee57600080fd5b506104cc610e38565b34801561060357600080fd5b506103cd6004803603602081101561061a57600080fd5b810190602081018135600160201b81111561063457600080fd5b82018360208201111561064657600080fd5b803590602001918460018302840111600160201b8311171561066757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610e6c945050505050565b3480156106b457600080fd5b506104cc61108b565b610497611091565b3480156106d157600080fd5b5061057e6110c3565b3480156106e657600080fd5b5061057e6110d2565b3480156106fb57600080fd5b506104cc6004803603602081101561071257600080fd5b50356110e1565b34801561072557600080fd5b506104cc6004803603602081101561073c57600080fd5b50356001600160a01b0316611128565b34801561075857600080fd5b506104cc61117a565b34801561076d57600080fd5b506104cc611186565b34801561078257600080fd5b506104cc6004803603602081101561079957600080fd5b50356111be565b3480156107ac57600080fd5b506104cc611205565b3480156107c157600080fd5b506104cc600480360360208110156107d857600080fd5b50356001600160a01b031661122d565b3480156107f457600080fd5b506104cc61127f565b34801561080957600080fd5b506104cc6112b7565b34801561081e57600080fd5b5061047b6004803603604081101561083557600080fd5b506001600160a01b0381351690602001356112ef565b6104976004803603604081101561086157600080fd5b506001600160a01b0381358116916020013516611345565b34801561088557600080fd5b506104cc61139e565b34801561089a57600080fd5b506104cc600480360360608110156108b157600080fd5b506001600160a01b038135811691602081013590911690604001356113d6565b3480156108dd57600080fd5b506104cc600480360360208110156108f457600080fd5b50356001600160a01b0316611434565b34801561091057600080fd5b5061047b6004803603604081101561092757600080fd5b813515159190810190604081016020820135600160201b81111561094a57600080fd5b82018360208201111561095c57600080fd5b803590602001918460018302840111600160201b8311171561097d57600080fd5b509092509050611486565b34801561099457600080fd5b506104cc6116c3565b3480156109a957600080fd5b506109d0600480360360208110156109c057600080fd5b50356001600160a01b03166116fb565b604080519485526020850193909352838301919091526060830152519081900360800190f35b348015610a0257600080fd5b506104cc60048036036020811015610a1957600080fd5b503561178d565b348015610a2c57600080fd5b506104cc60048036036020811015610a4357600080fd5b50356117d4565b348015610a5657600080fd5b506104cc60048036036040811015610a6d57600080fd5b506001600160a01b038135811691602001351661181b565b61049760048036036020811015610a9b57600080fd5b50356001600160a01b0316611875565b348015610ab757600080fd5b506104cc6118c1565b348015610acc57600080fd5b506104cc60048036036020811015610ae357600080fd5b50356001600160a01b03166118f9565b348015610aff57600080fd5b5061057e61194b565b348015610b1457600080fd5b506104cc61195a565b348015610b2957600080fd5b506104cc60048036036020811015610b4057600080fd5b5035611992565b348015610b5357600080fd5b5061047b6119d9565b600354606090610b75906001600160a01b0316836119de565b92915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052600090606090610bd190610b5c565b9050808060200190516020811015610be857600080fd5b5051949350505050565b6040805160048152602481019091526020810180516001600160e01b0316631249c58b60e01b179052610c2490610b5c565b50565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166305eff7ef60e21b179052600090606090610c7990610b5c565b9050808060200190516020811015610c9057600080fd5b50519392505050565b6040805160048152602481019091526020810180516001600160e01b031663182df0f560e01b179052600090606090610cd190610e6c565b9050808060200190516020811015610ce857600080fd5b505191505090565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031662df0cab60e51b179052610d3b90610b5c565b5050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052600090606090610d9d90610b5c565b9050808060200190516020811015610db457600080fd5b505195945050505050565b6001546001600160a01b031681565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b0316633af9e66960e01b179052600090606090610c7990610b5c565b6040805160048152602481019091526020810180516001600160e01b0316631d8e90d160e11b179052600090606090610cd1905b606060006060306001600160a01b0316846040516024018080602001828103825283818151815260200191508051906020019080838360005b83811015610ebd578181015183820152602001610ea5565b50505050905090810190601f168015610eea5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b0316630933c1ed60e01b178152905182519295509350839250908083835b60208310610f455780518252601f199092019160209182019101610f26565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610fa5576040519150601f19603f3d011682016040523d82523d6000602084013e610faa565b606091505b50915091506000821415610fbf573d60208201fd5b808060200190516020811015610fd457600080fd5b8101908080516040519392919084600160201b821115610ff357600080fd5b90830190602082018581111561100857600080fd5b8251600160201b81118282018810171561102157600080fd5b82525081516020918201929091019080838360005b8381101561104e578181015183820152602001611036565b50505050905090810190601f16801561107b5780820380516001836020036101000a031916815260200191505b5060405250505092505050919050565b60045481565b6040805160048152602481019091526020810180516001600160e01b0316632726cff560e11b179052610c2490610b5c565b6003546001600160a01b031681565b6002546001600160a01b031681565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663601a0bf160e01b179052600090606090610c7990610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166370a0823160e01b179052600090606090610c7990610e6c565b6706f05b59d3b2000081565b6040805160048152602481019091526020810180516001600160e01b0316630e759dd360e31b179052600090606090610cd190610b5c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663852a12e360e01b179052600090606090610c7990610b5c565b604080516f27a730ba34bb32a232b632b3b0ba37b960811b8152905190819003601001902081565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166395dd919360e01b179052600090606090610c7990610e6c565b6040805160048152602481019091526020810180516001600160e01b0316634c8baa6960e11b179052600090606090610cd190610e6c565b6040805160048152602481019091526020810180516001600160e01b031663a6afed9560e01b179052600090606090610cd190610b5c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052600090606090610bd190610b5c565b604080516001600160a01b03808516602483015283166044808301919091528251808303909101815260649091019091526020810180516001600160e01b0316635572051560e11b17905261139990610b5c565b505050565b6040805160048152602481019091526020810180516001600160e01b0316630ae9d70b60e41b179052600090606090610cd190610e6c565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b031663b2a02ff160e01b179052600090606090610d9d90610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b0316632dc7468360e21b179052600090606090610c7990610b5c565b6002546000906001600160a01b031633146114da576040805162461bcd60e51b815260206004820152600f60248201526e2737ba1031b7b6b83a3937b63632b960891b604482015290519081900360640190fd5b60025460408051635ab1bd5360e01b815290516000926001600160a01b031691635ab1bd53916004808301926020929190829003018186803b15801561151f57600080fd5b505afa158015611533573d6000803e3d6000fd5b505050506040513d602081101561154957600080fd5b50516002546004805460408051635fa4cae760e01b81526001600160a01b03948516938101939093526024830191909152519190921691635fa4cae79160448083019260209291908290030181600087803b1580156115a757600080fd5b505af11580156115bb573d6000803e3d6000fd5b505050506040513d60208110156115d157600080fd5b505190506001600160a01b038116611624576040805162461bcd60e51b815260206004820152601160248201527027379034b6b83632b6b2b73a30ba34b7b760791b604482015290519081900360640190fd5b6003546001600160a01b0382811691161461167f5761167a818686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611aa092505050565b6116b8565b6003546040516001600160a01b03909116907f4c1be6dd39236a8e070692d274dd5d9c6893e79d76431a2600b41b182a5c2fc290600090a25b506001949350505050565b6040805160048152602481019091526020810180516001600160e01b031663bd6d894d60e01b179052600090606090610cd190610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166361bfb47160e11b17905260009081908190819060609061175390610e6c565b905080806020019051608081101561176a57600080fd5b508051602082015160408301516060909301519199909850919650945092505050565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663317afabb60e21b179052600090606090610c7990610b5c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663db006a7560e01b179052600090606090610c7990610b5c565b604080516001600160a01b03808516602483015283166044808301919091528251808303909101815260649091019091526020810180516001600160e01b0316636eb1769f60e11b179052600090606090610bd190610e6c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031663e597461960e01b179052610d3b90610b5c565b6040805160048152602481019091526020810180516001600160e01b03166374e38a7960e11b179052600090606090610cd190610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031663f2b3abbd60e01b179052600090606090610c7990610b5c565b6000546001600160a01b031681565b6040805160048152602481019091526020810180516001600160e01b0316631f1f3b4560e31b179052600090606090610cd190610e6c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663fca7820b60e01b179052600090606090610c7990610b5c565b600181565b606060006060846001600160a01b0316846040518082805190602001908083835b60208310611a1e5780518252601f1990920191602091820191016119ff565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114611a7e576040519150601f19603f3d011682016040523d82523d6000602084013e611a83565b606091505b50915091506000821415611a98573d60208201fd5b949350505050565b8115611ada576040805160048152602481019091526020810180516001600160e01b031663153ab50560e01b179052611ad890610b5c565b505b826001600160a01b031663fe9c44ae6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1357600080fd5b505afa158015611b27573d6000803e3d6000fd5b505050506040513d6020811015611b3d57600080fd5b5051611b7e576040805162461bcd60e51b815260206004820152600b60248201526a4e6f742043546f6b656e7360a81b604482015290519081900360640190fd5b600380546001600160a01b038581166001600160a01b03198316179092556040516020602482018181528551604484015285519490931693611c4a938693909283926064909201919085019080838360005b83811015611be8578181015183820152602001611bd0565b50505050905090810190601f168015611c155780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b0316630adccee560e31b1790529250610b5c915050565b506003546040516001600160a01b03918216918316907fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a90600090a35050505056fe4f44656c656761746f723a66616c6c6261636b3a2063616e6e6f742073656e642076616c756520746f2066616c6c6261636ba265627a7a7231582004f98f1715397a84d65c3eede9b284823a1cfeb84c69682ee0f9f3b4a0973a2064736f6c63430005100032000000000000000000000000dbb6b59a58cedaec2eeac4a889d3329ea9fdd8e6000000000000000000000000d64c3186a9c6ae6c1e92a110f76ab86f4c6295f9000000000000000000000000000000000000000000a56fa5b99019a5c8000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000008000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d950000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000b4f6c6120476c696d6d657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056f474c4d520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361061025c5760003560e01c80638694505611610144578063c37f68e2116100b6578063e9c714f21161007a578063e9c714f214610aab578063f2b3abbd14610ac0578063f851a44014610af3578063f8f9da2814610b08578063fca7820b14610b1d578063fe9c44ae14610b475761025c565b8063c37f68e21461099d578063c5ebeaec146109f6578063db006a7514610a20578063dd62ed3e14610a4a578063e597461914610a855761025c565b8063aae40a2a11610108578063aae40a2a1461084b578063ae9d70b014610879578063b2a02ff11461088e578063b71d1a0c146108d1578063bc3246d914610904578063bd6d894d146109885761025c565b806386945056146107a057806395dd9193146107b5578063991754d2146107e8578063a6afed95146107fd578063a9059cbb146108125761025c565b80633b1d21a2116101dd5780635fe3b567116101a15780635fe3b567146106da578063601a0bf1146106ef57806370a0823114610719578063721db5b11461074c57806373acee9814610761578063852a12e3146107765761025c565b80633b1d21a2146105e25780634487152f146105f7578063469ab1e3146106a85780634e4d9fea146106bd5780635c60da1b146106c55761025c565b80631be19560116102245780631be19560146104f357806323b872dd1461052657806326782247146105695780632f7034981461059a5780633af9e669146105af5761025c565b80630933c1ed1461031c578063095ea7b3146104425780631249c58b1461048f57806317bfdfbc14610499578063182df0f5146104de575b34156102995760405162461bcd60e51b8152600401808060200182810382526032815260200180611c8d6032913960400191505060405180910390fd5b6003546040516000916001600160a01b031690829036908083838082843760405192019450600093509091505080830381855af49150503d80600081146102fc576040519150601f19603f3d011682016040523d82523d6000602084013e610301565b606091505b505090506040513d6000823e818015610318573d82f35b3d82fd5b34801561032857600080fd5b506103cd6004803603602081101561033f57600080fd5b810190602081018135600160201b81111561035957600080fd5b82018360208201111561036b57600080fd5b803590602001918460018302840111600160201b8311171561038c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610b5c945050505050565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104075781810151838201526020016103ef565b50505050905090810190601f1680156104345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561044e57600080fd5b5061047b6004803603604081101561046557600080fd5b506001600160a01b038135169060200135610b7b565b604080519115158252519081900360200190f35b610497610bf2565b005b3480156104a557600080fd5b506104cc600480360360208110156104bc57600080fd5b50356001600160a01b0316610c27565b60408051918252519081900360200190f35b3480156104ea57600080fd5b506104cc610c99565b3480156104ff57600080fd5b506104976004803603602081101561051657600080fd5b50356001600160a01b0316610cf0565b34801561053257600080fd5b5061047b6004803603606081101561054957600080fd5b506001600160a01b03813581169160208101359091169060400135610d3f565b34801561057557600080fd5b5061057e610dbf565b604080516001600160a01b039092168252519081900360200190f35b3480156105a657600080fd5b5061057e610dce565b3480156105bb57600080fd5b506104cc600480360360208110156105d257600080fd5b50356001600160a01b0316610de6565b3480156105ee57600080fd5b506104cc610e38565b34801561060357600080fd5b506103cd6004803603602081101561061a57600080fd5b810190602081018135600160201b81111561063457600080fd5b82018360208201111561064657600080fd5b803590602001918460018302840111600160201b8311171561066757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610e6c945050505050565b3480156106b457600080fd5b506104cc61108b565b610497611091565b3480156106d157600080fd5b5061057e6110c3565b3480156106e657600080fd5b5061057e6110d2565b3480156106fb57600080fd5b506104cc6004803603602081101561071257600080fd5b50356110e1565b34801561072557600080fd5b506104cc6004803603602081101561073c57600080fd5b50356001600160a01b0316611128565b34801561075857600080fd5b506104cc61117a565b34801561076d57600080fd5b506104cc611186565b34801561078257600080fd5b506104cc6004803603602081101561079957600080fd5b50356111be565b3480156107ac57600080fd5b506104cc611205565b3480156107c157600080fd5b506104cc600480360360208110156107d857600080fd5b50356001600160a01b031661122d565b3480156107f457600080fd5b506104cc61127f565b34801561080957600080fd5b506104cc6112b7565b34801561081e57600080fd5b5061047b6004803603604081101561083557600080fd5b506001600160a01b0381351690602001356112ef565b6104976004803603604081101561086157600080fd5b506001600160a01b0381358116916020013516611345565b34801561088557600080fd5b506104cc61139e565b34801561089a57600080fd5b506104cc600480360360608110156108b157600080fd5b506001600160a01b038135811691602081013590911690604001356113d6565b3480156108dd57600080fd5b506104cc600480360360208110156108f457600080fd5b50356001600160a01b0316611434565b34801561091057600080fd5b5061047b6004803603604081101561092757600080fd5b813515159190810190604081016020820135600160201b81111561094a57600080fd5b82018360208201111561095c57600080fd5b803590602001918460018302840111600160201b8311171561097d57600080fd5b509092509050611486565b34801561099457600080fd5b506104cc6116c3565b3480156109a957600080fd5b506109d0600480360360208110156109c057600080fd5b50356001600160a01b03166116fb565b604080519485526020850193909352838301919091526060830152519081900360800190f35b348015610a0257600080fd5b506104cc60048036036020811015610a1957600080fd5b503561178d565b348015610a2c57600080fd5b506104cc60048036036020811015610a4357600080fd5b50356117d4565b348015610a5657600080fd5b506104cc60048036036040811015610a6d57600080fd5b506001600160a01b038135811691602001351661181b565b61049760048036036020811015610a9b57600080fd5b50356001600160a01b0316611875565b348015610ab757600080fd5b506104cc6118c1565b348015610acc57600080fd5b506104cc60048036036020811015610ae357600080fd5b50356001600160a01b03166118f9565b348015610aff57600080fd5b5061057e61194b565b348015610b1457600080fd5b506104cc61195a565b348015610b2957600080fd5b506104cc60048036036020811015610b4057600080fd5b5035611992565b348015610b5357600080fd5b5061047b6119d9565b600354606090610b75906001600160a01b0316836119de565b92915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052600090606090610bd190610b5c565b9050808060200190516020811015610be857600080fd5b5051949350505050565b6040805160048152602481019091526020810180516001600160e01b0316631249c58b60e01b179052610c2490610b5c565b50565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166305eff7ef60e21b179052600090606090610c7990610b5c565b9050808060200190516020811015610c9057600080fd5b50519392505050565b6040805160048152602481019091526020810180516001600160e01b031663182df0f560e01b179052600090606090610cd190610e6c565b9050808060200190516020811015610ce857600080fd5b505191505090565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031662df0cab60e51b179052610d3b90610b5c565b5050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052600090606090610d9d90610b5c565b9050808060200190516020811015610db457600080fd5b505195945050505050565b6001546001600160a01b031681565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b0316633af9e66960e01b179052600090606090610c7990610b5c565b6040805160048152602481019091526020810180516001600160e01b0316631d8e90d160e11b179052600090606090610cd1905b606060006060306001600160a01b0316846040516024018080602001828103825283818151815260200191508051906020019080838360005b83811015610ebd578181015183820152602001610ea5565b50505050905090810190601f168015610eea5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b0316630933c1ed60e01b178152905182519295509350839250908083835b60208310610f455780518252601f199092019160209182019101610f26565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610fa5576040519150601f19603f3d011682016040523d82523d6000602084013e610faa565b606091505b50915091506000821415610fbf573d60208201fd5b808060200190516020811015610fd457600080fd5b8101908080516040519392919084600160201b821115610ff357600080fd5b90830190602082018581111561100857600080fd5b8251600160201b81118282018810171561102157600080fd5b82525081516020918201929091019080838360005b8381101561104e578181015183820152602001611036565b50505050905090810190601f16801561107b5780820380516001836020036101000a031916815260200191505b5060405250505092505050919050565b60045481565b6040805160048152602481019091526020810180516001600160e01b0316632726cff560e11b179052610c2490610b5c565b6003546001600160a01b031681565b6002546001600160a01b031681565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663601a0bf160e01b179052600090606090610c7990610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166370a0823160e01b179052600090606090610c7990610e6c565b6706f05b59d3b2000081565b6040805160048152602481019091526020810180516001600160e01b0316630e759dd360e31b179052600090606090610cd190610b5c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663852a12e360e01b179052600090606090610c7990610b5c565b604080516f27a730ba34bb32a232b632b3b0ba37b960811b8152905190819003601001902081565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166395dd919360e01b179052600090606090610c7990610e6c565b6040805160048152602481019091526020810180516001600160e01b0316634c8baa6960e11b179052600090606090610cd190610e6c565b6040805160048152602481019091526020810180516001600160e01b031663a6afed9560e01b179052600090606090610cd190610b5c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052600090606090610bd190610b5c565b604080516001600160a01b03808516602483015283166044808301919091528251808303909101815260649091019091526020810180516001600160e01b0316635572051560e11b17905261139990610b5c565b505050565b6040805160048152602481019091526020810180516001600160e01b0316630ae9d70b60e41b179052600090606090610cd190610e6c565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b031663b2a02ff160e01b179052600090606090610d9d90610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b0316632dc7468360e21b179052600090606090610c7990610b5c565b6002546000906001600160a01b031633146114da576040805162461bcd60e51b815260206004820152600f60248201526e2737ba1031b7b6b83a3937b63632b960891b604482015290519081900360640190fd5b60025460408051635ab1bd5360e01b815290516000926001600160a01b031691635ab1bd53916004808301926020929190829003018186803b15801561151f57600080fd5b505afa158015611533573d6000803e3d6000fd5b505050506040513d602081101561154957600080fd5b50516002546004805460408051635fa4cae760e01b81526001600160a01b03948516938101939093526024830191909152519190921691635fa4cae79160448083019260209291908290030181600087803b1580156115a757600080fd5b505af11580156115bb573d6000803e3d6000fd5b505050506040513d60208110156115d157600080fd5b505190506001600160a01b038116611624576040805162461bcd60e51b815260206004820152601160248201527027379034b6b83632b6b2b73a30ba34b7b760791b604482015290519081900360640190fd5b6003546001600160a01b0382811691161461167f5761167a818686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611aa092505050565b6116b8565b6003546040516001600160a01b03909116907f4c1be6dd39236a8e070692d274dd5d9c6893e79d76431a2600b41b182a5c2fc290600090a25b506001949350505050565b6040805160048152602481019091526020810180516001600160e01b031663bd6d894d60e01b179052600090606090610cd190610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166361bfb47160e11b17905260009081908190819060609061175390610e6c565b905080806020019051608081101561176a57600080fd5b508051602082015160408301516060909301519199909850919650945092505050565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663317afabb60e21b179052600090606090610c7990610b5c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663db006a7560e01b179052600090606090610c7990610b5c565b604080516001600160a01b03808516602483015283166044808301919091528251808303909101815260649091019091526020810180516001600160e01b0316636eb1769f60e11b179052600090606090610bd190610e6c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031663e597461960e01b179052610d3b90610b5c565b6040805160048152602481019091526020810180516001600160e01b03166374e38a7960e11b179052600090606090610cd190610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031663f2b3abbd60e01b179052600090606090610c7990610b5c565b6000546001600160a01b031681565b6040805160048152602481019091526020810180516001600160e01b0316631f1f3b4560e31b179052600090606090610cd190610e6c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663fca7820b60e01b179052600090606090610c7990610b5c565b600181565b606060006060846001600160a01b0316846040518082805190602001908083835b60208310611a1e5780518252601f1990920191602091820191016119ff565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114611a7e576040519150601f19603f3d011682016040523d82523d6000602084013e611a83565b606091505b50915091506000821415611a98573d60208201fd5b949350505050565b8115611ada576040805160048152602481019091526020810180516001600160e01b031663153ab50560e01b179052611ad890610b5c565b505b826001600160a01b031663fe9c44ae6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1357600080fd5b505afa158015611b27573d6000803e3d6000fd5b505050506040513d6020811015611b3d57600080fd5b5051611b7e576040805162461bcd60e51b815260206004820152600b60248201526a4e6f742043546f6b656e7360a81b604482015290519081900360640190fd5b600380546001600160a01b038581166001600160a01b03198316179092556040516020602482018181528551604484015285519490931693611c4a938693909283926064909201919085019080838360005b83811015611be8578181015183820152602001611bd0565b50505050905090810190601f168015611c155780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b0316630adccee560e31b1790529250610b5c915050565b506003546040516001600160a01b03918216918316907fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a90600090a35050505056fe4f44656c656761746f723a66616c6c6261636b3a2063616e6e6f742073656e642076616c756520746f2066616c6c6261636ba265627a7a7231582004f98f1715397a84d65c3eede9b284823a1cfeb84c69682ee0f9f3b4a0973a2064736f6c63430005100032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000dbb6b59a58cedaec2eeac4a889d3329ea9fdd8e6000000000000000000000000d64c3186a9c6ae6c1e92a110f76ab86f4c6295f9000000000000000000000000000000000000000000a56fa5b99019a5c8000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000008000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d950000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000b4f6c6120476c696d6d657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056f474c4d520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : comptroller_ (address): 0xdBB6B59a58CEDaEC2eeAc4A889D3329Ea9fdd8e6
Arg [1] : interestRateModel_ (address): 0xD64c3186A9C6ae6c1E92A110F76ab86F4C6295F9
Arg [2] : initialExchangeRateMantissa_ (uint256): 200000000000000000000000000
Arg [3] : name_ (string): Ola Glimmer
Arg [4] : symbol_ (string): oGLMR
Arg [5] : decimals_ (uint8): 8
Arg [6] : admin_ (address): 0xc333A03e8040CaD31993E02615Fd1b3F88447d95
Arg [7] : becomeImplementationData (bytes): 0x
-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 000000000000000000000000dbb6b59a58cedaec2eeac4a889d3329ea9fdd8e6
Arg [1] : 000000000000000000000000d64c3186a9c6ae6c1e92a110f76ab86f4c6295f9
Arg [2] : 000000000000000000000000000000000000000000a56fa5b99019a5c8000000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [6] : 000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d95
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [8] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [9] : 4f6c6120476c696d6d6572000000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [11] : 6f474c4d52000000000000000000000000000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
54067:17754:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53395:9;:14;53387:76;;;;-1:-1:-1;;;53387:76:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53562:14;;:37;;53544:12;;-1:-1:-1;;;;;53562:14:0;;53544:12;;53590:8;;53562:37;53544:12;53590:8;;53544:12;53562:37;1:33:-1;53562:37:0;;45:16:-1;;;-1:-1;53562:37:0;;-1:-1:-1;53562:37:0;;-1:-1:-1;;53562:37:0;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;53543:56:0;;;53662:4;53656:11;53713:14;53710:1;53696:12;53681:47;53751:7;53772:47;;;;53864:14;53850:12;53843:36;53772:47;53802:14;53788:12;53781:36;51367:141;;8:9:-1;5:2;;;30:1;27;20:12;5:2;51367:141:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;51367:141:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;51367:141:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;51367:141:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;51367:141:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;51367:141:0;;-1:-1:-1;51367:141:0;;-1:-1:-1;;;;;51367:141:0:i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;51367:141:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61189:249;;8:9:-1;5:2;;;30:1;27;20:12;5:2;61189:249:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;61189:249:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;56687:111;;;:::i;:::-;;65000:243;;8:9:-1;5:2;;;30:1;27;20:12;5:2;65000:243:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;65000:243:0;-1:-1:-1;;;;;65000:243:0;;:::i;:::-;;;;;;;;;;;;;;;;66312:215;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66312:215:0;;;:::i;68764:160::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;68764:160:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;68764:160:0;-1:-1:-1;;;;;68764:160:0;;:::i;60442:277::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60442:277:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;60442:277:0;;;;;;;;;;;;;;;;;:::i;35957:35::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;35957:35:0;;;:::i;:::-;;;;-1:-1:-1;;;;;35957:35:0;;;;;;;;;;;;;;40160:98;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40160:98:0;;;:::i;62700:237::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;62700:237:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;62700:237:0;-1:-1:-1;;;;;62700:237:0;;:::i;66697:195::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66697:195:0;;;:::i;51930:434::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;51930:434:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;51930:434:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;51930:434:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;51930:434:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;51930:434:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;51930:434:0;;-1:-1:-1;51930:434:0;;-1:-1:-1;;;;;51930:434:0:i;36287:31::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36287:31:0;;;:::i;58570:125::-;;;:::i;36206:29::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36206:29:0;;;:::i;36083:39::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36083:39:0;;;:::i;70930:240::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;70930:240:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;70930:240:0;;:::i;62218:226::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;62218:226:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;62218:226:0;-1:-1:-1;;;;;62218:226:0;;:::i;40419:54::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40419:54:0;;;:::i;64499:210::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64499:210:0;;;:::i;57727:242::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57727:242:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;57727:242:0;;:::i;54197:84::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54197:84:0;;;:::i;65452:248::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;65452:248:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;65452:248:0;-1:-1:-1;;;;;65452:248:0;;:::i;67019:223::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;67019:223:0;;;:::i;67498:198::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;67498:198:0;;;:::i;59895:240::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59895:240:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;59895:240:0;;;;;;;;:::i;59408:226::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;59408:226:0;;;;;;;;;;:::i;64136:217::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64136:217:0;;;:::i;68257:294::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;68257:294:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;68257:294:0;;;;;;;;;;;;;;;;;:::i;69373:259::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;69373:259:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;69373:259:0;-1:-1:-1;;;;;69373:259:0;;:::i;52372:780::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52372:780:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;52372:780:0;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;52372:780:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;52372:780:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;52372:780:0;;-1:-1:-1;52372:780:0;-1:-1:-1;52372:780:0;:::i;65854:208::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;65854:208:0;;;:::i;63283:284::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;63283:284:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;63283:284:0;-1:-1:-1;;;;;63283:284:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58237:222;;8:9:-1;5:2;;;30:1;27;20:12;5:2;58237:222:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;58237:222:0;;:::i;57149:::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57149:222:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;57149:222:0;;:::i;61768:260::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;61768:260:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;61768:260:0;;;;;;;;;;:::i;58886:170::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;58886:170:0;-1:-1:-1;;;;;58886:170:0;;:::i;70481:196::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;70481:196:0;;;:::i;71539:279::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;71539:279:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;71539:279:0;-1:-1:-1;;;;;71539:279:0;;:::i;35846:28::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;35846:28:0;;;:::i;63743:217::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;63743:217:0;;;:::i;69935:268::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;69935:268:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;69935:268:0;;:::i;40574:36::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40574:36:0;;;:::i;51367:141::-;51479:14;;51436:12;;51468:32;;-1:-1:-1;;;;;51479:14:0;51495:4;51468:10;:32::i;:::-;51461:39;51367:141;-1:-1:-1;;51367:141:0:o;61189:249::-;61319:68;;;-1:-1:-1;;;;;61319:68:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;61319:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;61257:4:0;;61274:17;;61294:94;;:24;:94::i;:::-;61274:114;;61417:4;61406:24;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;61406:24:0;;61189:249;-1:-1:-1;;;;61189:249:0:o;56687:111::-;56756:33;;;22:32:-1;6:49;;56756:33:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;56731:59:0;;:24;:59::i;:::-;;56687:111::o;65000:243::-;65127:65;;;-1:-1:-1;;;;;65127:65:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;65127:65:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;65065:4:0;;65082:17;;65102:91;;:24;:91::i;:::-;65082:111;;65222:4;65211:24;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;65211:24:0;;65000:243;-1:-1:-1;;;65000:243:0:o;66312:215::-;66429:47;;;22:32:-1;6:49;;66429:47:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;66363:4:0;;66380:17;;66400:77;;:28;:77::i;:::-;66380:97;;66506:4;66495:24;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;66495:24:0;;-1:-1:-1;;66312:215:0;:::o;68764:160::-;68862:53;;;-1:-1:-1;;;;;68862:53:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;68862:53:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;68837:79:0;;:24;:79::i;:::-;;68764:160;:::o;60442:277::-;60586:82;;;-1:-1:-1;;;;;60586:82:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;60586:82:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;60524:4:0;;60541:17;;60561:108;;:24;:108::i;:::-;60541:128;;60698:4;60687:24;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;60687:24:0;;60442:277;-1:-1:-1;;;;;60442:277:0:o;35957:35::-;;;-1:-1:-1;;;;;35957:35:0;;:::o;40160:98::-;40215:42;40160:98;:::o;62700:237::-;62824:62;;;-1:-1:-1;;;;;62824:62:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;62824:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;62762:4:0;;62779:17;;62799:88;;:24;:88::i;66697:195::-;66805:36;;;22:32:-1;6:49;;66805:36:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;66739:4:0;;66756:17;;66776:66;;51930:434;52008:12;52034;52048:23;52083:4;-1:-1:-1;;;;;52075:24:0;52159:4;52100:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;52100:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;52100:64:0;;;-1:-1:-1;;26:21;;;22:32;6:49;;52100:64:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;52075:90:0;;;;52100:64;;-1:-1:-1;52075:90:0;-1:-1:-1;52075:90:0;;-1:-1:-1;25:18;52075:90:0;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;52075:90:0;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;52033:132:0;;;;52215:1;52206:7;52203:14;52200:2;;;52267:14;52260:4;52248:10;52244:21;52237:45;52200:2;52336:10;52325:31;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;52325:31:0;;;;;;;;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;52325:31:0;;420:4:-1;411:14;;;;52325:31:0;;;;;411:14:-1;52325:31:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;52325:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52318:38;;;;51930:434;;;:::o;36287:31::-;;;;:::o;58570:125::-;58646:40;;;22:32:-1;6:49;;58646:40:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;58621:66:0;;:24;:66::i;36206:29::-;;;-1:-1:-1;;;;;36206:29:0;;:::o;36083:39::-;;;-1:-1:-1;;;;;36083:39:0;;:::o;70930:240::-;71054:65;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;71054:65:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;70992:4:0;;71009:17;;71029:91;;:24;:91::i;62218:226::-;62341:52;;;-1:-1:-1;;;;;62341:52:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;62341:52:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;62275:4:0;;62292:17;;62312:82;;:28;:82::i;40419:54::-;40467:6;40419:54;:::o;64499:210::-;64610:48;;;22:32:-1;6:49;;64610:48:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;64548:4:0;;64565:17;;64585:74;;:24;:74::i;57727:242::-;57852:66;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;57852:66:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;57790:4:0;;57807:17;;57827:92;;:24;:92::i;54197:84::-;54252:29;;;-1:-1:-1;;;54252:29:0;;;;;;;;;;;;54197:84;:::o;65452:248::-;65585:64;;;-1:-1:-1;;;;;65585:64:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;65585:64:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;65519:4:0;;65536:17;;65556:94;;:28;:94::i;67019:223::-;67141:50;;;22:32:-1;6:49;;67141:50:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;67075:4:0;;67092:17;;67112:80;;:28;:80::i;67498:198::-;67602:43;;;22:32:-1;6:49;;67602:43:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;67540:4:0;;67557:17;;67577:69;;:24;:69::i;59895:240::-;60019:65;;;-1:-1:-1;;;;;60019:65:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;60019:65:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;59957:4:0;;59974:17;;59994:91;;:24;:91::i;59408:226::-;59538:87;;;-1:-1:-1;;;;;59538:87:0;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;59538:87:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;59513:113:0;;:24;:113::i;:::-;;59408:226;;:::o;64136:217::-;64255:47;;;22:32:-1;6:49;;64255:47:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;64189:4:0;;64206:17;;64226:77;;:28;:77::i;68257:294::-;68408:92;;;-1:-1:-1;;;;;68408:92:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;68408:92:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;68346:4:0;;68363:17;;68383:118;;:24;:118::i;69373:259::-;69512:69;;;-1:-1:-1;;;;;69512:69:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;69512:69:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;69450:4:0;;69467:17;;69487:95;;:24;:95::i;52372:780::-;52538:11;;52491:4;;-1:-1:-1;;;;;52538:11:0;52516:10;:34;52508:62;;;;;-1:-1:-1;;;52508:62:0;;;;;;;;;;;;-1:-1:-1;;;52508:62:0;;;;;;;;;;;;;;;52633:11;;:25;;;-1:-1:-1;;;52633:25:0;;;;52581:27;;-1:-1:-1;;;;;52633:11:0;;:23;;:25;;;;;;;;;;;;;;:11;:25;;;5:2:-1;;;;30:1;27;20:12;5:2;52633:25:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;52633:25:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;52633:25:0;52691:11;;52705:16;;;52611:111;;;-1:-1:-1;;;52611:111:0;;-1:-1:-1;;;;;52691:11:0;;;52611:111;;;;;;;;;;;;;;;:71;;;;;;;:111;;;;;52633:25;;52611:111;;;;;;;52691:11;52611:71;:111;;;5:2:-1;;;;30:1;27;20:12;5:2;52611:111:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;52611:111:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;52611:111:0;;-1:-1:-1;;;;;;52741:33:0;;52733:63;;;;;-1:-1:-1;;;52733:63:0;;;;;;;;;;;;-1:-1:-1;;;52733:63:0;;;;;;;;;;;;;;;52836:14;;-1:-1:-1;;;;;52813:37:0;;;52836:14;;52813:37;52809:312;;52951:78;52970:19;52991:11;53004:24;;52951:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;52951:18:0;;-1:-1:-1;;;52951:78:0:i;:::-;52809:312;;;53094:14;;53067:42;;-1:-1:-1;;;;;53094:14:0;;;;53067:42;;53094:14;;53067:42;52809:312;-1:-1:-1;53140:4:0;;52372:780;-1:-1:-1;;;;52372:780:0:o;65854:208::-;65963:48;;;22:32:-1;6:49;;65963:48:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;65901:4:0;;65918:17;;65938:74;;:24;:74::i;63283:284::-;63435:63;;;-1:-1:-1;;;;;63435:63:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;63435:63:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;63351:4:0;;;;;;;;63386:17;;63406:93;;:28;:93::i;:::-;63386:113;;63528:4;63517:42;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;63517:42:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;63517:42:0;;-1:-1:-1;63517:42:0;-1:-1:-1;63283:284:0;-1:-1:-1;;;63283:284:0:o;58237:222::-;58352:56;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;58352:56:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;58290:4:0;;58307:17;;58327:82;;:24;:82::i;57149:222::-;57264:56;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;57264:56:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;57202:4:0;;57219:17;;57239:82;;:24;:82::i;61768:260::-;61908:69;;;-1:-1:-1;;;;;61908:69:0;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;61908:69:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;61842:4:0;;61859:17;;61879:99;;:28;:99::i;58886:170::-;58984:63;;;-1:-1:-1;;;;;58984:63:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;58984:63:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;58959:89:0;;:24;:89::i;70481:196::-;70585:41;;;22:32:-1;6:49;;70585:41:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;70523:4:0;;70540:17;;70560:67;;:24;:67::i;71539:279::-;71688:79;;;-1:-1:-1;;;;;71688:79:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;71688:79:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;71626:4:0;;71643:17;;71663:105;;:24;:105::i;35846:28::-;;;-1:-1:-1;;;;;35846:28:0;;:::o;63743:217::-;63862:47;;;22:32:-1;6:49;;63862:47:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;63796:4:0;;63813:17;;63833:77;;:28;:77::i;69935:268::-;70073:79;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;70073:79:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;70011:4:0;;70028:17;;70048:105;;:24;:105::i;40574:36::-;40606:4;40574:36;:::o;50722:343::-;50795:12;50821;50835:23;50862:6;-1:-1:-1;;;;;50862:19:0;50882:4;50862:25;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;50862:25:0;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;50820:67:0;;;;50937:1;50928:7;50925:14;50922:2;;;50989:14;50982:4;50970:10;50966:21;50959:45;50922:2;51047:10;50722:343;-1:-1:-1;;;;50722:343:0:o;49719:643::-;49853:11;49849:120;;;49906:50;;;22:32:-1;6:49;;49906:50:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;49881:76:0;;:24;:76::i;:::-;;49849:120;50021:15;-1:-1:-1;;;;;50014:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;50014:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;50014:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;50014:34:0;50006:58;;;;;-1:-1:-1;;;50006:58:0;;;;;;;;;;;;-1:-1:-1;;;50006:58:0;;;;;;;;;;;;;;;50105:14;;;-1:-1:-1;;;;;50130:32:0;;;-1:-1:-1;;;;;;50130:32:0;;;;;;50202:81;;;;;;;;;;;;;;;;;50105:14;;;;;50177:107;;50258:24;;50202:81;;;;;;;;;;;;;;;;50077:25;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;50202:81:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;50202:81:0;;;-1:-1:-1;;26:21;;;22:32;6:49;;50202:81:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;50202:81:0;-1:-1:-1;50177:24:0;;-1:-1:-1;;50177:107:0:i;:::-;-1:-1:-1;50339:14:0;;50302:52;;-1:-1:-1;;;;;50339:14:0;;;;50302:52;;;;;50339:14;;50302:52;49719:643;;;;:::o
Swarm Source
bzzr://04f98f1715397a84d65c3eede9b284823a1cfeb84c69682ee0f9f3b4a0973a20
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.13
Net Worth in GLMR
Token Allocations
GLMR
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| GLMR | 100.00% | $0.016815 | 7.5781 | $0.127425 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.