gdex-hl-outcomes · git:20261019.d793ca7 · 2026-10-19 · sha256 e5db74e70112f510
gdex-hl-outcomes git:20261019.d793ca7A
Immutable. This exact content never changes and is served at /api/v1/blob/e5db74e70112f510.
---
name: gdex-hl-outcomes
description: Hyperliquid HIP-4 outcome markets on GDEX — discover a market, pick a side, check spot collateral, place a limit order, track resting/fill state, cancel or exit (partial/full), and reconcile
---
# GDEX: Hyperliquid HIP-4 Outcome Markets
GDEX outcome markets are **Hyperliquid HIP-4 outcome markets**: each market has
two or more sides; each side is a token that trades at a probability price in
(0, 1), and the winning side settles on Hyperliquid. They are traded with spot
collateral (the market's `quoteToken`, USDC today) from the managed wallet's
**Hyperliquid spot balance**.
They are **not** HIP-3 builder perps, not perps, and not spot tokens. **GDEX has
no Polymarket or Kalshi integration.**
## When to Use
- "What prediction / outcome markets can I trade?" → discover
- Buy or sell one side of an outcome market
- Track a resting order, cancel it, or exit a position fully or partially
- Explain what happens when a market expires or resolves
## Prerequisites
- `@gemachdao/gdex-skill` installed and a managed-custody session — see
**gdex-authentication**. You need `apiKey`, the **control** `walletAddress`
used at sign-in, and `sessionPrivateKey`. The SDK and the MCP tools build
and encrypt the payload for you; you don't need the backend ABI.
- The **managed** wallet address (outcome balances and orders live there).
- Quote collateral in the managed wallet's **HL spot** balance (step 3).
## Workflow
### 1. Discover
```typescript
const { markets } = await skill.getHlOutcomeMarkets({ state: 'active', query: 'BTC' });
```
MCP: `hl_outcomes` (`state`, `query`, `excludeFallback`, `limit`, `withVolume`).
Each market is normalised:
| Field | Meaning | Source |
|---|---|---|
| `outcomeId` | Market id | `outcomeMeta.outcomes[].outcome` |
| `title` | Readable question built from the market parameters | `name` + `description` (`key:value\|…`), question parameters |
| `sides[]` | `{ sideIndex, label, rawName, coin, balanceCoin, assetId, exchangeAssetId, price }` | `sideSpecs[]`. `coin` = `#<token>` or `#<outcomeId*10+sideIndex>`. `balanceCoin` = `+<assetId>`. `price` = `allMids[coin]`. |
| `quoteToken` | Collateral currency | `outcomes[].quoteToken` |
| `state` | `active` · `pre_launch` (no mids yet) · `expired` (deadline passed, not yet settled) · `settled` | `questions[].settledNamedOutcomes`, the expiry parameter, `allMids` |
| `rules` | Price 0.00001–0.99999, tick 0.00001 (5 dp); whole-contract size; min notional 11 quote; full-position sell exempt; market orders ±5%; `reduceOnlyHonoured: false` | GDEX backend + gdex.pro (see Rules) |
| `settlement` | `claimViaGdex: false`, resolution source and deadline, and what to do | see "Expiry and settlement" |
| `volume24h` | Only with `withVolume`: `{ volume, asOf, source, coverage }`. `coverage` is `complete`, `partial` or `unavailable`. A zero that was actually read stays `0`; `null` means no reading. The wait is bounded (default 2.5 s), so a slow feed never blocks discovery. | Hyperliquid WS `activeAssetCtx.dayNtlVlm` |
`isFallback: true` marks the "none of the listed outcomes" leg of a
multi-outcome question.
### 2. Pick a side
Read `sides[].label`. **Don't assume side 0 is "Yes".**
- A match market's sides can be the two team names (`LOS` / `T1`).
- A question can have one market per candidate, each with its own Yes/No.
Select a side with exactly one of these:
- `coin` (e.g. `"#143151"`)
- `sideIndex`
- `sideLabel` (exact label)
The SDK rejects a coin that doesn't belong to `outcomeId`.
### 3. Check collateral
```typescript
const c = await skill.checkHlOutcomeCollateral({
managedAddress, quoteToken: market.quoteToken, size: '120', price: '0.12',
});
// { available, required: 14.4, sufficient: true|false, ... }
```
MCP: `hl_outcome_check_collateral`.
- Buys draw on the managed wallet's HL **spot** balance of `quoteToken`
(`total − hold`), not on the perp account.
- If it's short, move USDC from perp to spot or fund the account. See
**gdex-perp-funding**.
- If a market is ever quoted in a token other than USDC, swap into it with
`hl_swap_collateral` first.
### 4. Place a limit order
```typescript
const r = await skill.createHlOutcomeOrder({
apiKey, walletAddress /* control */, sessionPrivateKey,
outcomeId: 14315, sideLabel: 'Yes', isBuy: true,
price: '0.12', // probability, at most 5 decimals
size: '120', // whole contracts; 120 × 0.12 = 14.4 ≥ 11
});
// r.status: 'resting' (r.orderId) | 'filled' (r.filledSize, r.avgPrice) | 'rejected' (r.error)
```
MCP: `hl_create_outcome_order`.
- `isBuy: false` sells side tokens you hold. It can't short.
- `isMarket: true` takes the book at ±5% of the top level. Omit `price`
(or pass `"0"`) for market orders.
- Pass `managedAddress` on sells. The SDK then checks the real position, and
a sell of the whole position is allowed below the minimum.
### 5. Track resting and fill state
```typescript
const s = await skill.getHlOutcomeAccountState({ userAddress: managedAddress, outcomeId: 14315 });
```
MCP: `hl_outcome_account`. It returns:
- `positions[]`: `size`, `hold`, `available`, `avgEntryPrice`, `markPrice`,
`value`, `unrealizedPnl`.
- `openOrders[]`: `orderId`, `price`, `size`, `originalSize`, `filledSize`,
and `status` (`resting` or `partially_filled`).
- `fills[]`.
- `historicalOrders[]`, with Hyperliquid's status, e.g. `filled`, `canceled`,
`minTradeNtlRejected`.
### 6. Cancel, or exit fully or partially
```typescript
await skill.cancelHlOutcomeOrder({ apiKey, walletAddress, sessionPrivateKey,
outcomeId: 14315, coin: '#143150', orderId: String(r.orderId) });
// Full exit: omit size (the backend sells everything available).
await skill.closeHlOutcomeOrder({ apiKey, walletAddress, sessionPrivateKey,
outcomeId: 14315, sideLabel: 'Yes', price: '0.15' });
// Partial exit: the sold part AND the remainder must each be worth ≥ 11.
await skill.closeHlOutcomeOrder({ apiKey, walletAddress, sessionPrivateKey,
outcomeId: 14315, sideLabel: 'Yes', price: '0.15', size: '80', managedAddress });
```
MCP: `hl_cancel_outcome_order` and `hl_close_outcome_order`.
- `orderId` is the numeric Hyperliquid oid.
- A close is always a sell of held tokens.
- Any partial fill that happened before a cancel stays in the position.
### 7. Reconcile
Call `hl_outcome_account` again. Check that:
- a cancelled order has left `openOrders`;
- fills are in `fills`;
- `positions[].available` matches what you expect.
If a write's outcome is unknown, check here before you submit anything again.
## Rules (and where they come from)
- **Price** must be in (0, 1). The backend rounds to 5 decimals
(`hyperLiquidOutcomes.ts:85-91`). The SDK rejects anything outside
[0.00001, 0.99999] or with more than 5 decimals.
- **Size** is whole contracts (`OUTCOME_SIZE_DECIMALS = 0`,
`hyperLiquidOutcomes.ts:69,185-188`).
- **Minimum order** is size × price ≥ **11** quote units. This is gdex.pro's
rule (`HyperliquidOutcomeDetail.tsx:84`). Hyperliquid's own floor is 10. A
sell of the full position is exempt. Partial closes must leave both legs at
11 or more.
- **`reduceOnly`** is ignored: the backend always sends `r:false`.
- **Tick size and minimum order** aren't per-market fields in `outcomeMeta`.
The rules above apply to every outcome market.
## Parameter modes
Every write accepts **either** the structured fields **or** a pre-built
`computedData` on its own. Never mix them.
- **Structured fields:** the SDK validates against the live market first.
- **Pre-built `computedData`:** posted as is, with no validation.
A mix of the two is rejected with `VALIDATION_ERROR` before anything is signed
or sent, as are missing structured fields. `dex` and `status` are not read by
the backend for outcomes.
## Expiry and settlement
- **`expired`:** the market's deadline has passed, but Hyperliquid hasn't
marked it settled yet. The SDK refuses new orders. You can still try to
exit with `hl_close_outcome_order`, but it may fail if the book has halted.
- **`settled`:** the outcome is listed in its question's
`settledNamedOutcomes`. There is no book.
- **Settlement is done on Hyperliquid** by the market deployer (the
`settleOutcome` and `settleQuestion` permissions in `outcomeMeta.deployers`).
- **GDEX has no claim, redeem or settle endpoint.** The backend's outcome
routes are exactly: `outcomes`, `outcome_account`, `outcome/create_order`,
`outcome/cancel_order`, `outcome/close_order`. After resolution there is
nothing to claim through GDEX. Read the managed wallet's HL spot balances
(`hl_outcome_account`) to see the result.
## Backend endpoints
| Method | Path | Notes |
|--------|------|-------|
| `GET` | `/v1/hl/outcomes` | `{ meta: outcomeMeta, mids: allMids }`. Ignores query params. `outcomeMeta` is cached for 60 s. |
| `GET` | `/v1/hl/outcome_account?address=<managed>&outcomeId=<id>` | positions (spot balances `+<assetId>`), openOrders, fills, historicalOrders |
| `POST` | `/v1/hl/outcome/create_order` | `{ computedData }` |
| `POST` | `/v1/hl/outcome/cancel_order` | `{ computedData }` |
| `POST` | `/v1/hl/outcome/close_order` | `{ computedData }` (always a sell) |