In the constructor, we initialize the ERC20 token that we wish to use as collateral and cToken contract address:
supply() - lender deposits collateral
Lender calls supply(uint _amount) to deposit ERC20 token as collateral and get cToken back as "receipt token":
When calling cToken.mint(), the ERC20 token in this contract will be transferred to the cToken contract via transferFrom(). This is why we have to do token.approve() first.
redeem() - lender withdraws collateral
This function is the opposite of supply(). Lender calls redeem() to burn cToken and get ERC20 token back (interest is included in cToken price):
This is just a wrapper that calls cToken.redeem().
Utility Functions
We need a getter to query cToken balance:
Query exchange rate and supply rate:
We can estimate underlying asset balance by the formula cTokenBal * exchangeRate. And figure out some messy decimals things:
Official API for querying underlying asset balance:
function supply(uint _amount) external {
// Step 1: transfer ERC20 token from lender's wallet to this contract
token.transferFrom(msg.sender, address(this), _amount);
// Step 2: approve cToken contract to spend the token we just transfered
token.approve(address(cToken), _amount);
// Step 3: mint cToken, equivalent to deposit collateral to Compound
// cToken.mint() returning 0 means function call succeeded
require(cToken.mint(_amount) == 0, "mint failed");
}
function redeem(uint _cTokenAmount) external {
// cToken.redeem() returning 0 means function call succeeded
require(cToken.redeem(_cTokenAmount) == 0, "redeem failed");
}
function getCTokenBalance() external view returns (uint) {
return cToken.balanceOf(address(this));
}
// not view function
function getInfo() external returns (uint exchangeRate, uint supplyRate) {
// Exchange rate between cToken and underlying token
// For example, cETH <-> ETH begins at 0.02 and is increased by APR
exchangeRate = cToken.exchangeRateCurrent();
// Amount added to you supply balance this block
// This is just the interest rate
supplyRate = cToken.supplyRatePerBlock();
}
// not view function
function balanceOfUnderlying() external returns (uint) {
// cToken.balanceOfUnderlying() returning 0 means function call succeeded
return cToken.balanceOfUnderlying(address(this));
}