Protocol

Markets and maturities

What a market is on chain, what it fixes when it opens, and the limits it enforces.

A market is one maturity

A market is a program account for one maturity of a Phoenix perp. Tack supports SOL, slot 0 of Phoenix's PerpAssetMap (market_index 0), so each market is one SOL-PERP maturity. Its address is derived from the perp, the maturity and its creator:

Text
market   = PDA("market", market_index as u16 LE, maturity as i64 LE, admin)
vault    = PDA("vault", market)              USDC token account owned by the market
venue    = PDA("venue", market_index as u16 LE, admin)   shared by every maturity one creator opens
listing  = PDA("listing", market_index as u16 LE, creator)

Anyone can create a market. The program validates its configuration against fixed bounds, and nothing about it can change afterwards: there is no admin key that updates parameters, moves funds or overrides the funding source. A market's admin is only its creator, and it is part of the address, so markets opened by different creators at the same maturity never collide. Parameters and units lists every setting and its bounds.

What a market fixes when it opens

Creating a market reads Phoenix's SOL slot once and stores what it finds:

FieldMeaning
referencePricePhoenix's SOL mark price at creation. The floating leg is funding on N ÷ referencePrice SOL for the market's whole life.
cumulativeFundingPhoenix's cumulative funding at creation.
sourceTimestampThe start of Phoenix's funding interval at creation; checkpoints follow it one interval at a time.
fundingIntervalPhoenix's funding interval, one hour. A different interval stops the market.
fundingPeriod, fundingClampPhoenix's funding period and per-interval clamp. A change to either stops the market.
maturityBetween one hour and 31 days after creation, on the funding interval's grid.

The source must be fresh when the market opens: its funding accumulator and index price updated within the market's maxAge. Phoenix starts each hour's interval on its first update after the hour; until it has, a market cannot open (SourceRollover), so its first checkpoint is always the next record.

Maturities Tack lists

Tack's maturities come from its listing account: a schedule and the terms its markets open with, whose authority is the deployer key at launch and TACK governance after the handover. Opening a listed maturity is permissionless: anyone can call list_market for the next maturity the schedule calls for, and it opens on the listing's terms with the listing as its admin. Tack's crank does it as each one comes due.

Tack keeps three weekly SOL-PERP maturities open: the next Fridays at 08:00 UTC that are between 36 hours and 30 days away. As the nearest one comes within 36 hours of its maturity, the next Friday is listed. All of them use the same parameters, which TACK holders set by vote:

ParameterValue
Initial margin floor25% of notional
Maintenance margin floor10% of notional
Shock rate100% a year
Open-interest cap1% of Phoenix's SOL open interest
Largest fixed rate100% a year
Rate tick0.01%
Source freshness (maxAge)15 minutes
Freeze grace1 day

Every market's parameters are on its account. The API returns them with GET /markets.

Collateral

Collateral is canonical USDC, mint EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v, six decimals, held in the market's vault: an SPL Token account whose authority is the market account itself. Token-2022 mints and any other mint are refused.

The market keeps a liabilities total: every quote's collateral and both balances of every position. Deposits add to it, withdrawals take from it, and settlement moves money between two balances without changing it. Before any USDC leaves the vault, the program checks that the vault holds at least liabilities.

Quotes and positions

A market takes any number of quotes and positions: each is its own account, and no instruction walks through them. Quote and position accounts are never reused; a filled or cancelled quote stays on chain as a record with no collateral.

The open-interest cap

Funding can be moved by trading the perp, so Tack keeps its size small next to Phoenix's. Phoenix's open interest counts as the smaller of its value at the market's last checkpoint and its value at the fill, so open interest added on Phoenix in the fill's own transaction raises nothing. Two checks run on every fill:

  • Per maturity, open notional must stay within oiCapBps of Phoenix's SOL open interest, valued at the market's reference price.
  • Across maturities, the venue account adds up the SOL exposure of every open position in every SOL-PERP maturity its creator opened (for Tack, every listed maturity), ceil(N × 1e9 ÷ referencePrice) base units each, and the total must stay within the same share of Phoenix's open interest in SOL.

Opening more maturities does not raise the cap, and a market someone else opens counts against its own venue, never against Tack's listed maturities. If Phoenix's open interest shrinks, existing positions stay open and new fills stop until there is room.

When trading is open

A quote can be posted or taken while all of these hold:

  • a fill now would start before maturity: trading closes when the last funding interval before maturity begins;
  • Phoenix's funding accumulator and index price were updated within maxAge of now;
  • the market has published a checkpoint for Phoenix's latest funding record;
  • Phoenix's SOL slot reads as the reviewed layout and units.

Cancelling a quote and withdrawing a closed position's balance need none of these.