> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mystockline.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Liquidators

> Watch health, quote the Dutch auction on LiquidationModule, and submit through Stockline.liquidate.

Keepers repay USDG and receive stock. The core gates the call. The module sizes the seize.

Network: Robinhood Chain testnet. Addresses: [Addresses](/resources/addresses). ABIs: [`Stockline.json`](/abis/Stockline.json), [`LiquidationModule.json`](/abis/LiquidationModule.json).

<Steps>
  <Step title="Watch positions">
    Index `Borrow`, `Repay`, `SupplyCollateral`, `WithdrawCollateral`, and `Liquidate` from the [indexer](/developers/indexer), or poll `RiskLens.snapshot` on known accounts.

    A candidate is `health < 1e18`. Confirm `regime` is `LIVE` or `DARK` and the core is not paused.

    ```typescript theme={"system"}
    import { parseAbi } from "viem"
    import { addresses } from "./addresses" // Addresses, testnet

    const lensAbi = parseAbi([
      "function health(address account) view returns (uint256)",
      "function snapshot(address account) view returns ((uint256 health, uint256 maxBorrow, (uint16 bookId, address collateral, uint256 amount, uint256 amountUi, uint256 debt, uint256 liquidationPrice)[] books))",
    ])

    const health = await client.readContract({
      address: addresses.riskLens,
      abi: lensAbi,
      functionName: "health",
      args: [account],
    })
    const liquidatable = health < 10n ** 18n
    ```
  </Step>

  <Step title="Price the Dutch auction">
    Call `LiquidationModule.quote(account, bookId, repayAmount)` offchain. `discountOf` ramps from 0 to the book max over `auctionWindow`. Pass `type(uint256).max` as repay to let the module cap at the target-health need.

    <CodeGroup>
      ```typescript theme={"system"}
      const moduleAbi = parseAbi([
        "function quote(address account, uint16 bookId, uint256 repayAmount) view returns (uint256 repay, uint256 seizeToLiquidator, uint256 seizeToProtocol, uint256 discount)",
        "function discountOf(address account, uint16 bookId) view returns (uint256)",
      ])

      const q = await client.readContract({
        address: addresses.liquidationModule,
        abi: moduleAbi,
        functionName: "quote",
        args: [account, bookId, 2n ** 256n - 1n],
      })
      // q.repay is USDG you must hold. q.seizeToLiquidator is stock you receive.
      ```

      ```solidity theme={"system"}
      struct LiqQuote {
          uint256 repay;
          uint256 seizeToLiquidator;
          uint256 seizeToProtocol;
          uint256 discount;
      }

      interface ILiquidationModule {
          function quote(address account, uint16 bookId, uint256 repayAmount) external view returns (LiqQuote memory);
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Submit through the core">
    Do not call `LiquidationModule.liquidate` yourself. It reverts `NotCore`. Approve USDG on `Stockline`, then:

    ```typescript theme={"system"}
    const coreAbi = parseAbi([
      "function liquidate(address account, uint16 bookId, uint256 repayAmount)",
    ])

    await wallet.writeContract({
      address: addresses.stockline,
      abi: coreAbi,
      functionName: "liquidate",
      args: [account, bookId, q.repay],
    })
    ```
  </Step>

  <Step title="Respect the allowlist flag">
    `RiskRegistry.liquidatorAllowlist(bookId)` is true at launch.

    The module **does not enforce it**. `LiquidationModule` NatSpec: liquidations are permissionless. If governance later wires a check, this guide will change on the next generate of the contract page. Today, anyone who can pay `q.repay` can liquidate.

    Still read the flag. If you operate an allowlisted keeper set, do not assume competitors are blocked.
  </Step>
</Steps>

## What can go wrong

* `NotLiquidatable` if health recovered between quote and send.
* `RegimeBlocked` / `Paused` if the book left LIVE/DARK or the guardian paused.
* `NothingToSeize` if collateral or debt is now zero.
* Quote vs execution: discount rises with time. Re-quote in the same block you send, or you may overpay relative to the UI.
* You need USDG, not sUSDG. Zap first if you hold another dollar.
* Thin exit: selling seized stock onchain can move more than the auction bonus. Size for offchain hedges. See [Risk](/resources/risks).

## Parameters that size the auction

| Parameter             | Where                    | Launch value                                   | Effect on your bot                                                    |
| --------------------- | ------------------------ | ---------------------------------------------- | --------------------------------------------------------------------- |
| `maxLiqDiscount`      | `RiskRegistry`, per book | [5%, 6%, or 8%](/resources/parameters) by tier | Ceiling on the discount you receive.                                  |
| `auctionWindow`       | `RiskRegistry`           | [two hours](/resources/parameters)             | Time for the discount to ramp from 0 to the ceiling.                  |
| `targetHealth`        | `RiskRegistry`           | [Parameters](/resources/parameters)            | The module caps `repay` so the account lands here, not at full close. |
| `dustDebt`            | `RiskRegistry`           | [Parameters](/resources/parameters)            | Below this, the module closes the whole loan instead of a partial.    |
| `protocolLiqFeeShare` | `RiskRegistry`           | [Parameters](/resources/parameters)            | Slice of the seized discount that goes to the reserve, not to you.    |
| `liquidatableSince`   | `Stockline`, per account | n/a                                            | Timestamp the auction clock started. `discountOf` reads it.           |

Next: [Liquidations](/concepts/liquidations), [Indexer](/developers/indexer).
