@aephia/atlas-kit 0.6.0-next.11 → 0.6.0-next.110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (686) hide show
  1. package/README.md +3 -1
  2. package/dist/cargo/actions/deposit.d.ts +1 -1
  3. package/dist/cargo/actions/deposit.d.ts.map +1 -1
  4. package/dist/cargo/actions/deposit.js +26 -115
  5. package/dist/cargo/actions/deposit.js.map +1 -1
  6. package/dist/cargo/actions/index.d.ts.map +1 -1
  7. package/dist/cargo/actions/index.js +15 -37
  8. package/dist/cargo/actions/index.js.map +1 -1
  9. package/dist/cargo/actions/wallet-context.d.ts +51 -2
  10. package/dist/cargo/actions/wallet-context.d.ts.map +1 -1
  11. package/dist/cargo/actions/wallet-context.js +125 -2
  12. package/dist/cargo/actions/wallet-context.js.map +1 -1
  13. package/dist/cargo/actions/wallet-token.d.ts +1 -6
  14. package/dist/cargo/actions/wallet-token.d.ts.map +1 -1
  15. package/dist/cargo/actions/wallet-token.js +0 -53
  16. package/dist/cargo/actions/wallet-token.js.map +1 -1
  17. package/dist/cargo/actions/withdrawal.d.ts.map +1 -1
  18. package/dist/cargo/actions/withdrawal.js +37 -162
  19. package/dist/cargo/actions/withdrawal.js.map +1 -1
  20. package/dist/claim-stakes/actions/index.d.ts +13 -0
  21. package/dist/claim-stakes/actions/index.d.ts.map +1 -1
  22. package/dist/claim-stakes/actions/index.js +373 -544
  23. package/dist/claim-stakes/actions/index.js.map +1 -1
  24. package/dist/claim-stakes/index.d.ts +14 -0
  25. package/dist/claim-stakes/index.d.ts.map +1 -1
  26. package/dist/claim-stakes/index.js +23 -2
  27. package/dist/claim-stakes/index.js.map +1 -1
  28. package/dist/client/context.d.ts.map +1 -1
  29. package/dist/client/context.js +1 -1
  30. package/dist/client/context.js.map +1 -1
  31. package/dist/client/contracts.d.ts +16 -6
  32. package/dist/client/contracts.d.ts.map +1 -1
  33. package/dist/client/errors.d.ts +6 -2
  34. package/dist/client/errors.d.ts.map +1 -1
  35. package/dist/client/errors.js +31 -1
  36. package/dist/client/errors.js.map +1 -1
  37. package/dist/client/index.d.ts +35 -0
  38. package/dist/client/index.d.ts.map +1 -1
  39. package/dist/client/index.js +35 -0
  40. package/dist/client/index.js.map +1 -1
  41. package/dist/client/rpc-subscription-provider.d.ts +35 -0
  42. package/dist/client/rpc-subscription-provider.d.ts.map +1 -0
  43. package/dist/client/rpc-subscription-provider.js +190 -0
  44. package/dist/client/rpc-subscription-provider.js.map +1 -0
  45. package/dist/combat/actions/index.d.ts +2 -2
  46. package/dist/combat/actions/index.d.ts.map +1 -1
  47. package/dist/combat/actions/index.js +192 -224
  48. package/dist/combat/actions/index.js.map +1 -1
  49. package/dist/combat/index.d.ts +4 -3
  50. package/dist/combat/index.d.ts.map +1 -1
  51. package/dist/combat/index.js +3 -2
  52. package/dist/combat/index.js.map +1 -1
  53. package/dist/crafting/actions/index.d.ts +11 -0
  54. package/dist/crafting/actions/index.d.ts.map +1 -1
  55. package/dist/crafting/actions/index.js +175 -283
  56. package/dist/crafting/actions/index.js.map +1 -1
  57. package/dist/crafting/index.d.ts +33 -3
  58. package/dist/crafting/index.d.ts.map +1 -1
  59. package/dist/crafting/index.js +45 -16
  60. package/dist/crafting/index.js.map +1 -1
  61. package/dist/factions/actions/index.d.ts +1 -0
  62. package/dist/factions/actions/index.d.ts.map +1 -1
  63. package/dist/factions/actions/index.js +2 -1
  64. package/dist/factions/actions/index.js.map +1 -1
  65. package/dist/factions/index.d.ts +1 -1
  66. package/dist/factions/index.d.ts.map +1 -1
  67. package/dist/factions/index.js +14 -8
  68. package/dist/factions/index.js.map +1 -1
  69. package/dist/factions/profile-faction.d.ts +20 -8
  70. package/dist/factions/profile-faction.d.ts.map +1 -1
  71. package/dist/factions/profile-faction.js +20 -8
  72. package/dist/factions/profile-faction.js.map +1 -1
  73. package/dist/fleets/actions/add-ship.d.ts +35 -0
  74. package/dist/fleets/actions/add-ship.d.ts.map +1 -0
  75. package/dist/fleets/actions/add-ship.js +149 -0
  76. package/dist/fleets/actions/add-ship.js.map +1 -0
  77. package/dist/fleets/actions/create-fleet.d.ts +36 -0
  78. package/dist/fleets/actions/create-fleet.d.ts.map +1 -0
  79. package/dist/fleets/actions/create-fleet.js +138 -0
  80. package/dist/fleets/actions/create-fleet.js.map +1 -0
  81. package/dist/fleets/actions/crew-transfer.d.ts +41 -0
  82. package/dist/fleets/actions/crew-transfer.d.ts.map +1 -0
  83. package/dist/fleets/actions/crew-transfer.js +114 -0
  84. package/dist/fleets/actions/crew-transfer.js.map +1 -0
  85. package/dist/fleets/actions/dock-bounds.d.ts +38 -0
  86. package/dist/fleets/actions/dock-bounds.d.ts.map +1 -0
  87. package/dist/fleets/actions/dock-bounds.js +46 -0
  88. package/dist/fleets/actions/dock-bounds.js.map +1 -0
  89. package/dist/fleets/actions/index.d.ts +37 -16
  90. package/dist/fleets/actions/index.d.ts.map +1 -1
  91. package/dist/fleets/actions/index.js +303 -284
  92. package/dist/fleets/actions/index.js.map +1 -1
  93. package/dist/fleets/actions/respawn.d.ts +38 -0
  94. package/dist/fleets/actions/respawn.d.ts.map +1 -0
  95. package/dist/fleets/actions/respawn.js +122 -0
  96. package/dist/fleets/actions/respawn.js.map +1 -0
  97. package/dist/fleets/actions/ship-import.d.ts.map +1 -1
  98. package/dist/fleets/actions/ship-import.js +59 -76
  99. package/dist/fleets/actions/ship-import.js.map +1 -1
  100. package/dist/fleets/cooldown.d.ts +44 -0
  101. package/dist/fleets/cooldown.d.ts.map +1 -0
  102. package/dist/fleets/cooldown.js +43 -0
  103. package/dist/fleets/cooldown.js.map +1 -0
  104. package/dist/fleets/coordinate-warp-estimate.d.ts +70 -0
  105. package/dist/fleets/coordinate-warp-estimate.d.ts.map +1 -0
  106. package/dist/fleets/coordinate-warp-estimate.js +46 -0
  107. package/dist/fleets/coordinate-warp-estimate.js.map +1 -0
  108. package/dist/fleets/index.d.ts +35 -0
  109. package/dist/fleets/index.d.ts.map +1 -1
  110. package/dist/fleets/index.js +52 -2
  111. package/dist/fleets/index.js.map +1 -1
  112. package/dist/fleets/movement-arithmetic.d.ts +21 -0
  113. package/dist/fleets/movement-arithmetic.d.ts.map +1 -0
  114. package/dist/fleets/movement-arithmetic.js +41 -0
  115. package/dist/fleets/movement-arithmetic.js.map +1 -0
  116. package/dist/fleets/subwarp-estimate.d.ts +70 -0
  117. package/dist/fleets/subwarp-estimate.d.ts.map +1 -0
  118. package/dist/fleets/subwarp-estimate.js +38 -0
  119. package/dist/fleets/subwarp-estimate.js.map +1 -0
  120. package/dist/fleets/travel-profile.d.ts +102 -0
  121. package/dist/fleets/travel-profile.d.ts.map +1 -0
  122. package/dist/fleets/travel-profile.js +120 -0
  123. package/dist/fleets/travel-profile.js.map +1 -0
  124. package/dist/fleets/warp-lane-estimate.d.ts +59 -0
  125. package/dist/fleets/warp-lane-estimate.d.ts.map +1 -0
  126. package/dist/fleets/warp-lane-estimate.js +36 -0
  127. package/dist/fleets/warp-lane-estimate.js.map +1 -0
  128. package/dist/fleets/warp-lane-policy.d.ts +68 -0
  129. package/dist/fleets/warp-lane-policy.d.ts.map +1 -0
  130. package/dist/fleets/warp-lane-policy.js +91 -0
  131. package/dist/fleets/warp-lane-policy.js.map +1 -0
  132. package/dist/fleets/warp-lane-toll.d.ts +55 -0
  133. package/dist/fleets/warp-lane-toll.d.ts.map +1 -0
  134. package/dist/fleets/warp-lane-toll.js +79 -0
  135. package/dist/fleets/warp-lane-toll.js.map +1 -0
  136. package/dist/identity/actions/index.d.ts +3 -3
  137. package/dist/identity/actions/index.d.ts.map +1 -1
  138. package/dist/identity/actions/index.js +50 -28
  139. package/dist/identity/actions/index.js.map +1 -1
  140. package/dist/identity/index.d.ts +12 -2
  141. package/dist/identity/index.d.ts.map +1 -1
  142. package/dist/identity/index.js +10 -1
  143. package/dist/identity/index.js.map +1 -1
  144. package/dist/identity/permissions.d.ts +11 -2
  145. package/dist/identity/permissions.d.ts.map +1 -1
  146. package/dist/identity/permissions.js +13 -4
  147. package/dist/identity/permissions.js.map +1 -1
  148. package/dist/identity/research-state.d.ts +60 -0
  149. package/dist/identity/research-state.d.ts.map +1 -0
  150. package/dist/identity/research-state.js +68 -0
  151. package/dist/identity/research-state.js.map +1 -0
  152. package/dist/index.d.ts +24 -0
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.js +20 -3
  155. package/dist/index.js.map +1 -1
  156. package/dist/internal/c4/account-decoding.d.ts +12 -0
  157. package/dist/internal/c4/account-decoding.d.ts.map +1 -0
  158. package/dist/internal/c4/account-decoding.js +36 -0
  159. package/dist/internal/c4/account-decoding.js.map +1 -0
  160. package/dist/internal/c4/cargo-bytes-config.d.ts +7 -0
  161. package/dist/internal/c4/cargo-bytes-config.d.ts.map +1 -0
  162. package/dist/internal/c4/cargo-bytes-config.js +19 -0
  163. package/dist/internal/c4/cargo-bytes-config.js.map +1 -0
  164. package/dist/internal/c4/character-modifier.d.ts +1 -1
  165. package/dist/internal/c4/character-modifier.d.ts.map +1 -1
  166. package/dist/internal/c4/character-registration.d.ts +2 -0
  167. package/dist/internal/c4/character-registration.d.ts.map +1 -1
  168. package/dist/internal/c4/character-registration.js +2 -0
  169. package/dist/internal/c4/character-registration.js.map +1 -1
  170. package/dist/internal/c4/character.d.ts +155 -0
  171. package/dist/internal/c4/character.d.ts.map +1 -0
  172. package/dist/internal/c4/character.js +79 -0
  173. package/dist/internal/c4/character.js.map +1 -0
  174. package/dist/internal/c4/claim-stake-configuration.js +4 -2
  175. package/dist/internal/c4/claim-stake-configuration.js.map +1 -1
  176. package/dist/internal/c4/claim-stake-definitions.d.ts +4 -4
  177. package/dist/internal/c4/claim-stake-definitions.d.ts.map +1 -1
  178. package/dist/internal/c4/claim-stake-definitions.js.map +1 -1
  179. package/dist/internal/c4/claim-stake.d.ts +4 -27
  180. package/dist/internal/c4/claim-stake.d.ts.map +1 -1
  181. package/dist/internal/c4/claim-stake.js +30 -41
  182. package/dist/internal/c4/claim-stake.js.map +1 -1
  183. package/dist/internal/c4/combat.d.ts +1 -82
  184. package/dist/internal/c4/combat.d.ts.map +1 -1
  185. package/dist/internal/c4/combat.js +10 -171
  186. package/dist/internal/c4/combat.js.map +1 -1
  187. package/dist/internal/c4/crafting-process-codec.d.ts +13 -0
  188. package/dist/internal/c4/crafting-process-codec.d.ts.map +1 -0
  189. package/dist/internal/c4/crafting-process-codec.js +34 -0
  190. package/dist/internal/c4/crafting-process-codec.js.map +1 -0
  191. package/dist/internal/c4/crafting.d.ts +25 -33
  192. package/dist/internal/c4/crafting.d.ts.map +1 -1
  193. package/dist/internal/c4/crafting.js +61 -49
  194. package/dist/internal/c4/crafting.js.map +1 -1
  195. package/dist/internal/c4/currency-cache.d.ts +6 -0
  196. package/dist/internal/c4/currency-cache.d.ts.map +1 -0
  197. package/dist/internal/c4/currency-cache.js +30 -0
  198. package/dist/internal/c4/currency-cache.js.map +1 -0
  199. package/dist/internal/c4/docking-funding.d.ts +4 -0
  200. package/dist/internal/c4/docking-funding.d.ts.map +1 -0
  201. package/dist/internal/c4/docking-funding.js +11 -0
  202. package/dist/internal/c4/docking-funding.js.map +1 -0
  203. package/dist/internal/c4/faction-adapter.d.ts +12 -0
  204. package/dist/internal/c4/faction-adapter.d.ts.map +1 -0
  205. package/dist/internal/c4/faction-adapter.js +52 -0
  206. package/dist/internal/c4/faction-adapter.js.map +1 -0
  207. package/dist/internal/c4/faction-epoch-meter.d.ts +10 -0
  208. package/dist/internal/c4/faction-epoch-meter.d.ts.map +1 -0
  209. package/dist/internal/c4/faction-epoch-meter.js +31 -0
  210. package/dist/internal/c4/faction-epoch-meter.js.map +1 -0
  211. package/dist/internal/c4/faction-treasury.d.ts +23 -0
  212. package/dist/internal/c4/faction-treasury.d.ts.map +1 -0
  213. package/dist/internal/c4/faction-treasury.js +48 -0
  214. package/dist/internal/c4/faction-treasury.js.map +1 -0
  215. package/dist/internal/c4/faction.d.ts +21 -0
  216. package/dist/internal/c4/faction.d.ts.map +1 -0
  217. package/dist/internal/c4/faction.js +23 -0
  218. package/dist/internal/c4/faction.js.map +1 -0
  219. package/dist/internal/c4/factions.d.ts +9 -57
  220. package/dist/internal/c4/factions.d.ts.map +1 -1
  221. package/dist/internal/c4/factions.js +29 -156
  222. package/dist/internal/c4/factions.js.map +1 -1
  223. package/dist/internal/c4/fleet-arrival.d.ts +28 -0
  224. package/dist/internal/c4/fleet-arrival.d.ts.map +1 -0
  225. package/dist/internal/c4/fleet-arrival.js +42 -0
  226. package/dist/internal/c4/fleet-arrival.js.map +1 -0
  227. package/dist/internal/c4/fleet-creation.d.ts +7 -0
  228. package/dist/internal/c4/fleet-creation.d.ts.map +1 -0
  229. package/dist/internal/c4/fleet-creation.js +180 -0
  230. package/dist/internal/c4/fleet-creation.js.map +1 -0
  231. package/dist/internal/c4/fleet-crew-binding.d.ts +9 -0
  232. package/dist/internal/c4/fleet-crew-binding.d.ts.map +1 -1
  233. package/dist/internal/c4/fleet-crew-binding.js +20 -3
  234. package/dist/internal/c4/fleet-crew-binding.js.map +1 -1
  235. package/dist/internal/c4/fleet-respawn.d.ts +17 -0
  236. package/dist/internal/c4/fleet-respawn.d.ts.map +1 -0
  237. package/dist/internal/c4/fleet-respawn.js +62 -0
  238. package/dist/internal/c4/fleet-respawn.js.map +1 -0
  239. package/dist/internal/c4/fleet-ship-assembly.d.ts +11 -0
  240. package/dist/internal/c4/fleet-ship-assembly.d.ts.map +1 -0
  241. package/dist/internal/c4/fleet-ship-assembly.js +44 -0
  242. package/dist/internal/c4/fleet-ship-assembly.js.map +1 -0
  243. package/dist/internal/c4/fleet.d.ts +45 -19
  244. package/dist/internal/c4/fleet.d.ts.map +1 -1
  245. package/dist/internal/c4/fleet.js +37 -29
  246. package/dist/internal/c4/fleet.js.map +1 -1
  247. package/dist/internal/c4/game-definition-layout.d.ts +2 -0
  248. package/dist/internal/c4/game-definition-layout.d.ts.map +1 -1
  249. package/dist/internal/c4/game-definition-layout.js +4 -0
  250. package/dist/internal/c4/game-definition-layout.js.map +1 -1
  251. package/dist/internal/c4/game.d.ts +47 -12
  252. package/dist/internal/c4/game.d.ts.map +1 -1
  253. package/dist/internal/c4/game.js +110 -21
  254. package/dist/internal/c4/game.js.map +1 -1
  255. package/dist/internal/c4/identity.d.ts +2 -152
  256. package/dist/internal/c4/identity.d.ts.map +1 -1
  257. package/dist/internal/c4/identity.js +6 -110
  258. package/dist/internal/c4/identity.js.map +1 -1
  259. package/dist/internal/c4/local-market-order.d.ts +31 -0
  260. package/dist/internal/c4/local-market-order.d.ts.map +1 -0
  261. package/dist/internal/c4/local-market-order.js +47 -0
  262. package/dist/internal/c4/local-market-order.js.map +1 -0
  263. package/dist/internal/c4/loot-layout.js +1 -1
  264. package/dist/internal/c4/loot-layout.js.map +1 -1
  265. package/dist/internal/c4/loot.d.ts +58 -0
  266. package/dist/internal/c4/loot.d.ts.map +1 -0
  267. package/dist/internal/c4/loot.js +130 -0
  268. package/dist/internal/c4/loot.js.map +1 -0
  269. package/dist/internal/c4/loyalty.d.ts +0 -27
  270. package/dist/internal/c4/loyalty.d.ts.map +1 -1
  271. package/dist/internal/c4/loyalty.js +14 -43
  272. package/dist/internal/c4/loyalty.js.map +1 -1
  273. package/dist/internal/c4/market.d.ts +2 -38
  274. package/dist/internal/c4/market.d.ts.map +1 -1
  275. package/dist/internal/c4/market.js +13 -51
  276. package/dist/internal/c4/market.js.map +1 -1
  277. package/dist/internal/c4/mining-instructions.d.ts +2 -0
  278. package/dist/internal/c4/mining-instructions.d.ts.map +1 -0
  279. package/dist/internal/c4/mining-instructions.js +3 -0
  280. package/dist/internal/c4/mining-instructions.js.map +1 -0
  281. package/dist/internal/c4/open-signal.d.ts +8 -0
  282. package/dist/internal/c4/open-signal.d.ts.map +1 -0
  283. package/dist/internal/c4/open-signal.js +37 -0
  284. package/dist/internal/c4/open-signal.js.map +1 -0
  285. package/dist/internal/c4/pda.js +1 -1
  286. package/dist/internal/c4/pda.js.map +1 -1
  287. package/dist/internal/c4/profile-faction.d.ts.map +1 -1
  288. package/dist/internal/c4/profile-faction.js +11 -21
  289. package/dist/internal/c4/profile-faction.js.map +1 -1
  290. package/dist/internal/c4/profile-permissions.d.ts +5 -3
  291. package/dist/internal/c4/profile-permissions.d.ts.map +1 -1
  292. package/dist/internal/c4/profile-permissions.js +61 -8
  293. package/dist/internal/c4/profile-permissions.js.map +1 -1
  294. package/dist/internal/c4/region-geometry.d.ts +8 -0
  295. package/dist/internal/c4/region-geometry.d.ts.map +1 -0
  296. package/dist/internal/c4/region-geometry.js +43 -0
  297. package/dist/internal/c4/region-geometry.js.map +1 -0
  298. package/dist/internal/c4/rewards.d.ts +1 -61
  299. package/dist/internal/c4/rewards.d.ts.map +1 -1
  300. package/dist/internal/c4/rewards.js +14 -115
  301. package/dist/internal/c4/rewards.js.map +1 -1
  302. package/dist/internal/c4/runtime-bindings.d.ts +4 -0
  303. package/dist/internal/c4/runtime-bindings.d.ts.map +1 -0
  304. package/dist/internal/c4/runtime-bindings.js +4 -0
  305. package/dist/internal/c4/runtime-bindings.js.map +1 -0
  306. package/dist/internal/c4/scan-detection-codecs.d.ts +3 -0
  307. package/dist/internal/c4/scan-detection-codecs.d.ts.map +1 -0
  308. package/dist/internal/c4/scan-detection-codecs.js +3 -0
  309. package/dist/internal/c4/scan-detection-codecs.js.map +1 -0
  310. package/dist/internal/c4/scan-lifecycle.d.ts +306 -0
  311. package/dist/internal/c4/scan-lifecycle.d.ts.map +1 -0
  312. package/dist/internal/c4/scan-lifecycle.js +261 -0
  313. package/dist/internal/c4/scan-lifecycle.js.map +1 -0
  314. package/dist/internal/c4/scanning.d.ts +1 -28
  315. package/dist/internal/c4/scanning.d.ts.map +1 -1
  316. package/dist/internal/c4/scanning.js +7 -36
  317. package/dist/internal/c4/scanning.js.map +1 -1
  318. package/dist/internal/c4/ship-import.d.ts +4 -0
  319. package/dist/internal/c4/ship-import.d.ts.map +1 -0
  320. package/dist/internal/c4/ship-import.js +13 -0
  321. package/dist/internal/c4/ship-import.js.map +1 -0
  322. package/dist/internal/c4/ship-stats.d.ts.map +1 -1
  323. package/dist/internal/c4/ship-stats.js +25 -21
  324. package/dist/internal/c4/ship-stats.js.map +1 -1
  325. package/dist/internal/c4/starbase.d.ts +0 -32
  326. package/dist/internal/c4/starbase.d.ts.map +1 -1
  327. package/dist/internal/c4/starbase.js +12 -62
  328. package/dist/internal/c4/starbase.js.map +1 -1
  329. package/dist/internal/c4/world.d.ts +36 -7
  330. package/dist/internal/c4/world.d.ts.map +1 -1
  331. package/dist/internal/c4/world.js +67 -48
  332. package/dist/internal/c4/world.js.map +1 -1
  333. package/dist/internal/cargo.d.ts +2 -0
  334. package/dist/internal/cargo.d.ts.map +1 -1
  335. package/dist/internal/cargo.js +8 -0
  336. package/dist/internal/cargo.js.map +1 -1
  337. package/dist/internal/fleet.d.ts +1 -0
  338. package/dist/internal/fleet.d.ts.map +1 -1
  339. package/dist/internal/fleet.js +3 -1
  340. package/dist/internal/fleet.js.map +1 -1
  341. package/dist/internal/loyalty-atlas-bank-state.d.ts +16 -0
  342. package/dist/internal/loyalty-atlas-bank-state.d.ts.map +1 -0
  343. package/dist/internal/loyalty-atlas-bank-state.js +10 -0
  344. package/dist/internal/loyalty-atlas-bank-state.js.map +1 -0
  345. package/dist/internal/planning/action-runtime.d.ts +38 -0
  346. package/dist/internal/planning/action-runtime.d.ts.map +1 -0
  347. package/dist/internal/planning/action-runtime.js +63 -0
  348. package/dist/internal/planning/action-runtime.js.map +1 -0
  349. package/dist/internal/planning/arrival-guards.d.ts +19 -0
  350. package/dist/internal/planning/arrival-guards.d.ts.map +1 -0
  351. package/dist/internal/planning/arrival-guards.js +171 -0
  352. package/dist/internal/planning/arrival-guards.js.map +1 -0
  353. package/dist/internal/planning/authorization-adapter.d.ts +45 -37
  354. package/dist/internal/planning/authorization-adapter.d.ts.map +1 -1
  355. package/dist/internal/planning/authorization-adapter.js +165 -76
  356. package/dist/internal/planning/authorization-adapter.js.map +1 -1
  357. package/dist/internal/planning/character-registration-guard.d.ts +4 -0
  358. package/dist/internal/planning/character-registration-guard.d.ts.map +1 -0
  359. package/dist/internal/planning/character-registration-guard.js +58 -0
  360. package/dist/internal/planning/character-registration-guard.js.map +1 -0
  361. package/dist/internal/planning/character-registration.d.ts +23 -0
  362. package/dist/internal/planning/character-registration.d.ts.map +1 -0
  363. package/dist/internal/planning/character-registration.js +87 -0
  364. package/dist/internal/planning/character-registration.js.map +1 -0
  365. package/dist/internal/planning/currency-cache-guard.d.ts +4 -0
  366. package/dist/internal/planning/currency-cache-guard.d.ts.map +1 -0
  367. package/dist/internal/planning/currency-cache-guard.js +32 -0
  368. package/dist/internal/planning/currency-cache-guard.js.map +1 -0
  369. package/dist/internal/planning/democracy-history.d.ts +50 -0
  370. package/dist/internal/planning/democracy-history.d.ts.map +1 -0
  371. package/dist/internal/planning/democracy-history.js +198 -0
  372. package/dist/internal/planning/democracy-history.js.map +1 -0
  373. package/dist/internal/planning/faction-enrollment.d.ts +0 -2
  374. package/dist/internal/planning/faction-enrollment.d.ts.map +1 -1
  375. package/dist/internal/planning/faction-enrollment.js +1 -22
  376. package/dist/internal/planning/faction-enrollment.js.map +1 -1
  377. package/dist/internal/planning/faction-trade-guards.d.ts +30 -0
  378. package/dist/internal/planning/faction-trade-guards.d.ts.map +1 -0
  379. package/dist/internal/planning/faction-trade-guards.js +15 -0
  380. package/dist/internal/planning/faction-trade-guards.js.map +1 -0
  381. package/dist/internal/planning/faction-trade-state.d.ts +16 -0
  382. package/dist/internal/planning/faction-trade-state.d.ts.map +1 -0
  383. package/dist/internal/planning/faction-trade-state.js +43 -0
  384. package/dist/internal/planning/faction-trade-state.js.map +1 -0
  385. package/dist/internal/planning/fleet-arrival.d.ts +40 -0
  386. package/dist/internal/planning/fleet-arrival.d.ts.map +1 -0
  387. package/dist/internal/planning/fleet-arrival.js +106 -0
  388. package/dist/internal/planning/fleet-arrival.js.map +1 -0
  389. package/dist/internal/planning/fleet-attack-xp.d.ts +20 -0
  390. package/dist/internal/planning/fleet-attack-xp.d.ts.map +1 -0
  391. package/dist/internal/planning/fleet-attack-xp.js +110 -0
  392. package/dist/internal/planning/fleet-attack-xp.js.map +1 -0
  393. package/dist/internal/planning/fleet-creation.d.ts +30 -0
  394. package/dist/internal/planning/fleet-creation.d.ts.map +1 -0
  395. package/dist/internal/planning/fleet-creation.js +109 -0
  396. package/dist/internal/planning/fleet-creation.js.map +1 -0
  397. package/dist/internal/planning/fleet-crew-guard.d.ts +28 -0
  398. package/dist/internal/planning/fleet-crew-guard.d.ts.map +1 -0
  399. package/dist/internal/planning/fleet-crew-guard.js +47 -0
  400. package/dist/internal/planning/fleet-crew-guard.js.map +1 -0
  401. package/dist/internal/planning/fleet-crew-transfer.d.ts +7 -0
  402. package/dist/internal/planning/fleet-crew-transfer.d.ts.map +1 -0
  403. package/dist/internal/planning/fleet-crew-transfer.js +132 -0
  404. package/dist/internal/planning/fleet-crew-transfer.js.map +1 -0
  405. package/dist/internal/planning/fleet-dock-funding-guard.d.ts +42 -0
  406. package/dist/internal/planning/fleet-dock-funding-guard.d.ts.map +1 -0
  407. package/dist/internal/planning/fleet-dock-funding-guard.js +208 -0
  408. package/dist/internal/planning/fleet-dock-funding-guard.js.map +1 -0
  409. package/dist/internal/planning/fleet-dock-funding.d.ts +9 -0
  410. package/dist/internal/planning/fleet-dock-funding.d.ts.map +1 -0
  411. package/dist/internal/planning/fleet-dock-funding.js +154 -0
  412. package/dist/internal/planning/fleet-dock-funding.js.map +1 -0
  413. package/dist/internal/planning/fleet-docking-guard.d.ts +4 -0
  414. package/dist/internal/planning/fleet-docking-guard.d.ts.map +1 -0
  415. package/dist/internal/planning/fleet-docking-guard.js +42 -0
  416. package/dist/internal/planning/fleet-docking-guard.js.map +1 -0
  417. package/dist/internal/planning/fleet-docking.d.ts +10 -0
  418. package/dist/internal/planning/fleet-docking.d.ts.map +1 -0
  419. package/dist/internal/planning/fleet-docking.js +85 -0
  420. package/dist/internal/planning/fleet-docking.js.map +1 -0
  421. package/dist/internal/planning/fleet-respawn.d.ts +28 -0
  422. package/dist/internal/planning/fleet-respawn.d.ts.map +1 -0
  423. package/dist/internal/planning/fleet-respawn.js +167 -0
  424. package/dist/internal/planning/fleet-respawn.js.map +1 -0
  425. package/dist/internal/planning/fleet-ship-assembly.d.ts +36 -0
  426. package/dist/internal/planning/fleet-ship-assembly.d.ts.map +1 -0
  427. package/dist/internal/planning/fleet-ship-assembly.js +138 -0
  428. package/dist/internal/planning/fleet-ship-assembly.js.map +1 -0
  429. package/dist/internal/planning/fleet-state.d.ts +25 -0
  430. package/dist/internal/planning/fleet-state.d.ts.map +1 -0
  431. package/dist/internal/planning/fleet-state.js +28 -0
  432. package/dist/internal/planning/fleet-state.js.map +1 -0
  433. package/dist/internal/planning/governance-fees.d.ts +64 -0
  434. package/dist/internal/planning/governance-fees.d.ts.map +1 -0
  435. package/dist/internal/planning/governance-fees.js +239 -0
  436. package/dist/internal/planning/governance-fees.js.map +1 -0
  437. package/dist/internal/planning/local-market-order-funding.d.ts +8 -0
  438. package/dist/internal/planning/local-market-order-funding.d.ts.map +1 -0
  439. package/dist/internal/planning/local-market-order-funding.js +127 -0
  440. package/dist/internal/planning/local-market-order-funding.js.map +1 -0
  441. package/dist/internal/planning/local-market-order.d.ts +40 -0
  442. package/dist/internal/planning/local-market-order.d.ts.map +1 -0
  443. package/dist/internal/planning/local-market-order.js +138 -0
  444. package/dist/internal/planning/local-market-order.js.map +1 -0
  445. package/dist/internal/planning/mining-stop.d.ts +14 -0
  446. package/dist/internal/planning/mining-stop.d.ts.map +1 -0
  447. package/dist/internal/planning/mining-stop.js +41 -0
  448. package/dist/internal/planning/mining-stop.js.map +1 -0
  449. package/dist/internal/planning/movement-character.d.ts +7 -0
  450. package/dist/internal/planning/movement-character.d.ts.map +1 -0
  451. package/dist/internal/planning/movement-character.js +41 -0
  452. package/dist/internal/planning/movement-character.js.map +1 -0
  453. package/dist/internal/planning/movement-xp-guard.d.ts +4 -0
  454. package/dist/internal/planning/movement-xp-guard.d.ts.map +1 -0
  455. package/dist/internal/planning/movement-xp-guard.js +103 -0
  456. package/dist/internal/planning/movement-xp-guard.js.map +1 -0
  457. package/dist/internal/planning/open-signal-guard.d.ts +3 -0
  458. package/dist/internal/planning/open-signal-guard.d.ts.map +1 -0
  459. package/dist/internal/planning/open-signal-guard.js +31 -0
  460. package/dist/internal/planning/open-signal-guard.js.map +1 -0
  461. package/dist/internal/planning/open-signal.d.ts +31 -0
  462. package/dist/internal/planning/open-signal.d.ts.map +1 -0
  463. package/dist/internal/planning/open-signal.js +86 -0
  464. package/dist/internal/planning/open-signal.js.map +1 -0
  465. package/dist/internal/planning/original-token.d.ts +34 -0
  466. package/dist/internal/planning/original-token.d.ts.map +1 -0
  467. package/dist/internal/planning/original-token.js +98 -0
  468. package/dist/internal/planning/original-token.js.map +1 -0
  469. package/dist/internal/planning/plan-fields.d.ts +59 -0
  470. package/dist/internal/planning/plan-fields.d.ts.map +1 -0
  471. package/dist/internal/planning/plan-fields.js +153 -0
  472. package/dist/internal/planning/plan-fields.js.map +1 -0
  473. package/dist/internal/planning/plan-guards.d.ts +4 -0
  474. package/dist/internal/planning/plan-guards.d.ts.map +1 -0
  475. package/dist/internal/planning/plan-guards.js +168 -0
  476. package/dist/internal/planning/plan-guards.js.map +1 -0
  477. package/dist/internal/planning/recipe-state.d.ts +6 -0
  478. package/dist/internal/planning/recipe-state.d.ts.map +1 -0
  479. package/dist/internal/planning/recipe-state.js +20 -0
  480. package/dist/internal/planning/recipe-state.js.map +1 -0
  481. package/dist/internal/planning/rent.d.ts +19 -0
  482. package/dist/internal/planning/rent.d.ts.map +1 -0
  483. package/dist/internal/planning/rent.js +35 -0
  484. package/dist/internal/planning/rent.js.map +1 -0
  485. package/dist/internal/planning/respawn-guards.d.ts +3 -0
  486. package/dist/internal/planning/respawn-guards.d.ts.map +1 -0
  487. package/dist/internal/planning/respawn-guards.js +41 -0
  488. package/dist/internal/planning/respawn-guards.js.map +1 -0
  489. package/dist/internal/planning/runtime-guards.d.ts +41 -0
  490. package/dist/internal/planning/runtime-guards.d.ts.map +1 -0
  491. package/dist/internal/planning/runtime-guards.js +635 -0
  492. package/dist/internal/planning/runtime-guards.js.map +1 -0
  493. package/dist/internal/planning/scan-completion-guard.d.ts +43 -0
  494. package/dist/internal/planning/scan-completion-guard.d.ts.map +1 -0
  495. package/dist/internal/planning/scan-completion-guard.js +94 -0
  496. package/dist/internal/planning/scan-completion-guard.js.map +1 -0
  497. package/dist/internal/planning/scan-completion.d.ts +20 -0
  498. package/dist/internal/planning/scan-completion.d.ts.map +1 -0
  499. package/dist/internal/planning/scan-completion.js +197 -0
  500. package/dist/internal/planning/scan-completion.js.map +1 -0
  501. package/dist/internal/planning/scan-detect-guard.d.ts +34 -0
  502. package/dist/internal/planning/scan-detect-guard.d.ts.map +1 -0
  503. package/dist/internal/planning/scan-detect-guard.js +77 -0
  504. package/dist/internal/planning/scan-detect-guard.js.map +1 -0
  505. package/dist/internal/planning/scan-detect.d.ts +24 -0
  506. package/dist/internal/planning/scan-detect.d.ts.map +1 -0
  507. package/dist/internal/planning/scan-detect.js +245 -0
  508. package/dist/internal/planning/scan-detect.js.map +1 -0
  509. package/dist/internal/planning/scan-input.d.ts +9 -0
  510. package/dist/internal/planning/scan-input.d.ts.map +1 -0
  511. package/dist/internal/planning/scan-input.js +58 -0
  512. package/dist/internal/planning/scan-input.js.map +1 -0
  513. package/dist/internal/planning/ship-import-funding.d.ts +22 -0
  514. package/dist/internal/planning/ship-import-funding.d.ts.map +1 -0
  515. package/dist/internal/planning/ship-import-funding.js +53 -0
  516. package/dist/internal/planning/ship-import-funding.js.map +1 -0
  517. package/dist/internal/planning/ship-token.d.ts +1 -6
  518. package/dist/internal/planning/ship-token.d.ts.map +1 -1
  519. package/dist/internal/planning/ship-token.js +2 -41
  520. package/dist/internal/planning/ship-token.js.map +1 -1
  521. package/dist/internal/planning/starbase-player-owner.d.ts +21 -0
  522. package/dist/internal/planning/starbase-player-owner.d.ts.map +1 -0
  523. package/dist/internal/planning/starbase-player-owner.js +17 -0
  524. package/dist/internal/planning/starbase-player-owner.js.map +1 -0
  525. package/dist/internal/planning/starbase-system-guard.d.ts +6 -0
  526. package/dist/internal/planning/starbase-system-guard.d.ts.map +1 -0
  527. package/dist/internal/planning/starbase-system-guard.js +93 -0
  528. package/dist/internal/planning/starbase-system-guard.js.map +1 -0
  529. package/dist/internal/planning/starbase-system.d.ts +15 -0
  530. package/dist/internal/planning/starbase-system.d.ts.map +1 -0
  531. package/dist/internal/planning/starbase-system.js +25 -0
  532. package/dist/internal/planning/starbase-system.js.map +1 -0
  533. package/dist/internal/planning/token-mint.d.ts +4 -0
  534. package/dist/internal/planning/token-mint.d.ts.map +1 -0
  535. package/dist/internal/planning/token-mint.js +15 -0
  536. package/dist/internal/planning/token-mint.js.map +1 -0
  537. package/dist/internal/planning/trade-faction-market.d.ts +20 -0
  538. package/dist/internal/planning/trade-faction-market.d.ts.map +1 -0
  539. package/dist/internal/planning/trade-faction-market.js +56 -0
  540. package/dist/internal/planning/trade-faction-market.js.map +1 -0
  541. package/dist/internal/planning/wallet-starbase.d.ts +34 -0
  542. package/dist/internal/planning/wallet-starbase.d.ts.map +1 -0
  543. package/dist/internal/planning/wallet-starbase.js +39 -0
  544. package/dist/internal/planning/wallet-starbase.js.map +1 -0
  545. package/dist/internal/planning/xp-runtime.d.ts +36 -0
  546. package/dist/internal/planning/xp-runtime.d.ts.map +1 -0
  547. package/dist/internal/planning/xp-runtime.js +126 -0
  548. package/dist/internal/planning/xp-runtime.js.map +1 -0
  549. package/dist/internal/system-program.d.ts +4 -0
  550. package/dist/internal/system-program.d.ts.map +1 -0
  551. package/dist/internal/system-program.js +3 -0
  552. package/dist/internal/system-program.js.map +1 -0
  553. package/dist/loyalty/actions/index.d.ts.map +1 -1
  554. package/dist/loyalty/actions/index.js +8 -21
  555. package/dist/loyalty/actions/index.js.map +1 -1
  556. package/dist/loyalty/index.d.ts.map +1 -1
  557. package/dist/loyalty/index.js +2 -6
  558. package/dist/loyalty/index.js.map +1 -1
  559. package/dist/markets/actions/index.d.ts +61 -3
  560. package/dist/markets/actions/index.d.ts.map +1 -1
  561. package/dist/markets/actions/index.js +227 -160
  562. package/dist/markets/actions/index.js.map +1 -1
  563. package/dist/markets/actions/trade-faction-market.d.ts +43 -0
  564. package/dist/markets/actions/trade-faction-market.d.ts.map +1 -0
  565. package/dist/markets/actions/trade-faction-market.js +282 -0
  566. package/dist/markets/actions/trade-faction-market.js.map +1 -0
  567. package/dist/markets/index.d.ts +38 -7
  568. package/dist/markets/index.d.ts.map +1 -1
  569. package/dist/markets/index.js +57 -10
  570. package/dist/markets/index.js.map +1 -1
  571. package/dist/mining/actions/index.d.ts +87 -0
  572. package/dist/mining/actions/index.d.ts.map +1 -0
  573. package/dist/mining/actions/index.js +319 -0
  574. package/dist/mining/actions/index.js.map +1 -0
  575. package/dist/mining/estimate.d.ts +114 -0
  576. package/dist/mining/estimate.d.ts.map +1 -0
  577. package/dist/mining/estimate.js +127 -0
  578. package/dist/mining/estimate.js.map +1 -0
  579. package/dist/mining/index.d.ts +9 -2
  580. package/dist/mining/index.d.ts.map +1 -1
  581. package/dist/mining/index.js +7 -2
  582. package/dist/mining/index.js.map +1 -1
  583. package/dist/mining/profile.d.ts +82 -0
  584. package/dist/mining/profile.d.ts.map +1 -0
  585. package/dist/mining/profile.js +109 -0
  586. package/dist/mining/profile.js.map +1 -0
  587. package/dist/planning/assembly.d.ts +5 -0
  588. package/dist/planning/assembly.d.ts.map +1 -1
  589. package/dist/planning/assembly.js +8 -4
  590. package/dist/planning/assembly.js.map +1 -1
  591. package/dist/planning/execution.d.ts +18 -3
  592. package/dist/planning/execution.d.ts.map +1 -1
  593. package/dist/planning/execution.js +492 -40
  594. package/dist/planning/execution.js.map +1 -1
  595. package/dist/planning/index.d.ts +196 -149
  596. package/dist/planning/index.d.ts.map +1 -1
  597. package/dist/planning/index.js +44 -292
  598. package/dist/planning/index.js.map +1 -1
  599. package/dist/planning/plan-sequence-checkpoint.d.ts +9 -0
  600. package/dist/planning/plan-sequence-checkpoint.d.ts.map +1 -1
  601. package/dist/planning/plan-sequence-checkpoint.js +16 -7
  602. package/dist/planning/plan-sequence-checkpoint.js.map +1 -1
  603. package/dist/planning/plan-sequence-execution.d.ts +5 -0
  604. package/dist/planning/plan-sequence-execution.d.ts.map +1 -1
  605. package/dist/planning/plan-sequence-execution.js +74 -30
  606. package/dist/planning/plan-sequence-execution.js.map +1 -1
  607. package/dist/planning/plan-sequence.d.ts +2 -1
  608. package/dist/planning/plan-sequence.d.ts.map +1 -1
  609. package/dist/planning/plan-sequence.js +8 -1
  610. package/dist/planning/plan-sequence.js.map +1 -1
  611. package/dist/planning/plan-validation.d.ts +14 -0
  612. package/dist/planning/plan-validation.d.ts.map +1 -0
  613. package/dist/planning/plan-validation.js +124 -0
  614. package/dist/planning/plan-validation.js.map +1 -0
  615. package/dist/planning/simulation.d.ts +25 -1
  616. package/dist/planning/simulation.d.ts.map +1 -1
  617. package/dist/planning/simulation.js +111 -11
  618. package/dist/planning/simulation.js.map +1 -1
  619. package/dist/registry/cargo.d.ts +7 -12
  620. package/dist/registry/cargo.d.ts.map +1 -1
  621. package/dist/registry/cargo.js +19 -19
  622. package/dist/registry/cargo.js.map +1 -1
  623. package/dist/registry/docking.d.ts +10 -0
  624. package/dist/registry/docking.d.ts.map +1 -0
  625. package/dist/registry/docking.js +12 -0
  626. package/dist/registry/docking.js.map +1 -0
  627. package/dist/registry/index.d.ts +4 -0
  628. package/dist/registry/index.d.ts.map +1 -1
  629. package/dist/registry/index.js.map +1 -1
  630. package/dist/registry/onboarding.d.ts +10 -2
  631. package/dist/registry/onboarding.d.ts.map +1 -1
  632. package/dist/registry/onboarding.js +20 -7
  633. package/dist/registry/onboarding.js.map +1 -1
  634. package/dist/registry/scanning.d.ts +7 -0
  635. package/dist/registry/scanning.d.ts.map +1 -0
  636. package/dist/registry/scanning.js +13 -0
  637. package/dist/registry/scanning.js.map +1 -0
  638. package/dist/registry/ship-stats-snapshot.js +19 -19
  639. package/dist/registry/ship-stats-snapshot.js.map +1 -1
  640. package/dist/registry/ships.d.ts +22 -2
  641. package/dist/registry/ships.d.ts.map +1 -1
  642. package/dist/registry/ships.js +31 -4
  643. package/dist/registry/ships.js.map +1 -1
  644. package/dist/registry/xp-runtime.d.ts +4 -0
  645. package/dist/registry/xp-runtime.d.ts.map +1 -0
  646. package/dist/registry/xp-runtime.js +14 -0
  647. package/dist/registry/xp-runtime.js.map +1 -0
  648. package/dist/rewards/index.d.ts.map +1 -1
  649. package/dist/rewards/index.js +5 -4
  650. package/dist/rewards/index.js.map +1 -1
  651. package/dist/scanning/actions/index.d.ts +116 -0
  652. package/dist/scanning/actions/index.d.ts.map +1 -0
  653. package/dist/scanning/actions/index.js +185 -0
  654. package/dist/scanning/actions/index.js.map +1 -0
  655. package/dist/scanning/index.d.ts +5 -2
  656. package/dist/scanning/index.d.ts.map +1 -1
  657. package/dist/scanning/index.js +13 -9
  658. package/dist/scanning/index.js.map +1 -1
  659. package/dist/scanning/lifecycle.d.ts +77 -0
  660. package/dist/scanning/lifecycle.d.ts.map +1 -0
  661. package/dist/scanning/lifecycle.js +93 -0
  662. package/dist/scanning/lifecycle.js.map +1 -0
  663. package/dist/scanning/odds.d.ts +111 -0
  664. package/dist/scanning/odds.d.ts.map +1 -0
  665. package/dist/scanning/odds.js +294 -0
  666. package/dist/scanning/odds.js.map +1 -0
  667. package/dist/scanning/signals.d.ts +121 -0
  668. package/dist/scanning/signals.d.ts.map +1 -0
  669. package/dist/scanning/signals.js +171 -0
  670. package/dist/scanning/signals.js.map +1 -0
  671. package/dist/starbases/actions/index.d.ts.map +1 -1
  672. package/dist/starbases/actions/index.js +3 -14
  673. package/dist/starbases/actions/index.js.map +1 -1
  674. package/dist/world/index.d.ts +110 -5
  675. package/dist/world/index.d.ts.map +1 -1
  676. package/dist/world/index.js +109 -4
  677. package/dist/world/index.js.map +1 -1
  678. package/dist/world/planet-claim-stake-plots.d.ts +130 -0
  679. package/dist/world/planet-claim-stake-plots.d.ts.map +1 -0
  680. package/dist/world/planet-claim-stake-plots.js +110 -0
  681. package/dist/world/planet-claim-stake-plots.js.map +1 -0
  682. package/dist/world/starbase-status.d.ts +176 -0
  683. package/dist/world/starbase-status.d.ts.map +1 -0
  684. package/dist/world/starbase-status.js +153 -0
  685. package/dist/world/starbase-status.js.map +1 -0
  686. package/package.json +10 -2
@@ -1,21 +1,41 @@
1
- import { getAddressEncoder, getBytesEncoder, getProgramDerivedAddress, isAddress, } from '@solana/kit';
1
+ import { deriveCurrencyCache, validateCurrencyCache, } from '../../internal/c4/currency-cache.js';
2
+ import { getAddressEncoder, isAddress } from '@solana/kit';
2
3
  import { InvalidActionInputError, SageSdkError } from '../../client/errors.js';
3
4
  import { readContextRawAccounts } from '../../client/reconciliation.js';
4
- import { sage } from '../../internal/c4/bindings.js';
5
+ import { StarbaseLevel } from '../../internal/c4/runtime-bindings.js';
5
6
  import { readFreshGameClaimStakeConfiguration, } from '../../registry/claim-stakes.js';
6
- import { characterAccountDefinition, findCharacterPda, } from '../../internal/c4/identity.js';
7
+ import { characterAccountDefinition, findCharacterPda, } from '../../internal/c4/character.js';
7
8
  import { deriveFactionOwnershipAddress, factionOwnershipAccountDefinition, } from '../../internal/c4/factions.js';
8
9
  import { claimStakeAccountDefinition } from '../../internal/c4/claim-stake.js';
9
- import { deriveFleetCrewBindingAddress, fleetCrewBindingAccountDefinition, } from '../../internal/c4/fleet-crew-binding.js';
10
+ import { factionValue } from '../../internal/c4/faction.js';
11
+ import { deriveFleetCrewBindingAddress, fleetCrewBindingAccountDefinition, matchesFleetCrewBindingIdentity, } from '../../internal/c4/fleet-crew-binding.js';
10
12
  import { deriveFleetAddress, fleetAccountDefinition, } from '../../internal/c4/fleet.js';
11
13
  import { deriveProfileFactionAddress, profileFactionIdentityAccountDefinition, } from '../../internal/c4/profile-faction.js';
12
14
  import { deriveStarbasePlayerAddress, starbasePlayerAccountDefinition, } from '../../internal/c4/starbase.js';
13
- import { celestialBodyAccountDefinition, decodeIndexedCelestialBodyAccount, deriveCelestialBodyAddress, deriveStarSystemAddress, starSystemAccountDefinition, } from '../../internal/c4/world.js';
15
+ import { celestialBodyAccountDefinition, deriveCelestialBodyAddress, deriveStarSystemAddress, starSystemAccountDefinition, } from '../../internal/c4/world.js';
16
+ import { resolveXpRuntime } from '../../internal/planning/xp-runtime.js';
17
+ import { requireProfileStarbasePlayer } from '../../internal/planning/starbase-player-owner.js';
14
18
  import { requireGameAddress } from '../../internal/game-context.js';
15
- import { adaptCancelClaimStakeBuildingChangesInstruction, adaptClaimStakeBuildingChangesInstruction, adaptDeconstructClaimStakeInstruction, adaptFinalizeClaimStakeBuildingChangesInstruction, adaptPlaceClaimStakeInstruction, adaptRecoverClaimStakeFleetTransferInstruction, adaptStartClaimStakeFleetTransferInstruction, adaptTopUpClaimStakeRentInstruction, validatePlanAuthorization, } from '../../internal/planning/authorization-adapter.js';
19
+ import { cargoStorageUnits } from '../../internal/cargo.js';
20
+ import { adaptCancelClaimStakeBuildingChangesInstruction, adaptClaimStakeBuildingChangesInstruction, adaptDeconstructClaimStakeInstruction, adaptFinalizeClaimStakeBuildingChangesInstruction, adaptPlaceClaimStakeInstruction, adaptRecoverClaimStakeFleetTransferInstruction, adaptStartClaimStakeFleetTransferInstruction, adaptTopUpClaimStakeRentInstruction, readPlanAuthorization, } from '../../internal/planning/authorization-adapter.js';
16
21
  import { createPlan, } from '../../planning/index.js';
17
22
  import { readFreshGameCargoDefinitions } from '../../registry/cargo.js';
18
23
  import { resolveCargo } from '../../registry/index.js';
24
+ async function resolveClaimStakeXp(ctx, game, structure, character) {
25
+ const xp = await resolveXpRuntime(ctx, {
26
+ game,
27
+ structure,
28
+ ...(character === undefined ? {} : { character }),
29
+ });
30
+ const guard = {
31
+ kind: 'xp-runtime',
32
+ address: game,
33
+ intent: xp.intent,
34
+ accounts: xp.accounts,
35
+ describes: 'The Game and canonical Claim Stake XP accounts remain supported; accrued XP may change. Initialize or repair missing XP state using the game client, then recreate the Plan.',
36
+ };
37
+ return { accounts: xp.accounts, guard };
38
+ }
19
39
  const U64_MAX = (1n << 64n) - 1n;
20
40
  const U16_MAX = 65_535;
21
41
  const I32_MAX = 2_147_483_647;
@@ -31,13 +51,13 @@ const LEVEL_INDEX = Object.freeze({
31
51
  css: 6,
32
52
  });
33
53
  const CLAIM_STAKE_PLOT_LEVELS = Object.freeze([
34
- sage.StarbaseLevel.Level0,
35
- sage.StarbaseLevel.Level1,
36
- sage.StarbaseLevel.Level2,
37
- sage.StarbaseLevel.Level3,
38
- sage.StarbaseLevel.Level4,
39
- sage.StarbaseLevel.Level5,
40
- sage.StarbaseLevel.Css,
54
+ StarbaseLevel.Level0,
55
+ StarbaseLevel.Level1,
56
+ StarbaseLevel.Level2,
57
+ StarbaseLevel.Level3,
58
+ StarbaseLevel.Level4,
59
+ StarbaseLevel.Level5,
60
+ StarbaseLevel.Css,
41
61
  ]);
42
62
  const TIER_INDEX = Object.freeze({
43
63
  one: 0,
@@ -90,15 +110,7 @@ function validateOptions(value) {
90
110
  'hubBuildingId',
91
111
  'initialRentAmount',
92
112
  ]);
93
- const authorizationRecord = record(options.authorization, 'authorization');
94
- exactKeys(authorizationRecord, 'authorization', ['profile', 'authority', 'keyIndex'], ['certificate']);
95
- const authorization = authorizationRecord;
96
- address(authorization.profile, 'authorization.profile');
97
- address(authorization.authority, 'authorization.authority');
98
- if (authorization.certificate !== undefined) {
99
- address(authorization.certificate, 'authorization.certificate');
100
- }
101
- validatePlanAuthorization(authorization);
113
+ const authorization = readPlanAuthorization(options.authorization);
102
114
  if (typeof options.initialRentAmount !== 'bigint' ||
103
115
  options.initialRentAmount <= 0n ||
104
116
  options.initialRentAmount > U64_MAX) {
@@ -112,22 +124,10 @@ function validateOptions(value) {
112
124
  initialRentAmount: options.initialRentAmount,
113
125
  };
114
126
  }
115
- function validateAuthorization(value) {
116
- const authorizationRecord = record(value, 'authorization');
117
- exactKeys(authorizationRecord, 'authorization', ['profile', 'authority', 'keyIndex'], ['certificate']);
118
- const authorization = authorizationRecord;
119
- address(authorization.profile, 'authorization.profile');
120
- address(authorization.authority, 'authorization.authority');
121
- if (authorization.certificate !== undefined) {
122
- address(authorization.certificate, 'authorization.certificate');
123
- }
124
- validatePlanAuthorization(authorization);
125
- return authorization;
126
- }
127
127
  function validateBuildingChangeOptions(value) {
128
128
  const options = record(value, 'options');
129
129
  exactKeys(options, 'options', ['authorization', 'buildingChanges']);
130
- const authorization = validateAuthorization(options.authorization);
130
+ const authorization = readPlanAuthorization(options.authorization);
131
131
  const values = options.buildingChanges;
132
132
  if (!Array.isArray(values) || values.length === 0) {
133
133
  invalid('buildingChanges', values, 'a non-empty dense array of add/remove building changes', 'Provide at least one exact building change before retrying.');
@@ -168,22 +168,22 @@ function validateBuildingChangeOptions(value) {
168
168
  function validateFinalizeBuildingChangeOptions(value) {
169
169
  const options = record(value, 'options');
170
170
  exactKeys(options, 'options', ['authorization']);
171
- return { authorization: validateAuthorization(options.authorization) };
171
+ return { authorization: readPlanAuthorization(options.authorization) };
172
172
  }
173
173
  function validateCancelBuildingChangeOptions(value) {
174
174
  const options = record(value, 'options');
175
175
  exactKeys(options, 'options', ['authorization']);
176
- return { authorization: validateAuthorization(options.authorization) };
176
+ return { authorization: readPlanAuthorization(options.authorization) };
177
177
  }
178
178
  function validateDeconstructOptions(value) {
179
179
  const options = record(value, 'options');
180
180
  exactKeys(options, 'options', ['authorization']);
181
- return { authorization: validateAuthorization(options.authorization) };
181
+ return { authorization: readPlanAuthorization(options.authorization) };
182
182
  }
183
183
  function validateTopUpRentOptions(value) {
184
184
  const options = record(value, 'options');
185
185
  exactKeys(options, 'options', ['amount', 'authorization']);
186
- const authorization = validateAuthorization(options.authorization);
186
+ const authorization = readPlanAuthorization(options.authorization);
187
187
  if (typeof options.amount !== 'bigint' ||
188
188
  options.amount <= 0n ||
189
189
  options.amount > U64_MAX) {
@@ -220,7 +220,7 @@ function validateCargoRequests(value, field, seen) {
220
220
  function validateStartFleetTransferOptions(value) {
221
221
  const options = record(value, 'options');
222
222
  exactKeys(options, 'options', ['authorization', 'load', 'unload']);
223
- const authorization = validateAuthorization(options.authorization);
223
+ const authorization = readPlanAuthorization(options.authorization);
224
224
  const seen = new Set();
225
225
  const load = validateCargoRequests(options.load, 'load', seen);
226
226
  const unload = validateCargoRequests(options.unload, 'unload', seen);
@@ -232,7 +232,7 @@ function validateStartFleetTransferOptions(value) {
232
232
  function validateRecoverFleetTransferOptions(value) {
233
233
  const options = record(value, 'options');
234
234
  exactKeys(options, 'options', ['atUnixSeconds', 'authorization']);
235
- const authorization = validateAuthorization(options.authorization);
235
+ const authorization = readPlanAuthorization(options.authorization);
236
236
  if (typeof options.atUnixSeconds !== 'bigint' ||
237
237
  options.atUnixSeconds < 0n ||
238
238
  options.atUnixSeconds > U64_MAX) {
@@ -240,27 +240,6 @@ function validateRecoverFleetTransferOptions(value) {
240
240
  }
241
241
  return { atUnixSeconds: options.atUnixSeconds, authorization };
242
242
  }
243
- async function deriveCurrencyCacheAddress(game) {
244
- const [derived] = await getProgramDerivedAddress({
245
- programAddress: sage.SAGE_PROGRAM_ADDRESS,
246
- seeds: [
247
- getBytesEncoder().encode(new TextEncoder().encode('CurrencyConfig')),
248
- getAddressEncoder().encode(game),
249
- ],
250
- });
251
- return derived;
252
- }
253
- function validateCurrencyCache(account, game, canonicalAddress, action) {
254
- const decoder = sage.getCurrencyConfigCacheDecoder();
255
- const validDiscriminator = sage.CURRENCY_CONFIG_CACHE_DISCRIMINATOR.every((byte, index) => account.data[index] === byte);
256
- if (account.address !== canonicalAddress ||
257
- account.owner !== sage.SAGE_PROGRAM_ADDRESS ||
258
- account.data.length !== decoder.fixedSize ||
259
- !validDiscriminator ||
260
- decoder.decode(account.data).gameId !== game) {
261
- fail(`CurrencyCache ${account.address} does not match the configured Game, canonical PDA, owner, or pinned account layout. Refresh the Game currency configuration and retry ${action}.`, account.address);
262
- }
263
- }
264
243
  function requireAccount(account, accountAddress, message) {
265
244
  return account ?? fail(message, accountAddress);
266
245
  }
@@ -332,17 +311,7 @@ export async function planPlaceClaimStake(ctx, body, player, input) {
332
311
  if (canonicalBody !== body.address) {
333
312
  fail(`Celestial Body ${body.address} is not the canonical Body ${String(body.id)} for the configured Game. Refresh the Body and retry.`, body.address);
334
313
  }
335
- if (player.playerProfile.address !== options.authorization.profile) {
336
- fail(`Starbase Player ${player.address} does not belong to authorization Profile ${options.authorization.profile}. Refresh the Starbase Player for that Profile and retry.`, player.address);
337
- }
338
- const character = await findCharacterPda(options.authorization.profile, game);
339
- if (player.character.address !== character) {
340
- fail(`Starbase Player ${player.address} does not reference the canonical Character ${character} for authorization Profile ${options.authorization.profile}. Refresh the Starbase Player and retry.`, player.address);
341
- }
342
- const canonicalPlayer = await deriveStarbasePlayerAddress(player.system.address, character);
343
- if (canonicalPlayer !== player.address) {
344
- fail(`Starbase Player ${player.address} is not canonical for its Character and System. Refresh the Starbase Player and retry.`, player.address);
345
- }
314
+ const character = await requireProfileStarbasePlayer(player, options.authorization.profile, game);
346
315
  if (body.system.address !== player.system.address) {
347
316
  fail(`Celestial Body ${body.address} belongs to System ${body.system.address}, but Starbase Player ${player.address} belongs to System ${player.system.address}. Choose both snapshots from the same System and retry.`, body.address);
348
317
  }
@@ -385,11 +354,10 @@ export async function planPlaceClaimStake(ctx, body, player, input) {
385
354
  }
386
355
  const currentBodyAccount = requireAccount(bodyAccount, body.address, `Celestial Body ${body.address} is missing. Refresh the Body and retry placement.`);
387
356
  const currentPlayerAccount = requireAccount(playerAccount, player.address, `Starbase Player ${player.address} is missing. Refresh it and retry placement.`);
388
- const currentCharacterAccount = requireAccount(characterAccount, character, `Canonical Character ${character} is missing. Refresh the Profile Character and retry placement.`);
389
357
  const currentSystemAccount = requireAccount(systemAccount, body.system.address, `Star System ${body.system.address} is missing. Refresh the System and retry placement.`);
390
358
  const currentBody = celestialBodyAccountDefinition.decode(currentBodyAccount);
391
359
  const currentPlayer = starbasePlayerAccountDefinition.decode(currentPlayerAccount);
392
- const currentCharacter = characterAccountDefinition.decode(currentCharacterAccount);
360
+ const { account: currentCharacterAccount } = requireProfileCharacter(characterAccount, character, options.authorization.profile, game, 'placement');
393
361
  const currentSystem = starSystemAccountDefinition.decode(currentSystemAccount);
394
362
  const canonicalSystem = await deriveStarSystemAddress(game, currentSystem.systemId);
395
363
  if (canonicalSystem !== body.system.address ||
@@ -411,10 +379,6 @@ export async function planPlaceClaimStake(ctx, body, player, input) {
411
379
  currentPlayer.totalCrew - currentPlayer.busyCrew !== player.availableCrew) {
412
380
  fail(`Starbase Player ${player.address} changed or does not match the authorization Profile, canonical Character, System, or available crew. Refresh it and retry.`, player.address);
413
381
  }
414
- if (currentCharacter.playerProfile !== options.authorization.profile ||
415
- currentCharacter.game !== game) {
416
- fail(`Character ${character} does not match authorization Profile ${options.authorization.profile} and configured Game ${game}. Refresh the Character and retry.`, character);
417
- }
418
382
  const currentCargo = currentPlayer.cargo.amounts.find(({ cargoId }) => cargoId === definition.cargoId)?.amount ?? 0n;
419
383
  if (currentCargo !== cargoQuantity || currentCargo < 1n) {
420
384
  fail(`Starbase Player ${player.address} Claim Stake cargo changed from the loaded snapshot or is no longer sufficient. Refresh its cargo and retry.`, player.address);
@@ -432,7 +396,7 @@ export async function planPlaceClaimStake(ctx, body, player, input) {
432
396
  fail(`Planet ${body.name} (${body.address}) has no available ${definition.name} plot at Starbase ${currentSystem.starbase.level}; ${String(usedPlots)} of ${String(plotLimit)} known plots are occupied. Choose another eligible Planet or tier, refresh it, and retry.`, body.address);
433
397
  }
434
398
  const profileFaction = await deriveProfileFactionAddress(options.authorization.profile);
435
- const currencyCache = await deriveCurrencyCacheAddress(game);
399
+ const currencyCache = await deriveCurrencyCache(game).then(([address]) => address);
436
400
  const description = `Place ${definition.name} on Planet ${body.name} (${body.address}) with bundled hub ${hub.name}, ${String(hub.neededCrew)} crew, and ${String(options.initialRentAmount)} raw initial rent.`;
437
401
  return createPlan({
438
402
  kind: 'claim-stakes.place',
@@ -441,7 +405,7 @@ export async function planPlaceClaimStake(ctx, body, player, input) {
441
405
  precondition(freshGame.account, `The configured Game retains Claim Stake definition ${String(definition.id)} and bundled hub ${String(hub.id)} eligibility.`),
442
406
  precondition(currentBodyAccount, `Planet ${body.name} retains an available ${definition.name} plot and its configured Game/System relationship.`),
443
407
  precondition(currentPlayerAccount, `Starbase Player ${player.address} retains its Profile, Character, System, available crew, and ${cargoName} balance.`),
444
- precondition(currentCharacterAccount, `The canonical Character remains assigned to Profile ${options.authorization.profile} in the configured Game.`),
408
+ characterPrecondition(currentCharacterAccount, options.authorization.profile),
445
409
  precondition(currentSystemAccount, `Star System ${currentSystem.name} retains its configured Game, sequence, and active Starbase level.`),
446
410
  ])),
447
411
  absentPrecondition(options.claimStake, 'The caller-supplied Claim Stake signer address remains unallocated.'),
@@ -492,12 +456,165 @@ function sameStakeState(left, right) {
492
456
  sameQuantities(left.buildings, right.buildings));
493
457
  }
494
458
  }
495
- const LEGACY_CONTROLLER_ID = Object.freeze({
496
- unaligned: 0,
497
- mud: 1,
498
- oni: 2,
499
- ustur: 3,
500
- });
459
+ // Common facts for planners acting on an owned, placed Claim Stake. Each
460
+ // planner keeps its own eligibility checks and Plan wording at its call site;
461
+ // `action` completes the shared remedies ("retry <action>").
462
+ /** Requires the loaded Claim Stake to belong to the configured Game and to the
463
+ * authorization Profile's canonical Character, which it returns. */
464
+ async function requireOwnedStake(stake, game, profile) {
465
+ if (stake.game !== game) {
466
+ fail(`Claim Stake ${stake.address} does not match the configured Game ${game}. Refresh it through this context and retry.`, stake.address);
467
+ }
468
+ const character = await findCharacterPda(profile, game);
469
+ if (stake.ownerCharacter.address !== character) {
470
+ fail(`Claim Stake ${stake.address} does not belong to authorization Profile ${profile}'s canonical Character ${character}. Choose an owned Claim Stake, refresh it, and retry.`, stake.address);
471
+ }
472
+ return character;
473
+ }
474
+ /** Reads and decodes the fresh Claim Stake and Body, with `extra` accounts in
475
+ * the same batch. */
476
+ async function readOwnedStake(ctx, stake, action, extra = []) {
477
+ const [stakeCandidate, bodyCandidate, ...extraAccounts] = await readContextRawAccounts(ctx, [
478
+ stake.address,
479
+ stake.body.address,
480
+ ...extra,
481
+ ]);
482
+ const stakeAccount = requireAccount(stakeCandidate, stake.address, `Claim Stake ${stake.address} is missing. Refresh it and retry ${action}.`);
483
+ const bodyAccount = requireAccount(bodyCandidate, stake.body.address, `Celestial Body ${stake.body.address} is missing. Refresh the Claim Stake Body and retry ${action}.`);
484
+ return {
485
+ bodyAccount,
486
+ currentBody: celestialBodyAccountDefinition.decode(bodyAccount),
487
+ currentStake: claimStakeAccountDefinition.decode(stakeAccount),
488
+ extraAccounts,
489
+ stakeAccount,
490
+ };
491
+ }
492
+ /** Whether the fresh Claim Stake keeps the loaded ownership, Body,
493
+ * definitions, buildings and System generation. */
494
+ function sameOwnedStake(current, stake, game, character) {
495
+ return (current.game === game &&
496
+ current.body === stake.body.address &&
497
+ current.ownerCharacter === character &&
498
+ current.claimStakeDefinitionId === stake.claimStakeDefinitionId &&
499
+ current.claimStakeDefinitionSeqId === stake.claimStakeDefinitionSeqId &&
500
+ current.buildingDefinitionSeqId === stake.buildingDefinitionSeqId &&
501
+ current.systemSeqId === stake.systemSeqId &&
502
+ sameQuantities(current.buildings, stake.buildings));
503
+ }
504
+ /** Whether the fresh Claim Stake keeps the loaded transfer facts: ownership,
505
+ * Body, active state, System generation, resources and capacity. */
506
+ function sameTransferStake(current, stake, game, character) {
507
+ return (current.game === game &&
508
+ current.ownerCharacter === character &&
509
+ current.body === stake.body.address &&
510
+ current.systemSeqId === stake.systemSeqId &&
511
+ current.state.kind === 'active' &&
512
+ current.production.cargoPod.storageCost ===
513
+ stake.resources.capacity.usedRaw &&
514
+ current.production.resourceCapacityRaw ===
515
+ stake.resources.capacity.totalRaw &&
516
+ sameCargoAmounts(current.production.cargoPod.amounts, stake.resources.inventory.items.map(({ id, quantityRaw }) => ({
517
+ amount: quantityRaw,
518
+ id,
519
+ }))));
520
+ }
521
+ /** Whether the fresh Fleet keeps the loaded Game, owner, name, cargo and
522
+ * capacities. */
523
+ function sameTransferFleet(current, fleet, game, profile) {
524
+ return (current.game === game &&
525
+ current.ownerProfile === profile &&
526
+ current.name === fleet.name &&
527
+ current.ammoBank.cargoId === fleet.ammo.id &&
528
+ current.ammoBank.amount === fleet.ammo.amount &&
529
+ current.fuelTank.cargoId === fleet.fuel.id &&
530
+ current.fuelTank.amount === fleet.fuel.amount &&
531
+ current.cargoHold.storageCost === fleet.cargoHold.storageCost &&
532
+ sameCargoAmounts(current.cargoHold.amounts, fleet.cargoHold.items) &&
533
+ current.stats.cargo.ammoCapacity === fleet.capacities.ammo.total &&
534
+ current.stats.cargo.fuelCapacity === fleet.capacities.fuel.total &&
535
+ current.stats.cargo.cargoCapacity === fleet.capacities.cargo.total);
536
+ }
537
+ /** Requires the fresh Body to be the Claim Stake's canonical Planet in the
538
+ * configured Game at the Claim Stake's System generation. */
539
+ async function requireStakePlanet(currentBody, stake, game, action) {
540
+ if (currentBody.kind !== 'planet' ||
541
+ currentBody.game !== game ||
542
+ currentBody.systemSequenceId !== stake.systemSeqId ||
543
+ (await deriveCelestialBodyAddress(game, currentBody.id)) !==
544
+ stake.body.address) {
545
+ fail(`Celestial Body ${stake.body.address} does not match the Claim Stake's configured Game, canonical Planet identity, or System generation. Refresh the Body and Claim Stake before retrying ${action}.`, stake.body.address);
546
+ }
547
+ return currentBody;
548
+ }
549
+ /** Requires and decodes the canonical Character of the authorization Profile in
550
+ * the configured Game. */
551
+ function requireProfileCharacter(candidate, character, profile, game, action) {
552
+ const account = requireAccount(candidate, character, `Canonical Character ${character} is missing. Refresh the Profile Character and retry ${action}.`);
553
+ const current = characterAccountDefinition.decode(account);
554
+ if (current.playerProfile !== profile || current.game !== game) {
555
+ fail(`Character ${character} does not match authorization Profile ${profile} and configured Game ${game}. Refresh the Character and retry ${action}.`, character);
556
+ }
557
+ return { account, current };
558
+ }
559
+ /** Reads the Claim Stake's System and the authorization Profile's canonical
560
+ * Starbase Player there, with `extra` accounts in the same batch. Requires a
561
+ * canonical, current System with an active Starbase that lists the Body, and a
562
+ * Starbase Player of the Profile, Character and System. */
563
+ async function readStakeStarbase(ctx, stake, game, system, character, profile, action, extra = []) {
564
+ const player = await deriveStarbasePlayerAddress(system, character);
565
+ const [systemCandidate, playerCandidate, ...extraAccounts] = await readContextRawAccounts(ctx, [system, player, ...extra]);
566
+ const systemAccount = requireAccount(systemCandidate, system, `Star System ${system} is missing. Refresh the Claim Stake's System and retry ${action}.`);
567
+ const playerAccount = requireAccount(playerCandidate, player, `Starbase Player ${player} is missing for authorization Profile ${profile}. Register or refresh it in the Claim Stake's System before retrying ${action}.`);
568
+ const currentSystem = starSystemAccountDefinition.decode(systemAccount);
569
+ const currentPlayer = starbasePlayerAccountDefinition.decode(playerAccount);
570
+ if (currentSystem.game !== game ||
571
+ currentSystem.sequenceId !== stake.systemSeqId ||
572
+ currentSystem.starbase === undefined ||
573
+ !currentSystem.celestialBodyAddresses.includes(stake.body.address) ||
574
+ (await deriveStarSystemAddress(game, currentSystem.systemId)) !== system) {
575
+ fail(`Star System ${system} does not match the configured Game, canonical identity, Claim Stake generation, active nested Starbase, or Claim Stake Body relationship. Refresh the System and retry ${action}.`, system);
576
+ }
577
+ if (currentPlayer.playerProfile !== profile ||
578
+ currentPlayer.character !== character ||
579
+ currentPlayer.system !== system) {
580
+ fail(`Starbase Player ${player} does not match the authorization Profile, canonical Character, and Claim Stake System. Refresh it and retry ${action}.`, player);
581
+ }
582
+ return {
583
+ currentPlayer,
584
+ currentSystem,
585
+ extraAccounts,
586
+ player,
587
+ playerAccount,
588
+ starbase: currentSystem.starbase,
589
+ systemAccount,
590
+ };
591
+ }
592
+ async function claimStakeCurrencyCache(game) {
593
+ const [currencyCache] = await deriveCurrencyCache(game);
594
+ return currencyCache;
595
+ }
596
+ /** Requires the canonical CurrencyCache and returns its Plan guard. */
597
+ async function requireCurrencyCache(candidate, currencyCache, game, action, planName) {
598
+ await validateCurrencyCache(requireAccount(candidate, currencyCache, `Canonical CurrencyCache ${currencyCache} is missing for configured Game ${game}. Refresh the Game currency configuration and retry ${action}.`), game, planName);
599
+ return {
600
+ kind: 'currency-cache',
601
+ address: currencyCache,
602
+ game,
603
+ describes: 'The canonical CurrencyCache remains assigned to the configured Game; shared accounting may change.',
604
+ };
605
+ }
606
+ function planetPrecondition(account, system) {
607
+ return precondition(account, `The Claim Stake Planet remains assigned to System ${system} at the current generation.`);
608
+ }
609
+ function characterPrecondition(account, profile) {
610
+ return precondition(account, `The canonical Character remains assigned to Profile ${profile} in the configured Game.`);
611
+ }
612
+ function systemPrecondition(account, name) {
613
+ return precondition(account, `Star System ${name} retains its configured Game, sequence, nested Starbase, and Claim Stake Body relationship.`);
614
+ }
615
+ function playerPrecondition(account, player, facts = 'Profile, Character, and System') {
616
+ return precondition(account, `Starbase Player ${player} retains its ${facts}.`);
617
+ }
501
618
  function buildingDescription(change, name) {
502
619
  return `${change.kind} ${String(change.quantity)} ${name}`;
503
620
  }
@@ -509,6 +626,9 @@ function buildingDescription(change, name) {
509
626
  * construction cargo. Rent synchronization and the final concurrent sequence
510
627
  * race remain chain-authoritative.
511
628
  *
629
+ * Requires Game 2 and its existing canonical Claim Stake XP ledger.
630
+ * Missing XP state must be repaired outside this Plan; no accounts are created.
631
+ *
512
632
  * @example
513
633
  * ```ts
514
634
  * declare const ctx: SageContext;
@@ -521,85 +641,37 @@ function buildingDescription(change, name) {
521
641
  export async function planClaimStakeBuildingChanges(ctx, stake, input) {
522
642
  const options = validateBuildingChangeOptions(input);
523
643
  const game = requireGameAddress(ctx);
644
+ const { profile } = options.authorization;
524
645
  if (stake.state.kind === 'deactivated') {
525
646
  fail(`Claim Stake ${stake.address} is deactivated; building changes require an active or design Claim Stake. Refresh it or choose another owned Claim Stake before retrying.`, stake.address);
526
647
  }
527
- if (stake.game !== game) {
528
- fail(`Claim Stake ${stake.address} does not match the configured Game ${game}. Refresh it through this context and retry.`, stake.address);
529
- }
530
- const character = await findCharacterPda(options.authorization.profile, game);
531
- if (stake.ownerCharacter.address !== character) {
532
- fail(`Claim Stake ${stake.address} does not belong to authorization Profile ${options.authorization.profile}'s canonical Character ${character}. Choose an owned Claim Stake, refresh it, and retry.`, stake.address);
533
- }
534
- const [freshGame, firstAccounts] = await Promise.all([
648
+ const character = await requireOwnedStake(stake, game, profile);
649
+ const action = 'building changes';
650
+ const [freshGame, loaded] = await Promise.all([
535
651
  readFreshGameClaimStakeConfiguration(ctx),
536
- readContextRawAccounts(ctx, [stake.address, stake.body.address, character]),
652
+ readOwnedStake(ctx, stake, action, [character]),
537
653
  ]);
538
654
  if (freshGame === undefined) {
539
655
  fail(`Configured Game ${game} is missing. Refresh the Game catalog and retry building changes.`, game);
540
656
  }
541
- const stakeAccount = requireAccount(firstAccounts[0], stake.address, `Claim Stake ${stake.address} is missing. Refresh it and retry building changes.`);
542
- const bodyAccount = requireAccount(firstAccounts[1], stake.body.address, `Celestial Body ${stake.body.address} is missing. Refresh the Claim Stake Body and retry building changes.`);
543
- const characterAccount = requireAccount(firstAccounts[2], character, `Canonical Character ${character} is missing. Refresh the Profile Character and retry building changes.`);
544
- const currentStake = claimStakeAccountDefinition.decode(stakeAccount);
545
- const currentBody = celestialBodyAccountDefinition.decode(bodyAccount);
546
- const currentCharacter = characterAccountDefinition.decode(characterAccount);
547
- if (currentStake.game !== game ||
548
- currentStake.body !== stake.body.address ||
549
- currentStake.ownerCharacter !== character ||
550
- currentStake.claimStakeDefinitionId !== stake.claimStakeDefinitionId ||
551
- currentStake.claimStakeDefinitionSeqId !==
552
- stake.claimStakeDefinitionSeqId ||
553
- currentStake.buildingDefinitionSeqId !== stake.buildingDefinitionSeqId ||
554
- currentStake.systemSeqId !== stake.systemSeqId ||
555
- !sameQuantities(currentStake.buildings, stake.buildings) ||
657
+ const { bodyAccount, currentStake, stakeAccount } = loaded;
658
+ if (!sameOwnedStake(currentStake, stake, game, character) ||
556
659
  currentStake.neededCrew !== stake.neededCrew) {
557
660
  fail(`Claim Stake ${stake.address} changed or does not match its loaded ownership, Body, definitions, buildings, crew, or System generation. Refresh it and retry building changes.`, stake.address);
558
661
  }
559
- if (currentCharacter.playerProfile !== options.authorization.profile ||
560
- currentCharacter.game !== game) {
561
- fail(`Character ${character} does not match authorization Profile ${options.authorization.profile} and configured Game ${game}. Refresh the Character and retry building changes.`, character);
562
- }
563
- if (currentBody.kind !== 'planet' ||
564
- currentBody.game !== game ||
565
- currentBody.systemSequenceId !== stake.systemSeqId ||
566
- (await deriveCelestialBodyAddress(game, currentBody.id)) !==
567
- stake.body.address) {
568
- fail(`Celestial Body ${stake.body.address} does not match the Claim Stake's configured Game, canonical Planet identity, or System generation. Refresh the Body and Claim Stake before retrying.`, stake.body.address);
569
- }
570
- const system = currentBody.system;
571
- const [player, ownership, profileFaction] = await Promise.all([
572
- deriveStarbasePlayerAddress(system, character),
662
+ const { system } = await requireStakePlanet(loaded.currentBody, stake, game, action);
663
+ const { account: characterAccount } = requireProfileCharacter(loaded.extraAccounts[0], character, profile, game, action);
664
+ const [ownership, profileFaction] = await Promise.all([
573
665
  deriveFactionOwnershipAddress(game, 'starbase', system),
574
- deriveProfileFactionAddress(options.authorization.profile),
575
- ]);
576
- const [systemAccountCandidate, playerAccountCandidate, ownershipAccount, profileFactionAccountCandidate,] = await readContextRawAccounts(ctx, [
577
- system,
578
- player,
579
- ownership,
580
- profileFaction,
666
+ deriveProfileFactionAddress(profile),
581
667
  ]);
582
- const systemAccount = requireAccount(systemAccountCandidate, system, `Star System ${system} is missing. Refresh the Claim Stake's System and retry building changes.`);
583
- const playerAccount = requireAccount(playerAccountCandidate, player, `Starbase Player ${player} is missing for authorization Profile ${options.authorization.profile}. Register or refresh it in the Claim Stake's System before retrying.`);
584
- const profileFactionAccount = requireAccount(profileFactionAccountCandidate, profileFaction, `ProfileFaction ${profileFaction} is missing for authorization Profile ${options.authorization.profile}. Choose or repair the Profile faction, refresh it, and retry building changes.`);
585
- const currentSystem = starSystemAccountDefinition.decode(systemAccount);
586
- const currentPlayer = starbasePlayerAccountDefinition.decode(playerAccount);
668
+ const { currentPlayer, currentSystem, extraAccounts: [ownershipAccount, profileFactionCandidate], player, playerAccount, starbase, systemAccount, } = await readStakeStarbase(ctx, stake, game, system, character, profile, action, [ownership, profileFaction]);
669
+ const profileFactionAccount = requireAccount(profileFactionCandidate, profileFaction, `ProfileFaction ${profileFaction} is missing for authorization Profile ${profile}. Choose or repair the Profile faction, refresh it, and retry building changes.`);
587
670
  const currentProfileFaction = profileFactionIdentityAccountDefinition.decode(profileFactionAccount);
588
- if (currentSystem.game !== game ||
589
- currentSystem.sequenceId !== stake.systemSeqId ||
590
- currentSystem.starbase === undefined ||
591
- (await deriveStarSystemAddress(game, currentSystem.systemId)) !== system) {
592
- fail(`Star System ${system} does not match the configured Game, canonical identity, Claim Stake generation, or an active nested Starbase. Refresh the System and retry building changes.`, system);
593
- }
594
- if (currentPlayer.playerProfile !== options.authorization.profile ||
595
- currentPlayer.character !== character ||
596
- currentPlayer.system !== system) {
597
- fail(`Starbase Player ${player} does not match the authorization Profile, canonical Character, and Claim Stake System. Refresh it and retry building changes.`, player);
671
+ if (currentProfileFaction.profile !== profile) {
672
+ fail(`ProfileFaction ${profileFaction} does not match authorization Profile ${profile}. Refresh or repair the Profile faction before retrying building changes.`, profileFaction);
598
673
  }
599
- if (currentProfileFaction.profile !== options.authorization.profile) {
600
- fail(`ProfileFaction ${profileFaction} does not match authorization Profile ${options.authorization.profile}. Refresh or repair the Profile faction before retrying building changes.`, profileFaction);
601
- }
602
- let controllerFactionId = LEGACY_CONTROLLER_ID[currentSystem.starbase.owner];
674
+ let controllerFactionId = factionValue(starbase.owner);
603
675
  let ownershipPrecondition;
604
676
  if (ownershipAccount === undefined) {
605
677
  ownershipPrecondition = absentPrecondition(ownership, `The canonical Starbase FactionOwnership ${ownership} remains unallocated so the chain applies its legacy controller gate.`);
@@ -744,26 +816,29 @@ export async function planClaimStakeBuildingChanges(ctx, stake, input) {
744
816
  if (currentStake.production.cargoPod.storageCost > resourceStorageRaw) {
745
817
  fail(`The resulting Claim Stake design provides ${String(resourceStorageRaw)} raw storage capacity, below the fresh known cargo usage of ${String(currentStake.production.cargoPod.storageCost)}. Keep enough storage buildings, remove cargo, refresh the Claim Stake, and retry building changes.`, stake.address);
746
818
  }
747
- const currencyCache = await deriveCurrencyCacheAddress(game);
819
+ const currencyCache = await claimStakeCurrencyCache(game);
748
820
  const description = `Change buildings on Claim Stake ${stake.address}: ${descriptions.join('; ')}.`;
821
+ const xp = await resolveClaimStakeXp(ctx, game, stake.address);
749
822
  return createPlan({
750
823
  kind: 'claim-stakes.building-changes',
751
824
  preconditions: [
752
825
  ...(await Promise.all([
753
826
  precondition(freshGame.account, 'The configured Game retains the exact Claim Stake and building definitions.'),
754
827
  precondition(stakeAccount, `Claim Stake ${stake.address} retains its ownership, design sequence, buildings, cargo, crew, and Body relationship.`),
755
- precondition(bodyAccount, `The Claim Stake Planet remains assigned to System ${system} at the current generation.`),
756
- precondition(characterAccount, `The canonical Character remains assigned to Profile ${options.authorization.profile} in the configured Game.`),
757
- precondition(systemAccount, `Star System ${currentSystem.name} retains its configured Game, sequence, and nested Starbase.`),
758
- precondition(playerAccount, `Starbase Player ${player} retains its Profile, Character, System, and available crew.`),
759
- precondition(profileFactionAccount, `ProfileFaction ${profileFaction} remains assigned to Profile ${options.authorization.profile} and aligned with the current Starbase controller.`),
828
+ planetPrecondition(bodyAccount, system),
829
+ characterPrecondition(characterAccount, profile),
830
+ systemPrecondition(systemAccount, currentSystem.name),
831
+ playerPrecondition(playerAccount, player, 'Profile, Character, System, and available crew'),
832
+ precondition(profileFactionAccount, `ProfileFaction ${profileFaction} remains assigned to Profile ${profile} and aligned with the current Starbase controller.`),
760
833
  ])),
761
834
  ownershipPrecondition,
835
+ xp.guard,
762
836
  ],
763
837
  steps: [
764
838
  {
765
839
  describes: description,
766
840
  instruction: adaptClaimStakeBuildingChangesInstruction({
841
+ ...xp.accounts,
767
842
  authorization: options.authorization,
768
843
  buildingChanges: options.buildingChanges.map(({ buildingId, kind, quantity }) => [buildingId, kind === 'add' ? quantity : -quantity]),
769
844
  celestialBody: stake.body.address,
@@ -789,6 +864,10 @@ export async function planClaimStakeBuildingChanges(ctx, stake, input) {
789
864
  * CurrencyCache, and a known positive rent balance. Rent timing and the final
790
865
  * crew/building validation remain chain-authoritative.
791
866
  *
867
+ * Requires Game 2 and its existing canonical Claim Stake XP ledger.
868
+ * The Character XP budget and configuration must also be reconciled.
869
+ * Missing XP state must be repaired outside this Plan; no accounts are created.
870
+ *
792
871
  * @example
793
872
  * ```ts
794
873
  * declare const ctx: SageContext;
@@ -804,22 +883,18 @@ export async function planClaimStakeBuildingChanges(ctx, stake, input) {
804
883
  export async function planFinalizeClaimStakeBuildingChanges(ctx, stake, input) {
805
884
  const options = validateFinalizeBuildingChangeOptions(input);
806
885
  const game = requireGameAddress(ctx);
886
+ const { profile } = options.authorization;
807
887
  if (stake.state.kind !== 'design') {
808
888
  fail(`Claim Stake ${stake.address} is not in design state. Refresh it and finalize only a pending building design.`, stake.address);
809
889
  }
810
- if (stake.game !== game) {
811
- fail(`Claim Stake ${stake.address} does not match the configured Game ${game}. Refresh it through this context and retry.`, stake.address);
812
- }
813
- const character = await findCharacterPda(options.authorization.profile, game);
814
- if (stake.ownerCharacter.address !== character) {
815
- fail(`Claim Stake ${stake.address} does not belong to authorization Profile ${options.authorization.profile}'s canonical Character ${character}. Choose an owned Claim Stake, refresh it, and retry.`, stake.address);
816
- }
890
+ const character = await requireOwnedStake(stake, game, profile);
817
891
  if (stake.rentBalanceRaw <= 0n) {
818
892
  fail(`Claim Stake ${stake.address} has a known delinquent rent balance of ${String(stake.rentBalanceRaw)} raw units. Top up rent, refresh the Claim Stake, and retry finalization.`, stake.address);
819
893
  }
820
- const [freshGame, firstAccounts] = await Promise.all([
894
+ const action = 'finalization';
895
+ const [freshGame, loaded] = await Promise.all([
821
896
  readFreshGameClaimStakeConfiguration(ctx),
822
- readContextRawAccounts(ctx, [stake.address, stake.body.address, character]),
897
+ readOwnedStake(ctx, stake, action, [character]),
823
898
  ]);
824
899
  if (freshGame === undefined) {
825
900
  fail(`Configured Game ${game} is missing. Refresh the Game catalog and retry finalization.`, game);
@@ -828,75 +903,40 @@ export async function planFinalizeClaimStakeBuildingChanges(ctx, stake, input) {
828
903
  freshGame.data.buildings.sequenceId !== stake.buildingDefinitionSeqId) {
829
904
  fail(`Claim Stake ${stake.address} definition sequence is stale against the current Game catalog. Refresh the Claim Stake and definitions to rule out stale local data. If the on-chain generation still differs, use a Claim Stake matching the current catalog before retrying finalization.`, stake.address);
830
905
  }
831
- const stakeAccount = requireAccount(firstAccounts[0], stake.address, `Claim Stake ${stake.address} is missing. Refresh it and retry finalization.`);
832
- const bodyAccount = requireAccount(firstAccounts[1], stake.body.address, `Celestial Body ${stake.body.address} is missing. Refresh the Claim Stake Body and retry finalization.`);
833
- const characterAccount = requireAccount(firstAccounts[2], character, `Canonical Character ${character} is missing. Refresh the Profile Character and retry finalization.`);
834
- const currentStake = claimStakeAccountDefinition.decode(stakeAccount);
835
- const currentBody = celestialBodyAccountDefinition.decode(bodyAccount);
836
- const currentCharacter = characterAccountDefinition.decode(characterAccount);
837
- if (currentStake.game !== game ||
838
- currentStake.body !== stake.body.address ||
839
- currentStake.ownerCharacter !== character ||
840
- currentStake.claimStakeDefinitionId !== stake.claimStakeDefinitionId ||
841
- currentStake.claimStakeDefinitionSeqId !==
842
- stake.claimStakeDefinitionSeqId ||
843
- currentStake.buildingDefinitionSeqId !== stake.buildingDefinitionSeqId ||
844
- currentStake.systemSeqId !== stake.systemSeqId ||
906
+ const { bodyAccount, currentStake, stakeAccount } = loaded;
907
+ if (!sameOwnedStake(currentStake, stake, game, character) ||
845
908
  currentStake.rentBalanceRaw !== stake.rentBalanceRaw ||
846
- !sameQuantities(currentStake.buildings, stake.buildings) ||
847
909
  currentStake.state.kind !== 'design' ||
848
910
  currentStake.state.sequenceId !== stake.state.sequenceId ||
849
911
  !sameQuantities(currentStake.state.buildings, stake.state.buildings)) {
850
912
  fail(`Claim Stake ${stake.address} changed or does not match its loaded ownership, Body, definitions, buildings, design sequence, rent, or System generation. Refresh it and retry finalization.`, stake.address);
851
913
  }
852
- if (currentCharacter.playerProfile !== options.authorization.profile ||
853
- currentCharacter.game !== game) {
854
- fail(`Character ${character} does not match authorization Profile ${options.authorization.profile} and configured Game ${game}. Refresh the Character and retry finalization.`, character);
855
- }
856
- if (currentBody.kind !== 'planet' ||
857
- currentBody.game !== game ||
858
- currentBody.systemSequenceId !== stake.systemSeqId ||
859
- (await deriveCelestialBodyAddress(game, currentBody.id)) !==
860
- stake.body.address) {
861
- fail(`Celestial Body ${stake.body.address} does not match the Claim Stake's configured Game, canonical Planet identity, or System generation. Refresh the Body and Claim Stake before retrying finalization.`, stake.body.address);
862
- }
863
- const system = currentBody.system;
864
- const player = await deriveStarbasePlayerAddress(system, character);
865
- const currencyCache = await deriveCurrencyCacheAddress(game);
866
- const [systemCandidate, playerCandidate, currencyCandidate] = await readContextRawAccounts(ctx, [system, player, currencyCache]);
867
- const systemAccount = requireAccount(systemCandidate, system, `Star System ${system} is missing. Refresh the Claim Stake's System and retry finalization.`);
868
- const playerAccount = requireAccount(playerCandidate, player, `Starbase Player ${player} is missing for authorization Profile ${options.authorization.profile}. Register or refresh it in the Claim Stake's System before retrying finalization.`);
869
- const currencyAccount = requireAccount(currencyCandidate, currencyCache, `Canonical CurrencyCache ${currencyCache} is missing for configured Game ${game}. Refresh the Game currency configuration and retry finalization.`);
870
- const currentSystem = starSystemAccountDefinition.decode(systemAccount);
871
- const currentPlayer = starbasePlayerAccountDefinition.decode(playerAccount);
872
- if (currentSystem.game !== game ||
873
- currentSystem.sequenceId !== stake.systemSeqId ||
874
- currentSystem.starbase === undefined ||
875
- (await deriveStarSystemAddress(game, currentSystem.systemId)) !== system) {
876
- fail(`Star System ${system} does not match the configured Game, canonical identity, Claim Stake generation, or an active nested Starbase. Refresh the System and retry finalization.`, system);
877
- }
878
- if (currentPlayer.playerProfile !== options.authorization.profile ||
879
- currentPlayer.character !== character ||
880
- currentPlayer.system !== system) {
881
- fail(`Starbase Player ${player} does not match the authorization Profile, canonical Character, and Claim Stake System. Refresh it and retry finalization.`, player);
882
- }
883
- validateCurrencyCache(currencyAccount, game, currencyCache, 'finalization');
914
+ const { system } = await requireStakePlanet(loaded.currentBody, stake, game, action);
915
+ const { account: characterAccount } = requireProfileCharacter(loaded.extraAccounts[0], character, profile, game, action);
916
+ const currencyCache = await claimStakeCurrencyCache(game);
917
+ const { currentSystem, extraAccounts: [currencyCandidate], player, playerAccount, systemAccount, } = await readStakeStarbase(ctx, stake, game, system, character, profile, action, [currencyCache]);
918
+ const currencyGuard = await requireCurrencyCache(currencyCandidate, currencyCache, game, action, 'Claim Stake finalization');
884
919
  const description = `Finalize building changes on Claim Stake ${stake.address}.`;
920
+ const xp = await resolveClaimStakeXp(ctx, game, stake.address, character);
885
921
  return createPlan({
886
922
  kind: 'claim-stakes.finalize-building-changes',
887
- preconditions: await Promise.all([
888
- precondition(freshGame.account, 'The configured Game remains current.'),
889
- precondition(stakeAccount, `Claim Stake ${stake.address} retains its ownership, design sequence, rent balance, Body, and System generation.`),
890
- precondition(characterAccount, `The canonical Character remains assigned to Profile ${options.authorization.profile} in the configured Game.`),
891
- precondition(bodyAccount, `The Claim Stake Planet remains assigned to System ${system} at the current generation.`),
892
- precondition(systemAccount, `Star System ${currentSystem.name} retains its configured Game, sequence, and nested Starbase.`),
893
- precondition(playerAccount, `Starbase Player ${player} retains its Profile, Character, and System.`),
894
- precondition(currencyAccount, 'The canonical CurrencyCache remains assigned to the configured Game.'),
895
- ]),
923
+ preconditions: [
924
+ xp.guard,
925
+ ...(await Promise.all([
926
+ precondition(freshGame.account, 'The configured Game remains current.'),
927
+ precondition(stakeAccount, `Claim Stake ${stake.address} retains its ownership, design sequence, rent balance, Body, and System generation.`),
928
+ characterPrecondition(characterAccount, profile),
929
+ planetPrecondition(bodyAccount, system),
930
+ systemPrecondition(systemAccount, currentSystem.name),
931
+ playerPrecondition(playerAccount, player),
932
+ ])),
933
+ currencyGuard,
934
+ ],
896
935
  steps: [
897
936
  {
898
937
  describes: description,
899
938
  instruction: adaptFinalizeClaimStakeBuildingChangesInstruction({
939
+ ...xp.accounts,
900
940
  authorization: options.authorization,
901
941
  celestialBody: stake.body.address,
902
942
  character,
@@ -920,6 +960,9 @@ export async function planFinalizeClaimStakeBuildingChanges(ctx, stake, input) {
920
960
  * state; rent arithmetic and concurrent state transitions remain
921
961
  * chain-authoritative.
922
962
  *
963
+ * Requires Game 2 and its existing canonical Claim Stake XP ledger.
964
+ * Missing XP state must be repaired outside this Plan; no accounts are created.
965
+ *
923
966
  * @example
924
967
  * ```ts
925
968
  * declare const ctx: SageContext;
@@ -934,80 +977,42 @@ export async function planFinalizeClaimStakeBuildingChanges(ctx, stake, input) {
934
977
  export async function planCancelClaimStakeBuildingChanges(ctx, stake, input) {
935
978
  const options = validateCancelBuildingChangeOptions(input);
936
979
  const game = requireGameAddress(ctx);
980
+ const { profile } = options.authorization;
937
981
  if (stake.state.kind !== 'design') {
938
982
  fail(`Claim Stake ${stake.address} is not in design state. Refresh it and cancel only a pending building design.`, stake.address);
939
983
  }
940
- if (stake.game !== game) {
941
- fail(`Claim Stake ${stake.address} does not match the configured Game ${game}. Refresh it through this context and retry.`, stake.address);
942
- }
943
- const character = await findCharacterPda(options.authorization.profile, game);
944
- if (stake.ownerCharacter.address !== character) {
945
- fail(`Claim Stake ${stake.address} does not belong to authorization Profile ${options.authorization.profile}'s canonical Character ${character}. Choose an owned Claim Stake, refresh it, and retry.`, stake.address);
946
- }
947
- const firstAccounts = await readContextRawAccounts(ctx, [
948
- stake.address,
949
- stake.body.address,
950
- ]);
951
- const stakeAccount = requireAccount(firstAccounts[0], stake.address, `Claim Stake ${stake.address} is missing. Refresh it and retry cancellation.`);
952
- const bodyAccount = requireAccount(firstAccounts[1], stake.body.address, `Celestial Body ${stake.body.address} is missing. Refresh the Claim Stake Body and retry cancellation.`);
953
- const currentStake = claimStakeAccountDefinition.decode(stakeAccount);
954
- const currentBody = celestialBodyAccountDefinition.decode(bodyAccount);
955
- if (currentStake.game !== game ||
956
- currentStake.body !== stake.body.address ||
957
- currentStake.ownerCharacter !== character ||
958
- currentStake.claimStakeDefinitionId !== stake.claimStakeDefinitionId ||
959
- currentStake.claimStakeDefinitionSeqId !==
960
- stake.claimStakeDefinitionSeqId ||
961
- currentStake.buildingDefinitionSeqId !== stake.buildingDefinitionSeqId ||
962
- currentStake.systemSeqId !== stake.systemSeqId ||
963
- !sameQuantities(currentStake.buildings, stake.buildings) ||
984
+ const character = await requireOwnedStake(stake, game, profile);
985
+ const action = 'cancellation';
986
+ const { bodyAccount, currentBody, currentStake, stakeAccount } = await readOwnedStake(ctx, stake, action);
987
+ if (!sameOwnedStake(currentStake, stake, game, character) ||
964
988
  currentStake.state.kind !== 'design' ||
965
989
  currentStake.state.sequenceId !== stake.state.sequenceId ||
966
990
  !sameQuantities(currentStake.state.buildings, stake.state.buildings)) {
967
991
  fail(`Claim Stake ${stake.address} changed or does not match its loaded ownership, Body, definitions, buildings, design sequence, or System generation. Refresh it and retry cancellation.`, stake.address);
968
992
  }
969
- if (currentBody.kind !== 'planet' ||
970
- currentBody.game !== game ||
971
- currentBody.systemSequenceId !== stake.systemSeqId ||
972
- (await deriveCelestialBodyAddress(game, currentBody.id)) !==
973
- stake.body.address) {
974
- fail(`Celestial Body ${stake.body.address} does not match the Claim Stake's configured Game, canonical Planet identity, or System generation. Refresh the Body and Claim Stake before retrying cancellation.`, stake.body.address);
975
- }
976
- const system = currentBody.system;
977
- const player = await deriveStarbasePlayerAddress(system, character);
978
- const currencyCache = await deriveCurrencyCacheAddress(game);
979
- const [systemCandidate, playerCandidate, currencyCandidate] = await readContextRawAccounts(ctx, [system, player, currencyCache]);
980
- const systemAccount = requireAccount(systemCandidate, system, `Star System ${system} is missing. Refresh the Claim Stake's System and retry cancellation.`);
981
- const playerAccount = requireAccount(playerCandidate, player, `Starbase Player ${player} is missing for authorization Profile ${options.authorization.profile}. Register or refresh it in the Claim Stake's System before retrying cancellation.`);
982
- const currencyAccount = requireAccount(currencyCandidate, currencyCache, `Canonical CurrencyCache ${currencyCache} is missing for configured Game ${game}. Refresh the Game currency configuration and retry cancellation.`);
983
- const currentSystem = starSystemAccountDefinition.decode(systemAccount);
984
- const currentPlayer = starbasePlayerAccountDefinition.decode(playerAccount);
985
- if (currentSystem.game !== game ||
986
- currentSystem.sequenceId !== stake.systemSeqId ||
987
- currentSystem.starbase === undefined ||
988
- (await deriveStarSystemAddress(game, currentSystem.systemId)) !== system) {
989
- fail(`Star System ${system} does not match the configured Game, canonical identity, Claim Stake generation, or an active nested Starbase. Refresh the System and retry cancellation.`, system);
990
- }
991
- if (currentPlayer.playerProfile !== options.authorization.profile ||
992
- currentPlayer.character !== character ||
993
- currentPlayer.system !== system) {
994
- fail(`Starbase Player ${player} does not match the authorization Profile, canonical Character, and Claim Stake System. Refresh it and retry cancellation.`, player);
995
- }
996
- validateCurrencyCache(currencyAccount, game, currencyCache, 'cancellation');
993
+ const { system } = await requireStakePlanet(currentBody, stake, game, action);
994
+ const currencyCache = await claimStakeCurrencyCache(game);
995
+ const { currentSystem, extraAccounts: [currencyCandidate], player, playerAccount, systemAccount, } = await readStakeStarbase(ctx, stake, game, system, character, profile, action, [currencyCache]);
996
+ const currencyGuard = await requireCurrencyCache(currencyCandidate, currencyCache, game, action, 'Claim Stake cancellation');
997
997
  const description = `Cancel the pending building design on Claim Stake ${stake.address} and return it to active state.`;
998
+ const xp = await resolveClaimStakeXp(ctx, game, stake.address);
998
999
  return createPlan({
999
1000
  kind: 'claim-stakes.cancel-building-changes',
1000
- preconditions: await Promise.all([
1001
- precondition(stakeAccount, `Claim Stake ${stake.address} retains its ownership, design sequence, buildings, Body, and System generation.`),
1002
- precondition(bodyAccount, `The Claim Stake Planet remains assigned to System ${system} at the current generation.`),
1003
- precondition(systemAccount, `Star System ${currentSystem.name} retains its configured Game, sequence, and nested Starbase.`),
1004
- precondition(playerAccount, `Starbase Player ${player} retains its Profile, Character, and System.`),
1005
- precondition(currencyAccount, 'The canonical CurrencyCache remains assigned to the configured Game.'),
1006
- ]),
1001
+ preconditions: [
1002
+ xp.guard,
1003
+ ...(await Promise.all([
1004
+ precondition(stakeAccount, `Claim Stake ${stake.address} retains its ownership, design sequence, buildings, Body, and System generation.`),
1005
+ planetPrecondition(bodyAccount, system),
1006
+ systemPrecondition(systemAccount, currentSystem.name),
1007
+ playerPrecondition(playerAccount, player),
1008
+ ])),
1009
+ currencyGuard,
1010
+ ],
1007
1011
  steps: [
1008
1012
  {
1009
1013
  describes: description,
1010
1014
  instruction: adaptCancelClaimStakeBuildingChangesInstruction({
1015
+ ...xp.accounts,
1011
1016
  authorization: options.authorization,
1012
1017
  celestialBody: stake.body.address,
1013
1018
  claimStakeInstance: stake.address,
@@ -1043,46 +1048,25 @@ export async function planCancelClaimStakeBuildingChanges(ctx, stake, input) {
1043
1048
  export async function planDeconstructClaimStake(ctx, stake, input) {
1044
1049
  const options = validateDeconstructOptions(input);
1045
1050
  const game = requireGameAddress(ctx);
1051
+ const { profile } = options.authorization;
1046
1052
  if (stake.state.kind !== 'active') {
1047
1053
  fail(`Claim Stake ${stake.address} is not in active state. Refresh it, finalize or cancel any pending design, and retry deconstruction.`, stake.address);
1048
1054
  }
1049
- if (stake.game !== game) {
1050
- fail(`Claim Stake ${stake.address} does not match the configured Game ${game}. Refresh it through this context and retry.`, stake.address);
1051
- }
1052
- const character = await findCharacterPda(options.authorization.profile, game);
1053
- if (stake.ownerCharacter.address !== character) {
1054
- fail(`Claim Stake ${stake.address} does not belong to authorization Profile ${options.authorization.profile}'s canonical Character ${character}. Choose an owned Claim Stake, refresh it, and retry.`, stake.address);
1055
- }
1056
- const [freshGame, firstAccounts] = await Promise.all([
1055
+ const character = await requireOwnedStake(stake, game, profile);
1056
+ const action = 'deconstruction';
1057
+ const [freshGame, { bodyAccount, currentBody, currentStake, stakeAccount }] = await Promise.all([
1057
1058
  readFreshGameClaimStakeConfiguration(ctx),
1058
- readContextRawAccounts(ctx, [stake.address, stake.body.address]),
1059
+ readOwnedStake(ctx, stake, action),
1059
1060
  ]);
1060
1061
  if (freshGame === undefined) {
1061
1062
  fail(`Configured Game ${game} is missing. Refresh the Game definitions and retry deconstruction.`, game);
1062
1063
  }
1063
- const stakeAccount = requireAccount(firstAccounts[0], stake.address, `Claim Stake ${stake.address} is missing. Refresh it and retry deconstruction.`);
1064
- const bodyAccount = requireAccount(firstAccounts[1], stake.body.address, `Celestial Body ${stake.body.address} is missing. Refresh the Claim Stake Body and retry deconstruction.`);
1065
- const currentStake = claimStakeAccountDefinition.decode(stakeAccount);
1066
- const currentBody = decodeIndexedCelestialBodyAccount(bodyAccount);
1067
- if (currentStake.game !== game ||
1068
- currentStake.body !== stake.body.address ||
1069
- currentStake.ownerCharacter !== character ||
1070
- currentStake.claimStakeDefinitionId !== stake.claimStakeDefinitionId ||
1071
- currentStake.claimStakeDefinitionSeqId !==
1072
- stake.claimStakeDefinitionSeqId ||
1073
- currentStake.buildingDefinitionSeqId !== stake.buildingDefinitionSeqId ||
1074
- currentStake.systemSeqId !== stake.systemSeqId ||
1075
- !sameQuantities(currentStake.buildings, stake.buildings) ||
1064
+ if (!sameOwnedStake(currentStake, stake, game, character) ||
1076
1065
  currentStake.state.kind !== 'active') {
1077
1066
  fail(`Claim Stake ${stake.address} changed or does not match its loaded ownership, Body, definitions, buildings, active state, or System generation. Refresh it and retry deconstruction.`, stake.address);
1078
1067
  }
1079
- if (currentBody.kind !== 'planet' ||
1080
- currentBody.game !== game ||
1081
- currentBody.systemSequenceId !== stake.systemSeqId ||
1082
- (await deriveCelestialBodyAddress(game, currentBody.id)) !==
1083
- stake.body.address) {
1084
- fail(`Celestial Body ${stake.body.address} does not match the Claim Stake's configured Game, canonical Planet identity, or System generation. Refresh the Body and Claim Stake before retrying deconstruction.`, stake.body.address);
1085
- }
1068
+ const planet = await requireStakePlanet(currentBody, stake, game, action);
1069
+ const { system } = planet;
1086
1070
  if (freshGame.data.claimStakes.sequenceId !== stake.claimStakeDefinitionSeqId) {
1087
1071
  fail(`Claim Stake ${stake.address} definition generation is stale against the current Game catalog. Refresh the Claim Stake and definitions to rule out stale local data. If the on-chain generation still differs, use a Claim Stake matching the current catalog before retrying deconstruction.`, stake.address);
1088
1072
  }
@@ -1104,18 +1088,19 @@ export async function planDeconstructClaimStake(ctx, stake, input) {
1104
1088
  bundledHub.hubValue !== claimDefinition.hubValue ||
1105
1089
  bundledHub.minimumTier !== claimDefinition.tier ||
1106
1090
  bundledHub.constructionCost.length !== 0) {
1091
+ // Only a building with a construction cost is player-funded; a zero-cost
1092
+ // hub from another definition family is a foreign bundled hub.
1107
1093
  const hasPlayerFundedBuilding = stake.buildings.some((building) => {
1108
1094
  const definition = definitions.get(building.buildingId);
1109
- return (definition === undefined ||
1110
- definition.hubValue !== claimDefinition.hubValue ||
1111
- definition.minimumTier !== claimDefinition.tier ||
1112
- definition.constructionCost.length !== 0);
1095
+ return (definition !== undefined && definition.constructionCost.length !== 0);
1113
1096
  });
1114
1097
  fail(hasPlayerFundedBuilding
1115
1098
  ? `Claim Stake ${stake.address} still contains a player-funded building. Remove and finalize every player-funded building so only its verified bundled hub remains before retrying deconstruction.`
1116
- : `Claim Stake ${stake.address} does not contain exactly one verified bundled hub. Refresh it and restore the definition-compatible bundled hub before retrying deconstruction.`, stake.address);
1099
+ : bundledHub === undefined
1100
+ ? `Claim Stake ${stake.address} does not contain exactly one verified bundled hub. Refresh it and restore the definition-compatible bundled hub before retrying deconstruction.`
1101
+ : `Claim Stake ${stake.address} holds ${bundledHub.name} (${String(bundledHub.id)}), which is not the zero-cost ${claimDefinition.tier} bundled hub for Claim Stake definition ${String(claimDefinition.id)} (${claimDefinition.name}). Refresh the Claim Stake and Game definitions so the recorded hub matches its definition before retrying deconstruction.`, stake.address);
1117
1102
  }
1118
- const groups = currentBody.details.claimedPlots.filter(({ key }) => key === claimDefinition.id);
1103
+ const groups = planet.details.claimedPlots.filter(({ key }) => key === claimDefinition.id);
1119
1104
  if (groups.length !== 1) {
1120
1105
  fail(`Claim Stake definition ${String(claimDefinition.id)} does not have exactly one coherent group in Planet ${stake.body.address}'s Claim Stake Body data. Refresh the Body before retrying deconstruction.`, stake.body.address);
1121
1106
  }
@@ -1132,7 +1117,7 @@ export async function planDeconstructClaimStake(ctx, stake, input) {
1132
1117
  }
1133
1118
  const claimStakeIndex = chronologyMatches[0].index;
1134
1119
  const tierIndex = TIER_INDEX[claimDefinition.tier];
1135
- const plotCapacities = currentBody.details.claimStakePlots.map((row) => row[tierIndex]);
1120
+ const plotCapacities = planet.details.claimStakePlots.map((row) => row[tierIndex]);
1136
1121
  if (plotCapacities.some((capacity, index) => index > 0 && capacity < plotCapacities[index - 1])) {
1137
1122
  fail(`Planet ${stake.body.address} Claim Stake plot capacity is not coherent across Starbase levels for definition tier ${claimDefinition.tier}. Refresh the Body and verify the pinned binding version before retrying deconstruction.`, stake.body.address);
1138
1123
  }
@@ -1141,31 +1126,8 @@ export async function planDeconstructClaimStake(ctx, stake, input) {
1141
1126
  }
1142
1127
  const plotLevelIndex = plotCapacities.findIndex((capacity) => claimStakeIndex < capacity);
1143
1128
  const claimStakeLevel = CLAIM_STAKE_PLOT_LEVELS[plotLevelIndex];
1144
- const system = currentBody.system;
1145
- const player = await deriveStarbasePlayerAddress(system, character);
1146
- const [characterCandidate, systemCandidate, playerCandidate] = await readContextRawAccounts(ctx, [character, system, player]);
1147
- const characterAccount = requireAccount(characterCandidate, character, `Canonical Character ${character} is missing. Refresh the Profile Character and retry deconstruction.`);
1148
- const systemAccount = requireAccount(systemCandidate, system, `Star System ${system} is missing. Refresh the Claim Stake's System and retry deconstruction.`);
1149
- const playerAccount = requireAccount(playerCandidate, player, `Starbase Player ${player} is missing for authorization Profile ${options.authorization.profile}. Register or refresh it in the Claim Stake's System before retrying deconstruction.`);
1150
- const currentCharacter = characterAccountDefinition.decode(characterAccount);
1151
- const currentSystem = starSystemAccountDefinition.decode(systemAccount);
1152
- const currentPlayer = starbasePlayerAccountDefinition.decode(playerAccount);
1153
- if (currentCharacter.playerProfile !== options.authorization.profile ||
1154
- currentCharacter.game !== game) {
1155
- fail(`Character ${character} does not match authorization Profile ${options.authorization.profile} and configured Game ${game}. Refresh the Character and retry deconstruction.`, character);
1156
- }
1157
- if (currentSystem.game !== game ||
1158
- currentSystem.sequenceId !== stake.systemSeqId ||
1159
- currentSystem.starbase === undefined ||
1160
- !currentSystem.celestialBodyAddresses.includes(stake.body.address) ||
1161
- (await deriveStarSystemAddress(game, currentSystem.systemId)) !== system) {
1162
- fail(`Star System ${system} does not match the configured Game, canonical identity, Claim Stake generation, or an active nested Starbase. Refresh the System and retry deconstruction.`, system);
1163
- }
1164
- if (currentPlayer.playerProfile !== options.authorization.profile ||
1165
- currentPlayer.character !== character ||
1166
- currentPlayer.system !== system) {
1167
- fail(`Starbase Player ${player} does not match the authorization Profile, canonical Character, and Claim Stake System. Refresh it and retry deconstruction.`, player);
1168
- }
1129
+ const { currentSystem, extraAccounts: [characterCandidate], player, playerAccount, systemAccount, } = await readStakeStarbase(ctx, stake, game, system, character, profile, action, [character]);
1130
+ const { account: characterAccount } = requireProfileCharacter(characterCandidate, character, profile, game, action);
1169
1131
  const description = `Deconstruct Claim Stake ${stake.address} and discard its bundled hub ${bundledHub.name}; rent settlement, cargo return, account closure, and any refund remain chain-authoritative.`;
1170
1132
  return createPlan({
1171
1133
  kind: 'claim-stakes.deconstruct',
@@ -1173,9 +1135,9 @@ export async function planDeconstructClaimStake(ctx, stake, input) {
1173
1135
  precondition(freshGame.account, `The configured Game retains Claim Stake definition ${String(claimDefinition.id)}, bundled hub ${String(bundledHub.id)}, and their current generations.`),
1174
1136
  precondition(stakeAccount, `Claim Stake ${stake.address} retains its ownership, active state, definitions, bundled hub, Body, and System generation.`),
1175
1137
  precondition(bodyAccount, `The Planet retains Claim Stake ${stake.address} at chronology index ${String(claimStakeIndex)} in definition group ${String(claimDefinition.id)}.`),
1176
- precondition(characterAccount, `The canonical Character remains assigned to Profile ${options.authorization.profile} in the configured Game.`),
1177
- precondition(systemAccount, `Star System ${currentSystem.name} retains its configured Game, sequence, nested Starbase, and Claim Stake Body relationship.`),
1178
- precondition(playerAccount, `Starbase Player ${player} retains its Profile, Character, and System.`),
1138
+ characterPrecondition(characterAccount, profile),
1139
+ systemPrecondition(systemAccount, currentSystem.name),
1140
+ playerPrecondition(playerAccount, player),
1179
1141
  ]),
1180
1142
  steps: [
1181
1143
  {
@@ -1219,86 +1181,34 @@ export async function planDeconstructClaimStake(ctx, stake, input) {
1219
1181
  export async function planTopUpClaimStakeRent(ctx, stake, input) {
1220
1182
  const options = validateTopUpRentOptions(input);
1221
1183
  const game = requireGameAddress(ctx);
1184
+ const { profile } = options.authorization;
1222
1185
  const loadedState = stake.state;
1223
1186
  if (loadedState.kind === 'deactivated') {
1224
1187
  fail(`Claim Stake ${stake.address} is not placed. Refresh it and choose an active Claim Stake or pending building design before topping up rent.`, stake.address);
1225
1188
  }
1226
- if (stake.game !== game) {
1227
- fail(`Claim Stake ${stake.address} does not match the configured Game ${game}. Refresh it through this context and retry.`, stake.address);
1228
- }
1229
- const character = await findCharacterPda(options.authorization.profile, game);
1230
- if (stake.ownerCharacter.address !== character) {
1231
- fail(`Claim Stake ${stake.address} does not belong to authorization Profile ${options.authorization.profile}'s canonical Character ${character}. Choose an owned Claim Stake, refresh it, and retry.`, stake.address);
1232
- }
1233
- const firstAccounts = await readContextRawAccounts(ctx, [
1234
- stake.address,
1235
- stake.body.address,
1236
- character,
1237
- ]);
1238
- const stakeAccount = requireAccount(firstAccounts[0], stake.address, `Claim Stake ${stake.address} is missing. Refresh it and retry the rent top-up.`);
1239
- const bodyAccount = requireAccount(firstAccounts[1], stake.body.address, `Celestial Body ${stake.body.address} is missing. Refresh the Claim Stake Body and retry the rent top-up.`);
1240
- const characterAccount = requireAccount(firstAccounts[2], character, `Canonical Character ${character} is missing. Refresh the Profile Character and retry the rent top-up.`);
1241
- const currentStake = claimStakeAccountDefinition.decode(stakeAccount);
1242
- const currentBody = celestialBodyAccountDefinition.decode(bodyAccount);
1243
- const currentCharacter = characterAccountDefinition.decode(characterAccount);
1244
- if (currentStake.game !== game ||
1245
- currentStake.body !== stake.body.address ||
1246
- currentStake.ownerCharacter !== character ||
1247
- currentStake.claimStakeDefinitionId !== stake.claimStakeDefinitionId ||
1248
- currentStake.claimStakeDefinitionSeqId !==
1249
- stake.claimStakeDefinitionSeqId ||
1250
- currentStake.buildingDefinitionSeqId !== stake.buildingDefinitionSeqId ||
1251
- currentStake.systemSeqId !== stake.systemSeqId ||
1189
+ const character = await requireOwnedStake(stake, game, profile);
1190
+ const action = 'the rent top-up';
1191
+ const { bodyAccount, currentBody, currentStake, extraAccounts: [characterCandidate], stakeAccount, } = await readOwnedStake(ctx, stake, action, [character]);
1192
+ if (!sameOwnedStake(currentStake, stake, game, character) ||
1252
1193
  currentStake.rentBalanceRaw !== stake.rentBalanceRaw ||
1253
- !sameQuantities(currentStake.buildings, stake.buildings) ||
1254
1194
  !sameStakeState(currentStake.state, loadedState)) {
1255
1195
  fail(`Claim Stake ${stake.address} changed or does not match its loaded ownership, Body, definitions, buildings, rent balance, placed state, or System generation. Refresh it and retry the rent top-up.`, stake.address);
1256
1196
  }
1257
- if (currentBody.kind !== 'planet' ||
1258
- currentBody.game !== game ||
1259
- currentBody.systemSequenceId !== stake.systemSeqId ||
1260
- (await deriveCelestialBodyAddress(game, currentBody.id)) !==
1261
- stake.body.address) {
1262
- fail(`Celestial Body ${stake.body.address} does not match the Claim Stake's configured Game, canonical Planet identity, or System generation. Refresh the Body and Claim Stake before retrying the rent top-up.`, stake.body.address);
1263
- }
1264
- if (currentCharacter.playerProfile !== options.authorization.profile ||
1265
- currentCharacter.game !== game) {
1266
- fail(`Character ${character} does not match authorization Profile ${options.authorization.profile} and configured Game ${game}. Refresh the Character and retry the rent top-up.`, character);
1267
- }
1197
+ const { system } = await requireStakePlanet(currentBody, stake, game, action);
1198
+ const { account: characterAccount, current: currentCharacter } = requireProfileCharacter(characterCandidate, character, profile, game, action);
1268
1199
  if (currentCharacter.atlasRaw < options.amount) {
1269
1200
  fail(`Character ${character} has only ${String(currentCharacter.atlasRaw)} known raw ATLAS, below the requested ${String(options.amount)} raw rent top-up. Reduce the amount or add ATLAS, refresh the Character, and retry.`, character);
1270
1201
  }
1271
- const system = currentBody.system;
1272
- const player = await deriveStarbasePlayerAddress(system, character);
1273
- const [systemCandidate, playerCandidate] = await readContextRawAccounts(ctx, [
1274
- system,
1275
- player,
1276
- ]);
1277
- const systemAccount = requireAccount(systemCandidate, system, `Star System ${system} is missing. Refresh the Claim Stake's System and retry the rent top-up.`);
1278
- const playerAccount = requireAccount(playerCandidate, player, `Starbase Player ${player} is missing for authorization Profile ${options.authorization.profile}. Register or refresh it in the Claim Stake's System before retrying the rent top-up.`);
1279
- const currentSystem = starSystemAccountDefinition.decode(systemAccount);
1280
- const currentPlayer = starbasePlayerAccountDefinition.decode(playerAccount);
1281
- if (currentSystem.game !== game ||
1282
- currentSystem.sequenceId !== stake.systemSeqId ||
1283
- currentSystem.starbase === undefined ||
1284
- !currentSystem.celestialBodyAddresses.includes(stake.body.address) ||
1285
- (await deriveStarSystemAddress(game, currentSystem.systemId)) !== system) {
1286
- fail(`Star System ${system} does not match the configured Game, canonical identity, Claim Stake generation, active nested Starbase, or Claim Stake Body relationship. Refresh the System and retry the rent top-up.`, system);
1287
- }
1288
- if (currentPlayer.playerProfile !== options.authorization.profile ||
1289
- currentPlayer.character !== character ||
1290
- currentPlayer.system !== system) {
1291
- fail(`Starbase Player ${player} does not match the authorization Profile, canonical Character, and Claim Stake System. Refresh it and retry the rent top-up.`, player);
1292
- }
1202
+ const { currentSystem, player, playerAccount, systemAccount } = await readStakeStarbase(ctx, stake, game, system, character, profile, action);
1293
1203
  const description = `Top up Claim Stake ${stake.address} rent with ${String(options.amount)} raw rent units; rent arithmetic remains chain-authoritative.`;
1294
1204
  return createPlan({
1295
1205
  kind: 'claim-stakes.top-up-rent',
1296
1206
  preconditions: await Promise.all([
1297
1207
  precondition(stakeAccount, `Claim Stake ${stake.address} retains its ownership, rent balance, placed state, Body, and System generation.`),
1298
- precondition(bodyAccount, `The Claim Stake Planet remains assigned to System ${system} at the current generation.`),
1299
- precondition(characterAccount, `The canonical Character remains assigned to Profile ${options.authorization.profile} with at least ${String(options.amount)} known raw ATLAS.`),
1300
- precondition(systemAccount, `Star System ${currentSystem.name} retains its configured Game, sequence, nested Starbase, and Claim Stake Body relationship.`),
1301
- precondition(playerAccount, `Starbase Player ${player} retains its Profile, Character, and System.`),
1208
+ planetPrecondition(bodyAccount, system),
1209
+ precondition(characterAccount, `The canonical Character remains assigned to Profile ${profile} with at least ${String(options.amount)} known raw ATLAS.`),
1210
+ systemPrecondition(systemAccount, currentSystem.name),
1211
+ playerPrecondition(playerAccount, player),
1302
1212
  ]),
1303
1213
  steps: [
1304
1214
  {
@@ -1357,6 +1267,9 @@ function describeCargoRequests(direction, requests) {
1357
1267
  * FleetCrewBinding. The chain remains authoritative for range, duration,
1358
1268
  * permission bits, concurrent state changes, and transfer arithmetic.
1359
1269
  *
1270
+ * Requires Game 2 and its existing canonical Claim Stake XP ledger.
1271
+ * Missing XP state must be repaired outside this Plan; no accounts are created.
1272
+ *
1360
1273
  * @example
1361
1274
  * ```ts
1362
1275
  * declare const ctx: SageContext;
@@ -1374,119 +1287,53 @@ function describeCargoRequests(direction, requests) {
1374
1287
  export async function planStartClaimStakeFleetTransfer(ctx, fleet, stake, input) {
1375
1288
  const options = validateStartFleetTransferOptions(input);
1376
1289
  const game = requireGameAddress(ctx);
1290
+ const { profile } = options.authorization;
1377
1291
  if (fleet.game !== game || stake.game !== game) {
1378
1292
  fail(`Fleet ${fleet.address} and Claim Stake ${stake.address} must both belong to configured Game ${game}. Refresh both snapshots through this context and retry.`, fleet.game !== game ? fleet.address : stake.address);
1379
1293
  }
1380
- if (fleet.ownerProfile.address !== options.authorization.profile) {
1381
- fail(`Fleet ${fleet.name} belongs to Profile ${fleet.ownerProfile.address}, not authorization Profile ${options.authorization.profile}. Use the owning Profile, refresh the Fleet, and retry.`, fleet.address);
1294
+ if (fleet.ownerProfile.address !== profile) {
1295
+ fail(`Fleet ${fleet.name} belongs to Profile ${fleet.ownerProfile.address}, not authorization Profile ${profile}. Use the owning Profile, refresh the Fleet, and retry.`, fleet.address);
1382
1296
  }
1383
1297
  if (fleet.state.kind !== 'idle') {
1384
1298
  fail(`Fleet ${fleet.name} is ${fleet.state.kind}, but starting a Claim Stake transfer requires an idle Fleet. Return it to idle state, refresh it, and retry.`, fleet.address);
1385
1299
  }
1300
+ const crewFailure = `Fleet ${fleet.name} has no valid normalized crew and cannot start a Claim Stake transfer. Crew the Fleet, refresh it, and retry.`;
1386
1301
  if (!Number.isSafeInteger(fleet.crewCount) || fleet.crewCount <= 0) {
1387
- fail(`Fleet ${fleet.name} has no valid normalized crew and cannot start a Claim Stake transfer. Crew the Fleet, refresh it, and retry.`, fleet.address);
1302
+ fail(crewFailure, fleet.address);
1388
1303
  }
1389
1304
  if (stake.state.kind !== 'active') {
1390
1305
  fail(`Claim Stake ${stake.address} is ${stake.state.kind}, but starting a Fleet transfer requires an active Claim Stake. Activate or restore it, refresh it, and retry.`, stake.address);
1391
1306
  }
1392
- const character = await findCharacterPda(options.authorization.profile, game);
1393
- if (stake.ownerCharacter.address !== character) {
1394
- fail(`Claim Stake ${stake.address} does not belong to authorization Profile ${options.authorization.profile}'s canonical Character ${character}. Choose an owned active Claim Stake, refresh it, and retry.`, stake.address);
1395
- }
1396
- const [fleetCandidate, stakeCandidate, bodyCandidate, characterCandidate] = await readContextRawAccounts(ctx, [
1397
- fleet.address,
1398
- stake.address,
1399
- stake.body.address,
1400
- character,
1401
- ]);
1402
- const fleetAccount = requireAccount(fleetCandidate, fleet.address, `Fleet ${fleet.name} is missing. Refresh it and retry the Claim Stake transfer.`);
1403
- const stakeAccount = requireAccount(stakeCandidate, stake.address, `Claim Stake ${stake.address} is missing. Refresh it and retry the Fleet transfer.`);
1404
- const bodyAccount = requireAccount(bodyCandidate, stake.body.address, `Celestial Body ${stake.body.address} is missing. Refresh the Claim Stake Body and retry the Fleet transfer.`);
1405
- const characterAccount = requireAccount(characterCandidate, character, `Canonical Character ${character} is missing. Refresh the Profile Character and retry the Claim Stake transfer.`);
1307
+ const character = await requireOwnedStake(stake, game, profile);
1308
+ const action = 'the Fleet transfer';
1309
+ const { bodyAccount, currentBody, currentStake, extraAccounts: [fleetCandidate, characterCandidate], stakeAccount, } = await readOwnedStake(ctx, stake, action, [fleet.address, character]);
1310
+ const fleetAccount = requireAccount(fleetCandidate, fleet.address, `Fleet ${fleet.name} is missing. Refresh it and retry the Fleet transfer.`);
1406
1311
  const currentFleet = fleetAccountDefinition.decode(fleetAccount);
1407
- const currentStake = claimStakeAccountDefinition.decode(stakeAccount);
1408
- const currentBody = celestialBodyAccountDefinition.decode(bodyAccount);
1409
- const currentCharacter = characterAccountDefinition.decode(characterAccount);
1410
1312
  if (!Number.isSafeInteger(currentFleet.crewCount) ||
1411
1313
  currentFleet.crewCount <= 0) {
1412
- fail(`Fleet ${fleet.name} has no valid normalized crew and cannot start a Claim Stake transfer. Crew the Fleet, refresh it, and retry.`, fleet.address);
1314
+ fail(crewFailure, fleet.address);
1413
1315
  }
1414
- if (currentFleet.game !== game ||
1415
- currentFleet.ownerProfile !== options.authorization.profile ||
1416
- currentFleet.name !== fleet.name ||
1316
+ if (!sameTransferFleet(currentFleet, fleet, game, profile) ||
1417
1317
  currentFleet.state.kind !== 'idle' ||
1418
1318
  currentFleet.crewCount !== fleet.crewCount ||
1419
- (await deriveFleetAddress(currentFleet)) !== fleet.address ||
1420
- currentFleet.ammoBank.cargoId !== fleet.ammo.id ||
1421
- currentFleet.ammoBank.amount !== fleet.ammo.amount ||
1422
- currentFleet.fuelTank.cargoId !== fleet.fuel.id ||
1423
- currentFleet.fuelTank.amount !== fleet.fuel.amount ||
1424
- currentFleet.cargoHold.storageCost !== fleet.cargoHold.storageCost ||
1425
- !sameCargoAmounts(currentFleet.cargoHold.amounts, fleet.cargoHold.items) ||
1426
- currentFleet.stats.cargo.ammoCapacity !== fleet.capacities.ammo.total ||
1427
- currentFleet.stats.cargo.fuelCapacity !== fleet.capacities.fuel.total ||
1428
- currentFleet.stats.cargo.cargoCapacity !== fleet.capacities.cargo.total) {
1319
+ (await deriveFleetAddress(currentFleet)) !== fleet.address) {
1429
1320
  fail(`Fleet ${fleet.name} changed or no longer matches its loaded Game, owner, canonical address, name, idle state, normalized crew, cargo, or capacities. Refresh it and create a new Claim Stake transfer Plan.`, fleet.address);
1430
1321
  }
1431
- if (currentStake.game !== game ||
1432
- currentStake.ownerCharacter !== character ||
1433
- currentStake.body !== stake.body.address ||
1434
- currentStake.systemSeqId !== stake.systemSeqId ||
1435
- currentStake.state.kind !== 'active' ||
1436
- currentStake.production.cargoPod.storageCost !==
1437
- stake.resources.capacity.usedRaw ||
1438
- currentStake.production.resourceCapacityRaw !==
1439
- stake.resources.capacity.totalRaw ||
1440
- !sameCargoAmounts(currentStake.production.cargoPod.amounts, stake.resources.inventory.items.map(({ id, quantityRaw }) => ({
1441
- amount: quantityRaw,
1442
- id,
1443
- })))) {
1322
+ if (!sameTransferStake(currentStake, stake, game, character)) {
1444
1323
  fail(`Claim Stake ${stake.address} changed or no longer matches its loaded Game, owner, Body, active state, resources, capacity, or System generation. Refresh it and create a new Fleet transfer Plan.`, stake.address);
1445
1324
  }
1446
- if (currentBody.kind !== 'planet' ||
1447
- currentBody.game !== game ||
1448
- currentBody.systemSequenceId !== stake.systemSeqId ||
1449
- (await deriveCelestialBodyAddress(game, currentBody.id)) !==
1450
- stake.body.address) {
1451
- fail(`Celestial Body ${stake.body.address} does not match the Claim Stake's configured Game, canonical Planet identity, or System generation. Refresh the Body and Claim Stake before retrying the Fleet transfer.`, stake.body.address);
1452
- }
1453
- if (currentCharacter.playerProfile !== options.authorization.profile ||
1454
- currentCharacter.game !== game) {
1455
- fail(`Character ${character} does not match authorization Profile ${options.authorization.profile} and configured Game ${game}. Refresh the Character and retry the Claim Stake transfer.`, character);
1456
- }
1457
- const system = currentBody.system;
1458
- const player = await deriveStarbasePlayerAddress(system, character);
1459
- const currencyCache = await deriveCurrencyCacheAddress(game);
1460
- const crewBinding = await deriveFleetCrewBindingAddress(fleet.address);
1461
- const [systemCandidate, playerCandidate, currencyCandidate, crewCandidate] = await readContextRawAccounts(ctx, [
1462
- system,
1463
- player,
1464
- currencyCache,
1465
- crewBinding,
1325
+ const { system } = await requireStakePlanet(currentBody, stake, game, action);
1326
+ const { account: characterAccount } = requireProfileCharacter(characterCandidate, character, profile, game, action);
1327
+ const [currencyCache, crewBinding] = await Promise.all([
1328
+ claimStakeCurrencyCache(game),
1329
+ deriveFleetCrewBindingAddress(fleet.address),
1466
1330
  ]);
1467
- const systemAccount = requireAccount(systemCandidate, system, `Star System ${system} is missing. Refresh the Claim Stake System and retry the Fleet transfer.`);
1468
- const playerAccount = requireAccount(playerCandidate, player, `Starbase Player ${player} is missing for authorization Profile ${options.authorization.profile}. Register or refresh it in the Claim Stake System before retrying the Fleet transfer.`);
1469
- const currencyAccount = requireAccount(currencyCandidate, currencyCache, `Canonical CurrencyCache ${currencyCache} is missing for configured Game ${game}. Refresh the Game currency configuration and retry the Fleet transfer.`);
1470
- const currentSystem = starSystemAccountDefinition.decode(systemAccount);
1471
- const currentPlayer = starbasePlayerAccountDefinition.decode(playerAccount);
1472
- if (currentSystem.game !== game ||
1473
- currentSystem.sequenceId !== stake.systemSeqId ||
1474
- currentSystem.starbase === undefined ||
1475
- !currentSystem.celestialBodyAddresses.includes(stake.body.address) ||
1476
- (await deriveStarSystemAddress(game, currentSystem.systemId)) !== system) {
1477
- fail(`Star System ${system} does not match the configured Game, canonical identity, Claim Stake generation, nested Starbase, or Claim Stake Body relationship. Refresh the System and retry the Fleet transfer.`, system);
1478
- }
1479
- if (currentPlayer.playerProfile !== options.authorization.profile ||
1480
- currentPlayer.character !== character ||
1481
- currentPlayer.system !== system) {
1482
- fail(`Starbase Player ${player} does not match the authorization Profile, canonical Character, and Claim Stake System. Refresh it and retry the Fleet transfer.`, player);
1483
- }
1484
- validateCurrencyCache(currencyAccount, game, currencyCache, 'the Claim Stake Fleet transfer');
1331
+ const { currentSystem, extraAccounts: [currencyCandidate, crewCandidate], player, playerAccount, systemAccount, } = await readStakeStarbase(ctx, stake, game, system, character, profile, action, [currencyCache, crewBinding]);
1332
+ const currencyGuard = await requireCurrencyCache(currencyCandidate, currencyCache, game, action, 'Claim Stake Fleet transfer');
1485
1333
  if (crewCandidate !== undefined) {
1486
1334
  const currentCrewBinding = fleetCrewBindingAccountDefinition.decode(crewCandidate);
1487
1335
  if (crewCandidate.address !== crewBinding ||
1488
- currentCrewBinding.fleet !== fleet.address ||
1489
- currentCrewBinding.ownerProfile !== options.authorization.profile) {
1336
+ !matchesFleetCrewBindingIdentity(currentCrewBinding, fleet.address, profile)) {
1490
1337
  fail(`FleetCrewBinding ${crewCandidate.address} does not match Fleet ${fleet.address}, its owner Profile, or its canonical PDA. Refresh the Fleet crew registration or remove the invalid binding before retrying.`, crewCandidate.address);
1491
1338
  }
1492
1339
  }
@@ -1509,37 +1356,43 @@ export async function planStartClaimStakeFleetTransfer(ctx, fleet, stake, input)
1509
1356
  const loadCargoStorage = options.load
1510
1357
  .filter(({ cargoId }) => cargoId !== currentFleet.ammoBank.cargoId &&
1511
1358
  cargoId !== currentFleet.fuelTank.cargoId)
1512
- .reduce((total, { amount, cargoId }) => total + amount * BigInt(definitions.get(cargoId).storageCost), 0n);
1359
+ .reduce((total, { amount, cargoId }) => total +
1360
+ cargoStorageUnits(amount, definitions.get(cargoId).storageCost), 0n);
1513
1361
  requireTransferCapacity(`Fleet ${fleet.name} ammo destination`, fleet.address, currentFleet.ammoBank.amount, loadAmmo, currentFleet.stats.cargo.ammoCapacity);
1514
1362
  requireTransferCapacity(`Fleet ${fleet.name} fuel destination`, fleet.address, currentFleet.fuelTank.amount, loadFuel, currentFleet.stats.cargo.fuelCapacity);
1515
1363
  requireTransferCapacity(`Fleet ${fleet.name} cargo destination`, fleet.address, currentFleet.cargoHold.storageCost, loadCargoStorage, currentFleet.stats.cargo.cargoCapacity);
1516
- const unloadStorage = options.unload.reduce((total, { amount, cargoId }) => total + amount * BigInt(definitions.get(cargoId).storageCost), 0n);
1364
+ const unloadStorage = options.unload.reduce((total, { amount, cargoId }) => total + cargoStorageUnits(amount, definitions.get(cargoId).storageCost), 0n);
1517
1365
  requireTransferCapacity(`Claim Stake ${stake.address} resource destination`, stake.address, currentStake.production.cargoPod.storageCost, unloadStorage, currentStake.production.resourceCapacityRaw);
1518
1366
  const descriptions = [
1519
1367
  ...describeCargoRequests('load', options.load),
1520
1368
  ...describeCargoRequests('unload', options.unload),
1521
1369
  ];
1522
1370
  const description = `Start fleet ${fleet.name}'s transfer to Claim Stake ${stake.address}: ${descriptions.join('; ')}. Range and transfer duration remain chain-authoritative.`;
1371
+ const xp = await resolveClaimStakeXp(ctx, game, stake.address);
1523
1372
  return createPlan({
1524
1373
  kind: 'claim-stakes.start-fleet-transfer',
1525
- preconditions: await Promise.all([
1526
- precondition(fleetAccount, `Fleet ${fleet.name} retains its owner, name, idle state, normalized crew, cargo balances, and destination capacities.`),
1527
- precondition(stakeAccount, `Claim Stake ${stake.address} retains its owner, active state, cargo balances, destination capacity, Body, and System generation.`),
1528
- precondition(bodyAccount, `The Claim Stake Planet remains assigned to System ${system} at the current generation.`),
1529
- precondition(characterAccount, `The canonical Character remains assigned to Profile ${options.authorization.profile} in the configured Game.`),
1530
- precondition(systemAccount, `Star System ${currentSystem.name} retains its configured Game, sequence, nested Starbase, and Claim Stake Body relationship.`),
1531
- precondition(playerAccount, `Starbase Player ${player} retains its Profile, Character, and System.`),
1532
- precondition(currencyAccount, 'The canonical CurrencyCache remains assigned to the configured Game.'),
1533
- ...(crewCandidate === undefined
1534
- ? []
1535
- : [
1536
- precondition(crewCandidate, `Fleet ${fleet.name}'s optional FleetCrewBinding remains assigned to the Fleet and owner Profile.`),
1537
- ]),
1538
- ]),
1374
+ preconditions: [
1375
+ xp.guard,
1376
+ ...(await Promise.all([
1377
+ precondition(fleetAccount, `Fleet ${fleet.name} retains its owner, name, idle state, normalized crew, cargo balances, and destination capacities.`),
1378
+ precondition(stakeAccount, `Claim Stake ${stake.address} retains its owner, active state, cargo balances, destination capacity, Body, and System generation.`),
1379
+ planetPrecondition(bodyAccount, system),
1380
+ characterPrecondition(characterAccount, profile),
1381
+ systemPrecondition(systemAccount, currentSystem.name),
1382
+ playerPrecondition(playerAccount, player),
1383
+ ...(crewCandidate === undefined
1384
+ ? []
1385
+ : [
1386
+ precondition(crewCandidate, `Fleet ${fleet.name}'s optional FleetCrewBinding remains assigned to the Fleet and owner Profile.`),
1387
+ ]),
1388
+ ])),
1389
+ currencyGuard,
1390
+ ],
1539
1391
  steps: [
1540
1392
  {
1541
1393
  describes: description,
1542
1394
  instruction: adaptStartClaimStakeFleetTransferInstruction({
1395
+ ...xp.accounts,
1543
1396
  authorization: options.authorization,
1544
1397
  celestialBody: stake.body.address,
1545
1398
  character,
@@ -1606,10 +1459,7 @@ export async function planRecoverClaimStakeFleetTransfer(ctx, fleet, stake, inpu
1606
1459
  if (options.atUnixSeconds < fleet.state.endAtUnixSeconds) {
1607
1460
  fail(`Fleet ${fleet.name}'s Claim Stake transfer lock has not elapsed at Unix timestamp ${String(options.atUnixSeconds)}; it ends at ${String(fleet.state.endAtUnixSeconds)}. Wait until the lock elapses, provide a current timestamp, and retry recovery.`, fleet.address);
1608
1461
  }
1609
- const character = await findCharacterPda(options.authorization.profile, game);
1610
- if (stake.ownerCharacter.address !== character) {
1611
- fail(`Claim Stake ${stake.address} does not belong to authorization Profile ${options.authorization.profile}'s canonical Character ${character}. Supply the owned current Claim Stake and retry recovery.`, stake.address);
1612
- }
1462
+ const character = await requireOwnedStake(stake, game, options.authorization.profile);
1613
1463
  const [fleetCandidate, stakeCandidate] = await readContextRawAccounts(ctx, [
1614
1464
  fleet.address,
1615
1465
  stake.address,
@@ -1618,40 +1468,17 @@ export async function planRecoverClaimStakeFleetTransfer(ctx, fleet, stake, inpu
1618
1468
  const stakeAccount = requireAccount(stakeCandidate, stake.address, `Claim Stake ${stake.address} is missing. Refresh it and retry Fleet transfer recovery.`);
1619
1469
  const currentFleet = fleetAccountDefinition.decode(fleetAccount);
1620
1470
  const currentStake = claimStakeAccountDefinition.decode(stakeAccount);
1621
- if (currentFleet.game !== game ||
1622
- currentFleet.ownerProfile !== options.authorization.profile ||
1623
- currentFleet.name !== fleet.name ||
1471
+ if (!sameTransferFleet(currentFleet, fleet, game, options.authorization.profile) ||
1624
1472
  currentFleet.state.kind !== 'claimStakeTransfer' ||
1625
1473
  currentFleet.state.claimStake !== stake.address ||
1626
1474
  currentFleet.state.planet !== stake.body.address ||
1627
1475
  currentFleet.state.endAtUnixSeconds !== fleet.state.endAtUnixSeconds ||
1628
1476
  !sameCargoAmounts(currentFleet.state.load, fleet.state.load) ||
1629
1477
  !sameCargoAmounts(currentFleet.state.unload, fleet.state.unload) ||
1630
- (await deriveFleetAddress(currentFleet)) !== fleet.address ||
1631
- currentFleet.ammoBank.cargoId !== fleet.ammo.id ||
1632
- currentFleet.ammoBank.amount !== fleet.ammo.amount ||
1633
- currentFleet.fuelTank.cargoId !== fleet.fuel.id ||
1634
- currentFleet.fuelTank.amount !== fleet.fuel.amount ||
1635
- currentFleet.cargoHold.storageCost !== fleet.cargoHold.storageCost ||
1636
- !sameCargoAmounts(currentFleet.cargoHold.amounts, fleet.cargoHold.items) ||
1637
- currentFleet.stats.cargo.ammoCapacity !== fleet.capacities.ammo.total ||
1638
- currentFleet.stats.cargo.fuelCapacity !== fleet.capacities.fuel.total ||
1639
- currentFleet.stats.cargo.cargoCapacity !== fleet.capacities.cargo.total) {
1478
+ (await deriveFleetAddress(currentFleet)) !== fleet.address) {
1640
1479
  fail(`Fleet ${fleet.name} changed or no longer matches its loaded owner, Game, canonical address, Claim Stake transfer snapshot, cargo, or capacities. Refresh it and retry recovery.`, fleet.address);
1641
1480
  }
1642
- if (currentStake.game !== game ||
1643
- currentStake.ownerCharacter !== character ||
1644
- currentStake.body !== stake.body.address ||
1645
- currentStake.systemSeqId !== stake.systemSeqId ||
1646
- currentStake.state.kind !== 'active' ||
1647
- currentStake.production.cargoPod.storageCost !==
1648
- stake.resources.capacity.usedRaw ||
1649
- currentStake.production.resourceCapacityRaw !==
1650
- stake.resources.capacity.totalRaw ||
1651
- !sameCargoAmounts(currentStake.production.cargoPod.amounts, stake.resources.inventory.items.map(({ id, quantityRaw }) => ({
1652
- amount: quantityRaw,
1653
- id,
1654
- })))) {
1481
+ if (!sameTransferStake(currentStake, stake, game, character)) {
1655
1482
  fail(`Claim Stake ${stake.address} changed or no longer matches its loaded owner, Game, Body, active state, resources, capacity, or System generation. Refresh it and retry Fleet transfer recovery.`, stake.address);
1656
1483
  }
1657
1484
  let reason;
@@ -1695,8 +1522,10 @@ export async function planRecoverClaimStakeFleetTransfer(ctx, fleet, stake, inpu
1695
1522
  const loadCargoStorage = currentFleet.state.load
1696
1523
  .filter(({ cargoId }) => cargoId !== currentFleet.ammoBank.cargoId &&
1697
1524
  cargoId !== currentFleet.fuelTank.cargoId)
1698
- .reduce((total, { amount, cargoId }) => total + amount * BigInt(queuedDefinitions.get(cargoId).storageCost), 0n);
1699
- const unloadStorage = currentFleet.state.unload.reduce((total, { amount, cargoId }) => total + amount * BigInt(queuedDefinitions.get(cargoId).storageCost), 0n);
1525
+ .reduce((total, { amount, cargoId }) => total +
1526
+ cargoStorageUnits(amount, queuedDefinitions.get(cargoId).storageCost), 0n);
1527
+ const unloadStorage = currentFleet.state.unload.reduce((total, { amount, cargoId }) => total +
1528
+ cargoStorageUnits(amount, queuedDefinitions.get(cargoId).storageCost), 0n);
1700
1529
  if (currentFleet.ammoBank.amount + loadAmmo >
1701
1530
  currentFleet.stats.cargo.ammoCapacity) {
1702
1531
  reason = 'Fleet ammo destination overflow';