# Coupon Token

{% hint style="info" %}
**Source:** `src/fira_bonding/core/YieldContracts/CouponToken.sol`, `src/fira_bonding/core/YieldContracts/InterestManagerCT.sol`
{% endhint %}

## Contract summary

CT extends `InterestManagerCT` and `FiraERC20`. Like BT, the FW, BT, factory, expiry, and `doCacheIndexSameBlock` fields are all immutable. All external mutating functions use `nonReentrant`.

## Minting BT+CT

`mintBC(receiverBT, receiverCT)` takes FW that has been pre-transferred to the CT contract, converts the FW amount to underlying asset units via the BC index, and mints equal BT and CT. The BC index is `max(FW.exchangeRate(), storedIndex)` — monotonically non-decreasing.

`mintBCMulti` does the same for multiple receivers in one call.

## Redeeming BT+CT

`redeemBC(receiver)` burns BT from `address(this)` (must be pre-transferred) and burns CT if not expired. FW is returned based on the current BC index.

**Post-expiry:** The redeemable FW amount is calculated at the *current* BC index, but the excess between the post-expiry first index and the current index accrues as treasury interest. Post-expiry yield goes to the protocol, not to redeemers.

## Interest accounting

`InterestManagerCT` tracks per-user interest via `UserInterest { index, accrued }`. On every CT transfer (`_beforeTokenTransfer`), interest is distributed to both sender and receiver:

```
interest = principal × (currentIndex - prevIndex) / (prevIndex × currentIndex)
```

Claims go through `_doTransferOutInterest`, which deducts `interestFeeRate` and sends the fee to treasury.

### Key design decisions

* Interest is based on CT balance, not FW balance
* Protocol fees are taken at claim time, not at accrual time
* `_distributeInterestForTwo` skips `address(0)` and `address(this)` to avoid phantom accounting

## BC index caching

If `doCacheIndexSameBlock` is true, the BC index is only updated once per block. This prevents sandwich attacks where the FW exchange rate is manipulated within a block to extract value from CT holders.

## Post-expiry state

`_setPostExpiryData()` is called on the first interaction after expiry. It snapshots the BC index and reward indices. After this, the interest index is frozen to `postExpiry.firstBCIndex`, and all subsequent yield flows to treasury.

`redeemInterestAndRewardsPostExpiryForTreasury()` sweeps all post-expiry interest to the treasury.

## Inherited contracts

* `InterestManagerCT` — Per-user interest tracking
* `FiraERC20` — ERC-20 with reentrancy guard


---

# Agent Instructions: 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.fira.money/developers/protocol-contracts/yield-contracts/coupon-token.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.
