Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Initialize | 19782452 | 661 days ago | IN | 0 ETH | 0.00163487 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
LendingPoolCore
Compiler Version
v0.5.17+commit.d19bba13
Optimization Enabled:
Yes with 200 runs
Other Settings:
istanbul EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.5.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, 'SafeMath: addition overflow');
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, 'SafeMath: subtraction overflow');
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, 'SafeMath: multiplication overflow');
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, 'SafeMath: division by zero');
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, 'SafeMath: modulo by zero');
return a % b;
}
}
/**
* @title WadRayMath library
* @author Aave
* @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits)
**/
library WadRayMath {
using SafeMath for uint256;
uint256 internal constant WAD = 1e18;
uint256 internal constant halfWAD = WAD / 2;
uint256 internal constant RAY = 1e27;
uint256 internal constant halfRAY = RAY / 2;
uint256 internal constant WAD_RAY_RATIO = 1e9;
/**
* @return one ray, 1e27
**/
function ray() internal pure returns (uint256) {
return RAY;
}
/**
* @return one wad, 1e18
**/
function wad() internal pure returns (uint256) {
return WAD;
}
/**
* @return half ray, 1e27/2
**/
function halfRay() internal pure returns (uint256) {
return halfRAY;
}
/**
* @return half ray, 1e18/2
**/
function halfWad() internal pure returns (uint256) {
return halfWAD;
}
/**
* @dev multiplies two wad, rounding half up to the nearest wad
* @param a wad
* @param b wad
* @return the result of a*b, in wad
**/
function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
return halfWAD.add(a.mul(b)).div(WAD);
}
/**
* @dev divides two wad, rounding half up to the nearest wad
* @param a wad
* @param b wad
* @return the result of a/b, in wad
**/
function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 halfB = b / 2;
return halfB.add(a.mul(WAD)).div(b);
}
/**
* @dev multiplies two ray, rounding half up to the nearest ray
* @param a ray
* @param b ray
* @return the result of a*b, in ray
**/
function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
return halfRAY.add(a.mul(b)).div(RAY);
}
/**
* @dev divides two ray, rounding half up to the nearest ray
* @param a ray
* @param b ray
* @return the result of a/b, in ray
**/
function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 halfB = b / 2;
return halfB.add(a.mul(RAY)).div(b);
}
/**
* @dev casts ray down to wad
* @param a ray
* @return a casted to wad, rounded half up to the nearest wad
**/
function rayToWad(uint256 a) internal pure returns (uint256) {
uint256 halfRatio = WAD_RAY_RATIO / 2;
return halfRatio.add(a).div(WAD_RAY_RATIO);
}
/**
* @dev convert wad up to ray
* @param a wad
* @return a converted in ray
**/
function wadToRay(uint256 a) internal pure returns (uint256) {
return a.mul(WAD_RAY_RATIO);
}
/**
* @dev calculates base^exp. The code uses the ModExp precompile
* @return base^exp, in ray
*/
//solium-disable-next-line
function rayPow(uint256 x, uint256 n) internal pure returns (uint256 z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rayMul(x, x);
if (n % 2 != 0) {
z = rayMul(z, x);
}
}
}
}
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the `nonReentrant` modifier
* available, which can be aplied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*/
contract ReentrancyGuard {
/// @dev counter to allow mutex lock with only one SSTORE operation
uint256 private _guardCounter;
constructor() internal {
// The counter starts at one to prevent changing it from zero to a non-zero
// value, which is a more expensive operation.
_guardCounter = 1;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_guardCounter += 1;
uint256 localCounter = _guardCounter;
_;
require(localCounter == _guardCounter, 'ReentrancyGuard: reentrant call');
}
}
/**
* @dev Collection of functions related to the address type,
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* This test is non-exhaustive, and there may be false-negatives: during the
* execution of a contract's constructor, its address will be reported as
* not containing a contract.
*
* > It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*/
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through `transferFrom`. This is
* zero by default.
*
* This value changes when `approve` or `transferFrom` are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* > Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an `Approval` event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to `approve`. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
* @dev Implementation of the `IERC20` interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using `_mint`.
* For a generic mechanism see `ERC20Mintable`.
*
* *For a detailed writeup see our guide [How to implement supply
* mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).*
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an `Approval` event is emitted on calls to `transferFrom`.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard `decreaseAllowance` and `increaseAllowance`
* functions have been added to mitigate the well-known issues around setting
* allowances. See `IERC20.approve`.
*/
contract ERC20 is IERC20 {
using SafeMath for uint256;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
/**
* @dev See `IERC20.totalSupply`.
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev See `IERC20.balanceOf`.
*/
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
/**
* @dev See `IERC20.transfer`.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
/**
* @dev See `IERC20.allowance`.
*/
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See `IERC20.approve`.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
/**
* @dev See `IERC20.transferFrom`.
*
* Emits an `Approval` event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of `ERC20`;
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `value`.
* - the caller must have allowance for `sender`'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to `approve` that can be used as a mitigation for
* problems described in `IERC20.approve`.
*
* Emits an `Approval` event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to `approve` that can be used as a mitigation for
* problems described in `IERC20.approve`.
*
* Emits an `Approval` event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue));
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to `transfer`, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a `Transfer` event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), 'ERC20: transfer from the zero address');
require(recipient != address(0), 'ERC20: transfer to the zero address');
_balances[sender] = _balances[sender].sub(amount);
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a `Transfer` event with `from` set to the zero address.
*
* Requirements
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal {
require(account != address(0), 'ERC20: mint to the zero address');
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
/**
* @dev Destoys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a `Transfer` event with `to` set to the zero address.
*
* Requirements
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 value) internal {
require(account != address(0), 'ERC20: burn from the zero address');
_totalSupply = _totalSupply.sub(value);
_balances[account] = _balances[account].sub(value);
emit Transfer(account, address(0), value);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
*
* This is internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an `Approval` event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 value) internal {
require(owner != address(0), 'ERC20: approve from the zero address');
require(spender != address(0), 'ERC20: approve to the zero address');
_allowances[owner][spender] = value;
emit Approval(owner, spender, value);
}
/**
* @dev Destoys `amount` tokens from `account`.`amount` is then deducted
* from the caller's allowance.
*
* See `_burn` and `_approve`.
*/
function _burnFrom(address account, uint256 amount) internal {
_burn(account, amount);
_approve(account, msg.sender, _allowances[account][msg.sender].sub(amount));
}
}
/**
* @dev Optional functions from the ERC20 standard.
*/
contract ERC20Detailed is IERC20 {
string private _name;
string private _symbol;
uint8 private _decimals;
/**
* @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
* these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name, string memory symbol, uint8 decimals) public {
_name = name;
_symbol = symbol;
_decimals = decimals;
}
/**
* @dev Returns the name of the token.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei.
*
* > Note that this information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* `IERC20.balanceOf` and `IERC20.transfer`.
*/
function decimals() public view returns (uint8) {
return _decimals;
}
}
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
'SafeERC20: approve from non-zero to non-zero allowance'
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value);
callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
);
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), 'SafeERC20: call to non-contract');
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, 'SafeERC20: low-level call failed');
if (returndata.length > 0) {
// Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
}
}
}
/**
* @title VersionedInitializable
*
* @dev Helper contract to support initializer functions. To use it, replace
* the constructor with a function that has the `initializer` modifier.
* WARNING: Unlike constructors, initializer functions must be manually
* invoked. This applies both to deploying an Initializable contract, as well
* as extending an Initializable contract via inheritance.
* WARNING: When used with inheritance, manual care must be taken to not invoke
* a parent initializer twice, or ensure that all initializers are idempotent,
* because this is not dealt with automatically as with constructors.
*
* @author Aave, inspired by the OpenZeppelin Initializable contract
*/
contract VersionedInitializable {
/**
* @dev Indicates that the contract has been initialized.
*/
uint256 private lastInitializedRevision = 0;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private initializing;
/**
* @dev Modifier to use in the initializer function of a contract.
*/
modifier initializer() {
uint256 revision = getRevision();
require(
initializing || isConstructor() || revision > lastInitializedRevision,
'Contract instance has already been initialized'
);
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
lastInitializedRevision = revision;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
/// @dev returns the revision number of the contract.
/// Needs to be defined in the inherited class as a constant.
function getRevision() internal pure returns (uint256);
/// @dev Returns true if and only if the function is running in the constructor
function isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
uint256 cs;
//solium-disable-next-line
assembly {
cs := extcodesize(address)
}
return cs == 0;
}
// Reserved storage space to allow for layout changes in the future.
uint256[50] private ______gap;
}
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be aplied to your functions to restrict their use to
* the owner.
*/
contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), 'Ownable: caller is not the owner');
_;
}
/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* > Note: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), 'Ownable: new owner is the zero address');
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
/**
* @title Proxy
* @dev Implements delegation of calls to other contracts, with proper
* forwarding of return values and bubbling of failures.
* It defines a fallback function that delegates all calls to the address
* returned by the abstract _implementation() internal function.
*/
contract Proxy {
/**
* @dev Fallback function.
* Implemented entirely in `_fallback`.
*/
function() external payable {
_fallback();
}
/**
* @return The Address of the implementation.
*/
function _implementation() internal view returns (address);
/**
* @dev Delegates execution to an implementation contract.
* This is a low level function that doesn't return to its internal call site.
* It will return to the external caller whatever the implementation returns.
* @param implementation Address to delegate.
*/
function _delegate(address implementation) internal {
//solium-disable-next-line
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize)
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize)
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize)
}
default {
return(0, returndatasize)
}
}
}
/**
* @dev Function that is run as the first thing in the fallback function.
* Can be redefined in derived contracts to add functionality.
* Redefinitions must call super._willFallback().
*/
function _willFallback() internal {}
/**
* @dev fallback implementation.
* Extracted to enable manual triggering.
*/
function _fallback() internal {
_willFallback();
_delegate(_implementation());
}
}
/**
* @title BaseUpgradeabilityProxy
* @dev This contract implements a proxy that allows to change the
* implementation address to which it will delegate.
* Such a change is called an implementation upgrade.
*/
contract BaseUpgradeabilityProxy is Proxy {
/**
* @dev Emitted when the implementation is upgraded.
* @param implementation Address of the new implementation.
*/
event Upgraded(address indexed implementation);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant IMPLEMENTATION_SLOT =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation.
* @return Address of the current implementation
*/
function _implementation() internal view returns (address impl) {
bytes32 slot = IMPLEMENTATION_SLOT;
//solium-disable-next-line
assembly {
impl := sload(slot)
}
}
/**
* @dev Upgrades the proxy to a new implementation.
* @param newImplementation Address of the new implementation.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Sets the implementation address of the proxy.
* @param newImplementation Address of the new implementation.
*/
function _setImplementation(address newImplementation) internal {
require(
Address.isContract(newImplementation),
'Cannot set a proxy implementation to a non-contract address'
);
bytes32 slot = IMPLEMENTATION_SLOT;
//solium-disable-next-line
assembly {
sstore(slot, newImplementation)
}
}
}
/**
* @title BaseAdminUpgradeabilityProxy
* @dev This contract combines an upgradeability proxy with an authorization
* mechanism for administrative tasks.
* All external functions in this contract must be guarded by the
* `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
* feature proposal that would enable this to be done automatically.
*/
contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
/**
* @dev Emitted when the administration has been transferred.
* @param previousAdmin Address of the previous admin.
* @param newAdmin Address of the new admin.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant ADMIN_SLOT =
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Modifier to check whether the `msg.sender` is the admin.
* If it is, it will run the function. Otherwise, it will delegate the call
* to the implementation.
*/
modifier ifAdmin() {
if (msg.sender == _admin()) {
_;
} else {
_fallback();
}
}
/**
* @return The address of the proxy admin.
*/
function admin() external ifAdmin returns (address) {
return _admin();
}
/**
* @return The address of the implementation.
*/
function implementation() external ifAdmin returns (address) {
return _implementation();
}
/**
* @dev Changes the admin of the proxy.
* Only the current admin can call this function.
* @param newAdmin Address to transfer proxy administration to.
*/
function changeAdmin(address newAdmin) external ifAdmin {
require(newAdmin != address(0), 'Cannot change the admin of a proxy to the zero address');
emit AdminChanged(_admin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev Upgrade the backing implementation of the proxy.
* Only the admin can call this function.
* @param newImplementation Address of the new implementation.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
/**
* @dev Upgrade the backing implementation of the proxy and call a function
* on the new implementation.
* This is useful to initialize the proxied contract.
* @param newImplementation Address of the new implementation.
* @param data Data to send as msg.data in the low level call.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
*/
function upgradeToAndCall(
address newImplementation,
bytes calldata data
) external payable ifAdmin {
_upgradeTo(newImplementation);
(bool success, ) = newImplementation.delegatecall(data);
require(success);
}
/**
* @return The admin slot.
*/
function _admin() internal view returns (address adm) {
bytes32 slot = ADMIN_SLOT;
//solium-disable-next-line
assembly {
adm := sload(slot)
}
}
/**
* @dev Sets the address of the proxy admin.
* @param newAdmin Address of the new proxy admin.
*/
function _setAdmin(address newAdmin) internal {
bytes32 slot = ADMIN_SLOT;
//solium-disable-next-line
assembly {
sstore(slot, newAdmin)
}
}
/**
* @dev Only fall back when the sender is not the admin.
*/
function _willFallback() internal {
require(msg.sender != _admin(), 'Cannot call fallback function from the proxy admin');
super._willFallback();
}
}
/**
* @title UpgradeabilityProxy
* @dev Extends BaseUpgradeabilityProxy with a constructor for initializing
* implementation and init data.
*/
contract UpgradeabilityProxy is BaseUpgradeabilityProxy {
/**
* @dev Contract constructor.
* @param _logic Address of the initial implementation.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
constructor(address _logic, bytes memory _data) public payable {
assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
_setImplementation(_logic);
if (_data.length > 0) {
(bool success, ) = _logic.delegatecall(_data);
require(success);
}
}
}
/**
* @title AdminUpgradeabilityProxy
* @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for
* initializing the implementation, admin, and init data.
*/
contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy {
/**
* Contract constructor.
* @param _logic address of the initial implementation.
* @param _admin Address of the proxy administrator.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
constructor(
address _logic,
address _admin,
bytes memory _data
) public payable UpgradeabilityProxy(_logic, _data) {
assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
_setAdmin(_admin);
}
}
/**
* @title InitializableUpgradeabilityProxy
* @dev Extends BaseUpgradeabilityProxy with an initializer for initializing
* implementation and init data.
*/
contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy {
/**
* @dev Contract initializer.
* @param _logic Address of the initial implementation.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
function initialize(address _logic, bytes memory _data) public payable {
require(_implementation() == address(0));
assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
_setImplementation(_logic);
if (_data.length > 0) {
(bool success, ) = _logic.delegatecall(_data);
require(success);
}
}
}
contract AddressStorage {
mapping(bytes32 => address) private addresses;
function getAddress(bytes32 _key) public view returns (address) {
return addresses[_key];
}
function _setAddress(bytes32 _key, address _value) internal {
addresses[_key] = _value;
}
}
/**
* @title InitializableAdminUpgradeabilityProxy
* @dev Extends from BaseAdminUpgradeabilityProxy with an initializer for
* initializing the implementation, admin, and init data.
*/
contract InitializableAdminUpgradeabilityProxy is
BaseAdminUpgradeabilityProxy,
InitializableUpgradeabilityProxy
{
/**
* Contract initializer.
* @param _logic address of the initial implementation.
* @param _admin Address of the proxy administrator.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
function initialize(address _logic, address _admin, bytes memory _data) public payable {
require(_implementation() == address(0));
InitializableUpgradeabilityProxy.initialize(_logic, _data);
assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
_setAdmin(_admin);
}
}
/**
@title ILendingPoolAddressesProvider interface
@notice provides the interface to fetch the LendingPoolCore address
*/
contract ILendingPoolAddressesProvider {
function getLendingPool() public view returns (address);
function setLendingPoolImpl(address _pool) public;
function getLendingPoolCore() public view returns (address payable);
function setLendingPoolCoreImpl(address _lendingPoolCore) public;
function getLendingPoolConfigurator() public view returns (address);
function setLendingPoolConfiguratorImpl(address _configurator) public;
function getLendingPoolDataProvider() public view returns (address);
function setLendingPoolDataProviderImpl(address _provider) public;
function getLendingPoolParametersProvider() public view returns (address);
function setLendingPoolParametersProviderImpl(address _parametersProvider) public;
function getTokenDistributor() public view returns (address);
function setTokenDistributor(address _tokenDistributor) public;
function getFeeProvider() public view returns (address);
function setFeeProviderImpl(address _feeProvider) public;
function getLendingPoolLiquidationManager() public view returns (address);
function setLendingPoolLiquidationManager(address _manager) public;
function getLendingPoolManager() public view returns (address);
function setLendingPoolManager(address _lendingPoolManager) public;
function getPriceOracle() public view returns (address);
function setPriceOracle(address _priceOracle) public;
function getLendingRateOracle() public view returns (address);
function setLendingRateOracle(address _lendingRateOracle) public;
}
/**
* @title LendingPoolAddressesProvider contract
* @notice Is the main registry of the protocol. All the different components of the protocol are accessible
* through the addresses provider.
* @author Aave
**/
contract LendingPoolAddressesProvider is Ownable, ILendingPoolAddressesProvider, AddressStorage {
//events
event LendingPoolUpdated(address indexed newAddress);
event LendingPoolCoreUpdated(address indexed newAddress);
event LendingPoolParametersProviderUpdated(address indexed newAddress);
event LendingPoolManagerUpdated(address indexed newAddress);
event LendingPoolConfiguratorUpdated(address indexed newAddress);
event LendingPoolLiquidationManagerUpdated(address indexed newAddress);
event LendingPoolDataProviderUpdated(address indexed newAddress);
event EthereumAddressUpdated(address indexed newAddress);
event PriceOracleUpdated(address indexed newAddress);
event LendingRateOracleUpdated(address indexed newAddress);
event FeeProviderUpdated(address indexed newAddress);
event TokenDistributorUpdated(address indexed newAddress);
event ProxyCreated(bytes32 id, address indexed newAddress);
bytes32 private constant LENDING_POOL = 'LENDING_POOL';
bytes32 private constant LENDING_POOL_CORE = 'LENDING_POOL_CORE';
bytes32 private constant LENDING_POOL_CONFIGURATOR = 'LENDING_POOL_CONFIGURATOR';
bytes32 private constant LENDING_POOL_PARAMETERS_PROVIDER = 'PARAMETERS_PROVIDER';
bytes32 private constant LENDING_POOL_MANAGER = 'LENDING_POOL_MANAGER';
bytes32 private constant LENDING_POOL_LIQUIDATION_MANAGER = 'LIQUIDATION_MANAGER';
bytes32 private constant LENDING_POOL_FLASHLOAN_PROVIDER = 'FLASHLOAN_PROVIDER';
bytes32 private constant DATA_PROVIDER = 'DATA_PROVIDER';
bytes32 private constant ETHEREUM_ADDRESS = 'ETHEREUM_ADDRESS';
bytes32 private constant PRICE_ORACLE = 'PRICE_ORACLE';
bytes32 private constant LENDING_RATE_ORACLE = 'LENDING_RATE_ORACLE';
bytes32 private constant FEE_PROVIDER = 'FEE_PROVIDER';
bytes32 private constant WALLET_BALANCE_PROVIDER = 'WALLET_BALANCE_PROVIDER';
bytes32 private constant TOKEN_DISTRIBUTOR = 'TOKEN_DISTRIBUTOR';
/**
* @dev returns the address of the LendingPool proxy
* @return the lending pool proxy address
**/
function getLendingPool() public view returns (address) {
return getAddress(LENDING_POOL);
}
/**
* @dev updates the implementation of the lending pool
* @param _pool the new lending pool implementation
**/
function setLendingPoolImpl(address _pool) public onlyOwner {
updateImplInternal(LENDING_POOL, _pool);
emit LendingPoolUpdated(_pool);
}
/**
* @dev returns the address of the LendingPoolCore proxy
* @return the lending pool core proxy address
*/
function getLendingPoolCore() public view returns (address payable) {
address payable core = address(uint160(getAddress(LENDING_POOL_CORE)));
return core;
}
/**
* @dev updates the implementation of the lending pool core
* @param _lendingPoolCore the new lending pool core implementation
**/
function setLendingPoolCoreImpl(address _lendingPoolCore) public onlyOwner {
updateImplInternal(LENDING_POOL_CORE, _lendingPoolCore);
emit LendingPoolCoreUpdated(_lendingPoolCore);
}
/**
* @dev returns the address of the LendingPoolConfigurator proxy
* @return the lending pool configurator proxy address
**/
function getLendingPoolConfigurator() public view returns (address) {
return getAddress(LENDING_POOL_CONFIGURATOR);
}
/**
* @dev updates the implementation of the lending pool configurator
* @param _configurator the new lending pool configurator implementation
**/
function setLendingPoolConfiguratorImpl(address _configurator) public onlyOwner {
updateImplInternal(LENDING_POOL_CONFIGURATOR, _configurator);
emit LendingPoolConfiguratorUpdated(_configurator);
}
/**
* @dev returns the address of the LendingPoolDataProvider proxy
* @return the lending pool data provider proxy address
*/
function getLendingPoolDataProvider() public view returns (address) {
return getAddress(DATA_PROVIDER);
}
/**
* @dev updates the implementation of the lending pool data provider
* @param _provider the new lending pool data provider implementation
**/
function setLendingPoolDataProviderImpl(address _provider) public onlyOwner {
updateImplInternal(DATA_PROVIDER, _provider);
emit LendingPoolDataProviderUpdated(_provider);
}
/**
* @dev returns the address of the LendingPoolParametersProvider proxy
* @return the address of the Lending pool parameters provider proxy
**/
function getLendingPoolParametersProvider() public view returns (address) {
return getAddress(LENDING_POOL_PARAMETERS_PROVIDER);
}
/**
* @dev updates the implementation of the lending pool parameters provider
* @param _parametersProvider the new lending pool parameters provider implementation
**/
function setLendingPoolParametersProviderImpl(address _parametersProvider) public onlyOwner {
updateImplInternal(LENDING_POOL_PARAMETERS_PROVIDER, _parametersProvider);
emit LendingPoolParametersProviderUpdated(_parametersProvider);
}
/**
* @dev returns the address of the FeeProvider proxy
* @return the address of the Fee provider proxy
**/
function getFeeProvider() public view returns (address) {
return getAddress(FEE_PROVIDER);
}
/**
* @dev updates the implementation of the FeeProvider proxy
* @param _feeProvider the new lending pool fee provider implementation
**/
function setFeeProviderImpl(address _feeProvider) public onlyOwner {
updateImplInternal(FEE_PROVIDER, _feeProvider);
emit FeeProviderUpdated(_feeProvider);
}
/**
* @dev returns the address of the LendingPoolLiquidationManager. Since the manager is used
* through delegateCall within the LendingPool contract, the proxy contract pattern does not work properly hence
* the addresses are changed directly.
* @return the address of the Lending pool liquidation manager
**/
function getLendingPoolLiquidationManager() public view returns (address) {
return getAddress(LENDING_POOL_LIQUIDATION_MANAGER);
}
/**
* @dev updates the address of the Lending pool liquidation manager
* @param _manager the new lending pool liquidation manager address
**/
function setLendingPoolLiquidationManager(address _manager) public onlyOwner {
_setAddress(LENDING_POOL_LIQUIDATION_MANAGER, _manager);
emit LendingPoolLiquidationManagerUpdated(_manager);
}
/**
* @dev the functions below are storing specific addresses that are outside the context of the protocol
* hence the upgradable proxy pattern is not used
**/
function getLendingPoolManager() public view returns (address) {
return getAddress(LENDING_POOL_MANAGER);
}
function setLendingPoolManager(address _lendingPoolManager) public onlyOwner {
_setAddress(LENDING_POOL_MANAGER, _lendingPoolManager);
emit LendingPoolManagerUpdated(_lendingPoolManager);
}
function getPriceOracle() public view returns (address) {
return getAddress(PRICE_ORACLE);
}
function setPriceOracle(address _priceOracle) public onlyOwner {
_setAddress(PRICE_ORACLE, _priceOracle);
emit PriceOracleUpdated(_priceOracle);
}
function getLendingRateOracle() public view returns (address) {
return getAddress(LENDING_RATE_ORACLE);
}
function setLendingRateOracle(address _lendingRateOracle) public onlyOwner {
_setAddress(LENDING_RATE_ORACLE, _lendingRateOracle);
emit LendingRateOracleUpdated(_lendingRateOracle);
}
function getTokenDistributor() public view returns (address) {
return getAddress(TOKEN_DISTRIBUTOR);
}
function setTokenDistributor(address _tokenDistributor) public onlyOwner {
_setAddress(TOKEN_DISTRIBUTOR, _tokenDistributor);
emit TokenDistributorUpdated(_tokenDistributor);
}
/**
* @dev internal function to update the implementation of a specific component of the protocol
* @param _id the id of the contract to be updated
* @param _newAddress the address of the new implementation
**/
function updateImplInternal(bytes32 _id, address _newAddress) internal {
address payable proxyAddress = address(uint160(getAddress(_id)));
InitializableAdminUpgradeabilityProxy proxy = InitializableAdminUpgradeabilityProxy(
proxyAddress
);
bytes memory params = abi.encodeWithSignature('initialize(address)', address(this));
if (proxyAddress == address(0)) {
proxy = new InitializableAdminUpgradeabilityProxy();
proxy.initialize(_newAddress, address(this), params);
_setAddress(_id, address(proxy));
emit ProxyCreated(_id, address(proxy));
} else {
proxy.upgradeToAndCall(_newAddress, params);
}
}
}
contract UintStorage {
mapping(bytes32 => uint256) private uints;
function getUint(bytes32 _key) public view returns (uint256) {
return uints[_key];
}
function _setUint(bytes32 _key, uint256 _value) internal {
uints[_key] = _value;
}
}
/**
* @title LendingPoolParametersProvider
* @author Aave
* @notice stores the configuration parameters of the Lending Pool contract
**/
contract LendingPoolParametersProvider is VersionedInitializable {
uint256 private constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 25;
uint256 private constant REBALANCE_DOWN_RATE_DELTA = (1e27) / 5;
uint256 private constant FLASHLOAN_FEE_TOTAL = 35;
uint256 private constant FLASHLOAN_FEE_PROTOCOL = 3000;
uint256 private constant DATA_PROVIDER_REVISION = 0x1;
function getRevision() internal pure returns (uint256) {
return DATA_PROVIDER_REVISION;
}
/**
* @dev initializes the LendingPoolParametersProvider after it's added to the proxy
* @param _addressesProvider the address of the LendingPoolAddressesProvider
*/
function initialize(address _addressesProvider) public initializer {}
/**
* @dev returns the maximum stable rate borrow size, in percentage of the available liquidity.
**/
function getMaxStableRateBorrowSizePercent() external pure returns (uint256) {
return MAX_STABLE_RATE_BORROW_SIZE_PERCENT;
}
/**
* @dev returns the delta between the current stable rate and the user stable rate at
* which the borrow position of the user will be rebalanced (scaled down)
**/
function getRebalanceDownRateDelta() external pure returns (uint256) {
return REBALANCE_DOWN_RATE_DELTA;
}
/**
* @dev returns the fee applied to a flashloan and the portion to redirect to the protocol, in basis points.
**/
function getFlashLoanFeesInBips() external pure returns (uint256, uint256) {
return (FLASHLOAN_FEE_TOTAL, FLASHLOAN_FEE_PROTOCOL);
}
}
/**
* @title CoreLibrary library
* @author Aave
* @notice Defines the data structures of the reserves and the user data
**/
library CoreLibrary {
using SafeMath for uint256;
using WadRayMath for uint256;
enum InterestRateMode {
NONE,
STABLE,
VARIABLE
}
uint256 internal constant SECONDS_PER_YEAR = 365 days;
struct UserReserveData {
//principal amount borrowed by the user.
uint256 principalBorrowBalance;
//cumulated variable borrow index for the user. Expressed in ray
uint256 lastVariableBorrowCumulativeIndex;
//origination fee cumulated by the user
uint256 originationFee;
// stable borrow rate at which the user has borrowed. Expressed in ray
uint256 stableBorrowRate;
uint40 lastUpdateTimestamp;
//defines if a specific deposit should or not be used as a collateral in borrows
bool useAsCollateral;
}
struct ReserveData {
/**
* @dev refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
**/
//the liquidity index. Expressed in ray
uint256 lastLiquidityCumulativeIndex;
//the current supply rate. Expressed in ray
uint256 currentLiquidityRate;
//the total borrows of the reserve at a stable rate. Expressed in the currency decimals
uint256 totalBorrowsStable;
//the total borrows of the reserve at a variable rate. Expressed in the currency decimals
uint256 totalBorrowsVariable;
//the current variable borrow rate. Expressed in ray
uint256 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint256 currentStableBorrowRate;
//the current average stable borrow rate (weighted average of all the different stable rate loans). Expressed in ray
uint256 currentAverageStableBorrowRate;
//variable borrow index. Expressed in ray
uint256 lastVariableBorrowCumulativeIndex;
//the ltv of the reserve. Expressed in percentage (0-100)
uint256 baseLTVasCollateral;
//the liquidation threshold of the reserve. Expressed in percentage (0-100)
uint256 liquidationThreshold;
//the liquidation bonus of the reserve. Expressed in percentage
uint256 liquidationBonus;
//the decimals of the reserve asset
uint256 decimals;
/**
* @dev address of the aToken representing the asset
**/
address aTokenAddress;
/**
* @dev address of the interest rate strategy contract
**/
address interestRateStrategyAddress;
uint40 lastUpdateTimestamp;
// borrowingEnabled = true means users can borrow from this reserve
bool borrowingEnabled;
// usageAsCollateralEnabled = true means users can use this reserve as collateral
bool usageAsCollateralEnabled;
// isStableBorrowRateEnabled = true means users can borrow at a stable rate
bool isStableBorrowRateEnabled;
// isActive = true means the reserve has been activated and properly configured
bool isActive;
// isFreezed = true means the reserve only allows repays and redeems, but not deposits, new borrowings or rate swap
bool isFreezed;
}
/**
* @dev returns the ongoing normalized income for the reserve.
* a value of 1e27 means there is no income. As time passes, the income is accrued.
* A value of 2*1e27 means that the income of the reserve is double the initial amount.
* @param _reserve the reserve object
* @return the normalized income. expressed in ray
**/
function getNormalizedIncome(
CoreLibrary.ReserveData storage _reserve
) internal view returns (uint256) {
uint256 cumulated = calculateLinearInterest(
_reserve.currentLiquidityRate,
_reserve.lastUpdateTimestamp
).rayMul(_reserve.lastLiquidityCumulativeIndex);
return cumulated;
}
/**
* @dev Updates the liquidity cumulative index Ci and variable borrow cumulative index Bvc. Refer to the whitepaper for
* a formal specification.
* @param _self the reserve object
**/
function updateCumulativeIndexes(ReserveData storage _self) internal {
uint256 totalBorrows = getTotalBorrows(_self);
if (totalBorrows > 0) {
//only cumulating if there is any income being produced
uint256 cumulatedLiquidityInterest = calculateLinearInterest(
_self.currentLiquidityRate,
_self.lastUpdateTimestamp
);
_self.lastLiquidityCumulativeIndex = cumulatedLiquidityInterest.rayMul(
_self.lastLiquidityCumulativeIndex
);
uint256 cumulatedVariableBorrowInterest = calculateCompoundedInterest(
_self.currentVariableBorrowRate,
_self.lastUpdateTimestamp
);
_self.lastVariableBorrowCumulativeIndex = cumulatedVariableBorrowInterest.rayMul(
_self.lastVariableBorrowCumulativeIndex
);
}
}
/**
* @dev accumulates a predefined amount of asset to the reserve as a fixed, one time income. Used for example to accumulate
* the flashloan fee to the reserve, and spread it through the depositors.
* @param _self the reserve object
* @param _totalLiquidity the total liquidity available in the reserve
* @param _amount the amount to accomulate
**/
function cumulateToLiquidityIndex(
ReserveData storage _self,
uint256 _totalLiquidity,
uint256 _amount
) internal {
uint256 amountToLiquidityRatio = _amount.wadToRay().rayDiv(_totalLiquidity.wadToRay());
uint256 cumulatedLiquidity = amountToLiquidityRatio.add(WadRayMath.ray());
_self.lastLiquidityCumulativeIndex = cumulatedLiquidity.rayMul(
_self.lastLiquidityCumulativeIndex
);
}
/**
* @dev initializes a reserve
* @param _self the reserve object
* @param _aTokenAddress the address of the overlying atoken contract
* @param _decimals the number of decimals of the underlying asset
* @param _interestRateStrategyAddress the address of the interest rate strategy contract
**/
function init(
ReserveData storage _self,
address _aTokenAddress,
uint256 _decimals,
address _interestRateStrategyAddress
) external {
require(_self.aTokenAddress == address(0), 'Reserve has already been initialized');
if (_self.lastLiquidityCumulativeIndex == 0) {
//if the reserve has not been initialized yet
_self.lastLiquidityCumulativeIndex = WadRayMath.ray();
}
if (_self.lastVariableBorrowCumulativeIndex == 0) {
_self.lastVariableBorrowCumulativeIndex = WadRayMath.ray();
}
_self.aTokenAddress = _aTokenAddress;
_self.decimals = _decimals;
_self.interestRateStrategyAddress = _interestRateStrategyAddress;
_self.isActive = true;
_self.isFreezed = false;
}
/**
* @dev enables borrowing on a reserve
* @param _self the reserve object
* @param _stableBorrowRateEnabled true if the stable borrow rate must be enabled by default, false otherwise
**/
function enableBorrowing(ReserveData storage _self, bool _stableBorrowRateEnabled) external {
require(_self.borrowingEnabled == false, 'Reserve is already enabled');
_self.borrowingEnabled = true;
_self.isStableBorrowRateEnabled = _stableBorrowRateEnabled;
}
/**
* @dev disables borrowing on a reserve
* @param _self the reserve object
**/
function disableBorrowing(ReserveData storage _self) external {
_self.borrowingEnabled = false;
}
/**
* @dev enables a reserve to be used as collateral
* @param _self the reserve object
* @param _baseLTVasCollateral the loan to value of the asset when used as collateral
* @param _liquidationThreshold the threshold at which loans using this asset as collateral will be considered undercollateralized
* @param _liquidationBonus the bonus liquidators receive to liquidate this asset
**/
function enableAsCollateral(
ReserveData storage _self,
uint256 _baseLTVasCollateral,
uint256 _liquidationThreshold,
uint256 _liquidationBonus
) external {
require(_self.usageAsCollateralEnabled == false, 'Reserve is already enabled as collateral');
_self.usageAsCollateralEnabled = true;
_self.baseLTVasCollateral = _baseLTVasCollateral;
_self.liquidationThreshold = _liquidationThreshold;
_self.liquidationBonus = _liquidationBonus;
if (_self.lastLiquidityCumulativeIndex == 0)
_self.lastLiquidityCumulativeIndex = WadRayMath.ray();
}
/**
* @dev disables a reserve as collateral
* @param _self the reserve object
**/
function disableAsCollateral(ReserveData storage _self) external {
_self.usageAsCollateralEnabled = false;
}
/**
* @dev calculates the compounded borrow balance of a user
* @param _self the userReserve object
* @param _reserve the reserve object
* @return the user compounded borrow balance
**/
function getCompoundedBorrowBalance(
CoreLibrary.UserReserveData storage _self,
CoreLibrary.ReserveData storage _reserve
) internal view returns (uint256) {
if (_self.principalBorrowBalance == 0) return 0;
uint256 principalBorrowBalanceRay = _self.principalBorrowBalance.wadToRay();
uint256 compoundedBalance = 0;
uint256 cumulatedInterest = 0;
if (_self.stableBorrowRate > 0) {
cumulatedInterest = calculateCompoundedInterest(
_self.stableBorrowRate,
_self.lastUpdateTimestamp
);
} else {
//variable interest
cumulatedInterest = calculateCompoundedInterest(
_reserve.currentVariableBorrowRate,
_reserve.lastUpdateTimestamp
).rayMul(_reserve.lastVariableBorrowCumulativeIndex).rayDiv(
_self.lastVariableBorrowCumulativeIndex
);
}
compoundedBalance = principalBorrowBalanceRay.rayMul(cumulatedInterest).rayToWad();
if (compoundedBalance == _self.principalBorrowBalance) {
//solium-disable-next-line
if (_self.lastUpdateTimestamp != block.timestamp) {
//no interest cumulation because of the rounding - we add 1 wei
//as symbolic cumulated interest to avoid interest free loans.
return _self.principalBorrowBalance.add(1 wei);
}
}
return compoundedBalance;
}
/**
* @dev increases the total borrows at a stable rate on a specific reserve and updates the
* average stable rate consequently
* @param _reserve the reserve object
* @param _amount the amount to add to the total borrows stable
* @param _rate the rate at which the amount has been borrowed
**/
function increaseTotalBorrowsStableAndUpdateAverageRate(
ReserveData storage _reserve,
uint256 _amount,
uint256 _rate
) internal {
if (_amount == 0) {
return;
}
uint256 previousTotalBorrowStable = _reserve.totalBorrowsStable;
//updating reserve borrows stable
_reserve.totalBorrowsStable = _reserve.totalBorrowsStable.add(_amount);
//update the average stable rate
//weighted average of all the borrows
uint256 weightedLastBorrow = _amount.wadToRay().rayMul(_rate);
uint256 weightedPreviousTotalBorrows = previousTotalBorrowStable.wadToRay().rayMul(
_reserve.currentAverageStableBorrowRate
);
_reserve.currentAverageStableBorrowRate = weightedLastBorrow
.add(weightedPreviousTotalBorrows)
.rayDiv(_reserve.totalBorrowsStable.wadToRay());
}
/**
* @dev decreases the total borrows at a stable rate on a specific reserve and updates the
* average stable rate consequently
* @param _reserve the reserve object
* @param _amount the amount to substract to the total borrows stable
* @param _rate the rate at which the amount has been repaid
**/
function decreaseTotalBorrowsStableAndUpdateAverageRate(
ReserveData storage _reserve,
uint256 _amount,
uint256 _rate
) internal {
uint256 previousTotalBorrowStable = _reserve.totalBorrowsStable;
if (previousTotalBorrowStable == 0 || _amount >= previousTotalBorrowStable) {
_reserve.totalBorrowsStable = 0;
_reserve.currentAverageStableBorrowRate = 0; // no income if there are no stable rate borrows
return;
}
//updating reserve borrows stable
_reserve.totalBorrowsStable = _reserve.totalBorrowsStable.sub(_amount);
//update the average stable rate
//weighted average of all the borrows
uint256 weightedLastBorrow = _amount.wadToRay().rayMul(_rate);
uint256 weightedPreviousTotalBorrows = previousTotalBorrowStable.wadToRay().rayMul(
_reserve.currentAverageStableBorrowRate
);
if (weightedPreviousTotalBorrows <= weightedLastBorrow) {
_reserve.totalBorrowsStable = 0;
_reserve.currentAverageStableBorrowRate = 0; // no income if there are no stable rate borrows
return;
}
_reserve.currentAverageStableBorrowRate = weightedPreviousTotalBorrows
.sub(weightedLastBorrow)
.rayDiv(_reserve.totalBorrowsStable.wadToRay());
}
/**
* @dev increases the total borrows at a variable rate
* @param _reserve the reserve object
* @param _amount the amount to add to the total borrows variable
**/
function increaseTotalBorrowsVariable(ReserveData storage _reserve, uint256 _amount) internal {
_reserve.totalBorrowsVariable = _reserve.totalBorrowsVariable.add(_amount);
}
/**
* @dev decreases the total borrows at a variable rate
* @param _reserve the reserve object
* @param _amount the amount to substract to the total borrows variable
**/
function decreaseTotalBorrowsVariable(ReserveData storage _reserve, uint256 _amount) internal {
require(
_reserve.totalBorrowsVariable >= _amount,
'The amount that is being subtracted from the variable total borrows is incorrect'
);
_reserve.totalBorrowsVariable = _reserve.totalBorrowsVariable.sub(_amount);
}
/**
* @dev function to calculate the interest using a linear interest rate formula
* @param _rate the interest rate, in ray
* @param _lastUpdateTimestamp the timestamp of the last update of the interest
* @return the interest rate linearly accumulated during the timeDelta, in ray
**/
function calculateLinearInterest(
uint256 _rate,
uint40 _lastUpdateTimestamp
) internal view returns (uint256) {
//solium-disable-next-line
uint256 timeDifference = block.timestamp.sub(uint256(_lastUpdateTimestamp));
uint256 timeDelta = timeDifference.wadToRay().rayDiv(SECONDS_PER_YEAR.wadToRay());
return _rate.rayMul(timeDelta).add(WadRayMath.ray());
}
/**
* @dev function to calculate the interest using a compounded interest rate formula
* @param _rate the interest rate, in ray
* @param _lastUpdateTimestamp the timestamp of the last update of the interest
* @return the interest rate compounded during the timeDelta, in ray
**/
function calculateCompoundedInterest(
uint256 _rate,
uint40 _lastUpdateTimestamp
) internal view returns (uint256) {
//solium-disable-next-line
uint256 timeDifference = block.timestamp.sub(uint256(_lastUpdateTimestamp));
uint256 ratePerSecond = _rate.div(SECONDS_PER_YEAR);
return ratePerSecond.add(WadRayMath.ray()).rayPow(timeDifference);
}
/**
* @dev returns the total borrows on the reserve
* @param _reserve the reserve object
* @return the total borrows (stable + variable)
**/
function getTotalBorrows(
CoreLibrary.ReserveData storage _reserve
) internal view returns (uint256) {
return _reserve.totalBorrowsStable.add(_reserve.totalBorrowsVariable);
}
}
/**
* @title IPriceOracleGetter interface
* @notice Interface for the Aave price oracle.
**/
interface IPriceOracleGetter {
/**
* @dev returns the asset price in ETH
* @param _asset the address of the asset
* @return the ETH price of the asset
**/
function getAssetPrice(address _asset) external view returns (uint256);
}
/**
* @title IFeeProvider interface
* @notice Interface for the Aave fee provider.
**/
interface IFeeProvider {
function calculateLoanOriginationFee(
address _user,
uint256 _amount
) external view returns (uint256);
function getLoanOriginationFeePercentage() external view returns (uint256);
}
/**
* @title LendingPoolDataProvider contract
* @author Aave
* @notice Implements functions to fetch data from the core, and aggregate them in order to allow computation
* on the compounded balances and the account balances in ETH
**/
contract LendingPoolDataProvider is VersionedInitializable {
using SafeMath for uint256;
using WadRayMath for uint256;
LendingPoolCore public core;
LendingPoolAddressesProvider public addressesProvider;
/**
* @dev specifies the health factor threshold at which the user position is liquidated.
* 1e18 by default, if the health factor drops below 1e18, the loan can be liquidated.
**/
uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18;
uint256 public constant DATA_PROVIDER_REVISION = 0x1;
function getRevision() internal pure returns (uint256) {
return DATA_PROVIDER_REVISION;
}
function initialize(LendingPoolAddressesProvider _addressesProvider) public initializer {
addressesProvider = _addressesProvider;
core = LendingPoolCore(_addressesProvider.getLendingPoolCore());
}
/**
* @dev struct to hold calculateUserGlobalData() local computations
**/
struct UserGlobalDataLocalVars {
uint256 reserveUnitPrice;
uint256 tokenUnit;
uint256 compoundedLiquidityBalance;
uint256 compoundedBorrowBalance;
uint256 reserveDecimals;
uint256 baseLtv;
uint256 liquidationThreshold;
uint256 originationFee;
bool usageAsCollateralEnabled;
bool userUsesReserveAsCollateral;
address currentReserve;
}
/**
* @dev calculates the user data across the reserves.
* this includes the total liquidity/collateral/borrow balances in ETH,
* the average Loan To Value, the average Liquidation Ratio, and the Health factor.
* @param _user the address of the user
* @return the total liquidity, total collateral, total borrow balances of the user in ETH.
* also the average Ltv, liquidation threshold, and the health factor
**/
function calculateUserGlobalData(
address _user
)
public
view
returns (
uint256 totalLiquidityBalanceETH,
uint256 totalCollateralBalanceETH,
uint256 totalBorrowBalanceETH,
uint256 totalFeesETH,
uint256 currentLtv,
uint256 currentLiquidationThreshold,
uint256 healthFactor,
bool healthFactorBelowThreshold
)
{
IPriceOracleGetter oracle = IPriceOracleGetter(addressesProvider.getPriceOracle());
// Usage of a memory struct of vars to avoid "Stack too deep" errors due to local variables
UserGlobalDataLocalVars memory vars;
address[] memory reserves = core.getReserves();
for (uint256 i = 0; i < reserves.length; i++) {
vars.currentReserve = reserves[i];
(
vars.compoundedLiquidityBalance,
vars.compoundedBorrowBalance,
vars.originationFee,
vars.userUsesReserveAsCollateral
) = core.getUserBasicReserveData(vars.currentReserve, _user);
if (vars.compoundedLiquidityBalance == 0 && vars.compoundedBorrowBalance == 0) {
continue;
}
//fetch reserve data
(
vars.reserveDecimals,
vars.baseLtv,
vars.liquidationThreshold,
vars.usageAsCollateralEnabled
) = core.getReserveConfiguration(vars.currentReserve);
vars.tokenUnit = 10 ** vars.reserveDecimals;
vars.reserveUnitPrice = oracle.getAssetPrice(vars.currentReserve);
//liquidity and collateral balance
if (vars.compoundedLiquidityBalance > 0) {
uint256 liquidityBalanceETH = vars
.reserveUnitPrice
.mul(vars.compoundedLiquidityBalance)
.div(vars.tokenUnit);
totalLiquidityBalanceETH = totalLiquidityBalanceETH.add(liquidityBalanceETH);
if (vars.usageAsCollateralEnabled && vars.userUsesReserveAsCollateral) {
totalCollateralBalanceETH = totalCollateralBalanceETH.add(liquidityBalanceETH);
currentLtv = currentLtv.add(liquidityBalanceETH.mul(vars.baseLtv));
currentLiquidationThreshold = currentLiquidationThreshold.add(
liquidityBalanceETH.mul(vars.liquidationThreshold)
);
}
}
if (vars.compoundedBorrowBalance > 0) {
totalBorrowBalanceETH = totalBorrowBalanceETH.add(
vars.reserveUnitPrice.mul(vars.compoundedBorrowBalance).div(vars.tokenUnit)
);
totalFeesETH = totalFeesETH.add(
vars.originationFee.mul(vars.reserveUnitPrice).div(vars.tokenUnit)
);
}
}
currentLtv = totalCollateralBalanceETH > 0 ? currentLtv.div(totalCollateralBalanceETH) : 0;
currentLiquidationThreshold = totalCollateralBalanceETH > 0
? currentLiquidationThreshold.div(totalCollateralBalanceETH)
: 0;
healthFactor = calculateHealthFactorFromBalancesInternal(
totalCollateralBalanceETH,
totalBorrowBalanceETH,
totalFeesETH,
currentLiquidationThreshold
);
healthFactorBelowThreshold = healthFactor < HEALTH_FACTOR_LIQUIDATION_THRESHOLD;
}
struct balanceDecreaseAllowedLocalVars {
uint256 decimals;
uint256 collateralBalanceETH;
uint256 borrowBalanceETH;
uint256 totalFeesETH;
uint256 currentLiquidationThreshold;
uint256 reserveLiquidationThreshold;
uint256 amountToDecreaseETH;
uint256 collateralBalancefterDecrease;
uint256 liquidationThresholdAfterDecrease;
uint256 healthFactorAfterDecrease;
bool reserveUsageAsCollateralEnabled;
}
/**
* @dev check if a specific balance decrease is allowed (i.e. doesn't bring the user borrow position health factor under 1e18)
* @param _reserve the address of the reserve
* @param _user the address of the user
* @param _amount the amount to decrease
* @return true if the decrease of the balance is allowed
**/
function balanceDecreaseAllowed(
address _reserve,
address _user,
uint256 _amount
) external view returns (bool) {
// Usage of a memory struct of vars to avoid "Stack too deep" errors due to local variables
balanceDecreaseAllowedLocalVars memory vars;
(vars.decimals, , vars.reserveLiquidationThreshold, vars.reserveUsageAsCollateralEnabled) = core
.getReserveConfiguration(_reserve);
if (
!vars.reserveUsageAsCollateralEnabled ||
!core.isUserUseReserveAsCollateralEnabled(_reserve, _user)
) {
return true; //if reserve is not used as collateral, no reasons to block the transfer
}
(
,
vars.collateralBalanceETH,
vars.borrowBalanceETH,
vars.totalFeesETH,
,
vars.currentLiquidationThreshold,
,
) = calculateUserGlobalData(_user);
if (vars.borrowBalanceETH == 0) {
return true; //no borrows - no reasons to block the transfer
}
IPriceOracleGetter oracle = IPriceOracleGetter(addressesProvider.getPriceOracle());
vars.amountToDecreaseETH = oracle.getAssetPrice(_reserve).mul(_amount).div(10 ** vars.decimals);
vars.collateralBalancefterDecrease = vars.collateralBalanceETH.sub(vars.amountToDecreaseETH);
//if there is a borrow, there can't be 0 collateral
if (vars.collateralBalancefterDecrease == 0) {
return false;
}
vars.liquidationThresholdAfterDecrease = vars
.collateralBalanceETH
.mul(vars.currentLiquidationThreshold)
.sub(vars.amountToDecreaseETH.mul(vars.reserveLiquidationThreshold))
.div(vars.collateralBalancefterDecrease);
uint256 healthFactorAfterDecrease = calculateHealthFactorFromBalancesInternal(
vars.collateralBalancefterDecrease,
vars.borrowBalanceETH,
vars.totalFeesETH,
vars.liquidationThresholdAfterDecrease
);
return healthFactorAfterDecrease > HEALTH_FACTOR_LIQUIDATION_THRESHOLD;
}
/**
* @notice calculates the amount of collateral needed in ETH to cover a new borrow.
* @param _reserve the reserve from which the user wants to borrow
* @param _amount the amount the user wants to borrow
* @param _fee the fee for the amount that the user needs to cover
* @param _userCurrentBorrowBalanceTH the current borrow balance of the user (before the borrow)
* @param _userCurrentLtv the average ltv of the user given his current collateral
* @return the total amount of collateral in ETH to cover the current borrow balance + the new amount + fee
**/
function calculateCollateralNeededInETH(
address _reserve,
uint256 _amount,
uint256 _fee,
uint256 _userCurrentBorrowBalanceTH,
uint256 _userCurrentFeesETH,
uint256 _userCurrentLtv
) external view returns (uint256) {
uint256 reserveDecimals = core.getReserveDecimals(_reserve);
IPriceOracleGetter oracle = IPriceOracleGetter(addressesProvider.getPriceOracle());
uint256 requestedBorrowAmountETH = oracle.getAssetPrice(_reserve).mul(_amount.add(_fee)).div(
10 ** reserveDecimals
); //price is in ether
//add the current already borrowed amount to the amount requested to calculate the total collateral needed.
uint256 collateralNeededInETH = _userCurrentBorrowBalanceTH
.add(_userCurrentFeesETH)
.add(requestedBorrowAmountETH)
.mul(100)
.div(_userCurrentLtv); //LTV is calculated in percentage
return collateralNeededInETH;
}
/**
* @dev calculates the equivalent amount in ETH that an user can borrow, depending on the available collateral and the
* average Loan To Value.
* @param collateralBalanceETH the total collateral balance
* @param borrowBalanceETH the total borrow balance
* @param totalFeesETH the total fees
* @param ltv the average loan to value
* @return the amount available to borrow in ETH for the user
**/
function calculateAvailableBorrowsETHInternal(
uint256 collateralBalanceETH,
uint256 borrowBalanceETH,
uint256 totalFeesETH,
uint256 ltv
) internal view returns (uint256) {
uint256 availableBorrowsETH = collateralBalanceETH.mul(ltv).div(100); //ltv is in percentage
if (availableBorrowsETH < borrowBalanceETH) {
return 0;
}
availableBorrowsETH = availableBorrowsETH.sub(borrowBalanceETH.add(totalFeesETH));
//calculate fee
uint256 borrowFee = IFeeProvider(addressesProvider.getFeeProvider())
.calculateLoanOriginationFee(msg.sender, availableBorrowsETH);
return availableBorrowsETH.sub(borrowFee);
}
/**
* @dev calculates the health factor from the corresponding balances
* @param collateralBalanceETH the total collateral balance in ETH
* @param borrowBalanceETH the total borrow balance in ETH
* @param totalFeesETH the total fees in ETH
* @param liquidationThreshold the avg liquidation threshold
**/
function calculateHealthFactorFromBalancesInternal(
uint256 collateralBalanceETH,
uint256 borrowBalanceETH,
uint256 totalFeesETH,
uint256 liquidationThreshold
) internal pure returns (uint256) {
if (borrowBalanceETH == 0) return uint256(-1);
return
(collateralBalanceETH.mul(liquidationThreshold).div(100)).wadDiv(
borrowBalanceETH.add(totalFeesETH)
);
}
/**
* @dev returns the health factor liquidation threshold
**/
function getHealthFactorLiquidationThreshold() public pure returns (uint256) {
return HEALTH_FACTOR_LIQUIDATION_THRESHOLD;
}
/**
* @dev accessory functions to fetch data from the lendingPoolCore
**/
function getReserveConfigurationData(
address _reserve
)
external
view
returns (
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
address rateStrategyAddress,
bool usageAsCollateralEnabled,
bool borrowingEnabled,
bool stableBorrowRateEnabled,
bool isActive
)
{
(, ltv, liquidationThreshold, usageAsCollateralEnabled) = core.getReserveConfiguration(
_reserve
);
stableBorrowRateEnabled = core.getReserveIsStableBorrowRateEnabled(_reserve);
borrowingEnabled = core.isReserveBorrowingEnabled(_reserve);
isActive = core.getReserveIsActive(_reserve);
liquidationBonus = core.getReserveLiquidationBonus(_reserve);
rateStrategyAddress = core.getReserveInterestRateStrategyAddress(_reserve);
}
function getReserveData(
address _reserve
)
external
view
returns (
uint256 totalLiquidity,
uint256 availableLiquidity,
uint256 totalBorrowsStable,
uint256 totalBorrowsVariable,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 utilizationRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
address aTokenAddress,
uint40 lastUpdateTimestamp
)
{
totalLiquidity = core.getReserveTotalLiquidity(_reserve);
availableLiquidity = core.getReserveAvailableLiquidity(_reserve);
totalBorrowsStable = core.getReserveTotalBorrowsStable(_reserve);
totalBorrowsVariable = core.getReserveTotalBorrowsVariable(_reserve);
liquidityRate = core.getReserveCurrentLiquidityRate(_reserve);
variableBorrowRate = core.getReserveCurrentVariableBorrowRate(_reserve);
stableBorrowRate = core.getReserveCurrentStableBorrowRate(_reserve);
averageStableBorrowRate = core.getReserveCurrentAverageStableBorrowRate(_reserve);
utilizationRate = core.getReserveUtilizationRate(_reserve);
liquidityIndex = core.getReserveLiquidityCumulativeIndex(_reserve);
variableBorrowIndex = core.getReserveVariableBorrowsCumulativeIndex(_reserve);
aTokenAddress = core.getReserveATokenAddress(_reserve);
lastUpdateTimestamp = core.getReserveLastUpdate(_reserve);
}
function getUserAccountData(
address _user
)
external
view
returns (
uint256 totalLiquidityETH,
uint256 totalCollateralETH,
uint256 totalBorrowsETH,
uint256 totalFeesETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
)
{
(
totalLiquidityETH,
totalCollateralETH,
totalBorrowsETH,
totalFeesETH,
ltv,
currentLiquidationThreshold,
healthFactor,
) = calculateUserGlobalData(_user);
availableBorrowsETH = calculateAvailableBorrowsETHInternal(
totalCollateralETH,
totalBorrowsETH,
totalFeesETH,
ltv
);
}
function getUserReserveData(
address _reserve,
address _user
)
external
view
returns (
uint256 currentATokenBalance,
uint256 currentBorrowBalance,
uint256 principalBorrowBalance,
uint256 borrowRateMode,
uint256 borrowRate,
uint256 liquidityRate,
uint256 originationFee,
uint256 variableBorrowIndex,
uint256 lastUpdateTimestamp,
bool usageAsCollateralEnabled
)
{
currentATokenBalance = AToken(core.getReserveATokenAddress(_reserve)).balanceOf(_user);
CoreLibrary.InterestRateMode mode = core.getUserCurrentBorrowRateMode(_reserve, _user);
(principalBorrowBalance, currentBorrowBalance, ) = core.getUserBorrowBalances(_reserve, _user);
//default is 0, if mode == CoreLibrary.InterestRateMode.NONE
if (mode == CoreLibrary.InterestRateMode.STABLE) {
borrowRate = core.getUserCurrentStableBorrowRate(_reserve, _user);
} else if (mode == CoreLibrary.InterestRateMode.VARIABLE) {
borrowRate = core.getReserveCurrentVariableBorrowRate(_reserve);
}
borrowRateMode = uint256(mode);
liquidityRate = core.getReserveCurrentLiquidityRate(_reserve);
originationFee = core.getUserOriginationFee(_reserve, _user);
variableBorrowIndex = core.getUserVariableBorrowCumulativeIndex(_reserve, _user);
lastUpdateTimestamp = core.getUserLastUpdate(_reserve, _user);
usageAsCollateralEnabled = core.isUserUseReserveAsCollateralEnabled(_reserve, _user);
}
}
/**
* @title Aave ERC20 AToken
*
* @dev Implementation of the interest bearing token for the DLP protocol.
* @author Aave
*/
contract AToken is ERC20, ERC20Detailed {
using WadRayMath for uint256;
uint256 public constant UINT_MAX_VALUE = uint256(-1);
/**
* @dev emitted after the redeem action
* @param _from the address performing the redeem
* @param _value the amount to be redeemed
* @param _fromBalanceIncrease the cumulated balance since the last update of the user
* @param _fromIndex the last index of the user
**/
event Redeem(
address indexed _from,
uint256 _value,
uint256 _fromBalanceIncrease,
uint256 _fromIndex
);
/**
* @dev emitted after the mint action
* @param _from the address performing the mint
* @param _value the amount to be minted
* @param _fromBalanceIncrease the cumulated balance since the last update of the user
* @param _fromIndex the last index of the user
**/
event MintOnDeposit(
address indexed _from,
uint256 _value,
uint256 _fromBalanceIncrease,
uint256 _fromIndex
);
/**
* @dev emitted during the liquidation action, when the liquidator reclaims the underlying
* asset
* @param _from the address from which the tokens are being burned
* @param _value the amount to be burned
* @param _fromBalanceIncrease the cumulated balance since the last update of the user
* @param _fromIndex the last index of the user
**/
event BurnOnLiquidation(
address indexed _from,
uint256 _value,
uint256 _fromBalanceIncrease,
uint256 _fromIndex
);
/**
* @dev emitted during the transfer action
* @param _from the address from which the tokens are being transferred
* @param _to the adress of the destination
* @param _value the amount to be minted
* @param _fromBalanceIncrease the cumulated balance since the last update of the user
* @param _toBalanceIncrease the cumulated balance since the last update of the destination
* @param _fromIndex the last index of the user
* @param _toIndex the last index of the liquidator
**/
event BalanceTransfer(
address indexed _from,
address indexed _to,
uint256 _value,
uint256 _fromBalanceIncrease,
uint256 _toBalanceIncrease,
uint256 _fromIndex,
uint256 _toIndex
);
/**
* @dev emitted when the accumulation of the interest
* by an user is redirected to another user
* @param _from the address from which the interest is being redirected
* @param _to the adress of the destination
* @param _fromBalanceIncrease the cumulated balance since the last update of the user
* @param _fromIndex the last index of the user
**/
event InterestStreamRedirected(
address indexed _from,
address indexed _to,
uint256 _redirectedBalance,
uint256 _fromBalanceIncrease,
uint256 _fromIndex
);
/**
* @dev emitted when the redirected balance of an user is being updated
* @param _targetAddress the address of which the balance is being updated
* @param _targetBalanceIncrease the cumulated balance since the last update of the target
* @param _targetIndex the last index of the user
* @param _redirectedBalanceAdded the redirected balance being added
* @param _redirectedBalanceRemoved the redirected balance being removed
**/
event RedirectedBalanceUpdated(
address indexed _targetAddress,
uint256 _targetBalanceIncrease,
uint256 _targetIndex,
uint256 _redirectedBalanceAdded,
uint256 _redirectedBalanceRemoved
);
event InterestRedirectionAllowanceChanged(address indexed _from, address indexed _to);
address public underlyingAssetAddress;
mapping(address => uint256) private userIndexes;
mapping(address => address) private interestRedirectionAddresses;
mapping(address => uint256) private redirectedBalances;
mapping(address => address) private interestRedirectionAllowances;
LendingPoolAddressesProvider private addressesProvider;
LendingPoolCore private core;
LendingPool private pool;
LendingPoolDataProvider private dataProvider;
modifier onlyLendingPool() {
require(msg.sender == address(pool), 'The caller of this function must be a lending pool');
_;
}
modifier whenTransferAllowed(address _from, uint256 _amount) {
require(isTransferAllowed(_from, _amount), 'Transfer cannot be allowed.');
_;
}
constructor(
LendingPoolAddressesProvider _addressesProvider,
address _underlyingAsset,
uint8 _underlyingAssetDecimals,
string memory _name,
string memory _symbol
) public ERC20Detailed(_name, _symbol, _underlyingAssetDecimals) {
addressesProvider = _addressesProvider;
core = LendingPoolCore(addressesProvider.getLendingPoolCore());
pool = LendingPool(addressesProvider.getLendingPool());
dataProvider = LendingPoolDataProvider(addressesProvider.getLendingPoolDataProvider());
underlyingAssetAddress = _underlyingAsset;
}
/**
* @notice ERC20 implementation internal function backing transfer() and transferFrom()
* @dev validates the transfer before allowing it. NOTE: This is not standard ERC20 behavior
**/
function _transfer(
address _from,
address _to,
uint256 _amount
) internal whenTransferAllowed(_from, _amount) {
executeTransferInternal(_from, _to, _amount);
}
/**
* @dev redirects the interest generated to a target address.
* when the interest is redirected, the user balance is added to
* the recepient redirected balance.
* @param _to the address to which the interest will be redirected
**/
function redirectInterestStream(address _to) external {
redirectInterestStreamInternal(msg.sender, _to);
}
/**
* @dev redirects the interest generated by _from to a target address.
* when the interest is redirected, the user balance is added to
* the recepient redirected balance. The caller needs to have allowance on
* the interest redirection to be able to execute the function.
* @param _from the address of the user whom interest is being redirected
* @param _to the address to which the interest will be redirected
**/
function redirectInterestStreamOf(address _from, address _to) external {
require(
msg.sender == interestRedirectionAllowances[_from],
'Caller is not allowed to redirect the interest of the user'
);
redirectInterestStreamInternal(_from, _to);
}
/**
* @dev gives allowance to an address to execute the interest redirection
* on behalf of the caller.
* @param _to the address to which the interest will be redirected. Pass address(0) to reset
* the allowance.
**/
function allowInterestRedirectionTo(address _to) external {
require(_to != msg.sender, 'User cannot give allowance to himself');
interestRedirectionAllowances[msg.sender] = _to;
emit InterestRedirectionAllowanceChanged(msg.sender, _to);
}
/**
* @dev redeems aToken for the underlying asset
* @param _amount the amount being redeemed
**/
function redeem(uint256 _amount) external {
require(_amount > 0, 'Amount to redeem needs to be > 0');
//cumulates the balance of the user
(, uint256 currentBalance, uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(
msg.sender
);
uint256 amountToRedeem = _amount;
//if amount is equal to uint(-1), the user wants to redeem everything
if (_amount == UINT_MAX_VALUE) {
amountToRedeem = currentBalance;
}
require(amountToRedeem <= currentBalance, 'User cannot redeem more than the available balance');
//check that the user is allowed to redeem the amount
require(isTransferAllowed(msg.sender, amountToRedeem), 'Transfer cannot be allowed.');
//if the user is redirecting his interest towards someone else,
//we update the redirected balance of the redirection address by adding the accrued interest,
//and removing the amount to redeem
updateRedirectedBalanceOfRedirectionAddressInternal(
msg.sender,
balanceIncrease,
amountToRedeem
);
// burns tokens equivalent to the amount requested
_burn(msg.sender, amountToRedeem);
bool userIndexReset = false;
//reset the user data if the remaining balance is 0
if (currentBalance.sub(amountToRedeem) == 0) {
userIndexReset = resetDataOnZeroBalanceInternal(msg.sender);
}
// executes redeem of the underlying asset
pool.redeemUnderlying(
underlyingAssetAddress,
msg.sender,
amountToRedeem,
currentBalance.sub(amountToRedeem)
);
emit Redeem(msg.sender, amountToRedeem, balanceIncrease, userIndexReset ? 0 : index);
}
/**
* @dev mints token in the event of users depositing the underlying asset into the lending pool
* only lending pools can call this function
* @param _account the address receiving the minted tokens
* @param _amount the amount of tokens to mint
*/
function mintOnDeposit(address _account, uint256 _amount) external onlyLendingPool {
//cumulates the balance of the user
(, , uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(_account);
//if the user is redirecting his interest towards someone else,
//we update the redirected balance of the redirection address by adding the accrued interest
//and the amount deposited
updateRedirectedBalanceOfRedirectionAddressInternal(_account, balanceIncrease.add(_amount), 0);
//mint an equivalent amount of tokens to cover the new deposit
_mint(_account, _amount);
emit MintOnDeposit(_account, _amount, balanceIncrease, index);
}
/**
* @dev burns token in the event of a borrow being liquidated, in case the liquidators reclaims the underlying asset
* Transfer of the liquidated asset is executed by the lending pool contract.
* only lending pools can call this function
* @param _account the address from which burn the aTokens
* @param _value the amount to burn
**/
function burnOnLiquidation(address _account, uint256 _value) external onlyLendingPool {
//cumulates the balance of the user being liquidated
(, uint256 accountBalance, uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(
_account
);
//adds the accrued interest and substracts the burned amount to
//the redirected balance
updateRedirectedBalanceOfRedirectionAddressInternal(_account, balanceIncrease, _value);
//burns the requested amount of tokens
_burn(_account, _value);
bool userIndexReset = false;
//reset the user data if the remaining balance is 0
if (accountBalance.sub(_value) == 0) {
userIndexReset = resetDataOnZeroBalanceInternal(_account);
}
emit BurnOnLiquidation(_account, _value, balanceIncrease, userIndexReset ? 0 : index);
}
/**
* @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* only lending pools can call this function
* @param _from the address from which transfer the aTokens
* @param _to the destination address
* @param _value the amount to transfer
**/
function transferOnLiquidation(
address _from,
address _to,
uint256 _value
) external onlyLendingPool {
//being a normal transfer, the Transfer() and BalanceTransfer() are emitted
//so no need to emit a specific event here
executeTransferInternal(_from, _to, _value);
}
/**
* @dev calculates the balance of the user, which is the
* principal balance + interest generated by the principal balance + interest generated by the redirected balance
* @param _user the user for which the balance is being calculated
* @return the total balance of the user
**/
function balanceOf(address _user) public view returns (uint256) {
//current principal balance of the user
uint256 currentPrincipalBalance = super.balanceOf(_user);
//balance redirected by other users to _user for interest rate accrual
uint256 redirectedBalance = redirectedBalances[_user];
if (currentPrincipalBalance == 0 && redirectedBalance == 0) {
return 0;
}
//if the _user is not redirecting the interest to anybody, accrues
//the interest for himself
if (interestRedirectionAddresses[_user] == address(0)) {
//accruing for himself means that both the principal balance and
//the redirected balance partecipate in the interest
return
calculateCumulatedBalanceInternal(_user, currentPrincipalBalance.add(redirectedBalance))
.sub(redirectedBalance);
} else {
//if the user redirected the interest, then only the redirected
//balance generates interest. In that case, the interest generated
//by the redirected balance is added to the current principal balance.
return
currentPrincipalBalance.add(
calculateCumulatedBalanceInternal(_user, redirectedBalance).sub(redirectedBalance)
);
}
}
/**
* @dev returns the principal balance of the user. The principal balance is the last
* updated stored balance, which does not consider the perpetually accruing interest.
* @param _user the address of the user
* @return the principal balance of the user
**/
function principalBalanceOf(address _user) external view returns (uint256) {
return super.balanceOf(_user);
}
/**
* @dev calculates the total supply of the specific aToken
* since the balance of every single user increases over time, the total supply
* does that too.
* @return the current total supply
**/
function totalSupply() public view returns (uint256) {
uint256 currentSupplyPrincipal = super.totalSupply();
if (currentSupplyPrincipal == 0) {
return 0;
}
return
currentSupplyPrincipal
.wadToRay()
.rayMul(core.getReserveNormalizedIncome(underlyingAssetAddress))
.rayToWad();
}
/**
* @dev Used to validate transfers before actually executing them.
* @param _user address of the user to check
* @param _amount the amount to check
* @return true if the _user can transfer _amount, false otherwise
**/
function isTransferAllowed(address _user, uint256 _amount) public view returns (bool) {
return dataProvider.balanceDecreaseAllowed(underlyingAssetAddress, _user, _amount);
}
/**
* @dev returns the last index of the user, used to calculate the balance of the user
* @param _user address of the user
* @return the last user index
**/
function getUserIndex(address _user) external view returns (uint256) {
return userIndexes[_user];
}
/**
* @dev returns the address to which the interest is redirected
* @param _user address of the user
* @return 0 if there is no redirection, an address otherwise
**/
function getInterestRedirectionAddress(address _user) external view returns (address) {
return interestRedirectionAddresses[_user];
}
/**
* @dev returns the redirected balance of the user. The redirected balance is the balance
* redirected by other accounts to the user, that is accrueing interest for him.
* @param _user address of the user
* @return the total redirected balance
**/
function getRedirectedBalance(address _user) external view returns (uint256) {
return redirectedBalances[_user];
}
/**
* @dev accumulates the accrued interest of the user to the principal balance
* @param _user the address of the user for which the interest is being accumulated
* @return the previous principal balance, the new principal balance, the balance increase
* and the new user index
**/
function cumulateBalanceInternal(
address _user
) internal returns (uint256, uint256, uint256, uint256) {
uint256 previousPrincipalBalance = super.balanceOf(_user);
//calculate the accrued interest since the last accumulation
uint256 balanceIncrease = balanceOf(_user).sub(previousPrincipalBalance);
//mints an amount of tokens equivalent to the amount accumulated
_mint(_user, balanceIncrease);
//updates the user index
uint256 index = userIndexes[_user] = core.getReserveNormalizedIncome(underlyingAssetAddress);
return (
previousPrincipalBalance,
previousPrincipalBalance.add(balanceIncrease),
balanceIncrease,
index
);
}
/**
* @dev updates the redirected balance of the user. If the user is not redirecting his
* interest, nothing is executed.
* @param _user the address of the user for which the interest is being accumulated
* @param _balanceToAdd the amount to add to the redirected balance
* @param _balanceToRemove the amount to remove from the redirected balance
**/
function updateRedirectedBalanceOfRedirectionAddressInternal(
address _user,
uint256 _balanceToAdd,
uint256 _balanceToRemove
) internal {
address redirectionAddress = interestRedirectionAddresses[_user];
//if there isn't any redirection, nothing to be done
if (redirectionAddress == address(0)) {
return;
}
//compound balances of the redirected address
(, , uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(redirectionAddress);
//updating the redirected balance
redirectedBalances[redirectionAddress] = redirectedBalances[redirectionAddress]
.add(_balanceToAdd)
.sub(_balanceToRemove);
//if the interest of redirectionAddress is also being redirected, we need to update
//the redirected balance of the redirection target by adding the balance increase
address targetOfRedirectionAddress = interestRedirectionAddresses[redirectionAddress];
if (targetOfRedirectionAddress != address(0)) {
redirectedBalances[targetOfRedirectionAddress] = redirectedBalances[
targetOfRedirectionAddress
].add(balanceIncrease);
}
emit RedirectedBalanceUpdated(
redirectionAddress,
balanceIncrease,
index,
_balanceToAdd,
_balanceToRemove
);
}
/**
* @dev calculate the interest accrued by _user on a specific balance
* @param _user the address of the user for which the interest is being accumulated
* @param _balance the balance on which the interest is calculated
* @return the interest rate accrued
**/
function calculateCumulatedBalanceInternal(
address _user,
uint256 _balance
) internal view returns (uint256) {
return
_balance
.wadToRay()
.rayMul(core.getReserveNormalizedIncome(underlyingAssetAddress))
.rayDiv(userIndexes[_user])
.rayToWad();
}
/**
* @dev executes the transfer of aTokens, invoked by both _transfer() and
* transferOnLiquidation()
* @param _from the address from which transfer the aTokens
* @param _to the destination address
* @param _value the amount to transfer
**/
function executeTransferInternal(address _from, address _to, uint256 _value) internal {
require(_value > 0, 'Transferred amount needs to be greater than zero');
//cumulate the balance of the sender
(
,
uint256 fromBalance,
uint256 fromBalanceIncrease,
uint256 fromIndex
) = cumulateBalanceInternal(_from);
//cumulate the balance of the receiver
(, , uint256 toBalanceIncrease, uint256 toIndex) = cumulateBalanceInternal(_to);
//if the sender is redirecting his interest towards someone else,
//adds to the redirected balance the accrued interest and removes the amount
//being transferred
updateRedirectedBalanceOfRedirectionAddressInternal(_from, fromBalanceIncrease, _value);
//if the receiver is redirecting his interest towards someone else,
//adds to the redirected balance the accrued interest and the amount
//being transferred
updateRedirectedBalanceOfRedirectionAddressInternal(_to, toBalanceIncrease.add(_value), 0);
//performs the transfer
super._transfer(_from, _to, _value);
bool fromIndexReset = false;
//reset the user data if the remaining balance is 0
if (fromBalance.sub(_value) == 0) {
fromIndexReset = resetDataOnZeroBalanceInternal(_from);
}
emit BalanceTransfer(
_from,
_to,
_value,
fromBalanceIncrease,
toBalanceIncrease,
fromIndexReset ? 0 : fromIndex,
toIndex
);
}
/**
* @dev executes the redirection of the interest from one address to another.
* immediately after redirection, the destination address will start to accrue interest.
* @param _from the address from which transfer the aTokens
* @param _to the destination address
**/
function redirectInterestStreamInternal(address _from, address _to) internal {
address currentRedirectionAddress = interestRedirectionAddresses[_from];
require(_to != currentRedirectionAddress, 'Interest is already redirected to the user');
//accumulates the accrued interest to the principal
(
uint256 previousPrincipalBalance,
uint256 fromBalance,
uint256 balanceIncrease,
uint256 fromIndex
) = cumulateBalanceInternal(_from);
require(fromBalance > 0, 'Interest stream can only be redirected if there is a valid balance');
//if the user is already redirecting the interest to someone, before changing
//the redirection address we substract the redirected balance of the previous
//recipient
if (currentRedirectionAddress != address(0)) {
updateRedirectedBalanceOfRedirectionAddressInternal(_from, 0, previousPrincipalBalance);
}
//if the user is redirecting the interest back to himself,
//we simply set to 0 the interest redirection address
if (_to == _from) {
interestRedirectionAddresses[_from] = address(0);
emit InterestStreamRedirected(_from, address(0), fromBalance, balanceIncrease, fromIndex);
return;
}
//first set the redirection address to the new recipient
interestRedirectionAddresses[_from] = _to;
//adds the user balance to the redirected balance of the destination
updateRedirectedBalanceOfRedirectionAddressInternal(_from, fromBalance, 0);
emit InterestStreamRedirected(_from, _to, fromBalance, balanceIncrease, fromIndex);
}
/**
* @dev function to reset the interest stream redirection and the user index, if the
* user has no balance left.
* @param _user the address of the user
* @return true if the user index has also been reset, false otherwise. useful to emit the proper user index value
**/
function resetDataOnZeroBalanceInternal(address _user) internal returns (bool) {
//if the user has 0 principal balance, the interest stream redirection gets reset
interestRedirectionAddresses[_user] = address(0);
//emits a InterestStreamRedirected event to notify that the redirection has been reset
emit InterestStreamRedirected(_user, address(0), 0, 0, 0);
//if the redirected balance is also 0, we clear up the user index
if (redirectedBalances[_user] == 0) {
userIndexes[_user] = 0;
return true;
} else {
return false;
}
}
}
/**
* @title IFlashLoanReceiver interface
* @notice Interface for the Aave fee IFlashLoanReceiver.
* @author Aave
* @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract
**/
interface IFlashLoanReceiver {
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params
) external;
}
/**
* @title ILendingRateOracle interface
* @notice Interface for the Aave borrow rate oracle. Provides the average market borrow rate to be used as a base for the stable borrow rate calculations
**/
interface ILendingRateOracle {
/**
@dev returns the market borrow rate in ray
**/
function getMarketBorrowRate(address _asset) external view returns (uint256);
/**
@dev sets the market borrow rate. Rate value must be in ray
**/
function setMarketBorrowRate(address _asset, uint256 _rate) external;
}
/**
@title IReserveInterestRateStrategyInterface interface
@notice Interface for the calculation of the interest rates.
*/
interface IReserveInterestRateStrategy {
/**
* @dev returns the base variable borrow rate, in rays
*/
function getBaseVariableBorrowRate() external view returns (uint256);
/**
* @dev calculates the liquidity, stable, and variable rates depending on the current utilization rate
* and the base parameters
*
*/
function calculateInterestRates(
address _reserve,
uint256 _utilizationRate,
uint256 _totalBorrowsStable,
uint256 _totalBorrowsVariable,
uint256 _averageStableBorrowRate
)
external
view
returns (uint256 liquidityRate, uint256 stableBorrowRate, uint256 variableBorrowRate);
}
library EthAddressLib {
/**
* @dev returns the address used within the protocol to identify ETH
* @return the address assigned to ETH
*/
function ethAddress() internal pure returns (address) {
return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
}
}
/**
* @title LendingPool contract
* @notice Implements the actions of the LendingPool, and exposes accessory methods to fetch the users and reserve data
* @author Aave
**/
contract LendingPool is ReentrancyGuard, VersionedInitializable {
using SafeMath for uint256;
using WadRayMath for uint256;
using Address for address;
using SafeERC20 for ERC20;
LendingPoolAddressesProvider public addressesProvider;
LendingPoolCore public core;
LendingPoolDataProvider public dataProvider;
LendingPoolParametersProvider public parametersProvider;
IFeeProvider feeProvider;
/**
* @dev emitted on deposit
* @param _reserve the address of the reserve
* @param _user the address of the user
* @param _amount the amount to be deposited
* @param _referral the referral number of the action
* @param _timestamp the timestamp of the action
**/
event Deposit(
address indexed _reserve,
address indexed _user,
uint256 _amount,
uint16 indexed _referral,
uint256 _timestamp
);
/**
* @dev emitted during a redeem action.
* @param _reserve the address of the reserve
* @param _user the address of the user
* @param _amount the amount to be deposited
* @param _timestamp the timestamp of the action
**/
event RedeemUnderlying(
address indexed _reserve,
address indexed _user,
uint256 _amount,
uint256 _timestamp
);
/**
* @dev emitted on borrow
* @param _reserve the address of the reserve
* @param _user the address of the user
* @param _amount the amount to be deposited
* @param _borrowRateMode the rate mode, can be either 1-stable or 2-variable
* @param _borrowRate the rate at which the user has borrowed
* @param _originationFee the origination fee to be paid by the user
* @param _borrowBalanceIncrease the balance increase since the last borrow, 0 if it's the first time borrowing
* @param _referral the referral number of the action
* @param _timestamp the timestamp of the action
**/
event Borrow(
address indexed _reserve,
address indexed _user,
uint256 _amount,
uint256 _borrowRateMode,
uint256 _borrowRate,
uint256 _originationFee,
uint256 _borrowBalanceIncrease,
uint16 indexed _referral,
uint256 _timestamp
);
/**
* @dev emitted on repay
* @param _reserve the address of the reserve
* @param _user the address of the user for which the repay has been executed
* @param _repayer the address of the user that has performed the repay action
* @param _amountMinusFees the amount repaid minus fees
* @param _fees the fees repaid
* @param _borrowBalanceIncrease the balance increase since the last action
* @param _timestamp the timestamp of the action
**/
event Repay(
address indexed _reserve,
address indexed _user,
address indexed _repayer,
uint256 _amountMinusFees,
uint256 _fees,
uint256 _borrowBalanceIncrease,
uint256 _timestamp
);
/**
* @dev emitted when a user performs a rate swap
* @param _reserve the address of the reserve
* @param _user the address of the user executing the swap
* @param _newRateMode the new interest rate mode
* @param _newRate the new borrow rate
* @param _borrowBalanceIncrease the balance increase since the last action
* @param _timestamp the timestamp of the action
**/
event Swap(
address indexed _reserve,
address indexed _user,
uint256 _newRateMode,
uint256 _newRate,
uint256 _borrowBalanceIncrease,
uint256 _timestamp
);
/**
* @dev emitted when a user enables a reserve as collateral
* @param _reserve the address of the reserve
* @param _user the address of the user
**/
event ReserveUsedAsCollateralEnabled(address indexed _reserve, address indexed _user);
/**
* @dev emitted when a user disables a reserve as collateral
* @param _reserve the address of the reserve
* @param _user the address of the user
**/
event ReserveUsedAsCollateralDisabled(address indexed _reserve, address indexed _user);
/**
* @dev emitted when the stable rate of a user gets rebalanced
* @param _reserve the address of the reserve
* @param _user the address of the user for which the rebalance has been executed
* @param _newStableRate the new stable borrow rate after the rebalance
* @param _borrowBalanceIncrease the balance increase since the last action
* @param _timestamp the timestamp of the action
**/
event RebalanceStableBorrowRate(
address indexed _reserve,
address indexed _user,
uint256 _newStableRate,
uint256 _borrowBalanceIncrease,
uint256 _timestamp
);
/**
* @dev emitted when a flashloan is executed
* @param _target the address of the flashLoanReceiver
* @param _reserve the address of the reserve
* @param _amount the amount requested
* @param _totalFee the total fee on the amount
* @param _protocolFee the part of the fee for the protocol
* @param _timestamp the timestamp of the action
**/
event FlashLoan(
address indexed _target,
address indexed _reserve,
uint256 _amount,
uint256 _totalFee,
uint256 _protocolFee,
uint256 _timestamp
);
/**
* @dev these events are not emitted directly by the LendingPool
* but they are declared here as the LendingPoolLiquidationManager
* is executed using a delegateCall().
* This allows to have the events in the generated ABI for LendingPool.
**/
/**
* @dev emitted when a borrow fee is liquidated
* @param _collateral the address of the collateral being liquidated
* @param _reserve the address of the reserve
* @param _user the address of the user being liquidated
* @param _feeLiquidated the total fee liquidated
* @param _liquidatedCollateralForFee the amount of collateral received by the protocol in exchange for the fee
* @param _timestamp the timestamp of the action
**/
event OriginationFeeLiquidated(
address indexed _collateral,
address indexed _reserve,
address indexed _user,
uint256 _feeLiquidated,
uint256 _liquidatedCollateralForFee,
uint256 _timestamp
);
/**
* @dev emitted when a borrower is liquidated
* @param _collateral the address of the collateral being liquidated
* @param _reserve the address of the reserve
* @param _user the address of the user being liquidated
* @param _purchaseAmount the total amount liquidated
* @param _liquidatedCollateralAmount the amount of collateral being liquidated
* @param _accruedBorrowInterest the amount of interest accrued by the borrower since the last action
* @param _liquidator the address of the liquidator
* @param _receiveAToken true if the liquidator wants to receive aTokens, false otherwise
* @param _timestamp the timestamp of the action
**/
event LiquidationCall(
address indexed _collateral,
address indexed _reserve,
address indexed _user,
uint256 _purchaseAmount,
uint256 _liquidatedCollateralAmount,
uint256 _accruedBorrowInterest,
address _liquidator,
bool _receiveAToken,
uint256 _timestamp
);
/**
* @dev Emitted during the token rescue
* @param tokenRescued The token which is being rescued
* @param receiver The recipient which will receive the rescued token
* @param amountRescued The amount being rescued
**/
event TokensRescued(
address indexed tokenRescued,
address indexed receiver,
uint256 amountRescued
);
/**
* @dev functions affected by this modifier can only be invoked by the
* aToken.sol contract
* @param _reserve the address of the reserve
**/
modifier onlyOverlyingAToken(address _reserve) {
require(
msg.sender == core.getReserveATokenAddress(_reserve),
'The caller of this function can only be the aToken contract of this reserve'
);
_;
}
/**
* @dev functions affected by this modifier can only be invoked if the reserve is active
* @param _reserve the address of the reserve
**/
modifier onlyActiveReserve(address _reserve) {
requireReserveActiveInternal(_reserve);
_;
}
/**
* @dev functions affected by this modifier can only be invoked if the reserve is not freezed.
* A freezed reserve only allows redeems, repays, rebalances and liquidations.
* @param _reserve the address of the reserve
**/
modifier onlyUnfreezedReserve(address _reserve) {
requireReserveNotFreezedInternal(_reserve);
_;
}
/**
* @dev functions affected by this modifier can only be invoked if the provided _amount input parameter
* is not zero.
* @param _amount the amount provided
**/
modifier onlyAmountGreaterThanZero(uint256 _amount) {
requireAmountGreaterThanZeroInternal(_amount);
_;
}
modifier onlyAddressesProviderOwner() {
require(
msg.sender == addressesProvider.owner(),
'The caller of this function can only be the addressesProvider owner'
);
_;
}
uint256 public constant UINT_MAX_VALUE = uint256(-1);
uint256 public constant LENDINGPOOL_REVISION = 0x8;
function getRevision() internal pure returns (uint256) {
return LENDINGPOOL_REVISION;
}
/**
* @dev this function is invoked by the proxy contract when the LendingPool contract is added to the
* AddressesProvider.
* @param _addressesProvider the address of the LendingPoolAddressesProvider registry
**/
function initialize(LendingPoolAddressesProvider _addressesProvider) public initializer {
addressesProvider = _addressesProvider;
core = LendingPoolCore(addressesProvider.getLendingPoolCore());
dataProvider = LendingPoolDataProvider(addressesProvider.getLendingPoolDataProvider());
parametersProvider = LendingPoolParametersProvider(
addressesProvider.getLendingPoolParametersProvider()
);
feeProvider = IFeeProvider(addressesProvider.getFeeProvider());
}
/**
* @dev deposits The underlying asset into the reserve. A corresponding amount of the overlying asset (aTokens)
* is minted.
* @param _reserve the address of the reserve
* @param _amount the amount to be deposited
* @param _referralCode integrators are assigned a referral code and can potentially receive rewards.
**/
function deposit(
address _reserve,
uint256 _amount,
uint16 _referralCode
)
external
payable
nonReentrant
onlyActiveReserve(_reserve)
onlyUnfreezedReserve(_reserve)
onlyAmountGreaterThanZero(_amount)
{
require(false, 'METHOD_DISABLED');
}
/**
* @dev Redeems the underlying amount of assets requested by _user.
* This function is executed by the overlying aToken contract in response to a redeem action.
* @param _reserve the address of the reserve
* @param _user the address of the user performing the action
* @param _amount the underlying amount to be redeemed
**/
function redeemUnderlying(
address _reserve,
address payable _user,
uint256 _amount,
uint256 _aTokenBalanceAfterRedeem
)
external
nonReentrant
onlyOverlyingAToken(_reserve)
onlyActiveReserve(_reserve)
onlyAmountGreaterThanZero(_amount)
{
uint256 currentAvailableLiquidity = core.getReserveAvailableLiquidity(_reserve);
require(
currentAvailableLiquidity >= _amount,
'There is not enough liquidity available to redeem'
);
core.updateStateOnRedeem(_reserve, _user, _amount, _aTokenBalanceAfterRedeem == 0);
core.transferToUser(_reserve, _user, _amount);
//solium-disable-next-line
emit RedeemUnderlying(_reserve, _user, _amount, block.timestamp);
}
/**
* @dev data structures for local computations in the borrow() method.
*/
struct BorrowLocalVars {
uint256 principalBorrowBalance;
uint256 currentLtv;
uint256 currentLiquidationThreshold;
uint256 borrowFee;
uint256 requestedBorrowAmountETH;
uint256 amountOfCollateralNeededETH;
uint256 userCollateralBalanceETH;
uint256 userBorrowBalanceETH;
uint256 userTotalFeesETH;
uint256 borrowBalanceIncrease;
uint256 currentReserveStableRate;
uint256 availableLiquidity;
uint256 reserveDecimals;
uint256 finalUserBorrowRate;
CoreLibrary.InterestRateMode rateMode;
bool healthFactorBelowThreshold;
}
/**
* @dev Allows users to borrow a specific amount of the reserve currency, provided that the borrower
* already deposited enough collateral.
* @param _reserve the address of the reserve
* @param _amount the amount to be borrowed
* @param _interestRateMode the interest rate mode at which the user wants to borrow. Can be 0 (STABLE) or 1 (VARIABLE)
**/
function borrow(
address _reserve,
uint256 _amount,
uint256 _interestRateMode,
uint16 _referralCode
)
external
nonReentrant
onlyActiveReserve(_reserve)
onlyUnfreezedReserve(_reserve)
onlyAmountGreaterThanZero(_amount)
{
require(false, 'METHOD_DISABLED');
}
/**
* @notice repays a borrow on the specific reserve, for the specified amount (or for the whole amount, if uint256(-1) is specified).
* @dev the target user is defined by _onBehalfOf. If there is no repayment on behalf of another account,
* _onBehalfOf must be equal to msg.sender.
* @param _reserve the address of the reserve on which the user borrowed
* @param _amount the amount to repay, or uint256(-1) if the user wants to repay everything
* @param _onBehalfOf the address for which msg.sender is repaying.
**/
struct RepayLocalVars {
uint256 principalBorrowBalance;
uint256 compoundedBorrowBalance;
uint256 borrowBalanceIncrease;
bool isETH;
uint256 paybackAmount;
uint256 paybackAmountMinusFees;
uint256 currentStableRate;
uint256 originationFee;
}
function repay(
address _reserve,
uint256 _amount,
address payable _onBehalfOf
) external payable nonReentrant onlyActiveReserve(_reserve) onlyAmountGreaterThanZero(_amount) {
// Usage of a memory struct of vars to avoid "Stack too deep" errors due to local variables
RepayLocalVars memory vars;
(vars.principalBorrowBalance, vars.compoundedBorrowBalance, vars.borrowBalanceIncrease) = core
.getUserBorrowBalances(_reserve, _onBehalfOf);
vars.originationFee = core.getUserOriginationFee(_reserve, _onBehalfOf);
vars.isETH = EthAddressLib.ethAddress() == _reserve;
require(vars.compoundedBorrowBalance > 0, 'The user does not have any borrow pending');
require(
_amount != UINT_MAX_VALUE || msg.sender == _onBehalfOf,
'To repay on behalf of an user an explicit amount to repay is needed.'
);
//default to max amount
vars.paybackAmount = vars.compoundedBorrowBalance.add(vars.originationFee);
if (_amount != UINT_MAX_VALUE && _amount < vars.paybackAmount) {
vars.paybackAmount = _amount;
}
require(
!vars.isETH || msg.value >= vars.paybackAmount,
'Invalid msg.value sent for the repayment'
);
//if the amount is smaller than the origination fee, just transfer the amount to the fee destination address
if (vars.paybackAmount <= vars.originationFee) {
core.updateStateOnRepay(
_reserve,
_onBehalfOf,
0,
vars.paybackAmount,
vars.borrowBalanceIncrease,
false
);
core.transferToFeeCollectionAddress.value(vars.isETH ? vars.paybackAmount : 0)(
_reserve,
msg.sender,
vars.paybackAmount,
addressesProvider.getTokenDistributor()
);
emit Repay(
_reserve,
_onBehalfOf,
msg.sender,
0,
vars.paybackAmount,
vars.borrowBalanceIncrease,
//solium-disable-next-line
block.timestamp
);
return;
}
vars.paybackAmountMinusFees = vars.paybackAmount.sub(vars.originationFee);
core.updateStateOnRepay(
_reserve,
_onBehalfOf,
vars.paybackAmountMinusFees,
vars.originationFee,
vars.borrowBalanceIncrease,
vars.compoundedBorrowBalance == vars.paybackAmountMinusFees
);
//if the user didn't repay the origination fee, transfer the fee to the fee collection address
if (vars.originationFee > 0) {
core.transferToFeeCollectionAddress.value(vars.isETH ? vars.originationFee : 0)(
_reserve,
msg.sender,
vars.originationFee,
addressesProvider.getTokenDistributor()
);
}
//sending the total msg.value if the transfer is ETH.
//the transferToReserve() function will take care of sending the
//excess ETH back to the caller
core.transferToReserve.value(vars.isETH ? msg.value.sub(vars.originationFee) : 0)(
_reserve,
msg.sender,
vars.paybackAmountMinusFees
);
emit Repay(
_reserve,
_onBehalfOf,
msg.sender,
vars.paybackAmountMinusFees,
vars.originationFee,
vars.borrowBalanceIncrease,
//solium-disable-next-line
block.timestamp
);
}
/**
* @dev borrowers can user this function to swap between stable and variable borrow rate modes.
* @param _reserve the address of the reserve on which the user borrowed
**/
function swapBorrowRateMode(
address _reserve
) external nonReentrant onlyActiveReserve(_reserve) onlyUnfreezedReserve(_reserve) {
require(false, 'METHOD_DISABLED');
}
/**
* @dev rebalances the stable interest rate of a user if current liquidity rate > user stable rate.
* this is regulated by Aave to ensure that the protocol is not abused, and the user is paying a fair
* rate. The rebalance mechanism is updated in the context of the V1 -> V2 transition to automatically switch the user to variable.
* @param _reserve the address of the reserve
* @param _user the address of the user to be rebalanced
**/
function rebalanceStableBorrowRate(
address _reserve,
address _user
) external nonReentrant onlyActiveReserve(_reserve) {
require(false, 'METHOD_DISABLED');
}
/**
* @dev allows depositors to enable or disable a specific deposit as collateral.
* @param _reserve the address of the reserve
* @param _useAsCollateral true if the user wants to user the deposit as collateral, false otherwise.
**/
function setUserUseReserveAsCollateral(
address _reserve,
bool _useAsCollateral
) external nonReentrant onlyActiveReserve(_reserve) onlyUnfreezedReserve(_reserve) {
require(false, 'METHOD_DISABLED');
}
/**
* @dev users can invoke this function to liquidate an undercollateralized position.
* This version has some important differences to the previous:
* - a liquidator **can** liquidate up to 100% of the position
* - a liquidator **can** liquidate healthy(collateralized) positions for a fixed 1% liquidationBonus
* - a liquidator **can not** receive aTokens as the result of the liquidation
* @param _reserve the address of the collateral to liquidated
* @param _reserve the address of the principal reserve
* @param _user the address of the borrower
* @param _purchaseAmount the amount of principal that the liquidator wants to repay
* @param _receiveAToken DEPRECATED not used anymore
**/
function liquidationCall(
address _collateral,
address _reserve,
address _user,
uint256 _purchaseAmount,
bool _receiveAToken
) external payable nonReentrant onlyActiveReserve(_reserve) onlyActiveReserve(_collateral) {
address liquidationManager = addressesProvider.getLendingPoolLiquidationManager();
//solium-disable-next-line
(bool success, bytes memory result) = liquidationManager.delegatecall(
abi.encodeWithSignature(
'liquidationCall(address,address,address,uint256)',
_collateral,
_reserve,
_user,
_purchaseAmount
)
);
require(success, 'Liquidation call failed');
(uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string));
if (returnCode != 0) {
//error found
revert(string(abi.encodePacked('Liquidation failed: ', returnMessage)));
}
}
/**
* @dev allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
* that must be kept into consideration. For further details please visit https://developers.aave.com
* @param _receiver The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
* @param _reserve the address of the principal reserve
* @param _amount the amount requested for this flashloan
**/
function flashLoan(
address _receiver,
address _reserve,
uint256 _amount,
bytes memory _params
) public nonReentrant onlyActiveReserve(_reserve) onlyAmountGreaterThanZero(_amount) {
require(false, 'METHOD_DISABLED');
}
function rescueTokens(
address token,
address to,
uint256 amount
) external onlyAddressesProviderOwner {
ERC20(token).safeTransfer(to, amount);
emit TokensRescued(token, to, amount);
}
/**
* @dev accessory functions to fetch data from the core contract
**/
function getReserveConfigurationData(
address _reserve
)
external
view
returns (
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
address interestRateStrategyAddress,
bool usageAsCollateralEnabled,
bool borrowingEnabled,
bool stableBorrowRateEnabled,
bool isActive
)
{
return dataProvider.getReserveConfigurationData(_reserve);
}
function getReserveData(
address _reserve
)
external
view
returns (
uint256 totalLiquidity,
uint256 availableLiquidity,
uint256 totalBorrowsStable,
uint256 totalBorrowsVariable,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 utilizationRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
address aTokenAddress,
uint40 lastUpdateTimestamp
)
{
return dataProvider.getReserveData(_reserve);
}
function getUserAccountData(
address _user
)
external
view
returns (
uint256 totalLiquidityETH,
uint256 totalCollateralETH,
uint256 totalBorrowsETH,
uint256 totalFeesETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
)
{
return dataProvider.getUserAccountData(_user);
}
function getUserReserveData(
address _reserve,
address _user
)
external
view
returns (
uint256 currentATokenBalance,
uint256 currentBorrowBalance,
uint256 principalBorrowBalance,
uint256 borrowRateMode,
uint256 borrowRate,
uint256 liquidityRate,
uint256 originationFee,
uint256 variableBorrowIndex,
uint256 lastUpdateTimestamp,
bool usageAsCollateralEnabled
)
{
return dataProvider.getUserReserveData(_reserve, _user);
}
function getReserves() external view returns (address[] memory) {
return core.getReserves();
}
/**
* @dev internal function to save on code size for the onlyActiveReserve modifier
**/
function requireReserveActiveInternal(address _reserve) internal view {
require(core.getReserveIsActive(_reserve), 'Action requires an active reserve');
}
/**
* @notice internal function to save on code size for the onlyUnfreezedReserve modifier
**/
function requireReserveNotFreezedInternal(address _reserve) internal view {
require(!core.getReserveIsFreezed(_reserve), 'Action requires an unfreezed reserve');
}
/**
* @notice internal function to save on code size for the onlyAmountGreaterThanZero modifier
**/
function requireAmountGreaterThanZeroInternal(uint256 _amount) internal pure {
require(_amount > 0, 'Amount must be greater than 0');
}
}
/**
* @title LendingPoolCore contract
* @author Aave
* @notice Holds the state of the lending pool and all the funds deposited
* @dev NOTE: The core does not enforce security checks on the update of the state
* (eg, updateStateOnBorrow() does not enforce that borrowed is enabled on the reserve).
* The check that an action can be performed is a duty of the overlying LendingPool contract.
**/
contract LendingPoolCore is VersionedInitializable {
using SafeMath for uint256;
using WadRayMath for uint256;
using CoreLibrary for CoreLibrary.ReserveData;
using CoreLibrary for CoreLibrary.UserReserveData;
using SafeERC20 for ERC20;
using Address for address payable;
/**
* @dev Emitted when the state of a reserve is updated
* @param reserve the address of the reserve
* @param liquidityRate the new liquidity rate
* @param stableBorrowRate the new stable borrow rate
* @param variableBorrowRate the new variable borrow rate
* @param liquidityIndex the new liquidity index
* @param variableBorrowIndex the new variable borrow index
**/
event ReserveUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
address public lendingPoolAddress;
LendingPoolAddressesProvider public addressesProvider;
/**
* @dev only lending pools can use functions affected by this modifier
**/
modifier onlyLendingPool() {
require(lendingPoolAddress == msg.sender, 'The caller must be a lending pool contract');
_;
}
/**
* @dev only lending pools configurator can use functions affected by this modifier
**/
modifier onlyLendingPoolConfigurator() {
require(
addressesProvider.getLendingPoolConfigurator() == msg.sender,
'The caller must be a lending pool configurator contract'
);
_;
}
mapping(address => CoreLibrary.ReserveData) internal reserves;
mapping(address => mapping(address => CoreLibrary.UserReserveData)) internal usersReserveData;
address[] public reservesList;
uint256 public constant CORE_REVISION = 0x8;
/**
* @dev returns the revision number of the contract
**/
function getRevision() internal pure returns (uint256) {
return CORE_REVISION;
}
/**
* @dev initializes the Core contract, invoked upon registration on the AddressesProvider
* @param _addressesProvider the addressesProvider contract
**/
function initialize(LendingPoolAddressesProvider _addressesProvider) public initializer {
addressesProvider = _addressesProvider;
refreshConfigInternal();
}
/**
* @dev updates the state of the core as a result of a deposit action
* @param _reserve the address of the reserve in which the deposit is happening
* @param _user the address of the the user depositing
* @param _amount the amount being deposited
* @param _isFirstDeposit true if the user is depositing for the first time
**/
function updateStateOnDeposit(
address _reserve,
address _user,
uint256 _amount,
bool _isFirstDeposit
) external onlyLendingPool {
reserves[_reserve].updateCumulativeIndexes();
updateReserveInterestRatesAndTimestampInternal(_reserve, _amount, 0);
if (_isFirstDeposit) {
//if this is the first deposit of the user, we configure the deposit as enabled to be used as collateral
setUserUseReserveAsCollateral(_reserve, _user, true);
}
}
/**
* @dev updates the state of the core as a result of a redeem action
* @param _reserve the address of the reserve in which the redeem is happening
* @param _user the address of the the user redeeming
* @param _amountRedeemed the amount being redeemed
* @param _userRedeemedEverything true if the user is redeeming everything
**/
function updateStateOnRedeem(
address _reserve,
address _user,
uint256 _amountRedeemed,
bool _userRedeemedEverything
) external onlyLendingPool {
//compound liquidity and variable borrow interests
reserves[_reserve].updateCumulativeIndexes();
updateReserveInterestRatesAndTimestampInternal(_reserve, 0, _amountRedeemed);
//if user redeemed everything the useReserveAsCollateral flag is reset
if (_userRedeemedEverything) {
setUserUseReserveAsCollateral(_reserve, _user, false);
}
}
/**
* @dev updates the state of the core as a result of a flashloan action
* @param _reserve the address of the reserve in which the flashloan is happening
* @param _income the income of the protocol as a result of the action
**/
function updateStateOnFlashLoan(
address _reserve,
uint256 _availableLiquidityBefore,
uint256 _income,
uint256 _protocolFee
) external onlyLendingPool {
transferFlashLoanProtocolFeeInternal(_reserve, _protocolFee);
//compounding the cumulated interest
reserves[_reserve].updateCumulativeIndexes();
uint256 totalLiquidityBefore = _availableLiquidityBefore.add(getReserveTotalBorrows(_reserve));
//compounding the received fee into the reserve
reserves[_reserve].cumulateToLiquidityIndex(totalLiquidityBefore, _income);
//refresh interest rates
updateReserveInterestRatesAndTimestampInternal(_reserve, _income, 0);
}
/**
* @dev updates the state of the core as a consequence of a borrow action.
* @param _reserve the address of the reserve on which the user is borrowing
* @param _user the address of the borrower
* @param _amountBorrowed the new amount borrowed
* @param _borrowFee the fee on the amount borrowed
* @param _rateMode the borrow rate mode (stable, variable)
* @return the new borrow rate for the user
**/
function updateStateOnBorrow(
address _reserve,
address _user,
uint256 _amountBorrowed,
uint256 _borrowFee,
CoreLibrary.InterestRateMode _rateMode
) external onlyLendingPool returns (uint256, uint256) {
// getting the previous borrow data of the user
(uint256 principalBorrowBalance, , uint256 balanceIncrease) = getUserBorrowBalances(
_reserve,
_user
);
updateReserveStateOnBorrowInternal(
_reserve,
_user,
principalBorrowBalance,
balanceIncrease,
_amountBorrowed,
_rateMode
);
updateUserStateOnBorrowInternal(
_reserve,
_user,
_amountBorrowed,
balanceIncrease,
_borrowFee,
_rateMode
);
updateReserveInterestRatesAndTimestampInternal(_reserve, 0, _amountBorrowed);
return (getUserCurrentBorrowRate(_reserve, _user), balanceIncrease);
}
/**
* @dev updates the state of the core as a consequence of a repay action.
* @param _reserve the address of the reserve on which the user is repaying
* @param _user the address of the borrower
* @param _paybackAmountMinusFees the amount being paid back minus fees
* @param _originationFeeRepaid the fee on the amount that is being repaid
* @param _balanceIncrease the accrued interest on the borrowed amount
* @param _repaidWholeLoan true if the user is repaying the whole loan
**/
function updateStateOnRepay(
address _reserve,
address _user,
uint256 _paybackAmountMinusFees,
uint256 _originationFeeRepaid,
uint256 _balanceIncrease,
bool _repaidWholeLoan
) external onlyLendingPool {
updateReserveStateOnRepayInternal(_reserve, _user, _paybackAmountMinusFees, _balanceIncrease);
updateUserStateOnRepayInternal(
_reserve,
_user,
_paybackAmountMinusFees,
_originationFeeRepaid,
_balanceIncrease,
_repaidWholeLoan
);
updateReserveInterestRatesAndTimestampInternal(_reserve, _paybackAmountMinusFees, 0);
}
/**
* @dev updates the state of the core as a consequence of a swap rate action.
* @param _reserve the address of the reserve on which the user is repaying
* @param _user the address of the borrower
* @param _principalBorrowBalance the amount borrowed by the user
* @param _compoundedBorrowBalance the amount borrowed plus accrued interest
* @param _balanceIncrease the accrued interest on the borrowed amount
* @param _currentRateMode the current interest rate mode for the user
**/
function updateStateOnSwapRate(
address _reserve,
address _user,
uint256 _principalBorrowBalance,
uint256 _compoundedBorrowBalance,
uint256 _balanceIncrease,
CoreLibrary.InterestRateMode _currentRateMode
) external onlyLendingPool returns (CoreLibrary.InterestRateMode, uint256) {
updateReserveStateOnSwapRateInternal(
_reserve,
_user,
_principalBorrowBalance,
_compoundedBorrowBalance,
_currentRateMode
);
CoreLibrary.InterestRateMode newRateMode = updateUserStateOnSwapRateInternal(
_reserve,
_user,
_balanceIncrease,
_currentRateMode
);
updateReserveInterestRatesAndTimestampInternal(_reserve, 0, 0);
return (newRateMode, getUserCurrentBorrowRate(_reserve, _user));
}
/**
* @dev updates the state of the core as a consequence of a liquidation action.
* @param _principalReserve the address of the principal reserve that is being repaid
* @param _collateralReserve the address of the collateral reserve that is being liquidated
* @param _user the address of the borrower
* @param _amountToLiquidate the amount being repaid by the liquidator
* @param _collateralToLiquidate the amount of collateral being liquidated
* @param _feeLiquidated the amount of origination fee being liquidated
* @param _liquidatedCollateralForFee the amount of collateral equivalent to the origination fee + bonus
* @param _balanceIncrease the accrued interest on the borrowed amount
* @param _liquidatorReceivesAToken true if the liquidator will receive aTokens, false otherwise
**/
function updateStateOnLiquidation(
address _principalReserve,
address _collateralReserve,
address _user,
uint256 _amountToLiquidate,
uint256 _collateralToLiquidate,
uint256 _feeLiquidated,
uint256 _liquidatedCollateralForFee,
uint256 _balanceIncrease,
bool _liquidatorReceivesAToken
) external onlyLendingPool {
updatePrincipalReserveStateOnLiquidationInternal(
_principalReserve,
_user,
_amountToLiquidate,
_balanceIncrease
);
updateCollateralReserveStateOnLiquidationInternal(_collateralReserve);
updateUserStateOnLiquidationInternal(
_principalReserve,
_user,
_amountToLiquidate,
_feeLiquidated,
_balanceIncrease
);
updateReserveInterestRatesAndTimestampInternal(_principalReserve, _amountToLiquidate, 0);
if (!_liquidatorReceivesAToken) {
updateReserveInterestRatesAndTimestampInternal(
_collateralReserve,
0,
_collateralToLiquidate.add(_liquidatedCollateralForFee)
);
}
}
/**
* @dev updates the state of the core as a consequence of a stable rate rebalance
* @param _reserve the address of the principal reserve where the user borrowed
* @param _user the address of the borrower
* @param _balanceIncrease the accrued interest on the borrowed amount
* @return the new stable rate for the user
**/
function updateStateOnRebalance(
address _reserve,
address _user,
uint256 _balanceIncrease
) external onlyLendingPool returns (uint256) {
updateReserveStateOnRebalanceInternal(_reserve, _user, _balanceIncrease);
//update user data and rebalance the rate
updateUserStateOnRebalanceInternal(_reserve, _user, _balanceIncrease);
updateReserveInterestRatesAndTimestampInternal(_reserve, 0, 0);
return usersReserveData[_user][_reserve].stableBorrowRate;
}
/**
* @dev enables or disables a reserve as collateral
* @param _reserve the address of the principal reserve where the user deposited
* @param _user the address of the depositor
* @param _useAsCollateral true if the depositor wants to use the reserve as collateral
**/
function setUserUseReserveAsCollateral(
address _reserve,
address _user,
bool _useAsCollateral
) public onlyLendingPool {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
user.useAsCollateral = _useAsCollateral;
}
/**
* @notice ETH/token transfer functions
**/
/**
* @dev fallback function enforces that the caller is a contract, to support flashloan transfers
**/
function() external payable {
//only contracts can send ETH to the core
require(msg.sender.isContract(), 'Only contracts can send ether to the Lending pool core');
}
/**
* @dev transfers to the user a specific amount from the reserve.
* @param _reserve the address of the reserve where the transfer is happening
* @param _user the address of the user receiving the transfer
* @param _amount the amount being transferred
**/
function transferToUser(
address _reserve,
address payable _user,
uint256 _amount
) external onlyLendingPool {
if (_reserve != EthAddressLib.ethAddress()) {
ERC20(_reserve).safeTransfer(_user, _amount);
} else {
//solium-disable-next-line
(bool result, ) = _user.call.value(_amount).gas(50000)('');
require(result, 'Transfer of ETH failed');
}
}
/**
* @dev transfers the protocol fees to the fees collection address
* @param _token the address of the token being transferred
* @param _user the address of the user from where the transfer is happening
* @param _amount the amount being transferred
* @param _destination the fee receiver address
**/
function transferToFeeCollectionAddress(
address _token,
address _user,
uint256 _amount,
address _destination
) external payable onlyLendingPool {
address payable feeAddress = address(uint160(_destination)); //cast the address to payable
if (_token != EthAddressLib.ethAddress()) {
require(
msg.value == 0,
'User is sending ETH along with the ERC20 transfer. Check the value attribute of the transaction'
);
ERC20(_token).safeTransferFrom(_user, feeAddress, _amount);
} else {
require(msg.value >= _amount, 'The amount and the value sent to deposit do not match');
//solium-disable-next-line
(bool result, ) = feeAddress.call.value(_amount).gas(50000)('');
require(result, 'Transfer of ETH failed');
}
}
/**
* @dev transfers the fees to the fees collection address in the case of liquidation
* @param _token the address of the token being transferred
* @param _amount the amount being transferred
* @param _destination the fee receiver address
**/
function liquidateFee(
address _token,
uint256 _amount,
address _destination
) external payable onlyLendingPool {
address payable feeAddress = address(uint160(_destination)); //cast the address to payable
require(msg.value == 0, 'Fee liquidation does not require any transfer of value');
if (_token != EthAddressLib.ethAddress()) {
ERC20(_token).safeTransfer(feeAddress, _amount);
} else {
//solium-disable-next-line
(bool result, ) = feeAddress.call.value(_amount).gas(50000)('');
require(result, 'Transfer of ETH failed');
}
}
/**
* @dev transfers an amount from a user to the destination reserve
* @param _reserve the address of the reserve where the amount is being transferred
* @param _user the address of the user from where the transfer is happening
* @param _amount the amount being transferred
**/
function transferToReserve(
address _reserve,
address payable _user,
uint256 _amount
) external payable onlyLendingPool {
if (_reserve != EthAddressLib.ethAddress()) {
require(msg.value == 0, 'User is sending ETH along with the ERC20 transfer.');
ERC20(_reserve).safeTransferFrom(_user, address(this), _amount);
} else {
require(msg.value >= _amount, 'The amount and the value sent to deposit do not match');
if (msg.value > _amount) {
//send back excess ETH
uint256 excessAmount = msg.value.sub(_amount);
//solium-disable-next-line
(bool result, ) = _user.call.value(excessAmount).gas(50000)('');
require(result, 'Transfer of ETH failed');
}
}
}
/**
* @notice data access functions
**/
/**
* @dev returns the basic data (balances, fee accrued, reserve enabled/disabled as collateral)
* needed to calculate the global account data in the LendingPoolDataProvider
* @param _reserve the address of the reserve
* @param _user the address of the user
* @return the user deposited balance, the principal borrow balance, the fee, and if the reserve is enabled as collateral or not
**/
function getUserBasicReserveData(
address _reserve,
address _user
) external view returns (uint256, uint256, uint256, bool) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
uint256 underlyingBalance = getUserUnderlyingAssetBalance(_reserve, _user);
if (user.principalBorrowBalance == 0) {
return (underlyingBalance, 0, 0, user.useAsCollateral);
}
return (
underlyingBalance,
user.getCompoundedBorrowBalance(reserve),
user.originationFee,
user.useAsCollateral
);
}
/**
* @dev checks if a user is allowed to borrow at a stable rate
* @param _reserve the reserve address
* @param _user the user
* @param _amount the amount the the user wants to borrow
* @return true if the user is allowed to borrow at a stable rate, false otherwise
**/
function isUserAllowedToBorrowAtStable(
address _reserve,
address _user,
uint256 _amount
) external view returns (bool) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
if (!reserve.isStableBorrowRateEnabled) return false;
return
!user.useAsCollateral ||
!reserve.usageAsCollateralEnabled ||
_amount > getUserUnderlyingAssetBalance(_reserve, _user);
}
/**
* @dev gets the underlying asset balance of a user based on the corresponding aToken balance.
* @param _reserve the reserve address
* @param _user the user address
* @return the underlying deposit balance of the user
**/
function getUserUnderlyingAssetBalance(
address _reserve,
address _user
) public view returns (uint256) {
AToken aToken = AToken(reserves[_reserve].aTokenAddress);
return aToken.balanceOf(_user);
}
/**
* @dev gets the interest rate strategy contract address for the reserve
* @param _reserve the reserve address
* @return the address of the interest rate strategy contract
**/
function getReserveInterestRateStrategyAddress(address _reserve) public view returns (address) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.interestRateStrategyAddress;
}
/**
* @dev gets the aToken contract address for the reserve
* @param _reserve the reserve address
* @return the address of the aToken contract
**/
function getReserveATokenAddress(address _reserve) public view returns (address) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.aTokenAddress;
}
/**
* @dev gets the available liquidity in the reserve. The available liquidity is the balance of the core contract
* @param _reserve the reserve address
* @return the available liquidity
**/
function getReserveAvailableLiquidity(address _reserve) public view returns (uint256) {
uint256 balance = 0;
if (_reserve == EthAddressLib.ethAddress()) {
balance = address(this).balance;
} else {
balance = IERC20(_reserve).balanceOf(address(this));
}
return balance;
}
/**
* @dev gets the total liquidity in the reserve. The total liquidity is the balance of the core contract + total borrows
* @param _reserve the reserve address
* @return the total liquidity
**/
function getReserveTotalLiquidity(address _reserve) public view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return getReserveAvailableLiquidity(_reserve).add(reserve.getTotalBorrows());
}
/**
* @dev gets the normalized income of the reserve. a value of 1e27 means there is no income. A value of 2e27 means there
* there has been 100% income.
* @param _reserve the reserve address
* @return the reserve normalized income
**/
function getReserveNormalizedIncome(address _reserve) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.getNormalizedIncome();
}
/**
* @dev gets the reserve total borrows
* @param _reserve the reserve address
* @return the total borrows (stable + variable)
**/
function getReserveTotalBorrows(address _reserve) public view returns (uint256) {
return reserves[_reserve].getTotalBorrows();
}
/**
* @dev gets the reserve total borrows stable
* @param _reserve the reserve address
* @return the total borrows stable
**/
function getReserveTotalBorrowsStable(address _reserve) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.totalBorrowsStable;
}
/**
* @dev gets the reserve total borrows variable
* @param _reserve the reserve address
* @return the total borrows variable
**/
function getReserveTotalBorrowsVariable(address _reserve) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.totalBorrowsVariable;
}
/**
* @dev gets the reserve liquidation threshold
* @param _reserve the reserve address
* @return the reserve liquidation threshold
**/
function getReserveLiquidationThreshold(address _reserve) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.liquidationThreshold;
}
/**
* @dev gets the reserve liquidation bonus
* @param _reserve the reserve address
* @return the reserve liquidation bonus
**/
function getReserveLiquidationBonus(address _reserve) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.liquidationBonus;
}
/**
* @dev gets the reserve current variable borrow rate. Is the base variable borrow rate if the reserve is empty
* @param _reserve the reserve address
* @return the reserve current variable borrow rate
**/
function getReserveCurrentVariableBorrowRate(address _reserve) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
if (reserve.currentVariableBorrowRate == 0) {
return
IReserveInterestRateStrategy(reserve.interestRateStrategyAddress)
.getBaseVariableBorrowRate();
}
return reserve.currentVariableBorrowRate;
}
/**
* @dev gets the reserve current stable borrow rate. Is the market rate if the reserve is empty
* @param _reserve the reserve address
* @return the reserve current stable borrow rate
**/
function getReserveCurrentStableBorrowRate(address _reserve) public view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
ILendingRateOracle oracle = ILendingRateOracle(addressesProvider.getLendingRateOracle());
if (reserve.currentStableBorrowRate == 0) {
//no stable rate borrows yet
return oracle.getMarketBorrowRate(_reserve);
}
return reserve.currentStableBorrowRate;
}
/**
* @dev gets the reserve average stable borrow rate. The average stable rate is the weighted average
* of all the loans taken at stable rate.
* @param _reserve the reserve address
* @return the reserve current average borrow rate
**/
function getReserveCurrentAverageStableBorrowRate(
address _reserve
) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.currentAverageStableBorrowRate;
}
/**
* @dev gets the reserve liquidity rate
* @param _reserve the reserve address
* @return the reserve liquidity rate
**/
function getReserveCurrentLiquidityRate(address _reserve) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.currentLiquidityRate;
}
/**
* @dev gets the reserve liquidity cumulative index
* @param _reserve the reserve address
* @return the reserve liquidity cumulative index
**/
function getReserveLiquidityCumulativeIndex(address _reserve) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.lastLiquidityCumulativeIndex;
}
/**
* @dev gets the reserve variable borrow index
* @param _reserve the reserve address
* @return the reserve variable borrow index
**/
function getReserveVariableBorrowsCumulativeIndex(
address _reserve
) external view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.lastVariableBorrowCumulativeIndex;
}
/**
* @dev this function aggregates the configuration parameters of the reserve.
* It's used in the LendingPoolDataProvider specifically to save gas, and avoid
* multiple external contract calls to fetch the same data.
* @param _reserve the reserve address
* @return the reserve decimals
* @return the base ltv as collateral
* @return the liquidation threshold
* @return if the reserve is used as collateral or not
**/
function getReserveConfiguration(
address _reserve
) external view returns (uint256, uint256, uint256, bool) {
uint256 decimals;
uint256 baseLTVasCollateral;
uint256 liquidationThreshold;
bool usageAsCollateralEnabled;
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
decimals = reserve.decimals;
baseLTVasCollateral = reserve.baseLTVasCollateral;
liquidationThreshold = reserve.liquidationThreshold;
usageAsCollateralEnabled = reserve.usageAsCollateralEnabled;
return (decimals, baseLTVasCollateral, liquidationThreshold, usageAsCollateralEnabled);
}
/**
* @dev returns the decimals of the reserve
* @param _reserve the reserve address
* @return the reserve decimals
**/
function getReserveDecimals(address _reserve) external view returns (uint256) {
return reserves[_reserve].decimals;
}
/**
* @dev returns true if the reserve is enabled for borrowing
* @param _reserve the reserve address
* @return true if the reserve is enabled for borrowing, false otherwise
**/
function isReserveBorrowingEnabled(address _reserve) external view returns (bool) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.borrowingEnabled;
}
/**
* @dev returns true if the reserve is enabled as collateral
* @param _reserve the reserve address
* @return true if the reserve is enabled as collateral, false otherwise
**/
function isReserveUsageAsCollateralEnabled(address _reserve) external view returns (bool) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.usageAsCollateralEnabled;
}
/**
* @dev returns true if the stable rate is enabled on reserve
* @param _reserve the reserve address
* @return true if the stable rate is enabled on reserve, false otherwise
**/
function getReserveIsStableBorrowRateEnabled(address _reserve) external view returns (bool) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.isStableBorrowRateEnabled;
}
/**
* @dev returns true if the reserve is active
* @param _reserve the reserve address
* @return true if the reserve is active, false otherwise
**/
function getReserveIsActive(address _reserve) external view returns (bool) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.isActive;
}
/**
* @notice returns if a reserve is freezed
* @param _reserve the reserve for which the information is needed
* @return true if the reserve is freezed, false otherwise
**/
function getReserveIsFreezed(address _reserve) external view returns (bool) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return reserve.isFreezed;
}
/**
* @notice returns the timestamp of the last action on the reserve
* @param _reserve the reserve for which the information is needed
* @return the last updated timestamp of the reserve
**/
function getReserveLastUpdate(address _reserve) external view returns (uint40 timestamp) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
timestamp = reserve.lastUpdateTimestamp;
}
/**
* @dev returns the utilization rate U of a specific reserve
* @param _reserve the reserve for which the information is needed
* @return the utilization rate in ray
**/
function getReserveUtilizationRate(address _reserve) public view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
uint256 totalBorrows = reserve.getTotalBorrows();
if (totalBorrows == 0) {
return 0;
}
uint256 availableLiquidity = getReserveAvailableLiquidity(_reserve);
return totalBorrows.rayDiv(availableLiquidity.add(totalBorrows));
}
/**
* @return the array of reserves configured on the core
**/
function getReserves() external view returns (address[] memory) {
return reservesList;
}
/**
* @param _reserve the address of the reserve for which the information is needed
* @param _user the address of the user for which the information is needed
* @return true if the user has chosen to use the reserve as collateral, false otherwise
**/
function isUserUseReserveAsCollateralEnabled(
address _reserve,
address _user
) external view returns (bool) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
return user.useAsCollateral;
}
/**
* @param _reserve the address of the reserve for which the information is needed
* @param _user the address of the user for which the information is needed
* @return the origination fee for the user
**/
function getUserOriginationFee(address _reserve, address _user) external view returns (uint256) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
return user.originationFee;
}
/**
* @dev users with no loans in progress have NONE as borrow rate mode
* @param _reserve the address of the reserve for which the information is needed
* @param _user the address of the user for which the information is needed
* @return the borrow rate mode for the user,
**/
function getUserCurrentBorrowRateMode(
address _reserve,
address _user
) public view returns (CoreLibrary.InterestRateMode) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
if (user.principalBorrowBalance == 0) {
return CoreLibrary.InterestRateMode.NONE;
}
return
user.stableBorrowRate > 0
? CoreLibrary.InterestRateMode.STABLE
: CoreLibrary.InterestRateMode.VARIABLE;
}
/**
* @dev gets the current borrow rate of the user
* @param _reserve the address of the reserve for which the information is needed
* @param _user the address of the user for which the information is needed
* @return the borrow rate for the user,
**/
function getUserCurrentBorrowRate(
address _reserve,
address _user
) internal view returns (uint256) {
CoreLibrary.InterestRateMode rateMode = getUserCurrentBorrowRateMode(_reserve, _user);
if (rateMode == CoreLibrary.InterestRateMode.NONE) {
return 0;
}
return
rateMode == CoreLibrary.InterestRateMode.STABLE
? usersReserveData[_user][_reserve].stableBorrowRate
: reserves[_reserve].currentVariableBorrowRate;
}
/**
* @dev the stable rate returned is 0 if the user is borrowing at variable or not borrowing at all
* @param _reserve the address of the reserve for which the information is needed
* @param _user the address of the user for which the information is needed
* @return the user stable rate
**/
function getUserCurrentStableBorrowRate(
address _reserve,
address _user
) external view returns (uint256) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
return user.stableBorrowRate;
}
/**
* @dev calculates and returns the borrow balances of the user
* @param _reserve the address of the reserve
* @param _user the address of the user
* @return the principal borrow balance, the compounded balance and the balance increase since the last borrow/repay/swap/rebalance
**/
function getUserBorrowBalances(
address _reserve,
address _user
) public view returns (uint256, uint256, uint256) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
if (user.principalBorrowBalance == 0) {
return (0, 0, 0);
}
uint256 principal = user.principalBorrowBalance;
uint256 compoundedBalance = CoreLibrary.getCompoundedBorrowBalance(user, reserves[_reserve]);
return (principal, compoundedBalance, compoundedBalance.sub(principal));
}
/**
* @dev the variable borrow index of the user is 0 if the user is not borrowing or borrowing at stable
* @param _reserve the address of the reserve for which the information is needed
* @param _user the address of the user for which the information is needed
* @return the variable borrow index for the user
**/
function getUserVariableBorrowCumulativeIndex(
address _reserve,
address _user
) external view returns (uint256) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
return user.lastVariableBorrowCumulativeIndex;
}
/**
* @dev the variable borrow index of the user is 0 if the user is not borrowing or borrowing at stable
* @param _reserve the address of the reserve for which the information is needed
* @param _user the address of the user for which the information is needed
* @return the variable borrow index for the user
**/
function getUserLastUpdate(
address _reserve,
address _user
) external view returns (uint256 timestamp) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
timestamp = user.lastUpdateTimestamp;
}
/**
* @dev updates the lending pool core configuration
**/
function refreshConfiguration() external onlyLendingPoolConfigurator {
refreshConfigInternal();
}
/**
* @dev initializes a reserve
* @param _reserve the address of the reserve
* @param _aTokenAddress the address of the overlying aToken contract
* @param _decimals the decimals of the reserve currency
* @param _interestRateStrategyAddress the address of the interest rate strategy contract
**/
function initReserve(
address _reserve,
address _aTokenAddress,
uint256 _decimals,
address _interestRateStrategyAddress
) external onlyLendingPoolConfigurator {
reserves[_reserve].init(_aTokenAddress, _decimals, _interestRateStrategyAddress);
addReserveToListInternal(_reserve);
}
/**
* @dev removes the last added reserve in the reservesList array
* @param _reserveToRemove the address of the reserve
**/
function removeLastAddedReserve(address _reserveToRemove) external onlyLendingPoolConfigurator {
address lastReserve = reservesList[reservesList.length - 1];
require(
lastReserve == _reserveToRemove,
'Reserve being removed is different than the reserve requested'
);
//as we can't check if totalLiquidity is 0 (since the reserve added might not be an ERC20) we at least check that there is nothing borrowed
require(
getReserveTotalBorrows(lastReserve) == 0,
'Cannot remove a reserve with liquidity deposited'
);
reserves[lastReserve].isActive = false;
reserves[lastReserve].aTokenAddress = address(0);
reserves[lastReserve].decimals = 0;
reserves[lastReserve].lastLiquidityCumulativeIndex = 0;
reserves[lastReserve].lastVariableBorrowCumulativeIndex = 0;
reserves[lastReserve].borrowingEnabled = false;
reserves[lastReserve].usageAsCollateralEnabled = false;
reserves[lastReserve].baseLTVasCollateral = 0;
reserves[lastReserve].liquidationThreshold = 0;
reserves[lastReserve].liquidationBonus = 0;
reserves[lastReserve].interestRateStrategyAddress = address(0);
reservesList.pop();
}
/**
* @dev updates the address of the interest rate strategy contract
* @param _reserve the address of the reserve
* @param _rateStrategyAddress the address of the interest rate strategy contract
**/
function setReserveInterestRateStrategyAddress(
address _reserve,
address _rateStrategyAddress
) external onlyLendingPoolConfigurator {
updateReserveInterestRatesAndTimestampInternal(_reserve, 0, 0);
reserves[_reserve].updateCumulativeIndexes();
reserves[_reserve].interestRateStrategyAddress = _rateStrategyAddress;
updateReserveInterestRatesAndTimestampInternal(_reserve, 0, 0);
}
/**
* @dev enables borrowing on a reserve. Also sets the stable rate borrowing
* @param _reserve the address of the reserve
* @param _stableBorrowRateEnabled true if the stable rate needs to be enabled, false otherwise
**/
function enableBorrowingOnReserve(
address _reserve,
bool _stableBorrowRateEnabled
) external onlyLendingPoolConfigurator {
reserves[_reserve].enableBorrowing(_stableBorrowRateEnabled);
}
/**
* @dev disables borrowing on a reserve
* @param _reserve the address of the reserve
**/
function disableBorrowingOnReserve(address _reserve) external onlyLendingPoolConfigurator {
reserves[_reserve].disableBorrowing();
}
/**
* @dev enables a reserve to be used as collateral
* @param _reserve the address of the reserve
**/
function enableReserveAsCollateral(
address _reserve,
uint256 _baseLTVasCollateral,
uint256 _liquidationThreshold,
uint256 _liquidationBonus
) external onlyLendingPoolConfigurator {
reserves[_reserve].enableAsCollateral(
_baseLTVasCollateral,
_liquidationThreshold,
_liquidationBonus
);
}
/**
* @dev disables a reserve to be used as collateral
* @param _reserve the address of the reserve
**/
function disableReserveAsCollateral(address _reserve) external onlyLendingPoolConfigurator {
reserves[_reserve].disableAsCollateral();
}
/**
* @dev enable the stable borrow rate mode on a reserve
* @param _reserve the address of the reserve
**/
function enableReserveStableBorrowRate(address _reserve) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.isStableBorrowRateEnabled = true;
}
/**
* @dev disable the stable borrow rate mode on a reserve
* @param _reserve the address of the reserve
**/
function disableReserveStableBorrowRate(address _reserve) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.isStableBorrowRateEnabled = false;
}
/**
* @dev activates a reserve
* @param _reserve the address of the reserve
**/
function activateReserve(address _reserve) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
require(
reserve.lastLiquidityCumulativeIndex > 0 && reserve.lastVariableBorrowCumulativeIndex > 0,
'Reserve has not been initialized yet'
);
reserve.isActive = true;
}
/**
* @dev deactivates a reserve
* @param _reserve the address of the reserve
**/
function deactivateReserve(address _reserve) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.isActive = false;
}
/**
* @notice allows the configurator to freeze the reserve.
* A freezed reserve does not allow any action apart from repay, redeem, liquidationCall, rebalance.
* @param _reserve the address of the reserve
**/
function freezeReserve(address _reserve) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.isFreezed = true;
}
/**
* @notice allows the configurator to unfreeze the reserve. A unfreezed reserve allows any action to be executed.
* @param _reserve the address of the reserve
**/
function unfreezeReserve(address _reserve) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.isFreezed = false;
}
/**
* @notice allows the configurator to update the loan to value of a reserve
* @param _reserve the address of the reserve
* @param _ltv the new loan to value
**/
function setReserveBaseLTVasCollateral(
address _reserve,
uint256 _ltv
) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.baseLTVasCollateral = _ltv;
}
/**
* @notice allows the configurator to update the liquidation threshold of a reserve
* @param _reserve the address of the reserve
* @param _threshold the new liquidation threshold
**/
function setReserveLiquidationThreshold(
address _reserve,
uint256 _threshold
) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.liquidationThreshold = _threshold;
}
/**
* @notice allows the configurator to update the liquidation bonus of a reserve
* @param _reserve the address of the reserve
* @param _bonus the new liquidation bonus
**/
function setReserveLiquidationBonus(
address _reserve,
uint256 _bonus
) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.liquidationBonus = _bonus;
}
/**
* @notice allows the configurator to update the reserve decimals
* @param _reserve the address of the reserve
* @param _decimals the decimals of the reserve
**/
function setReserveDecimals(
address _reserve,
uint256 _decimals
) external onlyLendingPoolConfigurator {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
reserve.decimals = _decimals;
}
/**
* @notice internal functions
**/
/**
* @dev updates the state of a reserve as a consequence of a borrow action.
* @param _reserve the address of the reserve on which the user is borrowing
* @param _user the address of the borrower
* @param _principalBorrowBalance the previous borrow balance of the borrower before the action
* @param _balanceIncrease the accrued interest of the user on the previous borrowed amount
* @param _amountBorrowed the new amount borrowed
* @param _rateMode the borrow rate mode (stable, variable)
**/
function updateReserveStateOnBorrowInternal(
address _reserve,
address _user,
uint256 _principalBorrowBalance,
uint256 _balanceIncrease,
uint256 _amountBorrowed,
CoreLibrary.InterestRateMode _rateMode
) internal {
reserves[_reserve].updateCumulativeIndexes();
//increasing reserve total borrows to account for the new borrow balance of the user
//NOTE: Depending on the previous borrow mode, the borrows might need to be switched from variable to stable or vice versa
updateReserveTotalBorrowsByRateModeInternal(
_reserve,
_user,
_principalBorrowBalance,
_balanceIncrease,
_amountBorrowed,
_rateMode
);
}
/**
* @dev updates the state of a user as a consequence of a borrow action.
* @param _reserve the address of the reserve on which the user is borrowing
* @param _user the address of the borrower
* @param _amountBorrowed the amount borrowed
* @param _balanceIncrease the accrued interest of the user on the previous borrowed amount
* @param _rateMode the borrow rate mode (stable, variable)
* @return the final borrow rate for the user. Emitted by the borrow() event
**/
function updateUserStateOnBorrowInternal(
address _reserve,
address _user,
uint256 _amountBorrowed,
uint256 _balanceIncrease,
uint256 _fee,
CoreLibrary.InterestRateMode _rateMode
) internal {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
if (_rateMode == CoreLibrary.InterestRateMode.STABLE) {
//stable
//reset the user variable index, and update the stable rate
user.stableBorrowRate = reserve.currentStableBorrowRate;
user.lastVariableBorrowCumulativeIndex = 0;
} else if (_rateMode == CoreLibrary.InterestRateMode.VARIABLE) {
//variable
//reset the user stable rate, and store the new borrow index
user.stableBorrowRate = 0;
user.lastVariableBorrowCumulativeIndex = reserve.lastVariableBorrowCumulativeIndex;
} else {
revert('Invalid borrow rate mode');
}
//increase the principal borrows and the origination fee
user.principalBorrowBalance = user.principalBorrowBalance.add(_amountBorrowed).add(
_balanceIncrease
);
user.originationFee = user.originationFee.add(_fee);
//solium-disable-next-line
user.lastUpdateTimestamp = uint40(block.timestamp);
}
/**
* @dev updates the state of the reserve as a consequence of a repay action.
* @param _reserve the address of the reserve on which the user is repaying
* @param _user the address of the borrower
* @param _paybackAmountMinusFees the amount being paid back minus fees
* @param _balanceIncrease the accrued interest on the borrowed amount
**/
function updateReserveStateOnRepayInternal(
address _reserve,
address _user,
uint256 _paybackAmountMinusFees,
uint256 _balanceIncrease
) internal {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
CoreLibrary.InterestRateMode borrowRateMode = getUserCurrentBorrowRateMode(_reserve, _user);
//update the indexes
reserves[_reserve].updateCumulativeIndexes();
//compound the cumulated interest to the borrow balance and then subtracting the payback amount
if (borrowRateMode == CoreLibrary.InterestRateMode.STABLE) {
reserve.increaseTotalBorrowsStableAndUpdateAverageRate(
_balanceIncrease,
user.stableBorrowRate
);
reserve.decreaseTotalBorrowsStableAndUpdateAverageRate(
_paybackAmountMinusFees,
user.stableBorrowRate
);
} else {
reserve.increaseTotalBorrowsVariable(_balanceIncrease);
reserve.decreaseTotalBorrowsVariable(_paybackAmountMinusFees);
}
}
/**
* @dev updates the state of the user as a consequence of a repay action.
* @param _reserve the address of the reserve on which the user is repaying
* @param _user the address of the borrower
* @param _paybackAmountMinusFees the amount being paid back minus fees
* @param _originationFeeRepaid the fee on the amount that is being repaid
* @param _balanceIncrease the accrued interest on the borrowed amount
* @param _repaidWholeLoan true if the user is repaying the whole loan
**/
function updateUserStateOnRepayInternal(
address _reserve,
address _user,
uint256 _paybackAmountMinusFees,
uint256 _originationFeeRepaid,
uint256 _balanceIncrease,
bool _repaidWholeLoan
) internal {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
//update the user principal borrow balance, adding the cumulated interest and then subtracting the payback amount
user.principalBorrowBalance = user.principalBorrowBalance.add(_balanceIncrease).sub(
_paybackAmountMinusFees
);
user.lastVariableBorrowCumulativeIndex = reserve.lastVariableBorrowCumulativeIndex;
//if the balance decrease is equal to the previous principal (user is repaying the whole loan)
//and the rate mode is stable, we reset the interest rate mode of the user
if (_repaidWholeLoan) {
user.stableBorrowRate = 0;
user.lastVariableBorrowCumulativeIndex = 0;
}
user.originationFee = user.originationFee.sub(_originationFeeRepaid);
//solium-disable-next-line
user.lastUpdateTimestamp = uint40(block.timestamp);
}
/**
* @dev updates the state of the user as a consequence of a swap rate action.
* @param _reserve the address of the reserve on which the user is performing the rate swap
* @param _user the address of the borrower
* @param _principalBorrowBalance the the principal amount borrowed by the user
* @param _compoundedBorrowBalance the principal amount plus the accrued interest
* @param _currentRateMode the rate mode at which the user borrowed
**/
function updateReserveStateOnSwapRateInternal(
address _reserve,
address _user,
uint256 _principalBorrowBalance,
uint256 _compoundedBorrowBalance,
CoreLibrary.InterestRateMode _currentRateMode
) internal {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
//compounding reserve indexes
reserve.updateCumulativeIndexes();
if (_currentRateMode == CoreLibrary.InterestRateMode.STABLE) {
uint256 userCurrentStableRate = user.stableBorrowRate;
//swap to variable
reserve.decreaseTotalBorrowsStableAndUpdateAverageRate(
_principalBorrowBalance,
userCurrentStableRate
); //decreasing stable from old principal balance
reserve.increaseTotalBorrowsVariable(_compoundedBorrowBalance); //increase variable borrows
} else if (_currentRateMode == CoreLibrary.InterestRateMode.VARIABLE) {
//swap to stable
uint256 currentStableRate = reserve.currentStableBorrowRate;
reserve.decreaseTotalBorrowsVariable(_principalBorrowBalance);
reserve.increaseTotalBorrowsStableAndUpdateAverageRate(
_compoundedBorrowBalance,
currentStableRate
);
} else {
revert('Invalid rate mode received');
}
}
/**
* @dev updates the state of the user as a consequence of a swap rate action.
* @param _reserve the address of the reserve on which the user is performing the swap
* @param _user the address of the borrower
* @param _balanceIncrease the accrued interest on the borrowed amount
* @param _currentRateMode the current rate mode of the user
**/
function updateUserStateOnSwapRateInternal(
address _reserve,
address _user,
uint256 _balanceIncrease,
CoreLibrary.InterestRateMode _currentRateMode
) internal returns (CoreLibrary.InterestRateMode) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
CoreLibrary.InterestRateMode newMode = CoreLibrary.InterestRateMode.NONE;
if (_currentRateMode == CoreLibrary.InterestRateMode.VARIABLE) {
//switch to stable
newMode = CoreLibrary.InterestRateMode.STABLE;
user.stableBorrowRate = reserve.currentStableBorrowRate;
user.lastVariableBorrowCumulativeIndex = 0;
} else if (_currentRateMode == CoreLibrary.InterestRateMode.STABLE) {
newMode = CoreLibrary.InterestRateMode.VARIABLE;
user.stableBorrowRate = 0;
user.lastVariableBorrowCumulativeIndex = reserve.lastVariableBorrowCumulativeIndex;
} else {
revert('Invalid interest rate mode received');
}
//compounding cumulated interest
user.principalBorrowBalance = user.principalBorrowBalance.add(_balanceIncrease);
//solium-disable-next-line
user.lastUpdateTimestamp = uint40(block.timestamp);
return newMode;
}
/**
* @dev updates the state of the principal reserve as a consequence of a liquidation action.
* @param _principalReserve the address of the principal reserve that is being repaid
* @param _user the address of the borrower
* @param _amountToLiquidate the amount being repaid by the liquidator
* @param _balanceIncrease the accrued interest on the borrowed amount
**/
function updatePrincipalReserveStateOnLiquidationInternal(
address _principalReserve,
address _user,
uint256 _amountToLiquidate,
uint256 _balanceIncrease
) internal {
CoreLibrary.ReserveData storage reserve = reserves[_principalReserve];
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_principalReserve];
//update principal reserve data
reserve.updateCumulativeIndexes();
CoreLibrary.InterestRateMode borrowRateMode = getUserCurrentBorrowRateMode(
_principalReserve,
_user
);
if (borrowRateMode == CoreLibrary.InterestRateMode.STABLE) {
//increase the total borrows by the compounded interest
reserve.increaseTotalBorrowsStableAndUpdateAverageRate(
_balanceIncrease,
user.stableBorrowRate
);
//decrease by the actual amount to liquidate
reserve.decreaseTotalBorrowsStableAndUpdateAverageRate(
_amountToLiquidate,
user.stableBorrowRate
);
} else {
//increase the total borrows by the compounded interest
reserve.increaseTotalBorrowsVariable(_balanceIncrease);
//decrease by the actual amount to liquidate
reserve.decreaseTotalBorrowsVariable(_amountToLiquidate);
}
}
/**
* @dev updates the state of the collateral reserve as a consequence of a liquidation action.
* @param _collateralReserve the address of the collateral reserve that is being liquidated
**/
function updateCollateralReserveStateOnLiquidationInternal(address _collateralReserve) internal {
//update collateral reserve
reserves[_collateralReserve].updateCumulativeIndexes();
}
/**
* @dev updates the state of the user being liquidated as a consequence of a liquidation action.
* @param _reserve the address of the principal reserve that is being repaid
* @param _user the address of the borrower
* @param _amountToLiquidate the amount being repaid by the liquidator
* @param _feeLiquidated the amount of origination fee being liquidated
* @param _balanceIncrease the accrued interest on the borrowed amount
**/
function updateUserStateOnLiquidationInternal(
address _reserve,
address _user,
uint256 _amountToLiquidate,
uint256 _feeLiquidated,
uint256 _balanceIncrease
) internal {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
//first increase by the compounded interest, then decrease by the liquidated amount
user.principalBorrowBalance = user.principalBorrowBalance.add(_balanceIncrease).sub(
_amountToLiquidate
);
if (getUserCurrentBorrowRateMode(_reserve, _user) == CoreLibrary.InterestRateMode.VARIABLE) {
user.lastVariableBorrowCumulativeIndex = reserve.lastVariableBorrowCumulativeIndex;
}
if (_feeLiquidated > 0) {
user.originationFee = user.originationFee.sub(_feeLiquidated);
}
//solium-disable-next-line
user.lastUpdateTimestamp = uint40(block.timestamp);
}
/**
* @dev updates the state of the reserve as a consequence of a stable rate rebalance
* DEPRECATED FOR THE V1 -> V2 migration
* @param _reserve the address of the principal reserve where the user borrowed
* @param _user the address of the borrower
* @param _balanceIncrease the accrued interest on the borrowed amount
**/
function updateReserveStateOnRebalanceInternal(
address _reserve,
address _user,
uint256 _balanceIncrease
) internal {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
reserve.updateCumulativeIndexes();
reserve.increaseTotalBorrowsStableAndUpdateAverageRate(_balanceIncrease, user.stableBorrowRate);
}
/**
* @dev updates the state of the user as a consequence of a stable rate rebalance
* @param _reserve the address of the principal reserve where the user borrowed
* @param _user the address of the borrower
* @param _balanceIncrease the accrued interest on the borrowed amount
**/
function updateUserStateOnRebalanceInternal(
address _reserve,
address _user,
uint256 _balanceIncrease
) internal {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
user.principalBorrowBalance = user.principalBorrowBalance.add(_balanceIncrease);
user.stableBorrowRate = reserve.currentStableBorrowRate;
//solium-disable-next-line
user.lastUpdateTimestamp = uint40(block.timestamp);
}
/**
* @dev updates the state of the user as a consequence of a stable rate rebalance
* @param _reserve the address of the principal reserve where the user borrowed
* @param _user the address of the borrower
* @param _balanceIncrease the accrued interest on the borrowed amount
* @param _amountBorrowed the accrued interest on the borrowed amount
**/
function updateReserveTotalBorrowsByRateModeInternal(
address _reserve,
address _user,
uint256 _principalBalance,
uint256 _balanceIncrease,
uint256 _amountBorrowed,
CoreLibrary.InterestRateMode _newBorrowRateMode
) internal {
CoreLibrary.InterestRateMode previousRateMode = getUserCurrentBorrowRateMode(_reserve, _user);
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
if (previousRateMode == CoreLibrary.InterestRateMode.STABLE) {
CoreLibrary.UserReserveData storage user = usersReserveData[_user][_reserve];
reserve.decreaseTotalBorrowsStableAndUpdateAverageRate(
_principalBalance,
user.stableBorrowRate
);
} else if (previousRateMode == CoreLibrary.InterestRateMode.VARIABLE) {
reserve.decreaseTotalBorrowsVariable(_principalBalance);
}
uint256 newPrincipalAmount = _principalBalance.add(_balanceIncrease).add(_amountBorrowed);
if (_newBorrowRateMode == CoreLibrary.InterestRateMode.STABLE) {
reserve.increaseTotalBorrowsStableAndUpdateAverageRate(
newPrincipalAmount,
reserve.currentStableBorrowRate
);
} else if (_newBorrowRateMode == CoreLibrary.InterestRateMode.VARIABLE) {
reserve.increaseTotalBorrowsVariable(newPrincipalAmount);
} else {
revert('Invalid new borrow rate mode');
}
}
/**
* @dev Updates the reserve current stable borrow rate Rf, the current variable borrow rate Rv and the current liquidity rate Rl.
* Also updates the lastUpdateTimestamp value. Please refer to the whitepaper for further information.
* @param _reserve the address of the reserve to be updated
* @param _liquidityAdded the amount of liquidity added to the protocol (deposit or repay) in the previous action
* @param _liquidityTaken the amount of liquidity taken from the protocol (redeem or borrow)
**/
function updateReserveInterestRatesAndTimestampInternal(
address _reserve,
uint256 _liquidityAdded,
uint256 _liquidityTaken
) internal {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
(
uint256 newLiquidityRate,
uint256 newStableRate,
uint256 newVariableRate
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
_reserve,
getReserveAvailableLiquidity(_reserve).add(_liquidityAdded).sub(_liquidityTaken),
reserve.totalBorrowsStable,
reserve.totalBorrowsVariable,
reserve.currentAverageStableBorrowRate
);
reserve.currentLiquidityRate = newLiquidityRate;
reserve.currentStableBorrowRate = newStableRate;
reserve.currentVariableBorrowRate = newVariableRate;
//solium-disable-next-line
reserve.lastUpdateTimestamp = uint40(block.timestamp);
emit ReserveUpdated(
_reserve,
newLiquidityRate,
newStableRate,
newVariableRate,
reserve.lastLiquidityCumulativeIndex,
reserve.lastVariableBorrowCumulativeIndex
);
}
/**
* @dev transfers to the protocol fees of a flashloan to the fees collection address
* @param _token the address of the token being transferred
* @param _amount the amount being transferred
**/
function transferFlashLoanProtocolFeeInternal(address _token, uint256 _amount) internal {
address payable receiver = address(uint160(addressesProvider.getTokenDistributor()));
if (_token != EthAddressLib.ethAddress()) {
ERC20(_token).safeTransfer(receiver, _amount);
} else {
//solium-disable-next-line
(bool result, ) = receiver.call.value(_amount)('');
require(result, 'Transfer to token distributor failed');
}
}
/**
* @dev updates the internal configuration of the core
**/
function refreshConfigInternal() internal {
lendingPoolAddress = addressesProvider.getLendingPool();
}
/**
* @dev adds a reserve to the array of the reserves address
**/
function addReserveToListInternal(address _reserve) internal {
bool reserveAlreadyAdded = false;
for (uint256 i = 0; i < reservesList.length; i++)
if (reservesList[i] == _reserve) {
reserveAlreadyAdded = true;
}
if (!reserveAlreadyAdded) reservesList.push(_reserve);
}
}{
"remappings": [
"@aave/core-v3/=lib/aave-address-book/lib/aave-v3-core/",
"@aave/periphery-v3/=lib/aave-address-book/lib/aave-v3-periphery/",
"aave-address-book/=lib/aave-address-book/src/",
"solidity-utils/=lib/solidity-utils/src/",
"aave-v3-core/=lib/aave-address-book/lib/aave-v3-core/",
"aave-v3-periphery/=lib/aave-address-book/lib/aave-v3-periphery/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "istanbul",
"libraries": {
"src/contracts/UpdatedLendingPool.sol": {
"CoreLibrary": "0x57fF2Cbf0D1dfd79b497795B2eDd3B56F1a30397"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"reserve","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidityRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stableBorrowRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"variableBorrowRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidityIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"variableBorrowIndex","type":"uint256"}],"name":"ReserveUpdated","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"CORE_REVISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"activateReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"addressesProvider","outputs":[{"internalType":"contract LendingPoolAddressesProvider","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"deactivateReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"disableBorrowingOnReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"disableReserveAsCollateral","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"disableReserveStableBorrowRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"bool","name":"_stableBorrowRateEnabled","type":"bool"}],"name":"enableBorrowingOnReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"uint256","name":"_baseLTVasCollateral","type":"uint256"},{"internalType":"uint256","name":"_liquidationThreshold","type":"uint256"},{"internalType":"uint256","name":"_liquidationBonus","type":"uint256"}],"name":"enableReserveAsCollateral","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"enableReserveStableBorrowRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"freezeReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveATokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveAvailableLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveConfiguration","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveCurrentAverageStableBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveCurrentLiquidityRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveCurrentStableBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveCurrentVariableBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveInterestRateStrategyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveIsFreezed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveIsStableBorrowRateEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveLastUpdate","outputs":[{"internalType":"uint40","name":"timestamp","type":"uint40"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveLiquidationBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveLiquidationThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveLiquidityCumulativeIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveNormalizedIncome","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveTotalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveTotalBorrowsStable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveTotalBorrowsVariable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveTotalLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveUtilizationRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"getReserveVariableBorrowsCumulativeIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserBasicReserveData","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserBorrowBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserCurrentBorrowRateMode","outputs":[{"internalType":"enum CoreLibrary.InterestRateMode","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserCurrentStableBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserLastUpdate","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserOriginationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserUnderlyingAssetBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserVariableBorrowCumulativeIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_aTokenAddress","type":"address"},{"internalType":"uint256","name":"_decimals","type":"uint256"},{"internalType":"address","name":"_interestRateStrategyAddress","type":"address"}],"name":"initReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract LendingPoolAddressesProvider","name":"_addressesProvider","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"isReserveBorrowingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"isReserveUsageAsCollateralEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"isUserAllowedToBorrowAtStable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"isUserUseReserveAsCollateralEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lendingPoolAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_destination","type":"address"}],"name":"liquidateFee","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"refreshConfiguration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserveToRemove","type":"address"}],"name":"removeLastAddedReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"reservesList","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"uint256","name":"_ltv","type":"uint256"}],"name":"setReserveBaseLTVasCollateral","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"uint256","name":"_decimals","type":"uint256"}],"name":"setReserveDecimals","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_rateStrategyAddress","type":"address"}],"name":"setReserveInterestRateStrategyAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"uint256","name":"_bonus","type":"uint256"}],"name":"setReserveLiquidationBonus","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"setReserveLiquidationThreshold","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"bool","name":"_useAsCollateral","type":"bool"}],"name":"setUserUseReserveAsCollateral","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_destination","type":"address"}],"name":"transferToFeeCollectionAddress","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address payable","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToReserve","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address payable","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToUser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"}],"name":"unfreezeReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amountBorrowed","type":"uint256"},{"internalType":"uint256","name":"_borrowFee","type":"uint256"},{"internalType":"enum CoreLibrary.InterestRateMode","name":"_rateMode","type":"uint8"}],"name":"updateStateOnBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_isFirstDeposit","type":"bool"}],"name":"updateStateOnDeposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"uint256","name":"_availableLiquidityBefore","type":"uint256"},{"internalType":"uint256","name":"_income","type":"uint256"},{"internalType":"uint256","name":"_protocolFee","type":"uint256"}],"name":"updateStateOnFlashLoan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_principalReserve","type":"address"},{"internalType":"address","name":"_collateralReserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amountToLiquidate","type":"uint256"},{"internalType":"uint256","name":"_collateralToLiquidate","type":"uint256"},{"internalType":"uint256","name":"_feeLiquidated","type":"uint256"},{"internalType":"uint256","name":"_liquidatedCollateralForFee","type":"uint256"},{"internalType":"uint256","name":"_balanceIncrease","type":"uint256"},{"internalType":"bool","name":"_liquidatorReceivesAToken","type":"bool"}],"name":"updateStateOnLiquidation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_balanceIncrease","type":"uint256"}],"name":"updateStateOnRebalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amountRedeemed","type":"uint256"},{"internalType":"bool","name":"_userRedeemedEverything","type":"bool"}],"name":"updateStateOnRedeem","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_paybackAmountMinusFees","type":"uint256"},{"internalType":"uint256","name":"_originationFeeRepaid","type":"uint256"},{"internalType":"uint256","name":"_balanceIncrease","type":"uint256"},{"internalType":"bool","name":"_repaidWholeLoan","type":"bool"}],"name":"updateStateOnRepay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reserve","type":"address"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_principalBorrowBalance","type":"uint256"},{"internalType":"uint256","name":"_compoundedBorrowBalance","type":"uint256"},{"internalType":"uint256","name":"_balanceIncrease","type":"uint256"},{"internalType":"enum CoreLibrary.InterestRateMode","name":"_currentRateMode","type":"uint8"}],"name":"updateStateOnSwapRate","outputs":[{"internalType":"enum CoreLibrary.InterestRateMode","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040526000805534801561001457600080fd5b5061579c80620000256000396000f3fe60806040526004361061041b5760003560e01c8063a2353fdc1161021e578063d15e005311610123578063e8ae2f5b116100ab578063f61483111161007a578063f6148311146113bf578063f6ea8d7614611443578063fa51854c1461147e578063fa93b2a5146114c3578063feab31ac146115065761041b565b8063e8ae2f5b146112eb578063eede87c11461131e578063ef1f937314611359578063f054ab461461138c5761041b565b8063dae4c4e7116100f2578063dae4c4e7146111d4578063e10076ad14611207578063e2174d8614611242578063e240301914611285578063e6d18190146112b85761041b565b8063d15e0053146110fc578063d3ae26b31461112f578063d466016f14611144578063da12d96f1461117d5761041b565b8063bd7fd79a116101a6578063c540148e11610175578063c540148e14611012578063c72c4d1014611045578063c76a6c9c1461105a578063c7d142371461108d578063d06e2ec1146110c95761041b565b8063bd7fd79a14610f46578063bfacad8414610f79578063c33cfd9014610fac578063c4d66de814610fdf5761041b565b8063afcdbea3116101ed578063afcdbea314610e17578063b701d09314610e62578063b75d6f3414610e95578063b8c0f74514610ec8578063bcd6ffa414610efb5761041b565b8063a2353fdc14610d29578063a5bc826c14610d5c578063a8dc0f4514610da1578063af825b0714610dd45761041b565b80635cf2e656116103245780637aca76eb116102ac578063906c0a411161027b578063906c0a4114610bfc57806398bd473714610c2f5780639e3c4f3b14610c625780639e67484814610c9d5780639fb8afcd14610cd05761041b565b80637aca76eb14610b2d5780637f90fec514610b6057806388079d8814610b935780638f385c2214610bc65761041b565b806366d103f3116102f357806366d103f3146109e057806368beb4d614610a1b5780636ae1441614610a865780636fffab0c14610ab957806370fb84f414610af45761041b565b80635cf2e656146109045780635fc526ff14610937578063646810831461099257806366bbd928146109a75761041b565b80633443a14b116103a757806345330a401161037657806345330a40146107de57806346bc0f28146108275780634a08accb1461085a5780634f1446091461088d5780634fe7a6e5146108da5761041b565b80633443a14b146106b757806334b3beee146106f057806337ac6fe41461073f5780633e72a454146107ab5761041b565b806318a4dbca116103ee57806318a4dbca1461057957806318f9bbae146105b45780631ca19f19146105e75780631d2118f91461064657806328fcf4d3146106815761041b565b806305075d6e146104615780630902f1ac146104a857806309ac29531461050d5780630c7de4e914610552575b61042433611541565b61045f5760405162461bcd60e51b81526004018080602001828103825260368152602001806154ef6036913960400191505060405180910390fd5b005b34801561046d57600080fd5b506104946004803603602081101561048457600080fd5b50356001600160a01b031661154b565b604080519115158252519081900360200190f35b3480156104b457600080fd5b506104bd611573565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104f95781810151838201526020016104e1565b505050509050019250505060405180910390f35b34801561051957600080fd5b5061045f6004803603608081101561053057600080fd5b506001600160a01b0381351690602081013590604081013590606001356115d5565b34801561055e57600080fd5b506105676116a3565b60408051918252519081900360200190f35b34801561058557600080fd5b506105676004803603604081101561059c57600080fd5b506001600160a01b03813581169160200135166116a8565b3480156105c057600080fd5b50610494600480360360208110156105d757600080fd5b50356001600160a01b031661173b565b3480156105f357600080fd5b506106226004803603604081101561060a57600080fd5b506001600160a01b0381358116916020013516611763565b6040518082600281111561063257fe5b60ff16815260200191505060405180910390f35b34801561065257600080fd5b5061045f6004803603604081101561066957600080fd5b506001600160a01b03813581169160200135166117b8565b61045f6004803603606081101561069757600080fd5b506001600160a01b038135811691602081013590911690604001356118dc565b3480156106c357600080fd5b5061045f600480360360408110156106da57600080fd5b506001600160a01b038135169060200135611aa7565b3480156106fc57600080fd5b506107236004803603602081101561071357600080fd5b50356001600160a01b0316611b7b565b604080516001600160a01b039092168252519081900360200190f35b34801561074b57600080fd5b50610792600480360360a081101561076257600080fd5b5080356001600160a01b03908116916020810135909116906040810135906060810135906080013560ff16611b9c565b6040805192835260208301919091528051918290030190f35b3480156107b757600080fd5b5061045f600480360360208110156107ce57600080fd5b50356001600160a01b0316611c3c565b3480156107ea57600080fd5b5061045f6004803603608081101561080157600080fd5b506001600160a01b03813581169160208101358216916040820135916060013516611d18565b34801561083357600080fd5b506105676004803603602081101561084a57600080fd5b50356001600160a01b0316611e72565b34801561086657600080fd5b506104946004803603602081101561087d57600080fd5b50356001600160a01b0316611e90565b34801561089957600080fd5b506108c0600480360360208110156108b057600080fd5b50356001600160a01b0316611eb8565b6040805164ffffffffff9092168252519081900360200190f35b3480156108e657600080fd5b50610723600480360360208110156108fd57600080fd5b5035611ee4565b34801561091057600080fd5b506104946004803603602081101561092757600080fd5b50356001600160a01b0316611f0b565b34801561094357600080fd5b5061096a6004803603602081101561095a57600080fd5b50356001600160a01b0316611f33565b6040805194855260208501939093528383019190915215156060830152519081900360800190f35b34801561099e57600080fd5b5061045f611f71565b3480156109b357600080fd5b5061045f600480360360408110156109ca57600080fd5b506001600160a01b038135169060200135612030565b3480156109ec57600080fd5b5061056760048036036040811015610a0357600080fd5b506001600160a01b0381358116916020013516612104565b348015610a2757600080fd5b5061045f6004803603610120811015610a3f57600080fd5b506001600160a01b03813581169160208101358216916040820135169060608101359060808101359060a08101359060c08101359060e0810135906101000135151561213a565b348015610a9257600080fd5b5061072360048036036020811015610aa957600080fd5b50356001600160a01b03166121dc565b348015610ac557600080fd5b5061056760048036036040811015610adc57600080fd5b506001600160a01b03813581169160200135166121fd565b348015610b0057600080fd5b5061045f60048036036040811015610b1757600080fd5b506001600160a01b03813516906020013561222c565b348015610b3957600080fd5b5061045f60048036036020811015610b5057600080fd5b50356001600160a01b0316612300565b348015610b6c57600080fd5b5061056760048036036020811015610b8357600080fd5b50356001600160a01b03166123e2565b348015610b9f57600080fd5b5061056760048036036020811015610bb657600080fd5b50356001600160a01b0316612400565b61045f60048036036060811015610bdc57600080fd5b506001600160a01b03813581169160208101359160409091013516612528565b348015610c0857600080fd5b5061056760048036036020811015610c1f57600080fd5b50356001600160a01b031661263e565b348015610c3b57600080fd5b5061056760048036036020811015610c5257600080fd5b50356001600160a01b03166126ee565b348015610c6e57600080fd5b5061049460048036036040811015610c8557600080fd5b506001600160a01b038135811691602001351661270c565b348015610ca957600080fd5b5061049460048036036020811015610cc057600080fd5b50356001600160a01b0316612745565b348015610cdc57600080fd5b50610d0b60048036036040811015610cf357600080fd5b506001600160a01b038135811691602001351661276d565b60408051938452602084019290925282820152519081900360600190f35b348015610d3557600080fd5b5061056760048036036020811015610d4c57600080fd5b50356001600160a01b03166127f8565b348015610d6857600080fd5b5061045f60048036036080811015610d7f57600080fd5b506001600160a01b038135169060208101359060408101359060600135612816565b348015610dad57600080fd5b5061045f60048036036020811015610dc457600080fd5b50356001600160a01b0316612964565b348015610de057600080fd5b5061056760048036036060811015610df757600080fd5b506001600160a01b03813581169160208101359091169060400135612a93565b348015610e2357600080fd5b5061045f60048036036080811015610e3a57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001351515612b33565b348015610e6e57600080fd5b5061056760048036036020811015610e8557600080fd5b50356001600160a01b0316612bbb565b348015610ea157600080fd5b5061045f60048036036020811015610eb857600080fd5b50356001600160a01b0316612bd9565b348015610ed457600080fd5b5061045f60048036036020811015610eeb57600080fd5b50356001600160a01b0316612d0c565b348015610f0757600080fd5b5061045f60048036036080811015610f1e57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001351515612de8565b348015610f5257600080fd5b5061056760048036036020811015610f6957600080fd5b50356001600160a01b0316612e70565b348015610f8557600080fd5b5061056760048036036020811015610f9c57600080fd5b50356001600160a01b0316612e8b565b348015610fb857600080fd5b5061056760048036036020811015610fcf57600080fd5b50356001600160a01b0316612ef5565b348015610feb57600080fd5b5061045f6004803603602081101561100257600080fd5b50356001600160a01b0316612f2e565b34801561101e57600080fd5b506105676004803603602081101561103557600080fd5b50356001600160a01b0316612fed565b34801561105157600080fd5b5061072361300b565b34801561106657600080fd5b506105676004803603602081101561107d57600080fd5b50356001600160a01b031661301a565b61045f600480360360808110156110a357600080fd5b506001600160a01b03813581169160208101358216916040820135916060013516613038565b3480156110d557600080fd5b5061045f600480360360208110156110ec57600080fd5b50356001600160a01b03166131ea565b34801561110857600080fd5b506105676004803603602081101561111f57600080fd5b50356001600160a01b03166133ef565b34801561113b57600080fd5b50610723613410565b34801561115057600080fd5b5061045f6004803603604081101561116757600080fd5b506001600160a01b03813516906020013561341f565b34801561118957600080fd5b5061045f600480360360c08110156111a057600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a0013515156134f3565b3480156111e057600080fd5b5061045f600480360360208110156111f757600080fd5b50356001600160a01b0316613562565b34801561121357600080fd5b5061096a6004803603604081101561122a57600080fd5b506001600160a01b0381358116916020013516613644565b34801561124e57600080fd5b506104946004803603606081101561126557600080fd5b506001600160a01b038135811691602081013590911690604001356136f1565b34801561129157600080fd5b50610567600480360360208110156112a857600080fd5b50356001600160a01b0316613787565b3480156112c457600080fd5b50610567600480360360208110156112db57600080fd5b50356001600160a01b031661382b565b3480156112f757600080fd5b5061045f6004803603602081101561130e57600080fd5b50356001600160a01b031661384c565b34801561132a57600080fd5b5061045f6004803603604081101561134157600080fd5b506001600160a01b0381351690602001351515613967565b34801561136557600080fd5b5061045f6004803603602081101561137c57600080fd5b50356001600160a01b0316613a9e565b34801561139857600080fd5b50610567600480360360208110156113af57600080fd5b50356001600160a01b0316613b7a565b3480156113cb57600080fd5b50611418600480360360c08110156113e257600080fd5b5080356001600160a01b039081169160208101359091169060408101359060608101359060808101359060a0013560ff16613b98565b6040518083600281111561142857fe5b60ff1681526020018281526020019250505060405180910390f35b34801561144f57600080fd5b506105676004803603604081101561146657600080fd5b506001600160a01b0381358116916020013516613c2a565b34801561148a57600080fd5b5061045f600480360360608110156114a157600080fd5b506001600160a01b038135811691602081013590911690604001351515613c59565b3480156114cf57600080fd5b5061045f600480360360608110156114e657600080fd5b506001600160a01b03813581169160208101359091169060400135613ceb565b34801561151257600080fd5b506105676004803603604081101561152957600080fd5b506001600160a01b0381358116916020013516613e12565b803b15155b919050565b6001600160a01b03166000908152603660205260409020600d0154600160e01b900460ff1690565b606060388054806020026020016040519081016040528092919081815260200182805480156115cb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116115ad575b5050505050905090565b6034546001600160a01b0316331461161e5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b6116288482613e41565b6001600160a01b038416600090815260366020526040902061164990613f7e565b60006116646116578661382b565b859063ffffffff61401516565b6001600160a01b038616600090815260366020526040902090915061169090828563ffffffff61406f16565b61169c858460006140cd565b5050505050565b600881565b6001600160a01b038083166000908152603660209081526040808320600c015481516370a0823160e01b8152868616600482015291519394169283926370a082319260248082019391829003018186803b15801561170557600080fd5b505afa158015611719573d6000803e3d6000fd5b505050506040513d602081101561172f57600080fd5b50519150505b92915050565b6001600160a01b03166000908152603660205260409020600d0154600160d01b900460ff1690565b6001600160a01b0380821660009081526037602090815260408083209386168352929052908120805461179a576000915050611735565b60008160030154116117ad5760026117b0565b60015b949350505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b1580156117fc57600080fd5b505afa158015611810573d6000803e3d6000fd5b505050506040513d602081101561182657600080fd5b50516001600160a01b03161461186d5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b611879826000806140cd565b6001600160a01b038216600090815260366020526040902061189a90613f7e565b6001600160a01b038281166000908152603660205260408120600d0180546001600160a01b031916928416929092179091556118d8908390806140cd565b5050565b6034546001600160a01b031633146119255760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b61192d614266565b6001600160a01b0316836001600160a01b0316146119a25734156119825760405162461bcd60e51b81526004018080602001828103825260328152602001806155626032913960400191505060405180910390fd5b61199d6001600160a01b03841683308463ffffffff61427e16565b611aa2565b803410156119e15760405162461bcd60e51b81526004018080602001828103825260358152602001806154ba6035913960400191505060405180910390fd5b80341115611aa25760006119fb348363ffffffff6142d816565b6040519091506000906001600160a01b0385169061c35090849084818181858888f193505050503d8060008114611a4e576040519150601f19603f3d011682016040523d82523d6000602084013e611a53565b606091505b505090508061169c576040805162461bcd60e51b8152602060048201526016602482015275151c985b9cd9995c881bd9881155120819985a5b195960521b604482015290519081900360640190fd5b505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015611aeb57600080fd5b505afa158015611aff573d6000803e3d6000fd5b505050506040513d6020811015611b1557600080fd5b50516001600160a01b031614611b5c5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03909116600090815260366020526040902060090155565b6001600160a01b039081166000908152603660205260409020600c01541690565b60345460009081906001600160a01b03163314611bea5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b600080611bf7898961276d565b9250509150611c0a898984848b8a614335565b611c18898989848a8a614364565b611c24896000896140cd565b611c2e8989614489565b999098509650505050505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015611c8057600080fd5b505afa158015611c94573d6000803e3d6000fd5b505050506040513d6020811015611caa57600080fd5b50516001600160a01b031614611cf15760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60e01b19169055565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015611d5c57600080fd5b505afa158015611d70573d6000803e3d6000fd5b505050506040513d6020811015611d8657600080fd5b50516001600160a01b031614611dcd5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b0380851660009081526036602052604080822081516304dda73560e21b815260048101919091528684166024820152604481018690529284166064840152517357ff2cbf0d1dfd79b497795b2edd3b56f1a30397926313769cd4926084808301939192829003018186803b158015611e4b57600080fd5b505af4158015611e5f573d6000803e3d6000fd5b50505050611e6c8461451b565b50505050565b6001600160a01b031660009081526036602052604090206006015490565b6001600160a01b03166000908152603660205260409020600d0154600160e81b900460ff1690565b6001600160a01b03166000908152603660205260409020600d0154600160a01b900464ffffffffff1690565b60388181548110611ef157fe5b6000918252602090912001546001600160a01b0316905081565b6001600160a01b03166000908152603660205260409020600d0154600160c81b900460ff1690565b6001600160a01b03166000908152603660205260409020600b81015460088201546009830154600d909301549193909291600160d01b900460ff1690565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015611fb557600080fd5b505afa158015611fc9573d6000803e3d6000fd5b505050506040513d6020811015611fdf57600080fd5b50516001600160a01b0316146120265760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b61202e6145bf565b565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561207457600080fd5b505afa158015612088573d6000803e3d6000fd5b505050506040513d602081101561209e57600080fd5b50516001600160a01b0316146120e55760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b039091166000908152603660205260409020600b0155565b6001600160a01b0390811660009081526037602090815260408083209490931682529290925290206004015464ffffffffff1690565b6034546001600160a01b031633146121835760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b61218f8988888561465a565b61219888614713565b6121a58988888786614737565b6121b1898760006140cd565b806121d1576121d18860006121cc888763ffffffff61401516565b6140cd565b505050505050505050565b6001600160a01b039081166000908152603660205260409020600d01541690565b6001600160a01b0380821660009081526037602090815260408083209386168352929052206003015492915050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561227057600080fd5b505afa158015612284573d6000803e3d6000fd5b505050506040513d602081101561229a57600080fd5b50516001600160a01b0316146122e15760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b039091166000908152603660205260409020600a0155565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561234457600080fd5b505afa158015612358573d6000803e3d6000fd5b505050506040513d602081101561236e57600080fd5b50516001600160a01b0316146123b55760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60e81b1916600160e81b179055565b6001600160a01b031660009081526036602052604090206002015490565b6001600160a01b0380821660009081526036602090815260408083206035548251631b0c55dd60e11b815292519495919486949190921692633618abba9260048083019392829003018186803b15801561245957600080fd5b505afa15801561246d573d6000803e3d6000fd5b505050506040513d602081101561248357600080fd5b5051600583015490915061251d57806001600160a01b031663bb85c0bb856040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156124e757600080fd5b505afa1580156124fb573d6000803e3d6000fd5b505050506040513d602081101561251157600080fd5b50519250611546915050565b506005015492915050565b6034546001600160a01b031633146125715760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b8034156125af5760405162461bcd60e51b81526004018080602001828103825260368152602001806154346036913960400191505060405180910390fd5b6125b7614266565b6001600160a01b0316846001600160a01b0316146125ee576125e96001600160a01b038516828563ffffffff6147e916565b611e6c565b6040516000906001600160a01b0383169061c35090869084818181858888f193505050503d8060008114611a4e576040519150601f19603f3d011682016040523d82523d6000602084013e611a53565b6001600160a01b038116600090815260366020526040812060048101546126e45780600d0160009054906101000a90046001600160a01b03166001600160a01b03166334762ca56040518163ffffffff1660e01b815260040160206040518083038186803b1580156126af57600080fd5b505afa1580156126c3573d6000803e3d6000fd5b505050506040513d60208110156126d957600080fd5b505191506115469050565b6004015492915050565b6001600160a01b031660009081526036602052604090206003015490565b6001600160a01b03908116600090815260376020908152604080832094909316825292909252902060040154600160281b900460ff1690565b6001600160a01b03166000908152603660205260409020600d0154600160d81b900460ff1690565b6001600160a01b03808216600090815260376020908152604080832093861683529290529081208054829182916127ae5750600092508291508190506127f1565b80546001600160a01b03871660009081526036602052604081206127d390849061483b565b905081816127e7818363ffffffff6142d816565b9550955095505050505b9250925092565b6001600160a01b03166000908152603660205260409020600b015490565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561285a57600080fd5b505afa15801561286e573d6000803e3d6000fd5b505050506040513d602081101561288457600080fd5b50516001600160a01b0316146128cb5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b038416600090815260366020526040808220815163126ee27360e11b8152600481019190915260248101869052604481018590526064810184905290517357ff2cbf0d1dfd79b497795b2edd3b56f1a30397926324ddc4e69260848082019391829003018186803b15801561294657600080fd5b505af415801561295a573d6000803e3d6000fd5b5050505050505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b1580156129a857600080fd5b505afa1580156129bc573d6000803e3d6000fd5b505050506040513d60208110156129d257600080fd5b50516001600160a01b031614612a195760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03811660009081526036602052604080822081516372efab5360e11b8152600481019190915290517357ff2cbf0d1dfd79b497795b2edd3b56f1a303979263e5df56a69260248082019391829003018186803b158015612a7f57600080fd5b505af415801561169c573d6000803e3d6000fd5b6034546000906001600160a01b03163314612adf5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b612aea84848461492d565b612af584848461497d565b612b01846000806140cd565b506001600160a01b038083166000908152603760209081526040808320938716835292905220600301545b9392505050565b6034546001600160a01b03163314612b7c5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b6001600160a01b0384166000908152603660205260409020612b9d90613f7e565b612ba9846000846140cd565b8015611e6c57611e6c84846000613c59565b6001600160a01b031660009081526036602052604090206007015490565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015612c1d57600080fd5b505afa158015612c31573d6000803e3d6000fd5b505050506040513d6020811015612c4757600080fd5b50516001600160a01b031614612c8e5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b0381166000908152603660205260409020805415801590612cba575060008160070154115b612cf55760405162461bcd60e51b815260040180806020018281038252602481526020018061565a6024913960400191505060405180910390fd5b600d01805460ff60e01b1916600160e01b17905550565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015612d5057600080fd5b505afa158015612d64573d6000803e3d6000fd5b505050506040513d6020811015612d7a57600080fd5b50516001600160a01b031614612dc15760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60d81b19169055565b6034546001600160a01b03163314612e315760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b6001600160a01b0384166000908152603660205260409020612e5290613f7e565b612e5e848360006140cd565b8015611e6c57611e6c84846001613c59565b6001600160a01b031660009081526036602052604090205490565b6001600160a01b038116600090815260366020526040812081612ead826149e6565b905080612ebf57600092505050611546565b6000612eca85613787565b9050612eec612edf828463ffffffff61401516565b839063ffffffff614a0316565b95945050505050565b6001600160a01b0381166000908152603660205260408120612b2c612f19826149e6565b612f2285613787565b9063ffffffff61401516565b6000612f38614a3f565b60015490915060ff1680612f4f5750612f4f614a44565b80612f5b575060005481115b612f965760405162461bcd60e51b815260040180806020018281038252602e8152602001806156c3602e913960400191505060405180910390fd5b60015460ff16158015612fb5576001805460ff19168117905560008290555b603580546001600160a01b0319166001600160a01b038516179055612fd86145bf565b8015611aa2576001805460ff19169055505050565b6001600160a01b031660009081526036602052604090206001015490565b6035546001600160a01b031681565b6001600160a01b03166000908152603660205260409020600a015490565b6034546001600160a01b031633146130815760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b8061308a614266565b6001600160a01b0316856001600160a01b0316146130ff5734156130df5760405162461bcd60e51b815260040180806020018281038252605f815260200180615594605f913960600191505060405180910390fd5b6130fa6001600160a01b03861685838663ffffffff61427e16565b61169c565b8234101561313e5760405162461bcd60e51b81526004018080602001828103825260358152602001806154ba6035913960400191505060405180910390fd5b6040516000906001600160a01b0383169061c35090869084818181858888f193505050503d806000811461318e576040519150601f19603f3d011682016040523d82523d6000602084013e613193565b606091505b50509050806131e2576040805162461bcd60e51b8152602060048201526016602482015275151c985b9cd9995c881bd9881155120819985a5b195960521b604482015290519081900360640190fd5b505050505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561322e57600080fd5b505afa158015613242573d6000803e3d6000fd5b505050506040513d602081101561325857600080fd5b50516001600160a01b03161461329f5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b603880546000919060001981019081106132b557fe5b6000918252602090912001546001600160a01b0390811691508216811461330d5760405162461bcd60e51b815260040180806020018281038252603d815260200180615525603d913960400191505060405180910390fd5b6133168161382b565b156133525760405162461bcd60e51b81526004018080602001828103825260308152602001806155f36030913960400191505060405180910390fd5b6001600160a01b0381166000908152603660205260408120600d81018054600c830180546001600160a01b0319169055600b8301849055838355600783018490556008830184905560098301849055600a90920192909255600168ff00ffff000000000160a01b031916905560388054806133c957fe5b600082815260209020810160001990810180546001600160a01b03191690550190555050565b6001600160a01b0381166000908152603660205260408120612b2c81614a4a565b6034546001600160a01b031681565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561346357600080fd5b505afa158015613477573d6000803e3d6000fd5b505050506040513d602081101561348d57600080fd5b50516001600160a01b0316146134d45760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03909116600090815260366020526040902060080155565b6034546001600160a01b0316331461353c5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b61354886868685614a78565b613556868686868686614adf565b6131e2868560006140cd565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b1580156135a657600080fd5b505afa1580156135ba573d6000803e3d6000fd5b505050506040513d60208110156135d057600080fd5b50516001600160a01b0316146136175760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60d81b1916600160d81b179055565b6001600160a01b03808316600081815260366020908152604080832094861683526037825280832093835292905290812090918291829182918261368889896116a8565b82549091506136b5576004909101549095506000945084935060ff600160281b9091041691506136e89050565b806136c6838563ffffffff61483b16565b6002840154600490940154919850965091945050600160281b900460ff169150505b92959194509250565b6001600160a01b038381166000818152603660209081526040808320948716835260378252808320938352929052908120600d830154919291600160d81b900460ff1661374357600092505050612b2c565b6004810154600160281b900460ff16158061376a5750600d820154600160d01b900460ff16155b8061377d575061377a86866116a8565b84115b9695505050505050565b600080613792614266565b6001600160a01b0316836001600160a01b031614156137b2575047611735565b604080516370a0823160e01b815230600482015290516001600160a01b038516916370a08231916024808301926020929190829003018186803b1580156137f857600080fd5b505afa15801561380c573d6000803e3d6000fd5b505050506040513d602081101561382257600080fd5b50519392505050565b6001600160a01b0381166000908152603660205260408120611735906149e6565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561389057600080fd5b505afa1580156138a4573d6000803e3d6000fd5b505050506040513d60208110156138ba57600080fd5b50516001600160a01b0316146139015760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b038116600090815260366020526040808220815163041e0b2d60e51b8152600481019190915290517357ff2cbf0d1dfd79b497795b2edd3b56f1a30397926383c165a09260248082019391829003018186803b158015612a7f57600080fd5b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b1580156139ab57600080fd5b505afa1580156139bf573d6000803e3d6000fd5b505050506040513d60208110156139d557600080fd5b50516001600160a01b031614613a1c5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b0382166000908152603660205260408082208151637b1dd5df60e11b81526004810191909152831515602482015290517357ff2cbf0d1dfd79b497795b2edd3b56f1a303979263f63babbe9260448082019391829003018186803b158015613a8a57600080fd5b505af41580156131e2573d6000803e3d6000fd5b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015613ae257600080fd5b505afa158015613af6573d6000803e3d6000fd5b505050506040513d6020811015613b0c57600080fd5b50516001600160a01b031614613b535760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60e81b19169055565b6001600160a01b031660009081526036602052604090206009015490565b60345460009081906001600160a01b03163314613be65760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b613bf38888888887614b5c565b6000613c0189898787614c5b565b9050613c0f896000806140cd565b80613c1a8a8a614489565b9250925050965096945050505050565b6001600160a01b0380821660009081526037602090815260408083209386168352929052206001015492915050565b6034546001600160a01b03163314613ca25760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b6001600160a01b0391821660009081526037602090815260408083209590941682529390935291206004018054911515600160281b0265ff000000000019909216919091179055565b6034546001600160a01b03163314613d345760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b613d3c614266565b6001600160a01b0316836001600160a01b031614613d6e5761199d6001600160a01b038416838363ffffffff6147e916565b6040516000906001600160a01b0384169061c35090849084818181858888f193505050503d8060008114613dbe576040519150601f19603f3d011682016040523d82523d6000602084013e613dc3565b606091505b5050905080611e6c576040805162461bcd60e51b8152602060048201526016602482015275151c985b9cd9995c881bd9881155120819985a5b195960521b604482015290519081900360640190fd5b6001600160a01b0380821660009081526037602090815260408083209386168352929052206002015492915050565b60355460408051637744894b60e11b815290516000926001600160a01b03169163ee891296916004808301926020929190829003018186803b158015613e8657600080fd5b505afa158015613e9a573d6000803e3d6000fd5b505050506040513d6020811015613eb057600080fd5b50519050613ebc614266565b6001600160a01b0316836001600160a01b031614613eee5761199d6001600160a01b038416828463ffffffff6147e916565b6040516000906001600160a01b0383169084908381818185875af1925050503d8060008114613f39576040519150601f19603f3d011682016040523d82523d6000602084013e613f3e565b606091505b5050905080611e6c5760405162461bcd60e51b815260040180806020018281038252602481526020018061569f6024913960400191505060405180910390fd5b6000613f89826149e6565b905080156118d8576001820154600d830154600091613fb591600160a01b900464ffffffffff16614d59565b8354909150613fcb90829063ffffffff614da416565b83556004830154600d840154600091613ff191600160a01b900464ffffffffff16614ddc565b905061400a846007015482614da490919063ffffffff16565b600785015550505050565b600082820183811015612b2c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600061409261407d84614e2b565b61408684614e2b565b9063ffffffff614a0316565b905060006140ae6140a1614e41565b839063ffffffff61401516565b85549091506140c490829063ffffffff614da416565b90945550505050565b6001600160a01b038084166000908152603660205260408120600d810154909282918291166357e37af088614115886141098b612f2285613787565b9063ffffffff6142d816565b8760020154886003015489600601546040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b031681526020018581526020018481526020018381526020018281526020019550505050505060606040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d60608110156141b057600080fd5b508051602080830151604093840151600189018490556005890182905560048901819055600d8901805464ffffffffff4216600160a01b0264ffffffffff60a01b19909116179055885460078a0154865186815294850184905284870183905260608501919091526080840152935192965094509192506001600160a01b038916917f04e4f521f16fcfd987978b05504262c2a2db223844977aab000e5accedb2d725919081900360a00190a250505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611e6c908590614e51565b60008282111561432f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6001600160a01b038616600090815260366020526040902061435690613f7e565b6131e2868686868686615009565b6001600160a01b038087166000818152603660209081526040808320948a168352603782528083209383529290522060018360028111156143a157fe5b14156143bd576005820154600382015560006001820155614434565b60028360028111156143cb57fe5b14156143e7576000600382015560078201546001820155614434565b6040805162461bcd60e51b815260206004820152601860248201527f496e76616c696420626f72726f772072617465206d6f64650000000000000000604482015290519081900360640190fd5b805461444c908690612f22908963ffffffff61401516565b81556002810154614463908563ffffffff61401516565b6002820155600401805464ffffffffff19164264ffffffffff1617905550505050505050565b6000806144968484611763565b905060008160028111156144a657fe5b14156144b6576000915050611735565b60018160028111156144c457fe5b146144ea576001600160a01b0384166000908152603660205260409020600401546117b0565b50506001600160a01b0390811660009081526037602090815260408083209490931682529290925290206003015490565b6000805b60385481101561456857826001600160a01b03166038828154811061454057fe5b6000918252602090912001546001600160a01b0316141561456057600191505b60010161451f565b50806118d857603880546001810182556000919091527f38395c5dceade9603479b177b68959049485df8aa97b39f3533039af5f4561990180546001600160a01b0384166001600160a01b03199091161790555050565b603560009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561460d57600080fd5b505afa158015614621573d6000803e3d6000fd5b505050506040513d602081101561463757600080fd5b5051603480546001600160a01b0319166001600160a01b03909216919091179055565b6001600160a01b0380851660008181526036602090815260408083209488168352603782528083209383529290522061469282613f7e565b600061469e8787611763565b905060015b8160028111156146af57fe5b14156146ea5760038201546146cd908490869063ffffffff61516516565b60038201546146e5908490879063ffffffff6151dc16565b61470a565b6146fa838563ffffffff61528416565b61470a838663ffffffff6152a516565b50505050505050565b6001600160a01b038116600090815260366020526040902061473490613f7e565b50565b6001600160a01b03808516600090815260376020908152604080832093891683529281528282206036909152919020815461477e908690614109908663ffffffff61401516565b8255600261478c8888611763565b600281111561479757fe5b14156147a857600781015460018301555b83156147c95760028201546147c3908563ffffffff6142d816565b60028301555b50600401805464ffffffffff19164264ffffffffff161790555050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611aa2908490614e51565b815460009061484c57506000611735565b600061485b8460000154614e2b565b600385015490915060009081901561488f5760038601546004870154614888919064ffffffffff16614ddc565b90506148d1565b6148ce866001015461408687600701546148c289600401548a600d0160149054906101000a900464ffffffffff16614ddc565b9063ffffffff614da416565b90505b6148e96148e4848363ffffffff614da416565b6152fd565b865490925082141561492457600486015464ffffffffff16421461492457855461491a90600163ffffffff61401516565b9350505050611735565b50949350505050565b6001600160a01b0380841660008181526036602090815260408083209487168352603782528083209383529290522061496582613f7e565b600381015461169c908390859063ffffffff61516516565b6001600160a01b0380831660009081526037602090815260408083209387168352928152828220603690915291902081546149be908463ffffffff61401516565b8255600501546003820155600401805464ffffffffff19164264ffffffffff16179055505050565b60006117358260030154836002015461401590919063ffffffff16565b6000600282046117b083614a33614a26876b033b2e3c9fd0803ce8000000615316565b849063ffffffff61401516565b9063ffffffff61536f16565b600890565b303b1590565b600080612b2c83600001546148c2856001015486600d0160149054906101000a900464ffffffffff16614d59565b6001600160a01b03808516600081815260366020908152604080832094881683526037825280832093835292905290812090614ab48787611763565b6001600160a01b0388166000908152603660205260409020909150614ad890613f7e565b60016146a3565b6001600160a01b038087166000818152603660209081526040808320948a16835260378252808320938352929052208054614b26908790614109908763ffffffff61401516565b8155600782015460018201558215614b475760006003820181905560018201555b6002810154614463908663ffffffff6142d816565b6001600160a01b03808616600081815260366020908152604080832094891683526037825280832093835292905220614b9482613f7e565b6001836002811115614ba257fe5b1415614bd4576003810154614bbe83878363ffffffff6151dc16565b614bce838663ffffffff61528416565b5061470a565b6002836002811115614be257fe5b1415614c0e576005820154614bfd838763ffffffff6152a516565b614bce83868363ffffffff61516516565b6040805162461bcd60e51b815260206004820152601a60248201527f496e76616c69642072617465206d6f6465207265636569766564000000000000604482015290519081900360640190fd5b6001600160a01b03808416600090815260376020908152604080832093881683529281528282206036909152918120909190826002856002811115614c9c57fe5b1415614cbd5750600581015460038301556000600183810191909155614d21565b6001856002811115614ccb57fe5b1415614cea575060006003830155600781015460018301556002614d21565b60405162461bcd60e51b815260040180806020018281038252602381526020018061571b6023913960400191505060405180910390fd5b8254614d33908763ffffffff61401516565b83556004909201805464ffffffffff19164264ffffffffff161790555095945050505050565b600080614d734264ffffffffff851663ffffffff6142d816565b90506000614d8761407d6301e13380614e2b565b9050612eec614d94614e41565b612f22878463ffffffff614da416565b6000612b2c6b033b2e3c9fd0803ce8000000614a33614dc9868663ffffffff61531616565b6b019d971e4fe8401e7400000090614015565b600080614df64264ffffffffff851663ffffffff6142d816565b90506000614e0e856301e1338063ffffffff61536f16565b9050612eec82614e1f614a26614e41565b9063ffffffff6153d916565b600061173582633b9aca0063ffffffff61531616565b6b033b2e3c9fd0803ce800000090565b614e63826001600160a01b0316611541565b614eb4576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310614ef25780518252601f199092019160209182019101614ed3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614f54576040519150601f19603f3d011682016040523d82523d6000602084013e614f59565b606091505b509150915081614fb0576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115611e6c57808060200190516020811015614fcc57600080fd5b5051611e6c5760405162461bcd60e51b815260040180806020018281038252602a81526020018061573e602a913960400191505060405180910390fd5b60006150158787611763565b6001600160a01b0388166000908152603660205260409020909150600182600281111561503e57fe5b1415615087576001600160a01b038088166000908152603760209081526040808320938c168352929052206003810154615081908390899063ffffffff6151dc16565b506150ab565b600282600281111561509557fe5b14156150ab576150ab818763ffffffff6152a516565b60006150c185612f22898963ffffffff61401516565b905060018460028111156150d157fe5b14156150f45760058201546150ef908390839063ffffffff61516516565b6121d1565b600284600281111561510257fe5b1415615118576150ef828263ffffffff61528416565b6040805162461bcd60e51b815260206004820152601c60248201527f496e76616c6964206e657720626f72726f772072617465206d6f646500000000604482015290519081900360640190fd5b8161516f57611aa2565b6002830154615184818463ffffffff61401516565b60028501556000615198836148c286614e2b565b905060006151ad86600601546148c285614e2b565b90506151cf6151bf8760020154614e2b565b614086848463ffffffff61401516565b6006870155505050505050565b60028301548015806151ee5750808310155b1561520757506000600284018190556006840155611aa2565b600284015461521c908463ffffffff6142d816565b60028501556000615230836148c286614e2b565b9050600061524586600601546148c285614e2b565b9050818111615264575050600060028501819055600685015550611aa2565b6151cf6152748760020154614e2b565b614086838563ffffffff6142d816565b6003820154615299908263ffffffff61401516565b82600301819055505050565b80826003015410156152e85760405162461bcd60e51b815260040180806020018281038252605081526020018061546a6050913960600191505060405180910390fd5b6003820154615299908263ffffffff6142d816565b6000631dcd6500612b2c633b9aca00614a338386614015565b60008261532557506000611735565b8282028284828161533257fe5b0414612b2c5760405162461bcd60e51b815260040180806020018281038252602181526020018061567e6021913960400191505060405180910390fd5b60008082116153c5576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b60008284816153d057fe5b04949350505050565b6000600282066153f5576b033b2e3c9fd0803ce80000006153f7565b825b90506002820491505b8115611735576154108384614da4565b92506002820615615428576154258184614da4565b90505b60028204915061540056fe466565206c69717569646174696f6e20646f6573206e6f74207265717569726520616e79207472616e73666572206f662076616c756554686520616d6f756e742074686174206973206265696e6720737562747261637465642066726f6d20746865207661726961626c6520746f74616c20626f72726f777320697320696e636f727265637454686520616d6f756e7420616e64207468652076616c75652073656e7420746f206465706f73697420646f206e6f74206d617463684f6e6c7920636f6e7472616374732063616e2073656e6420657468657220746f20746865204c656e64696e6720706f6f6c20636f726552657365727665206265696e672072656d6f76656420697320646966666572656e74207468616e20746865207265736572766520726571756573746564557365722069732073656e64696e672045544820616c6f6e67207769746820746865204552433230207472616e736665722e557365722069732073656e64696e672045544820616c6f6e67207769746820746865204552433230207472616e736665722e20436865636b207468652076616c756520617474726962757465206f6620746865207472616e73616374696f6e43616e6e6f742072656d6f7665206120726573657276652077697468206c6971756964697479206465706f73697465645468652063616c6c6572206d7573742062652061206c656e64696e6720706f6f6c20636f6e666967757261746f7220636f6e74726163745265736572766520686173206e6f74206265656e20696e697469616c697a656420796574536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775472616e7366657220746f20746f6b656e206469737472696275746f72206661696c6564436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a65645468652063616c6c6572206d7573742062652061206c656e64696e6720706f6f6c20636f6e7472616374496e76616c696420696e7465726573742072617465206d6f64652072656365697665645361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a265627a7a723158203463a6d16b06fd2eaec8053909bb75658e7ac0932c4bf200cddb23757876cf4c64736f6c63430005110032
Deployed Bytecode
0x60806040526004361061041b5760003560e01c8063a2353fdc1161021e578063d15e005311610123578063e8ae2f5b116100ab578063f61483111161007a578063f6148311146113bf578063f6ea8d7614611443578063fa51854c1461147e578063fa93b2a5146114c3578063feab31ac146115065761041b565b8063e8ae2f5b146112eb578063eede87c11461131e578063ef1f937314611359578063f054ab461461138c5761041b565b8063dae4c4e7116100f2578063dae4c4e7146111d4578063e10076ad14611207578063e2174d8614611242578063e240301914611285578063e6d18190146112b85761041b565b8063d15e0053146110fc578063d3ae26b31461112f578063d466016f14611144578063da12d96f1461117d5761041b565b8063bd7fd79a116101a6578063c540148e11610175578063c540148e14611012578063c72c4d1014611045578063c76a6c9c1461105a578063c7d142371461108d578063d06e2ec1146110c95761041b565b8063bd7fd79a14610f46578063bfacad8414610f79578063c33cfd9014610fac578063c4d66de814610fdf5761041b565b8063afcdbea3116101ed578063afcdbea314610e17578063b701d09314610e62578063b75d6f3414610e95578063b8c0f74514610ec8578063bcd6ffa414610efb5761041b565b8063a2353fdc14610d29578063a5bc826c14610d5c578063a8dc0f4514610da1578063af825b0714610dd45761041b565b80635cf2e656116103245780637aca76eb116102ac578063906c0a411161027b578063906c0a4114610bfc57806398bd473714610c2f5780639e3c4f3b14610c625780639e67484814610c9d5780639fb8afcd14610cd05761041b565b80637aca76eb14610b2d5780637f90fec514610b6057806388079d8814610b935780638f385c2214610bc65761041b565b806366d103f3116102f357806366d103f3146109e057806368beb4d614610a1b5780636ae1441614610a865780636fffab0c14610ab957806370fb84f414610af45761041b565b80635cf2e656146109045780635fc526ff14610937578063646810831461099257806366bbd928146109a75761041b565b80633443a14b116103a757806345330a401161037657806345330a40146107de57806346bc0f28146108275780634a08accb1461085a5780634f1446091461088d5780634fe7a6e5146108da5761041b565b80633443a14b146106b757806334b3beee146106f057806337ac6fe41461073f5780633e72a454146107ab5761041b565b806318a4dbca116103ee57806318a4dbca1461057957806318f9bbae146105b45780631ca19f19146105e75780631d2118f91461064657806328fcf4d3146106815761041b565b806305075d6e146104615780630902f1ac146104a857806309ac29531461050d5780630c7de4e914610552575b61042433611541565b61045f5760405162461bcd60e51b81526004018080602001828103825260368152602001806154ef6036913960400191505060405180910390fd5b005b34801561046d57600080fd5b506104946004803603602081101561048457600080fd5b50356001600160a01b031661154b565b604080519115158252519081900360200190f35b3480156104b457600080fd5b506104bd611573565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104f95781810151838201526020016104e1565b505050509050019250505060405180910390f35b34801561051957600080fd5b5061045f6004803603608081101561053057600080fd5b506001600160a01b0381351690602081013590604081013590606001356115d5565b34801561055e57600080fd5b506105676116a3565b60408051918252519081900360200190f35b34801561058557600080fd5b506105676004803603604081101561059c57600080fd5b506001600160a01b03813581169160200135166116a8565b3480156105c057600080fd5b50610494600480360360208110156105d757600080fd5b50356001600160a01b031661173b565b3480156105f357600080fd5b506106226004803603604081101561060a57600080fd5b506001600160a01b0381358116916020013516611763565b6040518082600281111561063257fe5b60ff16815260200191505060405180910390f35b34801561065257600080fd5b5061045f6004803603604081101561066957600080fd5b506001600160a01b03813581169160200135166117b8565b61045f6004803603606081101561069757600080fd5b506001600160a01b038135811691602081013590911690604001356118dc565b3480156106c357600080fd5b5061045f600480360360408110156106da57600080fd5b506001600160a01b038135169060200135611aa7565b3480156106fc57600080fd5b506107236004803603602081101561071357600080fd5b50356001600160a01b0316611b7b565b604080516001600160a01b039092168252519081900360200190f35b34801561074b57600080fd5b50610792600480360360a081101561076257600080fd5b5080356001600160a01b03908116916020810135909116906040810135906060810135906080013560ff16611b9c565b6040805192835260208301919091528051918290030190f35b3480156107b757600080fd5b5061045f600480360360208110156107ce57600080fd5b50356001600160a01b0316611c3c565b3480156107ea57600080fd5b5061045f6004803603608081101561080157600080fd5b506001600160a01b03813581169160208101358216916040820135916060013516611d18565b34801561083357600080fd5b506105676004803603602081101561084a57600080fd5b50356001600160a01b0316611e72565b34801561086657600080fd5b506104946004803603602081101561087d57600080fd5b50356001600160a01b0316611e90565b34801561089957600080fd5b506108c0600480360360208110156108b057600080fd5b50356001600160a01b0316611eb8565b6040805164ffffffffff9092168252519081900360200190f35b3480156108e657600080fd5b50610723600480360360208110156108fd57600080fd5b5035611ee4565b34801561091057600080fd5b506104946004803603602081101561092757600080fd5b50356001600160a01b0316611f0b565b34801561094357600080fd5b5061096a6004803603602081101561095a57600080fd5b50356001600160a01b0316611f33565b6040805194855260208501939093528383019190915215156060830152519081900360800190f35b34801561099e57600080fd5b5061045f611f71565b3480156109b357600080fd5b5061045f600480360360408110156109ca57600080fd5b506001600160a01b038135169060200135612030565b3480156109ec57600080fd5b5061056760048036036040811015610a0357600080fd5b506001600160a01b0381358116916020013516612104565b348015610a2757600080fd5b5061045f6004803603610120811015610a3f57600080fd5b506001600160a01b03813581169160208101358216916040820135169060608101359060808101359060a08101359060c08101359060e0810135906101000135151561213a565b348015610a9257600080fd5b5061072360048036036020811015610aa957600080fd5b50356001600160a01b03166121dc565b348015610ac557600080fd5b5061056760048036036040811015610adc57600080fd5b506001600160a01b03813581169160200135166121fd565b348015610b0057600080fd5b5061045f60048036036040811015610b1757600080fd5b506001600160a01b03813516906020013561222c565b348015610b3957600080fd5b5061045f60048036036020811015610b5057600080fd5b50356001600160a01b0316612300565b348015610b6c57600080fd5b5061056760048036036020811015610b8357600080fd5b50356001600160a01b03166123e2565b348015610b9f57600080fd5b5061056760048036036020811015610bb657600080fd5b50356001600160a01b0316612400565b61045f60048036036060811015610bdc57600080fd5b506001600160a01b03813581169160208101359160409091013516612528565b348015610c0857600080fd5b5061056760048036036020811015610c1f57600080fd5b50356001600160a01b031661263e565b348015610c3b57600080fd5b5061056760048036036020811015610c5257600080fd5b50356001600160a01b03166126ee565b348015610c6e57600080fd5b5061049460048036036040811015610c8557600080fd5b506001600160a01b038135811691602001351661270c565b348015610ca957600080fd5b5061049460048036036020811015610cc057600080fd5b50356001600160a01b0316612745565b348015610cdc57600080fd5b50610d0b60048036036040811015610cf357600080fd5b506001600160a01b038135811691602001351661276d565b60408051938452602084019290925282820152519081900360600190f35b348015610d3557600080fd5b5061056760048036036020811015610d4c57600080fd5b50356001600160a01b03166127f8565b348015610d6857600080fd5b5061045f60048036036080811015610d7f57600080fd5b506001600160a01b038135169060208101359060408101359060600135612816565b348015610dad57600080fd5b5061045f60048036036020811015610dc457600080fd5b50356001600160a01b0316612964565b348015610de057600080fd5b5061056760048036036060811015610df757600080fd5b506001600160a01b03813581169160208101359091169060400135612a93565b348015610e2357600080fd5b5061045f60048036036080811015610e3a57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001351515612b33565b348015610e6e57600080fd5b5061056760048036036020811015610e8557600080fd5b50356001600160a01b0316612bbb565b348015610ea157600080fd5b5061045f60048036036020811015610eb857600080fd5b50356001600160a01b0316612bd9565b348015610ed457600080fd5b5061045f60048036036020811015610eeb57600080fd5b50356001600160a01b0316612d0c565b348015610f0757600080fd5b5061045f60048036036080811015610f1e57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001351515612de8565b348015610f5257600080fd5b5061056760048036036020811015610f6957600080fd5b50356001600160a01b0316612e70565b348015610f8557600080fd5b5061056760048036036020811015610f9c57600080fd5b50356001600160a01b0316612e8b565b348015610fb857600080fd5b5061056760048036036020811015610fcf57600080fd5b50356001600160a01b0316612ef5565b348015610feb57600080fd5b5061045f6004803603602081101561100257600080fd5b50356001600160a01b0316612f2e565b34801561101e57600080fd5b506105676004803603602081101561103557600080fd5b50356001600160a01b0316612fed565b34801561105157600080fd5b5061072361300b565b34801561106657600080fd5b506105676004803603602081101561107d57600080fd5b50356001600160a01b031661301a565b61045f600480360360808110156110a357600080fd5b506001600160a01b03813581169160208101358216916040820135916060013516613038565b3480156110d557600080fd5b5061045f600480360360208110156110ec57600080fd5b50356001600160a01b03166131ea565b34801561110857600080fd5b506105676004803603602081101561111f57600080fd5b50356001600160a01b03166133ef565b34801561113b57600080fd5b50610723613410565b34801561115057600080fd5b5061045f6004803603604081101561116757600080fd5b506001600160a01b03813516906020013561341f565b34801561118957600080fd5b5061045f600480360360c08110156111a057600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a0013515156134f3565b3480156111e057600080fd5b5061045f600480360360208110156111f757600080fd5b50356001600160a01b0316613562565b34801561121357600080fd5b5061096a6004803603604081101561122a57600080fd5b506001600160a01b0381358116916020013516613644565b34801561124e57600080fd5b506104946004803603606081101561126557600080fd5b506001600160a01b038135811691602081013590911690604001356136f1565b34801561129157600080fd5b50610567600480360360208110156112a857600080fd5b50356001600160a01b0316613787565b3480156112c457600080fd5b50610567600480360360208110156112db57600080fd5b50356001600160a01b031661382b565b3480156112f757600080fd5b5061045f6004803603602081101561130e57600080fd5b50356001600160a01b031661384c565b34801561132a57600080fd5b5061045f6004803603604081101561134157600080fd5b506001600160a01b0381351690602001351515613967565b34801561136557600080fd5b5061045f6004803603602081101561137c57600080fd5b50356001600160a01b0316613a9e565b34801561139857600080fd5b50610567600480360360208110156113af57600080fd5b50356001600160a01b0316613b7a565b3480156113cb57600080fd5b50611418600480360360c08110156113e257600080fd5b5080356001600160a01b039081169160208101359091169060408101359060608101359060808101359060a0013560ff16613b98565b6040518083600281111561142857fe5b60ff1681526020018281526020019250505060405180910390f35b34801561144f57600080fd5b506105676004803603604081101561146657600080fd5b506001600160a01b0381358116916020013516613c2a565b34801561148a57600080fd5b5061045f600480360360608110156114a157600080fd5b506001600160a01b038135811691602081013590911690604001351515613c59565b3480156114cf57600080fd5b5061045f600480360360608110156114e657600080fd5b506001600160a01b03813581169160208101359091169060400135613ceb565b34801561151257600080fd5b506105676004803603604081101561152957600080fd5b506001600160a01b0381358116916020013516613e12565b803b15155b919050565b6001600160a01b03166000908152603660205260409020600d0154600160e01b900460ff1690565b606060388054806020026020016040519081016040528092919081815260200182805480156115cb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116115ad575b5050505050905090565b6034546001600160a01b0316331461161e5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b6116288482613e41565b6001600160a01b038416600090815260366020526040902061164990613f7e565b60006116646116578661382b565b859063ffffffff61401516565b6001600160a01b038616600090815260366020526040902090915061169090828563ffffffff61406f16565b61169c858460006140cd565b5050505050565b600881565b6001600160a01b038083166000908152603660209081526040808320600c015481516370a0823160e01b8152868616600482015291519394169283926370a082319260248082019391829003018186803b15801561170557600080fd5b505afa158015611719573d6000803e3d6000fd5b505050506040513d602081101561172f57600080fd5b50519150505b92915050565b6001600160a01b03166000908152603660205260409020600d0154600160d01b900460ff1690565b6001600160a01b0380821660009081526037602090815260408083209386168352929052908120805461179a576000915050611735565b60008160030154116117ad5760026117b0565b60015b949350505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b1580156117fc57600080fd5b505afa158015611810573d6000803e3d6000fd5b505050506040513d602081101561182657600080fd5b50516001600160a01b03161461186d5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b611879826000806140cd565b6001600160a01b038216600090815260366020526040902061189a90613f7e565b6001600160a01b038281166000908152603660205260408120600d0180546001600160a01b031916928416929092179091556118d8908390806140cd565b5050565b6034546001600160a01b031633146119255760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b61192d614266565b6001600160a01b0316836001600160a01b0316146119a25734156119825760405162461bcd60e51b81526004018080602001828103825260328152602001806155626032913960400191505060405180910390fd5b61199d6001600160a01b03841683308463ffffffff61427e16565b611aa2565b803410156119e15760405162461bcd60e51b81526004018080602001828103825260358152602001806154ba6035913960400191505060405180910390fd5b80341115611aa25760006119fb348363ffffffff6142d816565b6040519091506000906001600160a01b0385169061c35090849084818181858888f193505050503d8060008114611a4e576040519150601f19603f3d011682016040523d82523d6000602084013e611a53565b606091505b505090508061169c576040805162461bcd60e51b8152602060048201526016602482015275151c985b9cd9995c881bd9881155120819985a5b195960521b604482015290519081900360640190fd5b505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015611aeb57600080fd5b505afa158015611aff573d6000803e3d6000fd5b505050506040513d6020811015611b1557600080fd5b50516001600160a01b031614611b5c5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03909116600090815260366020526040902060090155565b6001600160a01b039081166000908152603660205260409020600c01541690565b60345460009081906001600160a01b03163314611bea5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b600080611bf7898961276d565b9250509150611c0a898984848b8a614335565b611c18898989848a8a614364565b611c24896000896140cd565b611c2e8989614489565b999098509650505050505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015611c8057600080fd5b505afa158015611c94573d6000803e3d6000fd5b505050506040513d6020811015611caa57600080fd5b50516001600160a01b031614611cf15760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60e01b19169055565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015611d5c57600080fd5b505afa158015611d70573d6000803e3d6000fd5b505050506040513d6020811015611d8657600080fd5b50516001600160a01b031614611dcd5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b0380851660009081526036602052604080822081516304dda73560e21b815260048101919091528684166024820152604481018690529284166064840152517357ff2cbf0d1dfd79b497795b2edd3b56f1a30397926313769cd4926084808301939192829003018186803b158015611e4b57600080fd5b505af4158015611e5f573d6000803e3d6000fd5b50505050611e6c8461451b565b50505050565b6001600160a01b031660009081526036602052604090206006015490565b6001600160a01b03166000908152603660205260409020600d0154600160e81b900460ff1690565b6001600160a01b03166000908152603660205260409020600d0154600160a01b900464ffffffffff1690565b60388181548110611ef157fe5b6000918252602090912001546001600160a01b0316905081565b6001600160a01b03166000908152603660205260409020600d0154600160c81b900460ff1690565b6001600160a01b03166000908152603660205260409020600b81015460088201546009830154600d909301549193909291600160d01b900460ff1690565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015611fb557600080fd5b505afa158015611fc9573d6000803e3d6000fd5b505050506040513d6020811015611fdf57600080fd5b50516001600160a01b0316146120265760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b61202e6145bf565b565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561207457600080fd5b505afa158015612088573d6000803e3d6000fd5b505050506040513d602081101561209e57600080fd5b50516001600160a01b0316146120e55760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b039091166000908152603660205260409020600b0155565b6001600160a01b0390811660009081526037602090815260408083209490931682529290925290206004015464ffffffffff1690565b6034546001600160a01b031633146121835760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b61218f8988888561465a565b61219888614713565b6121a58988888786614737565b6121b1898760006140cd565b806121d1576121d18860006121cc888763ffffffff61401516565b6140cd565b505050505050505050565b6001600160a01b039081166000908152603660205260409020600d01541690565b6001600160a01b0380821660009081526037602090815260408083209386168352929052206003015492915050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561227057600080fd5b505afa158015612284573d6000803e3d6000fd5b505050506040513d602081101561229a57600080fd5b50516001600160a01b0316146122e15760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b039091166000908152603660205260409020600a0155565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561234457600080fd5b505afa158015612358573d6000803e3d6000fd5b505050506040513d602081101561236e57600080fd5b50516001600160a01b0316146123b55760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60e81b1916600160e81b179055565b6001600160a01b031660009081526036602052604090206002015490565b6001600160a01b0380821660009081526036602090815260408083206035548251631b0c55dd60e11b815292519495919486949190921692633618abba9260048083019392829003018186803b15801561245957600080fd5b505afa15801561246d573d6000803e3d6000fd5b505050506040513d602081101561248357600080fd5b5051600583015490915061251d57806001600160a01b031663bb85c0bb856040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156124e757600080fd5b505afa1580156124fb573d6000803e3d6000fd5b505050506040513d602081101561251157600080fd5b50519250611546915050565b506005015492915050565b6034546001600160a01b031633146125715760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b8034156125af5760405162461bcd60e51b81526004018080602001828103825260368152602001806154346036913960400191505060405180910390fd5b6125b7614266565b6001600160a01b0316846001600160a01b0316146125ee576125e96001600160a01b038516828563ffffffff6147e916565b611e6c565b6040516000906001600160a01b0383169061c35090869084818181858888f193505050503d8060008114611a4e576040519150601f19603f3d011682016040523d82523d6000602084013e611a53565b6001600160a01b038116600090815260366020526040812060048101546126e45780600d0160009054906101000a90046001600160a01b03166001600160a01b03166334762ca56040518163ffffffff1660e01b815260040160206040518083038186803b1580156126af57600080fd5b505afa1580156126c3573d6000803e3d6000fd5b505050506040513d60208110156126d957600080fd5b505191506115469050565b6004015492915050565b6001600160a01b031660009081526036602052604090206003015490565b6001600160a01b03908116600090815260376020908152604080832094909316825292909252902060040154600160281b900460ff1690565b6001600160a01b03166000908152603660205260409020600d0154600160d81b900460ff1690565b6001600160a01b03808216600090815260376020908152604080832093861683529290529081208054829182916127ae5750600092508291508190506127f1565b80546001600160a01b03871660009081526036602052604081206127d390849061483b565b905081816127e7818363ffffffff6142d816565b9550955095505050505b9250925092565b6001600160a01b03166000908152603660205260409020600b015490565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561285a57600080fd5b505afa15801561286e573d6000803e3d6000fd5b505050506040513d602081101561288457600080fd5b50516001600160a01b0316146128cb5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b038416600090815260366020526040808220815163126ee27360e11b8152600481019190915260248101869052604481018590526064810184905290517357ff2cbf0d1dfd79b497795b2edd3b56f1a30397926324ddc4e69260848082019391829003018186803b15801561294657600080fd5b505af415801561295a573d6000803e3d6000fd5b5050505050505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b1580156129a857600080fd5b505afa1580156129bc573d6000803e3d6000fd5b505050506040513d60208110156129d257600080fd5b50516001600160a01b031614612a195760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03811660009081526036602052604080822081516372efab5360e11b8152600481019190915290517357ff2cbf0d1dfd79b497795b2edd3b56f1a303979263e5df56a69260248082019391829003018186803b158015612a7f57600080fd5b505af415801561169c573d6000803e3d6000fd5b6034546000906001600160a01b03163314612adf5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b612aea84848461492d565b612af584848461497d565b612b01846000806140cd565b506001600160a01b038083166000908152603760209081526040808320938716835292905220600301545b9392505050565b6034546001600160a01b03163314612b7c5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b6001600160a01b0384166000908152603660205260409020612b9d90613f7e565b612ba9846000846140cd565b8015611e6c57611e6c84846000613c59565b6001600160a01b031660009081526036602052604090206007015490565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015612c1d57600080fd5b505afa158015612c31573d6000803e3d6000fd5b505050506040513d6020811015612c4757600080fd5b50516001600160a01b031614612c8e5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b0381166000908152603660205260409020805415801590612cba575060008160070154115b612cf55760405162461bcd60e51b815260040180806020018281038252602481526020018061565a6024913960400191505060405180910390fd5b600d01805460ff60e01b1916600160e01b17905550565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015612d5057600080fd5b505afa158015612d64573d6000803e3d6000fd5b505050506040513d6020811015612d7a57600080fd5b50516001600160a01b031614612dc15760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60d81b19169055565b6034546001600160a01b03163314612e315760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b6001600160a01b0384166000908152603660205260409020612e5290613f7e565b612e5e848360006140cd565b8015611e6c57611e6c84846001613c59565b6001600160a01b031660009081526036602052604090205490565b6001600160a01b038116600090815260366020526040812081612ead826149e6565b905080612ebf57600092505050611546565b6000612eca85613787565b9050612eec612edf828463ffffffff61401516565b839063ffffffff614a0316565b95945050505050565b6001600160a01b0381166000908152603660205260408120612b2c612f19826149e6565b612f2285613787565b9063ffffffff61401516565b6000612f38614a3f565b60015490915060ff1680612f4f5750612f4f614a44565b80612f5b575060005481115b612f965760405162461bcd60e51b815260040180806020018281038252602e8152602001806156c3602e913960400191505060405180910390fd5b60015460ff16158015612fb5576001805460ff19168117905560008290555b603580546001600160a01b0319166001600160a01b038516179055612fd86145bf565b8015611aa2576001805460ff19169055505050565b6001600160a01b031660009081526036602052604090206001015490565b6035546001600160a01b031681565b6001600160a01b03166000908152603660205260409020600a015490565b6034546001600160a01b031633146130815760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b8061308a614266565b6001600160a01b0316856001600160a01b0316146130ff5734156130df5760405162461bcd60e51b815260040180806020018281038252605f815260200180615594605f913960600191505060405180910390fd5b6130fa6001600160a01b03861685838663ffffffff61427e16565b61169c565b8234101561313e5760405162461bcd60e51b81526004018080602001828103825260358152602001806154ba6035913960400191505060405180910390fd5b6040516000906001600160a01b0383169061c35090869084818181858888f193505050503d806000811461318e576040519150601f19603f3d011682016040523d82523d6000602084013e613193565b606091505b50509050806131e2576040805162461bcd60e51b8152602060048201526016602482015275151c985b9cd9995c881bd9881155120819985a5b195960521b604482015290519081900360640190fd5b505050505050565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561322e57600080fd5b505afa158015613242573d6000803e3d6000fd5b505050506040513d602081101561325857600080fd5b50516001600160a01b03161461329f5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b603880546000919060001981019081106132b557fe5b6000918252602090912001546001600160a01b0390811691508216811461330d5760405162461bcd60e51b815260040180806020018281038252603d815260200180615525603d913960400191505060405180910390fd5b6133168161382b565b156133525760405162461bcd60e51b81526004018080602001828103825260308152602001806155f36030913960400191505060405180910390fd5b6001600160a01b0381166000908152603660205260408120600d81018054600c830180546001600160a01b0319169055600b8301849055838355600783018490556008830184905560098301849055600a90920192909255600168ff00ffff000000000160a01b031916905560388054806133c957fe5b600082815260209020810160001990810180546001600160a01b03191690550190555050565b6001600160a01b0381166000908152603660205260408120612b2c81614a4a565b6034546001600160a01b031681565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561346357600080fd5b505afa158015613477573d6000803e3d6000fd5b505050506040513d602081101561348d57600080fd5b50516001600160a01b0316146134d45760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03909116600090815260366020526040902060080155565b6034546001600160a01b0316331461353c5760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b61354886868685614a78565b613556868686868686614adf565b6131e2868560006140cd565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b1580156135a657600080fd5b505afa1580156135ba573d6000803e3d6000fd5b505050506040513d60208110156135d057600080fd5b50516001600160a01b0316146136175760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60d81b1916600160d81b179055565b6001600160a01b03808316600081815260366020908152604080832094861683526037825280832093835292905290812090918291829182918261368889896116a8565b82549091506136b5576004909101549095506000945084935060ff600160281b9091041691506136e89050565b806136c6838563ffffffff61483b16565b6002840154600490940154919850965091945050600160281b900460ff169150505b92959194509250565b6001600160a01b038381166000818152603660209081526040808320948716835260378252808320938352929052908120600d830154919291600160d81b900460ff1661374357600092505050612b2c565b6004810154600160281b900460ff16158061376a5750600d820154600160d01b900460ff16155b8061377d575061377a86866116a8565b84115b9695505050505050565b600080613792614266565b6001600160a01b0316836001600160a01b031614156137b2575047611735565b604080516370a0823160e01b815230600482015290516001600160a01b038516916370a08231916024808301926020929190829003018186803b1580156137f857600080fd5b505afa15801561380c573d6000803e3d6000fd5b505050506040513d602081101561382257600080fd5b50519392505050565b6001600160a01b0381166000908152603660205260408120611735906149e6565b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b15801561389057600080fd5b505afa1580156138a4573d6000803e3d6000fd5b505050506040513d60208110156138ba57600080fd5b50516001600160a01b0316146139015760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b038116600090815260366020526040808220815163041e0b2d60e51b8152600481019190915290517357ff2cbf0d1dfd79b497795b2edd3b56f1a30397926383c165a09260248082019391829003018186803b158015612a7f57600080fd5b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b1580156139ab57600080fd5b505afa1580156139bf573d6000803e3d6000fd5b505050506040513d60208110156139d557600080fd5b50516001600160a01b031614613a1c5760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b0382166000908152603660205260408082208151637b1dd5df60e11b81526004810191909152831515602482015290517357ff2cbf0d1dfd79b497795b2edd3b56f1a303979263f63babbe9260448082019391829003018186803b158015613a8a57600080fd5b505af41580156131e2573d6000803e3d6000fd5b603554604080516385c858b160e01b8152905133926001600160a01b0316916385c858b1916004808301926020929190829003018186803b158015613ae257600080fd5b505afa158015613af6573d6000803e3d6000fd5b505050506040513d6020811015613b0c57600080fd5b50516001600160a01b031614613b535760405162461bcd60e51b81526004018080602001828103825260378152602001806156236037913960400191505060405180910390fd5b6001600160a01b03166000908152603660205260409020600d01805460ff60e81b19169055565b6001600160a01b031660009081526036602052604090206009015490565b60345460009081906001600160a01b03163314613be65760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b613bf38888888887614b5c565b6000613c0189898787614c5b565b9050613c0f896000806140cd565b80613c1a8a8a614489565b9250925050965096945050505050565b6001600160a01b0380821660009081526037602090815260408083209386168352929052206001015492915050565b6034546001600160a01b03163314613ca25760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b6001600160a01b0391821660009081526037602090815260408083209590941682529390935291206004018054911515600160281b0265ff000000000019909216919091179055565b6034546001600160a01b03163314613d345760405162461bcd60e51b815260040180806020018281038252602a8152602001806156f1602a913960400191505060405180910390fd5b613d3c614266565b6001600160a01b0316836001600160a01b031614613d6e5761199d6001600160a01b038416838363ffffffff6147e916565b6040516000906001600160a01b0384169061c35090849084818181858888f193505050503d8060008114613dbe576040519150601f19603f3d011682016040523d82523d6000602084013e613dc3565b606091505b5050905080611e6c576040805162461bcd60e51b8152602060048201526016602482015275151c985b9cd9995c881bd9881155120819985a5b195960521b604482015290519081900360640190fd5b6001600160a01b0380821660009081526037602090815260408083209386168352929052206002015492915050565b60355460408051637744894b60e11b815290516000926001600160a01b03169163ee891296916004808301926020929190829003018186803b158015613e8657600080fd5b505afa158015613e9a573d6000803e3d6000fd5b505050506040513d6020811015613eb057600080fd5b50519050613ebc614266565b6001600160a01b0316836001600160a01b031614613eee5761199d6001600160a01b038416828463ffffffff6147e916565b6040516000906001600160a01b0383169084908381818185875af1925050503d8060008114613f39576040519150601f19603f3d011682016040523d82523d6000602084013e613f3e565b606091505b5050905080611e6c5760405162461bcd60e51b815260040180806020018281038252602481526020018061569f6024913960400191505060405180910390fd5b6000613f89826149e6565b905080156118d8576001820154600d830154600091613fb591600160a01b900464ffffffffff16614d59565b8354909150613fcb90829063ffffffff614da416565b83556004830154600d840154600091613ff191600160a01b900464ffffffffff16614ddc565b905061400a846007015482614da490919063ffffffff16565b600785015550505050565b600082820183811015612b2c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600061409261407d84614e2b565b61408684614e2b565b9063ffffffff614a0316565b905060006140ae6140a1614e41565b839063ffffffff61401516565b85549091506140c490829063ffffffff614da416565b90945550505050565b6001600160a01b038084166000908152603660205260408120600d810154909282918291166357e37af088614115886141098b612f2285613787565b9063ffffffff6142d816565b8760020154886003015489600601546040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b031681526020018581526020018481526020018381526020018281526020019550505050505060606040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d60608110156141b057600080fd5b508051602080830151604093840151600189018490556005890182905560048901819055600d8901805464ffffffffff4216600160a01b0264ffffffffff60a01b19909116179055885460078a0154865186815294850184905284870183905260608501919091526080840152935192965094509192506001600160a01b038916917f04e4f521f16fcfd987978b05504262c2a2db223844977aab000e5accedb2d725919081900360a00190a250505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611e6c908590614e51565b60008282111561432f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6001600160a01b038616600090815260366020526040902061435690613f7e565b6131e2868686868686615009565b6001600160a01b038087166000818152603660209081526040808320948a168352603782528083209383529290522060018360028111156143a157fe5b14156143bd576005820154600382015560006001820155614434565b60028360028111156143cb57fe5b14156143e7576000600382015560078201546001820155614434565b6040805162461bcd60e51b815260206004820152601860248201527f496e76616c696420626f72726f772072617465206d6f64650000000000000000604482015290519081900360640190fd5b805461444c908690612f22908963ffffffff61401516565b81556002810154614463908563ffffffff61401516565b6002820155600401805464ffffffffff19164264ffffffffff1617905550505050505050565b6000806144968484611763565b905060008160028111156144a657fe5b14156144b6576000915050611735565b60018160028111156144c457fe5b146144ea576001600160a01b0384166000908152603660205260409020600401546117b0565b50506001600160a01b0390811660009081526037602090815260408083209490931682529290925290206003015490565b6000805b60385481101561456857826001600160a01b03166038828154811061454057fe5b6000918252602090912001546001600160a01b0316141561456057600191505b60010161451f565b50806118d857603880546001810182556000919091527f38395c5dceade9603479b177b68959049485df8aa97b39f3533039af5f4561990180546001600160a01b0384166001600160a01b03199091161790555050565b603560009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561460d57600080fd5b505afa158015614621573d6000803e3d6000fd5b505050506040513d602081101561463757600080fd5b5051603480546001600160a01b0319166001600160a01b03909216919091179055565b6001600160a01b0380851660008181526036602090815260408083209488168352603782528083209383529290522061469282613f7e565b600061469e8787611763565b905060015b8160028111156146af57fe5b14156146ea5760038201546146cd908490869063ffffffff61516516565b60038201546146e5908490879063ffffffff6151dc16565b61470a565b6146fa838563ffffffff61528416565b61470a838663ffffffff6152a516565b50505050505050565b6001600160a01b038116600090815260366020526040902061473490613f7e565b50565b6001600160a01b03808516600090815260376020908152604080832093891683529281528282206036909152919020815461477e908690614109908663ffffffff61401516565b8255600261478c8888611763565b600281111561479757fe5b14156147a857600781015460018301555b83156147c95760028201546147c3908563ffffffff6142d816565b60028301555b50600401805464ffffffffff19164264ffffffffff161790555050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611aa2908490614e51565b815460009061484c57506000611735565b600061485b8460000154614e2b565b600385015490915060009081901561488f5760038601546004870154614888919064ffffffffff16614ddc565b90506148d1565b6148ce866001015461408687600701546148c289600401548a600d0160149054906101000a900464ffffffffff16614ddc565b9063ffffffff614da416565b90505b6148e96148e4848363ffffffff614da416565b6152fd565b865490925082141561492457600486015464ffffffffff16421461492457855461491a90600163ffffffff61401516565b9350505050611735565b50949350505050565b6001600160a01b0380841660008181526036602090815260408083209487168352603782528083209383529290522061496582613f7e565b600381015461169c908390859063ffffffff61516516565b6001600160a01b0380831660009081526037602090815260408083209387168352928152828220603690915291902081546149be908463ffffffff61401516565b8255600501546003820155600401805464ffffffffff19164264ffffffffff16179055505050565b60006117358260030154836002015461401590919063ffffffff16565b6000600282046117b083614a33614a26876b033b2e3c9fd0803ce8000000615316565b849063ffffffff61401516565b9063ffffffff61536f16565b600890565b303b1590565b600080612b2c83600001546148c2856001015486600d0160149054906101000a900464ffffffffff16614d59565b6001600160a01b03808516600081815260366020908152604080832094881683526037825280832093835292905290812090614ab48787611763565b6001600160a01b0388166000908152603660205260409020909150614ad890613f7e565b60016146a3565b6001600160a01b038087166000818152603660209081526040808320948a16835260378252808320938352929052208054614b26908790614109908763ffffffff61401516565b8155600782015460018201558215614b475760006003820181905560018201555b6002810154614463908663ffffffff6142d816565b6001600160a01b03808616600081815260366020908152604080832094891683526037825280832093835292905220614b9482613f7e565b6001836002811115614ba257fe5b1415614bd4576003810154614bbe83878363ffffffff6151dc16565b614bce838663ffffffff61528416565b5061470a565b6002836002811115614be257fe5b1415614c0e576005820154614bfd838763ffffffff6152a516565b614bce83868363ffffffff61516516565b6040805162461bcd60e51b815260206004820152601a60248201527f496e76616c69642072617465206d6f6465207265636569766564000000000000604482015290519081900360640190fd5b6001600160a01b03808416600090815260376020908152604080832093881683529281528282206036909152918120909190826002856002811115614c9c57fe5b1415614cbd5750600581015460038301556000600183810191909155614d21565b6001856002811115614ccb57fe5b1415614cea575060006003830155600781015460018301556002614d21565b60405162461bcd60e51b815260040180806020018281038252602381526020018061571b6023913960400191505060405180910390fd5b8254614d33908763ffffffff61401516565b83556004909201805464ffffffffff19164264ffffffffff161790555095945050505050565b600080614d734264ffffffffff851663ffffffff6142d816565b90506000614d8761407d6301e13380614e2b565b9050612eec614d94614e41565b612f22878463ffffffff614da416565b6000612b2c6b033b2e3c9fd0803ce8000000614a33614dc9868663ffffffff61531616565b6b019d971e4fe8401e7400000090614015565b600080614df64264ffffffffff851663ffffffff6142d816565b90506000614e0e856301e1338063ffffffff61536f16565b9050612eec82614e1f614a26614e41565b9063ffffffff6153d916565b600061173582633b9aca0063ffffffff61531616565b6b033b2e3c9fd0803ce800000090565b614e63826001600160a01b0316611541565b614eb4576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310614ef25780518252601f199092019160209182019101614ed3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614f54576040519150601f19603f3d011682016040523d82523d6000602084013e614f59565b606091505b509150915081614fb0576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115611e6c57808060200190516020811015614fcc57600080fd5b5051611e6c5760405162461bcd60e51b815260040180806020018281038252602a81526020018061573e602a913960400191505060405180910390fd5b60006150158787611763565b6001600160a01b0388166000908152603660205260409020909150600182600281111561503e57fe5b1415615087576001600160a01b038088166000908152603760209081526040808320938c168352929052206003810154615081908390899063ffffffff6151dc16565b506150ab565b600282600281111561509557fe5b14156150ab576150ab818763ffffffff6152a516565b60006150c185612f22898963ffffffff61401516565b905060018460028111156150d157fe5b14156150f45760058201546150ef908390839063ffffffff61516516565b6121d1565b600284600281111561510257fe5b1415615118576150ef828263ffffffff61528416565b6040805162461bcd60e51b815260206004820152601c60248201527f496e76616c6964206e657720626f72726f772072617465206d6f646500000000604482015290519081900360640190fd5b8161516f57611aa2565b6002830154615184818463ffffffff61401516565b60028501556000615198836148c286614e2b565b905060006151ad86600601546148c285614e2b565b90506151cf6151bf8760020154614e2b565b614086848463ffffffff61401516565b6006870155505050505050565b60028301548015806151ee5750808310155b1561520757506000600284018190556006840155611aa2565b600284015461521c908463ffffffff6142d816565b60028501556000615230836148c286614e2b565b9050600061524586600601546148c285614e2b565b9050818111615264575050600060028501819055600685015550611aa2565b6151cf6152748760020154614e2b565b614086838563ffffffff6142d816565b6003820154615299908263ffffffff61401516565b82600301819055505050565b80826003015410156152e85760405162461bcd60e51b815260040180806020018281038252605081526020018061546a6050913960600191505060405180910390fd5b6003820154615299908263ffffffff6142d816565b6000631dcd6500612b2c633b9aca00614a338386614015565b60008261532557506000611735565b8282028284828161533257fe5b0414612b2c5760405162461bcd60e51b815260040180806020018281038252602181526020018061567e6021913960400191505060405180910390fd5b60008082116153c5576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b60008284816153d057fe5b04949350505050565b6000600282066153f5576b033b2e3c9fd0803ce80000006153f7565b825b90506002820491505b8115611735576154108384614da4565b92506002820615615428576154258184614da4565b90505b60028204915061540056fe466565206c69717569646174696f6e20646f6573206e6f74207265717569726520616e79207472616e73666572206f662076616c756554686520616d6f756e742074686174206973206265696e6720737562747261637465642066726f6d20746865207661726961626c6520746f74616c20626f72726f777320697320696e636f727265637454686520616d6f756e7420616e64207468652076616c75652073656e7420746f206465706f73697420646f206e6f74206d617463684f6e6c7920636f6e7472616374732063616e2073656e6420657468657220746f20746865204c656e64696e6720706f6f6c20636f726552657365727665206265696e672072656d6f76656420697320646966666572656e74207468616e20746865207265736572766520726571756573746564557365722069732073656e64696e672045544820616c6f6e67207769746820746865204552433230207472616e736665722e557365722069732073656e64696e672045544820616c6f6e67207769746820746865204552433230207472616e736665722e20436865636b207468652076616c756520617474726962757465206f6620746865207472616e73616374696f6e43616e6e6f742072656d6f7665206120726573657276652077697468206c6971756964697479206465706f73697465645468652063616c6c6572206d7573742062652061206c656e64696e6720706f6f6c20636f6e666967757261746f7220636f6e74726163745265736572766520686173206e6f74206265656e20696e697469616c697a656420796574536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775472616e7366657220746f20746f6b656e206469737472696275746f72206661696c6564436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a65645468652063616c6c6572206d7573742062652061206c656e64696e6720706f6f6c20636f6e7472616374496e76616c696420696e7465726573742072617465206d6f64652072656365697665645361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a265627a7a723158203463a6d16b06fd2eaec8053909bb75658e7ac0932c4bf200cddb23757876cf4c64736f6c63430005110032
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.