# Security Design

## Access control

### Ownership model

All privileged Fira contracts inherit `BoringOwnableUpgradeable`, which provides:

* Single `owner` with a two-step transfer (`transferOwnership` → `claimOwnership`) to prevent accidental misassignment.
* `onlyOwner` modifier gating admin functions (pause, parameter updates, upgrades).

### Router selector guards

The `FiraRouterV4` uses a diamond-like facet dispatch table. Each facet registers its function selectors during `initialize()`. Calls to unregistered selectors revert with `Errors.RouterInvalidAction`. This ensures that only explicitly whitelisted facets can be invoked through the Router.

### Minting privileges

BondToken and CouponToken restrict `mintBC()` and `redeemBC()` to the `YieldContractFactory` address set at initialization, preventing arbitrary minting.

The LiquidityInjector holds a separate minting privilege on BondToken via the `LIQUIDITY_INJECTOR` role, constrained by the `injectLiquidityLimit` cap.

## Reentrancy protection

Fira applies the `nonReentrant` modifier (OpenZeppelin `ReentrancyGuard`) to all external state-mutating functions across:

| Contract                  | Protected functions                                                 |
| ------------------------- | ------------------------------------------------------------------- |
| **FWBase**                | `deposit`, `redeem`, `claimRewards`                                 |
| **FiraMarket**            | `mint`, `burn`, `swapExactBtForFw`, `swapFwForExactBt`              |
| **CouponToken**           | `mintBC`, `redeemBC`, `redeemInterest`, `redeemInterestAndTransfer` |
| **LiquidityInjector**     | `injectLiquidity`, `withdrawLiquidity`                              |
| **RehypothecationModule** | `rebalance`                                                         |

The Router's `_safeTransferWithFeeExtraction` and callback patterns (flash swaps) are additionally protected by the facet-level lock state in `ActionStorageV4`.

## Pause controls

FW token contracts (`FWBase`, `USDCFW`) inherit OpenZeppelin's `PausableUpgradeable`:

* **`pause()`** — Owner freezes all deposit and redeem operations.
* **`unpause()`** — Owner resumes normal operations.
* **`whenNotPaused`** modifier — Applied to `deposit()`, `redeem()`, and related transfer functions.

{% hint style="warning" %}
Pause does not affect BT/CT trading on FiraMarket. Market operations remain available to allow users to exit positions even during an FW pause.
{% endhint %}

## Upgrade patterns

### Initializable contracts

All upgradeable contracts use OpenZeppelin's `Initializable` with `initializer` / `reinitializer(n)` modifiers to prevent double-initialization attacks.

### Router versioning

The Router facet system supports additive upgrades:

1. Deploy a new facet contract.
2. Call `Router.addToSelectorMapping(selectors, facetAddress)` to register new selectors.
3. Existing selectors can be overwritten to point to the new facet, enabling in-place upgrades without redeploying the Router proxy.

Old facets remain deployed on-chain but become unreachable once their selectors are reassigned.

### Storage layout safety

Upgradeable contracts follow the "storage gap" convention and use dedicated storage slots (e.g., `ActionStorageV4.STORAGE_SLOT`) to avoid slot collisions across upgrades.

## Oracle defence-in-depth

The Fira oracle pipeline stacks multiple validation layers:

```
Aave V3 Oracle
      ↓
AaveToChainlinkAdapter  (normalizes to Chainlink AggregatorV3 interface)
      ↓
ChainlinkOracleV2       (staleness check, sequencer-down check on L2)
      ↓
FiraSolvencyOracle      (solvency ratio validation)
      ↓
BCLpOracle              (fair LP token pricing using BT/FW spot + TWAP)
```

Each layer can reject stale or invalid data independently. `ChainlinkOracleV2` enforces a configurable `heartbeat` and reverts with `StalePrice` if the feed has not updated within the window.

## Fixed-point arithmetic safety

All yield and pricing math uses the `PMath` and `LogExpMath` libraries with 18-decimal fixed-point representation. Key invariants:

* **No division by zero** — All divisors are checked or guaranteed non-zero by prior validation.
* **Overflow protection** — Solidity 0.8.x built-in overflow checks apply; `LogExpMath` additionally validates input ranges before exponentiation.
* **Rounding direction** — Deposit/mint operations round against the user (ceiling); redeem/burn operations round in favor of the protocol (floor), preventing rounding exploits.

## Contract size management

Several Fira contracts approach the EIP-170 24 KB limit. The codebase uses two mitigation strategies:

1. **Library extraction** — Heavy logic is moved to external libraries (e.g., `MarketMathCore`, `MarketApproxPtInLib`) that are deployed separately and linked via `DELEGATECALL`.
2. **Split-code deployment** — The `FiraMarket` factory uses a two-part deployment (`MarketMathCore` + `FiraMarketV3`) to keep each deployment unit under the size limit.

## Invariants summary

| Invariant                                        | Enforced by                                      |
| ------------------------------------------------ | ------------------------------------------------ |
| FW exchange rate monotonically non-decreasing    | `FWBase._afterUpdateBCIndex` + rehyp rebalance   |
| BT total supply = minted via Factory + LI inject | `BondToken.mintBC` access control                |
| CT interest accrual ≥ 0                          | `CouponToken._updateAndDistributeInterest`       |
| LP pool BT + FW reserves ≥ total LP supply       | FiraMarket mint/burn invariant checks            |
| Rehyp ratio stays within `[phiMin, phiMax]`      | `RehypothecationModule.rebalance` bounds check   |
| Lending market solvency                          | LendingMarket liquidation + oracle health checks |


---

# 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/security-and-audits/security-practices.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.
