---
title: Perps SDK
description: Quote, inspect, and prepare SV3 physical longs and offset shorts from browsers, Node, bots, and other viem applications.
---

> **For AI agents:** the complete documentation index is at [llms.txt](/llms.txt). Append `.md` to any page URL for its markdown version.

`@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.

<Warning title="The two sides are intentionally asymmetric">
  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.
</Warning>

## Leverage units

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

```ts
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

```ts
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

```ts
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:

```ts
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`:

```ts
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

```ts
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:

```ts
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](/developers/prepare-perp-position) 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](/developers/math/perp-leverage) for the complete return fields and constraint codes, and [Native Offset Shorts](/protocol/offset-shorts) for the economic model.
