Category: actions
This page is field notes for a subset of messages. There is no MsgStructBuild RPC. The live list is messages.md. CLI names: generated/commands.md.
| Category | Actions |
|---|---|
| construction | MsgStructBuildInitiate, MsgStructBuildComplete |
| combat | MsgStructAttack, MsgPlanetRaidComplete |
| resource | MsgReactorInfuse, MsgReactorDefuse, MsgReactorBeginMigration, MsgReactorCancelDefusion, MsgReactorRestart, MsgAllocationCreate, MsgAllocationUpdate, MsgAllocationDelete, MsgAllocationTransfer, MsgSubstationAllocationConnect, MsgSubstationCreate, MsgSubstationPlayerConnect, MsgStructOreMinerComplete, MsgStructOreRefineryComplete |
| economic | MsgProviderCreate, MsgAgreementOpen, MsgStructGeneratorInfuse, MsgPlayerSend, MsgVaultSend |
| exploration | MsgPlanetExplore |
| fleet | MsgFleetMove |
| guild | MsgGuildCreate, MsgGuildUpdateRankPurchase, MsgGuildRankPurchase, MsgGuildMembershipJoinByRankPurchase, MsgGuildMembershipJoin, MsgGuildMembershipKick, MsgGuildMembershipJoinProxy, MsgGuildBankMint, MsgGuildBankRedeem, MsgGuildBankConvert, MsgGuildBankConvertToken |
| ugc | MsgPlayerUpdateName, MsgPlayerUpdatePfp, MsgPlayerUpdatePfpClientRenderAttributes, MsgGuildUpdateName, MsgGuildUpdatePfp, MsgPlanetUpdateName, MsgSubstationUpdateName, MsgSubstationUpdatePfp |
| struct-management | MsgStructActivate, MsgStructDeactivate, MsgStructDeactivateBatch, MsgStructTrash, MsgStructStealthActivate, MsgStructStealthDeactivate, MsgStructDefenseSet, MsgStructDefenseClear, MsgStructMove |
| Requirement | Description |
|---|---|
| playerOnline | player must be online (capacity covers load) |
| sufficientResources | Player must have sufficient resources |
| sufficientCharge | Acting player must have sufficient charge (charge is a single per-player bar, not per-struct) |
| proofOfWork | Action requires proof-of-work computation |
| validLocation | Location must be valid and accessible |
| validTarget | Target must be valid and attackable |
POST /cosmos/tx/v1beta1/txsIMPORTANT: Transaction status ‘broadcast’ does NOT mean action succeeded! Validation happens on-chain after broadcast. Always verify game state to confirm action occurred.
Common Validation Failures:
See patterns/validation-patterns.md for detailed validation patterns.
struct-build-initiate/structs.structs.MsgStructBuildInitiatePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_build_initiate.go:18-88proto/structs/structs/tx.proto:660-669Required Fields: creator, playerId, structTypeId, operatingAmbit, slot
Follow-Up Action: MsgStructBuildComplete
| Requirement | Details |
|---|---|
| playerOnline | true |
| sufficientResources | true |
| validLocation | true |
| sufficientPower | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructBuildInitiate",
"creator": "structs1...",
"playerId": "1-1",
"structTypeId": "1",
"operatingAmbit": 1,
"slot": 1
}
]
}
}
struct-build-complete/structs.structs.MsgStructBuildCompletePOST /cosmos/tx/v1beta1/txsRequired Fields: creator, structId, hash, nonce
| Requirement | Details |
|---|---|
| playerOnline | true |
| structInBuildingState | true |
| proofOfWork | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructBuildComplete",
"creator": "structs1...",
"structId": "1-1",
"hash": "proof-of-work-hash",
"nonce": "proof-of-work-nonce"
}
]
}
}
struct-attack/structs.structs.MsgStructAttackPOST /cosmos/tx/v1beta1/txsRequired Fields: creator, structId, targetId
| Requirement | Details |
|---|---|
| structOnline | true (the attacking struct, and its owner, must be online — the attacker’s Command Ship does not need to be online) |
| sufficientCharge | true |
| validTarget | true (the target must be a built struct; an unbuilt struct is rejected with unbuilt and a destroyed struct with destroyed. The target’s online status is irrelevant) |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructAttack",
"creator": "structs1...",
"structId": "1-1",
"targetId": "2-1"
}
]
}
}
planet-raid-complete/structs.structs.MsgPlanetRaidCompletePOST /cosmos/tx/v1beta1/txsRequired Fields: creator, fleetId, planetId, hash, nonce
| Requirement | Details |
|---|---|
| playerOnline | true (the raider’s player must be online) |
| fleetAway | true |
| fleetFirstInLine | true |
| defenderShieldsVulnerable | true (defender’s fleet off-station, or their Command Ship offline/destroyed/non-existent; otherwise rejected with shields_active) |
| raidClockStarted | true (blockStartRaid != 0; otherwise raid_clock_unset) |
| proofOfWork | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgPlanetRaidComplete",
"creator": "structs1...",
"fleetId": "1-1",
"planetId": "2-1",
"hash": "proof-of-work-hash",
"nonce": "proof-of-work-nonce"
}
]
}
}
reactor-infuse/structs.structs.MsgReactorInfusePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_reactor_infuse.goproto/structs/structs/tx.proto (MsgReactorInfuse)Required Fields: creator, validator_address, amount (Coin, ualpha)
Optional Fields: ownerId (player 1-N or guild 0-N whose vault funds the stake; empty = the signing player’s vault), delegator_address (alone: a registered player address or vault to stake from its own balance, needing PermTokenInfuse on its owner; together with ownerId: must equal that owner’s vault, else vault_owner_mismatch)
| Requirement | Details |
|---|---|
| playerOnline | true |
| registered address | Signer must already be a player (ante 2010 otherwise — a fresh key bootstraps with structsd tx staking delegate, not this message) |
| permission | PermTokenInfuse (32) on the funding owner; a guild vault additionally needs the signer to hold it on the guild |
| sufficient vault balance | amount is debited from the owner’s vault, not from creator’s key |
| stake cap | Refused (1613) when the reactor already holds ≥ reactorStakeCapBps of bonded stake and ≥ reactorStakeCapMinValidators are bonded. Check reactor-stake-share headroom first |
Conversion Rate: 1 µAlpha staked → 1 unit of power before commission (ReactorFuelToEnergyConversion = 1). See energy.md.
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgReactorInfuse",
"creator": "structs1...",
"validator_address": "structsvaloper1...",
"amount": { "denom": "ualpha", "amount": "1000000" },
"ownerId": ""
}
]
}
}
reactor-defuse/structs.structs.MsgReactorDefusePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_reactor_defuse.goRequired Fields: creator, validator_address, amount (Coin)
Optional Fields: ownerId, delegator_address (same semantics as MsgReactorInfuse)
| Requirement | Details |
|---|---|
| playerOnline | true |
| permission | PermTokenDefuse (128) on the funding owner |
| sufficient stake | amount ≤ the owner’s delegation to that validator |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgReactorDefuse",
"creator": "structs1...",
"validator_address": "structsvaloper1...",
"amount": { "denom": "ualpha", "amount": "1000000" }
}
]
}
}
reactor-begin-migration/structs.structs.MsgReactorBeginMigrationPOST /cosmos/tx/v1beta1/txsbondedRedelegationHeadroom).Required Fields: creator, validator_src_address, validator_dst_address, amount (Coin)
Optional Fields: ownerId, delegator_address
| Requirement | Details |
|---|---|
| playerOnline | true |
| permission | PermTokenMigrate (64) on the funding owner |
| hasActiveDelegation | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgReactorBeginMigration",
"creator": "structs1...",
"validator_src_address": "structsvaloper1aaa...",
"validator_dst_address": "structsvaloper1bbb...",
"amount": { "denom": "ualpha", "amount": "1000000" }
}
]
}
}
reactor-cancel-defusion/structs.structs.MsgReactorCancelDefusionPOST /cosmos/tx/v1beta1/txsRequired Fields: creator, validator_address, amount (Coin), creation_height (the height the unbonding began)
Optional Fields: ownerId, delegator_address
| Requirement | Details |
|---|---|
| playerOnline | true |
| inUndelegationPeriod | true |
| amount | ≤ the unbonding entry balance |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgReactorCancelDefusion",
"creator": "structs1...",
"validator_address": "structsvaloper1...",
"amount": { "denom": "ualpha", "amount": "1000000" },
"creation_height": "123456"
}
]
}
}
substation-allocation-connect/structs.structs.MsgSubstationAllocationConnectPOST /cosmos/tx/v1beta1/txsRequired Fields: creator, allocationId, destinationId
| Requirement | Details |
|---|---|
| playerOnline | true |
| validAllocation | true |
| validDestination | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgSubstationAllocationConnect",
"creator": "structs1...",
"allocationId": "6-1",
"destinationId": "4-1"
}
]
}
}
substation-create/structs.structs.MsgSubstationCreatePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_substation_create.goproto/structs/structs/tx.proto:131Required Fields: creator, planetId
| Requirement | Details |
|---|---|
| playerOnline | true |
| planetOwned | true |
| validLocation | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgSubstationCreate",
"creator": "structs1...",
"planetId": "2-1"
}
]
}
}
substation-player-connect/structs.structs.MsgSubstationPlayerConnectPOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_substation_player_connect.goproto/structs/structs/tx.proto:135Required Fields: creator, substationId
Effects: Player gains capacitySecondary from the substation’s connectionCapacity.
| Requirement | Details |
|---|---|
| playerOnline | true |
| substationExists | true |
| validConnection | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgSubstationPlayerConnect",
"creator": "structs1...",
"substationId": "1-1"
}
]
}
}
struct-ore-mine-complete/structs.structs.MsgStructOreMinerCompletePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_ore_miner_complete.goproto/structs/structs/tx.proto:763-770Required Fields: creator, structId, proof, nonce
| Requirement | Details |
|---|---|
| playerOnline | true |
| structOnline | true |
| planetHasOre | true |
| planetNotUnderRaid | locationListStart must be empty — otherwise under_raid |
| sufficientCharge | Charge >= structType.OreMiningCharge |
| proofOfWork | HashBuildAndCheckDifficulty with OreMiningDifficulty (14000); {blockStart} is the planet mine clock |
Effects: StoredOreIncrement(1) – fixed 1 ore per operation. Also resets the planet planetBlockStartOreMine to the current block — every extractor on the planet re-enters the full difficulty decay.
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructOreMinerComplete",
"creator": "structs1...",
"structId": "1-1",
"proof": "proof-of-work-hash",
"nonce": "proof-of-work-nonce"
}
]
}
}
struct-ore-refine-complete/structs.structs.MsgStructOreRefineryCompletePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_ore_refinery_complete.goproto/structs/structs/tx.proto:777-784Required Fields: creator, structId, proof, nonce
| Requirement | Details |
|---|---|
| playerOnline | true |
| structOnline | true |
| hasStoredOre | true |
| planetNotUnderRaid | locationListStart must be empty — otherwise under_raid |
| sufficientCharge | Charge >= structType.OreRefiningCharge |
| proofOfWork | HashBuildAndCheckDifficulty with OreRefiningDifficulty (28000); {blockStart} is the planet refine clock |
Effects:
DepositRefinedAlpha() – mints 1,000,000 ualpha (1 gram)StoredOreDecrement(1)planetBlockStartOreRefine to the current block — every refinery on the planet re-enters the full decay. hasStoredOre is only checked here at completion, so a refinery can be activated with 0 ore and complete once ore arrives mid-cycle.{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructOreRefineryComplete",
"creator": "structs1...",
"structId": "1-1",
"proof": "proof-of-work-hash",
"nonce": "proof-of-work-nonce"
}
]
}
}
provider-create/structs.structs.MsgProviderCreatePOST /cosmos/tx/v1beta1/txsownerId — a guild (0-N) that will own the provider; the signer then needs PermSourceAllocation on that guild. Empty = the signing playerRequired Fields: creator, rate, policy
| Requirement | Details |
|---|---|
| playerOnline | true |
| validRate | true |
| validPolicy | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgProviderCreate",
"creator": "structs1...",
"rate": {},
"policy": {}
}
]
}
}
agreement-open/structs.structs.MsgAgreementOpenPOST /cosmos/tx/v1beta1/txscapacity Watts for duration blocks. The full capacity × rate × duration collateral is debited from the consumer’s vault at open. Refused with expiration_height_full if 256 agreements already expire at the resulting end heightownerId — the player or guild consumer whose vault pays (PermTokenTransfer on that owner); empty = the signing playerRequired Fields: creator, providerId, duration, capacity
| Requirement | Details |
|---|---|
| playerOnline | true |
| validProvider | true |
| providerHasCapacity | true |
| sufficientFunds | Buyer holds rate × capacity × duration in the provider’s rate_denom |
Escrow effect (x/structs/keeper/msg_server_agreement_open.go): the full cost rate × capacity × duration is debited in full at open (not metered per block) and moved to the provider’s collateral pool; it then drips to the provider’s earnings as blocks pass. The charge is denominated in the provider’s rate_denom, not alpha — if the provider prices in a guild token, a buyer holding only ualpha is rejected at broadcast with an insufficient-funds error keyed agreement_open (surface rawLog for the missing denom). Acquire the correct denom before opening.
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgAgreementOpen",
"creator": "structs1...",
"providerId": "10-1",
"duration": "100000",
"capacity": "50000"
}
]
}
}
struct-generator-infuse/structs.structs.MsgStructGeneratorInfusePOST /cosmos/tx/v1beta1/txsRequired Fields: creator, structId, infuseAmount
| Requirement | Details |
|---|---|
| playerOnline | true |
| generatorOnline | true |
| sufficientAlphaMatter | true |
Generator Types:
| Generator | Rate | Formula |
|---|---|---|
| Field Generator | 2 | Energy (kW) = Alpha Matter (grams) x 2 |
| Continental Power Plant | 5 | Energy (kW) = Alpha Matter (grams) x 5 |
| World Engine | 10 | Energy (kW) = Alpha Matter (grams) x 10 |
Energy Properties: Energy is ephemeral – must be consumed immediately upon production, cannot be stored. Energy is shared across all Structs connected to the same power source.
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructGeneratorInfuse",
"creator": "structs1...",
"structId": "20-1",
"infuseAmount": "100000000ualpha"
}
]
}
}
Note: infuseAmount is a coin string in micrograms (100 grams = 100,000,000 micrograms). The ualpha denom is required — the handler parses the field with ParseCoinsNormalized and rejects a bare number.
planet-explore/structs.structs.MsgPlanetExplorePOST /cosmos/tx/v1beta1/txsname sets the planet display name at creation.Required Fields: creator, playerId
Optional Fields: name — planet display name (validated before explore; same rules as MsgPlanetUpdateName)
| Requirement | Details |
|---|---|
| playerOnline | true |
| currentPlanetEmpty | Only enforced if the player already owns a planet — current planet must have 0 ore remaining (all ore mined). New players exploring for the first time are exempt. |
| fleetOnStation | Only enforced if the player already owns a planet — fleet must be onStation at the current planet (not away). New players have no current planet, so this check is skipped. The chain rejects with fleet must be onStation to explore if violated. |
Transaction may broadcast but planet ownership unchanged if requirements are not met. Always verify game state after broadcast.
Result:
Planet Starting Properties:
| Property | Value |
|---|---|
| maxOre | 5 |
| spaceSlots | 4 |
| airSlots | 4 |
| landSlots | 4 |
| waterSlots | 4 |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgPlanetExplore",
"creator": "structs1...",
"playerId": "1-42",
"name": "MyPlanet"
}
]
}
}
fleet-move/structs.structs.MsgFleetMovePOST /cosmos/tx/v1beta1/txsRequired Fields: creator, fleetId, destinationType, destinationId
| Requirement | Details |
|---|---|
| playerOnline | true |
| commandShipOnline | Command Ship must be online in fleet |
| validDestination | Destination must exist and be accessible |
| queueCapacity | Foreign destinations only: locationListCount < 1 + locationListExtra or the move is queue_full |
Fleet Status:
| Status | Description | Can Build | Can Raid |
|---|---|---|---|
| onStation | Fleet is at planet | Yes | No |
| away | Fleet is away from planet | No | Yes |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgFleetMove",
"creator": "structs1...",
"fleetId": "1-1",
"destinationType": 1,
"destinationId": "2-1"
}
]
}
}
guild-create/structs.structs.MsgGuildCreatePOST /cosmos/tx/v1beta1/txsuguild.<id> into the new guild vault. The signer becomes the owner.Required Fields: creator, reactorId, endpoint, entrySubstationId
Deprecated Fields (decodable, must be empty): proof, nonce, founderPlayerId, address, proofPubKey, proofSignature — any nonempty value is rejected with legacy_charter_fields_not_supported. Third-party founding is not supported.
| Requirement | Details |
|---|---|
| playerOnline | true |
| permission | PermPlay and PermTokenTransfer on the founder |
| funds | ≥ 2,000,000 ualpha spendable in the founder’s vault |
| reactor | Exists and its validator is bonded and not jailed |
| entry substation | Signer may manage connections on it (CanManageConnectionsBy) |
| not owner | Founder who already owns a guild must transfer it first (is_owner) |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgGuildCreate",
"creator": "structs1...",
"reactorId": "3-1",
"endpoint": "https://guild.example",
"entrySubstationId": "4-1"
}
]
}
}
guild-update-rank-purchase/structs.structs.MsgGuildUpdateRankPurchaseuguild.<id>): the n-th rank step above the entry rank costs basePrice + (n−1) × stepIncrease, and a buyer pays the cumulative difference between their current and target rank. minimumRank = 0 disables sales.Required Fields: creator, guildId, basePrice, stepIncrease, minimumRank, joinByRankPurchaseEnabled
| Requirement | Details |
|---|---|
| permission | PermAdmin on the guild |
guild-rank-purchase/structs.structs.MsgGuildRankPurchaseuguild.<id>. maxPrice and expectedRank are slippage guards (quoted_price_exceeded, rank_changed). Emits EventGuildRankPurchase.Required Fields: creator, guildId, targetRank, maxPrice, expectedRank
| Requirement | Details |
|---|---|
| permission | PermGuildMembership and PermTokenTransfer on the buyer |
| range | Lower number = better rank. minimumRank ≤ targetRank ≤ entryRank else outside_purchase_range, and targetRank must be strictly better (lower) than the buyer’s current rank (must_improve_rank_within_entry_range); rank_purchase_disabled when minimumRank is 0 |
guild-membership-join-by-rank-purchase/structs.structs.MsgGuildMembershipJoinByRankPurchasejoinByRankPurchaseEnabled (rank_purchase_admission_disabled otherwise); migrates the player to the guild’s entry substation; refused while that substation is deletion_pending. Emits EventGuildRankPurchase with joined: true.Required Fields: creator, guildId, targetRank, maxPrice
Optional Fields: expectedGuildId (the guild you expect to currently be in; empty = guildless) — membership_changed if it does not match
guild-membership-join/structs.structs.MsgGuildMembershipJoinPOST /cosmos/tx/v1beta1/txsRequired Fields: creator, guildId
| Requirement | Details |
|---|---|
| playerOnline | true |
| notInGuild | Player must not already be in a guild |
| guildExists | Guild must exist. Check: query guild by ID. |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgGuildMembershipJoin",
"creator": "structs1...",
"guildId": "0-1"
}
]
}
}
guild-membership-join-proxy/structs.structs.MsgGuildMembershipJoinProxyPOST /cosmos/tx/v1beta1/txsualpha to pay fees. The proxy can also seed the new player’s UGC name and pfp directly so the chain is the single source of truth for player identity from creation.Required Fields: creator, address, proofPubKey, proofSignature
Optional Fields: substationId (override the guild’s default entry substation), playerName (set new player’s name immediately), playerPfp (set new player’s pfp immediately)
| Requirement | Details |
|---|---|
| permGuildMembership | Caller needs PermGuildMembership (512) on the guild |
| permSubstationConnection | Also PermSubstationConnection (1024) on the substation if substationId is set |
| validProof | proofPubKey and proofSignature must derive to address (secp256k1 sign-of-pubkey self-proof) |
| validPlayerName | If playerName is set, must satisfy ValidatePlayerName (3-20 runes, ^[\p{L}0-9\-_]{3,20}$, NFC, no combining/bidi/object-id-shaped) |
| validPlayerPfp | If playerPfp is set, must satisfy ValidatePfp (see UGC actions) |
Self-proof construction: Sign the secp256k1 compressed pubkey bytes with the corresponding private key; submit the signature as proofSignature. The chain rederives the address from proofPubKey and rejects mismatches.
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgGuildMembershipJoinProxy",
"creator": "structs1moderator...",
"address": "structs1newplayer...",
"proofPubKey": "Aqg...base64...",
"proofSignature": "MEU...base64...",
"substationId": "4-3",
"playerName": "Andromeda7",
"playerPfp": "ipfs://bafy..."
}
]
}
}
guild-membership-kick/structs.structs.MsgGuildMembershipKickPOST /cosmos/tx/v1beta1/txsRequired Fields: creator, guildId, playerId
| Requirement | Details |
|---|---|
| playerOnline | true |
| inGuild | The target player must be in the guild. Check: query player.guildId matches guildId. |
| permission | Removing another member requires the appropriate guild rank permission on the guild. |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgGuildMembershipKick",
"creator": "structs1...",
"guildId": "0-1",
"playerId": "1-11"
}
]
}
}
guild-bank-mint/structs.structs.MsgGuildBankMintPOST /cosmos/tx/v1beta1/txsamountAlpha is moved from the guild vault into the collateral pool and amountToken is minted into the guild vault; the signer’s own funds are never usedRequired Fields: creator, amountAlpha, amountToken
Optional Fields: guildId (defaults to the signer’s guild; an owner who is not a member names it explicitly)
| Requirement | Details |
|---|---|
| playerOnline | true |
| inGuild | Player must be in the guild |
| guildPermission | Player must have permission to mint tokens. Trust-based system – no technical safeguards against revocation or inflation. |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgGuildBankMint",
"creator": "structs1...",
"guildId": "0-1",
"amount": "1000000"
}
]
}
}
guild-bank-redeem/structs.structs.MsgGuildBankRedeemPOST /cosmos/tx/v1beta1/txsfloor(amount * collateral / supply) and must be ≥ minAmountAlpha.Required Fields: creator, amountToken, minAmountAlpha
| Requirement | Details |
|---|---|
| playerOnline | true |
| permTokenTransfer | PermTokenTransfer (16) on the signer |
| slippage | Alpha out must be ≥ minAmountAlpha |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgGuildBankRedeem",
"creator": "structs1...",
"amountToken": { "denom": "uguild.0-1", "amount": "1000000" },
"minAmountAlpha": "1"
}
]
}
}
guild-bank-convert/structs.structs.MsgGuildBankConvertPOST /cosmos/tx/v1beta1/txsualpha into an existing guild token at the live collateral ratio. Convert-in fee stays in collateral. minAmountToken is required and nonzero.Required Fields: creator, guildId, amountAlpha, minAmountToken
| Requirement | Details |
|---|---|
| playerOnline | true |
| permTokenTransfer | PermTokenTransfer (16) on the signer |
| slippage | Output tokens must be ≥ minAmountToken |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgGuildBankConvert",
"creator": "structs1...",
"guildId": "0-1",
"amountAlpha": "1000000",
"minAmountToken": "1"
}
]
}
}
guild-bank-convert-token/structs.structs.MsgGuildBankConvertTokenPOST /cosmos/tx/v1beta1/txsamountToken denom identifies the source guild; guildId is the target.Required Fields: creator, amountToken, guildId, minAmountToken
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgGuildBankConvertToken",
"creator": "structs1...",
"amountToken": { "denom": "uguild.0-1", "amount": "1000" },
"guildId": "0-2",
"minAmountToken": "1"
}
]
}
}
guild-update-entry-rank/structs.structs.MsgGuildUpdateEntryRankRequired Fields: creator, newEntryRank
| Requirement | Details |
|---|---|
| permUpdate | Requires PermUpdate (4) on the guild |
| rankConstraint | New entry rank must be >= caller’s own rank |
player-update-guild-rank/structs.structs.MsgPlayerUpdateGuildRankRequired Fields: creator, playerId, guildRank
| Requirement | Details |
|---|---|
| permAdmin | Requires PermAdmin (2) on the guild — ownership or a direct grant; a rank register never qualifies |
player-send/structs.structs.MsgPlayerSendfrom_address may be a vault address — the signer then needs PermTokenTransfer on the vault’s owner — which is how Alpha leaves a vault to an arbitrary addressRequired Fields: creator, from_address, to_address, amount (Coins)
vault-send/structs.structs.MsgVaultSend1-N or guild 0-N). Recipient vault is provisioned on demand.Required Fields: creator, ownerId, recipientOwnerId, amount (Coins)
| Requirement | Details |
|---|---|
| permission | PermTokenTransfer on ownerId |
| recipient | Must be an existing player or guild |
| Requirement | Details |
|---|---|
| permTokenTransfer | Requires PermTokenTransfer (16) on the player |
permission-guild-rank-set/structs.structs.MsgPermissionGuildRankSetRequired Fields: creator, objectId, guildId, permission, rank
| Requirement | Details |
|---|---|
| callerHasPermission | Caller must already have the specified permission on the object |
permission-guild-rank-revoke/structs.structs.MsgPermissionGuildRankRevokeRequired Fields: creator, objectId, guildId, permission
| Requirement | Details |
|---|---|
| callerHasPermission | Caller must already have the specified permission on the object |
User-generated content (name and pfp) updates. All seven messages are part of the free-gas Structs path. The Update*Name and Update*Pfp messages on player, planet, and substation route through UGCPermissionCheck (self-service via PermUpdate on the target, OR guild moderation via PermGuildUGCUpdate on the target owner’s guild). Guild rename/repfp uses the standard PermissionCheck with PermUpdate on the guild itself. Validation is enforced by types.ValidatePlayerName / ValidateEntityName / ValidatePlanetName / ValidatePfp (see schemas/validation.md and knowledge/mechanics/ugc-moderation.md). When the actor is not the target’s owner, the chain emits a ugc_moderated event.
player-update-name/structs.structs.MsgPlayerUpdateNameRequired Fields: creator, playerId, name
| Requirement | Details |
|---|---|
| permission | PermUpdate (4) on the player OR PermGuildUGCUpdate (16777216) on the player’s guild |
| validName | Must satisfy ValidatePlayerName (3-20 runes after NFC, ^[\p{L}0-9\-_]{3,20}$, no spaces, apostrophes, combining marks, bidi/zero-width, or object-id-shaped strings) |
player-update-pfp/structs.structs.MsgPlayerUpdatePfpRequired Fields: creator, playerId, pfp
| Requirement | Details |
|---|---|
| permission | PermUpdate (4) on the player OR PermGuildUGCUpdate (16777216) on the player’s guild |
| validPfp | Must satisfy ValidatePfp (empty string clears; otherwise <=256 runes, no control/bidi/whitespace/<>"\\ chars; no : -> ^[A-Za-z0-9._/\-]{1,256}$; with : -> scheme in {https, http, ipfs, ipns, ar} and parses cleanly) |
player-update-pfp-cr-attributes/structs.structs.MsgPlayerUpdatePfpClientRenderAttributesRequired Fields: creator, playerId, pfpClientRenderAttributes
| Requirement | Details |
|---|---|
| permission | PermUpdate (4) on the player (self-service only; does not route through UGCPermissionCheck) |
| validAttributes | Must satisfy ValidatePfpClientRenderAttributes (empty string clears; otherwise a JSON object <=512 bytes, stored compacted; arrays/scalars/malformed JSON rejected) |
guild-update-name/structs.structs.MsgGuildUpdateNameRequired Fields: creator, guildId, name
| Requirement | Details |
|---|---|
| permission | PermUpdate (4) on the guild |
| validName | Must satisfy ValidateEntityName (3-20 runes after NFC, ^[\p{L}0-9\-_' ]{3,20}$, no leading/trailing spaces, no double space, no combining marks, no bidi/zero-width, not object-id-shaped) |
| uniqueness | Names must be unique under NormalizeName (NFC + lowercase + trim) — chain rejects duplicates |
guild-update-pfp/structs.structs.MsgGuildUpdatePfpRequired Fields: creator, guildId, pfp
| Requirement | Details |
|---|---|
| permission | PermUpdate (4) on the guild |
| validPfp | Must satisfy ValidatePfp (see player-update-pfp) |
guild-update-primary-reactor/structs.structs.MsgGuildUpdatePrimaryReactorRequired Fields: creator, guildId, reactorId
| Requirement | Details |
|---|---|
| permission | PermAdmin (2) on the guild |
| validator | Target reactor’s validator must exist and not be jailed |
planet-update-name/structs.structs.MsgPlanetUpdateNameRequired Fields: creator, planetId, name
| Requirement | Details |
|---|---|
| permission | PermUpdate (4) on the planet OR PermGuildUGCUpdate (16777216) on the planet owner’s guild |
| validName | Must satisfy ValidatePlanetName (3-25 runes after NFC, ^[\p{L}0-9\-_' ]{3,25}$, no leading/trailing spaces, no double space, no combining marks, no bidi/zero-width, not object-id-shaped) |
substation-update-name/structs.structs.MsgSubstationUpdateNameRequired Fields: creator, substationId, name
| Requirement | Details |
|---|---|
| permission | PermUpdate (4) on the substation OR PermGuildUGCUpdate (16777216) on the substation owner’s guild |
| validName | Must satisfy ValidateEntityName |
substation-update-pfp/structs.structs.MsgSubstationUpdatePfpRequired Fields: creator, substationId, pfp
| Requirement | Details |
|---|---|
| permission | PermUpdate (4) on the substation OR PermGuildUGCUpdate (16777216) on the substation owner’s guild |
| validPfp | Must satisfy ValidatePfp |
struct-activate/structs.structs.MsgStructActivatePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_activate.goproto/structs/structs/tx.proto:644-649Required Fields: creator, structId
| Requirement | Details |
|---|---|
| playerOnline | true |
| structBuilt | true |
| structOffline | true |
| sufficientCharge | Charge >= structType.ActivateCharge |
| sufficientPower | Available capacity >= structType.PassiveDraw |
Effects:
oreMiningActiveQuantity; re-anchors planetBlockStartOreMine only on 0→1oreRefiningActiveQuantity; re-anchors planetBlockStartOreRefine only on 0→1{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructActivate",
"creator": "structs1...",
"structId": "1-1"
}
]
}
}
struct-deactivate/structs.structs.MsgStructDeactivatePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_deactivate.goproto/structs/structs/tx.proto:651-656Required Fields: creator, structId
| Requirement | Details |
|---|---|
| permission | Caller holds PermPlay on the struct (owner passes automatically) |
| structBuilt | true |
| structOnline | true |
Deactivate does not require the player to be online and costs no charge — it is a recovery action, so an overloaded (offline) player can always deactivate structs to get back under capacity.
Effects:
blockStart... = 0) — deactivating cancels the in-progress mine/refine cycle; re-activating starts a fresh one{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructDeactivate",
"creator": "structs1...",
"structId": "1-1"
}
]
}
}
struct-deactivate-batch/structs.structs.MsgStructDeactivateBatchPOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_deactivate_batch.goproto/structs/structs/tx.proto:776-781Required Fields: creator, structId (a list of struct IDs)
| Requirement | Details |
|---|---|
| batchSize | 1..=65 (MaxStructDeactivateBatchSize); empty or duplicate IDs are rejected |
| perStruct | Each struct must pass the same checks as MsgStructDeactivate (PermPlay, built, online) |
The batch is validated in full before any struct is deactivated — if any struct is ineligible the whole transaction fails and nothing changes. Same effects as MsgStructDeactivate, applied to each struct. No charge cost, no player-online requirement.
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructDeactivateBatch",
"creator": "structs1...",
"structId": ["1-1", "1-2", "1-3"]
}
]
}
}
struct-trash/structs.structs.MsgStructTrashPOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_trash.goproto/structs/structs/tx.proto:817-822Required Fields: creator, structId
| Requirement | Details |
|---|---|
| permission | Caller holds PermPlay on the struct (owner passes automatically) |
| structNotDestroyed | The struct must not already be destroyed |
| sufficientCharge | Owner charge >= structType.BuildCharge (trashing costs the same charge as building) |
Effects:
Discharge)Use this to reclaim a slot occupied by an unwanted built struct. To abort an unfinished build instead, use MsgStructBuildCancel.
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructTrash",
"creator": "structs1...",
"structId": "1-1"
}
]
}
}
struct-stealth-activate/structs.structs.MsgStructStealthActivatePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_stealth_activate.goproto/structs/structs/tx.proto:117Required Fields: creator, structId
| Requirement | Details |
|---|---|
| playerOnline | true |
| structCommandable | true |
| structNotHidden | true |
| hasStealthSystem | Struct must have stealth system |
| sufficientCharge | Charge >= structType.StealthActivateCharge |
Effects:
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructStealthActivate",
"creator": "structs1...",
"structId": "1-1"
}
]
}
}
struct-stealth-deactivate/structs.structs.MsgStructStealthDeactivatePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_stealth_deactivate.goproto/structs/structs/tx.proto:118Required Fields: creator, structId
| Requirement | Details |
|---|---|
| playerOnline | true |
| structCommandable | true |
| structHidden | true |
| hasStealthSystem | true |
Effects: Removes hidden status from struct.
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructStealthDeactivate",
"creator": "structs1...",
"structId": "1-1"
}
]
}
}
struct-defense-set/structs.structs.MsgStructDefenseSetPOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_defense_set.goproto/structs/structs/tx.proto:702-708Required Fields: creator, defenderStructId, protectedStructId
| Requirement | Details |
|---|---|
| playerOnline | true |
| defenderExists | true |
| protectedExists | true |
| canDefend | Defender’s StructType.canDefend is true (fleet types only) |
| coLocated | Defender and protected share a planet or fleet |
| builtAndOnline | Defender is built and online |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructDefenseSet",
"creator": "structs1...",
"defenderStructId": "1-1",
"protectedStructId": "2-1"
}
]
}
}
struct-defense-clear/structs.structs.MsgStructDefenseClearPOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_defense_clear.goproto/structs/structs/tx.proto:710-715Required Fields: creator, defenderStructId
| Requirement | Details |
|---|---|
| playerOnline | true |
| defenderExists | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructDefenseClear",
"creator": "structs1...",
"defenderStructId": "1-1"
}
]
}
}
struct-move/structs.structs.MsgStructMovePOST /cosmos/tx/v1beta1/txsx/structs/keeper/msg_server_struct_move.goproto/structs/structs/tx.proto:717-725Required Fields: creator, structId, locationType, ambit, slot
| Requirement | Details |
|---|---|
| playerOnline | true |
| structBuilt | true |
| validLocation | true |
{
"body": {
"messages": [
{
"@type": "/structs.structs.MsgStructMove",
"creator": "structs1...",
"structId": "1-1",
"locationType": 1,
"ambit": 1,
"slot": 1
}
]
}
}
| Field | Value |
|---|---|
| Verified | true |
| Verified By | GameCodeAnalyst |
| Verified Date | 2025-01-01 |
| Method | code-analysis |
| Confidence | high |
| Total Actions | 30 |
| Verified Actions | 30 |
| Percentage | 100% |
| Note | All documented actions verified against codebase. Additional actions exist in proto file but not yet documented. |