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_bpsof 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:
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.
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 hourcarry_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:
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:
- Charges the time since the last crank at the rate held over
it. At most
max_hold_secsis charged per crank; time beyond it goes uncharged, so a stalled crank never back-charges a large span. - Samples a fresh rate from the book.
- 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.
- Within a UTC hour, the held rate moves toward each fresh sample
as an exponential average, weighted by the time since the last
sample (
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). 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.
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:
funding = −10,000 lots × 30 ticks = −300,000 ticks = −0.30 USDCThe 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.