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.
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).
- by deploying the contract
- gaining ownership from previous owner
- Can transfer ownership to another admin
- Can update logic contract implementation addresses
- 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
- Can request or accept a credit line
- Can borrow from credit line
- Can add/withdraw collateral, repay, or close the credit line
- 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
- Can offer or accept a credit line request
- Can liquidate the credit line. Will be the only liquidator if
autoLiquidation
is set tofalse
- Can close the credit line
- If
autoLiquidation
istrue
, any one can act as liquidator by callingliquidate()
, if set as false, only lender can be the liquidator
- 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
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 request(
address _requestTo,
uint256 _borrowLimit,
uint256 _borrowRate,
bool _autoLiquidation,
uint256 _collateralRatio,
address _borrowAsset,
address _collateralAsset,
bool _requestAsLender
) external returns (uint256) {
None
Requires that the collateral and borrow asset chosen have a valid price feed
_requestTo
: address of the recipient. Ifmsg.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 asfalse
only lender can liquidate the credit line. If set astrue
anyone can liquidate the credit line by calling theliquidate()
_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
: Iftrue
msg.sender
is the lender for the credit line, while_requestTo
represents the borrower's address. The assignments are switched if this parameter isfalse
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 accept(uint256 _id) external
None
- Only the recipient (
_requestTo
) can accept the credit line
_id
: The credit line identifier
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 borrow(uint256 _id, uint256 _amount)
external payable nonReentrant onlyCreditLineBorrower(_id) {
- None
- The credit line identified by
_id
must beACTIVE
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
_id
: unique identifier of the credit line instance_amount
: amount (denominated inborrowAsset
) that the borrower wishes to withdraw
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 repay(
uint256 _id,
uint256 _amount,
bool _fromSavingsAccount
) external payable nonReentrant {
None
- The credit line identified by
_id
must beACTIVE
- Lender of the credit line cannot repay the credit line
_id
: unique identifier of the credit line instance_amount
: amountmsg.sender
wishes to repay_fromSavingsAccount
: iftrue
,_amount
is withdrawn by traversing through themsg.sender
's Savings Account on Sublime. Iffalse
,_amount
is directly transferred frommsg.sender
's wallet
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 depositCollateral(
uint256 _id,
uint256 _amount,
address _strategy,
bool _fromSavingsAccount
) external payable nonReentrant ifCreditLineExists(_id) {
None
- The credit line identified by
_id
must beACTIVE
_id
: unique identifier of the credit line instance_amount
: amountmsg.sender
wishes to deposit_strategy
: the savings strategy to which_amount
collateral should be deployed. Note that if_fromSavingsAccount
istrue
, this argument remains unused - a direct transfer of LP tokens takes place so that the original strategy remains intact_fromSavingsAccount
: Iftrue
collateral is transferred frommsg.sender
's Sublime Savings Account. Iffalse
collateral is transferred directly frommsg.sender
's wallet
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 withdrawCollateral(
uint256 _id,
uint256 _amount,
bool _toSavingsAccount
) external nonReentrant onlyCreditLineBorrower(_id) {
- None
- The credit line identified by
_id
must beACTIVE
- 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
_id
: unique identifier of the credit line instance_amount
: amount themsg.sender
wishes to withdraw_toSavingsAccount
: Iftrue
, the collateral is withdrawn to themsg.sender
's Sublime Savings Account through direct transfer of LP tokens. Iffalse
, collateral is withdrawn to themsg.sender
address after conversion to base tokens
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 liquidate(uint256 _id, bool _toSavingsAccount)
external payable nonReentrant {
- None
- The credit line identified by
_id
must beACTIVE
- The current collateral ratio of the credit line must be less than
_collateralRatio
set during instantiation
_id
: unique identifier of the credit line instance_toSavingsAccount
: Iftrue
, the collateral is withdrawn to themsg.sender
's Sublime Savings Account through direct transfer of LP tokens. Iffalse
, collateral is withdrawn to themsg.sender
address after conversion to base tokens (thecollateralAsset
)
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 close(uint256 _id) external ifCreditLineExists(_id) {
- None
- The credit line identified by
_id
must beACTIVE
Total debt must be 0
_id
: unique identifier of the credit line instance
The typical flow is as follows:
- 1.Borrower/lender requests/grants credit line to the lender/borrower
- 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.Borrower deposits collateral into the credit line's Savings Account
- 4.Borrower withdraws amount from the credit line if their current total debt + amount <= borrowLimit
- 5.Borrower can repay part of the credit line at any point
- 6.In case the borrower's collateral ratio crosses the liquidation threshold, the borrower can be liquidated
- 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.
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 lineRETURN
: 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.
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 lineRETURN
: 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.
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 lineRETURN
: 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.
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 lineRETURN
: 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.
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 lineRETURN
: 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 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 |
Last modified 1yr ago