SV3 logo

Perps SDK

Quote, inspect, and prepare SV3 physical longs and offset shorts from browsers, Node, bots, and other viem applications.

@repo/contract-client is the canonical perps integration surface. It is not tied to the SV3 web app: browser wallets, Node services, trading bots, mobile clients, and read-only analytics tools use the same raw bigint quotes and prepared actions.

A long buys and pledges physical AVM with floor-backed debt. A short is an isolated position against above-floor premium. Do not present the short as a full-token oracle perpetual or the long as a synthetic contract.

Leverage units

Leverage uses basis points, with 10_000n = 1×:

import { PERP_MAX_LEVERAGE_BPS, PERP_MIN_LEVERAGE_BPS } from "@repo/contract-client/math";

PERP_MIN_LEVERAGE_BPS; // 10_000n = 1×
PERP_MAX_LEVERAGE_BPS; // 33_000n = 3.3×

The returned maximum can be lower. Longs are limited by floor capacity, liquid reserve, and live Directory debt/backing headroom. Shorts are limited by initial margin, position/share/offset caps, minimum remaining curve supply, market and protocol escrow headroom, and Directory backing headroom.

Read complete perps state

const context = await sv3.perp.getContext(market);

context.address; // attached OffsetPerpMarket
context.snapshot; // matching FloorMarket snapshot
context.state.activeShortOffsetAvm;
context.marginPolicy.initialMarginMicroBps;
context.caps.maxMarketShortOffsetAvm;
context.protocol.aggregateEscrowRaw;
context.capHeadroom.backing;

getContext validates that the attached perp points back to the requested FloorMarket and uses the same reserve token. Every field is read at the FloorMarket snapshot's block.

Use sv3.perp.getMarket(market) when you only need the attachment address. It returns null when the market has not opted in.

One client quote for either side

import { parseUsdc } from "@repo/contract-client";

const quote = await sv3.perp.quoteByLeverage({
  market,
  owner,
  side: "long", // or "short"
  collateralRaw: parseUsdc("100"),
  leverageBps: 20_000n,
});

quote.side;
quote.requestedLeverageBps;
quote.effectiveLeverageBps;
quote.bounds.maxLeverageBps;
quote.bounds.limitingConstraint;

The discriminated result narrows by quote.side. Long results include AVM acquired, gross and net debt, both fee legs, average entry, floor equity, price impact, and the resulting physical position. Short results include exact AVM size, released premium, conservative restoration obligation, entry premium, IMR/MMR, liquidation buffer, equity, and total wallet debit.

Side-specific methods are also available:

await sv3.perp.quoteLongByLeverage({
  market,
  owner,
  userContributionRaw: parseUsdc("100"),
  leverageBps: 20_000n,
});

await sv3.perp.quoteShortByLeverage({
  market,
  marginRaw: parseUsdc("100"),
  leverageBps: 20_000n,
});

Quote repeatedly without display math

For quote-while-typing consumers, load contexts outside the input loop and use the pure helpers from @repo/contract-client/math:

import {
  getLongLeverageBounds,
  quoteLongByLeverage,
  quoteShortByLeverage,
} from "@repo/contract-client/math";

const account = await sv3.market.getAccountContext(market, owner);
const perp = await sv3.perp.getContext(market);

const bounds = getLongLeverageBounds(account, parseUsdc("100"));
const long = quoteLongByLeverage(account, {
  userContributionRaw: parseUsdc("100"),
  leverageBps: bounds.maxLeverageBps,
});
const short = quoteShortByLeverage(perp, {
  marginRaw: parseUsdc("100"),
  leverageBps: 20_000n,
});

The pure helpers make no RPC calls. Keep dollar formatting, localized numbers, labels, and slider state outside the SDK.

Positions

const lots = await sv3.perp.listOwnerPositionsForMarket(market, owner);

The result contains each live short lot with its deterministic position id, stored position, current health quote, and executable full-close quote. Lots remain separate because their entry bands and carry checkpoints cannot be merged safely.

The direct owner scan is intentionally bounded at 1,024 created lots. Historical or cross-wallet discovery belongs to the indexed API; current execution health still comes from chain.

The physical long is the normal FloorMarket position:

const long = await sv3.position.get(market, owner);

For one short lot, sv3.perp.getPosition, quoteHealth, and quoteClose discover the attachment and pin the read to the matching FloorMarket snapshot block. quoteOpenExactSize is available to integrators that deliberately work in AVM size rather than collateral-first leverage.

Prepare and execute

See Prepare perps actions for leverage-based opens, margin additions, long debt repayment, authorization requirements, simulation, and receipt handling.

Not floor calls

A 1× long pays the curve acquisition price and adds no debt. It is not a mint at the floor. Future floor-call exercise requires a separately issued option entitlement and is not exported by this SDK release.

See Perps leverage math for the complete return fields and constraint codes, and Native Offset Shorts for the economic model.