# Claim stakes
Documentation: next (source: develop).

Install the preview: `pnpm add @aephia/atlas-kit@next`. These docs follow develop and may include changes not yet published to npm.

> Claims on celestial bodies, their lifecycle, and what they yield.

Markdown source of https://develop.atlas-kit-docs.pages.dev/guides/claim-stakes/ — see https://develop.atlas-kit-docs.pages.dev/ai/ for the full machine-readable surface.

A claim stake is a player's claim on a celestial body: a hub to build
infrastructure on, producing resources over time rather than in a single
action.

:::game[A Claim Stake turns land into a base]
A Claim Stake lets a player take an available plot on a planet controlled by
their faction. They can build extraction, processing, power, and other
facilities there, turning empty land into a working base. Placing the stake
costs resources and keeping the plot requires ongoing ATLAS rent. If the
player's faction loses control of the system, the buildings can be lost and
the Claim Stake asset is returned.
:::

## Reading them

By owner, which is the usual direction:

```ts
const stakes = await character.claimStakes.all();
```

Or by the body, when you want to know who holds a particular place:

```ts
const stakes = await sage.claimStakes.byBody(bodyAddress);
```

> **Runnable example — Read the claim stakes on a body.** Every claim stake placed on one celestial body, with its state. Run it in the browser at https://develop.atlas-kit-docs.pages.dev/guides/claim-stakes/.

## Container and building catalogs

Read the available definition tables independently of any player's placed
stakes. Containers describe the Claim Stake itself; buildings describe its
infrastructure:

```ts
import {
  getClaimStakeDefinition,
  listClaimStakeDefinitions,
  getClaimStakeBuildingDefinition,
  listClaimStakeBuildingDefinitions,
} from '@aephia/atlas-kit/claim-stakes';

const containers = await listClaimStakeDefinitions(ctx);
const buildings = await listClaimStakeBuildingDefinitions(ctx);
const firstContainer = containers[0];
if (firstContainer !== undefined) {
  const definition = await getClaimStakeDefinition(ctx, firstContainer.id);
  console.log(definition.name, definition.slots);
}
const firstBuilding = buildings[0];
if (firstBuilding !== undefined) {
  const definition = await getClaimStakeBuildingDefinition(
    ctx,
    firstBuilding.id,
  );
  console.log(definition.power, definition.resourceExtraction);
}
```

These are two independent catalogs with immutable definitions shared between
list and by-id reads. Building production and extraction fields describe the
configuration; read a placed stake for its production state. A catalog entry
alone does not establish whether a player can build it on a particular stake.
See [Definition catalogs](/concepts/definitions/) for loading both together,
persistence, and section refresh behavior.

## Lifecycle is a state, not a flag

A stake's `state.kind` is one of `design`, `active`, or `deactivated`. Those are
genuinely different situations rather than degrees of the same one:

```ts
if (stake.state.kind === 'active') {
  // Producing. Other kinds are not.
}
```

Reading a stake and assuming it is producing is the mistake this shape exists
to prevent.

## Buildings and construction

A stake is not one thing — it is a plot with infrastructure on it. The
snapshot carries the whole layout:

```ts
const stakes = await character.claimStakes.all();
const layouts = stakes.map((stake) => ({
  buildings: stake.buildings.length,
  crew: stake.neededCrew,
  underConstruction: stake.constructionRemainingSeconds > 0n,
}));
```

`buildings` is what has been placed — extraction, processing, power, storage —
and each wants crew. Construction is live state: a stake can be active and
still have `constructionRemainingSeconds` left on recent changes.

## What it produces

Production follows the same pattern as [mining](/guides/mining/): rates
against a clock, not a stored total.

```ts
const output = stake.resources.netProduction;
const held = stake.resources.inventory;
```

`netProduction` is per-resource rates (consumption nets against generation —
a processing chain can make a rate negative), `inventory` and `capacity` are
what the stake holds right now, and `lastTickAtUnixSeconds` anchors the clock
you project from.

## Rent keeps it standing

A stake occupies land and pays for it: `rentBalanceRaw` is what remains and
`lastRentAtUnixSeconds` when it was last settled. A dry balance eventually
means eviction, and coming back from that is a respawn, not a resume.

:::game[Deployments cost rent]
A crafting hab or claim stake is not bought once and owned forever — it
occupies land, and land charges rent. Keeping the balance topped up is part of
running the operation; letting it run dry eventually gets the deployment
evicted, and rebuilding after that takes a respawn. The two systems share this
machinery: habs and stakes are both deployed, built upon, rented, and
reclaimed the same way.
:::

## Instances have no derivable address

Like crafting processes, claim stake **instances** cannot be computed from the
character and the body — the address is assigned at creation. That is why the
reads are `byCharacter` and `byBody` rather than a derivation, and why finding
one you have no reference to needs discovery.

## Placing a claim stake

Placement turns the reads above into one planned transaction. If this would be
your first write, read
[How Atlas Kit changes the game](/start-here/how-it-acts/) first.

The planner needs the Planet and Starbase Player snapshots you intend to use,
the exact Claim Stake definition and zero-cost bundled hub ids from the current
Game catalog, a positive raw initial rent amount, your Profile authorization,
and a fresh address for the new Claim Stake. That address has no derivation, so
generate its key before planning and retain the key only until execution:

```ts
import { generateKeyPairSigner } from '@solana/kit';
import type { PlanAuthorization } from '@aephia/atlas-kit/claim-stakes/actions';
import { planPlaceClaimStake } from '@aephia/atlas-kit/claim-stakes/actions';
import { executePlan } from '@aephia/atlas-kit/planning';

const authorization = {
  profile: character.profile.address,
  authority: authoritySigner.address,
  keyIndex: 0,
} satisfies PlanAuthorization;

const claimStakeKey = await generateKeyPairSigner();
const plan = await planPlaceClaimStake(ctx, planet, starbasePlayer, {
  authorization,
  claimStake: claimStakeKey.address,
  claimStakeDefinitionId: 2,
  hubBuildingId: 21,
  initialRentAmount: 500_000_000n,
});

console.log(plan.summary, plan.requiredSigners, plan.preconditions);

const result = await executePlan(ctx, plan, {
  feePayer: authoritySigner,
  signers: [claimStakeKey],
});
```

Planning is inert: it does not sign, submit, reserve a plot, or retain either
signer. Inspect the summary, accounts, and freshness preconditions before
passing the Plan to a wallet boundary. The Profile authority and fresh Claim
Stake key sign only during `executePlan`; afterwards, rediscover the instance
instead of trying to derive its address.

The planner rejects known stale identity, Game catalog, cargo, crew, tag, and
plot-capacity inputs before signing. Final plot races, permissions, rent
arithmetic, and program capacity remain chain-authoritative, so a locally valid
Plan can still fail safely at execution and should never be submitted twice
after an unknown result.

## Planning a building design

An owned stake in `active` or `design` can plan one finite set of building
additions and removals. Building-design planning uses the loaded stake plus the
same Profile authorization; quantities are positive and each building id can
appear only once:

```ts
import { planClaimStakeBuildingChanges } from '@aephia/atlas-kit/claim-stakes/actions';

const buildingPlan = await planClaimStakeBuildingChanges(ctx, stake, {
  authorization,
  buildingChanges: [
    { buildingId: 9, kind: 'add', quantity: 2 },
    { buildingId: 4, kind: 'remove', quantity: 1 },
  ],
});

console.log(
  buildingPlan.summary,
  buildingPlan.requiredSigners,
  buildingPlan.preconditions,
);
```

This planner is also inert. It refreshes the Claim Stake, Game definitions,
identity, Starbase controller, cargo, and crew relationships; then it rejects
known stale sequences, invalid definitions, quantity underflow or overflow,
incompatible tags, insufficient construction cargo, and an unrepresentable
resulting design before signing. Rent synchronization and the final concurrent
design-sequence race remain chain-authoritative.

## Finalizing a building design

An owned stake can finalize only while its loaded and fresh state is `design`.
Finalization accepts the stake and the same Profile authorization, then produces
one inspectable instruction:

```ts
import { planFinalizeClaimStakeBuildingChanges } from '@aephia/atlas-kit/claim-stakes/actions';

const finalizePlan = await planFinalizeClaimStakeBuildingChanges(ctx, stake, {
  authorization,
});

console.log(
  finalizePlan.summary,
  finalizePlan.requiredSigners,
  finalizePlan.preconditions,
);
```

The planner rejects active, deactivated, foreign, stale, mismatched, or known
delinquent stakes locally. The program re-synchronizes rent at execution and
keeps final crew/building validation chain-authoritative, so inspect and present
the Plan immediately before authorization.

## Cancelling a building design

An owned stake in `design` can discard its pending building changes and return
to `active`. Cancellation accepts the stake and the same Profile authorization:

```ts
import { planCancelClaimStakeBuildingChanges } from '@aephia/atlas-kit/claim-stakes/actions';

const cancelPlan = await planCancelClaimStakeBuildingChanges(ctx, stake, {
  authorization,
});

console.log(
  cancelPlan.summary,
  cancelPlan.requiredSigners,
  cancelPlan.preconditions,
);
```

The planner rejects active, deactivated, foreign, stale, or mismatched identity
graphs locally. It does not estimate a refund. The program re-synchronizes rent
and performs the design-to-active transition at execution, so rent arithmetic
and concurrent transitions remain chain-authoritative.

## Topping up rent

An owned Claim Stake in `active` or `design` state can receive one exact raw
rent top-up. Pass raw ATLAS units as a positive `bigint`; do not pass a display
ATLAS number:

```ts
import { planTopUpClaimStakeRent } from '@aephia/atlas-kit/claim-stakes/actions';

const topUpPlan = await planTopUpClaimStakeRent(ctx, stake, {
  amount: 500_000_000n,
  authorization,
});

console.log(
  topUpPlan.summary,
  topUpPlan.requiredSigners,
  topUpPlan.preconditions,
);
```

The planner validates the fresh owned stake, its canonical
Character/Planet/System/Starbase Player graph, and the Character's known raw
ATLAS balance. It preserves the exact raw amount in the Plan description and
does not estimate how much rent duration the amount purchases; permissions,
rent arithmetic, and concurrent balance changes remain chain-authoritative.

## Starting a Fleet transfer

An owned idle Fleet can start one transfer to an owned active Claim Stake.
Provide exact raw cargo quantities in dense `load` and `unload` lists. Loading
moves cargo from the Claim Stake to the Fleet; unloading moves it from the Fleet
to the Claim Stake:

```ts
import { planStartClaimStakeFleetTransfer } from '@aephia/atlas-kit/claim-stakes/actions';

const transferPlan = await planStartClaimStakeFleetTransfer(ctx, fleet, stake, {
  authorization,
  load: [{ cargoId: 3, amount: 25n }],
  unload: [{ cargoId: 1, amount: 10n }],
});

console.log(
  transferPlan.summary,
  transferPlan.requiredSigners,
  transferPlan.preconditions,
);
```

The planner verifies the shared owner and Game, the Fleet's positive normalized
crew, the current Fleet/Claim Stake/Planet/System/Starbase Player graph, known
source balances, destination capacities, and an optional present
FleetCrewBinding. Starbase Player remains a readonly instruction account and is
guarded by a whole-account precondition; it is not included in the Plan's
writable `affected` addresses. Cargo ids must be unique across both lists. The
chain remains authoritative for range, transfer duration, permissions, and
concurrent state changes. Normal exit remains a separate permissionless action.

## Recovering a stuck Fleet transfer

After the transfer lock expires, an owner can recover a Fleet only when the
current Fleet and Claim Stake cargo snapshots prove that the queued transfer
cannot execute exactly:

```ts
import { planRecoverClaimStakeFleetTransfer } from '@aephia/atlas-kit/claim-stakes/actions';

const recoveryPlan = await planRecoverClaimStakeFleetTransfer(
  ctx,
  fleet,
  stake,
  {
    atUnixSeconds: 1_700_000_100n,
    authorization,
  },
);

console.log(
  recoveryPlan.summary,
  recoveryPlan.requiredSigners,
  recoveryPlan.preconditions,
);
```

The planner accepts source shortfalls, invalid queued cargo ids, or destination
overflow. It rejects a currently executable transfer and directs the caller to
the permissionless normal exit. Recovery returns the Fleet to idle without
moving cargo or changing the active Claim Stake; it never infers closure or
uses force-exit semantics.

## Deconstructing a claim stake

An owned stake can be deconstructed only while it is `active` and after every
player-funded building has been removed and finalized. The definition-compatible
zero-cost bundled hub remains because deconstruction discards it:

```ts
import { planDeconstructClaimStake } from '@aephia/atlas-kit/claim-stakes/actions';

const deconstructPlan = await planDeconstructClaimStake(ctx, stake, {
  authorization,
});

console.log(
  deconstructPlan.summary,
  deconstructPlan.requiredSigners,
  deconstructPlan.preconditions,
);
```

The planner derives the exact Planet chronology index and current Starbase plot
level from fresh validated Game, Claim Stake, Body, System, Character, and
Starbase Player accounts; callers cannot assert either value. It does not
predict rent settlement, returned cargo, an account-close outcome, or a refund
amount. Those results and any concurrent close race remain chain-authoritative.

## Gotchas

**A stake in `design` is not yet producing.** It exists, it is yours, and it
yields nothing. Filter on state before summing output.

**Capacity and yield come from definitions.** What a stake produces depends on
the body and the Game account's rules, not on fields stored in the stake
account alone.

**A body can hold stakes from several players.** `byBody` returns an array for
that reason.

## Reference

- [`claim-stakes`](/reference/claim-stakes/) — every export in this entry
- [`claim-stakes/actions`](/reference/claim-stakes/actions/) — Claim Stake placement, building-design planning, rent top-up, Fleet-transfer start and recovery, finalization, cancellation, and deconstruction
- [`world`](/guides/world/) — the bodies stakes are placed on
- [Crafting habs](/guides/crafting-habs/) — the sibling deployment system,
  sharing the same lifecycle and rent machinery
