# Supply and Redeem

## Intro

{% embed url="<https://youtu.be/dHKLcbqFzvE>" %}
Supply and Redeem
{% endembed %}

`TestCompoundErc20.sol` provides the following 4 functionalities:

* `supply()` (lender deposits collateral)
* `redeem()` (lender withdraws collateral)
* `borrow()` (borrower enters market and borrows loan)
* `repay()` (borrower pays back loan)

In this section we are going to implement the lender's functions `supply` and `redeem`. The sample code is here:

{% embed url="<https://github.com/stakewithus/defi-by-example/blob/main/contracts/TestCompoundErc20.sol>" %}
TestCompoundErc20.sol
{% endembed %}

## Setup

In the constructor, we initialize the ERC20 token that we wish to use as collateral and cToken contract address:

<pre class="language-solidity"><code class="lang-solidity">// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/compound.sol";

// supply()
// redeem()
// borrow()
// repay()

<strong>contract TestCompoundErc20 {
</strong>    IERC20 public token;
    CErc20 public cToken;

    constructor(address _token, address _cToken) {
        token = IERC20(_token);
        cToken = CErc20(_cToken);
    }
}
</code></pre>

## supply() - lender deposits collateral

Lender calls `supply(uint _amount)` to deposit ERC20 token as collateral and get cToken back as "receipt token":

```solidity
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):

```solidity
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:

```solidity
function getCTokenBalance() external view returns (uint) {
    return cToken.balanceOf(address(this));
}
```

Query exchange rate and supply rate:

```solidity
// 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:

```solidity
// not view function
function estimateBalanceOfUnderlying() external returns (uint) {
    uint cTokenBal = cToken.balanceOf(address(this));
    uint exchangeRate = cToken.exchangeRateCurrent();
    uint decimals = 8; // WBTC = 8 decimals
    uint cTokenDecimals = 8;

    return (cTokenBal * exchangeRate) / 10**(18 + decimals - cTokenDecimals);
}
```

Official API for querying underlying asset balance:

```solidity
// not view function
function balanceOfUnderlying() external returns (uint) {
    // cToken.balanceOfUnderlying() returning 0 means function call succeeded
    return cToken.balanceOfUnderlying(address(this));
 }
```

## Tests

{% embed url="<https://github.com/stakewithus/defi-by-example/blob/main/test/test-compound-erc20.js>" %}
test-compound-erc20.js
{% endembed %}

In the setup, we create a whale user with each WBTC to run this demo:

```javascript
beforeEach(async () => {
    await sendEther(web3, accounts[0], WHALE, 1)

    testCompound = await TestCompoundErc20.new(TOKEN, C_TOKEN)
    token = await IERC20.at(TOKEN)
    cToken = await CErc20.at(C_TOKEN)

    const bal = await token.balanceOf(WHALE)
    console.log(`whale balance: ${bal}`)
    assert(bal.gte(DEPOSIT_AMOUNT), "bal < deposit")
 })
```

Create a function `snapshot()` that logs current states:

```javascript
const snapshot = async (testCompound, token, cToken) => {
    const { exchangeRate, supplyRate } = await testCompound.getInfo.call()

    return {
        exchangeRate,
        supplyRate,
        estimateBalance: await testCompound.estimateBalanceOfUnderlying.call(),
        balanceOfUnderlying: await testCompound.balanceOfUnderlying.call(),
        token: await token.balanceOf(testCompound.address),
        cToken: await cToken.balanceOf(testCompound.address),
    }
}
```

Test case:

```javascript
it("should supply and redeem", async () => {
    await token.approve(testCompound.address, DEPOSIT_AMOUNT, {
        from: WHALE
    })

    let tx = await testCompound.supply(DEPOSIT_AMOUNT, {
        from: WHALE,
    })

    let after = await snapshot(testCompound, token, cToken)

    // for (const log of tx.logs) {
    //   console.log(log.event, log.args.message, log.args.val.toString())
    // }

    console.log("--- supply ---")
    console.log(`exchange rate ${after.exchangeRate}`)
    console.log(`supply rate ${after.supplyRate}`)
    console.log(`estimate balance ${after.estimateBalance}`)
    console.log(`balance of underlying ${after.balanceOfUnderlying}`)
    console.log(`token balance ${after.token}`)
    console.log(`c token balance ${after.cToken}`)

    // accrue interest on supply
    const block = await web3.eth.getBlockNumber()
    await time.advanceBlockTo(block + 100)

    after = await snapshot(testCompound, token, cToken)

    console.log(`--- after some blocks... ---`)
    console.log(`balance of underlying ${after.balanceOfUnderlying}`)

    // test redeem
    const cTokenAmount = await cToken.balanceOf(testCompound.address)
    tx = await testCompound.redeem(cTokenAmount, {
        from: WHALE,
    })

    after = await snapshot(testCompound, token, cToken)

    console.log(`--- redeem ---`)
    console.log(`balance of underlying ${after.balanceOfUnderlying}`)
    console.log(`token balance ${after.token}`)
    console.log(`c token balance ${after.cToken}`)
})
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ret2basic.gitbook.io/ctfnote/web3-security-research/defi/compound-v3/interacting-with-compound/supply-and-redeem.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
