Skip to content

Reading Data

All read functions are view — free, and callable from any RPC. They live on the same Diamond address as the write functions.

If you would rather query over HTTP, most of this is also available through the REST API, which additionally covers closed positions and history.

Positions

getPositionsV4

solidity
function getPositionsV4(address user, address pairBase) external view returns (PositionV4[] memory);

Open positions for one user in one market. There are V2 and V3 variants with fewer fields; use V4 — the earlier ones exist only for backwards compatibility.

solidity
struct PositionV4 {
    bytes32 positionHash;
    string pair;               // "BTC/USD"
    address pairBase;
    address tokenIn;           // collateral deposited
    address marginToken;       // lvToken — the unit for every amount below
    bool isLong;
    uint96 margin;             // lvToken decimals
    uint128 qty;               // 1e10
    uint128 entryPrice;        // 1e18
    uint128 stopLoss;          // 1e18, 0 if unset
    uint128 takeProfit;        // 1e18, 0 if unset
    uint96 openFee;            // lvToken decimals
    uint96 executionFee;       // lvToken decimals
    int256 fundingFee;         // signed, total = accrued + since-snapshot
    uint32 timestamp;
    uint96 holdingFee;         // total = accrued + since-snapshot
    uint256 earliestCloseTime;
    int256 accruedFundingFee;  // booked-but-unsettled portion
    uint256 accruedHoldingFee; // booked-but-unsettled portion
}

fundingFee is signed: positive means the trader receives, negative means the trader pays. accruedFundingFee and accruedHoldingFee are the already-booked subsets of the totals — you generally want fundingFee and holdingFee, not the accrued fields.

ts
import { formatUnits } from 'viem'
import { publicClient, DIAMOND } from './config'

const POSITION_TUPLE = {
  type: 'tuple[]', name: '', components: [
    { name: 'positionHash', type: 'bytes32' },
    { name: 'pair', type: 'string' },
    { name: 'pairBase', type: 'address' },
    { name: 'tokenIn', type: 'address' },
    { name: 'marginToken', type: 'address' },
    { name: 'isLong', type: 'bool' },
    { name: 'margin', type: 'uint96' },
    { name: 'qty', type: 'uint128' },
    { name: 'entryPrice', type: 'uint128' },
    { name: 'stopLoss', type: 'uint128' },
    { name: 'takeProfit', type: 'uint128' },
    { name: 'openFee', type: 'uint96' },
    { name: 'executionFee', type: 'uint96' },
    { name: 'fundingFee', type: 'int256' },
    { name: 'timestamp', type: 'uint32' },
    { name: 'holdingFee', type: 'uint96' },
    { name: 'earliestCloseTime', type: 'uint256' },
    { name: 'accruedFundingFee', type: 'int256' },
    { name: 'accruedHoldingFee', type: 'uint256' },
  ],
} as const

const READER_ABI = [{
  type: 'function',
  name: 'getPositionsV4',
  stateMutability: 'view',
  inputs: [{ name: 'user', type: 'address' }, { name: 'pairBase', type: 'address' }],
  outputs: [POSITION_TUPLE],
}] as const

const positions = await publicClient.readContract({
  address: DIAMOND,
  abi: READER_ABI,
  functionName: 'getPositionsV4',
  args: [user, pairBase],
})

for (const p of positions) {
  console.log(
    p.pair,
    p.isLong ? 'LONG' : 'SHORT',
    formatUnits(p.qty, 10),
    '@', formatUnits(p.entryPrice, 18),
    '| margin', formatUnits(p.margin, 18),   // lvToken decimals
  )
}

Scanning all markets

getPositionsV4 takes one pairBase at a time. To sweep a user's whole book, fetch the pair list from GET /v1/pairs and batch the calls through Multicall3 — or use GET /v1/user/{address}/open-positions, which returns everything in one request.

getPositionByHashV4 / getPositionByKeyV4

solidity
function getPositionByHashV4(bytes32 tradeHash) external view returns (PositionV4 memory);
function getPositionByKeyV4(address user, address pairBase, bool isLong, address lvToken)
    external view returns (PositionV4 memory);

getPositionByKeyV4 avoids computing the hash yourself.

getPositionHash

solidity
function getPositionHash(address user, address pairBase, bool isLong, address lvToken)
    external pure returns (bytes32);

Pure, and reproducible offchain:

ts
import { keccak256, encodeAbiParameters } from 'viem'

const positionHash = keccak256(
  encodeAbiParameters(
    [{ type: 'address' }, { type: 'address' }, { type: 'bool' }, { type: 'address' }, { type: 'string' }],
    [user, pairBase, isLong, lvToken, 'position.v1'],
  ),
)

getPositionTrader

solidity
function getPositionTrader(bytes32 positionHash) external view returns (address);

getPendingTrade

solidity
function getPendingTrade(bytes32 tradeHash) external view returns (PendingTrade memory);

Look up a trade that has been requested but not yet filled, using the hash returned by openMarketTradeV2.

Limit orders

getLimitOrders

solidity
function getLimitOrders(address user, address pairBase) external view returns (LimitOrderView[] memory);
function getLimitOrderByHash(bytes32 orderHash) external view returns (LimitOrderView memory);
solidity
struct LimitOrderView {
    bytes32 orderHash;
    string pair;
    address pairBase;
    bool isLong;
    address tokenIn;
    address lvToken;
    uint96 amountIn;    // tokenIn decimals
    uint128 qty;        // 1e10
    uint128 limitPrice; // 1e18
    uint128 stopLoss;   // 1e18
    uint128 takeProfit; // 1e18
    uint24 broker;
    uint32 timestamp;
}
ts
const LIMIT_ORDERS_ABI = [{
  type: 'function',
  name: 'getLimitOrders',
  stateMutability: 'view',
  inputs: [{ name: 'user', type: 'address' }, { name: 'pairBase', type: 'address' }],
  outputs: [{
    type: 'tuple[]', name: '', components: [
      { name: 'orderHash', type: 'bytes32' },
      { name: 'pair', type: 'string' },
      { name: 'pairBase', type: 'address' },
      { name: 'isLong', type: 'bool' },
      { name: 'tokenIn', type: 'address' },
      { name: 'lvToken', type: 'address' },
      { name: 'amountIn', type: 'uint96' },
      { name: 'qty', type: 'uint128' },
      { name: 'limitPrice', type: 'uint128' },
      { name: 'stopLoss', type: 'uint128' },
      { name: 'takeProfit', type: 'uint128' },
      { name: 'broker', type: 'uint24' },
      { name: 'timestamp', type: 'uint32' },
    ],
  }],
}] as const

TP/SL orders

See TP/SL Orders → Reading orders for getDecreaseOrders, getTraderDecreaseOrders and getDecreaseOrder.

Brokers

getBrokerById and brokers return a broker's commission rate, receiver and accrued balances. See Brokers & Referrals → Reading your broker record.

Market data

getMarketInfoV2

solidity
function getMarketInfoV2(address pairBase) external view returns (MarketInfoV2 memory);
function getMarketInfosV2(address[] calldata pairBases) external view returns (MarketInfoV2[] memory);
solidity
struct MarketInfoV2 {
    address pairBase;
    uint256 longQty;                        // 1e10
    uint256 shortQty;                       // 1e10
    uint128 lpLongAvgPrice;                 // 1e18
    uint128 lpShortAvgPrice;                // 1e18
    int256 fundingFeeRate;                  // 1e18, signed
    int256 lastLongAccFundingFeePerShare;   // 1e18
}

Open interest per side and the current funding rate. Use the plural form to fetch several markets in one call.

Pair configuration

solidity
function getPairByBaseV4(address base) external view returns (PairView memory);
function getPairConfig(address base) external view returns (PairMaxOiAndFundingFeeConfig memory);
function getPairFeeConfig(address base) external view returns (FeeConfig memory);
function getPairHoldingFeeRate(address base, bool isLong) external view returns (uint40);

getPairByBaseV4 returns everything: status, OI caps, funding parameters, the leverage tiers, the fee config, holding fee rates, and the minimum holding period.

Leverage is tiered by notional size:

solidity
struct LeverageMargin {
    uint256 notionalUsd;  // upper bound of this tier
    uint16 maxLeverage;
    uint16 initialLostP;  // 1e4
    uint16 liqLostP;      // 1e4
}

Fees:

solidity
struct FeeConfig {
    uint16 openFeeP;          // 1e4
    uint16 closeFeeP;         // 1e4
    uint24 shareP;            // 1e5
    uint24 minCloseFeeP;      // 1e5
    uint24 lvTokenDiscountP;  // 1e5
}

Pair slippage configuration

solidity
function getPairSlippageConfig(address base) external view returns (SlippageConfigView memory);
solidity
enum SlippageType { FIXED, ONE_PERCENT_DEPTH, NET_POSITION, THRESHOLD }

struct SlippageConfigView {
    uint256 onePercentDepthAboveUsd;
    uint256 onePercentDepthBelowUsd;
    uint16 slippageLongP;      // 1e4
    uint16 slippageShortP;     // 1e4
    uint256 longThresholdUsd;
    uint256 shortThresholdUsd;
    SlippageType slippageType;
}

Use this to estimate the fill price before sending an open, and to size the price bound.

ts
import { formatUnits } from 'viem'

const SLIPPAGE_ABI = [{
  type: 'function',
  name: 'getPairSlippageConfig',
  stateMutability: 'view',
  inputs: [{ name: 'base', type: 'address' }],
  outputs: [{
    type: 'tuple', name: '', components: [
      { name: 'onePercentDepthAboveUsd', type: 'uint256' },
      { name: 'onePercentDepthBelowUsd', type: 'uint256' },
      { name: 'slippageLongP', type: 'uint16' },
      { name: 'slippageShortP', type: 'uint16' },
      { name: 'longThresholdUsd', type: 'uint256' },
      { name: 'shortThresholdUsd', type: 'uint256' },
      { name: 'slippageType', type: 'uint8' },
    ],
  }],
}] as const

const cfg = await publicClient.readContract({
  address: DIAMOND,
  abi: SLIPPAGE_ABI,
  functionName: 'getPairSlippageConfig',
  args: [pairBase],
})

console.log('model         ', ['FIXED', 'ONE_PERCENT_DEPTH', 'NET_POSITION', 'THRESHOLD'][cfg.slippageType])
console.log('long slippage ', Number(cfg.slippageLongP) / 100, '%')
console.log('1% depth above', formatUnits(cfg.onePercentDepthAboveUsd, 18))

Account assets

solidity
function traderAssets(address[] memory tokens) external view returns (TraderAsset[] memory);
solidity
enum AssetPurpose { LIMIT, PENDING, POSITION, PREDICTION_PENDING, PREDICTION }

struct TraderAsset {
    AssetPurpose purpose;
    address token;
    uint256 value;
}

Total value locked by the protocol per token, broken down by what it is locked for.

Trading perpetuals involves risk. Nothing here is financial advice.