Search
⌃K

Pool Contract

In the following sections we elaborate the Pool.sol specification.

Purpose

The Pool.sol contract handles the core logic required to implement pool-based borrowing. It handles important functions such as lending, borrowing, repayments, etc.

Roles

Admin

Assignment

  • by deploying the contract
  • gaining ownership from previous admin

Permissions

  • can transfer ownership to new admin
  • can update the pool logic
  • can update thresholds for relevant parameters

Note

Functions performed by the admin are meant to be transferred to governance over time.

Borrower

Assignment

  • by pool creation

Permissions

  • can call functions surrounding the loan - withdrawing amount raised, repayments, responding to margin calls, etc.

Lender

Assignment

  • Having possession of the pool's tokens

Permissions

  • can supply liquidity, withdraw repayments, or execute margin calls on the borrower

Functionality

Borrowing from a Pool

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

function withdrawBorrowedAmount()
external override onlyBorrower(msg.sender) nonReentrant {

Approvals

  • None

Restrictions

  • current time must be greater than loanStartTime and less than the loanWithdrawalDeadline
  • 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

Arguments

  • None - msg.sender has to be the borrower

Supplying capital to a Pool

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

function lend(
address _lender,
uint256 _amount,
bool _fromSavingsAccount
) external payable nonReentrant {

Approvals

  • None

Restrictions

  • If the pool creator has specified a lenderVerifier then the lender must be verified by them
  • the loan must be in the collection period

Arguments

  • _lender: address of the lender. Note that the msg.sender need not be _lender
  • _amount: amount the lender wishes to lend
  • _fromSavingsAccount: if true, _amount from msg.sender's Sublime Savings Account is withdrawn. If false _amount is directly transferred from msg.sender's wallet address

Liquidating a Pool

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

function liquidatePool(
bool _fromSavingsAccount,
bool _toSavingsAccount,
bool _recieveLiquidityShare
) external payable nonReentrant {

Approvals

  • None

Restrictions

  • the pool must be ACTIVE
  • the borrower is currently in default

Arguments

  • _fromSavingsAccount: if true, liquidity from msg.sender's Sublime Savings Account is used to buy out the collateral. If false, msg.sender directly transfers liquidity from their wallet
  • _toSavingsAccount: if true, the liquidated collateral is transferred to msg.sender's Sublime Savings Account. If false, the liquidated collateral is transferred to msg.sender's wallet
  • _receiveLiquidityShare: If true, liquidated collateral is directly transferred as LP tokens. If false, liquidated collateral is first converted to base tokens before transferring to msg.sender

Liquidating a margin call

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

function liquidateForLender(
address _lender,
bool _fromSavingsAccount,
bool _toSavingsAccount,
bool _recieveLiquidityShare
) external payable nonReentrant {

Approvals

  • None

Restrictions

  • 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

Arguments

  • _lender: address of the lender whose position is being liquidated
  • _fromSavingsAccount: if true, liquidity from msg.sender's Sublime Savings Account is used to buy out the collateral. If false, msg.sender directly transfers liquidity from their wallet
  • _toSavingsAccount: if true, the liquidated collateral is transferred to msg.sender's Sublime Savings Account. If false, the liquidated collateral is transferred to msg.sender's wallet
  • _receiveLiquidityShare: If true, liquidated collateral is directly transferred as LP tokens. If false, liquidated collateral is first converted to base tokens before transferring to msg.sender

Withdrawing repayments from pool

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

function withdrawRepayment()
external isLender(msg.sender) nonReentrant {

Approvals

  • None

Restrictions

  • msg.sender must possess valid pool tokens in their wallet

Arguments

  • None: msg.sender should be a valid lender (ie, possess pool tokens)

Adding collateral to a pool

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

function depositCollateral(uint256 _amount, bool _transferFromSavingsAccount)
external payable override {

Approvals

  • None

Restrictions

  • None

Arguments

  • _amount: The amount of collateral msg.sender wishes to deposit
  • _transferFromSavingsAccount: If true, collateral is directly transferred from msg.sender's Sublime Savings Account

Adding collateral to a margin call

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

function addCollateralInMarginCall(
address _lender,
uint256 _amount,
bool _transferFromSavingsAccount
) external payable override nonReentrant {

Approvals

  • None

Restrictions

  • loan status must be ACTIVE
  • the current time must be less than or equal to the marginCallEndTime

Arguments

  • _lender: address of the lender that has an active margin call
  • _amount: amount of collateral msg.sender wishes to transfer
  • _transferFromSavingsAccount: If true, collateral is directly transferred from msg.sender's Sublime Savings Account. If false, collateral is transferred from msg.sender's wallet

Closing a pool

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

function closeLoan()
external payable override nonReentrant onlyRepaymentImpl {

Approvals

  • None

Restrictions

  • only repayment contract can call this functino
  • the current status of the loan must be ACTIVE

Arguments

  • None

Withdrawing liquidity from a pool

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

function withdrawLiquidity()
external isLender(msg.sender) nonReentrant {

Approvals

  • None

Restrictions

  • the pool status must match CLOSED, CANCELLED, DEFAULTED, or TERMINATED

Arguments

  • None: msg.sender's balance is checked for the relevant pool tokens

Flow

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.

Helpers

PoolConstants

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 pool
  • borrowAmountRequested : Maximum amount of borrowAsset tokens requested
  • minborrowAmount : Minimum amount of borrowAsset tokens below which pool will be cancelled
  • loanStartTime : Timestamp till which borrowAsset tokens can be lent and at which the loan starts
  • loanWithdrawalDeadline : Timestamp till which borrower can withdraw lent tokens after loan starts
  • borrowAsset : Address of token which is being borrowed
  • idealCollateralRatio : 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 by
    103010^{30}
  • borrowRate : Rate of interest per annum multiplied by
    103010^{30}
  • noOfRepaymentIntervals : Number of intervals in which repayment has to be made
  • repaymentInterval : Time in seconds per repayment interval
  • collateralAsset : Address of token which is posted as collateral
  • poolSavingsStrategy : Address of strategy into which collateral tokens are invested while pool is active

PoolVars

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 strategy
    • extraLiquidityShares : Liquidity shares received by investing the collateral added as part of margin calls
    • loanStatus : Status of the Pool (ref)
    • penalityLiquidityAmount : Amount of collateral held as penalty for cancelling the pool

Lenders

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 pool
  • RETURNS :
    • interestWithdrawn : Interest withdrawn by the lender till now
    • marginCallEndTime : End time of margin call if call is made, otherwise 0
    • extraLiquidityShares : Liquidity Shares for the extra collateral received from borrower as part of margin calls

InterestTillNow

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.

calculateCollateralRatio

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 ratio
  • liquidityShares : Liquidity shares of collateral to calculate collateral ratio
  • RETURNS :
    • ratio : Collateral ratio calculated

getCurrentCollateralRatio

Pool

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.

Lender

This function is used to query current collateral ratio of lender
function getCurrentCollateralRatio(address lender) returns (uint256 ratio)
  • lender : Address of lender
  • 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.

interestPerSecond

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 calculated
  • RETURNS : Interest per second for the specified principal multiplied by
    103010^{30}

interestPerPeriod

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 calculated
  • RETURNS : Interest per period for the specified principal multiplied by
    103010^{30}

calculateCurrentPeriod

This function is used to calculate the current instalment period of the pool
function calcualteCurrentPeriod() returns (uint256)
  • RETURNS : Current Instalment period

calculateRepaymentWithdrawable

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 for
  • RETURNS : Repayment that lender can withdraw

getMarginCallEndTime

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 for
  • RETURNS : Timestamp at which margin call will end, if margin call is active otherwise 0

totalSupply

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.

getLoanStatus

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

getEquivalentTokens

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 token
  • target : Address of the target token in which equivalent tokens are to be calculated
  • amount : Amount of source tokens to calculate equivalent target tokens for
  • RETURNS : 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.

borrower

This function is used to query borrower of the pool
function borrower() view returns (address)
RETURNS : Address of the borrower of the pool

Error Codes

Error 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