Market Capacity#
Trader-ledger sizing, seat tiers, and the ledger-allocation prelude.
What capacity is#
Each market has a trader_ledger PDA with a fixed number of seats — the
maximum number of distinct traders who can hold a position. The seat count is
chosen at creation via the num_seats field of CreateMarket and cannot be
changed afterward.
Seat tiers#
The ledger-layout inventory contains twelve values
(TRADER_LEDGER_SEAT_OPTIONS). Market activation additionally requires both
num_seats <= 4,225 and the strict admission-headroom invariant
num_seats > bids_size + asks_size. The two larger values remain recognized
layouts for safe inspection and recovery; the program rejects their activation
with TraderLedgerCapacityUnsafe (0x3023). The legacy 128-seat layout is
also recognized but cannot activate with the smallest supported two-sided book
(64 + 64); new small markets use 129 seats, and the default Standard tier
uses 1,025.
| Status | num_seats | Ledger size (bytes) | Rent at 3,480 (≈) | Rent at 348 (≈) |
|---|---|---|---|---|
| Layout only | 128 | 9,272 | 0.065424 SOL | 0.006542 SOL |
| Small activation | 129 | 9,344 | 0.065925 SOL | 0.006593 SOL |
| 128/book-side floor | 257 | 18,560 | 0.130068 SOL | 0.013007 SOL |
| 256/book-side floor | 513 | 36,992 | 0.258355 SOL | 0.025836 SOL |
| Standard | 1,025 | 73,856 | 0.514929 SOL | 0.051493 SOL |
| Over-provisioned | 1,153 | 83,072 | 0.579072 SOL | 0.057907 SOL |
| Large | 2,049 | 147,584 | 1.028076 SOL | 0.102808 SOL |
| Over-provisioned | 2,177 | 156,800 | 1.092219 SOL | 0.109222 SOL |
| Very large | 4,097 | 295,040 | 2.054369 SOL | 0.205437 SOL |
| Over-provisioned | 4,225 | 304,256 | 2.118513 SOL | 0.211851 SOL |
| Layout only | 8,193 | 589,952 | 4.106957 SOL | 0.410696 SOL |
| Layout only | 8,321 | 599,168 | 4.171100 SOL | 0.417110 SOL |
Ledger size = 56 + num_seats * 72 bytes. Rent is the Solana rent-exempt
minimum, (128 + size) * lamports_per_byte_year * 2.
Both rent columns are planning figures, not constants. lamports_per_byte_year
is a cluster parameter: mainnet runs 3,480 today, and a pending network upgrade
reduces it to 348 (stated upstream as "6,960 → 696 lamports per stored byte",
which is the same 10x once the two-year exemption multiplier is folded in). Do
not embed either column in code — call
calibrateRentRate / rentExemptLamports from @seesaw/core, which derive the
figure from a live getMinimumBalanceForRentExemption probe and therefore stay
correct across the change. See
constants for the calling pattern.
The deep-orderbook tier inventory remains 64 through 4,096; the seat ceiling
is specifically for the trader-ledger's worst-case unique-maker lookup cost.
Launch seat policy#
For first-party launch catalogs, choose seat tiers from expected audience size instead of defaulting every market to maximum capacity:
| Symmetric book capacity | Minimum safe num_seats | Activation support |
|---|---|---|
| 64 | 129 | Supported |
| 128 | 257 | Supported |
| 256 | 513 | Supported |
| 512 | 1,025 | Supported |
| 1,024 | 2,049 | Supported |
| 2,048 | 4,097 | Supported |
| 4,096 | 8,193 | Not activatable under the 4,225-seat release ceiling |
For first-party catalog defaults, the corresponding audience-oriented policy is:
| Catalog tier | Symmetric book capacity | Default num_seats | Use when |
|---|---|---|---|
| Small | 64 | 129 | Experimental feeds, long-tail markets, and the first run of a new cadence |
| Standard (default) | 512 | 1,025 | Featured recurring markets with expected organic traffic |
| Large | 2,048 | 4,097 | Flagship markets with staged liquidity, marketing, or partner traffic |
DEFAULT_CAPACITY_TIER (packages/core/src/constants.ts) resolves to Standard:
the 64-order book is the tier most likely to fill and force a creator into
EnsureDeepOrderbookSpace, and the rent difference between tiers is refundable.
Choose the tier on expected book depth, not on creation cost. This is an
off-chain catalog default only — no program constant encodes a default tier.
Do not treat 8,193 or 8,321 as activatable market tiers. Raising the
ceiling requires a new release-SBF measurement of the T4096 / 63-distinct-maker
/ late-slot case and an explicit program update; allocation size alone is not
evidence of fill-path liveness.
Monitor trader-ledger occupancy by market and alert before the ledger reaches 90% occupied. The strict headroom invariant means a full ledger contains at least one slot with no live-order lock. An all-zero slot is recycled by the allocator; otherwise a keeper may drain each nonzero free bucket in full to that slot owner's mint-matched token account. The last drain clears the slot, and clients can atomically bundle that drain with a new admission to avoid a race. Partial drains, locked slots, and redirection to the keeper remain forbidden. Existing balances remain governed by the normal settlement, withdrawal, cancel, reduce, reclaim, and redemption paths. User-facing surfaces should describe an admission failure as market capacity being full, not as lost funds.
Bulk-cancellation launch policy#
CancelAllOrders and CancelUpTo perform a full targeted-side scan before
mutating any order. The measured launch envelope supports this family only for
deep-book tiers 64, 128, 256, and 512 orders per side. Tiers 1024,
2048, and 4096 remain valid for matching and direct CancelOrder,
CancelMultipleOrdersById, and ReduceOrder, but bulk range-cancellation is
not a launch-supported operation against a dense book. The program rejects
every scan-based bulk-cancel route before traversal on those tiers with
BulkCancelIncomplete; product surfaces must route users to direct, bounded
recovery operations and must not advertise a single bulk call as guaranteed
to complete for T1024+.
This policy is machine-pinned by
BULK_CANCEL_MAX_ORDERBOOK_CAPACITY = 512 and
DeepOrderbookCapacityTier::supports_bulk_cancel() in the on-chain state
module. The SBF dense-book certificate separately checks that an unsupported
T1024+ request returns before traversal with byte-for-byte rollback.
Refundable rent#
The creator pre-pays the ledger rent. When the market is closed after
resolution (CloseMarket), the trader_ledger rent (along with the market,
orderbook, and vault rent) is returned to the creator.
Allocation preludes#
Solana caps account growth at MAX_PERMITTED_DATA_INCREASE (10,240 bytes) per
top-level instruction, so a ledger larger than ~141 seats cannot be allocated
in one shot. Before CreateMarket, callers must invoke
EnsureTraderLedgerSpace (0x2E) ceil(target_size / 10240) times to grow the
PDA in chunks, where target_size = 56 + num_seats * 72. The instruction is
idempotent and a no-op once the PDA is at target size. CreateMarket rejects a
ledger that is not fully pre-grown.
Deep orderbooks use the same pattern. Callers must invoke
EnsureDeepOrderbookSpace (0x33) ceil(deep_orderbook_size / 10240) times,
where deep_orderbook_size = 192 + capacity * 224 and capacity is one of
64, 128, 256, 512, 1024, 2048, 4096. Large tiers can require many prelude
instructions, so split them across transactions before the final CreateMarket.
The TypeScript (@seesaw/core), Rust (sdk-rust), and Python (sdk-python)
SDKs bundle these preludes automatically — see the
SDK create-market example.
CU launch-tier evidence#
Before a release-candidate signoff can raise the first-party launch tier above
the documented launch policy, operators must attach a STRAT-4 CU launch-tier
artifact and point SEESAW_CU_LAUNCH_TIER_EVIDENCE_FILE at it when running
RELEASE_CANDIDATE=1 scripts/production-readiness-check.sh.
The measurement command must be the release BPF CU regression gate:
BPF_OUT_DIR="$(pwd)/target/deploy" cargo test -p seesaw --release --features test-sbf \
--test cu_benchmark release_sbf_cross_tier_upper_bound_unique_maker_fill_guard \
-- --nocapture --test-threads=1
The artifact is JSON with this shape:
{
"releaseCommit": "0123456789abcdef0123456789abcdef01234567",
"generatedAt": "2026-07-04T00:00:00Z",
"command": "BPF_OUT_DIR=target/deploy cargo test --release --test cu_regression --features test-sbf",
"maxLaunchDeepOrderbookCapacity": 1024,
"deepOrderbookTierMeasurements": [
{ "capacity": 64, "measuredCu": 123456, "sampleCount": 3, "status": "pass" },
{ "capacity": 128, "measuredCu": 123456, "sampleCount": 3, "status": "pass" },
{ "capacity": 256, "measuredCu": 123456, "sampleCount": 3, "status": "pass" },
{ "capacity": 512, "measuredCu": 123456, "sampleCount": 3, "status": "pass" },
{ "capacity": 1024, "measuredCu": 123456, "sampleCount": 3, "status": "pass" },
{ "capacity": 2048, "measuredCu": 123456, "sampleCount": 3, "status": "pass" },
{ "capacity": 4096, "measuredCu": 123456, "sampleCount": 3, "status": "pass" }
]
}
Validate the artifact offline before release signoff:
node scripts/security/validate_cu_launch_tier_evidence.mjs <artifact.json>
Reclaim-frontier launch evidence#
ReclaimExpiredOrder is intentionally one exact-ID, permissionless unwind per
transaction. The SDK's 64-target sweep is only a bounded planner for those
independent transactions; it does not change on-chain throughput or make an
economic claim. Therefore a release candidate must provide a measured
BOOK-008 artifact through SEESAW_RECLAIM_FRONTIER_EVIDENCE_FILE.
{
"releaseCommit": "0123456789abcdef0123456789abcdef01234567",
"generatedAt": "2026-08-09T12:00:00Z",
"command": "BPF_OUT_DIR=target/deploy cargo test -p seesaw --release --features test-sbf --test security_deep_orderbook_v3_attacks -- --nocapture",
"config": { "minRestingNotional": 2, "reclaimBountyBps": 10, "reclaimBountyMax": 100000 },
"profile": {
"priorityMicroLamportsPerCu": 1000000,
"keeperCount": 3,
"attackerEligibleOrdersPerSecond": 2,
"successfulReclaimsPerSecond": 4,
"worstReclaimTransactionFee": 1000,
"minimumEligibleRefund": 1250000,
"minimumObservedBounty": 1250,
"p99ReclaimableAgeSeconds": 30,
"maxReclaimableAgeSeconds": 120,
"maxConsecutiveDenialSlots": 2,
"maxPlacementDenialSeconds": 5
},
"measurements": [{ "capacity": 64, "staleFrontierOrders": 64, "successfulReclaims": 64 }]
}
Include one measurements object for every supported capacity tier.
The artifact records the live minimum-notional and reclaim-bounty inputs, the
measured transaction fee at exactly 1,000,000 micro-lamports/CU, and every
supported book tier with at least 64 stale-frontier orders. Its validator fails
closed unless the signed profile records all of: at least three keepers,
successful reclaim throughput at least twice eligible stale-order creation,
observed and configured bounty at least 1.25 times the measured fee, p99/max
reclaimable ages no greater than 30/120 seconds, and placement denial no more
than two slots/five seconds. No SOL/USD conversion, priority-fee forecast, or
unmeasured keeper cost is inferred by this gate.
node scripts/security/validate_reclaim_frontier_evidence.mjs <artifact.json>
If the configured minimum eligible refund cannot produce the required bounty at the measured fee, the artifact is rejected. The release remains blocked; raising scan limits or asserting that keepers will subsidize the gap is not an acceptable substitute for a bounded-progress design and fresh evidence.