Skip to content

Fleet Creation Workflow ​

Creating a fleet turns ships and starbase context into a new active SAGE C4 fleet account. It is one of the first workflows where Player Profile, Profile Faction, Character, StarbasePlayer, and SAGE world state all meet.

Use this as the canonical review pattern for new-account workflows: read context, build instructions, summarize the account set, simulate a full transaction, then show diff targets before asking for a signature.

Do not present fleet creation as only “ship plus name.” Crew is a real SAGE access and utility layer, so fleet setup screens should make crew availability and assignment visible when it affects the intended follow-up action.

Scaffold, not a copy-paste transaction

The snippets below show the verified account and review shape. Variables such as walletSigner, profileAddress, and gameAddress must come from your application's wallet, discovery, and transaction-building flow. The page does not assemble or send a complete transaction.

What Create Fleet Touches ​

createFleet uses the main SAGE program client:

ts
import { getCreateFleetInstructionAsync } from '@staratlas/dev-sage';

The instruction data is small:

FieldMeaning
fleetLabelFixed-size generated Name value shown on the fleet.
keyIndexPlayer Profile key index authorizing the action.

The account set is more important than the instruction data.

AccountRole in the workflow
profileValidationSignerWallet/profile signer authorizing the action.
profileValidationProfilePlayer Profile account being validated.
profileFactionFaction account for the profile.
characterSAGE Character for this profile and game.
gameRoot SAGE game account.
fleetNew Fleet account address.
systemAndStarbasePlayerSystemStar system where the fleet is created.
systemAndStarbasePlayerStarbasePlayerPlayer state at that starbase.
systemProgramSolana System Program for account creation.

1. Read the state ​

Before building the instruction, read:

  • Player Profile, to show the active keyIndex.
  • Profile Faction, to show faction context.
  • Character, to confirm the SAGE player state exists.
  • StarSystem, to confirm the starbase context.
  • StarbasePlayer, to show available local player state.
  • Any ship/cargo state your UI uses to explain what will become part of the fleet.
ts
import {
	fetchMaybeCharacterFromSeeds,
	fetchMaybeStarSystem,
	fetchMaybeStarbasePlayerFromSeeds
} from '@staratlas/dev-sage';

const [character, starSystem, starbasePlayer] = await Promise.all([
	fetchMaybeCharacterFromSeeds(
		rpc,
		{ playerProfile: profileAddress, gameId: gameAddress },
		{ commitment: 'confirmed' }
	),
	fetchMaybeStarSystem(rpc, systemAddress, {
		commitment: 'confirmed'
	}),
	fetchMaybeStarbasePlayerFromSeeds(
		rpc,
		{ system: systemAddress, character: characterAddress },
		{ commitment: 'confirmed' }
	)
]);

if (!character.exists) throw new Error('SAGE character not found');
if (!starSystem.exists) throw new Error('Star system not found');
if (!starbasePlayer.exists) throw new Error('Starbase player not found');

console.log({
	character: character.address,
	system: starSystem.data.name,
	starbasePresent: starSystem.data.starbase.__option === 'Some',
	starbasePlayer: starbasePlayer.address
});

2. Build the instruction ​

ts
import { address } from '@solana/kit';
import { getCreateFleetInstructionAsync } from '@staratlas/dev-sage';

const instruction = await getCreateFleetInstructionAsync({
	profileValidationSigner: walletSigner,
	profileValidationProfile: profileAddress,
	profileFaction: profileFactionAddress,
	character: characterAddress,
	game: gameAddress,
	fleet: address('NEW_FLEET_ADDRESS_HERE'),
	systemAndStarbasePlayerSystem: systemAddress,
	systemAndStarbasePlayerStarbasePlayer: starbasePlayerAddress,
	fleetLabel: 'Aephia Test Fleet',
	keyIndex: 0
});

getCreateFleetInstructionAsync can derive the Character PDA when it has the profile and game, but passing the address explicitly makes review screens easier to compare with preflight reads.

3. Review before signing ​

Show these items before a wallet signs:

  • Fleet label.
  • New fleet account address.
  • Player Profile and keyIndex.
  • Profile Faction value.
  • Star system and starbase player address.
  • Writable accounts: Player Profile, Character, Fleet, StarbasePlayer.
  • Any ships, crew, cargo, fuel, ammo, or components the UI expects to assign.

4. Simulate the full transaction ​

Simulation must run against the complete transaction, especially when the UI bundles createFleet with ship or crew assignment instructions.

ts
const simulation = await rpc
	.simulateTransaction(encodedTransactionBase64, {
		commitment: 'confirmed',
		encoding: 'base64',
		replaceRecentBlockhash: true,
		sigVerify: false
	})
	.send();

console.log({
	err: simulation.value.err,
	unitsConsumed: simulation.value.unitsConsumed,
	logs: simulation.value.logs
});

Live PTR shape ​

A recent PTR fleet-creation transaction bundled createFleet with follow-up addShipToFleet instructions in the same transaction. That is the shape real tooling should expect: creating the empty fleet account is often only the first step.

Decoded createFleet data:

ts
{
	fleetLabel: 'Frozen Lynx',
	keyIndex: 0
}

One decoded addShipToFleet payload from the same transaction:

ts
{
	ships: [{ id: 3101, amount: 4 }],
	shipEscrowIndex: 3,
	fleetShipInfoIndex: { __option: 'None' },
	keyIndex: 0
}

The transaction wrote the profile signer, profile, character, new fleet, and starbase-player accounts. It also read Profile Faction, Game, StarSystem, and System Program context. Total compute for the sampled transaction was about 67,000 units.

5. Diff targets ​

For simulation, use this account list to explain expected effects. When testing a real PTR transaction, compare before and after snapshots for:

AccountExpected change
FleetNew account should exist and decode as Fleet.
CharacterCounters or fleet references may change.
StarbasePlayerLocal starbase player state may change.
Player ProfileProfile validation may touch writable profile state.

Use Transaction Review and Account Diffs for the generic summary and snapshot helpers.