Skip to content

Scanning Workflow

Scanning is an exploration action. A fleet uses a scan pattern against the current game state, pays the configured scan costs, and may produce loot or state changes tied to fleet position and cooldowns.

Use this as the canonical review pattern for chance/result workflows: read fleet and scan-pattern context, build the instruction, summarize costs and writable accounts, simulate the full transaction, then show cooldown and loot diff targets before asking for a signature.

The KB frames scan output as part of the active economy, not just loot UX. SDUs and discovered resources can feed Infrastructure Contract recipes and other ATLAS-earning loops, so scan review should show why a result matters beyond the immediate transaction.

What Scan Touches

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

Instruction data:

FieldMeaning
keyIndexPlayer Profile key index authorizing the action.

Core accounts:

AccountRole in the workflow
profileValidationSignerWallet/profile signer.
profileValidationProfilePlayer Profile account.
characterSAGE Character for this profile/game.
fleetFleet performing the scan.
scanPatternScan configuration, costs, cooldown, and loot table.
gameRoot SAGE game account.
instructionsSysvarInstructions sysvar, defaulted by the generated client when omitted.
recentSlothashesRecent slot hashes sysvar used by the scan flow.
crewBindingOptional per-fleet crew binding touched by crew-aware scans.
regionTrackerOptional region context used when arming encounter state.
encounterCommitOptional writable encounter commit stamped when a scan arms an encounter.
encounterPoolOptional encounter pool context pinned into the commit.

1. Read the state

Read the fleet and scan pattern first:

ts
import {
	ScanPatternStatus,
	fetchMaybeFleet,
	fetchMaybeScanPattern
} from '@staratlas/dev-sage';

const [fleet, scanPattern] = await Promise.all([
	fetchMaybeFleet(rpc, fleetAddress, { commitment: 'confirmed' }),
	fetchMaybeScanPattern(rpc, scanPatternAddress, {
		commitment: 'confirmed'
	})
]);

if (!fleet.exists) throw new Error('Fleet not found');
if (!scanPattern.exists) throw new Error('Scan pattern not found');
if (ScanPatternStatus[scanPattern.data.status] !== 'Active') {
	throw new Error(
		`Scan pattern is not active: ${ScanPatternStatus[scanPattern.data.status]}`
	);
}

console.log({
	fleetLabel: fleet.data.fleetLabel,
	fleetState: fleet.data.state.__kind,
	pattern: scanPattern.data.name,
	costs: scanPattern.data.cost.length,
	lootEntries: scanPattern.data.lootTable.length
});

The UI should also show the fleet position, scan cooldown, cargo requirements, and any risk implied by the current fleet state.

2. Build the instruction

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

const RECENT_SLOTHASHES_SYSVAR = address(
	'SysvarS1otHashes111111111111111111111111111'
);

const instruction = getScanInstruction({
	profileValidationSigner: walletSigner,
	profileValidationProfile: profileAddress,
	character: characterAddress,
	fleet: fleetAddress,
	scanPattern: scanPatternAddress,
	game: gameAddress,
	recentSlothashes: RECENT_SLOTHASHES_SYSVAR,
	crewBinding: crewBindingAddress,
	regionTracker: regionTrackerAddress,
	encounterCommit: encounterCommitAddress,
	encounterPool: encounterPoolAddress,
	keyIndex: 0
});

Leave the optional encounter accounts out for a plain scan. When a scan is also arming encounter state, provide regionTracker, encounterCommit, and encounterPool together so the review screen can show the encounter side effects.

3. Review before signing

Show these items before a wallet signs:

  • Fleet label, state, and current location.
  • Scan pattern name, costs, cooldown, and possible loot entries.
  • Player Profile and keyIndex.
  • Writable accounts: Player Profile, Character, Fleet, optional Crew Binding, and optional Encounter Commit.
  • Expected cargo/resource costs.
  • Expected cooldown or state change.
  • Whether loot, encounter, or reward state is expected to appear or update.

4. Simulate the full transaction

Simulation should catch stale fleet state, inactive scan patterns, insufficient scan costs, and sysvar/account-shape mistakes before the wallet prompt.

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
});

5. Diff targets

AccountExpected change
FleetScan cooldown, state, or cargo/resource state may change.
CharacterProgression or counters may change.
LootNew or updated loot account may appear depending on result.
ScanPatternUsually config context; should not change during a normal player scan.

Use Transaction Review and Account Diffs for the generic simulation and diff pattern.