99: Add read-only Phoenix Perps positions to EvelynPerpsService
This commit is contained in:
@@ -22,15 +22,15 @@ The service SHALL run as two separate Hub-managed processes registered as `evely
|
||||
- **AND** no placeholder positions are generated before successful retrieval
|
||||
|
||||
### Requirement: Wallet configuration belongs to service construction
|
||||
The Hub SHALL supply the six PROD wallet addresses and one TEST wallet address specified in issue #98 and the corresponding existing Jupiter integration at construction. Each service SHALL retain immutable configuration and own its snapshot. Wallet addresses SHALL be used as stable identities and display labels. EMC SHALL neither own nor pass wallet configuration; reads SHALL remain parameterless.
|
||||
The Hub SHALL supply the six PROD wallet addresses and one TEST wallet address specified in issue #98 and the corresponding existing Jupiter integration plus a read-only Phoenix integration at construction. Each service SHALL retain immutable configuration and own its snapshot. Wallet addresses SHALL be used as stable identities and display labels. EMC SHALL neither own nor pass wallet configuration; reads SHALL remain parameterless.
|
||||
|
||||
#### Scenario: Separate configured instances
|
||||
- **WHEN** the Hub constructs and starts both instances
|
||||
- **THEN** each instance queries only its configured wallets through its corresponding integration
|
||||
- **THEN** each instance queries only its configured wallets through its injected integrations
|
||||
- **AND** the implementation does not define the wallet list internally
|
||||
|
||||
### Requirement: Background Jupiter refresh
|
||||
The service SHALL refresh immediately after startup and wait 60 seconds between completed cycles, without overlapping cycles or depending on EMC visibility. It SHALL use only existing Jupiter position reads and respect their cache. Snapshot reads SHALL make no integration calls. No transaction signing or position-management operation SHALL occur.
|
||||
The service SHALL refresh immediately after startup and wait 60 seconds between completed cycles, without overlapping cycles or depending on EMC visibility. It SHALL use Jupiter and Phoenix read operations and respect the existing Jupiter cache. Snapshot reads SHALL make no integration calls. No transaction signing or position-management operation SHALL occur.
|
||||
|
||||
#### Scenario: Background update while EMC is hidden
|
||||
- **WHEN** EMC is hidden and the next refresh is due
|
||||
@@ -38,16 +38,21 @@ The service SHALL refresh immediately after startup and wait 60 seconds between
|
||||
- **AND** no freshness guarantee bypasses the existing 60-second integration cache
|
||||
|
||||
### Requirement: Position mapping is stable and complete
|
||||
The service SHALL map position account to stable ID, mint to known instrument label or raw mint fallback, direction to Long/Short, and positionSize to USD size. Wallet order SHALL follow configuration, and positions SHALL be ordered deterministically by position account. Only Jupiter venues and actual positions SHALL be published.
|
||||
The service SHALL map position account to stable ID, mint to known instrument label or raw mint fallback, direction to Long/Short, and positionSize to USD size. Wallet order SHALL follow configuration, and positions SHALL be ordered deterministically by position account. Phoenix SHALL use PDA index, subaccount index and symbol as stable identity, signed quantity for direction and absolute current USD notional for size. Jupiter and Phoenix SHALL appear as separate venues, with no subaccount tree level.
|
||||
|
||||
#### Scenario: Changed and unknown positions
|
||||
- **WHEN** a successful read returns newly opened positions including an unknown token mint
|
||||
- **THEN** all returned positions appear with stable IDs and exact USD sizes, and the unknown mint is displayed rather than dropped
|
||||
|
||||
### Requirement: Refresh failures are isolated per wallet
|
||||
A failed wallet read or mapping SHALL retain its last successful data, log the failure and allow other wallets to refresh. Successful empty results SHALL remove previous positions. Interruption SHALL stop the current cycle. Failed first reads SHALL not invent positions.
|
||||
A failed read or mapping SHALL retain the last successful data for that wallet and venue, log the failure and allow other wallets and venues to refresh. Successful empty results SHALL remove only that wallet/venue's previous positions. Interruption SHALL stop the current cycle. Failed first reads SHALL not invent positions.
|
||||
|
||||
#### Scenario: Failure followed by recovery
|
||||
- **WHEN** one wallet fails while another succeeds
|
||||
- **THEN** only the successful wallet's data is replaced
|
||||
- **AND** a later successful empty read clears the recovered wallet's previous positions
|
||||
- **THEN** only the successful wallet/venue's data is replaced
|
||||
- **AND** a later successful empty read clears the recovered wallet/venue's previous positions
|
||||
|
||||
#### Scenario: One venue fails
|
||||
- **WHEN** Phoenix fails for a wallet while Jupiter succeeds, or vice versa
|
||||
- **THEN** only the successful venue is updated and the failed venue retains its previous data
|
||||
- **AND** subsequent wallets are still attempted
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user