- Protections (LP, claim A) — every swap where you are the protected LP, with a per-card Settle button at expiry.
- Deposits (depositor, claim B) — your senior and junior NAV in the pooled cvAMM vault, with inline request-withdrawal and withdraw.
- MM Book (market maker, claim B) — the swaps you underwrite on
Path B, plus your collateral usage in the
UnderwriterVault.
/markets or /data, the Dashboard is per-user
and write-capable: it is where the asymmetric actions happen — collect an LP payout,
queue a tranche exit. It is built on a bounded on-chain swap scan rather than the
subgraph, so it is fully live today within that bound.
Reads degrade, never throw. Discovery walks the chain directly (no subgraph yet); any
read that can’t resolve — a reverting oracle, an absent record, the not-yet-indexed
subgraph — renders a typed
PendingNote with its reason, never an error. “Pending” is a deliberate trust signal, not a bug.
See degradation and status & caveats.What you need before it shows anything
1
Connect on Arbitrum Sepolia
The whole page is behind a
ConnectGate: “Connect a wallet on Arbitrum Sepolia to see
your protections, deposits, and MM book”. Every query is
enabled: !!owner — nothing fetches until a wallet is connected. See prerequisites.2
Have actually transacted
The Dashboard is a mirror, not a faucet. It shows protections you bought on
/protect, deposits you made on /earn, and fills you
underwrote on /underwrite. With no activity, each of the three
sections renders its own honest empty-state.How discovery works — one bounded scan, three slices
There is no subgraph indexing events yet, so the page cannot ask “give me all of this user’s swaps.” Instead it enumerates the global swap table directly and filters client-side. The LP slice readsnextSwapId to bound the walk, then iterates downward from the
most recent swap for up to SCAN_LIMIT = 400 ids:
swaps(id) record — decode it,
keep only rows where lp == you and status != 0 — before paying for the enriched
getProtectionStatus, which touches the oracle and computes a settlement preview. An unreadable id is skipped, not fatal: a single bad row
cannot break the whole scan. The two underwriter slices
reuse the same idea — mm.getBook(owner, { fromSwapId: 1n }) walks the same range
internally.
The three slices are independent React-Query subscriptions, so a degraded depositor read
never blanks your LP protections, and vice-versa. A single
invalidateAll() re-fetches everything after any write succeeds.
Why a scan, not the subgraph?
The subgraph is the right tool for unbounded history and aggregates; it is not yet
indexed (events have been emitted on-chain since deploy block
274081134). Rather than
block the portfolio behind an offline indexer, the Dashboard reads the chain directly for
the recent, actionable window — the swaps you can still settle or manage. See
the subgraph integration and what’s live.Section 1 — Protections (LP, claim A)
Each discovered protection is enriched into aProtectionStatus and paired with its
checkpointed fees, then rendered as a card with its own settle transaction state — so
each row settles independently.
A protection card surfaces the load-bearing facts of the hedge: the cap and the
no-bad-debt framing. The section note restates the qualified
claim verbatim:
LPs are always paid — no bad debt in FULL (capped payout + solvent USDC +
oracle/settlement liveness). Payout = min(realized IL, MaxIL); the cap is load-bearing.
The payout an expired protection pays is exactly:
which is why the cap is what makes the guarantee hold by construction. See the
IL formula and the MaxIL derivation.
Settling at expiry
The Settle button on each card callssdk.lp.settle(swapId).
The SDK recovers the swap’s expiry, walks the Chainlink feed for the round bracketing the
expiry timestamp if you pass no hint, then submits settle(swapId, hintRoundId). The
button runs through useTx — signing → pending → success — and
trims viem’s verbose revert dumps to the first line.
Settlement is rail-agnostic and identical to
/protect. Whether the
counterparty is the cvAMM pool (Path A) or an
MM (Path B), settle pays your realized IL — capped at MaxIL —
from the underwriter’s collateral, and returns your NFT. The settlement core does not
branch on the rail; see the lifecycle.Section 2 — Deposits (depositor, claim B)
This slice readsdepositor.getPosition(owner) and renders a senior and a junior
card side by side, each with Your NAV (your shares converted to assets via
convertToAssets), Shares, any queued withdrawal with an unlock countdown, and inline
withdraw controls. The junior card is badged
FIRST-LOSS.
The section note states the risk before any number:
You underwrite pooled in-range IL via the dual-tranche cvAMM vault. Capital is NOT guaranteed — junior is first-loss; senior is protected from underwriting loss only, not the systemic tail.This is never merged with the LP no-bad-debt claim. They are two separate claims: claim A is a guarantee to the LP being paid; claim B is the depositor’s capital being at risk. The senior tranche’s structural protection is junior-first only: Senior still takes the systemic tail (USDC depeg, oracle/settlement failure, contract bug) once the junior buffer is exhausted. See tranches and the collateral models.
Withdrawing a tranche
Withdrawals are two-step and cooldown-gated, exposed inline on each card:1
Request withdrawal
The Request withdrawal button queues your full share balance via
sdk.depositor.requestWithdrawal(tranche, shares). It
appears only while shares > 0n.2
Wait out the cooldown
A queued withdrawal shows the share count and an Unlocks in countdown. The Withdraw button stays disabled until the request
has matured —
withdraw.secondsRemaining === 0n.3
Withdraw
Once matured, Withdraw calls
sdk.depositor.withdraw(tranche).Section 3 — MM Book (claim B)
The underwriter slice combines two reads:mm.getMmCollateral(owner) for the collateral
card and mm.getBook(owner, { fromSwapId: 1n }) for your active fills. The section note restates the risk:
Active swaps you underwrite (Path B) + your collateral usage. MM capital is NOT guaranteed — you are short the capped IL claim and post collateral == MaxIL per fill.
Collateral card
A degraded read or an address with no record renders aPendingNote inviting a deposit;
otherwise the card shows three stats:
The invariant on the card label is I5 — vault solvency:
locked ≤ deposited, enforced per-MM on-chain. Each Path-B fill locks exactly MaxIL
of your own collateral — that is what keeps payout ≤ collateral true for the swaps you
write, the no-bad-debt math applied to a single underwriter.
Active fills
When you have open fills, a panel headers the count and your aggregate exposure — Σ V0 and Σ MaxIL (amber) — over a per-swap table of swap / V0 / MaxIL / premium / expiry. Discovery is the same on-chain scan, so the aggregate exposure is exact for the scanned window. To manage outstanding quotes (cancel a nonce so it can never fill), go to/underwrite — cancelNonces lives there.
The two limits to read honestly
The Dashboard is fully live within two well-understood bounds. Neither is hidden; both are named on the page with their reason and path-forward.The on-chain scan is bounded to the last 400 swaps
The on-chain scan is bounded to the last 400 swaps
Limit. LP discovery and the MM book walk only the most recent
SCAN_LIMIT = 400 swap
ids. A protection older than that window will not
appear here.Why. With no subgraph yet, each id costs RPC reads (a cheap pre-filter plus, on a
match, an enriched oracle-backed status). An unbounded scan would be slow and could
rate-limit the public RPC; bounding it keeps the portfolio responsive and is more than
enough to cover the actionable window — the swaps near or past expiry that you can still
settle or manage.Mitigation. The section renders an explicit PendingNote: “Discovered by a bounded
on-chain scan of the last 400 swaps. Full position history (and exact uncollected fees)
goes live with the subgraph; the on-chain scan works now”.
Full, unbounded history is exactly what the subgraph will serve once
indexed. For the current cohort (a single fresh redeploy on 2026-06-05) every live swap is
inside the window.getClaimableFees under-states uncollected LP fees
getClaimableFees under-states uncollected LP fees
Limit. The fees shown on an LP protection card come from
getClaimableFees, which
reads the position’s checkpointed tokensOwed only — so it under-states the true
uncollected fee balance.Why. Fees accrued since the last on-chain checkpoint live in the pool’s per-position
fee-growth accumulators and are not materialized into tokensOwed until a collect/poke
touches the position. Reading the exact live figure would require replaying fee-growth
math off-chain.Mitigation. The card frames this as a floor, not the answer, and the pending note
points to the subgraph for the exact figure. Critically, this is a display-only
caveat on a secondary number — it does not affect your IL payout. Your hedge payout is
computed from min(realized_IL, MaxIL) at settlement and is unaffected by fee display. Note also that the LP keeps all position fee accrual
throughout the hedge — Inflexion never custodies the fee stream
(see the lifecycle).Quick reference
All discovery is a bounded on-chain swap scan (
SCAN_LIMIT = 400), live today; precise
history, aggregates, and exact fees follow the subgraph.
See also
Buy & settle protection
The LP flow that creates the protections this page settles.
Deposit into the vault
The depositor flow behind the senior/junior tranche cards.
Underwrite as an MM
Sign firm quotes and cancel nonces — the source of your MM book.
Live deployment addresses
Every contract this page reads, on Arbitrum Sepolia.