> ## Documentation Index
> Fetch the complete documentation index at: https://docs.seesaw.fun/llms.txt
> Use this file to discover all available pages before exploring further.

# Rubies and positions

> How stakes, prices, ruby boosts, app-only selling and the ruby balance fit together

This page explains the trading rules behind
[`preview_order`](/mcp/tools/preview-order),
[`list_my_positions`](/mcp/tools/list-my-positions) and
[`list_my_ruby_ledger`](/mcp/tools/list-my-ruby-ledger). Everything here
applies to `v21_lmsr` topics — the live market. Legacy `v2_share` topics are
readable but cannot be traded through the Open API.

## The stake: chosen by the user, bounded by the topic

Each topic fixes its own trading rules when it is created — the range of
stakes it accepts, how deep its market is, and which rules version it runs.
Those rules never change afterwards; a later platform change only affects
topics created after it. The part an agent needs is published on every topic
card and detail as `stake_rules`:

| Field                     | Meaning                                                                          |
| ------------------------- | -------------------------------------------------------------------------------- |
| `min_coins` / `max_coins` | The inclusive range of whole-coin stakes the topic accepts                       |
| `default_coins`           | What an order stakes if `amount_coins` is omitted — a fallback, not a suggestion |
| `rules_version`           | `1` = fixed stake (older topics, range 100..100), `2` = variable stake           |

`stake_rules` is `null` on `v2_share` topics.

<Warning>
  **Ask the user for the amount.** If they said how many coins to stake, pass
  exactly that as `amount_coins`. If they didn't, ask — never pick, infer or round
  an amount for them. An amount outside the range is refused with
  `STAKE_OUT_OF_RANGE`, never adjusted.
</Warning>

A user places **one order per topic**. There are no fees — the whole stake buys
units — and no adding to or switching a position later.

## Prices and opening probabilities

Each option's `implied_price` (0–1, summing to 1 across a topic) is its current
price. A topic can open at initial probabilities set when it is published
rather than at an even split, so read the price instead of assuming 1/n.
Buying moves the price: the preview shows `price_now`, `price_after` and the
average price paid (`avg_price`).

## Payout and ruby boosts

If the option a position is on wins, the position pays **rubies**; the stake
is not returned. The payout is:

```
payout = units × ruby multiplier
```

`units` is the raw unit count the stake bought. The **ruby multiplier** is 1
unless a ruby boost is live at one of three moments — when the order is
placed, when the topic settles, or (in the app) when the position is sold. A
running boost appears on the topic as `ruby_boost` (`multiplier`, `ends_at` —
`ends_at` is exclusive; `null` when there is no boost), and on the order
preview as `ruby_multiplier`.

* **Placed during a boost** — the order records that multiplier. A boost
  ending later never lowers it.
* **Settled during a boost** — positions still held when the topic settles get
  the higher of their recorded multiplier and the one live at settlement.
* **Sold in the app during a boost** — the sale uses the higher of the
  recorded multiplier and the one live at the moment of sale.

So every `payout_if_correct_rubies` figure is a **guaranteed minimum** (units ×
the order's current multiplier), not the final amount: if the topic settles
while a boost is live, the position pays more. Present it as "at least N
rubies if correct". The API does not project a future boost into it — a boost
live today may be over by settlement.

Where the payout shows up:

| Stage                   | Field                                                                                                                                        |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| Before ordering         | `preview_order` → `summary.payout_if_correct_rubies` (already multiplied; a guaranteed minimum)                                              |
| Right after ordering    | `place_order` → `order.payout_if_correct_rubies` (a guaranteed minimum; compare with `previewed.payout_if_correct_rubies`, not with `units`) |
| While open              | `list_my_positions` → `payout_if_correct_rubies` (a guaranteed minimum)                                                                      |
| After settlement        | `list_my_positions` → `payout_rubies` — what settlement actually paid, boost included (`"0.0000"` if the option lost)                        |
| After a sale in the app | `list_my_positions` → `sold_rubies` — what the sale actually paid                                                                            |

## Selling happens in the app only

In the SeeSaw app, a user can sell a whole position back for rubies. **The Open
API has no sell tool or endpoint** — an agent cannot sell on the user's behalf.
If the user asks to sell, point them to the app.

What the API does show is the result. A position sold in the app appears in
[`list_my_positions`](/mcp/tools/list-my-positions) with:

* `sold: true` and `sold_rubies` — what the sale paid;
* `won`, `payout_rubies` and `payout_if_correct_rubies` always `null`, and
  `refunded` always `false`. A sold position **does not take part in
  settlement** and is not refunded, whatever the topic's outcome — even if the
  option it was on wins;
* `settled` still turning `true` once the topic settles, because it describes
  the topic.

Read the row in this order: `sold` > `refunded` > settled (`won` /
`payout_rubies`) > open. Selling still counts as the topic's one order, so
`preview_order` on that topic answers `ALREADY_STAKED`.

The sale itself is a `ruby_trade_sell` row in
[`list_my_ruby_ledger`](/mcp/tools/list-my-ruby-ledger); its `created_at` is
the time of the sale.

## Where rubies come from

`rubies` on [`get_my_profile`](/mcp/tools/get-my-profile) is the ruby balance.
It moves when:

* a position on the winning option settles (`ruby_settlement`, boost
  included) — or is taken back after a takedown or a changed ruling
  (`ruby_revocation`);
* the user sells a position in the app (`ruby_trade_sell`);
* the user's opinions are backed, or later backers follow them in a relay
  (`sapphire_creator_fee`, `sapphire_back_relay`) — or those paybacks are
  clawed back when an opinion is taken down (`sapphire_opinion_takedown`);
* the old sapphire balance was converted (`sapphire_conversion`, once).

[`list_my_ruby_ledger`](/mcp/tools/list-my-ruby-ledger) lists every one of
these movements.

## Sapphires have been merged into rubies

Sapphires used to be a separate reward for opinions. They have been merged 1:1
into rubies, and opinions now pay rubies. The sapphire-named fields are still
returned so existing integrations keep working, with the same values as their
ruby replacements, and will be **removed in contract 3.0.0**:

| Deprecated                      | Use instead                | Where                                         |
| ------------------------------- | -------------------------- | --------------------------------------------- |
| `sapphires` (always `"0.0000"`) | `rubies`                   | `get_my_profile`                              |
| `sapphire_payback`              | `ruby_payback`             | `list_my_opinions`, `list_my_backed_opinions` |
| `sapphire_total`                | `ruby_total`               | the `stats` of those two lists                |
| `max_relay_payback_sapphires`   | `max_relay_payback_rubies` | `preview_back`, `back_opinion`                |

`ruby_payback` includes what an opinion paid as sapphires before the merge.
