> 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/lending-protocol/ctoken.md).

# cToken

## Overview

cTokens are Curvance vault tokens that represent user deposits inside an isolated lending market. Each cToken wraps one underlying asset. Some cTokens are simple wrappers, some are strategy vaults that harvest external rewards, and BorrowableCTokens accrue borrower interest for lenders. cTokens are designed so supported asset positions can be made available for protocol withdrawals and liquidations, but user withdrawals still depend on available liquidity, account cooldown state, collateral health, and pause status.

{% hint style="info" %}
While CTokens follow the ERC-4626 standard in spirit, they are **not fully ERC-4626 compliant**. Certain view functions include stricter reentrancy protections, and zero-amount transfers are intentionally blocked to minimize edge cases. These design decisions are made to prioritize security, predictable behavior, and flexible liquidity management.
{% endhint %}

## Core Architecture

CTokens follow a hierarchical inheritance structure designed for flexibility and extensibility:

1. **BaseCToken:** The foundational abstract contract implementing ERC4626 vault functionality and core Curvance protocol integration.
2. **SimpleCToken:** For basic assets that don't generate external rewards (e.g., WETH, stablecoins, liquid staking tokens).
3. **StrategyCToken:** Extended functionality for assets that generate yield, supporting automatic reward harvesting and compounding.
4. **StrategyCTokenWithExitFee:** Adds an exit fee mechanism to compounding vaults for strategies that require it.
5. **Protocol-Specific Implementations:** Custom implementations tailored for different DeFi protocols and yield strategies.

## Key Contracts and Interactions

CTokens integrate with several core Curvance contracts to provide comprehensive functionality:

* **CentralRegistry:** Protocol configuration and permissions management, ensuring proper authorization and global settings.
* **MarketManager:** Handles collateral position registration, risk parameters, and borrowing authorization.
* **Oracle System:** Provides accurate asset valuation for collateral and liquidation purposes.
* **External Protocol Contracts:** For staking, providing liquidity, and claiming rewards across various DeFi ecosystems.

## Types of cTokens

### Simple cTokens

Simple CTokens (SimpleCToken) are designed for assets that don't generate external rewards. They provide a straightforward vault wrapper for assets such as:

* Wrapped native assets
* Liquid Staking Tokens (LSTs)
* Principal tokens from yield-bearing assets
* Stablecoins and yield-bearing stablecoins
* Basic wrapped tokens

These vaults focus on capital efficiency and gas optimization.

### Strategy cTokens

Strategy cTokens (`StrategyCToken`) extend the base vault with permissioned harvest and compounding logic. These vaults:

* Allow approved harvest operators to call `harvest(bytes)` when harvesting is unpaused and the previous vesting period has finished.
* Claim rewards from the underlying protocol.
* Apply any strategy harvest fee in the reward token and send the fee to the fee manager.
* Swap or route the remaining rewards into the strategy's underlying position.
* Deposit the new strategy assets and vest the harvested yield over the configured vesting period.

### BorrowableCTokens

See [BorrowableCTokens](#borrowablectokens).

### Protocol-Specific Implementations

Curvance offers various protocol-specific CToken implementations tailored to different DeFi protocols and their unique characteristics.

Each implementations handles the specific deposit, withdrawal, reward harvesting, and risk management logic optimized for its respective protocol.

## State Managemecont

CTokens maintain several key state variables to track vault operations and user positions:

```solidity
// BaseCToken
IMarketManager public immutable marketManager;
uint256 public marketCollateralPosted;   // total shares posted as collateral in this cToken
mapping(address => uint256) public collateralPosted;   // account => collateralized shares
uint256 internal _totalAssets;           // minus any pending vesting
uint256 internal constant _BALANCE_SLOT_SEED = 0x87a211a2;
```

```solidity
// BaseCTokenWithYield (inherited by StrategyCToken and BorrowableCToken; not SimpleCToken)
uint256 public vestingPeriod;
uint256 internal _vestingData;           // packed vesting data; layout differs per subclass (see below)
```

## Data Flow

### Deposit Flow

1. User calls `deposit(assets, receiver)` with underlying assets.
2. The cToken accrues pending yield or interest, calculates shares from the updated asset accounting, and checks `marketManager.canMint(address(this))`.
3. The underlying tokens are transferred from the caller to the cToken.
4. The cToken updates `_totalAssets`. Strategy cTokens then use `_afterDeposit(assets, 0)` from `_updateAssetsForDeposit` to place the assets into the external strategy.
5. Vault shares are minted to `receiver`, and the cToken emits `Deposit`.
6. If the caller uses `depositAsCollateral` or `depositAsCollateralFor`, the cToken then posts the minted shares as collateral through `marketManager.canCollateralize`.

### Withdrawal Flow

1. User calls `withdraw(assets, receiver, owner)` or `redeem(shares, receiver, owner)`.
2. The cToken accrues pending yield or interest, calculates the shares or assets, checks allowance when `msg.sender != owner`, and asks the Market Manager whether the redemption is allowed.
3. For non-force withdrawals or redeems, posted collateral can still be removed if the requested shares exceed the owner's idle share balance and the Market Manager health check allows the collateral removal.
4. The cToken burns the owner's shares, updates `_totalAssets`, and then prepares or transfers underlying. Strategy cTokens call `_beforeWithdraw(assets, 0)` from `_updateAssetsForWithdrawal` before the underlying is sent to `receiver`.
5. The cToken emits `Withdraw`. If collateral was removed, it also emits `CollateralUpdated`.

### Collateral Management Flow

1. User calls `postCollateral()` to use cTokens as borrowing collateral.&#x20;
2. The cToken asks its Market Manager to verify that collateralization is unpaused and that the new market-wide posted-share total does not exceed `collateralCaps(cToken)`.
3. MarketManager is notified of the new collateral position.
4. User's cTokens are marked as collateral and transfer-restricted.
5. Collateral is now available for borrowing calculations.
6. User can borrow against collateralized position through BorrowableCTokens.

### Reward Harvesting Flow (Strategy Vaults)

1. `harvest()` function is called by authorized keepers or DAO.
2. External rewards are claimed from the underlying protocols.
3. Strategy harvests apply the configured strategy harvest fee in the reward token and transfer that fee to the fee manager. BorrowableCTokens do not use `harvest`; during interest accrual, a protocol interest fee can be minted as new cToken shares to the DAO address.
4. Rewards are swapped to underlying assets through optimized routes.
5. New assets are deposited back into the yield strategy.
6. Yield is distributed to vault users through vesting mechanism.
7. Exchange rate increases, benefiting all cToken holders.

### Yield Distribution Mechanism

Strategy cTokens and BorrowableCTokens employ a sophisticated vesting approach to distribute yield fairly and prevent MEV exploitation:

* **Gradual Distribution:** Newly recognized assets vest linearly over the vault's vesting period. For StrategyCTokens this is the configured `vestingPeriod`, which must be greater than zero and no more than 3 days and can be scheduled for update by governance. For BorrowableCTokens, the period is the linked IRM's `ADJUSTMENT_RATE`, which is currently `10 minutes` in `DynamicIRM`.
* **MEV Protection:** This creates a smoother increase in share price and reduces opportunities for front-running harvest transactions.
* **Fair Distribution:** All users benefit proportionally from yield regardless of when they deposited relative to harvest timing.

The vesting mechanism operates through packed data in `_vestingData`.

**In StrategyCTokens:**

* **`VESTING_RATE` (bits 0-175):** Rate at which rewards vest per second.
* **`VEST_END` (bits 176-215):** When current vesting period ends.
* **`LAST_VEST` (bits 216-255):** Last time vested rewards were claimed.

**In BorrowableCTokens:**

* **`VESTING_RATE` (bits 0-95):** Rate at which rewards vest per second.
* **`VEST_END` (bits 96-135):** When current vesting period ends.
* **`LAST_VEST` (bits 136-175):** Last time vested rewards were claimed.
* `DEBT_INDEX` **(bits 176-255):** Cumulative interest index used to calculate accrued interest on debt positions.

The `accrueIfNeeded()` function is called to update internal yield accounting and ensure vesting data reflects the current state.

### Security Features

cTokens incorporate multiple layers of security protection:

* **Collateral Restrictions:** Transfers route through the Market Manager. If an account transfers more than its idle shares, the transfer can remove posted collateral only when the hold-period and liquidity checks allow it. Otherwise, the transfer reverts.
* **Pause Mechanisms:** Market Managers expose market-wide `liquidationPaused`, `redeemPaused`, and `transferPaused` flags, and token-specific `mintPaused`, `collateralizationPaused`, and `borrowPaused` flags. Strategy cTokens also expose `harvestingPaused`.
* **Reentrancy Protection:** All critical functions implement comprehensive reentrancy guards.
* **Slippage Protection:** Swap operations and liquidity management include minimum output requirements and deadline protection.
* **Chain Validation:** Protocol-specific implementations validate deployment on correct networks.
* **Permissioned Operations:** Sensitive functions like harvesting and emergency actions are restricted to authorized addresses.
* **Time Locks:** Certain operations include minimum duration requirements to prevent flash loan attacks.

### Oracle Integration

cTokens integrate deeply with Curvance's oracle infrastructure for accurate and secure valuation:

* **Protocol-Specific Adaptors:** Custom oracle adaptors for complex assets like LP tokens, principal tokens, and yield-bearing assets.
* **TWAP Support:** Time-weighted average prices provide protection against price manipulation attacks.
* **Chainlink-Based Feeds:** Each priced asset routes through a single Chainlink-like adaptor configured for the asset. Staleness, heartbeat, and (for pegged assets) price-guard checks are applied on every read.
* **Price Guards:** For pegged assets (LSTs and stablecoins), an additional guard constrains the reported price inside a bounded range relative to a reference feed.

### Considerations

**Collateral Caps:** Each isolated Market Manager stores `collateralCaps(cToken)` in cToken shares. The cap limits how many shares of that cToken can be posted as collateral in that market; it is not a global protocol-wide deposit cap.

**Minimum duration requirements:** Posting collateral or borrowing starts an account-level 20-minute cooldown. During that window, repayment and cToken transfer, redeem, and withdraw paths that call the Market Manager checks revert. Deposits are not blocked by the cooldown.

**Gas Optimization:** Functions are designed to minimize gas costs while maintaining security and functionality.

**Yield Optimization:** Strategy implementations are regularly evaluated and updated to maximize user returns while managing risk.

***

## User Interaction Functions

### Share/Assets

{% hint style="info" %}
**A note on accrual and previews:**

`convertToShares`, `convertToAssets`, and the `preview*` functions do not trigger interest/yield accrual and operate on the last accrued state. `convertTo*`, `preview*`, `totalAssets`, and `exchangeRate()` read the last-accrued state and therefore drift between on-chain touches. For reads that reflect the current block, integrators should `staticCall` `exchangeRateUpdated()` or `getSnapshotUpdated(account)`; either triggers accrual inside the simulated call. Broadcasting an `accrueIfNeeded()` transaction is not a free way to refresh a view: by the time the next block arrives, the state has already drifted again. See the "Stale vs Fresh Reads" section in the integration cookbook for the canonical write-up.
{% endhint %}

#### convertToShares()

**Contract:** BaseCToken.sol

**Description:** The number of underlying tokens to theoretically convert to cToken shares.

**Function signature:**

```solidity
function convertToShares(uint256 assets) public view returns (uint256)
```

<table><thead><tr><th width="109">Type</th><th width="102">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>amount</td><td>The number of underlying tokens to theoretically convert to cTokens.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="106">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>The number of cTokens a user would receive for the given amount of underlying</td></tr></tbody></table>

***

#### convertToAssets()

**Contract:** BaseCToken.sol

**Description:** The number of cToken shares to theoretically convert to underlying assets.

**Function signature:**

```solidity
function convertToAssets(uint256 shares) public view returns (uint256) 
```

<table><thead><tr><th width="109">Type</th><th width="102">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>tokens</td><td>The number of cToken shares to theoretically convert to underlying assets.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="106">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>The number of underlying assets the user would receive for redeeming shares.</td></tr></tbody></table>

#### previewDeposit()

**Contract:** BaseCToken.sol

**Description:** Allows users to simulate the effects of their deposit at the current block.

**Function signature:**

```solidity
function previewDeposit(
    uint256 assets
) public view override returns (uint256) 
```

<table><thead><tr><th width="109">Type</th><th width="102">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The number of assets to preview a deposit call.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="106">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>The shares received for depositing <code>assets</code>.</td></tr></tbody></table>

#### previewMint()

**Contract:** BaseCToken.sol

**Description:** Allows users to simulate the assets required to mint `shares` at the current block.

**Function signature:**

```solidity
function previewMint(
    uint256 shares
) public view override returns (uint256)
```

<table><thead><tr><th width="109">Type</th><th width="102">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The number of assets, quoted as shares to preview a mint call.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="106">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>The assets required to mint <code>shares</code>.</td></tr></tbody></table>

#### previewWithdraw()

**Contract:** BaseCToken.sol

**Description:** Allows users to simulate the effects of their withdraw at the current block.

**Function signature:**

```solidity
function previewWithdraw(
    uint256 assets
) public view virtual override returns (uint256) 
```

<table><thead><tr><th width="109">Type</th><th width="102">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>tokens</td><td>The number of assets to preview a withdraw call.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="106">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>The shares required to withdraw <code>assets</code>.</td></tr></tbody></table>

#### previewRedeem()

**Contract:** BaseCToken.sol

**Description:** Converts an amount of cToken shares to equivalent underlying assets using the current exchange rate.

**Function signature:**

```solidity
function previewRedeem(
    uint256 shares
) public view virtual override returns (uint256) 
```

<table><thead><tr><th width="109">Type</th><th width="102">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The number of shares to preview a redeem call.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="106">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>The number of underlying assets the user would receive for redeeming shares.</td></tr></tbody></table>

***

### Deposits

#### deposit()

**Contract:** BaseCToken.sol

**Description:** Deposits assets into the vault and receives shares.

**Function signature:**

```solidity
function deposit(uint256 assets, address receiver) external returns (uint256 shares)
```

<table><thead><tr><th width="125">Type</th><th width="110">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The amount of underlying assets to deposit.</td></tr><tr><td>address</td><td>receiver</td><td>The account that should receive the cToken shares.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="121.98333740234375">Type</th><th width="118.70001220703125">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The amount of cToken shares received by receiver.</td></tr></tbody></table>

**Events:**

```solidity
// From cToken
event Deposit(address indexed caller, address indexed receiver, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
```

***

#### depositAsCollateral()

**Contract:** BaseCToken.sol

**Description:** The depositAsCollateralFor function enables users to deposit assets and automatically post them as collateral on behalf of another address, returning the amount of pToken shares received by the receiver.

**Function signature:**

```solidity
function depositAsCollateral(
    uint256 assets, 
    address receiver) external returns (uint256 shares)
```

<table><thead><tr><th width="119">Type</th><th width="140">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The amount of underlying assets to deposit.</td></tr><tr><td>uint256</td><td>receiver</td><td>The account that should receive the cToken shares.</td></tr></tbody></table>

**Return Data:**

<table><thead><tr><th width="124">Type</th><th width="139">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The amount of cToken shares received by receiver.</td></tr></tbody></table>

**Events:**

<pre class="language-solidity"><code class="lang-solidity"><strong>// From cToken
</strong>event Deposit(address indexed caller, address indexed receiver, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
</code></pre>

```solidity
// Only emitted if this is the user's first position in this cToken.
event PositionUpdated(address cToken, address account, bool open);
```

***

#### depositAsCollateralFor()

**Contract:** BaseCToken.sol

**Description:** The `depositAsCollateralFor` function enables users to deposit assets and automatically post them as collateral on behalf of another address, returning the amount of pToken shares received by the receiver. Unlike `depositAsCollateral`, this function requires explicit delegation permission, where the receiver must have previously approved the caller to act on their behalf. This makes it particularly useful for smart contract integrations, portfolio management tools, and protocols that assist users in capital optimization. The function operates by first checking delegation permissions, then transferring assets from the caller to the vault, minting shares to the receiver, and finally posting those shares as collateral through the `marketManager`.&#x20;

{% hint style="warning" %}
Users should exercise caution when delegating this permission, as delegates could potentially abuse it by repeatedly posting shares as collateral, which could temporarily prevent withdrawals and effectively lock a user's funds. If the caller lacks proper delegation permission, the call reverts with `PluginDelegable__Unauthorized()` before any deposit occurs. The receiver must first call `setDelegateApproval(caller, true)` on this cToken.
{% endhint %}

**Function signature:**

```solidity
function depositAsCollateralFor(
    uint256 assets,
    address receiver
) external nonReentrant returns (uint256 shares);
```

<table><thead><tr><th width="119">Type</th><th width="140">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The amount of underlying assets to deposit.</td></tr><tr><td>uint256</td><td>receiver</td><td>The account that should receive the cToken shares.</td></tr></tbody></table>

**Return Data:**

<table><thead><tr><th width="124">Type</th><th width="139">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The amount of cToken shares received by receiver.</td></tr></tbody></table>

**Events:**

<pre class="language-solidity"><code class="lang-solidity"><strong>// From cToken
</strong>event Deposit(address indexed caller, address indexed receiver, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
</code></pre>

```solidity
// From MarketManager
event PositionUpdated(address cToken, address account, bool open);
```

***

#### postCollateral()

Contract: BaseCToken.sol Description: Marks an existing cToken balance as collateral, making it available for borrowing against inside the same isolated market. Reverts if the cToken has `collRatio == 0`, if the market's `collateralCap` would be exceeded, or if the account does not hold enough un-posted shares. Triggers the 20-minute hold period on the account's collateralized shares. Function signature:

```solidity
function postCollateral(uint256 shares) external nonReentrant
```

Events:

```solidity
event CollateralUpdated(uint256 shares, bool increased, address account);   // from cToken
event PositionUpdated(address cToken, address account, bool open);          // from MarketManager, only on first-time posting
```

***

#### mint()

**Contract:** BaseCToken.sol

**Description:** Caller deposits the asset amount required to mint `shares`, and `receiver` receives the minted shares. Returns the underlying assets consumed.

**Function signature:**

```solidity
function mint(uint256 shares, address receiver) public nonReentrant returns (uint256 assets)
```

<table><thead><tr><th width="99">Type</th><th width="100">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>amount</td><td>The amount of the underlying asset to deposit</td></tr></tbody></table>

**Return Data:**

<table><thead><tr><th width="97">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>The amount of cTokens minted</td></tr></tbody></table>

**Events:**

```solidity
// Emitted from cToken and underlying asset.
event Transfer(address indexed from, address indexed to, uint256 value);
```

***

#### postCollateralFor()

Contract: BaseCToken.sol Description: Same as `postCollateral`, but posts shares already owned by `owner` on behalf of that owner. The caller must first have been approved via `setDelegateApproval(caller, true)` on this cToken by `owner`; if not, the call reverts with `PluginDelegable__Unauthorized()`. Powers portfolio-management and position-manager integrations. Delegates can delay withdrawals for the owner by repeatedly posting collateral, so owners should only approve addresses they trust. Function signature:

```solidity
function postCollateralFor(uint256 shares, address owner) external nonReentrant
```

Events: same as `postCollateral`.

***

### Withdrawals

#### withdraw()

**Contract:** BaseCToken.sol

**Description:** Facilitates the withdrawal of assets from the market and the burning of shares. Initially, it verifies if the owner is eligible to redeem shares within the given market. Upon successful validation, it proceeds to burn the shares and subsequently returns the asset. Importantly, it does not force the withdrawals. If the caller is withdrawing another owner's cTokens, they must first have enough approval.&#x20;

**Function signature:**

```solidity
    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public override nonReentrant returns (uint256 shares) {
```

<table><thead><tr><th width="119">Type</th><th width="125">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The amount of underlying assets to withdraw.</td></tr><tr><td>address</td><td>receiver</td><td>The account that should receive the assets.</td></tr><tr><td>address</td><td>owner</td><td>The account that will burn their shares to withdraw assets.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="134">Type</th><th width="104">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The amount of shares that were burned.</td></tr></tbody></table>

**Events:**

```solidity
// From cToken
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
```

```solidity
// From MarketManager
event PositionUpdated(address cToken, address account, bool open);
```

***

#### redeem()

**Function:** Burns shares to receive assets.

**Contract:** BaseCToken.sol

**Function signature:**

```solidity
function redeem(
    uint256 shares, 
    address receiver, 
    address owner) external returns (uint256 assets)
```

<table><thead><tr><th width="128.183349609375">Type</th><th width="130.45001220703125">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The amount of shares to redeem.</td></tr><tr><td>address</td><td>receiver</td><td>The account that should receive the assets.</td></tr><tr><td>address</td><td>owner</td><td>The account that will burn their shares to receive assets.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="137.11666870117188">Type</th><th width="118.75">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The amount of underlying assets sent to the receiver.</td></tr></tbody></table>

**Events:**

```solidity
// From cToken
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
```

```solidity
// From MarketManager
event PositionUpdated(address cToken, address account, bool open);
```

***

#### redeemCollateral()

**Description:** Redeems collateralized shares to receive assets.

**Contract:** BaseCToken.sol

**Function signature:**

```solidity
function redeemCollateral(
    uint256 shares,
    address receiver,
    address owner
) external nonReentrant returns (uint256 assets)
```

<table><thead><tr><th width="121.48330688476562">Type</th><th width="122.28338623046875">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The amount of collateralized shares to redeem.</td></tr><tr><td>address</td><td>receiver</td><td>The account that should receive the assets.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="133.76666259765625">Type</th><th width="109.58331298828125">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The amount of underlying assets sent to the receiver.</td></tr></tbody></table>

**Events:**

```solidity
// From cToken
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
```

```solidity
// From MarketManager
// Always emitted because collateral is being removed.
event PositionUpdated(address cToken, address account, bool open);
```

***

#### redeemFor()

**Description:** Withdraws assets, quoted in shares from the market, and burns owner shares, on behalf of owner.

**Contract:** BaseCToken.sol

**Function signature:**

```solidity
function redeemFor(
        uint256 shares,
        address receiver,
        address owner) public returns (uint256 assets)
```

<table><thead><tr><th width="121.48330688476562">Type</th><th width="122.28338623046875">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The amount of collateralized shares to redeem.</td></tr><tr><td>address</td><td>receiver</td><td>The account that should receive the assets.</td></tr><tr><td>address</td><td>owner</td><td>The account that will burn their shares to withdraw assets.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="133.76666259765625">Type</th><th width="109.58331298828125">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The amount of underlying assets sent to the receiver.</td></tr></tbody></table>

**Events:**

```solidity
// From cToken
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
```

```solidity
// From MarketManager
event PositionUpdated(address cToken, address account, bool open);
```

***

**redeemCollateralFor()**

**Description:** Redeems collateralized shares on behalf of an owner.

**Contract:** BaseCToken.sol

**Function signature:**

```solidity
function redeemCollateralFor(
    uint256 shares,
    address receiver, 
    address owner) external returns (uint256 assets)
```

<table><thead><tr><th width="134">Type</th><th width="122">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>shares</td><td>The amount of collateralized shares to redeem.</td></tr><tr><td>address</td><td>receiver</td><td>The account that should receive the assets.</td></tr><tr><td>address</td><td>owner</td><td>The account that owns the shares being redeemed.</td></tr></tbody></table>

**Return data:**

<table><thead><tr><th width="128.183349609375">Type</th><th width="108.11669921875">Name</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>assets</td><td>The amount of underlying assets sent to the receiver.</td></tr></tbody></table>

**Events:**

```solidity
// From cToken
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
```

```solidity
// From MarketManager
// Always emitted because collateral is being removed.
event CollateralUpdated(uint256 shares, bool increased, address account);
```

***

#### removeCollateral()

**Contract:** BaseCToken.sol Description: Un-posts `shares` from the caller's collateral position inside this market, returning them to freely-transferable cToken balance. Reverts if removing the shares would leave the account under-collateralized against outstanding debt in any BorrowableCToken in the same market (`marketManager.canRedeemWithCollateralRemoval` check). Does not burn shares or move underlying. Function signature:

```solidity
function removeCollateral(uint256 shares) external nonReentrant
```

Events:

```solidity
event CollateralUpdated(uint256 shares, bool increased, address account);   // from cToken, increased = false
event PositionUpdated(address cToken, address account, bool open);          // from MarketManager, only when position fully closes
```

***

#### removeCollateralFor()

**Contract:** BaseCToken.sol Description: Same as `removeCollateral`, but un-posts shares from `owner`'s collateral position on their behalf. The caller must be an approved delegate of `owner` (`setDelegateApproval`); if not, the call reverts with `PluginDelegable__Unauthorized()`. Function signature:

```solidity
function removeCollateralFor(uint256 shares, address owner) external nonReentrant
```

Events: same as `removeCollateral`.

***

#### withdrawCollateral()

**Contract:** BaseCToken.sol Description: Burns enough of `owner`'s shares to return exactly `assets` of the underlying to `receiver`, forcing collateral to be removed from `owner`'s collateral position if the free (un-posted) share balance is insufficient. This is the force-redeem assets variant; `withdraw()` by contrast never touches collateral and will revert with `InsufficientLiquidity` if the caller tries to withdraw more than their free balance. Reverts if removing the shares would leave the account under-collateralized against outstanding debt. If `msg.sender != owner`, a standard ERC20 share allowance is required; delegation does not apply to this function. Function signature:

```solidity
function withdrawCollateral(
    uint256 assets,
    address receiver,
    address owner
) external nonReentrant returns (uint256 shares)
```

Events:

```solidity
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);   // burn, from = owner, to = address(0)
event CollateralUpdated(uint256 shares, bool increased, address account);  // from cToken, only if collateral had to be pulled
event PositionUpdated(address cToken, address account, bool open);         // from MarketManager, only if position fully closes
```

***

### Exchange Rate Calculation

#### exchangeRate()

**Contract:** cToken

**Description:** Returns the current exchange rate without updating interest, showing how many underlying tokens each cToken is worth in WAD format (view function).

**Function signature:**

```solidity
function exchangeRate() external view returns (uint256)
```

**Return data:**

<table><thead><tr><th width="118">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>Exchange rate from shares to assets in WAD format</td></tr></tbody></table>

***

#### exchangeRateUpdated()

**Contract:** cToken

**Description:** Returns the current exchange rate after updating interest via `_accrueIfNeeded()`, used to determine how many underlying tokens each cToken is worth.

**Function signature:**

```solidity
function exchangeRateUpdated() external returns (uint256)
```

**Return data:**

<table><thead><tr><th width="118">Type</th><th>Description</th></tr></thead><tbody><tr><td>uint256</td><td>Exchange rate from shares to assets in WAD format.</td></tr></tbody></table>

***

### Interest Accrual Mechanism

Interest/yield is accrued on BorrowableCTokens/StrategyCTokens and distributed to cToken holders through the increasing exchange rate. The accrual process is managed by the `accrueIfNeeded` function.

#### accrueIfNeeded()

**Contract: BaseCToken.sol**

**Function signature:**

```solidity
function accrueIfNeeded() public
```

In BorrowableCToken, this function:

1. Calculates time elapsed since the last interest accrual.
2. Fetches the current interest rate from the interest rate model.
3. Computes the interest amount based on current total borrows.
4. Updates total borrows with the new interest.
5. Allocates a portion of interest to protocol reserves based on the `interestFee`.
6. Updates the exchange rate to reflect the new value of each BorrowableCToken.

In StrategyCTokens, this function vests previously harvested yield into `_totalAssets` based on elapsed time inside the current vesting window. It is called internally by `mint`, `deposit`, `redeem`, `withdraw`, and transfer flows. Strategy cTokens do not have `borrow` or `repay`; only `BorrowableCToken` does.

***

### Compounding Vault Specifics

For compounding vaults like PendleLPCToken, VelodromeVolatileCToken, AerodromeStableCToken.

#### Vesting Mechanism

Compounding vaults use a vesting mechanism to gradually distribute yield.

When yield is harvested:

1. Rewards are claimed from the external protocol.
2. A protocol fee is taken.
3. Remaining rewards are swapped to the underlying asset.
4. The yield is distributed over the vesting period (default 1 day).

```solidity
function harvest(bytes calldata data) external returns (uint256 yield)
```

<table><thead><tr><th width="157">Parameter</th><th>Description</th></tr></thead><tbody><tr><td>data</td><td>Encoded swap parameters to convert rewards to underlying assets.</td></tr></tbody></table>

#### Getting Vault Status

`getYieldInformation()` has two forms. Both live under the same "Getting Vault Status" slot but return different values depending on the cToken subclass.

**BorrowableCToken (borrowable markets, e.g. cUSDC, cWETH, cWBTC):**

```solidity
function getYieldInformation() external view nonReadReentrant returns (
    uint256 vestingRate,
    uint256 vestingEnd,
    uint256 lastVestingClaim,
    uint256 debtIndex
);
```

* `vestingRate`: borrower interest vested per second, scaled by `WAD`. Applied against `marketOutstandingDebt`, not against `_totalAssets`.
* `vestingEnd`: timestamp at which the current IRM adjustment window ends and rates recompute.
* `lastVestingClaim`: timestamp at which pending accrued interest was last rolled into `marketOutstandingDebt` and `_totalAssets`.
* `debtIndex`: the market-wide cumulative debt index. A borrower's current debt is `storedDebt * currentDebtIndex / borrowerDebtIndex`.

**StrategyCToken (compounding vaults, e.g. PendleLPCToken, AerodromeStableCToken, VelodromeVolatileCToken):**

```solidity
function getYieldInformation() external view nonReadReentrant returns (
    uint256 vestingRate,
    uint256 vestingEnd,
    uint256 lastVestingClaim,
    uint256 strategyPaused
);
```

* `vestingRate`: yield vested per second, in `asset()`, scaled by `WAD` (1e18).
* `vestingEnd`: timestamp at which the current vesting window ends and the next harvest becomes possible.
* `lastVestingClaim`: timestamp at which pending vested yield was last rolled into `_totalAssets`.
* `strategyPaused`: harvesting pause state. `1 = unpaused`, `2 = paused`. (Stored as a `uint256` sentinel, not a `bool`, for gas reasons.)

**Why the 4th slot differs:** the two subclasses pack `_vestingData` differently. StrategyCToken uses 176 bits for `vestingRate` (external yield can be large and arbitrary-denominated before fee), leaving 40+40 bits for the two timestamps and no room for an index. BorrowableCToken uses 96 bits for `vestingRate` (interest-per-second on a bounded debt pool fits), 40+40 for timestamps, and reuses the top 80 bits for `debtIndex` so borrower debt calculations don't need a second storage slot. Consumers should dispatch on `isBorrowable()` to know which shape to expect.

## Considerations

* **Collateral Caps**: Restricts the total exogenous risk from any single asset.
* **20-Minute Hold Period:** Posting collateral or opening a borrow starts a 20-minute window during which the account's collateralized share transfers and debt repayment are blocked. The hold does not prevent deposits or non-collateralized withdrawals.
* **Safe Functions**: Enhanced protection against reentrancy and other vulnerabilities.
* **Liquidation Safeguards**: Only authorized contracts can seize collateral during liquidations.


---

# 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://docs.curvance.com/app/developer-docs/lending-protocol/ctoken.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.
