Pool Contract
In the following sections we elaborate the Pool.sol specification.
The Pool.sol contract handles the core logic required to implement pool-based borrowing. It handles important functions such as lending, borrowing, repayments, etc.
- by deploying the contract
- gaining ownership from previous admin
- can transfer ownership to new admin
- can update the pool logic
- can update thresholds for relevant parameters
Functions performed by the admin are meant to be transferred to governance over time.
- by pool creation
- can call functions surrounding the loan - withdrawing amount raised, repayments, responding to margin calls, etc.
- Having possession of the pool's tokens
- can supply liquidity, withdraw repayments, or execute margin calls on the borrower
Once the collection period for a pool ends, the borrower can start withdrawing liquidity from the pool. Withdrawing the borrowed amount must be done within the withdrawal period. Having a withdrawal period ensures that the borrower cannot maliciously lock away capital from lenders by never withdrawing assets from the pool.
function withdrawBorrowedAmount()
external override onlyBorrower(msg.sender) nonReentrant {
- None
- current time must be greater than
loanStartTime
and less than theloanWithdrawalDeadline
msg.sender
should be the borrower as defined through pool creation- the total amount collected in the pool must be greater than or equal to the minimum borrow amount
- the pool's current collateral ratio must be greater than or equal to
idealCollateralRatio
- None -
msg.sender
has to be the borrower
Lenders can deposit liquidity into a pool during the collection period. Liquidity deposited cannot be withdrawn unless one of the following conditions are met:
- the pool is terminated due to malicious activity
- the pool is cancelled by the borrower
- the borrower fails to withdraw the loan amount before the
loanWithdrawalDeadline
- the borrower repays the loan at the end of the loan duration
- the pool is liquidated due to late repayments or a margin call by the lender
function lend(
address _lender,
uint256 _amount,
bool _fromSavingsAccount
) external payable nonReentrant {
- None
- If the pool creator has specified a
lenderVerifier
then the lender must be verified by them - the loan must be in the collection period
_lender
: address of the lender. Note that themsg.sender
need not be_lender
_amount
: amount the lender wishes to lend_fromSavingsAccount
: iftrue
,_amount
frommsg.sender
's Sublime Savings Account is withdrawn. Iffalse
_amount
is directly transferred frommsg.sender
's wallet address
An entire pool can be liquidated in case of missed repayments. In case the normal interval deadline is missed, the borrower enters a grace period, during which it is still possible for them to repay any interests due within that period. The borrower further has the possibility of requesting for an extension of the deadline for any given instalment period. However, each pool can only receive a single extension. In case all of the above measures fail, a liquidator can liquidate the pool collateral to receive the pool's collateral and the liquidation reward.
function liquidatePool(
bool _fromSavingsAccount,
bool _toSavingsAccount,
bool _recieveLiquidityShare
) external payable nonReentrant {
- None
- the pool must be
ACTIVE
- the borrower is currently in default
_fromSavingsAccount
: iftrue
, liquidity frommsg.sender
's Sublime Savings Account is used to buy out the collateral. Iffalse
,msg.sender
directly transfers liquidity from their wallet_toSavingsAccount
: iftrue
, the liquidated collateral is transferred tomsg.sender
's Sublime Savings Account. Iffalse
, the liquidated collateral is transferred tomsg.sender
's wallet_receiveLiquidityShare
: Iftrue
, liquidated collateral is directly transferred as LP tokens. Iffalse
, liquidated collateral is first converted to base tokens before transferring tomsg.sender
Lenders can use margin calls to request the borrower to add additional collateral to the pool in case they fall below
idealCollateralRatio
. If the borrower fails to meet a margin call, a liquidator can liquidate the lender's position in the pool by transferring an amount (denominated in borrowAsset
) equal to the value of the collateral backing the lender's position. function liquidateForLender(
address _lender,
bool _fromSavingsAccount,
bool _toSavingsAccount,
bool _recieveLiquidityShare
) external payable nonReentrant {
- None
- loan status must be
ACTIVE
- the current time must be greater than or equal to
marginCallEndTime
idealCollateralRatio
must be greater than the borrower's collateral ratio wrt the lender that executed the margin call_lender
must be a valid lender in the pool
_lender
: address of the lender whose position is being liquidated_fromSavingsAccount
: iftrue
, liquidity frommsg.sender
's Sublime Savings Account is used to buy out the collateral. Iffalse
,msg.sender
directly transfers liquidity from their wallet_toSavingsAccount
: iftrue
, the liquidated collateral is transferred tomsg.sender
's Sublime Savings Account. Iffalse
, the liquidated collateral is transferred tomsg.sender
's wallet_receiveLiquidityShare
: Iftrue
, liquidated collateral is directly transferred as LP tokens. Iffalse
, liquidated collateral is first converted to base tokens before transferring tomsg.sender
As the borrower repays the loan, lenders can start withdrawing them. The amount that a given lender can withdraw depends on the number of pool tokens in their possession, and the amount of interest they've already withdrawn. Repayments are directly transferred to
msg.sender
's wallet address.function withdrawRepayment()
external isLender(msg.sender) nonReentrant {
- None
msg.sender
must possess valid pool tokens in their wallet
- None:
msg.sender
should be a valid lender (ie, possess pool tokens)
Due to price volatilities, the borrower's collateral ratio can often drop. To prevent their collateral ratio from dropping below
idealCollateralRatio
, borrowers can deposit extra collateral throughout the loan duration.function depositCollateral(uint256 _amount, bool _transferFromSavingsAccount)
external payable override {
- None
- None
_amount
: The amount of collateralmsg.sender
wishes to deposit_transferFromSavingsAccount
: Iftrue
, collateral is directly transferred frommsg.sender
's Sublime Savings Account
In case of individual margin calls, a borrower might be requested to deposit extra collateral. Note that the collateral only goes to cover the lender that requested the margin call. The borrower only has a set amount of time since the beginning of the margin call for the excess collateral to be added. If they fail to do so, collateral backing the lender might be liquidated.
function addCollateralInMarginCall(
address _lender,
uint256 _amount,
bool _transferFromSavingsAccount
) external payable override nonReentrant {
- None
- loan status must be
ACTIVE
- the current time must be less than or equal to the
marginCallEndTime
_lender
: address of the lender that has an active margin call_amount
: amount of collateralmsg.sender
wishes to transfer_transferFromSavingsAccount
: Iftrue
, collateral is directly transferred frommsg.sender
's Sublime Savings Account. Iffalse
, collateral is transferred frommsg.sender
's wallet
At the end of the loan period, a pool is closed automatically when the borrower repays the last instalment. At this point, the borrower's collateral is transferred to the borrower's wallet address.
function closeLoan()
external payable override nonReentrant onlyRepaymentImpl {
- None
- only repayment contract can call this functino
- the current status of the loan must be
ACTIVE
- None
Lenders can withdraw liquidity from a pool if it is
CLOSED
, CANCELLED
, DEFAULTED
, or TERMINATED
. They receive liquidity proportional to the number of pool tokens they hold.function withdrawLiquidity()
external isLender(msg.sender) nonReentrant {
- None
- the pool status must match
CLOSED
,CANCELLED
,DEFAULTED
, orTERMINATED
- None:
msg.sender
's balance is checked for the relevant pool tokens
The following describes the typical flow while creating loan requests via pools:
- Borrower can create a pool by posting a collateral and specifying the various parameters for the pool.
- Lenders can lend borrow tokens to the pool in return for poolTokens till the pool start time
- If the total amount lent is higher than the min amount specified by borrower, then pool starts.
- If the total amount lent is lower than the min amount specified, then pool is cancelled and borrower can withdraw their collateral without any penalty and lenders can withdraw the lent amount by burning the poolTokens.
- If the pool starts, borrower can still cancel the pool within the withdrawal deadline till they withdraw the lent amount. But borrower will have to pay penalty based on the time between pool start and pool cancel times. Penalty received is distributed to the lenders in the proportion of poolTokens they hold.
- Pool can liquidated if repayments aren't correctly made or collateral ratio is not maintained above threshold.
- In case repayments not made, any one can liquidate the pool in return for a part of collateral as incentive. Liquidator has to supply borrow tokens equivalent to the collateral - (liquidator incentive) while liquidation.
- In case of collateral ratio not maintained above threshold, any lender can liquidate collateral proportional to the poolTokens they hold by making margin calls.
- Once a margin call is made, borrower has to supply enough collateral specific to the lender who made the margin call, so that borrower's collateral ratio is higher than the threshold. The collateral supplied is specific to the lender and can only be liquidated for that lender.
- If all repayments are made as per the pool parameters, the pool will be closed as soon as the principal is repaid and collateral is returned back to the borrower.
This function is used to query parameters which are set while creating pool and are constant
function poolConstants() returns (
address borrower,
uint256 borrowAmountRequested,
uint256 minborrowAmount,
uint256 loanStartTime,
uint256 loanWithdrawalDeadline,
address borrowAsset,
uint256 idealCollateralRatio,
uint256 borrowRate,
uint256 noOfRepaymentIntervals,
uint256 repaymentInterval,
address collateralAsset,
address poolSavingsStrategy
)
borrower
: Borrower requesting loan from the poolborrowAmountRequested
: Maximum amount of borrowAsset tokens requestedminborrowAmount
: Minimum amount of borrowAsset tokens below which pool will be cancelledloanStartTime
: Timestamp till which borrowAsset tokens can be lent and at which the loan startsloanWithdrawalDeadline
: Timestamp till which borrower can withdraw lent tokens after loan startsborrowAsset
: Address of token which is being borrowedidealCollateralRatio
: Ratio of collateral to the totalDebt (principal + interest) which is to be maintained subject to a volatility threshold that can be queried from poolFactory (link here). This parameter is multiplied byborrowRate
: Rate of interest per annum multiplied bynoOfRepaymentIntervals
: Number of intervals in which repayment has to be maderepaymentInterval
: Time in seconds per repayment intervalcollateralAsset
: Address of token which is posted as collateralpoolSavingsStrategy
: Address of strategy into which collateral tokens are invested while pool is active
This function is used to query the variables used to maintain the state of the Pool
function poolVars() returns (
uint256 baseLiquidityShares,
uint256 extraLiquidityShares,
LoanStatus loanStatus,
uint256 penalityLiquidityAmount
)
RETURNS
baseLiquidityShares
: Liquidity shares received by investing the collateral in pool's strategyextraLiquidityShares
: Liquidity shares received by investing the collateral added as part of margin callspenalityLiquidityAmount
: Amount of collateral held as penalty for cancelling the pool
This function is used to query the details of lender to the pool
function lenders(address lender) returns (
uint256 principalWithdrawn,
uint256 interestWithdrawn,
uint256 lastVoteTime,
uint256 marginCallEndTime,
uint256 extraLiquidityShares
)
lender
: Lender of the poolRETURNS
:interestWithdrawn
: Interest withdrawn by the lender till nowmarginCallEndTime
: End time of margin call if call is made, otherwise 0extraLiquidityShares
: Liquidity Shares for the extra collateral received from borrower as part of margin calls
This function is used to query the interest that is outstanding at the time of call
function interestTillNow() view returns(uint256 interest)
interest
: Interest that is outstanding till now
Note: The interest changes with every second, hence every block. So please keep in mind that interest returned by the above function is at the time of query.
This function is used to query the collateral ratio of any user, given the balance of the user and total collateral allocated to the user.
function calculateCollateralRatio(uint256 balance, uint256 liquidityShares) returns (uint256 ratio)
balance
: Pool Token balance of user to calculate collateral ratioliquidityShares
: Liquidity shares of collateral to calculate collateral ratioRETURNS
:ratio
: Collateral ratio calculated
This function is used to query current collateral ratio of pool
function getCurrentCollateralRatio() returns (uint256 ratio)
RETURNS
: Collateral ratio of the pool
Note: Collateral ratio might change every block as prices of the assets might change every block. Hence note that collateral ratio returned is for the block at which query is made.
This function is used to query current collateral ratio of lender
function getCurrentCollateralRatio(address lender) returns (uint256 ratio)
lender
: Address of lenderRETURNS
: Collateral ratio of the pool
Note: Collateral ratio might change every block as prices of the assets might change every block. Hence note that collateral ratio returned is for the block at which query is made.
This function is used to query interest per second for a specified principal
function interestPerSecond(uint256 principal) view returns (uint256)
principal
: Principal for which interestPerSecond is calculatedRETURNS
: Interest per second for the specified principal multiplied by
This function is used to query interest per instalment period for a specified principal
function interestPerPeriod(uint256 principal) view returns (uint256)
principal
: Principal for which interestPerPeriod is calculatedRETURNS
: Interest per period for the specified principal multiplied by
This function is used to calculate the current instalment period of the pool
function calcualteCurrentPeriod() returns (uint256)
RETURNS
: Current Instalment period
This function is used to query the amount of borrow tokens that can be withdrawn as repayment
function calculateRepaymentWithdrawable(address lender) returns (uint256)
lender
: Lender to calculate repayments received forRETURNS
: Repayment that lender can withdraw
This function is used to query the end time of the margin call for a lender
function getMarginCallEndTime(address lender) view returns (uint256)
lender
: Lender to calculate margin call end time forRETURNS
: Timestamp at which margin call will end, if margin call is active otherwise 0
This function is used to query the total amount of tokens lent to the Pool
function totalSupply() view rfunction totalSupply() public view
override(ERC20Upgradeable, IPool) returns (uint256)
RETURNS
: Total number of borrow tokens lent to the pool
As borrow tokens cannot be withdrawn or lent while pool is active, this function will returns constant value while pool is active.
This function is used to query the status of the Pool
function getLoanStatus() view returns (uint256)
RETURNS
: Status of the pool, reference to the returned values is below
LoanStatus | Value |
COLLECTION | 0 |
ACTIVE | 1 |
CLOSED | 2 |
CANCELLED | 3 |
DEFAULTED | 4 |
TERMINATED | 5 |
This function is used to query equivalent tokens for an amount given source and target tokens based on their prices
function getEquivalentTokens(address source, address target, uint256 amount) returns (uint256)
source
: Address of the source tokentarget
: Address of the target token in which equivalent tokens are to be calculatedamount
: Amount of source tokens to calculate equivalent target tokens forRETURNS
: Equivalent target tokens for the amount of source tokens specified
Note: Equivalent tokens might change every block as prices of the assets might change every block. Hence note that equivalent tokens returned is for the block at which query is made.
This function is used to query borrower of the pool
function borrower() view returns (address)
RETURNS
: Address of the borrower of the poolError code | Error Message | function/modifier |
OB1 | Not Borrower | OnlyBorrower |
IL1 | Not Lender | isLender |
OO1 | Not Owner | onlyOwner |
OR1 | Not Repayments contract | onlyRepaymentImpl |
DC1 | can’t deposit 0 | depositCollateral |
DC2 | Lender can’t deposit collateral | depositCollateral |
ID1 | Insufficient collateral | _initialDeposit |
ACMC1 | Pool not active | addCollateralInMarginCall |
ACMC2 | Lender can’t deposit collateral | addCollateralInMarginCall |
ACMC3 | Margin call ended | addCollateralInMarginCall |
ACMC4 | can’t deposit 0 | addCollateralInMarginCall |
WBA1 | Pool hasn’t started or withdrawal deadline passed | withdrawBorrowedAmount |
WBA2 | Minimum borrowable amount not reached | withdrawBorrowedAmount |
WBA3 | insufficient collateral | withdrawBorrowedAmount |
L1 | Borrower can’t lend | lend |
L2 | Lender not verified | lend |
L3 | Not in collection period | lend |
TT1 | Token transfers paused | _beforeTokenTransfer |
TT2 | can’t transfer to borrower | _beforeTokenTransfer |
TT3 | Margin call active for sender | _beforeTokenTransfer |
TT4 | Margin call active for receiver | _beforeTokenTransfer |
CP1 | Pool not in collection stage or Loan already withdrawn | cancelPool |
CP2 | only borrower before loan withdrawal deadline | cancelPool |
LCP1 | Not cancelled | liquidateCancelPenalty |
LCP2 | No penality | liquidateCancelPenalty |
CL1 | Pool not active | closeLoan |
WL1 | can’t withdraw when pool is in collection or active stage | withdrawLiquidity |
RMC1 | Pool not active | requestMarginCall |
RMC2 | Margin call active | requestMarginCall |
RMC3 | Collateral sufficient | requestMarginCall |
LP1 | Pool not active | liquidatePool |
LP2 | didn’t default | liquidatePool |
CLBL1 | loan withdrawal deadline not complete | _canLenderBeLiquidated |
CLBL2 | No margin call | _canLenderBeLiquidated |
CLBL3 | Margin call hasn’t ended | _canLenderBeLiquidated |
CLBL4 | collateral sufficient | _canLenderBeLiquidated |
CLBL5 | Not a lender | _canLenderBeLiquidated |
Last modified 1yr ago