Skip to main content
PositionManager handles the full position lifecycle: open, increase, reduce, and margin adjustments. It is the primary entry point for traders interacting with the protocol.

Contract Relationships

Position Data Structure

Every position is stored onchain as a Position struct (see Types Reference for full definition):
struct Position {
    address account;                     // Owner address
    bytes32 pairId;                      // Currency pair identifier (e.g., keccak256("EUR/USD"))
    Side side;                           // LONG or SHORT
    uint256 notional;                    // Position size in USDC (6 decimals)
    Tenor tenor;                         // Maturity tenor (ONE_DAY, ONE_WEEK, ONE_MONTH)
    uint32 tenorSeconds;                 // Tenor duration in seconds
    uint64 openTimestamp;                // Block timestamp when opened
    uint64 fixingTimestamp;              // Maturity date (business day adjusted)
    int256 entryStrike;                  // Forward price at open (18 decimals)
    uint64 entryOracleRoundId;           // Oracle round ID at open
    uint256 imLocked;                    // Locked initial margin (mutable via add/remove)
    uint256 mmThreshold;                 // Maintenance margin liquidation threshold
    PositionStatus status;               // OPEN or CLOSED
    CloseReason closeReason;             // Why it was closed (NONE while open)
    uint64 closeTimestamp;               // When closed (0 while open)
    int256 closePrice;                   // Settlement price at close (18 decimals)
    int256 realizedPnl;                  // Capped PnL used for accounting
    int256 marketPnl;                    // Uncapped true mathematical PnL
    uint16 snapshotImBps;                // IM factor at time of open
    uint16 snapshotMmBps;                // MM factor at time of open
    uint16 snapshotTradingFeeBps;        // Trading fee rate at time of open
    uint16 snapshotLiquidationPenaltyBps; // Liquidation penalty at time of open
    uint256 snapshotOracleFee;           // Oracle fee at time of open
    MarginMode marginMode;               // ISOLATED (M2 only)
}
The imLocked field is the only mutable economic field on an open position. It changes when the trader adds or removes margin. All snapshot* fields are immutable after position creation.

Read Functions

getPosition

function getPosition(uint256 positionId) external view returns (Position memory)
Returns the full Position struct for a given ID.

getOpenPositions

function getOpenPositions(address account) external view returns (uint256[] memory)
Returns all open position IDs for an account.

Position Queries

FunctionReturns
nextPositionId()Next position ID counter
allOpenPositionIds()All open position IDs in the system
openPositionCount()Total count of open positions
openPositionCountByPair(pairId)Open positions for a specific pair
openPositionCountAtFixingTs(fixingTs)Open positions at a fixing timestamp
getPositionStats()Aggregated stats (open, matured, liquidatable counts)

PnL and Risk

FunctionReturns
unrealizedPnl(positionId)Unrealized PnL for a single position
aggregateUnrealizedPnl()Total unrealized PnL across all positions
positionEquity(positionId)Position equity (allocated collateral + unrealized PnL)
isLiquidatable(positionId)Whether position is eligible for liquidation
tenorSeconds(tenor)Tenor duration in seconds

Write Functions

openPosition

function openPosition(OpenPositionParams params) returns (uint256 positionId)
Opens a new position. Only allowed in NORMAL mode. Validation checks (in order):
#CheckRevert Error
1Pair must be enabledPairNotEnabled
2Tenor must be enabledTenorNotEnabled
3notional > 0ZeroAmount
4notional >= minPositionNotional (default 100 USDC)NotionalTooSmall
5margin >= minIM where minIM = notional * imFactorBps / 10000MarginBelowMinimum
6margin <= notionalMarginExceedsNotional
7RiskManager caps: per-position, per-account, pool exposure, rate-of-changeVarious risk errors

increasePosition

function increasePosition(uint256 positionId, uint256 additionalNotional)
Increases an existing position’s notional. Only allowed in NORMAL mode. Preconditions: Owner only, OPEN status, not matured, not liquidatable. The increase uses a weighted average entry strike:
newEntryStrike = (oldNotional * oldStrike + additionalNotional * currentForwardPrice) / newNotional
Additional margin is calculated proportionally:
additionalMargin = additionalNotional * (imLocked / notional)

addPositionMargin

function addPositionMargin(uint256 positionId, uint256 amount)
Increases locked margin. Owner only, position must be OPEN and not matured.
  • imLocked + amount must not exceed notional
  • Allowed even when liquidatable (rescue mechanism)
  • Allowed in NORMAL, DEGRADED, and REDUCE_ONLY modes

removePositionMargin

function removePositionMargin(uint256 positionId, uint256 amount)
Decreases locked margin. Owner only, position must be OPEN and not matured.
  • Not allowed when liquidatable (reverts PositionLiquidatable)
  • Remaining margin must be >= minIM (using snapshotted IM bps)
  • Post-removal equity must stay above the MM threshold
  • Requires a forward price read (with oracle fee)

closePosition

function closePosition(uint256 positionId)
Early termination — closes the position at the current forward price before maturity. Owner only. Routes to SettlementEngine.

reducePosition

function reducePosition(uint256 positionId, uint256 reductionNotional)
Partially reduces the position. PnL on the reduced portion is settled immediately. Remaining notional must stay above minPositionNotional. Routes to SettlementEngine.

Snapshotted Parameters

Six configuration parameters are captured at open and remain immutable:
FieldPurpose
snapshotImBpsInitial margin factor — used for margin removal validation
snapshotMmBpsMaintenance margin factor — used for liquidation threshold
snapshotTradingFeeBpsTrading fee rate — used at settlement and close
snapshotLiquidationPenaltyBpsLiquidation penalty — used only if liquidated
snapshotOracleFeeOracle fee per price read
marginModeMargin mode (ISOLATED in M2)

Events

EventWhen Emitted
PositionOpenedNew position created
PositionIncreasedPosition notional increased
PositionMarginAddedMargin added to position
PositionMarginRemovedMargin removed from position
PositionReducedPosition partially reduced
PositionClosedPosition closed (any close reason)

Position Lifecycle

Product-level overview of the position lifecycle.

Settlement Engine

Settlement, liquidation, and early termination contract.

Margin Accounts

Collateral management contract.