Skip to content

Identity

Almost every read starts by working out who you are asking about. That chain has three links, and one of them is harder than it looks.

Wallet ──▶ Profile ──▶ Character

A wallet is a Solana account someone controls. A profileA player's on-chain identity across Star Atlas. Created by the player, so it cannot be derived from a wallet address. is their on-chain identity across Star Atlas. A characterA profile's presence inside SAGE. Owns fleets and accrues progress; one per profile. is that profile’s presence inside SAGEThe part of Star Atlas where fleets fly, mine, craft, and trade. specifically — the thing that owns fleets and accrues progress.

If you already have a profile address, one call gets you the character:

const character = await sage.characters.forProfile(profileAddress);

That is the normal starting point, and most guides here begin from it.

You cannot calculate a profile address from a wallet address.

Many Solana accounts have a derivable addressAn address derived deterministically from known inputs, so it can be computed rather than searched for. computed from known inputs, so you can work them out offline. Profiles do not: a profile is created by its owner, and its address is assigned at creation. Nothing about the wallet predicts it.

So going wallet → profile is a search, not a calculation, and the SDK makes you choose how to search rather than guessing:

const sage = createSageClient({
cluster: 'zink-ptr',
rpc,
discovery: { walletProfiles },
});
const wallet = sage.wallets.get(walletAddress);
const profiles = await wallet.profiles.all({ strategy: 'provider' });

walletProfiles is a provider you supply — a lookup table you maintain, an indexer, or anything else that can answer “which profiles belong to this wallet”. Without one, the provider strategy has no way to answer and says so.

If you already know the addresses, skip the provider entirely and pass them:

const profiles = await wallet.profiles.all({
strategy: 'known-addresses',
addresses: [profileAddress],
});

The character is the hub. Almost every gameplay read hangs off it:

const fleets = await character.fleets.all();
const stakes = await character.claimStakes.all();
const bases = await character.starbases.all();

Each of those is a separate network read, which is why each is a method rather than a property. See how the SDK thinks for why that distinction is consistent across the whole API.

A profile with no character is possible. Someone can hold a Star Atlas profile without having entered SAGE. forProfile will tell you rather than inventing an empty character.

A wallet can hold more than one profile. wallet.profiles.all() returns an array for that reason. Do not assume the first is the one you want.

Progression is a separate read. XP and pilot level are not on the character snapshot; they are joined against the Game account’s XP definitions and fetched on their own.

  • identity — every export in this entry
  • fleets — the usual next step