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

# Paytables

> The invariant in exact integers, how to size a prize against the pool, and the common refusals.

A paytable is an array of 1 to 32 buckets `{ p, m }`:

* `p`: probability as a `u64` in billionths. Every `p` is greater than zero, and they sum to **exactly** 1 000 000 000.
* `m`: multiplier as a `u64` in basis points of the stake. 10 000 is 1×, 0 pays nothing, and the ceiling is 100 000 000 (10 000×).

A bucket's payout is `stake × m / 10 000`, rounded down, in USDC base units.

## The invariant

`open_wager` computes, in 128-bit integers with no rounding:

```
lhs = Σ p_i · m_i
```

and admits the paytable only if, for the app fee `f` it passes:

```
lhs ≤ (10 000 − 100 − 20 − f) · 1 000 000 000
```

That is the **edge floor**: the declared edge must cover the 100 bps LP floor, the 20 bps protocol fee and the app's own fee. The program also derives the declared edge it stores in the wager:

```
paytable_edge_bps = 10 000 − ceil(lhs / 1 000 000 000)
pool_edge_bps     = paytable_edge_bps − f − 20
```

No floating-point value is involved anywhere, and your client should not use one either. Build paytables in `bigint`.

<Tip>
  Round in the house's favour: round probabilities down, and if you round a multiplier up, derive the probability from the rounded multiplier. Put the remainder of 1 000 000 000 on the zero bucket so the sum is exact.
</Tip>

## Examples

**Win or nothing.** For a target payout `T` on stake `s` at edge `e` bps:

```ts theme={null}
const m = (T * 10_000n + s - 1n) / s;          // round up so the prize is at least T
const p = ((10_000n - e) * 1_000_000_000n) / m; // round down to keep the edge
const paytable = [{ p, m }, { p: 1_000_000_000n - p, m: 0n }];
```

**Three tiers at a 3.5 % edge.**

| Bucket | `p` | `m` | `p · m` |
| - | - | - | - |
| 10× | 50 000 000 | 100 000 | 5.000 × 10¹² |
| 0.9× | 450 000 000 | 9 000 | 4.050 × 10¹² |
| 0.12× | 500 000 000 | 1 200 | 0.600 × 10¹² |
| | 1 000 000 000 | | 9.650 × 10¹² = 9 650 × 10⁹ |

**Refused: pays out more than it takes in.** `[{ p: 500_000_000n, m: 21_000n }, { p: 500_000_000n, m: 0n }]` returns 105 % on average. `open_wager` fails with `PaytableOverpays`.

**Refused: fair, but the edge does not cover the split.** A 1 % edge paytable with no app fee is fair to the user but leaves the pool less than its 100 bps floor plus the 20 bps protocol fee. `open_wager` fails with `EdgeFloor`.

## How much a pool can back

The pool reserves each wager's **liability**, its worst case net of what the stake brought in:

```
pool_credit = stake − protocol_fee − app_fee
payout_max  = stake × max(m) / 10 000
liability   = payout_max − pool_credit
```

Admission then checks, against the pool as it stands at open:

| Check | Rule | Refusal |
| - | - | - |
| Per-wager cap | `liability ≤ min(0.5 × pool_edge × free_balance, 150 bps × assets)` | `PerWagerCap` |
| App ceiling | the app's open liability, this wager included, `≤ 20 % × assets` | `IntegratorCap` |
| Utilisation | `(reserved + open credits) ≤ 70 % × assets`, after this wager | `UtilisationBreaker` |
| Global exposure | `reserved ≤ 80 % × assets`, after this wager | `GlobalExposure` |
| Gross solvency | `reserved + open credits ≤ assets` | `Insolvent` |

`free_balance = assets − reserved liability − open pool credits`. The per-wager cap uses the **pool edge**, net of fees, so inflating the declared edge does not widen it, and every basis point of app fee narrows it. After a drawdown trip the cap is halved for 48 hours.

### Sizing a prize

Two consequences matter for an interface:

1. **Only the top multiplier costs capital.** A paytable that pays something 90 % of the time can be trivial to back; a single large prize decides what the pool must hold.
2. **The cap bounds the liability, not the multiplier.** On a fixed paytable, a cap `C` admits a stake of about `C / (max(m) − 1)`. The same pool that refuses 25 USDC at 1 000× accepts a few cents at 1 000×.

On an idle pool with a 3.5 % declared edge and no app fee (pool edge 330 bps), the 150 bps bound on assets binds first. The smallest pool that carries a win-or-nothing ticket is roughly `liability / 0.015`:

| Ticket | Prize | Liability | Pool needed, idle |
| - | - | - | - |
| 1 USDC | 10 USDC | 9.00 | about 600 USDC |
| 2 USDC | 19.30 USDC | 17.30 | about 1 200 USDC |
| 1.90 USDC | 185.90 USDC | 184.00 | about 12 300 USDC |
| 6.45 USDC | 622.44 USDC | 616.00 | about 41 000 USDC |
| 7.5 USDC | 7 500 USDC (1 000×) | 7 492.52 | about 500 000 USDC |

As the pool fills up, the Kelly term on the free balance can bind instead, so the largest prize the pool accepts falls as utilisation rises.

### Show the limit, do not hit it

Read `Config` (for the parameters) and `Pool` (for `totalAssets`, `totalReservedLiability`, `openPoolCredits`) and apply the checks above in integers to show users the largest prize, or the largest stake, the pool accepts right now. Then simulate the transaction before asking for a signature: the program is the authority, and the pool can move between your read and the user's click.

```ts theme={null}
import { fetchConfig, fetchPool, findConfigPda, findPoolPda } from "./generated/fade";

const params = (await fetchConfig(rpc, (await findConfigPda(cfg))[0])).data.params;
const pool = (await fetchPool(rpc, (await findPoolPda(cfg))[0])).data;

const free = pool.totalAssets - pool.totalReservedLiability - pool.openPoolCredits;
const poolEdgeBps = 330n; // paytable edge − app fee − protocol fee
const kelly = (((free * poolEdgeBps) / 10_000n) * params.kellyFractionBps) / 10_000n;
const flat = (pool.totalAssets * params.censorshipBps) / 10_000n;
const cap = kelly < flat ? kelly : flat; // largest liability one wager may take now
```

## Common refusals

| Error | Cause | Fix |
| - | - | - |
| `BucketCount` | 0 or more than 32 buckets | Group outcomes that share a multiplier |
| `ProbabilityRange` | A `p` of 0, or above 1e9 | Remove unreachable outcomes |
| `ProbabilitySum` | Probabilities do not sum to exactly 1e9 | Put the remainder on the zero bucket |
| `MultiplierCeiling` | A multiplier above 10 000× | Lower the top prize |
| `PaytableOverpays` | Expected return above 100 % | Lower probabilities or multipliers |
| `EdgeFloor` | Edge below 120 bps + app fee | Raise the edge or lower the app fee |
| `IntegratorFeeTooHigh` | App fee above 500 bps | Lower it |
| `StakeBounds` | Stake below `min_stake` or above `max_stake` | See [Devnet parameters](/build/devnet) |
| `PerWagerCap` | Liability above the cap | Smaller top prize, smaller stake, lower app fee, or a larger pool |
| `IntegratorCap` | Your open liability above 20 % of assets | Wait for your open wagers to settle |
| `UtilisationBreaker` | The pool is more than 70 % committed | Wait; new wagers resume as wagers settle |

The full list is on [Errors](/build/errors).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.