> For the complete documentation index, see [llms.txt](https://ret2basic.gitbook.io/ctfnote/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ret2basic.gitbook.io/ctfnote/web3-security-research/defi/compound-v3/interacting-with-compound/liquidation.md).

# Liquidation

## Intro

{% embed url="<https://youtu.be/w-oVV0Ie3Fw>" %}
Liquidation
{% endembed %}

In this section, we simulate a borrow->liquidation scenario:

* Step 1: supply
* Step 2: borrow max
* Step 3: wait few blocks and let `borrowed_balance > supplied_balance * collateral_factor` -> leads to liquidation
* Step 4: liquidate

Code:

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

## Setup

Set Comptroller, borrowed token and borrowed cToken:

```solidity
Comptroller public comptroller = Comptroller(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);

IERC20 public tokenBorrow;
CErc20 public cTokenBorrow;

event Log(string message, uint val);

constructor(address _tokenBorrow, address _cTokenBorrow) {
    tokenBorrow = IERC20(_tokenBorrow);
    cTokenBorrow = CErc20(_cTokenBorrow);
}
```

## Close Factor

What is "close factor"? Quote from doc:

> The percent, ranging from 0% to 100%, of a liquidatable account’s borrow that can be repaid in a single liquidate transaction. If a user has multiple borrowed assets, the closeFactor applies to any single borrowed asset, not the aggregated value of a user’s outstanding borrowing.

Close factor can be queried via `comptroller.closeFactorMantissa()`:

```solidity
// close factor
function getCloseFactor() external view returns (uint) {
    return comptroller.closeFactorMantissa();
}
```

## Liquidation Incentive

What is "liquidation incentive"? Quote from doc:

> The additional collateral given to liquidators as an incentive to perform liquidation of underwater accounts. A portion of this is given to the collateral cToken reserves as determined by the seize share. The seize share is assumed to be 0 if the cToken does not have a `protocolSeizeShareMantissa` constant. For example, if the liquidation incentive is 1.08, and the collateral’s seize share is 1.028, liquidators receive an extra 5.2% of the borrower’s collateral for every unit they close, and the remaining 2.8% is added to the cToken’s reserves.

Liquidation incentive can be queried via `comptroller.liquidationIncentiveMantissa()`:

```solidity
// liquidation incentive
function getLiquidationIncentive() external view returns (uint) {
    return comptroller.liquidationIncentiveMantissa();
}
```

## Liquidate

To compute the amount of the collateral that we can liquidate, call `comptroller .liquidateCalculateSeizeTokens()`:

```solidity
// get amount of collateral to be liquidated
function getAmountToBeLiquidated(
    address _cTokenBorrowed,
    address _cTokenCollateral,
    uint _actualRepayAmount
) external view returns (uint) {
    /*
     * Get the exchange rate and calculate the number of collateral tokens to seize:
     *  seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral
     *  seizeTokens = seizeAmount / exchangeRate
     *   = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)
     */
    (uint error, uint cTokenCollateralAmount) = comptroller
    .liquidateCalculateSeizeTokens(
        _cTokenBorrowed,
        _cTokenCollateral,
        _actualRepayAmount
    );

    require(error == 0, "error");

    return cTokenCollateralAmount;
}
```

Finally let's implement the high-level `liquidate()` function:

```solidity
// liquidate
function liquidate(
    address _borrower,
    uint _repayAmount,
    address _cTokenCollateral
) external {
    // Transfer the fund from user's wallet to this contract
    tokenBorrow.transferFrom(msg.sender, address(this), _repayAmount);
    // Approve the cTokenBorrow contract to spend this fund
    tokenBorrow.approve(address(cTokenBorrow), _repayAmount);

    // Call cTokenBorrow.liquidateBorrow() to liquidate
    require(
        cTokenBorrow.liquidateBorrow(_borrower, _repayAmount, _cTokenCollateral) == 0,
        "liquidate failed"
    );
}
```

## Test

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

We supply WBTC and borrow DAI.

Test case:

```solidity
it("should liquidate", async () => {
    // used for debugging
    let tx
    let snap

    // supply
    await tokenSupply.approve(testCompound.address, SUPPLY_AMOUNT, {
        from: SUPPLY_WHALE
    })
    tx = await testCompound.supply(SUPPLY_AMOUNT, {
        from: SUPPLY_WHALE,
    })

    snap = await snapshot(testCompound, liquidator)
    console.log(`--- supplied ---`)
    console.log(`col factor: ${snap.colFactor} %`)
    console.log(`supplied: ${snap.supplied}`)

    // enter market
    tx = await testCompound.enterMarket({
        from: accounts[0]
    })

    // borrow
    const { liquidity } = await testCompound.getAccountLiquidity()
    const price = await testCompound.getPriceFeed(C_TOKEN_BORROW)
    const maxBorrow = liquidity.mul(pow(10, BORROW_DECIMALS)).div(price)
    // NOTE: tweak borrow amount if borrow fails
    const borrowAmount = maxBorrow.mul(new BN(9997)).div(new BN(10000))

    console.log(`--- entered market ---`)
    console.log(`liquidity: $ ${liquidity.div(pow(10, 18))}`)
    console.log(`price: $ ${price.div(pow(10, 18))}`)
    console.log(`max borrow: ${maxBorrow.div(pow(10, 18))}`)
    console.log(`borrow amount: ${borrowAmount.div(pow(10, 18))}`)

    tx = await testCompound.borrow(borrowAmount, {
        from: accounts[0]
    })

    snap = await snapshot(testCompound, liquidator)
    console.log(`--- borrowed ---`)
    console.log(`liquidity: $ ${snap.liquidity}`)
    console.log(`borrowed: ${snap.borrowed}`)

    // accrue interest on borrow
    const block = await web3.eth.getBlockNumber()
    // NOTE: tweak this to increase borrowed amount
    await time.advanceBlockTo(block + 10000)

    // send any tx to Compound to update liquidity and shortfall
    await testCompound.getBorrowBalance()

    snap = await snapshot(testCompound, liquidator)
    console.log(`--- after some blocks... ---`)
    console.log(`liquidity: $ ${snap.liquidity}`)
    console.log(`shortfall: $ ${snap.shortfall}`)
    console.log(`borrowed: ${snap.borrowed}`)

    // liquidate
    const closeFactor = await liquidator.getCloseFactor()
    const repayAmount = (await testCompound.getBorrowBalance.call()).mul(closeFactor).div(pow(10, 18))

    const liqBal = await tokenBorrow.balanceOf(LIQUIDATOR)
    console.log(`liquidator balance: ${liqBal.div(pow(10, BORROW_DECIMALS))}`)
    assert(liqBal.gte(repayAmount), "bal < repay")

    const amountToBeLiquidated = await liquidator.getAmountToBeLiquidated(C_TOKEN_BORROW, C_TOKEN_SUPPLY, repayAmount)
    console.log(
        `amount to be liquidated (cToken collateral):  ${amountToBeLiquidated.div(pow(10, SUPPLY_DECIMALS - 2)) / 100}`
    )

    await tokenBorrow.approve(liquidator.address, repayAmount, {
        from: LIQUIDATOR
    })
    tx = await liquidator.liquidate(testCompound.address, repayAmount, C_TOKEN_SUPPLY, {
        from: LIQUIDATOR,
    })

    snap = await snapshot(testCompound, liquidator)
    console.log(`--- liquidated ---`)
    console.log(`close factor: ${snap.closeFactor} %`)
    console.log(`liquidation incentive: ${snap.incentive}`)
    console.log(`supplied: ${snap.supplied}`)
    console.log(`liquidity: $ ${snap.liquidity}`)
    console.log(`shortfall: $ ${snap.shortfall}`)
    console.log(`borrowed: ${snap.borrowed}`)
    console.log(`liquidated: ${snap.liquidated}`)

    /* memo
    c = 31572
    r = c * 0.65 * 0.5
    b = 1
    i = 1.08
    r * i * b / c
    */
})
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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/liquidation.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.
