In this section we are going to implement the borrower's functions borrow and repay. The following concepts will be covered:
collateral
account liquidity: calculate how much can I borrow?
open price feed: USD price of token to borrow
enter market and borrow
borrowed balance (includes interest)
borrow rate
repay borrow
Code:
Setup
Initialize Compound controller and price feed:
// borrow and repay //Comptroller public comptroller =Comptroller(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);PriceFeed public priceFeed =PriceFeed(0x922018674c12a7F0D394ebEEf9B58F186CdE13c1);
Collateral
Query collateral factor via comptroller.markets():
// collateralfunctiongetCollateralFactor() externalviewreturns (uint) { (bool isListed,uint colFactor,bool isComped) = comptroller.markets(address(cToken) );return colFactor; // divide by 1e18 to get in %}
Account Liquidity
How much can I borrow? We can query the maximal amount we can borrow via comptroller.getAccountLiquidity():
// account liquidity - calculate how much can I borrow?// sum of (supplied balance of market entered * col factor) - borrowedfunctiongetAccountLiquidity()externalviewreturns (uint liquidity,uint shortfall){// liquidity and shortfall in USD scaled up by 1e18 (uinterror,uint _liquidity,uint _shortfall) = comptroller.getAccountLiquidity(address(this) );// error == 0 means no errorrequire(error==0,"error");// normal circumstance - liquidity > 0 and shortfall == 0// liquidity > 0 means account can borrow up to `liquidity`// shortfall > 0 is subject to liquidation, you borrowed over limitreturn (_liquidity, _shortfall);}
shortfall > 0 means borrowing amount exceeds limit and the collateral is facing liquidation. Under normal circumstances we want liquidity > 0 and shortfall == 0.
_liquidity is in USD.
Price Feed
USD price for borrowing token can be queried via priceFeed.getUnderlyingPrice():
// open price feed - USD price of token to borrowfunctiongetPriceFeed(address_cToken) externalviewreturns (uint) {// scaled up by 1e18return priceFeed.getUnderlyingPrice(_cToken);}
We need this function to compute how many cTokens we can borrow, since _liquidity divided by price gives us the amount of cTokens we can borrow.
borrow() - borrower enters market and borrows loan
We are going to build the borrow() function on top of the helper functions we just wrote. Here is the plan:
Step 1: enter market
Step 2: check account liquidity (how much we can borrow in USD)
Step 3: calculate max amount of cTokens that we can borrow
Step 4: borrow 50% of max borrow
Step 1: enter market
// enter market// enter the supply market so you can borrow another type of assetaddress[] memory cTokens =newaddress[](1);cTokens[0] =address(cToken);uint[] memory errors = comptroller.enterMarkets(cTokens);require(errors[0] ==0,"Comptroller.enterMarkets failed.");
Step 2: check account liquidity (how much we can borrow in USD)
Step 3: calculate max amount of cTokens that we can borrow
// calculate max borrowuint price = priceFeed.getUnderlyingPrice(_cTokenToBorrow);// liquidity - USD scaled up by 1e18// price - USD scaled up by 1e18// decimals - decimals of token to borrowuint maxBorrow = (liquidity * (10**_decimals)) / price;require(maxBorrow >0,"max borrow = 0");
Step 4: borrow 50% of max borrow
// borrow 50% of max borrowuint amount = (maxBorrow *50) /100;require(CErc20(_cTokenToBorrow).borrow(amount) ==0,"borrow failed");
Here is the complete implementation of borrow():
// enter market and borrowfunctionborrow(address_cTokenToBorrow,uint_decimals) external {// enter market// enter the supply market so you can borrow another type of assetaddress[] memory cTokens =newaddress[](1); cTokens[0] =address(cToken);uint[] memory errors = comptroller.enterMarkets(cTokens);require(errors[0] ==0,"Comptroller.enterMarkets failed.");// check liquidity (uinterror,uint liquidity,uint shortfall) = comptroller.getAccountLiquidity(address(this) );require(error==0,"error");require(shortfall ==0,"shortfall > 0");require(liquidity >0,"liquidity = 0");// calculate max borrowuint price = priceFeed.getUnderlyingPrice(_cTokenToBorrow);// liquidity - USD scaled up by 1e18// price - USD scaled up by 1e18// decimals - decimals of token to borrowuint maxBorrow = (liquidity * (10**_decimals)) / price;require(maxBorrow >0,"max borrow = 0");// borrow 50% of max borrowuint amount = (maxBorrow *50) /100;require(CErc20(_cTokenToBorrow).borrow(amount) ==0,"borrow failed");}
Two utility functions related to borrow:
// borrowed balance (includes interest)// not view functionfunctiongetBorrowedBalance(address_cTokenBorrowed) publicreturns (uint) {returnCErc20(_cTokenBorrowed).borrowBalanceCurrent(address(this));}// borrow ratefunctiongetBorrowRatePerBlock(address_cTokenBorrowed) externalviewreturns (uint) {// scaled up by 1e18returnCErc20(_cTokenBorrowed).borrowRatePerBlock(); }
repay() - borrower repays loan
Repay the borrowed cTokens via CErc20.repayBorrow():