Gloop
WebsiteTwitterDiscord
  • gLoop Litepaper v2
    • Introduction
    • The Two Tokens
    • Roadmap
  • PRODUCTS
    • GM Index
      • Providing/Removing Liquidity
      • Fees and Reflection
      • Deposit/Withdrawal Examples
    • GM Lend/Borrow
      • Lending USDC
      • Depositing Collateral Assets
      • Withdrawing Assets
      • Borrowing USDC
      • Repaying Debt
      • gLooping GM Assets
      • Position Management
        • Withdrawing Assets
        • Health Factor and Liquidations
      • Lending/Borrowing GMI (Coming Soon)
      • Frequently Asked Questions (FAQs)
    • GLOOP Staking (Coming Soon)
  • GM Points (COMING SOON)
  • Technical
    • Gloop Protocol Parameters
    • Gloop Parameters
    • Contracts
      • GM Lending and Looping
        • GM Lending Pool
        • GM Price Oracle
        • GM Vaults
        • GM Interest Rate Model
        • GM Incentives
      • GMI
        • GM Index
        • GMI USDC Zap
        • Token Banks
        • Token Oracles
        • Fees
  • FREQUENTLY ASKED QUESTIONS (FAQs)
    • GM Index (GMI)
    • GM Lending/Looping
    • GLOOP Staking (Coming Soon)
  • GLoop Ecosystem
    • Tokenomics
  • Security and Risk
    • Risks
    • Audits
  • Social
    • Socials
Powered by GitBook
On this page
  • constructor
  • Admin Functions
  • setGloopStakersWallet
  • setAddressStore
  • setOracle
  • setInterestRateModel
  • configureAsset
  • setGmTokens
  • addNewGmToken
  • setGMPointsContract
  • updateLiquidationBonus
  • liquidateBadDebt
  • setGloopStakersYieldFactor
  • updateReservesFactor
  • withdrawReserves
  • withdrawStakersYield
  • Core External/Public Functions
  • deposit
  • withdraw
  • borrow
  • repay
  • liquidateUser
  • Ancillary Functions
  • isValidGMToken
  • checkNotSameBlock
  • enableAsset
  • disableAsset
  • _seizeCollateral
  • getUserCollateralValue
  • vaultPauseInterestAccrual
  • calculateHealthFactor
  • calculateHFAfterCollChange
  • maxBorrowableValue
  • getCollateral
  • getInternalCachedTotalBorrows
  • Accounting Logic Functions
  • totalUnderlying
  • availableLiquidity
  • getEffectiveUSDCBalanceOf
  • balanceOf
  • internalBalanceExchangeRate
  • borrowBalance
  • internalDebtExchangeRate
  • totalBorrows
  • accrueInterest
  1. Technical
  2. Contracts
  3. GM Lending and Looping

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:

Name
Type
Description

_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:

Name
Type
Description

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:

Name
Type
Description

newOracle

PriceOracle

The Lending Oracle contract instance

setInterestRateModel

function setInterestRateModel(ERC20 asset, InterestRateModel newInterestRateModel, bool accrue) external requiresAuth 

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:

Name
Type
Description

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

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.
    }

Once the mappings are successfully updated, an AssetConfigured or AssetConfigurationUpdated event is emitted with caller's address, asset, vault contract, and configuration.

Parameters:

Name
Type
Description

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:

Name
Type
Description

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:

Name
Type
Description

newGmToken

address

The address of the GMX Market Token

setGMPointsContract

function setGMPointsContract(address newPointsAddress) external requiresAuth 

Parameters:

Name
Type
Description

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:

Name
Type
Description

_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:

Name
Type
Description

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:

Name
Type
Description

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:

Name
Type
Description

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:

Name
Type
Description

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:

Name
Type
Description

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.

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.

Parameters:

Name
Type
Description

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():

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.

Parameters:

Name
Type
Description

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.)

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.

Parameters:

Name
Type
Description

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():

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.

Parameters:

Name
Type
Description

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.

Parameters:

Name
Type
Description

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:

Name
Type
Description

asset

ERC20

The token to validate

Returns:

Name
Type
Description

isValid

bool

If true, the asset is a valid GM token.

checkNotSameBlock

function checkNotSameBlock() internal

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:

Name
Type
Description

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:

Name
Type
Description

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:

Name
Type
Description

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:

Name
Type
Description

borrower

address

The address the collateral belongs to

Returns:

Name
Type
Description

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:

Name
Type
Description

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 the maximumBorrowable value.

  • The hypotheticalBorrowBalance is determined by adding the requested borrow amount to the current borrowBalance, if any.

  • The hypotheticalBorrowValue is then determined by multiplying the hypotheticalBorrowBalance by the current price of the asset.

  • If the asset to be borrowed has a borrowFactor, it is multiplied by the maximumBorrowable value to obtain the actualBorrowableValue. USDC's borrowFactor is 1 or 1e18.

  • Dividing the actualBorrowableValue by the hypotheticalBorrowValue results in the Health Factor. If the Health Factor is above 1e18, e.g. if the actualBorrowableValue is greater than or equal to the future hypotheticalBorrowValue, then the user can borrow the amount requested.

Parameters:

Name
Type
Description

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:

Name
Type
Description

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:

Name
Type
Description

asset

ERC20

The collateral asset

user

address

The address to calculate the Health Factor for

collAmount

uint256

The collateral token amount adjustment

Returns:

Name
Type
Description

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:

Name
Type
Description

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:

Name
Type
Description

user

address

The owner of the collateral

Returns:

Name
Type
Description

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:

Name
Type
Description

asset

address

The address of the asset

Returns:

Name
Type
Description

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)

Parameters:

Name
Type
Description

asset

ERC20

The underlying asset

Returns:

Name
Type
Description

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:

Name
Type
Description

asset

ERC20

The underlying asset

Returns:

Name
Type
Description

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:

Name
Type
Description

user

address

The address to get the token balance of

Returns:

Name
Type
Description

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)

Parameters:

Name
Type
Description

asset

ERC20

The underlying asset

user

address

The address to get the token balance of

Returns:

Name
Type
Description

unnamed

uint256

The token balance of the user

internalBalanceExchangeRate

function internalBalanceExchangeRate(ERC20 asset) internal view returns (uint256)

Parameters:

Name
Type
Description

asset

ERC20

The underlying asset

Returns:

Name
Type
Description

unnamed

uint256

The exchange rate

borrowBalance

function borrowBalance(ERC20 asset, address user) public view returns (uint256)

Parameters:

Name
Type
Description

asset

ERC20

The borrowed asset

user

address

The address to calculate the borrow balance for

Returns:

Name
Type
Description

unnamed

uint256

The borrow balance of the user

internalDebtExchangeRate

function internalDebtExchangeRate(ERC20 asset) internal view returns (uint256)

Parameters:

Name
Type
Description

asset

ERC20

The underlying asset

Returns:

Name
Type
Description

unnamed

uint256

The exchange rate

totalBorrows

function totalBorrows(ERC20 asset) public view returns (uint256)
interestAccumulator=(1+interestRate/1e18)blockDelta×1e18interestAccumulator = (1+ interestRate / 1e18) ^{blockDelta} ×1e18interestAccumulator=(1+interestRate/1e18)blockDelta×1e18

Multiplying cachedtotalBorrows by the interestAccumulator gives us the total borrows with interest accrual.

Parameters:

Name
Type
Description

asset

ERC20

The underlying asset

Returns:

Name
Type
Description

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.timestampis then stored in lastInterestAccrual for the asset.

Parameters:

Name
Type
Description

asset

ERC20

The underlying asset (only USDC for now)

PreviousGM Lending and LoopingNextGM Price Oracle

Last updated 7 days ago

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 section for details.

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 section for more.) The decimals are obtained by calling decimals() on the ERC-20 token.

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 function that moves the tokens that should be called beforehand.

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 section for details.

When a user deposits, since the protocol uses ERC-4626 tokenized vaults, the amount of tokens to transfer are converted into "shares" using the . Then the internalBalances and totalInternalBalances mappings of the asset are increased by shares amount for the user and the protocol.

If there are live liquidity incentives, then the existingBalance, amount, and msg.sender address are relayed to the 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 contract.

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 . If the shares requested are less than the user's balance or zero, the call with revert. Similar to , 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.

If there are live liquidity incentives, then the existingBalance, amount, and msg.sender address are relayed to the 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 contract.

If the user has an existing loan, the unaccrued interest will be calculated for and added to the position via . The user's health factor is then calculated based on the requested borrow (see 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 . 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).

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 for more on the point system.

If the user has an existing loan, then all unaccrued interest will be added to their position via . Similar to borrowing, the repayment amount of tokens is converted to debtUnits by the , 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).

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 for more on the point system.

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 .

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 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.

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 is added to the .

Calculates the token balance of the user by multiplying the user's internal balance units by the .

Calculates the exchange rate between underlying tokens and internal balance units. By dividing the 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).

Calculates and returns the borrow balance of an address by multiplying the user's internal debt units by the .

Calculates the exchange rate between underlying tokens and internal debt units. By dividing the 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).

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 , which is called on the Interest Rate Model contract set for the asset (see section for details). Having obtained the interestRate, using the time or blockDelta since the lastInterestAccrual, we can calculate the interestAccumulator:

Interest Rate Model
GM Vaults
migrate()
GM Points
internalBalanceExchangeRate()
GM Incentives contract
GM Points
internalBalanceExchangeRate()
disableAsset()
GM Incentives contract
GM Points
accrueInterest()
calculateHealthFactor()
internalDebtExchangeRate()
GM Points
accrueInterest()
internalDebtExchangeRate()
GM Points
_seizeCollateral
Arbitrum Docs
availableLiquidity()
totalBorrows()
internalBalanceExchangeRate()
totalUnderlying()
internalDebtExchangeRate()
totalBorrows()
getBorrowRate()
Interest Rate Model