2.6 KiB
phoenix-perps-service Specification
Purpose
Read actual Phoenix perpetual positions for a Solana authority without signing or modifying accounts, preserving precise current USD notional and subaccount identities.
Requirements
Requirement: Read every active position under the authority
The integration SHALL read official Phoenix REST trader state for the requested wallet authority at PDA index 0. It SHALL include nonzero positions from cross-margin and isolated subaccounts, preserve subaccount/symbol identity independently of sequence numbers, and return an immutable deterministically ordered result. No signing, trading or account activation SHALL occur.
Scenario: Cross and isolated positions share a symbol
- WHEN subaccounts 0 and 2 both have a nonzero SOL position
- THEN both positions are returned with distinct identities
- AND zero-sized positions are excluded
Requirement: Current USD notional uses documented market units
Position direction SHALL follow signed quantity. USD size SHALL be the absolute current notional, calculated using exact decimal arithmetic from base lots divided by 10 to the market's base-lot decimal exponent and multiplied by its current mark price. Collateral, entry value and raw lot counts SHALL NOT be used as USD size. Missing conversion data SHALL fail the read.
Scenario: Convert a short position
- WHEN a position has -125 base lots, base-lot exponent 2 and mark price 104.45 USD
- THEN it represents -1.25 base units, Short direction and 130.5625 USD notional
Requirement: Read failures cannot masquerade as empty portfolios
HTTP, authentication, malformed schema, identity mismatch and numeric conversion errors SHALL fail the read. Requests SHALL have bounded timeouts. Only a valid response with no nonzero positions SHALL produce an empty result. Required mark prices SHALL be positive and finite.
Scenario: Missing mark price or rejected access
- WHEN a required price is missing or an HTTP request is rejected
- THEN the read fails instead of returning an empty or partial portfolio
Scenario: Empty account
- WHEN a valid trader snapshot has no subaccounts or no nonzero positions
- THEN an empty result is returned without market-price requests
Scenario: Public API rate limit
- WHEN the shared adapter issues requests for PROD and TEST
- THEN request starts SHALL be spaced at least one second apart
- AND HTTP 429 SHALL fail the lookup and establish a shared cooldown from Retry-After (seconds or HTTP date, 60 seconds fallback)
- AND lookups during cooldown SHALL fail without external calls, with no immediate retry