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

# How the product works

> Direction, stake, rung, barrier and tenor — and the ways a position ends.

A position's **terms** are stamped onto it at the moment it opens, and settlement reads those
stamped terms rather than whatever governance has done since. Governance cannot change a running
trade's terms. Two guardian switches can stop it closing; see
[settlement](#settlement-is-permissionless).

Its **size** is a different question. The owner — and only the owner — may add collateral to a live
position. That averages the entry and moves both price levels with it, so it is the one thing about
a live position that is not fixed. See [adding to a position](#adding-to-a-position). **No governed
value reaches a live position's terms, with one exception:** a position that stored a borrow grace of
`0` reads the live `config.params.borrowGraceS` (see [the borrow fee](#the-borrow-fee)).

## An open is an order

**Your stake is taken when the open lands, and the venue's next price sets your entry.** The open
carries no price. The program records it as an **order** with a target slot a short, governed delay
after the slot in which it landed (`d` slots). The entry is the first price of the venue's price
feed at or after that target. A filler on the venue's list writes it, and the order becomes a
position. The barrier and the rung are distances from that entry.

* **The price on your screen when you tap is not your entry.** Your entry is the next price after
  the delay.
* **An order that is not filled in time is returned.** If the first price comes too late or does
  not meet the venue's quality rule, if the market closes, or if no filler lands inside the fill
  window, anyone can return the order, and the venue's keepers do. You get your whole stake back.
* **You cannot fill your own order.** Only a filler on the venue's list can write an entry.
* **A landed open is not yet a position.** Read your entry when the order is filled, never from the
  screen at the tap.

The timing settings, the events that report each step and the SDK calls are in
[orders and closes](/sdk/orders).

## The five choices

<Steps>
  <Step title="Asset and direction">
    Which market you are trading, and whether you are long or short. The market names the price
    feed that decides your outcome — see [the price that decides](#the-price-that-decides-your-outcome).
  </Step>

  <Step title="Stake">
    Your collateral, between the venue's `minCollateral` and `maxCollateral`. It, and any entry fee
    paid on it, is the entire amount at risk. The bounds are governed and live on chain; read them
    from the config account.
  </Step>

  <Step title="Rung">
    Your take-profit target, as a multiple of the stake. Any multiple **at or above 2.00x** is
    admitted, up to the protocol's payout cap — the one ceiling, read as
    `config.params.payoutCapMultiple`. The presets are `presetRungsBps(ceilingBps)` at the live
    payout cap — not the only choices.
  </Step>

  <Step title="Leverage">
    How far the price has to move to reach either end — so, how *fast* the position resolves.
    **1000x on every market.** Pass `tier` on `open`: `0` means the market's own. A market's `tier` is
    the ceiling and the venue's `config.minTier` is the floor. Above the ceiling is refused
    (`LeverageAboveMarketTier`), below the floor is refused (`LeverageBelowMinTier`), and so is a
    value the program does not list. Both values are governed: read them from the chain.

    **It changes nothing about what you can win or lose.** There is no leverage term in the payout.
    What leverage changes is the DISTANCE to both levels.
  </Step>

  <Step title="Timer (optional)">
    You may set your own expiry. Leave it at zero and you have no clock at all, because the
    protocol's tenor is indefinite (see [the tenor](#the-tenor)). A timer you set is at least 26
    seconds.

    **Setting a timer is free.** A timed open pre-pays nothing. See [the fees](#the-fees).
  </Step>
</Steps>

## The barrier

Every position has a **barrier**: a price, fixed at open, sitting a set distance on the losing
side of your entry. If the market touches it, the position is over and **you receive nothing**.

Three things about it are worth internalising:

* **It is a distance, not a dollar amount.** The distance is set by **the leverage you chose**,
  which the market's tier caps. More leverage means a nearer barrier, which is exactly what makes
  the position resolve fast. Two positions on the same asset can sit at different distances.
* **It is direction-relative.** For a long it sits below entry; for a short, above.
* **It is fixed at your open.** Its distance is frozen when your order lands, and its price is set
  when the order is filled. A governance change later does not move a barrier that already exists.

The exact distance for the terms you are about to open is returned by the SDK's
`openPreview().barrierMicroBp`, and the resulting price by `levels()`. Read it, show it to the
person taking the risk, and do not hand-compute it.

<Warning>
  **At the barrier the trader receives nothing.** Any interface that tells a user they keep some
  fraction of their stake on a knockout is wrong. Plan your product around the stake being gone.

  Nothing is meant literally, not "nothing worth rounding". At the barrier the loss tax takes the
  whole of the position's equity, and the crumb the flooring leaves behind — a few base units, a
  ten-thousandth of a cent — goes to the LP pool, not back to the trader. `settlePreview` returns
  `0` for a knockout and that zero is exact.
</Warning>

## The rung

The rung is the other side of the same idea: a price, also fixed at open, sitting the distance
away that corresponds to your chosen multiple. Touch it and the position has a gross gain of the
multiple less one, times your stake: a 2.00x rung is a gain equal to the stake. What you receive is
that gain less the share of it the terms withhold and less the exit fee, so a rung pays less than
its multiple. [Fees and limits](/limits#how-a-win-is-calculated) has a worked example.

Your rung can be **any multiple of your stake at or above 2.00x** — not a fixed list. The floor is
`RUNG_FLOOR_BPS`, 2.00x.

**The presets are `presetRungsBps(ceilingBps)`**, which returns four values in bps of stake and ends
at the live payout cap. A preset above the live cap is refused `RungAbovePayoutCap`: compute the
presets from the live cap. The SDK's `RUNGS` export — `[2, 3, 5, 10]` — is **not** the preset list.
A client may offer any value at or above the floor.

**There is exactly one ceiling above that floor, and it is `config.params.payoutCapMultiple`.**
Read it from the config account; a market carries no take-profit ceiling of its own.

<Note>
  `RungAboveMarketCap` (6050) keeps its code in the error catalogue, but nothing in the program
  raises it: a client branching on 6050 is handling a refusal that cannot arrive.
  `RungAbovePayoutCap` is the live one.
</Note>

## Adding to a position

**A trader may add collateral to a position that is already live.** It is one order, not two: the
stake grows, the entry becomes the average of the prices actually paid, and both levels move with
it. Opening a second position instead would leave a trader holding two trades that knock out at two
different prices, which is the outcome this instruction exists to prevent.

**An add is an order too.** It takes the added stake when it lands (`CollateralCommitted`) and
carries no price. The add is priced at the first price of the venue's price feed at or after the
same short delay, and then one of two things happens:

* **It is filled** (`CollateralAdded`): the entry becomes the blend, and both levels move with it.
* **It is returned** (`AddReversed`), in full: if no price or no filler comes in time, or if at the
  add's price the position is already at its barrier or its target. A returned add keeps the time it
  added to your timer.

Until the add is filled or returned, and for a short, governed time after a filled add's price
(`M_add` slots), you cannot close the position, move its target or add again (`AddPending`). In
that time a price from before the add that breached the old barrier still proves a knockout: the
position is knocked out on its old stake, and the added stake comes back. A touch of the target
while an add waits for its price does not count, and it is lost if the add is then filled.

<Warning>
  **Adding while you are AHEAD moves the barrier TOWARD the live price.** This is the single fact
  an interface must not bury. Leverage is fixed by the POSITION's tier — chosen at open, frozen into the slot — so an add buys *size at
  market* — it is not "adding margin" and there is no top-up here that de-levers you.

  Both levels are distances from the entry, and the entry always moves toward the price the add
  filled at. So for a long:

  | You are | The entry | The barrier price | The take-profit price |
  | - | - | - | - |
  | **behind** (price below entry) | falls | falls — **away** from the price | falls — toward the price |
  | **flat** | unchanged | unchanged | unchanged |
  | **ahead** (price above entry) | rises | rises — **toward** the price | rises — away from the price |

  A short is the mirror in price and the identical statement in distance. **A trader who is ahead
  spends their profit cushion on size.** Do not offer this control to a winning position with
  copy that suggests it protects one.
</Warning>

Adding neither realises nor creates a profit or a loss. A trader who is $0.40 down and adds $1 is
still \$0.40 down at the add's price: the entry is the collateral-weighted **harmonic**
mean of the old entry and the fill price, which is the only blend with that property, and it is
also the average cost basis every trading interface already shows.

```text theme={"dark"}
E' = C' × E0 × S / (C0 × S + dC × E0)
```

What else it does, all of which a client has to handle:

* **The add is fee-inclusive, exactly as an open is.** You hand `added_budget` — the total
  to add — the venue takes its entry fee from inside it, and the debit is at most that.
  `min_added_collateral_out` is the trader's mandatory floor on the increment SIZE, the signature over
  what the add buys.
* **The stake bounds bind on two different quantities.** The minimum binds on the *increment*, the
  maximum on the *total*. So a position already holding more than `maxCollateral − minCollateral`
  has **no legal add at all** — quote the admissible range and never render a control whose every
  value is refused.
* **The clock may only be lengthened.** `extend_timer_s` is a delta in seconds and it only ever
  goes forward, and never past the tenor frozen on the position. A double-down is the only way to
  move a position's own timer, and it cannot shorten it.
* **A position that has touched a level cannot be added to.** An add whose price is at or through
  the barrier, or at or through the take-profit, is returned in full (`AddReversed`).
* **The hold clock restarts.** A filled add re-prices the position, so [the minimum
  hold](#the-minimum-hold) before a close you ask for runs again from the add's price.

The borrow fee below is the one clock an add does **not** reset: it is measured from the original
open, because the pool capital the first stake froze has been frozen the whole time.

```ts theme={"dark"}
import { addCollateralForMode } from '@rekt/1000x';

// The account list is `open`'s, minus `system_program` — an add grows a slot, it creates none.
// `config` is the decoded config. The add carries no remaining accounts, and while adds are off
// this refuses to build it (`AddsDisabled`).
export const addIx = addCollateralForMode(
  config,
  {
    authority, trader_token: traderToken, config, market, vault,
    vault_token: vaultToken, protocol_token: protocolToken,
    positions, delegate: null,
  },
  {
    seq,                    // the handle, never the slot index
    // Read the live entry fee. At an entry fee of 0 the increment equals the budget.
    added_budget: 250_000n,             // the fee-inclusive TOTAL to add; the debit is AT MOST this
    extend_timer_s: 0,                  // a DELTA, forward only. 0 leaves the clock alone
    min_added_collateral_out: 250_000n, // mandatory floor on the increment SIZE; 0n refused (MinCollateralOutRequired)
  },
  feeds,
);
```

### Sizing an add from a total

The trader can name what leaves their wallet instead of naming the increment. `sizeAddForTotal` is
that inverse, and it is **not** `sizeForTotal` with a different argument.

```ts theme={"dark"}
import { admissibleAdd, sizeAddForTotal, toEnginePosition } from '@rekt/1000x';

// `admissibleAdd` takes the ENGINE position, so a decoded slot goes through `toEnginePosition`.
const room = admissibleAdd(toEnginePosition(position), config.params); // null = the position is full
const size = sizeAddForTotal(500_000n, config.params.entryFeeBps, room!, /* setsTimer */ false);
// size.collateral  500000n   the increment this budget buys — pass as `min_added_collateral_out`
// size.debit       500000n   what actually leaves the wallet (at most the budget you sign)
// size.dust             0n   what could not be spent
// size.summary     "$0.50 adds $0.50 and costs exactly $0.50."
// size.refusal        null   or a Gate-shaped refusal naming the bound that was missed
```

Two things differ from the open path's answer, and each is money:

* **`setsTimer` does not change the debit.** Setting a timer is free, on an open or an extension.
* **The bounds are `admissibleAdd`'s interval, not `config.params`.** The ceiling binds on the
  total, so what a position may still take is the governed ceiling less what it already holds.

`size.debit` is never above the total, so the number the trader typed is the `added_budget` you sign
and the chain debits at most that. A fee change landing between the quote and the signature can only
shrink the increment, and the `min_added_collateral_out` floor you set from `size.collateral` turns
that into a `BudgetBelowCollateralFloor` revert rather than a silent shrink.

<Note>
  `addPreview`, `admissibleAdd`, `addCollateral` and `addImpact` answer *"what would this add do"*
  and *"what increments are legal"*, which covers the blended entry, the admissible range and the
  barrier's new price. Quote with them; do not derive the blend by hand from the formula above, and
  do not offer the control without showing where the barrier moves to. `addGates` is the gate report
  for an add — see [reading gates](/sdk/gates).
</Note>

## The tenor

**The tenor is the protocol's own clock for a position. It is `config.params.tMaxSeconds`, a governed
parameter, and it is frozen onto your position at open.** The tenor is the indefinite value, so a
position has no protocol clock: it ends by its barrier, its target, your own close, your own timer if
you set one, the close of its session on a market with trading hours, or the 24 hour refund under
[How a position ends](#how-a-position-ends). A position keeps the tenor it froze at open. The SDK
tests for it with `isIndefiniteTenor()`; show "no limit", not a date. A position that froze a finite
tenor is closable by anyone when the tenor runs out.

**On gold, the tenor is shorter.** It is `config.params.tMaxSeconds` or the time left until
`market.sessionBufferS` before the session's close, whichever is shorter, so every gold position's
tenor ends before its session closes. See [markets](/markets#what-happens-in-each-gold-session).

Frozen is the part that is a guarantee: settlement reads the tenor stamped on your position, so a
governance change afterwards cannot change a position you already hold. **Read the live value
rather than typing it, and do not build an interface that promises a reader a duration from a
constant.**

<Note>
  **Read `tMaxSeconds` and `borrowRateBpsPerHour` together;** neither one alone tells you how long a
  position can live. An LP's withdrawal wait does not follow the tenor — see
  [providing liquidity](/liquidity#getting-your-money-out).
</Note>

You may also set a shorter timer of your own. The two clocks are independent, and the earlier one
is the moment your position first becomes closable by a stranger. A double-down can push your own
timer out, never in — see [adding to a position](#adding-to-a-position). The SDK computes both
from the position itself:

```ts theme={"dark"}
import { deadlines, isIndefiniteTenor, type PositionView } from '@rekt/1000x';

export function clocks(position: PositionView) {
  const d = deadlines(position);
  const noTenor = isIndefiniteTenor(position.tMaxSeconds);
  return {
    openedAt: d.openedAt,
    // The protocol's clock, read from the position's own frozen tenor — never from live config.
    // null means no limit: show "no limit", never a date.
    tenorExpiresAt: noTenor ? null : d.tenorExpiresAt,
    // Your own timer, or null when you set none.
    userExpiresAt: d.userExpiresAt,
    // The earlier of the two: when a stranger may first close this position.
    firstExpiryAt: noTenor ? d.userExpiresAt : d.firstExpiryAt,
  };
}
```

## How a position ends

<AccordionGroup>
  <Accordion title="Knockout — the price touched the barrier" icon="circle-xmark">
    The position is over and the trader receives nothing. Plan for it: at high leverage the
    barrier sits close enough to entry that an ordinary move reaches it. A knockout settles *at*
    the barrier no matter how far past it the price ran, so it needs no exit price to price it.

    Anyone may prove it with any signed price that is newer than the entry and at most `W_ko`
    slots old, a governed setting. So a position can be knocked out by a recent price that has
    already moved back on your screen. After a close request or an expiry mark, only a price that is
    not later than the exit price can knock the position out.
  </Accordion>

  <Accordion title="Take-profit — the price reached your rung" icon="circle-check">
    The position pays the rung's multiple of your stake, subject to the overall payout cap. It is
    proved the same way as a knockout, and the price that proves it must also clear [the minimum
    hold](#the-minimum-hold). A touch while a double-down waits for its price does not count. After
    you move your target, only a price at least `d` slots later proves the new one.
  </Accordion>

  <Accordion title="Expiry — a clock ran out" icon="clock">
    Either your own timer or the protocol's finite tenor (an indefinite tenor never expires). From the deadline, anyone may mark the expiry
    (`mark_expiry`). The position settles at the first price at or after `d` slots from the mark,
    by the same window rule as a close you ask for, whatever that price is: a position expiring in
    profit is paid, and one expiring in loss is settled where it stands.
  </Accordion>

  <Accordion title="Voluntary — you closed it" icon="hand">
    You ask for the close with `request_close`, signed by you or by a session key you authorised.
    The request carries no price, so it cannot fail on a stale one, and **it cannot be withdrawn**.
    The exit price is the first price of the venue's price feed at or after `d` slots from the
    request. Anyone may then send the settle that pays it, and the venue's keepers do.

    **The window rule.** If nobody settles inside the exit window (`W` slots) from that target, the
    price becomes the first price of the next window, and so on, and a knockout price in between
    still counts. So the close price is not locked when you ask, and no interface should say it
    is. You cannot ask inside [the minimum hold](#the-minimum-hold).
  </Accordion>

  <Accordion title="Last resort — no price could be obtained" icon="life-ring">
    Anybody may close a position with no quote, but only while no fresh price exists, and only on one
    of two time grounds.

    **A market with no posted price for 24 hours is dark** (the governed `dark_after_min`, read from
    the governance table as `GovTable.darkAfterMin`). On a dark market anyone can close any position
    on it, and the position gets its stake back. Anyone can post a signed price with `provePrice` to
    reset the clock.

    **A position with a finite tenor** can also be closed once its frozen tenor plus a governed
    grace (`config.lastResortGraceS`) has elapsed. A position with the indefinite tenor has only the
    dark ground.

    A live position is paid its stake back with the exit fee waived; a position already stamped at a
    level is paid that level. The close is refused while the oracle is frozen, on an order that is
    not filled, and while an add waits for its price.

    **A position that is not settled before its session's close ends at par,** on a market with trading
    hours: a quote from a later session never prices it.
  </Accordion>
</AccordionGroup>

The SDK names six close reasons, because expiry has two flavours: `voluntary`, `knockout`,
`takeProfit`, `userExpiry`, `tenorExpiry` and `lastResort`.

## The minimum hold

**A position cannot be closed by its owner in the first slots after its entry price.** The venue
has one hold for every market, `resolveMinHoldSlots(config.minHoldSlots)` slots, and a market can
have a longer one, `market.closeHoldSlots`. The longer of the two applies. Both are governed
settings: read them from the chain.

* The hold starts at your entry price, and again at the price of each double-down.
* A close request inside it is refused (`MinimumHoldNotMet`, `MarketHoldNotMet`). The position is
  not affected. Send the request again from the first slot the hold allows:
  `closableFromSlotOf(position, config, market)` gives that slot from three public accounts, so an
  app can show "can close in N seconds" with no guess.
* A take-profit must also clear the hold, measured to the slot of the price that proves it. The
  venue's hold also applies to the end of your own timer.
* A knockout is never held back, and a market's own hold never holds back a timer end.

## Settlement is permissionless

Every close ends with a `settle` that **anyone may send**. Only one step needs the owner: the
request for a voluntary close. A knockout and a take-profit are proved by the price, and the two
expiries and `lastResort` by the clock. Every priced close carries a signed quote from the venue's
price feed; `lastResort` needs none.

Two switches can stop closes: the guardian's oracle freeze starves every priced close of a price and
refuses `lastResort`, and its settle kill-switch refuses every close. Only the config authority lifts
either. Read `config.oracleFrozen` and `config.settlesDisabled`.

**Nobody is paid for sending a close.** The protocol pays its submitter nothing — no fee, no share
of the settlement, no gas rebate. If you run a keeper, budget for it as a cost.

```ts theme={"dark"}
import { isPermissionless, type CloseReasonName } from '@rekt/1000x';

// Everything except `voluntary` can be submitted by a stranger, and `voluntary` too once the owner
// has requested it: pass the position's phase, `isPermissionless('voluntary', 'ExitRequested')`.
// None of them pays the submitter for it.
export const permissionless: CloseReasonName[] = (
  ['voluntary', 'knockout', 'takeProfit', 'userExpiry', 'tenorExpiry', 'lastResort'] as CloseReasonName[]
).filter((r) => isPermissionless(r));
```

## The payout cap

**No target can be set above the payout cap.** The cap is the governed `payoutCapMultiple`, the largest
multiple the program lets a target take. A position with no target of its own has the cap as its
target. Read it rather than typing it.

**A win is paid in full. Part of it may be paid later, in order. There is no guaranteed time. The
amount queued ahead of you is shown.** How, and what a client shows, is in
[how a win is paid](/liquidity#how-a-win-is-paid).

## The fees

Three, all on chain. Two are charged on an event; the third is charged on time. Setting a timer is
free. The rates, with the date they were read, are on [Fees and limits](/limits).

* an **entry fee** (`config.params.entryFeeBps`, basis points of the stake), taken from inside your
  budget when you open, and from the increment when you add. It is 0, so an open costs the stake and
  nothing more. The venue is fee-inclusive: you hand a total, it takes the fee from within it, and the
  debit is at most the number you signed;
* an **exit fee**, charged at every close **except a knockout**, and waived on a live position closed
  by `lastResort`. It is a share of the exit value, the money the position closes with before the
  fee. The rate depends on the price move at the close: one rate when the close is a gain beyond a
  small band around the entry price, a higher rate when it is a loss beyond the band, and a rate
  between the two inside the band. On a gain, the terms also withhold part of the gain: the share you
  keep is smaller for a small move and rises with the size of the move. [Fees and limits](/limits#how-a-win-is-calculated)
  has the values, dated, and a worked example. A position freezes its terms when it opens, so a later
  change to a market's terms never reaches a position that is already open. The terms of a market
  are read from its fee-terms account (`feeTermsTablePda` in the SDK), and the share of each close is
  on its `SettlementFeeTerms` event;
* a **borrow fee**, charged out of the payout for however long the position was held.

A knockout is excluded from the exit fee because there is nothing left to charge: the stake is
already gone. The total that leaves your wallet is **at most the budget you hand the venue** — it
takes its entry fee from inside it, and setting a timer is free, so nothing is added on top. The SDK
sizes the position for you:

```ts theme={"dark"}
import { sizeForTotal, parseUsdc, type ConfigView } from '@rekt/1000x';

// Money is bigint in USDC base units. Parse text exactly; never through a float.
const budget = parseUsdc('1.00');

// The venue is fee-inclusive: it takes its entry fee from INSIDE the budget and opens the largest
// position the remainder buys, so the debit is AT MOST what you hand it. Setting a timer is free,
// so a timed open costs no more.
// Read `config.params` from the config account in production.
export function open(config: ConfigView) {
  const size = sizeForTotal(budget, config.params);
  // size.debit is at most the budget; size.collateral is the position it buys (the smaller number),
  // which you also sign as `min_collateral_out`.
  return { debit: size.debit, collateral: size.collateral };
}
```

### The borrow fee

It is rent on the pool capital your position freezes, charged out of the payout at settlement for
the time held beyond a free grace period, at a flat hourly rate on the collateral you opened with.
All of it goes to the pool. It is taken after the loss tax and after the exit fee, never out of your
equity, so it does not move the price that ends your position.

A position freezes its rate when it opens, and a stored grace of `0` reads the live
`config.params.borrowGraceS`. [Fees and limits](/limits) has the rate in force; read the position's
own `borrowRateBpsPerHour` to price its settlement.

<Note>
  Every one of these parameters is **governed**: they can be changed on chain by the protocol's
  authority. Do not cache them. Read them from the config account, and show the reader how old
  your copy is.
</Note>

## The price that decides your outcome

It is the venue's price feed for the market you traded — not "the price of SOL", because no such
single number exists. Every venue reports a different one.

Every price is a quote signed by the venue's price feed, and the program accepts it only when it is
signed by at least `market.minSignatures` keys that the program recognises.

* **Your entry** is the first price at or after your order's target slot. An order is filled only
  by a price that meets the venue's quality rule for an entry. Otherwise it is returned.
* **Your exit** is the first price at or after your close's target slot, by the window rule, or the
  price that proves a level.
* If no quote can be obtained at all, `lastResort` is the backstop.

Markets also close. BTC, ETH, SOL and XRP trade around the clock; gold trades only in its own sessions. A scheduled event — a rate decision, a print — can also close a
market to new opens for a window, and a market can be paused or halted. See [markets](/markets) for the rules at each close. The SDK models this as a state, never a boolean.
Branch on the state:

```ts theme={"dark"}
import { type MarketAvailability } from '@rekt/1000x';

export function describe(a: MarketAvailability): string {
  switch (a.state) {
    case 'open':
      return 'open for business';
    case 'closed':
      return `closed (${a.reason}), opens ${a.opensAt.toISOString()}`;
    case 'closing-soon':
      return `opens already refused; forced close at ${a.forceCloseAt.toISOString()}`;
    case 'halted':
      return `halted: ${a.reason}`;
  }
}
```

## Your positions live in one account

A trader has a single account holding several position slots — twelve by default in the SDK, and a
client may ask for anywhere from 1 to 12 when the account is created, or resize it later. That
account is created by its own instruction, not by opening a position — but account creation and
your first open **fit in one transaction**, so a first-time trader signs once and pays the
account's rent only on that first trade. The rent comes back to whoever paid it when the account is
closed.

That transaction is one an interface composes; the SDK's own composer will not build it for you.
[Opening a position](/sdk/opening#create-and-trade-in-one-transaction) has the recipe.

Slots are reused, so a slot index is not a position handle. The SDK gives you
`{ trader, slot, seq }` and settlement addresses positions by `seq`, so a stale handle finds
nothing instead of closing a neighbour. See [reading positions](/sdk/positions).


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