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
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.
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.
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
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
function getPositionHash(address user, address pairBase, bool isLong, address lvToken)
external pure returns (bytes32);Pure, and reproducible offchain:
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
function getPositionTrader(bytes32 positionHash) external view returns (address);getPendingTrade
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
function getLimitOrders(address user, address pairBase) external view returns (LimitOrderView[] memory);
function getLimitOrderByHash(bytes32 orderHash) external view returns (LimitOrderView memory);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;
}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 constTP/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
function getMarketInfoV2(address pairBase) external view returns (MarketInfoV2 memory);
function getMarketInfosV2(address[] calldata pairBases) external view returns (MarketInfoV2[] memory);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
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:
struct LeverageMargin {
uint256 notionalUsd; // upper bound of this tier
uint16 maxLeverage;
uint16 initialLostP; // 1e4
uint16 liqLostP; // 1e4
}Fees:
struct FeeConfig {
uint16 openFeeP; // 1e4
uint16 closeFeeP; // 1e4
uint24 shareP; // 1e5
uint24 minCloseFeeP; // 1e5
uint24 lvTokenDiscountP; // 1e5
}Pair slippage configuration
function getPairSlippageConfig(address base) external view returns (SlippageConfigView memory);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.
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
function traderAssets(address[] memory tokens) external view returns (TraderAsset[] memory);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.