Search
⌃K

Credit Lines

Credit lines allow unverified borrowers to access capital from lenders who trust them. Borrowers don't need to be verified to create credit lines, thus making it ideal for those who prefer to keep their identities private.

Purpose

The credit lines contract allows a single borrower and a single lender to set up a direct agreement for a line of credit with no specific end term. A credit line can be created by either party - a borrower can request a credit line from a lender, or a lender can offer a credit line to a borrower - however, it has to be accepted by the other party to be activated.
Capital for a credit line is directly sourced from the lender's savings account. To do this, lender's balance in every strategy is iterated upon and the required capital removed to fulfill the loan request (the order of iteration over the strategies is preset).

Roles

Admin

Assignment

  • by deploying the contract
  • gaining ownership from previous owner

Permissions

  • Can transfer ownership to another admin
  • Can update logic contract implementation addresses

Borrower

Assignment

  • by accepting a credit line offered by a lender
  • by requesting a credit line to a lender that gets accepted
  • Every active credit line has a borrower. A single address can be a borrower in multiple active credit lines

Permissions

  • Can request or accept a credit line
  • Can borrow from credit line
  • Can add/withdraw collateral, repay, or close the credit line

Lender

Assignment

  • by accepting a credit line requested by a borrower
  • by offering a credit line to a borrower that gets accepted
  • Every active credit line has a lender. A single address can be a lender in multiple active credit lines

Permissions

  • Can offer or accept a credit line request
  • Can liquidate the credit line. Will be the only liquidator if autoLiquidation is set to false
  • Can close the credit line

Liquidator

Assignment

  • If autoLiquidation is true, any one can act as liquidator by calling liquidate(), if set as false, only lender can be the liquidator

Permissions

  • Liquidator liquidates a credit line that is undercollateralized. Note that the liquidator roles are not set - anyone that calls the liquidate() function is technically assigned the liquidator rule for the credit line in question

Functionality

Creating a credit line request

The first step in establishing a credit line is creating a request. The request can either be created by a borrower or by a lender. Once the credit line request is created, it needs to be accepted by the recipient (the lender, in case the creator was the borrower, or vice versa) for the credit line to be activated. Every credit line is represented by an id which is simply the serial number of the credit line.

Function

function request(
address _requestTo,
uint256 _borrowLimit,
uint256 _borrowRate,
bool _autoLiquidation,
uint256 _collateralRatio,
address _borrowAsset,
address _collateralAsset,
bool _requestAsLender
) external returns (uint256) {

Approvals

None

Restrictions

Requires that the collateral and borrow asset chosen have a valid price feed

Arguments

  • _requestTo: address of the recipient. If msg.sender is the borrower, then _requestTo should be the lender's address, or vice versa
  • _borrowLimit: the maximum debt (principal+interest) that the borrower can have as part of the credit line. Once the limit is reached, the borrower cannot withdraw more capital from the credit line. Note that the borrower's actual debt can in fact exceed _borrowLimit because of accrual of interest. Including interest to calculate the max. debt applies soft pressure on the borrower to occasionally repay their debt since interest accrual slowly eats away their borrowing capacity
  • _borrowRate: simple interest rate that the borrower must provide
  • _autoLiquidation: If set as false only lender can liquidate the credit line. If set as true anyone can liquidate the credit line by calling the liquidate()
  • _collateralRatio: the ideal collateral ratio that the borrower must maintain for the credit line to be considered sufficiently collateralized. If the borrower's collateral ratio drops below they're liable for liquidation
  • _borrowAsset: asset the borrower wishes to borrow
  • _collateralAsset: asset the borrower will be putting up as collateral
  • _requestAsLender: If true msg.sender is the lender for the credit line, while _requestTo represents the borrower's address. The assignments are switched if this parameter is false

Accepting a credit line

Once a credit line is created, it needs to be accepted by the recipient for the credit line to be established. As soon as it is accepted, the borrower can start drawing credit from it.

Function

function accept(uint256 _id) external

Approvals

None

Restrictions

  • Only the recipient (_requestTo) can accept the credit line

Arguments

  • _id: The credit line identifier

Borrowing from a credit line

As soon as a credit line is activated, the borrower can start withdrawing capital from the credit line. This capital is withdrawn from the lender's savings account by iterating over the lender's balance in the supported savings strategies. The order of traversal within the strategy list is fixed at a protocol level.

Function

function borrow(uint256 _id, uint256 _amount)
external payable nonReentrant onlyCreditLineBorrower(_id) {

Approvals

  • None

Restrictions

  • The credit line identified by _id must be ACTIVE
  • msg.sender is the borrower of the said credit line
  • The borrower's total final debt be less than or equal to borrowLimit as defined by the credit line instance
  • Borrower's collateral ratio after the borrow must be greater than or equal to idealCollateralRatio as defined by the credit line instance

Arguments

  • _id: unique identifier of the credit line instance
  • _amount: amount (denominated in borrowAsset) that the borrower wishes to withdraw

Repaying credit line debt

As the borrower accummulates debt, both due to principal borrowing as well as interest accrual on the principal, the borrower can repay the debt to replenish their borrowing limit. Note that there are no specified repayment plans or intervals. Additionally, calling the repay() function does not require msg.sender to be the borrower of the credit line instance. This crucially allows others to repay a borrower's debt as well.
Any amount repaid first counts towards repaying the interest. Prinicipal repayment occurs only if there are no outstanding interests.

Function

function repay(
uint256 _id,
uint256 _amount,
bool _fromSavingsAccount
) external payable nonReentrant {

Approvals

None

Restrictions

  • The credit line identified by _id must be ACTIVE
  • Lender of the credit line cannot repay the credit line

Arguments

  • _id: unique identifier of the credit line instance
  • _amount: amount msg.sender wishes to repay
  • _fromSavingsAccount: if true, _amount is withdrawn by traversing through the msg.sender's Savings Account on Sublime. If false, _amount is directly transferred from msg.sender's wallet

Depositing Collateral

Collateral deposits might be necessary depending on the terms of the credit line instance. If the borrower's collateral ratio falls below _collateralRatio set during the credit line creation, the borrower becomes liable for liquidation. Hence, regular replenishment of collateral might be necessary. Additionally, note that msg.sender does not have to be the borrower of the credit line instance. This allows the borrower to transfer the collateral required from a different wallet address than the one associated with the credit line instance.

Function

function depositCollateral(
uint256 _id,
uint256 _amount,
address _strategy,
bool _fromSavingsAccount
) external payable nonReentrant ifCreditLineExists(_id) {

Approvals

None

Restrictions

  • The credit line identified by _id must be ACTIVE

Arguments

  • _id: unique identifier of the credit line instance
  • _amount: amount msg.sender wishes to deposit
  • _strategy: the savings strategy to which _amount collateral should be deployed. Note that if _fromSavingsAccount is true, this argument remains unused - a direct transfer of LP tokens takes place so that the original strategy remains intact
  • _fromSavingsAccount: If true collateral is transferred from msg.sender's Sublime Savings Account. If false collateral is transferred directly from msg.sender's wallet

Withdrawing collateral

Borrower can withdraw collateral from a credit line instance, as long as the borrower's collateral ratio after the withdrawal is greater than or equal to the _collateralRatio as defined during the credit line instantiation.

Function

function withdrawCollateral(
uint256 _id,
uint256 _amount,
bool _toSavingsAccount
) external nonReentrant onlyCreditLineBorrower(_id) {

Approvals

  • None

Restrictions

  • The credit line identified by _id must be ACTIVE
  • Borrower's collateral ratio due to the withdrawal cannot fall below the collateralRatio for the credit line instance
  • msg.sender must be the borrower of the credit line

Arguments

  • _id: unique identifier of the credit line instance
  • _amount: amount the msg.sender wishes to withdraw
  • _toSavingsAccount: If true, the collateral is withdrawn to the msg.sender's Sublime Savings Account through direct transfer of LP tokens. If false, collateral is withdrawn to the msg.sender address after conversion to base tokens

Liquidation

If the borrower's collateral ratio falls below _collateralRatio as defined during the credit line instantiation. This requires msg.sender to pay an amount equivalent to the value of the collateral denominated in the credit line's borrowAsset less the liquidation reward that is fixed at the protocol level. For example, if a credit line that is collateralized $1,000 WBTC is up for liquidation, and the borrowAsset is USDC, then the liquidator might have to repay $900 USDC ($100 WBTC is the liquidation reward).
Valid liquidators for a credit line are determined by the _autoLiquidate parameter set during credit line instantiation. If _autoLiquidate is set as false, only the lender of the credit line can call the liquidation function. If set as true, anyone can call liquidate the credit line instance by calling the liquidate() function. Collateral is transferred to the liquidator, while the amount repaid (if _autoLiquidate is true) by the liquidator is transferred to the lender's wallet address.
Furthermore, the entire collateral needs to be liquidated at once, ie, partial liquidations are not possible.

Function

function liquidate(uint256 _id, bool _toSavingsAccount)
external payable nonReentrant {

Approvals

  • None

Restrictions

  • The credit line identified by _id must be ACTIVE
  • The current collateral ratio of the credit line must be less than _collateralRatio set during instantiation

Arguments

  • _id: unique identifier of the credit line instance
  • _toSavingsAccount: If true, the collateral is withdrawn to the msg.sender's Sublime Savings Account through direct transfer of LP tokens. If false, collateral is withdrawn to the msg.sender address after conversion to base tokens (the collateralAsset)

Closing a credit line

An active credit line can be closed by either the borrower or the lender. Active debt by the borrower must be 0 for the credit line to be closed.

Function

function close(uint256 _id) external ifCreditLineExists(_id) {

Approvals

  • None

Restrictions

  • The credit line identified by _id must be ACTIVE
  • Total debt must be 0

Arguments

  • _id: unique identifier of the credit line instance

Flow

The typical flow is as follows:
  1. 1.
    Borrower/lender requests/grants credit line to the lender/borrower
  2. 2.
    Lender/borrower accepts the credit line. Allowance for credit line is set to allow withdrawals from the lender's credit line when the borrower wishes to withdraw
  3. 3.
    Borrower deposits collateral into the credit line's Savings Account
  4. 4.
    Borrower withdraws amount from the credit line if their current total debt + amount <= borrowLimit
  5. 5.
    Borrower can repay part of the credit line at any point
  6. 6.
    In case the borrower's collateral ratio crosses the liquidation threshold, the borrower can be liquidated
  7. 7.
    In case the current borrowed amount is 0, the credit line can be closed by the lender or the borrower
Simple interest is used to perform interest accruals. To perform all the required calculations, we keep track of
  • totalInterestRepaid - total amount repaid by the borrower
  • principal - principal borrowed
  • interestAccruedTillPrincipalUpdate - interest accrued before last principle update.
  • lastPrincipleUpdateTime - Timestamp at which principle was last updated
  • _interestSincePrincipalUpdate(temp) - interest accrued after a principal update.

Helpers

calculateBorrowableAmount

This function is used to calculateBorrowableAmount based on the collateral tokens for the credit line.
function calculateBorrowableAmount(uint256 _id) returns (uint256)
  • _id: The unique ID that represents the credit line
  • RETURN: The amount of tokens that can be borrowed
Note: The borrowableAmount depends on the price of the collateral and borrow tokens, so it might change with every block. So it is advisable to borrow a little less than the amount returned by the function to account for price fluctuations from the time of query. Ignore if the function is being called in the same block as the tx.

calculateCurrentDebt

This function is used to calculateCurrentDebt which includes principle and the interest accrued till that point.
function calculateCurrentDebt(uint256 _id) returns (uint256)
  • _id: The unique ID that represents the credit line
  • RETURN: The amount of debt till now
Note: currentDebt changes per block based on the time difference between blocks. So when trying to completely repay it is advised to repay a little higher than the value returned by the function to account for the difference in time between the query and the actual tx. Ignore if the query and repayment are done in same block.

calculateInterestAccrued

This function is used to calculate the interest accrued till the current block
function calculateInterestAccrued(uint256 _id) returns (uint256)
  • _id: The unique ID that represents the credit line
  • RETURN: The amount of interest accrued till now
Note: The interest accrued will change based on the block number it is queried at. So please account for any difference between the time of query and when it is used.

calculateCurrentCollateralRatio

This function is used to calculate the current collateral ratio of the credit line.
function calculateCurrentCollateralRatio(uint256 _id) returns (uint256)
  • _id: The unique ID that represents the credit line
  • RETURN: The collateral ratio at the time of query
Note: The collateral ratio depends on the price of collateral asset and borrow asset, hence can vary every block.

calculateTotalCollateralTokens

This function is used to calculate the current collateral tokens as they might change based on the strategy they are invested in.
function calculateTotalCollateralTokens(uint256 _id) returns (uint256)
  • _id: The unique ID that represents the credit line
  • RETURN: Total collateral tokens at the time of query
Note: Total collateral tokens depends on the strategy that is used and hence can change every block.

Error Codes

Error Code
Error Message
Function/Modifier name
CL1
Credit line does not exist
ifCreditLineExists
CL2
Only credit line Borrower can access
onlyCreditLineBorrower
CL3
Invalid Strategy
_updateDefaultStrategy
CL4
Protocol fee collector can't be 0 address
_updateProtocolFeeCollector
CL5
Strategy registry can't be 0 address
_updateStrategyRegistry
CL6
Reward fraction has to be less than 1
_updateLiquidatorRewardFraction
CL7
Function can only be called if credit line is ACTIVE or REQUESTED
calculateBorrowableAmount
CL8
Function cannot be called since credit line doesn't exist
updateinterestAccruedTillLastPrincipalUpdate
CL9
Borrow asset and collateral asset can't be the same
request
CL10
Price feed doesn't exist for the passed asset pair
request
CL11
Borrow limit is out of the allowed range
request
CL12
Borrow rate is out of the allowed range
request
CL13
Ideal collateral ratio is out of the allowed range
request
CL14
Borrower and lender cannot be the same address
request
CL15
Credit lines has already been accepted
accept
CL16
msg.sender is not valid
accept
CL17
Credit line is not active
depositCollateral
CL18
Lender cannot deposit collateral
depositCollateral
CL19
Lender cannot deposit collateral
_depositCollateral
CL20
ETH is not required for this operation
_depositCollateral
CL21
Credit line is not active
borrow
CL22
Requested amount cannot be withdrawn
borrow
CL23
Credit line is not active
repay
CL24
Lender address cannot repay
repay
CL25
ETH is not required for this operation
repay
CL26
msg.sender needs to be lender or borrower
close
CL27
Credit line is not active
close
CL28
Credit line cannot be closed since principal is non-zero
close
CL29
Credit line cannot be closed since interest is non-zero
close
CL30
msg.sender should be the borrower or lender
cancel
CL31
Credit line is not in the requested state
cancel
CL32
Collateral ratio cannot fall below the ideal collateral ratio
withdrawCollateral
CL33
Insufficient collateral
_transferCollateral
CL34
Credit line is not active
liquidate
CL35
ETH is not required for this operation
liquidate
CL36
Cannot liquidate since principal is 0
liquidate
CL37
Collateral ratio is above the liquidation threshold
liquidate