Compound v2 cTokens represent claims on underlying assets at a market exchange rate
Compound v2 cTokens represent supplied assets through a market exchange rate. Multiplying a holding by that rate gives its underlying asset balance, with appropriate decimal scaling. Redemption exchanges cTokens for the underlying asset when market cash and account collateral checks permit it. Existing balances remain relevant after v2's deprecation, which paused new supplies and borrows.
The amount shown in a wallet can describe cTokens, underlying assets, or their monetary value. These quantities answer different questions. Understanding their relationship explains both an unchanged token count and a withdrawal that cannot immediately complete.
Holding, redeeming, and transferring existing balances
Existing holders can retain their cTokens, request redemption, or transfer them where the protocol permits the transfer.
Holding preserves the claim represented by the tokens. Redemption reduces the cToken holding and delivers underlying assets. A transfer changes who holds the claim without withdrawing underlying assets from the market.
Compound v2's wind-down paused new minting and borrowing while preserving withdrawal, repayment, and liquidation functions. Those remaining functions retain their contract conditions. A withdrawal being available does not mean every requested amount can succeed.
The underlying assets form a shared market pool. A holder does not own a particular borrower's repayment or wait for a personally assigned loan to mature.
Cash, borrowing, and reserves in the exchange rate
The exchange rate connects the market's net underlying assets with the cTokens representing claims on those assets. For a nonzero cToken supply, its economic relationship is:
exchange rate = (cash + total borrows - total reserves) / cToken total supply
Cash means underlying assets held by the market contract. Total borrows records outstanding borrowing, including accrued interest already incorporated into accounting. Reserves belong to the protocol and are excluded from the assets attributed to cToken holders. All quantities require compatible units before division.
If total supply is zero, the contract uses its configured initial exchange rate instead.
Why can the exchange rate stop growing?
The exchange rate can remain unchanged when borrower interest contributes nothing to suppliers after the reserve allocation. A constant cToken count is also normal: interest accounting changes the conversion rate rather than distributing additional cTokens.
The reserve factor determines how much borrower interest enters protocol reserves. When the factor allocates all interest to reserves, borrowing can accrue interest without increasing suppliers' net claim through that accrual. The rate calculation accounts for both utilization and the portion remaining after reserves.
The v2 deprecation measures increased reserve factors across its markets to allocate all borrower interest to reserves. Historical explanations of continuously growing supplier balances therefore do not establish continuing earnings after that change. Previously accumulated value remains part of the exchange-rate calculation.
Decimal scaling before redemption
Contract amounts use integer units, so the cToken balance and exchange-rate mantissa require different conversions before display.
Raw values and displayed quantities
Compound v2 cTokens use 8 decimal places, while the underlying asset's precision varies. The exchange-rate mantissa includes that difference. Treating every returned number as an ordinary decimal produces incorrect balances.
Underlying units per whole cToken
Let
M
denote the returned exchange-rate mantissa and
d
the underlying asset's decimals. The displayed underlying amount per whole cToken is
M / 10^(18 + d - 8).
Underlying balance from raw cTokens
Let
B
denote the raw cToken balance. Its underlying balance in raw units is
floor(B × M / 10^18). Dividing that result by
10^d
gives the displayed underlying quantity.
Integer division discards fractional smallest units. Rounded wallet displays can consequently hide residual cTokens or overstate a precisely redeemable amount. Full-balance requests should use the raw balance rather than reconstructing it from rounded text.
Stored values and interest accrual
The distinction between stored and accrued reads explains why two balance queries can return different underlying values.
exchangeRateStored()
calculates from existing accounting without first accruing interest.
exchangeRateCurrent()
accrues interest before calculating the rate. Similarly,
balanceOfUnderlying(account)
uses an updated rate, whereas
balanceOf(account)
returns the cToken quantity.
An off-chain simulation of a state-changing function can calculate its result without persisting the accounting changes. A later transaction executes against its own block state. A displayed calculation therefore establishes neither a reserved exchange rate nor a completed withdrawal.
Contract methods and the quantity they control
The relevant method depends on whether the task is valuation, withdrawal, or moving the claim to another address. The distinction also determines which quantity the caller supplies.
| Method | Purpose | Caller control |
|---|---|---|
balanceOf
|
Read cToken holdings | Select the account to inspect |
exchangeRateStored
|
Read the rate without accrual | Select the market; no funds move |
exchangeRateCurrent
|
Calculate the rate after accrual | Select the market; no payout occurs |
balanceOfUnderlying
|
Calculate an account's underlying claim | Select the account; no redemption occurs |
redeem
|
Redeem a specified cToken quantity | Caller fixes the cToken input |
redeemUnderlying
|
Request a specified underlying quantity | Caller fixes the underlying amount |
transfer
|
Move cTokens to another address | Holder selects quantity and recipient, subject to restrictions |
| Selection rule | Reads calculate; redemption withdraws; transfers move claims | Contract checks constrain every movement of funds |
The redemption methods use the exchange rate during execution. Specifying underlying units makes the requested withdrawal amount explicit; specifying cTokens makes the quantity surrendered explicit. Neither choice bypasses market or account restrictions.
Market cash and collateral restrictions
Redemption requires enough underlying cash in the selected market and permission under the account's collateral calculation. These conditions measure different things.
A positive underlying balance includes claims supported by outstanding borrowing. That borrowing does not become spendable cash merely because the exchange rate includes it.
getCash()
measures underlying assets held by the contract, so market cash can be smaller than an individual holder's calculated claim.
For an account that has entered the market, the Comptroller rejects redemption when its projected collateral calculation produces a shortfall. That calculation includes relevant collateral factors, prices, and debts. A market outside the account's collateral membership bypasses this particular liquidity check, although other redemption conditions remain.
Underlying asset delivery and contract compatibility
Redemption delivers the underlying asset through the market's transfer implementation, which differs between token and native-asset markets.
Token delivery
A CErc20 market transfers its configured underlying ERC-20 token to the redeemer. Its transfer wrapper handles token return data and rejects a reported transfer failure. The requested asset must match that market's underlying asset; redemption does not perform a swap.
Native-asset delivery
A CEther market sends native Ether. A receiving contract must accept the delivery behavior of the deployed implementation. A rejecting recipient can make redemption revert despite sufficient market cash and collateral. Contract ownership of cTokens therefore requires compatible withdrawal logic, not merely support for displaying an ERC-20 balance.
Redemption failures and the limits of retrying
A failed redemption needs a response tied to its cause, because elapsed time does not repair every failure.
Insufficient market cash can justify reducing the request or waiting for cash to return through repayments. Neither action guarantees that the next attempt will pass. A collateral rejection instead requires a permissible amount or a change in the account's debt and collateral position. Repaying debt can improve that calculation; repeating an unchanged rejected request cannot.
Missing price data requires the relevant oracle dependency to be restored; reducing the amount does not fix it. If a holding contract cannot receive the underlying asset but supports cToken transfers, it may transfer its cTokens to a compatible address under your control for redemption. That address must support redemption and receipt of the underlying asset, and both operations remain subject to their contract checks. Failure handling also varies across implementations: older cToken code can return a nonzero error and emit a failure event, while other implementations revert. Transaction inclusion alone is insufficient evidence of redemption.
Redemption records and the transfer alternative
A completed redemption records the underlying amount delivered and the cToken quantity removed in its
Redeem
event. The event must belong to the intended market and redeemer.
The resulting balances should agree with that operation. A successful transaction receipt without the expected redemption can reflect an application-level failure in implementations that return error codes. Contract integrations must handle those results rather than treating every mined transaction as a payout.
Transferring cTokens preserves the claim in token form and moves it to the recipient. It does not deliver underlying assets or eliminate restrictions on transferring collateral. Redemption is the operation that converts the permitted claim into the underlying asset; transfer changes who can exercise that claim.
Compound v2 cTokens: quick answers
Can redeemUnderlying send assets to a different recipient?
The standard redeemUnderlying method pays the caller and does not accept a separate recipient argument. An intermediary calling it receives the underlying assets itself. Forwarding those assets requires additional behavior in that intermediary, rather than a recipient setting in the standard redemption method.
Is the cToken exchange rate a dollar price?
The cToken exchange rate expresses underlying assets per cToken, not dollars per cToken. Monetary valuation additionally requires the underlying asset's price. A change in that price can alter the displayed monetary value even when the cToken quantity and underlying exchange rate remain unchanged.
Does the exchange rate differ between holders of the same cToken?
Holders of the same cToken market share its exchange rate at the same accounting state. Their underlying balances differ because their token quantities differ. Deposit dates do not create separate personal exchange rates, although comparing records from different blocks can produce different conversion values.
Will redeeming cTokens automatically repay my borrowing?
Redemption withdraws underlying assets and does not itself repay an outstanding loan. Repayment is a separate operation that reduces the borrow balance. An account can therefore retain debt after a permitted partial redemption, and collateral requirements continue to apply to that remaining position.
Must I claim supply interest separately before withdrawing?
Supply interest already reflected in the exchange rate is included in the underlying value used for redemption. It does not require a separate interest claim. Accrued COMP belongs to different reward accounting, so redeeming cTokens does not establish that a COMP payment occurred.
Why did my cToken holding decrease without a redemption?
A transfer or liquidation can reduce a cToken holding without a redemption by that holder. Liquidation seizes cToken collateral under the protocol's applicable rules. Token movements and liquidation records distinguish those changes from a change in the exchange rate, which alone does not reduce the token quantity.