GM Lending Pool
The core lending contract stores user balances, user debt, price oracles, asset data, and fee data; calculates interest and health factors; and is the executor of all deposits, borrows, repays, withdrawals, and liquidations. The pool contract inherits from Solmate's Auth contract and OpenZeppelin's ReentrancyGuard. The protocol and asset mechanisms are set according to the following functions:
constructor
At deployment, the constructor sets the deployer-provided _owner
as the owner and _authority
as the Authority (both hereafter referred to as Admin). It then stores the pool name
.
Admin Functions
setGloopStakersWallet
function setGloopStakersWallet(address _newWallet) external requiresAuth
Sets or updates the gloopStakersWallet
address, which will receive a portion of the platform fees to be distributed to future Gloop stakers. This can only be changed by the Admin. Upon success, the call emits a GloopStakersWalletUpdated
event with the caller's address and the new wallet address as parameters.
Parameters:
_newWallet
address
The address of the new Gloop Staker rewards wallet
setAddressStore
function setAddressStore(AddressStore newAddressStore) external requiresAuth
Sets or updates the Address Store contract. The Address Store can only be changed by the Admin.
Parameters:
newAddressStore
AddressStore
The new AddressStore instance
setOracle
function setOracle(PriceOracle newOracle) external requiresAuth
Sets or updates the Pool's Oracle contract. The Oracle can only be updated by the Admin. Upon success, the call emits an OracleUpdated
event with the caller's address and the new oracle contract as parameters.
Parameters:
newOracle
PriceOracle
The Lending Oracle contract instance
setInterestRateModel
function setInterestRateModel(ERC20 asset, InterestRateModel newInterestRateModel, bool accrue) external requiresAuth
Sets a new or updates the existing Interest Rate Model (IRM) for a specific asset. Models can only be set or updated by the Admin. Upon success, the call emits an InterestRateModelUpdated
event with the caller's address, asset, and model contract. See the Interest Rate Model section for details.
Before changing the IRM, interest is accrued using the existing model (if there is one). This helps avoid a stepwise jump in rates of interest accrual, which could result in wonky amounts of yield to users. This can be bypassed in emergency/unforeseen situations like an IRM that has been set but has a bug that causes interest accrual to revert, thereby leaving the Pool in a forever stuck state.
Parameters:
asset
ERC20
The asset to assign the model to
newInterestRateModel
InterestRateModel
The interest model that the asset will use.
accrue
boolean
If true and there is an existing model, accrue interest. If false, do not accrue interest.
configureAsset
function configureAsset(ERC20 asset, ERC4626 vault, Configuration memory configuration, bool updateVault)
external
requiresAuth
Configures/adds USDC or a GM token for the Lending Pool, so that users are able to utilize and transfer the tokens. Tokens can only be added or configured by the Admin. If the asset is new to the pool, the vault, configuration struct, and decimals are set for the asset in three separate mappings. The vault contract is the ERC-4626 Vault that has been deployed for the particular GM token. (See GM Vaults section for more.) The decimals are obtained by calling decimals()
on the ERC-20 token.
The configuration struct contains the lending/borrowing factors and caps for each asset as shown here:
struct Configuration {
uint256 lendFactor; // max lend amount in terms of token amount.
uint256 supplyCap; // max amount of tokens that can be supplied.
uint256 borrowFactor; // max borrow amount in terms of token amount.
uint256 borrowCap; // max amount of tokens that can be borrowed.
}
If the asset is not new to the pool, the call updates the config parameters, and, if the updateVault
boolean is marked as true, this function will assign the asset to a new vault. Note that this does not move any tokens to the new vault. Each vault has a migrate()
function that moves the tokens that should be called beforehand.
Once the mappings are successfully updated, an AssetConfigured
or AssetConfigurationUpdated
event is emitted with caller's address, asset, vault contract, and configuration.
Parameters:
asset
ERC20
The asset to be configured
vault
ERC4626
The tokenized standard type of the asset's vault
configuration
Configuration
A struct that contains an asset's lend and borrow factors
updateVault
boolean
Updates the asset's vault if true
setGmTokens
function setGmTokens(address[] memory newGmTokenAddress) external requiresAuth
Stores an array of GM Token addresses in the gmTokensAddresses
state array. The array can only be updated by the Admin.
Parameters:
newGmTokensAddress
address[] memory
An array of GM tokens
addNewGmToken
function addNewGmToken(address newGmToken) external requiresAuth
Adds a GMX Market (GM) Token to the gmTokensAddresses
state array. Tokens can only be added by the Admin. Upon success, the call emits a NewGMToken
event with the caller's address and the new GM Token address as parameters.
Parameters:
newGmToken
address
The address of the GMX Market Token
setGMPointsContract
function setGMPointsContract(address newPointsAddress) external requiresAuth
Sets the GM Points contract for the pool. The contract can only be set by the Admin. If a GM Points contract is active, depositing and borrowing USDC earn points. USDC transfer activity is relayed from the Pool to the Points contract via an updatePoints
modifier that sends msg.sender
, whether it's a deposit or withdrawal, and the amount. See the GM Points section for details.
Parameters:
newPointsAddress
address
The address of the GM Points contract
updateLiquidationBonus
function updateLiquidationBonus(uint256 _newLiquidationBonus) external requiresAuth
Sets or updates the liquidationBonus
, which can only be done by the Admin. The bonus cannot be more than the MAX_LIQUIDATION_BONUS
. This is hardcoded to 10%.
Parameters:
_newLiquidationBonus
uint256
The bonus multiplier for liquidations
liquidateBadDebt
function liquidateBadDebt(address borrower, uint256 repayAmount) external requiresAuth
Partially or fully repays a borrow position with "bad debt," meaning little or no collateral and the position is at risk of or is fully insolvent. Only the Admin can call this function. Admin does not receive any collateral for liquidating bad debt. Function is only used to avoid bad debt accrual.
Parameters:
borrower
address
The user with poor health factor
repayAmount
uint256
Amount repaid by owner (in USDC)
setGloopStakersYieldFactor
function setGloopStakersYieldFactor(address newGSYFactor) external requiresAuth
Sets or updates the gloopStakersYieldFactor
. Can only be called by the Admin. The factor cannot be greater than 45%. The factor represents the portion of the platform fees to be distributed to the gloopStakersWallet
. Pool interest is accrued before the factor change/setting. Upon success, the call emits a GloopStakersYieldUpdated
event with the caller's address and the new factor as parameters.
Parameters:
newGSYFactor
uint256
The new Gloop Staker Yield Factor (percentage of lending platform fees)
updateReservesFactor
function updateReservesFactor(address newReserveFactor) external requiresAuth
Sets or updates the reserveFactor
. Can only be called by the Admin. The factor represents the portion of the platform fees that will go to Protocol Reserves. Pool interest is accrued before the factor change/setting.
Parameters:
newReserveFactor
uint256
The new Reserve Factor (percentage of lending platform fees)
withdrawReserves
function withdrawReserves(ERC20 asset, uint256 amount) external requiresAuth
Transfers an amount
of totalReserves
from the USDC vault to the Admin wallet. The token amount
is subtracted from totalReserves
, then transferred out of the asset's vault to the pool contract, which immediately transfers them to the Admin wallet.
Parameters:
asset
ERC20
The asset to withdraw
amount
uint256
The amount of tokens to withdraw
withdrawStakersYield
function withdrawStakersYield(ERC20 asset, uint256 amount) external requiresAuth
Transfers an amount
of gloopStakersYield
from the USDC vault to the Admin wallet. The token amount
is subtracted from gloopStakersYield
, then transferred out of the asset's vault to the pool contract, which immediately transfers them to the gloopStakersWallet
.
Parameters:
asset
ERC20
The asset to withdraw
amount
uint256
The amount of tokens to withdraw
Core External/Public Functions
deposit
function deposit(ERC20 asset, uint256 amount) external nonReentrant
This function is the main and first point of entry to the protocol. At present, the only assets allowed for depositing are GM tokens and USDC. GM tokens can only be used as collateral. USDC cannot be used as collateral, but is the only token that can be used for lending. This call will revert if the amount
is zero, if the asset is not a valid token, or if the new deposit puts the Pool's supply of that asset over its supplyCap
.
When a user deposits, since the protocol uses ERC-4626 tokenized vaults, the amount of tokens to transfer are converted into "shares
" using the internalBalanceExchangeRate()
. Then the internalBalances
and totalInternalBalances
mappings of the asset are increased by shares
amount for the user and the protocol.
The token amount
is then transferred to the pool contract, which immediately transfers them to the asset's ERC-4626 vault. If the asset is a GM token, then it is automatically enabled as collateral for the user. If the asset is USDC, it is not. (Currently, USDC is solely used for liquidity provision and borrowing.) Upon successful transfer, the Deposit
event is emitted, including msg.sender
's address, the asset
, and the amount
.
If there are live liquidity incentives, then the existingBalance
, amount
, and msg.sender
address are relayed to the GM Incentives contract via the USDC Vault.
If block.timestamp
is not past the gmPointsContract.pointsEndTime()
(e.g. the Points program is still going on), then the caller's points are updated via _updatePoints()
in the GM Points contract.
Parameters:
asset
ERC20
The asset to deposit
amount
uint256
The amount of tokens to deposit
withdraw
function withdraw(ERC20 asset, uint256 amount) external nonReentrant
Transfers an amount
of tokens to the caller. This function is essentially a public wrapper of the internal function _withdraw()
. For convenience, the withdraw logic will be explained here.
_withdraw()
:
Withdraws an amount
of the caller's tokens from the pool. The asset
can be GM or USDC tokens. As during depositing, the amount of tokens to transfer are converted into "shares
" using the internalBalanceExchangeRate()
. If the shares requested are less than the user's balance or zero, the call with revert. Similar to disableAsset()
, if the withdrawal request would bring the user's health factor below 1e18 (100%), the call with revert. If the health factor remains above 1e18, then the internalBalances
and totalInternalBalances
mappings of the asset are decreased by shares
amount for the user and the protocol.
The token amount
is then transferred out of the asset's vault to the pool contract, which immediately transfers them to the user. Upon successful transfer, the Withdraw
event is emitted, including receiver
's address, the asset
, and the amount
. If _withdraw()
is called within a liquidation call via liquidateUser()
, the tokens are sent to the receiver
, which is the address that initiated the liquidation.
If there are live liquidity incentives, then the existingBalance
, amount
, and msg.sender
address are relayed to the GM Incentives contract via the USDC Vault.
If block.timestamp
is not past the gmPointsContract.pointsEndTime()
(e.g. the Points program is still going on), then the caller's points are updated via _updatePoints()
in the GM Points contract.
Parameters:
asset
ERC20
The asset to withdraw
amount
uint256
The amount of tokens to withdraw
borrow
function borrow(ERC20 asset, uint256 amount) external nonReentrant
Transfers an amount of borrowed USDC to the caller. Once a user has deposited GM tokens as enabled collateral, the user is able to borrow USDC. (More assets may be available to borrow in the future.)
If the user has an existing loan, the unaccrued interest will be calculated for and added to the position via accrueInterest()
. The user's health factor is then calculated based on the requested borrow (see calculateHealthFactor()
for details). If the health factor remains above 1e18 (100%), then the user may borrow. If not, the function will revert. If the borrowCap
is reached due to the new borrow, the call will revert.
Similar to depositing, the requested amount
of tokens is converted to debtUnits
by the internalDebtExchangeRate()
. The debtUnits
are then added to the internalDebt
and totalInternalDebt
mappings for the user and the protocol, respectively. The token amount is also added to the cachedTotalBorrows
mapping for the borrowed asset (USDC).
The tokens are now finally transferred from the USDC vault to the pool contract, which immediately transfers them to the caller/borrower. Upon successful transfer, the Borrow
event is emitted, including msg.sender
's address, the asset
, and the amount
.
If block.timestamp
is not past the gmPointsContract.pointsEndTime()
(e.g. the Points program is still going on), then the caller's points are updated via _updatePoints()
in the GM Points contract. See GM Points for more on the point system.
Parameters:
asset
ERC20
The asset to borrow (for now, this can only be USDC)
amount
uint256
The amount of USDC to borrow
repay
function repay(ERC20 asset, uint256 amount) external nonReentrant
Transfers an amount of USDC from the caller to the protocol as a repayment of debt. This function is essentially a public wrapper of the internal function _repay()
. For convenience, the repay logic will be explained here.
_repay()
:
If the user has an existing loan, then all unaccrued interest will be added to their position via accrueInterest()
. Similar to borrowing, the repayment amount
of tokens is converted to debtUnits
by the internalDebtExchangeRate()
, with the function reverting if the debtUnits
are greater than the internalDebt
of the user. The debtUnits
are then subtracted from the internalDebt
and totalInternalDebt
mappings for the user and the protocol, respectively. The token amount
is also subtracted from the cachedTotalBorrows
mapping for the borrowed asset (USDC).
The tokens are now finally transferred from the user to the pool contract, which immediately transfers them to the USDC vault. If _repay()
is called within a liquidation call, the tokens are transferred from the liquidator to the pool contract, on behalf of the borrower. Upon successful transfer, the Repay
event is emitted, including the msg.sender
's address, the asset
, and the amount
.
If block.timestamp
is not past the gmPointsContract.pointsEndTime()
(e.g. the Points program is still going on), then the caller's points are updated via _updatePoints()
in the GM Points contract. See GM Points for more on the point system.
Parameters:
asset
ERC20
The asset to repay (for now, this can only be USDC)
amount
uint256
The amount of USDC to repay
liquidateUser
function liquidateUser(ERC20 borrowedAsset, address borrower, uint256 repayAmount) external nonReentrant
Allows a liquidator to repay a borrower's debt and seize their collateral if their health factor has dropped below the liquidatable threshold (1e18 or 100%). Before proceeding, the function calls accrueInterest
to update any pending interest for the pool. If the borrower is healthy, the borrower has no collateral value, or the USDC vault is paused or has been recently unpaused and the block.timestamp
has not yet reached the liquidationsResumeTimestamp
, this function will revert.
The liquidator provides a repayment amount, which is used to calculate collValueToSeize
: the repayment amount in USDC multiplied by the price of the borrowed asset and the liquidation bonus factor (which gives a discount to the liquidator). If collValueToSeize
exceeds the borrower's total available collateral, the collValueToSeize
is adjusted to the maximum collateral value.
The internal _repay
function is then called to handle the repayment of the borrower's debt using the liquidator's funds. This updates the protocol’s internal debt tracking. The liquidation call finishes by calling _seizeCollateral
.
Parameters:
borrowedAsset
ERC20
The borrowed asset to be repaid
borrower
address
The address of the borrower to liquidate
repayAmount
uint256
The amount the liquidator is paying to cover some or all of the borrower's debt.
Ancillary Functions
isValidGMToken
function isValidGMToken(ERC20 asset) public view returns (bool isValid)
Searches the gmTokensAddresses
array to verify if the input asset is a valid GM token and returns true if so. This check ensures that only GM tokens can be deposited as collateral in the protocol.
Parameters:
asset
ERC20
The token to validate
Returns:
isValid
bool
If true, the asset is a valid GM token.
checkNotSameBlock
function checkNotSameBlock() internal
Checks if two transactions have the same block.number
and reverts if so to mitigate flash loans. The number is obtained via an arbBlockNumber()
call on the Arbitrum Precompile contract ArbSys.sol (see the Arbitrum Docs for details). This block number is mapped to the msg.sender
's address in an internal mapping _prevBlockCall
. Any ensuing calls will check to make sure that the current block.number
is not the same as the one stored in the mapping.
enableAsset
function enableAsset(ERC20 asset) public
Enables an asset as a user's collateral. The asset must be a valid (active) GM collateral token (notably, it cannot be USDC). The asset is pushed to the userCollateral
and enabledCollateral
mappings. An AssetEnabled
event is then emitted with the caller's address and asset
as event parameters.
Parameters:
asset
ERC20
The token to enable
disableAsset
function disableAsset(ERC20 asset) public
Disables an asset as a user's collateral. The asset must be an enabled GM token and cannot be USDC. If the asset is the user's sole collateral, then the user must not have an active borrow against it. If the user isn't borrowing, then the collateral will be disabled.
If the user has multiple assets as active collateral, the max borrow value against the asset to be disabled is subtracted from the user's total maxBorrowableValue
. If this value is greater or equal to the user's currentBorrowValue
, then the function will proceed. If not, the function reverts with an error.
The asset is disabled by deleting it from the userCollateral
mapping and switching the enabledCollateral[msg.sender]
boolean to false. An AssetDisabled
event is emitted with the msg.sender
's address and the asset
now disabled.
Parameters:
asset
ERC20
The token to disable
_seizeCollateral
function (address borrower, uint256 collValueToSeize) internal
During a call to liquidateUser
, after debt repayment, _seizeCollateral
loops through the borrower's collateral-enabled assets (in the order of utilized
, which is the sequence the assets were initially deposited in by the user), determines each asset's total value, and compares it to the collValueToSeize
. If the borrower's first collateral asset's total value exceeds the collValueToSeize
, then that value of asset tokens is withdrawn to the liquidator's address, allowing the borrower to retain the remaining tokens in that collateral. In that case, the liquidation would end there.
If the first collateral asset's total value is less than the collValueToSeize
, after the first withdraw, the function proceeds to the next collateral asset of the borrower and compares that asset's total value to collValueToSeize
. Tokens from both assets will be withdrawn to the liquidator's address, and the loop moves to the next collateral asset, if necessary. The Liquidation
event is emitted at process completion.
Parameters:
borrower
address
The address to be liquidated
collValueToSeize
uint256
The total value of the borrower's collateral to be seized
getUserCollateralValue
function getUserCollateralValue(address borrower) public view returns (uint256)
Calculates and sums the values of all assets the borrower currently has enabled as collateral.
Parameters:
borrower
address
The address the collateral belongs to
Returns:
totalCollateralValue
uint256
The total collateral value of the user/borrower
vaultPauseInterestAccrual
function vaultPauseInterestAccrual(bool willBePaused) external
Accrues or does not accrue interest based on USDC vault status. During the vault's paused window, interest
should not accrue, so when pause() is called on the USDC Vault, all pending interest is accrued before the actual pause happens. Then, once paused, no interest shall accrue . When the vault is unpaused, lastInterestAccrual
is updated to the current block.timestamp
and interest accrual can resume.
This ensures user positions do not become unhealthy when vault is paused. This call chain begins and
ends within the GMUSDCVault
contract, where the vault is actually paused or unpaused.
This function is only callable by the USDC Vault.
Parameters:
willBePaused
boolean
If true, interest shall be accrued. If false, interest is not accrued and lastInterestAccrual
gets updated to the current block.timestamp
.
calculateHealthFactor
function calculateHealthFactor(ERC20 asset, address user, uint256 amount) public view returns (uint256)
Returns the new Health Factor after a requested borrow by the user
. If zero is input as the amount
, then the user's current Health Factor will be calculated and returned. The calculation occurs in a few steps:
First, the collateral values for each of the user's enabled assets are multiplied by each asset's
lendingFactor
, then summed together to get themaximumBorrowable
value.The
hypotheticalBorrowBalance
is determined by adding the requested borrow amount to the currentborrowBalance
, if any.The
hypotheticalBorrowValue
is then determined by multiplying thehypotheticalBorrowBalance
by the current price of the asset.If the asset to be borrowed has a
borrowFactor
, it is multiplied by themaximumBorrowable
value to obtain theactualBorrowableValue
. USDC'sborrowFactor
is 1 or1e18
.Dividing the
actualBorrowableValue
by thehypotheticalBorrowValue
results in the Health Factor. If the Health Factor is above1e18
, e.g. if theactualBorrowableValue
is greater than or equal to the futurehypotheticalBorrowValue
, then the user can borrow the amount requested.
Parameters:
asset
ERC20
The asset requested to borrow
user
address
The address to calculate the Health Factor for
amount
uint256
The amount requested to borrow
Returns:
unnamed
uint256
The new Health Factor after the requested borrow
calculateHFAfterCollChange
function calculateHFAfterCollChange(ERC20 asset, address user, uint256 collAmount, bool collIncrease) public view returns (uint256)
Calculates the Health Factor of a user after a collateral change. Set the collIncrease
boolean argument to true if the change is a deposit or enabling an asset as collateral. Set to false when withdrawing a collateral asset or disabling it as collateral. The calculation occurs in a few steps:
After the maximum borrowable value against the collateral value being adjusted is calculated (this becomesadjustedCollMaxBorrow
), the user's current borrowed value is calculated. If the currentBorrowValue
is zero, then the new Health Factor is infinity.
If the collIncrease
boolean is true (meaning an asset will be enabled as collateral), then the adjustedCollMaxBorrow
is added to the user's maxBorrowableValue()
. If collIncrease
is false (disabling or withdrawing an asset), then adjustedCollMaxBorrow
is subtracted to the user's maxBorrowableValue()
. This is the newMaxBorrowValue
.
The resulting Health Factor after the collateral change is newMaxBorrowValue
/ currentBorrowValue
.
Parameters:
asset
ERC20
The collateral asset
user
address
The address to calculate the Health Factor for
collAmount
uint256
The collateral token amount adjustment
Returns:
hypotheticalHF
uint256
The hypothetical Health Factor after the collateral adjustment
maxBorrowableValue
function maxBorrowableValue(address user) public view returns (uint256 maximumBorrowableValue)
Calculates and returns the maximumBorrowableValue
for the caller. This function loops through the userCollateral
array and sums the products of the collateral value and the lendingFactor
for each asset. If the asset to be borrowed has a borrowFactor
, it is multiplied by the maximumBorrowableValue
to result in a lesser borrowable value. Since USDC has a borrowFactor
of 1 (or 1e18), currently this step has no effect on the answer.
The resulting maximumBorrowableValue
is the theoretical maximum value allowed to borrow in relation to the user's current collateral.
Returns:
maximumBorrowableValue
uint256
The maximum value the user can borrow
getCollateral
function getCollateral(address user) external view returns (ERC20[] memory)
Retrieves the user's ERC20[]
array of collateral assets from the userCollateral
mapping.
Parameters:
user
address
The owner of the collateral
Returns:
unnamed
ERC20[]
An ERC20[]
array of collateral assets
getInternalCachedTotalBorrows
function getInternalCachedTotalBorrows(address asset) public view returns (uint256)
Retrieves the internal cachedTotalBorrows
variable for the asset
.
Parameters:
asset
address
The address of the asset
Returns:
cachedTotalBorrows
uint256
The internal total borrow storage variable, which excludes non-accrued interest.
Accounting Logic Functions
totalUnderlying
function totalUnderlying(ERC20 asset) public view returns (uint256)
Returns the total amount of underlying tokens both held by and owed to the pool. If this getter is called for a GM token, it only needs to return availableLiquidity()
. If wanting the total amount of underlying USDC tokens, then the availableLiquidity()
is added to the totalBorrows()
.
Parameters:
asset
ERC20
The underlying asset
Returns:
unnamed
uint256
The total amount of tokens held by and owed to the pool
availableLiquidity
function availableLiquidity(ERC20 asset) public view returns (uint256)
Returns the total amount of tokens held in the token's vault for the Lending Pool that are immediately available. After calling balanceOf
on the asset's vault, the shares are converted to the amount of tokens held by the pool by calling convertToAssets()
on the vault.
A point of distinction is that the gloopStakersYield
and totalReserves
are not considered as the pool's availableLiquidity
for USDC, since when borrow interest is accrued, these portions never touch the pool's internal balances. They are tracked in cachedTotalBorrows
so that they are included in borrow balances and captured in repayments, but then they are sequestered for the Gloop Staker and Reserves wallets, so they are not exposed to further pool fluctuations or bear any additional interest.
Parameters:
asset
ERC20
The underlying asset
Returns:
unnamed
uint256
The total amount of tokens held in the asset's vault.
getEffectiveUSDCBalanceOf
function getEffectiveUSDCBalanceOf(address user) public view returns (uint256)
Since gloopStakersYield
and totalReserves
are not considered as the pool's availableLiquidity
for USDC, this getter calculates these pending interest allocations and removes them to get the effectiveTotalUnderlying
tokens. Once this is determined, it is multiplied by the ratio of the user's internalBalances
to the totalInternalBalance
and returns the effective USDC balance of the user.
Parameters:
user
address
The address to get the token balance of
Returns:
unnamed
uint256
The effective token balance of the user, adjusting for pending interest allocations
balanceOf
function balanceOf(ERC20 asset, address user) public view returns (uint256)
Calculates the token balance of the user by multiplying the user's internal balance units by the internalBalanceExchangeRate()
.
Parameters:
asset
ERC20
The underlying asset
user
address
The address to get the token balance of
Returns:
unnamed
uint256
The token balance of the user
internalBalanceExchangeRate
function internalBalanceExchangeRate(ERC20 asset) internal view returns (uint256)
Calculates the exchange rate between underlying tokens and internal balance units. By dividing the totalUnderlying()
shares by the totalInternalBalance
units for the asset, this function converts shares into tokens. If the totalInternalBalance
is zero, then the exchange rate is 1 (in the asset's base units).
Parameters:
asset
ERC20
The underlying asset
Returns:
unnamed
uint256
The exchange rate
borrowBalance
function borrowBalance(ERC20 asset, address user) public view returns (uint256)
Calculates and returns the borrow balance of an address by multiplying the user's internal debt units by the internalDebtExchangeRate()
.
Parameters:
asset
ERC20
The borrowed asset
user
address
The address to calculate the borrow balance for
Returns:
unnamed
uint256
The borrow balance of the user
internalDebtExchangeRate
function internalDebtExchangeRate(ERC20 asset) internal view returns (uint256)
Calculates the exchange rate between underlying tokens and internal debt units. By dividing the totalBorrows()
shares by the totalInternalDebt
units for the asset, this function converts shares into tokens. If the totalInternalDebt
is zero, then the exchange rate is 1 (in the asset's base units).
Parameters:
asset
ERC20
The underlying asset
Returns:
unnamed
uint256
The exchange rate
totalBorrows
function totalBorrows(ERC20 asset) public view returns (uint256)
Calculates and returns the total amount of underlying tokens being loaned out to borrowers. To calculate the pending interest, the availableLiquidity()
and cachedTotalBorrows
for the asset are passed as arguments into getBorrowRate()
, which is called on the Interest Rate Model contract set for the asset (see Interest Rate Model section for details). Having obtained the interestRate
, using the time or blockDelta
since the lastInterestAccrual
, we can calculate the interestAccumulator
:
Multiplying cachedtotalBorrows
by the interestAccumulator
gives us the total borrows with interest accrual.
Parameters:
asset
ERC20
The underlying asset
Returns:
unnamed
uint256
The total amount of borrowed tokens (including interest)
accrueInterest
function accrueInterest(ERC20 asset) internal
Deriving the totalInterestAccumulated
from totalBorrows() - cachedTotalBorrows
, this function calculates the accrued stakersYield
and reserveAmount
and adds them to their namesake state variables. After adding totalInterestAccumulated
to cachedTotalBorrows
, the current block.timestamp
is then stored in lastInterestAccrual
for the asset.
Parameters:
asset
ERC20
The underlying asset (only USDC for now)
Last updated