> For the complete documentation index, see [llms.txt](https://docs.curvance.com/app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.curvance.com/app/developer-docs/quick-start-guides/borrowing-and-repayment.md).

# Borrowing & Repayment

In Curvance's lending ecosystem, each isolated market has a set of cTokens, one per listed asset.

* **Lending-side accounting:** depositors receive cToken shares (ERC4626) that represent their claim on the underlying pool. Holding cUSDC shares means you deposited USDC and are earning interest as borrowers repay.
* **Borrowing-side accounting:** borrowers do not receive cToken shares when they borrow. Their debt is recorded separately on the same `BorrowableCToken` contract, using the internal `_debtOf` accounting, and grows as interest accrues. The borrower receives the underlying asset directly, while the cToken tracks what they owe.

For a deep dive, see the [BorrowableCTokens](/app/developer-docs/lending-protocol/borrowablectoken.md) page.

Use the subpages for transaction recipes:

* **Borrow:** opening a debt position against posted collateral.
* **Repaying Debt:** partial repayment, full repayment, and repayment on behalf of another account.
* **Flash Loans:** one-transaction liquidity from a borrowable cToken pool.

***

### Understanding `cUSDC`

`cUSDC` is the per-market `BorrowableCToken` wrapping USDC in a specific isolated market. The same concepts apply to the cTokens wrapping WETH, WBTC, AUSD, ezETH, and other listed assets. Source the real cToken address from the deployment registry for the chain you're on.

**Key characteristics:**

* **Underlying asset:** USDC, with 6 decimal places. (Underlying decimals vary by asset; always call `await underlying.decimals()` rather than hardcoding.)
* **Interest accrual:** borrow interest accrues lazily. Accruing paths include `deposit`, `withdraw`, `redeem`, `borrow`, `repay`, `liquidate`, `flashLoan`, `accrueIfNeeded`, and the updated-read helpers such as `exchangeRateUpdated`, `debtBalanceUpdated`, and `marketOutstandingDebtUpdated`. View functions can read last-accrued state, so use the `staticCall` pattern for fresh reads. See Integration Cookbook: Stale vs Fresh Reads.
* **Exchange rate:** the shares-to-assets rate increases as lenders earn interest. Lending positions are non-rebasing: share count stays fixed, value per share rises.
* **Dynamic IRM:** each borrowable cToken stores an `IRM()` address. The DynamicIRM adjustment interval is 10 minutes (`DynamicIRM.ADJUSTMENT_RATE()`), and rate updates happen lazily when accrual runs at or after an adjustment boundary. Higher utilization generally means a higher borrow APR.
* **20-minute hold period after posting collateral or borrowing:** posting collateral or borrowing starts an account-level cooldown inside that isolated market. During the next 20 minutes, repayment, redemption / withdrawal, and share transfers for that account revert with `MarketManager__MinimumHoldPeriod`. Plain deposits are not blocked and do not start or reset the cooldown. New collateral postings and new borrows are allowed if otherwise valid, and each one resets the cooldown.
* **Same cToken, not both roles for the same account:** a user cannot use the same cToken as posted collateral and debt at the same time. Borrowing from a cToken where the account has posted collateral reverts with `BorrowableCToken__CollateralPositionActive`. Posting collateral to a cToken where the account already has debt reverts with `BorrowableCToken__DebtPositionActive`. Typical flows borrow the other side of the isolated market, for example, deposit ezETH as collateral in an `ezETH | WETH` market and borrow WETH.

***

### Setting Up Your Development Environment

Before interacting with cUSDC, set up ethers v6 and load ABIs from the Curvance contracts repo or your generated ABI artifacts.

```js
const { ethers } = require('ethers');

const provider = new ethers.JsonRpcProvider('YOUR_RPC_URL');
const wallet   = new ethers.Wallet('YOUR_PRIVATE_KEY', provider);

// Placeholder addresses. Source the real values from the deployment registry
// for the chain you're targeting.
const cUSDCAddress      = '0x...';  // cUSDC contract for your target market
const USDCAddress       = '0x...';  // underlying USDC token on your target chain
const protocolReaderAddr = '0x...'; // Curvance ProtocolReader

// Initialize contract instances with the appropriate ABIs
const cUSDC          = new ethers.Contract(cUSDCAddress, BORROWABLE_CTOKEN_ABI, wallet);
const USDC           = new ethers.Contract(USDCAddress, ERC20_ABI, wallet);
const protocolReader = new ethers.Contract(protocolReaderAddr, PROTOCOL_READER_ABI, provider);
```

***

### Monitoring Your Debt Position

As interest accrues, monitor debt with the read that matches your UX. Use stale views for low-risk display copy, and fresh or projected reads for liquidation margin, close-out flows, and alerts.

#### Option A: `ProtocolReader.debtBalanceAtTimestamp`

Use this view for a current or future debt projection. If you pass a timestamp before the current block, the reader clamps it to the current block timestamp.

```js
async function checkProjectedDebtBalance() {
  const now = Math.floor(Date.now() / 1000);
  const debtBalance = await protocolReader.debtBalanceAtTimestamp(
    userAddress,
    cUSDCAddress,
    now
  );

  const USDCDecimals = await USDC.decimals();
  console.log(`Projected USDC debt: ${ethers.formatUnits(debtBalance, USDCDecimals)}`);
  return debtBalance;
}
```

`debtBalanceAtTimestamp` simulates debt at the supplied current or future timestamp without mutating chain state. It is useful when your UI wants to show what the account's debt will be after a short buffer.

#### Option B: `cUSDC.debtBalanceUpdated(account)` (fresh, via staticCall)

For a wei-accurate read at the current block, call `debtBalanceUpdated` with `staticCall`. This function accrues interest first before returning:

```js
const freshDebt = await cUSDC.debtBalanceUpdated.staticCall(wallet.address);
```

#### Option C: `cUSDC.debtBalance(account)` (view, cheap, stale)

The plain `view` version returns the last-accrued value, suitable for non-critical displays:

```js
const staleDebt = await cUSDC.debtBalance(wallet.address);
```

{% hint style="danger" %}
If your UX surfaces liquidation margin, health factor, or any "receive at least X" guarantee, use Option A or B. Stale reads can under-report pending debt and mask imminent liquidation. See the [Stale vs Fresh Reads](/app/developer-docs/quick-start-guides/integration-cookbook.md#stale-vs-fresh-reads) write-up for the full pattern.
{% endhint %}

Debt grows over time as interest accrues. If your debt grows faster than your collateral value, you risk liquidation. Maintain a collateralization buffer above the minimum and alert before the account approaches liquidation.

***

### Understanding Market Conditions

Borrow APR depends on utilization. The DynamicIRM computes utilization as:

```
utilization = outstandingDebt / (assetsHeld + outstandingDebt)
```

Higher utilization generally pushes borrow rates higher. Before borrowing, inspect the current market state.

```js
async function checkMarketInfo() {
  const USDCDecimals = await USDC.decimals();

  // Exchange-rate reads are WAD-scaled share-to-asset rates.
  const rateStale = await cUSDC.exchangeRate();
  const rateFresh = await cUSDC.exchangeRateUpdated.staticCall();

  console.log(`Stale exchange rate: ${ethers.formatUnits(rateStale, 18)}`);
  console.log(`Fresh exchange rate: ${ethers.formatUnits(rateFresh, 18)}`);

  // marketOutstandingDebt is a public uint240 storage variable. It reflects
  // last-accrued debt for this cToken's underlying asset.
  const totalBorrowsStale = await cUSDC.marketOutstandingDebt();
  const totalBorrowsFresh =
    await cUSDC.marketOutstandingDebtUpdated.staticCall();

  console.log(
    `Total USDC debt (stale): ${ethers.formatUnits(totalBorrowsStale, USDCDecimals)}`
  );
  console.log(
    `Total USDC debt (fresh): ${ethers.formatUnits(totalBorrowsFresh, USDCDecimals)}`
  );

  // A stale but internally consistent utilization display.
  const idleAssetsStale = await cUSDC.assetsHeld();
  const WAD = 10n ** 18n;
  const utilizationStale =
    totalBorrowsStale === 0n
      ? 0n
      : (totalBorrowsStale * WAD) / (idleAssetsStale + totalBorrowsStale);

  console.log(`Utilization (stale): ${ethers.formatUnits(utilizationStale, 18)}`);

  return { rateFresh, totalBorrowsFresh, utilizationStale };
}
```

Higher utilization generally leads to higher interest rates. Tracking these metrics can help you anticipate changes in borrowing costs and avoid taking on debt just before a rate spike.

`assetsHeld()` and `marketOutstandingDebt()` are view reads. They are useful for display and trend monitoring, but any transaction still rechecks the relevant conditions on-chain after accrual.

***

### Risk Considerations

When borrowing through `cUSDC`, be aware of:

* **Liquidation risk:** if collateral value falls or debt grows, the account can cross the market's liquidation threshold. Curvance uses soft and hard liquidation thresholds, plus per-token liquidation incentive and close-factor curves. The curve is based on how far the account is into liquidation.
* **Interest-rate volatility:** the DynamicIRM re-computes rates on a \~10-minute tick based on utilization. Your debt can grow faster than anticipated if utilization spikes.
* **Oracle risk:** live deployments use a single Chainlink-like adaptor per asset, with heartbeat checks and price guards for pegged or reference-priced assets. If a price-dependent action receives an invalid price signal, the affected borrow, redemption, or liquidation path reverts instead of proceeding with a bad price. Repayment is special: after the hold period, a full repay that leaves `newNetDebt == 0` skips the debt-asset oracle check, while a partial repay must still pass the residual loan-size price check.
* **Market risk:** the value of your collateral may decline relative to your borrowed asset, even without on-chain activity.
* **Hold-period interaction:** the 20-minute hold period after posting collateral or borrowing blocks repayment in that window. If your integration's liquidation-avoidance strategy depends on repaying on short notice, account for this lock.

To mitigate risk, keep a healthier collateralization buffer than the minimum, monitor positions with fresh or projected reads, and alert well before the account reaches liquidation.

***


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.curvance.com/app/developer-docs/quick-start-guides/borrowing-and-repayment.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
