# Router Architecture

## Overview

The `FiraRouterV4` is the single entry point for all user-facing protocol operations. It extends OpenZeppelin's `Proxy` and uses a selector-to-facet mapping to delegate every call to the appropriate action contract.

{% hint style="info" %}
Since the proxy uses `delegatecall`, all facets share the same storage. `RouterStorage` uses ERC-7201 storage namespacing (a hashed storage slot) to avoid collisions with any facet's own storage layout.
{% endhint %}

## How it works

### Call routing

When a user calls any function on the router:

1. The `fallback()` function reads `msg.sig` (the 4-byte function selector)
2. Looks up the registered facet address in `CoreStorage.selectorToFacet[msg.sig]`
3. If no facet is registered, reverts with `INVALID_SELECTOR`
4. Otherwise, `delegatecall`s into the facet contract

### Initialization

The constructor takes two arguments: the owner address and the `ActionStorageV4` facet address. It hard-wires the `setSelectorToFacets` and `selectorToFacet` selectors to the storage facet so the owner can configure all other mappings post-deployment.

### Upgrading

The owner can update selector-to-facet mappings at any time via `ActionStorageV4.setSelectorToFacets`. This allows:

* **Adding new features** — Register new selectors pointing to new facet contracts
* **Fixing bugs** — Point existing selectors to updated facet implementations
* **Removing features** — Set a selector's facet to `address(0)` to disable it

No state migration is needed because all facets share the router's storage via `delegatecall`.

## Facet contracts

| Facet                    | Responsibility                                              |
| ------------------------ | ----------------------------------------------------------- |
| **ActionSwapBTV3**       | BT swaps — token/FW to/from BT                              |
| **ActionSwapCTV3**       | CT swaps — synthesized via BT pool + mint/redeem            |
| **ActionAddRemoveLiqV3** | Liquidity operations — dual, single-sided, keep-CT variants |
| **ActionMiscV3**         | FW/BC minting, position exits, multicall, simulate          |
| **ActionBorrow**         | Fixed-rate borrow and repay via lending markets             |
| **ActionSimple**         | Gas-optimized operations using on-chain approximation       |
| **ActionCallbackV3**     | Flash-style swap callbacks from the market                  |
| **ActionStorageV4**      | Admin — ownership transfer, selector management             |

## CT swap synthesis

CT is not directly traded in the AMM (the pool only has BT and FW). CT swaps are synthesized using the flash-callback pattern:

**Buy CT (FW → CT):**

```mermaid
sequenceDiagram
  participant Router
  participant Market as FiraMarket
  participant CT as CouponToken

  Router->>Market: swapExactBtForFw (flash)
  Market-->>Router: FW out (sent first)
  Router->>CT: deposit FW, mintBC
  CT-->>Router: BT + CT minted
  Router->>Market: repay BT (callback)
  Router-->>Router: keep CT as output
```

**Sell CT (CT → FW):** The reverse — buy BT from market with FW, pair with user's CT, redeem BT+CT for FW.

## On-chain vs off-chain approximation

The router supports two modes for calculating swap amounts:

* **Off-chain hint** (`guessOffchain != 0`) — Binary search using `MarketApproxLibV2` with a hint provided by the caller. More gas-efficient for complex operations.
* **On-chain approximation** (`guessOffchain == 0`) — Closed-form approximation using `MarketApproxLibOnchain`. Simpler code path, lower gas cost, used automatically when no hint is provided and no limit orders are present.

## Related contracts

* [`FiraRouterV4.sol`](https://docs.fira.money/developers/protocol-contracts/router) — Router contract details
* [Router Facets](https://docs.fira.money/developers/protocol-contracts/router) — Individual facet documentation
* [Contract Deployments](https://docs.fira.money/developers/contract-deployments) — Deployed facet addresses
