You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/api-spec.md
+6-6Lines changed: 6 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -628,14 +628,14 @@ Response:
628
628
{
629
629
"outcomeId": 0,
630
630
"symbol": "PM-2026-ELECTION-NO",
631
-
"free": "10.00",
632
-
"lockedInOrders": "0.00"
631
+
"free": "10.000000000",
632
+
"lockedInOrders": "0.000000000"
633
633
},
634
634
{
635
635
"outcomeId": 1,
636
636
"symbol": "PM-2026-ELECTION-YES",
637
-
"free": "5.50",
638
-
"lockedInOrders": "1000.00"
637
+
"free": "5.500000000",
638
+
"lockedInOrders": "1000.000000000"
639
639
}
640
640
]
641
641
}
@@ -650,8 +650,8 @@ Response fields:
650
650
|`balances`| ARRAY | One entry per outcome of the market, sorted by `outcomeId` ascending. Length equals the market's `outcomes[]` length in `/api/v1/markets`. |
651
651
|`balances[].outcomeId`| INT | Stable outcome id; matches `outcomes[].outcomeId` from `/api/v1/markets`. |
652
652
|`balances[].symbol`| STRING | Outcome-token symbol; matches `outcomes[].symbol` from `/api/v1/markets`. |
653
-
|`balances[].free`| DECIMAL | Outcome tokens currently held by the trading PrivateNote across clean, debt, and coupon stake pools, scaled by the outcome's `quantityPrecision`. |
654
-
|`balances[].lockedInOrders`| DECIMAL | Outcome tokens locked in resting SELL orders on this outcome, scaled by the outcome's `quantityPrecision`. |
653
+
|`balances[].free`| DECIMAL | Outcome tokens currently held by the trading PrivateNote across clean, debt, and coupon stake pools, scaled by the quote asset's on-chain `decimals` (same scaling as `/api/v1/account`). |
654
+
|`balances[].lockedInOrders`| DECIMAL | Outcome tokens locked in resting SELL orders on this outcome, scaled by the quote asset's on-chain `decimals`. |
Copy file name to clipboardExpand all lines: docs/tech-specs/read-api.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -414,7 +414,7 @@ Returns the caller's outcome-token holdings for one market. `free` comes from a
414
414
415
415
Three inputs feed one response:
416
416
417
-
1.**Market resolution.** Two SELECTs (one on [`markets`](data-schema.md#markets), one on [`market_outcomes`](data-schema.md#market_outcomes)) return `(event_id, oracle_list_hash, token_type, orderbook_address, num_outcomes, [(outcome_id, symbol, quantity_precision) …])`. The first is gated on `last_reconciled_at IS NOT NULL`; pre-reconcile markets are hidden symmetrically with `/api/v1/markets`. The marketlifecycle status is NOT a gate — terminal markets still serve balances so holders can see what they own until they claim or settle. Splitting into two SELECTs keeps the row types simple at the cost of one extra round trip; the per-request volume is low enough that the JOIN form is not worth the type-erasure pain.
417
+
1.**Market resolution.** Two SELECTs (one on [`markets`](data-schema.md#markets) INNER-joined to [`ref_tokens`](data-schema.md#ref_tokens) for the quote-asset `decimals`, one on [`market_outcomes`](data-schema.md#market_outcomes)) return `(event_id, oracle_list_hash, token_type, orderbook_address, num_outcomes, decimals, [(outcome_id, symbol, quantity_precision) …])`. The first is gated on `last_reconciled_at IS NOT NULL`; pre-reconcile markets are hidden symmetrically with `/api/v1/markets`. The `ref_tokens` join cannot hide a market: `markets.token_type` is `NOT NULL` and FK-references the statically seeded `ref_tokens` PK, so it is a strict 1:1. The market lifecycle status is NOT a gate — terminal markets still serve balances so holders can see what they own until they claim or settle. Keeping the per-outcome rows in a separate SELECT keeps the row types simple at the cost of one extra round trip.
418
418
2.**PN stake state.** The chain-side accessor is the auto-generated getter for the public mapping `PrivateNote._stakes`. TVM Solidity auto-getters for public mappings take no arguments and return the entire `map(uint256 → StakeInfo)` — see the PN ABI under `contracts/abi/dex/PrivateNote.abi.json`. The API computes the per-market key `stake_hash = tvm.hash(abi.encode(event_id, oracle_list_hash, token_type))` — the same hash the PN itself uses internally — and looks it up on the returned map. The hash is built off-chain in Rust via a thin wrapper around `tvm_types`. Each `StakeInfo` value carries three parallel `uint128[]` arrays (`amount`, `debtAmount`, `couponsAmount`) indexed by `outcome_id`, plus housekeeping fields the API ignores. A missing key on the returned map (caller never staked on this market) is treated as "all outcomes at zero", not as an error.
419
419
420
420
Returning the whole mapping in one call costs the same as one keyed lookup would on EVM (the ABI shape is fixed by TVM Solidity), so this is an opportunity, not a tax: a future "all my outcomes" view across markets needs no additional chain calls.
@@ -442,8 +442,8 @@ Three inputs feed one response:
442
442
- Fetch the PN BOC and run the `_stakes` getter through `tvm_runner` (returns the full `map(uint256 → StakeInfo)`); the API then looks up `map[stake_hash]`.
443
443
- Run the `live_orders` aggregation SELECT.
444
444
6. Build `balances[]` in `outcome_id` ASC order. For each outcome:
445
-
-`free = scale(amount[outcome_id] + debtAmount[outcome_id] + couponsAmount[outcome_id], quantity_precision)`. The three pools are summed because the public surface is "what the user owns" — clean, debt-bound, and coupon-bound stakes are all the user's tokens; the distinction is internal accounting that the UI does not need at this layer.
446
-
-`lockedInOrders = scale(coalesce(SUM, 0), quantity_precision)` from the aggregation map; outcomes without a row default to 0.
445
+
-`free = scale(amount[outcome_id] + debtAmount[outcome_id] + couponsAmount[outcome_id], decimals)`. Scaled by the quote asset's on-chain `decimals` (not `quantity_precision`) — the `_stakes` amounts are chain atoms, the same scale `/api/v1/account` uses; scaling by `quantity_precision` would over-report by `10^(decimals − quantity_precision)`. The three pools are summed because the public surface is "what the user owns" — clean, debt-bound, and coupon-bound stakes are all the user's tokens; the distinction is internal accounting that the UI does not need at this layer.
446
+
-`lockedInOrders = scale(coalesce(SUM, 0), decimals)` from the aggregation map (the `live_orders` amounts are chain atoms too); outcomes without a row default to 0.
447
447
7. Capture `now_ms` once in the handler before executing the use case — surfaces as `updateTime`.
Copy file name to clipboardExpand all lines: docs/tech-specs/write-api.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -681,7 +681,7 @@ _Implementation tech spec to be filled in._
681
681
682
682
## `POST /api/v1/buyFullSet`
683
683
684
-
Buys a full set of outcome tokens for one market by depositing `collateral` of the market's quote asset into the PMP. The chain entry point is `PrivateNote.splitFullSet`; on a market sitting in `AWAITING_FREEZE` the first successful call also activates the OrderBookfor everyone else. From the caller's standpoint the request and response are identical to any later call against the same market.
684
+
Buys a full set of outcome tokens for one market by depositing `collateral` of the market's quote asset into the PMP. The chain entry point is `PrivateNote.splitFullSet`; on a market sitting in `AWAITING_FREEZE` the first successful call also activates the OrderBook, after which it stays active for all subsequent callers. From the caller's standpoint the request and response are identical to any later call against the same market.
685
685
686
686
The handler runs three phases: request parsing → market resolution + status gate → collateral validation + chain submission. Each phase fails closed with its own error code (see [Error mapping](#error-mapping-3)).
0 commit comments