# Preparing wallet imports
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.

> Check the Profile, Character, faction, and local Starbase prerequisites before bringing wallet assets into SAGE C4.

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

Bringing a wallet asset into the game needs an in-game destination. A wallet
balance and a Profile address alone do not establish that destination. Read the
existing accounts first, create only the missing prerequisites, then load fresh
snapshots before planning an import.

This guide describes the path checked through unsigned z.ink PTR simulations.
Explicit Profile creation, Character registration, initial faction enrollment,
and wallet cargo and ship imports each have separate planners. Simulation
coverage does not establish a live creation or import result.

## The accounts you need

| Account         | What it establishes                                                            | How to check today                                                                                                                 |
| --------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| Profile         | Your cross-game identity and authorized keys                                   | `getProfile` from `identity`; it is signer-created, never derived from the wallet.                                                 |
| Character       | That Profile's presence in this particular Game                                | `maybeGetCharacterForProfile` from `identity` derives and validates the canonical Character.                                       |
| Profile Faction | That Profile's faction enrollment                                              | `maybeGetFactionForProfile` from `factions` derives and validates it; only absence returns `undefined`.                            |
| Starbase Player | That Character's player-local storage at a particular System's nested Starbase | `getStarbasePlayerForCharacterAtSystem` from `starbases` derives and validates it; a missing account produces `ACCOUNT_NOT_FOUND`. |

These are separate accounts, with different scopes. Profile Faction belongs to
the Profile. Character belongs to a Profile **and Game**. Starbase Player belongs
to a Character **and System**. Reuse valid existing accounts; an account for a
different Game, Profile, Character, or System is not a substitute.

The example below reads an **existing** Profile/Character chain. It does not
register accounts or prove import readiness.

> **Runnable example — Walk the identity chain.** From a profile to its character, then to everything that character owns. Run it in the browser at https://develop.atlas-kit-docs.pages.dev/guides/import-onboarding/.

## From an existing Profile to a local Starbase

1. Read the Profile and its canonical Character. The normal
   `sage.characters.forProfile(profileAddress)` call reads an existing Character;
   it does not create one. Use `maybeGetCharacterForProfile` when absence is an
   expected onboarding state.
2. If Character registration is needed, its generated instruction takes a
   separate account-storage funder. It does not take a Profile authorization
   signer or a faction account. Use `planRegisterCharacter` from
   `@aephia/atlas-kit/identity/actions`; read and reuse an existing Character
   instead of trying to register it again. New registration Plans tolerate
   unrelated Game definition updates. Execution still requires a valid C4 Game,
   unchanged Profile state, and an absent canonical Character.
3. Read enrollment with `maybeGetFactionForProfile`. If absent, use
   `planChooseFaction(ctx, { faction, authorization })` from `factions/actions`.
   Select `mud`, `oni`, or `ustur` explicitly. The Profile authority signs;
   there is no separate funder. The Profile's own on-chain balance must fund
   creation while preserving its current rent reserve. The planner validates
   observed funding against current Rent data but never tops up the Profile.
   Existing enrollment, including `unaligned`, is rejected; this is not a
   faction-switching API. See [faction enrollment](/guides/factions/#first-enrollment).
4. Choose a System in the configured Game with a nested Starbase and suitable
   current access. For wallet imports, select a permitted CSS. Use the existing `planRegisterStarbasePlayer` with loaded
   Character and System snapshots and an explicit funder if the local account is
   missing. The planner freshly validates faction and Starbase relationships;
   it rejects an already registered player, so reuse that account instead.
   In the capture, a MUD-enrolled Profile could not register at Eternity's Ustur
   Starbase. Do not assume every nested Starbase accepts every faction.
5. Simulate a Plan, obtain the explicitly required signatures, execute once,
   and read the resulting account after confirmed success. Load fresh inputs
   before the next planner. Do not build later steps against accounts that only
   exist in an unexecuted Plan.

Character registration and faction enrollment are distinct prerequisites for
this supported Starbase-registration path; Character creation itself does not
require prior faction enrollment. If a Profile is missing, create and confirm it first using the separate planner
below. Character registration and initial faction enrollment then use the
focused planners described here and in the [faction guide](/guides/factions/#first-enrollment).

## Plan Profile creation

Use `planCreateProfile(ctx, profileAddress, options)` from
`@aephia/atlas-kit/identity/actions`. The target must be a fresh on-curve address
for a new external signer, remain absent, and differ from the funder. The
planner reads the target to check absence without loading Game definitions.
Choose initial keys and `keyThreshold` explicitly; the SDK adds no default
permissions or authority.

This illustrative example grants one key only Profile AUTH. Supply the declared
addresses and context from your application. Use `PROFILE_PERMISSION_SCOPE` and the named `authenticate` permission
from the SDK identity entry; AUTH has that meaning only in this scope. This key alone does not establish permissions for SAGE gameplay actions.

```ts
import { planCreateProfile } from '@aephia/atlas-kit/identity/actions';
import {
  composeProfilePermissions,
  PROFILE_PERMISSION_SCOPE,
} from '@aephia/atlas-kit/identity';
import type { Address, SageContext } from '@aephia/atlas-kit/client';

declare const ctx: SageContext;
declare const profileAddress: Address;
declare const funder: Address;
declare const authority: Address;

const plan = await planCreateProfile(ctx, profileAddress, {
  funder,
  keys: [
    {
      address: authority,
      scope: PROFILE_PERMISSION_SCOPE,
      permissionsRaw: composeProfilePermissions(PROFILE_PERMISSION_SCOPE, [
        'authenticate',
      ]),
    },
  ],
  keyThreshold: 1,
});
console.log(plan.describe());
```

Each initial key specifies an address, program `scope`, and exact unsigned
64-bit `permissionsRaw` bigint. Omitted `expiresAt` means `-1n`, nonexpiring.
Every key with AUTH bit 0 in the pinned Profile program scope must be
nonexpiring and must sign creation. Other scoped keys are readonly instruction
accounts and do not become signers merely by appearing in the key list.
Use [permission and key inspection](/guides/identity/#inspecting-permissions-and-keys)
to explain masks and inspect direct keys on a loaded Profile. These helpers
neither choose authority nor change the creation signer requirements. Separate
SAGE-scoped entries can use `SAGE_PERMISSION_SCOPE` and known names such as
`moveFleet` or `doMining`; see [SAGE permission inspection](/guides/identity/#inspecting-sage-gameplay-permission-names).
A recognized gameplay mask is not proof of an action's full authorization
requirements. SAGE `manageGame` at bit zero is not Profile AUTH and cannot
replace an initial Profile authority key.
Duplicate address-and-scope pairs are rejected because they could inflate the
AUTH count; the same address in distinct scopes is supported.

`keyThreshold` is an integer from 1 through the number of initial Profile AUTH
keys, at most 255. It governs protected Profile updates; individual gameplay
instructions have their own permission rules. All initial AUTH keys sign
creation even if the threshold is lower. The funder and new Profile also sign.
An AUTH key may share the funder or new Profile address; shared roles use the
same external signer. The Plan retains addresses, never signing keys.

The new Profile signer authorizes account creation. After creation, authority
comes from the stored Profile key entries; the Profile address is not
automatically AUTH. If that address is also an AUTH key, the same signer
continues to serve that authority role. Do not discard it just because the
creation transaction has completed.

Keep initial key lists small. The v0 transactions assembled by Atlas Kit can occupy at most
1,232 wire bytes. The number of keys that fits depends on unique addresses,
AUTH signers, the fee payer, and other instructions, so the threshold's upper
bound is not a usable-key-count guarantee. Assemble and simulate the exact Plan
before signing. There is no automatic chunking or curated later-key-addition
planner in the shipped surface.

Inspect the Plan and [simulate before execution](/guides/moving-a-fleet/#sign-and-execute-once).
The funder pays for Profile account rent; transaction fees are separate and
actual funding requirements remain chain-authoritative. Creation does not top
up the Profile's excess balance. In particular, later faction enrollment may
need additional Profile funding. This planner does not register a Character,
choose a faction, or complete onboarding.

If another transaction occupies the target after planning, the absence guard
fails before signing: refresh and inspect that account before continuing.
After confirmed success, call
`getProfile(ctx, profileAddress, { refresh: true })` and verify the initial key
addresses, scopes, permissions, expiry, and threshold before planning the next
step. Unsigned simulation alone does not prove creation. Cases outside this
curated scope require the explicit raw bindings escape hatch and their own
reviewed validation.

## Plan Character registration

**Current Game-2 limitation:** this planner still omits the registration XP
accounts. [#616](https://github.com/Aephia/atlas-kit/issues/616) tracks the fix
and verification of account creation and funding. The example describes the
API; it is not a qualified current-game registration route.

Supply the existing Profile address and an explicit funder. The planner derives
and checks the canonical Character, freshly validates the Profile and Game, and
produces an inspectable Plan. It does not choose a faction, fund the Profile, or
submit a transaction. Registration fails if the Character already exists.

```ts
import { planRegisterCharacter } from '@aephia/atlas-kit/identity/actions';
import { maybeGetCharacterForProfile } from '@aephia/atlas-kit/identity';
import type { Address, SageContext } from '@aephia/atlas-kit/client';

declare const ctx: SageContext;
declare const profileAddress: Address;
declare const funder: Address;

const character = await maybeGetCharacterForProfile(ctx, profileAddress, {
  refresh: true,
});
if (character === undefined) {
  const plan = await planRegisterCharacter(ctx, profileAddress, { funder });
  console.log(plan.describe());
}
```

Use the existing [simulation and execution flow](/guides/moving-a-fleet/#sign-and-execute-once)
with external signers when the caller wants to proceed. The funder pays for
Character storage; transaction fees are a separate assembly/execution concern.
Balances and account-creation costs remain chain-authoritative. If someone
registers the Character after planning, the Plan's strict absence guard fails
before signing: refresh and reuse the existing account. After confirmed success,
read with `getCharacterForProfile(ctx, profileAddress, { refresh: true })` and
verify its Profile and Game identity before continuing.

A Character records a Profile’s presence in a Game. Its existence alone does
not establish that the Profile owner participated in registration or consented
to another action. The sole-funder registration evidence applies to the pinned
bindings and captured PTR deployment.

## Cargo readiness

[Wallet cargo deposit](/guides/cargo/#depositing-wallet-cargo-into-the-game)
uses an existing Starbase Player at a Central Space Station (CSS). In the
captured PTR deployment, registration at a non-CSS Starbase succeeded but
Ammunition deposit there failed with `NOT_AT_CENTRAL_SPACE_STATION`. Registration
alone therefore does not prove import readiness. Confirm the selected System's
nested Starbase is a CSS using `system.starbase?.maxLevel.kind === 'css'` on a
loaded System snapshot. The cargo deposit planner checks this before returning
a Plan. Simulate the actual import as well; current ownership and access checks
remain chain-authoritative.

The selected
cargo must be importable under the current Game definition. The source token
account must have the expected mint, token program, token owner, and sufficient
raw balance. Profile authority and token-owner authority are separate roles.

Cargo backing is held in a Game-level cache vault; the player's entitlement is
recorded in the Starbase Player inventory. A vault balance alone does not prove
that your player received cargo. After confirmed execution, check both the
wallet token debit and the matching player inventory credit using fresh reads.

## Ship readiness

Ship import also requires a CSS in the tested deployment: registration at the
neighboring non-CSS Starbase succeeded, but ship import then failed with
`NOT_AT_CENTRAL_SPACE_STATION`.

Use [the ship import planner](/guides/fleets/#importing-wallet-ships),
`planDepositShipsToGame` from `fleets/actions`. It moves wallet ship tokens into
Character-owned escrow and records the ship entitlement in Starbase Player's
`shipsInEscrow`. Importing ships does not create a Fleet or add those ships to a
Fleet.

Do not infer that Starbase registration is unnecessary from the binding's
optional `starbasePlayer` input. The asynchronous builder fills an omitted
input with a derived Starbase Player address. Supplying no input to that builder
is therefore different from leaving the instruction account absent. In the
captured PTR simulations, an absent account and the program-address placeholder
both failed. The supported path therefore requires an existing, correctly
registered Starbase Player for ships as well as cargo.

Select an explicit configuration ID whose mint matches the source tokens. The
ship planner validates the source, Character-owned escrow, CSS relationships,
Profile authority and separate token-owner role. Missing escrow ATA creation
requires explicit payer consent. A new configuration entry uses the Profile’s
excess balance for Starbase storage; increasing an existing entry does not grow
storage. Verify wallet, token-escrow and player-entitlement deltas after
confirmation. Cargo’s shared vault rules do not apply to ships.

## What counts as ready

Readiness is an observation of current accounts, not a remembered “onboarding
complete” flag. Use refresh reads when resuming or following a confirmed write.

- Profile must contain the intended scoped keys, permissions, expiry, and threshold.
- Character must point to the expected Profile and configured Game.
- Profile Faction must point to the expected Profile and selected faction.
- Starbase Player must point to the expected Profile, Character, and chosen System.
- The import source and destination must satisfy the selected asset's rules.

Treat only `ACCOUNT_NOT_FOUND` as absence. An invalid owner, malformed account,
wrong relationship, transport failure, or permission rejection needs its own
remedy; it is not a reason to try creating another account.

The SDK does not silently enroll a faction, fund a Profile, choose an entry
System, or submit transactions during a read. Existing registration and import
Plans remain inspectable before signing. A submitted signature or a successful
unsigned simulation is not proof of a committed result.

## Evidence and limits

The [onboarding capture](https://github.com/Aephia/atlas-kit/blob/develop/docs/evidence/import-onboarding-ptr.md),
[Profile creation capture](https://github.com/Aephia/atlas-kit/blob/develop/docs/evidence/profile-creation-444.md),
and [ship capture](https://github.com/Aephia/atlas-kit/blob/develop/docs/evidence/import-ships-onboarding-ptr.md)
record the pinned bindings, deployed program fingerprints, simulation slots,
rejected prerequisites and returned account state. They use unsigned PTR
simulation with no live account creation or asset movement. They do not establish
mainnet behavior or all faction access, permission and certificate variants.
