A liquidity position is long the token it holds. HedgedLPVault is an LPVault paired with a short perp on Lighter, sized to the position's delta, so you keep the fee income and shed most of the price exposure.
How the hedge is counted
The chain cannot read Lighter, so the vault takes the hedge's value from reports:
totalAssets() = LP position + idle balances
+ equityUsd converted to WETH through Chainlink ETH/USD
If the feed reverts, answers zero or less, or has not updated for 25 h, the hedge counts as zero rather than reverting, so exits do not depend on the oracle.
Who does what
| Key | Can | Cannot |
|---|---|---|
| Hedger (hot, on the API server) | call reportHedge | move any funds |
| Funder (cold, one per vault) | call fundHedge and returnHedge; withdraw the margin on Lighter | make the vault pay any address but the fixed Lighter deposit contract |
| Signer's order key | open, close and resize the perp | withdraw from the account |
Where the margin lives
Trading a Lighter account needs an API key bound by a signature from the account's owner, and Lighter has no accounts owned by a contract. So fundHedge credits margin to the Lighter account of the vault's funder, an ordinary wallet key the operator holds offline. The signer holds that account's order key, the hedger trades and reports it, and fundingConfig().funderKey names it on chain. No two vaults share an account.
The caps bound what can leave for Lighter, measured against the position and idle balance, never against reported equity. They do not bound what happens to margin once it is there. The app takes no deposits into a hedged vault that has never been reported on.
Moving margin
fundHedge(assetAmount) is refused while the vault is paused. It sells WETH for USDG behind a TWAP check, with a floor of the TWAP quote less maxSlippageBps, and deposits at least 1 USDG through Lighter's bridge.
returnHedge(usdgAmount) works even while the vault is paused. The funder withdraws USDG on Lighter with its own key and calls it, and the vault sells the USDG for WETH behind the same floor. USDG sent straight to a vault is not counted and cannot be moved again.
Margin takes minutes to cross, so it is counted wherever it is. Both calls move the stored equity in the same transaction, and each report counts the Lighter account's equity, deposits not yet credited, withdrawals not yet paid out, and the USDG and WETH in the funder's wallet. A piece that moves during a read is counted twice for one report, so the share price can read briefly high and never low.
The hedger bot
The hedger runs every 30 s. It sizes the short to the position's balance of the risk asset, and acts when a report is due (every 15 min) or when drift passes 200 bps of the target. It sends at most one market order per tick, between $50 and $25,000. Buys shrink the short and are always reduce-only. Once the hedges have lost $2,500 in a UTC day it places no more orders that day, and reports continue.
When the vault pauses
A report from the hedger with a fresh asOf is always stored, even one that trips the band. The band compares it with the stored equity: the last report plus USDG funded less USDG returned since. A move of more than 15 % pauses the vault, and the next in-band report clears it. Staleness needs no transaction: the vault is paused the moment its last report is older than 1 h.
The band limits each report, not a series of them, so reports inside it can move equity step by step. A paused SPY Hedged also stops the Protected SPY note's entries and exits, because 15 % of the note sits in it.
contracts/src/HedgedLPVault.solfundHedge, returnHedge, reportHedge, pausedcontracts/src/libraries/HedgeFunding.solthe TWAP-floored swaps and the Lighter depositapps/api/src/bots/hedger.tsone tick: read, size, trade, report