# Funding

A perpetual never expires, so something has to pull its traded price
toward the underlying. On Flint that is **funding**: a continuous
transfer between longs and shorts, sized by how far the makers' book
sits from the index.

* When the book bids **above** the index, the rate is positive and
  **longs pay shorts**.
* When the book offers **below** the index, the rate is negative and
  **shorts pay longs**.

Funding is peer-to-peer. The protocol takes no cut of it.

## The rate

The rate is computed in the contract's own units — ticks per lot
per hour — from three readings taken at the moment of a funding
crank.

**1. Impact prices.** The program walks a probe of
`impact_notional_atoms` (PnL-currency atoms) into each side of the
makers' merged book and takes the average fill price:

* Only levels within `max_level_divergence_bps` of the index count.
* A side that runs out of depth, or whose average is not richer than
  the index, contributes nothing.

**2. Premium.** How far each side sits on the rich side of the
index:

```text
premium = max(0, impact_bid − index) − max(0, index − impact_ask)
```

A two-sided book that straddles the index has a premium of zero.

**3. Carry, clamp and cap.**

```text
rate  = premium + clamp(carry × index − premium,  ±carry_clamp × index)
cap   = min(max_rate_per_hour, max_rate_margin_factor × (imf − mmf)) × index
rate  = clamp(rate, ±cap)                      // ticks per lot per hour
```

`carry_per_hour` is a baseline hourly rate the premium is pulled
toward, by at most `carry_clamp`. The cap is the smaller of a fixed
hourly ceiling and a multiple of the contract's margin band, so
funding can never outrun the room between initial and maintenance
margin.

As a fraction, the hourly rate is `rate / index`. That is the
figure `FundingService.GetFundingRates` reports: `rate` is a
decimal fraction per `interval_seconds = 3600`, positive when longs
pay.

## Accrual

The rate is converted to ticks per lot **per second** and
integrated continuously into a cumulative **funding index** on the
contract (one for each side). A position owes:

```text
funding = −lots × (index_now − index_at_last_settlement)
```

so a long (positive lots) pays when the index rises and a short
receives the same amount.

Keepers crank each contract with `sync_linear_perp_cache`, which
does three things in order:

1. **Charges** the time since the last crank at the rate held over
   it. At most `max_hold_secs` is charged per crank; time beyond it
   goes uncharged, so a stalled crank never back-charges a large
   span.
2. **Samples** a fresh rate from the book.
3. **Holds** the next rate:
   * Within a UTC hour, the held rate moves toward each fresh sample
     as an exponential average, weighted by the time since the last
     sample (`rate_per_second_retention`).
   * At the first sample after the UTC hour changes, the period
     closes and the fresh sample replaces the held rate outright.

A new rate only applies from the moment it is sampled; no span is
ever charged at a rate measured after it.

## Parameters

Each contract carries its own funding parameters, set at listing
and changeable by Flint (rate-moving ones only through the 24-hour
timelock).

| Parameter | Listing default | Role |
| --- | --- | --- |
| `impact_notional_atoms` | 1,000 USDC | Probe size for the impact prices |
| `max_level_divergence_bps` | 500 (5%) | How far from the index a level still counts |
| `carry_per_hour` | 0 | Baseline hourly rate |
| `carry_clamp` | 0 | Max pull of the carry on the rate |
| `max_rate_per_hour` | 0.05% | Hard hourly ceiling |
| `max_rate_margin_factor` | 1 | `k` in the `k × (imf − mmf)` ceiling |
| `rate_per_second_retention` | ≈ 0.99923 | Exponential average; 15-minute half-life |
| `max_hold_secs` | 300 | Longest span one crank may charge |
| `funding_active` | on | Whether funding accrues at all |

With the defaults, the carry is zero and the rate is the clamped
premium. Turning `funding_active` off stops accrual (the index
holds) without pausing trading.

## How it hits your PnL

Funding never moves tokens by itself. It is booked onto your
position's **funding leg** in three ways:

| When | Booked through |
| --- | --- |
| Any fill on the position | The current index — the old size pays for all the time it was held |
| `settle_funding` (permissionless; keepers run it periodically) | The index as it stood when the current UTC-hour period began |
| Margin checks | Not booked, but the accrued amount through the current index always counts toward health |

The funding leg then moves into your settlement-asset balance with
the rest of your unsettled PnL when `settle_realised_pnl` runs (see
[Collateral & margin](/overview/margin#withdrawals)). Credits and
debits are whole ticks, rounded down; the sub-tick remainder is
carried, so many small settlements add up to exactly what one large
one would.

## Worked example

On `SOL-USDC-PERP` (1 lot = 0.001 SOL, 1 tick = 1 USDC atom), the
index is $150, which is 150,000 ticks per lot. A $1,000 probe walked
into the bids fills at an average of 150,030 ticks; the asks are no
richer than the index.

```text
premium         = 150,030 − 150,000              = 30 ticks/lot/hour
hourly rate     = 30 / 150,000                   = 0.02% per hour
cap             = min(0.05%, 1 × (10% − 5%)) × 150,000
                = 0.05% × 150,000                = 75 ticks/lot/hour
charged         = 30 ticks/lot/hour  (inside the cap)
```

A long of 10 SOL (10,000 lots) held for an hour at that rate:

```text
funding = −10,000 lots × 30 ticks  = −300,000 ticks = −0.30 USDC
```

The matching shorts receive 0.30 USDC between them. Check:
$1,500 notional × 0.02% = $0.30.

## Reading funding from the API

| RPC | Returns |
| --- | --- |
| `FundingService.GetFundingRates` / `SubscribeFundingRates` | The held rate as an hourly fraction per contract |
| `PerpPosition.accrued_funding_usd` | Funding accrued since the position's last booking |
| `GetAccountHistory(include_perp_pnl=true)` | Estimated cumulative funding in perp PnL history |

Funding accrues continuously, so no scheduled payment time is
advertised (`next_funding_at` is unset). Funding-rate history and
per-payment history RPCs are defined but not yet served.
