Funding Rate
Funding is the periodic payment between longs and shorts that tethers the perpetual price to the underlying index. When the mark price trades above the index, longs pay shorts; when it trades below, shorts pay longs. Over time, this incentivizes arbitrageurs to close the premium and keeps the perp anchored.
Interval and magnitude
| Parameter | Value |
|---|---|
| Funding interval | 8 hours |
| Max funding rate per period | ±0.1% (10 bps) of notional |
| Execution | Permissionless — any caller can invoke apply_funding |
| Direction | Positive rate → longs pay shorts. Negative rate → shorts pay longs. |
Implementation: programs/obv-perps/src/math/funding.rs.
At 10 bps per 8 hours, the maximum annualized funding is ~109% (compounded). Real funding rates are typically much smaller — the cap exists only to bound worst-case payments during extreme dislocations.
How the rate is computed (TWAP over the 8h window)
The funding rate is not an instantaneous premium snapshot. That would be trivially manipulable — an attacker could spike the mark at the moment apply_funding was called and force-pay the counterparty.
Instead, every update_oracle call appends a premium sample to an on-chain accumulator. The stored value is the absolute delta:
premium_sample = mark_price_ema − oracle_priceAcross an 8-hour funding window, dozens of samples accumulate (the crank pushes every ~5 minutes when prices move enough). At apply_funding, the program:
- Averages —
avg_premium = premium_accumulator / premium_sample_count(plain mean of all samples since the last interval). - Normalises to a rate —
avg_premium × 10000 / oracle_price, yielding a bps premium. - Clamps — the result is capped at ±10 bps.
The final clamped rate is what apply_funding applies. See calculate_funding_rate_from_premium in programs/obv-perps/src/math/funding.rs.
Note on outlier rejection. Earlier drafts described a 2σ outlier filter on the premium samples; this is not implemented in v1. The on-chain math is a plain mean. Outlier rejection is tracked as a potential future hardening, primarily defensive against multi-hour coordinated manipulation rather than single-block spikes (which the EMA mark already dampens).
Payment computation per position
Funding accrues into two cumulative counters on MarketConfig:
cumulative_funding_long— the total funding per unit of long OI since market inceptioncumulative_funding_short— same for short OI
Each position snapshots the cumulative value at open time into entry_cumulative_funding. When funding is applied — at trade close, at margin transfer, or at any explicit apply_funding call on the position — the payment is:
payment = size × (cumulative_now − cumulative_at_entry) / 10^6The sign flips for shorts: longs pay positive funding (lose collateral) and receive negative funding (gain collateral); shorts do the opposite. See calculate_funding_payment.
Worked example
Long position of 1,000 USDC opened when cumulative_funding_long = 0. After 24 hours (three funding intervals), suppose the cumulative counter has grown to 300 (scaled by 10^6 — representing 0.0003 per unit).
payment = 1_000_000_000 × 300 / 1_000_000 = 300_000 (0.30 USDC)The long has paid 0.30 USDC to the shorts over that day. Their effective collateral is reduced by that amount. The payment is settled on the next position interaction (close, margin transfer, or explicit apply).
Interval normalization
Under the hood, funding is stored as a per-8-hour rate. If apply_funding is called after a non-standard interval (e.g., a missed crank cycle means 12h between calls), the delta is scaled:
cumulative_delta = rate_bps × elapsed_seconds × 10^6 / 28_800 / 10_000
(where 28_800 = 8 × 3600 seconds)This means a single missed interval doesn’t let longs or shorts escape funding — the next application catches up with a proportionally larger delta.
What drives funding
Funding rate is the premium vs the oracle, not vs arbitrary fair value. So:
- Mark > Oracle (longs are bidding aggressively) → positive rate → longs pay shorts → arbitrage incentive for shorts to step in and close the premium.
- Mark < Oracle (shorts pressing) → negative rate → shorts pay longs → symmetric arbitrage.
- Mark = Oracle → zero rate.
Since the mark itself is a composite of oracle and vAMM (see Mark Price), the premium reflects how far the vAMM has dragged the mark away from the OBV-derived fair value. Funding is literally the cost of disagreeing with the index.
Operational characteristics
- Cranking is permissionless. The funding crank runs as part of the keeper bot on an 8h schedule, but any third party can call
apply_fundingto settle pending deltas. - Positions don’t need to be active for funding to accrue. Funding accrues into the market’s cumulative counter regardless of individual position activity. A trader who opens at cumulative = 0 and closes at cumulative = 1,000 pays the full 1,000-delta × size amount at close, even if they never explicitly applied funding.
- TWAP samples are collected by the oracle crank, not the on-chain program. The samples are passed through
update_oracleas part of the crank’s normal cadence. This keeps the on-chain logic simple while giving TWAP-level manipulation resistance.
Anti-manipulation characteristics
Two layers protect funding from being gamed:
- TWAP averaging — a single spike across dozens of samples can’t move the rate materially.
- ±10 bps cap — worst-case per-period payment is bounded regardless of premium magnitude.
An attacker would need to sustain an artificial mark-vs-oracle dislocation for most of the 8-hour window — a much harder ask than a single-block manipulation, even without outlier filtering. (Adding 2σ outlier rejection on premium samples is on the post-launch hardening list.)
Further reading
- Mark Price — the composite that produces the premium.
- Entry Price & PnL — how funding interacts with unrealized PnL in the effective-collateral check.
- Oracle Design — the other half of the premium calculation.