Lender calls supply(uint _amount) to deposit ERC20 token as collateral and get cToken back as "receipt token":
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");
}
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):
function redeem(uint _cTokenAmount) external {
// cToken.redeem() returning 0 means function call succeeded
require(cToken.redeem(_cTokenAmount) == 0, "redeem failed");
}
This is just a wrapper that calls cToken.redeem().
Utility Functions
We need a getter to query cToken balance:
function getCTokenBalance() external view returns (uint) {
return cToken.balanceOf(address(this));
}
Query exchange rate and supply rate:
// 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();
}
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:
// not view function
function balanceOfUnderlying() external returns (uint) {
// cToken.balanceOfUnderlying() returning 0 means function call succeeded
return cToken.balanceOfUnderlying(address(this));
}
Tests
In the setup, we create a whale user with each WBTC to run this demo: