> For the complete documentation index, see [llms.txt](https://docs.elara.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.elara.fi/protocol-reference/overview/how-it-works.md).

# How the System Works

Internal mechanics of minting, redeeming, staking, yield, and oracle pricing in Elara.

## Fee Calculation

Fees are defined per token in `TokenRegistry` as basis points (1 bps = 0.01%). The maximum allowed fee rate is **1000 bps (10%)**.

**Mint fee** is deducted from the collateral amount before pricing:

```
fee        = tokenAmount × mintFeeRate / 10_000
netAmount  = tokenAmount − fee
elUSDAmount = _calculateOracleMintAmount(netAmount, tokenDecimals, price)
```

**Redeem fee** is calculated on the elUSD amount, then both principal and fee are converted to collateral tokens at the oracle price:

```
feeInElUSD   = elUSDAmount × redeemFeeRate / 10_000
principal    = _calculateOracleRedeemAmount(elUSDAmount − feeInElUSD, tokenDecimals, price)
feeInTokens  = _calculateOracleRedeemAmount(feeInElUSD, tokenDecimals, price)
```

Both fee amounts are routed to `feeReceiver` in collateral tokens.

## Oracle Pricing & Depeg Guard

elUSD is backed 1:1 by stablecoin collateral held in the treasury — not valued through the oracle. The oracle exists as a **depeg guard**: every mint and redeem reads the live USD price of the incoming/outgoing stablecoin collateral (e.g. USDC, USDT) so the protocol can't be arbed if that collateral temporarily loses its peg.

`PriceOracle.getPrice(token)` returns the feed price normalized to **18 decimals**. The Vault then applies two asymmetric caps:

| Operation | Price used       | What it blocks                                                             |
| --------- | ---------------- | -------------------------------------------------------------------------- |
| Mint      | `min(price, $1)` | Depositing depegged-up collateral (e.g. USDC at $1.02) to mint extra elUSD |
| Redeem    | `max(price, $1)` | Redeeming elUSD for more-than-$1 worth of depegged-down collateral         |

Users always transact at the conservative side of $1 — the protocol refuses to price collateral above peg on the way in, or below peg on the way out.

## Decimal Conversion

The Vault normalizes all amounts through two helpers:

* `_toElUSD(amount, fromDecimals)` — scales amount up to 18 decimals before pricing
* `_fromElUSD(amount, toDecimals)` — scales result back down to collateral decimals after pricing

**Mint example** (1000 USDC at $1.01 — capped to $1.00):

```
Input:        1_000_000_000 units (1000 USDC, 6 dec)
→ _toElUSD:   1_000_000_000_000_000_000_000 (18 dec)
× price $1.00: 1_000_000_000_000_000_000_000 elUSD units = 1000 elUSD
```

**Redeem example** (1000 elUSD for USDC at $0.99 — floored to $1.00):

```
Input:        1_000_000_000_000_000_000_000 (1000 elUSD, 18 dec)
÷ price $1.00: 1_000_000_000_000_000_000_000 (18 dec)
→ _fromElUSD: 1_000_000_000 units = 1000 USDC (6 dec)
```

## Redemption State Machine

Every call to `Vault.redeem()` goes through a consistent lifecycle regardless of whether it settles instantly:

```
redeem()
  │
  ├── emit RedeemQueued(redemptionId, ...)   ← always emitted
  ├── transferFrom redeemer → vault (elUSD)
  │
  ├── canTransferOut?
  │     ├── YES → burn elUSD, pull collateral from withdrawWallet,
  │     │         distribute to recipient + feeReceiver
  │     │         emit RedeemSettled(...)
  │     │
  │     └── NO  → store Redemption{} in queuedRedemptions[id]
  │               (elUSD held in vault until settlement)
  │
settleRedemption(id)    ← callable by anyone (PUBLIC_ROLE)
  │
  ├── validate redemption exists
  ├── check liquidity again (revert if still insufficient)
  ├── delete queuedRedemptions[id]   ← CEI pattern
  ├── burn elUSD from vault balance
  ├── pull collateral from withdrawWallet
  ├── distribute to recipient + feeReceiver
  └── emit RedeemSettled(...)
```

The `redemptionIdCounter` is a monotonically incrementing `uint256` — overflow is practically impossible.

{% hint style="info" %}
elUSD is transferred to the Vault at `redeem()` time and held there until settlement. Burning only occurs when collateral leaves the treasury, preserving the 1:1 backing invariant at all times.
{% endhint %}

## Staking Share Price

`ElUSDStake` uses ERC4626-style share accounting without lock periods:

```
sharePrice = totalElUSD × 1e18 / totalSElUSD
```

On first stake (no shares exist), the ratio is 1:1. After that:

```
stakingShares = elUSDAmount × totalSElUSD / totalElUSD
unstakeAmount = sElUSDShares × totalElUSD / totalSElUSD
```

Share price is **read-only** from the contract's perspective — it rises automatically whenever elUSD is deposited as yield, because `totalElUSD` increases while `totalSElUSD` stays constant.

## Yield Distribution

Yield flows from the treasury operator through a chain of contract calls, with no user action required:

{% stepper %}
{% step %}

#### Treasury operator calls distributeYield

`TreasuryAdapter.distributeYield(amount)` — restricted to treasury operator role.
{% endstep %}

{% step %}

#### TreasuryAdapter delegates to Vault

`Vault.mintYieldToStaking(amount)` — only callable by TreasuryAdapter.
{% endstep %}

{% step %}

#### Vault mints fresh elUSD

`ElUSD.mint(stakingContract, amount)` — mints without collateral backing (intentional; backed by treasury yield).
{% endstep %}

{% step %}

#### Vault notifies staking contract

`ElUSDStake.receiveYield(amount)` — accounting notification only; no token transfer occurs here. Share price increases automatically because `totalElUSD` grew.
{% endstep %}
{% endstepper %}

## ElUSD Account Blocking

`ElUSD` supports compliance-driven account blocking via `blockAddresses` / `unblockAddresses`. The `_update` hook enforces restrictions:

* Blocked accounts **cannot transfer** tokens (reverts with `AccountBlocked`)
* Mint (`from == address(0)`) — **skips** block check; tokens can always be minted to a blocked address
* Burn (`to == address(0)`) — **skips** block check; authorized callers can burn from blocked accounts (compliance mechanism)
