@conquest-eth/tools 0.0.0 → 0.0.2

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 (178) hide show
  1. package/README.md +20 -51
  2. package/dist/cli-tool-generator.d.ts +2 -1
  3. package/dist/cli-tool-generator.d.ts.map +1 -1
  4. package/dist/cli.js +61 -32
  5. package/dist/cli.js.map +1 -1
  6. package/dist/contracts/space-info.d.ts.map +1 -1
  7. package/dist/contracts/space-info.js +22 -1
  8. package/dist/contracts/space-info.js.map +1 -1
  9. package/dist/fleet/resolve.d.ts +1 -1
  10. package/dist/fleet/resolve.d.ts.map +1 -1
  11. package/dist/fleet/resolve.js +5 -4
  12. package/dist/fleet/resolve.js.map +1 -1
  13. package/dist/fleet/send.d.ts.map +1 -1
  14. package/dist/fleet/send.js +8 -8
  15. package/dist/fleet/send.js.map +1 -1
  16. package/dist/index.d.ts +6 -32
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +21 -128
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp.d.ts +14 -0
  21. package/dist/mcp.d.ts.map +1 -0
  22. package/dist/mcp.js +29 -0
  23. package/dist/mcp.js.map +1 -0
  24. package/dist/planet/acquire.d.ts +3 -2
  25. package/dist/planet/acquire.d.ts.map +1 -1
  26. package/dist/planet/acquire.js +6 -4
  27. package/dist/planet/acquire.js.map +1 -1
  28. package/dist/planet/exit.d.ts.map +1 -1
  29. package/dist/planet/exit.js +1 -0
  30. package/dist/planet/exit.js.map +1 -1
  31. package/dist/planet/manager.d.ts +63 -0
  32. package/dist/planet/manager.d.ts.map +1 -1
  33. package/dist/planet/manager.js +125 -2
  34. package/dist/planet/manager.js.map +1 -1
  35. package/dist/planet/withdraw.d.ts +17 -0
  36. package/dist/planet/withdraw.d.ts.map +1 -0
  37. package/dist/planet/withdraw.js +25 -0
  38. package/dist/planet/withdraw.js.map +1 -0
  39. package/dist/storage/interface.d.ts +6 -0
  40. package/dist/storage/interface.d.ts.map +1 -1
  41. package/dist/storage/json-storage.d.ts +1 -0
  42. package/dist/storage/json-storage.d.ts.map +1 -1
  43. package/dist/storage/json-storage.js +10 -1
  44. package/dist/storage/json-storage.js.map +1 -1
  45. package/dist/tool-handling/cli-tool-generator.d.ts +22 -0
  46. package/dist/tool-handling/cli-tool-generator.d.ts.map +1 -0
  47. package/dist/tool-handling/cli-tool-generator.js +345 -0
  48. package/dist/tool-handling/cli-tool-generator.js.map +1 -0
  49. package/dist/tool-handling/cli.d.ts +19 -0
  50. package/dist/tool-handling/cli.d.ts.map +1 -0
  51. package/dist/tool-handling/cli.js +472 -0
  52. package/dist/tool-handling/cli.js.map +1 -0
  53. package/dist/tool-handling/index.d.ts +15 -0
  54. package/dist/tool-handling/index.d.ts.map +1 -0
  55. package/dist/tool-handling/index.js +32 -0
  56. package/dist/tool-handling/index.js.map +1 -0
  57. package/dist/tool-handling/mcp.d.ts +22 -0
  58. package/dist/tool-handling/mcp.d.ts.map +1 -0
  59. package/dist/tool-handling/mcp.js +88 -0
  60. package/dist/tool-handling/mcp.js.map +1 -0
  61. package/dist/tool-handling/types.d.ts +72 -0
  62. package/dist/tool-handling/types.d.ts.map +1 -0
  63. package/dist/tool-handling/types.js +10 -0
  64. package/dist/tool-handling/types.js.map +1 -0
  65. package/dist/tools/acquire_planets.d.ts +7 -5
  66. package/dist/tools/acquire_planets.d.ts.map +1 -1
  67. package/dist/tools/acquire_planets.js +28 -42
  68. package/dist/tools/acquire_planets.js.map +1 -1
  69. package/dist/tools/exit_planets.d.ts +7 -3
  70. package/dist/tools/exit_planets.d.ts.map +1 -1
  71. package/dist/tools/exit_planets.js +20 -9
  72. package/dist/tools/exit_planets.js.map +1 -1
  73. package/dist/tools/get_my_planets.d.ts +3 -2
  74. package/dist/tools/get_my_planets.d.ts.map +1 -1
  75. package/dist/tools/get_my_planets.js +5 -4
  76. package/dist/tools/get_my_planets.js.map +1 -1
  77. package/dist/tools/get_native_token_balance.d.ts +6 -0
  78. package/dist/tools/get_native_token_balance.d.ts.map +1 -0
  79. package/dist/tools/get_native_token_balance.js +64 -0
  80. package/dist/tools/get_native_token_balance.js.map +1 -0
  81. package/dist/tools/get_pending_exits.d.ts +2 -1
  82. package/dist/tools/get_pending_exits.d.ts.map +1 -1
  83. package/dist/tools/get_pending_exits.js +5 -4
  84. package/dist/tools/get_pending_exits.js.map +1 -1
  85. package/dist/tools/get_pending_fleets.d.ts +2 -1
  86. package/dist/tools/get_pending_fleets.d.ts.map +1 -1
  87. package/dist/tools/get_pending_fleets.js +5 -4
  88. package/dist/tools/get_pending_fleets.js.map +1 -1
  89. package/dist/tools/get_planets_around.d.ts +8 -4
  90. package/dist/tools/get_planets_around.d.ts.map +1 -1
  91. package/dist/tools/get_planets_around.js +40 -15
  92. package/dist/tools/get_planets_around.js.map +1 -1
  93. package/dist/tools/get_play_token_balance.d.ts +6 -0
  94. package/dist/tools/get_play_token_balance.d.ts.map +1 -0
  95. package/dist/tools/get_play_token_balance.js +80 -0
  96. package/dist/tools/get_play_token_balance.js.map +1 -0
  97. package/dist/tools/index.d.ts +7 -1
  98. package/dist/tools/index.d.ts.map +1 -1
  99. package/dist/tools/index.js +7 -1
  100. package/dist/tools/index.js.map +1 -1
  101. package/dist/tools/missiv_get_user.d.ts +6 -0
  102. package/dist/tools/missiv_get_user.d.ts.map +1 -0
  103. package/dist/tools/missiv_get_user.js +50 -0
  104. package/dist/tools/missiv_get_user.js.map +1 -0
  105. package/dist/tools/missiv_register.d.ts +6 -0
  106. package/dist/tools/missiv_register.d.ts.map +1 -0
  107. package/dist/tools/missiv_register.js +103 -0
  108. package/dist/tools/missiv_register.js.map +1 -0
  109. package/dist/tools/resolve_fleet.d.ts +3 -2
  110. package/dist/tools/resolve_fleet.d.ts.map +1 -1
  111. package/dist/tools/resolve_fleet.js +5 -4
  112. package/dist/tools/resolve_fleet.js.map +1 -1
  113. package/dist/tools/send_fleet.d.ts +3 -2
  114. package/dist/tools/send_fleet.d.ts.map +1 -1
  115. package/dist/tools/send_fleet.js +16 -15
  116. package/dist/tools/send_fleet.js.map +1 -1
  117. package/dist/tools/simulate.d.ts +14 -0
  118. package/dist/tools/simulate.d.ts.map +1 -0
  119. package/dist/tools/simulate.js +123 -0
  120. package/dist/tools/simulate.js.map +1 -0
  121. package/dist/tools/simulate_multiple.d.ts +17 -0
  122. package/dist/tools/simulate_multiple.d.ts.map +1 -0
  123. package/dist/tools/simulate_multiple.js +166 -0
  124. package/dist/tools/simulate_multiple.js.map +1 -0
  125. package/dist/tools/verify_exit_status.d.ts +5 -3
  126. package/dist/tools/verify_exit_status.d.ts.map +1 -1
  127. package/dist/tools/verify_exit_status.js +12 -8
  128. package/dist/tools/verify_exit_status.js.map +1 -1
  129. package/dist/tools/withdraw.d.ts +9 -0
  130. package/dist/tools/withdraw.d.ts.map +1 -0
  131. package/dist/tools/withdraw.js +86 -0
  132. package/dist/tools/withdraw.js.map +1 -0
  133. package/dist/types.d.ts +31 -28
  134. package/dist/types.d.ts.map +1 -1
  135. package/dist/types.js +1 -33
  136. package/dist/types.js.map +1 -1
  137. package/dist/util/time.d.ts +0 -30
  138. package/dist/util/time.d.ts.map +1 -1
  139. package/dist/util/time.js +0 -36
  140. package/dist/util/time.js.map +1 -1
  141. package/package.json +80 -77
  142. package/src/cli.ts +88 -59
  143. package/src/contracts/space-info.ts +24 -1
  144. package/src/fleet/resolve.ts +5 -4
  145. package/src/fleet/send.ts +9 -8
  146. package/src/index.ts +28 -162
  147. package/src/mcp.ts +46 -0
  148. package/src/planet/acquire.ts +6 -6
  149. package/src/planet/exit.ts +1 -0
  150. package/src/planet/manager.ts +163 -0
  151. package/src/planet/withdraw.ts +33 -0
  152. package/src/storage/interface.ts +7 -0
  153. package/src/storage/json-storage.ts +11 -1
  154. package/src/tool-handling/cli.ts +559 -0
  155. package/src/tool-handling/index.ts +45 -0
  156. package/src/tool-handling/mcp.ts +127 -0
  157. package/src/tool-handling/types.ts +86 -0
  158. package/src/tools/acquire_planets.ts +34 -60
  159. package/src/tools/exit_planets.ts +25 -12
  160. package/src/tools/get_native_token_balance.ts +72 -0
  161. package/src/tools/get_pending_exits.ts +8 -5
  162. package/src/tools/get_pending_fleets.ts +8 -5
  163. package/src/tools/get_planets_around.ts +45 -16
  164. package/src/tools/get_play_token_balance.ts +90 -0
  165. package/src/tools/index.ts +7 -1
  166. package/src/tools/missiv_get_user.ts +68 -0
  167. package/src/tools/missiv_register.ts +122 -0
  168. package/src/tools/resolve_fleet.ts +8 -5
  169. package/src/tools/send_fleet.ts +21 -18
  170. package/src/tools/simulate.ts +141 -0
  171. package/src/tools/simulate_multiple.ts +197 -0
  172. package/src/tools/verify_exit_status.ts +15 -11
  173. package/src/tools/withdraw.ts +100 -0
  174. package/src/types.ts +33 -71
  175. package/src/util/time.ts +0 -46
  176. package/src/cli-tool-generator.ts +0 -287
  177. package/src/helpers/index.ts +0 -59
  178. package/src/tools/get_my_planets.ts +0 -30
package/src/mcp.ts ADDED
@@ -0,0 +1,46 @@
1
+ import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import pkg from '../package.json' with {type: 'json'};
3
+ import {ConquestEnv} from './types.js';
4
+ import * as tools from './tools/index.js';
5
+ import {createEthereumEnv, createEthereumMPCServer} from 'tools-ethereum';
6
+ import {ServerOptions} from '@modelcontextprotocol/sdk/server';
7
+ import {Implementation} from '@modelcontextprotocol/sdk/types.js';
8
+ import {getChain} from 'tools-ethereum/helpers';
9
+ import {registerAllMCPTools} from './tool-handling/mcp.js';
10
+
11
+ /**
12
+ * Create and configure an MCP server for Conquest.eth game interactions
13
+ *
14
+ */
15
+ export async function createServer(
16
+ env: ConquestEnv,
17
+ options?: {
18
+ ethereum?: boolean;
19
+ serverInfo?: Implementation;
20
+ serverOptions?: ServerOptions;
21
+ },
22
+ ) {
23
+ let server: McpServer;
24
+ const name = `mcp-conquest-eth-v0`;
25
+
26
+ if (options?.ethereum) {
27
+ const ethereumEnv = await createEthereumEnv(env.options);
28
+
29
+ server = createEthereumMPCServer(ethereumEnv, {
30
+ serverInfo: {name, version: pkg.version, ...options?.serverInfo},
31
+ serverOptions: options?.serverOptions,
32
+ });
33
+ } else {
34
+ server = new McpServer(
35
+ options?.serverInfo || {
36
+ name,
37
+ version: pkg.version,
38
+ },
39
+ options?.serverOptions || {capabilities: {logging: {}}},
40
+ );
41
+ }
42
+
43
+ registerAllMCPTools({server, tools, env});
44
+
45
+ return server;
46
+ }
@@ -6,8 +6,9 @@ import {Clients, GameContract} from '../types.js';
6
6
  * @param clients - Viem clients (publicClient and walletClient)
7
7
  * @param gameContract - The game contract instance with address and ABI
8
8
  * @param planetIds - Array of planet location IDs to acquire
9
- * @param amountToMint - Amount of native token to spend
9
+ * @param amountToMint - Amount of play tokens to mint
10
10
  * @param tokenAmount - Amount of staking token to spend
11
+ * @param numTokensPerNativeToken - How many play tokens (at 18 decimals) you get per 1 native token (fetched from PlayToken contract)
11
12
  * @returns Transaction hash and list of planets acquired
12
13
  */
13
14
  export async function acquirePlanets(
@@ -16,14 +17,13 @@ export async function acquirePlanets(
16
17
  planetIds: bigint[],
17
18
  amountToMint: bigint,
18
19
  tokenAmount: bigint,
20
+ numTokensPerNativeToken: bigint,
19
21
  ): Promise<{hash: `0x${string}`; planetsAcquired: bigint[]}> {
20
22
  const sender = clients.walletClient.account!.address;
21
23
 
22
- const nativeTokenAmount = (amountToMint * 1000000000000000000n) / 1000000000000000000000n; // TODO BigInt((PlayToken.linkedData as any).numTokensPerNativeTokenAt18Decimals);
23
-
24
- console.log(
25
- `Acquiring ${planetIds.length} planets with ${amountToMint} native tokens and ${tokenAmount} staking tokens using ${nativeTokenAmount} native tokens`,
26
- );
24
+ // Calculate how much native token is needed to mint `amountToMint` play tokens
25
+ // nativeTokenAmount = amountToMint * 1e18 / numTokensPerNativeToken
26
+ const nativeTokenAmount = (amountToMint * 1000000000000000000n) / numTokensPerNativeToken;
27
27
 
28
28
  // Get the contract acquireMultipleViaNativeTokenAndStakingToken function signature
29
29
  const simulation = await clients.publicClient.simulateContract({
@@ -49,6 +49,7 @@ export async function exitPlanets(
49
49
  completed: false,
50
50
  interrupted: false,
51
51
  lastCheckedAt: currentTime,
52
+ withdrawn: false,
52
53
  };
53
54
 
54
55
  await storage.savePendingExit(exit);
@@ -3,6 +3,7 @@ import type {SpaceInfo} from 'conquest-eth-v0-contracts';
3
3
  import type {PlanetInfo, PlanetState} from 'conquest-eth-v0-contracts';
4
4
  import {acquirePlanets} from './acquire.js';
5
5
  import {exitPlanets} from './exit.js';
6
+ import {withdrawFromPlanets} from './withdraw.js';
6
7
  import type {FleetStorage} from '../storage/interface.js';
7
8
  import type {
8
9
  Clients,
@@ -13,6 +14,17 @@ import type {
13
14
  PendingExit,
14
15
  } from '../types.js';
15
16
 
17
+ // ERC20 balanceOf ABI for checking play token balance
18
+ const erc20BalanceOfAbi = [
19
+ {
20
+ name: 'balanceOf',
21
+ type: 'function',
22
+ stateMutability: 'view',
23
+ inputs: [{name: 'account', type: 'address'}],
24
+ outputs: [{name: '', type: 'uint256'}],
25
+ },
26
+ ] as const;
27
+
16
28
  /**
17
29
  * PlanetManager manages planet-related operations in the Conquest game
18
30
  * including acquiring new planets and initiating exit processes
@@ -52,6 +64,7 @@ export class PlanetManager {
52
64
  planetIds,
53
65
  amountToMint,
54
66
  tokenAmount,
67
+ this.contractConfig.numTokensPerNativeToken,
55
68
  );
56
69
  }
57
70
 
@@ -70,10 +83,37 @@ export class PlanetManager {
70
83
  planetIds,
71
84
  costs.amountToMint,
72
85
  costs.tokenAmount,
86
+ this.contractConfig.numTokensPerNativeToken,
73
87
  );
74
88
  return {...result, costs};
75
89
  }
76
90
 
91
+ /**
92
+ * Get the play token (staking token) balance for an address
93
+ *
94
+ * @param address - Address to check balance for. Defaults to current wallet address.
95
+ * @returns The balance in raw units (18 decimals)
96
+ */
97
+ async getPlayTokenBalance(address?: `0x${string}`): Promise<bigint> {
98
+ let targetAddress: `0x${string}`;
99
+
100
+ if (address) {
101
+ targetAddress = address;
102
+ } else {
103
+ const clients = this.requireWalletClient();
104
+ targetAddress = clients.walletClient.account!.address;
105
+ }
106
+
107
+ const balanceRaw = await this.clients.publicClient.readContract({
108
+ address: this.contractConfig.stakingToken,
109
+ abi: erc20BalanceOfAbi,
110
+ functionName: 'balanceOf',
111
+ args: [targetAddress],
112
+ });
113
+
114
+ return balanceRaw;
115
+ }
116
+
77
117
  /**
78
118
  * Calculate acquisition costs for planets based on their stats
79
119
  *
@@ -99,6 +139,59 @@ export class PlanetManager {
99
139
  return {amountToMint, tokenAmount: 0n};
100
140
  }
101
141
 
142
+ /**
143
+ * Acquire (stake) multiple planets using maximum available play token balance first,
144
+ * then minting the remainder with native tokens.
145
+ *
146
+ * This simplifies planet acquisition by automatically:
147
+ * 1. Calculating required token amount based on planet stats
148
+ * 2. Using ALL available play token balance first
149
+ * 3. Minting any remaining amount needed using native tokens
150
+ *
151
+ * @param planetIds - Array of planet location IDs to acquire
152
+ * @returns Transaction hash, planets acquired, and cost breakdown
153
+ */
154
+ async acquireWithMaxPlayToken(planetIds: bigint[]): Promise<{
155
+ hash: `0x${string}`;
156
+ planetsAcquired: bigint[];
157
+ costs: {
158
+ totalRequired: bigint;
159
+ playTokenUsed: bigint;
160
+ amountMinted: bigint;
161
+ };
162
+ }> {
163
+ // Calculate total required token amount
164
+ const {amountToMint: totalRequired} = this.calculateAcquisitionCosts(planetIds);
165
+
166
+ // Get current play token balance
167
+ const playTokenBalance = await this.getPlayTokenBalance();
168
+
169
+ // Determine how much play token to use (all of it, up to what's needed)
170
+ const playTokenUsed = playTokenBalance > totalRequired ? totalRequired : playTokenBalance;
171
+
172
+ // Calculate remaining amount to mint with native tokens
173
+ const amountToMint = totalRequired > playTokenUsed ? totalRequired - playTokenUsed : 0n;
174
+
175
+ // Acquire the planets
176
+ const result = await acquirePlanets(
177
+ this.requireWalletClient(),
178
+ this.gameContract,
179
+ planetIds,
180
+ amountToMint,
181
+ playTokenUsed,
182
+ this.contractConfig.numTokensPerNativeToken,
183
+ );
184
+
185
+ return {
186
+ ...result,
187
+ costs: {
188
+ totalRequired,
189
+ playTokenUsed,
190
+ amountMinted: amountToMint,
191
+ },
192
+ };
193
+ }
194
+
102
195
  /**
103
196
  * Exit (unstake) multiple planets
104
197
  */
@@ -112,6 +205,76 @@ export class PlanetManager {
112
205
  );
113
206
  }
114
207
 
208
+ /**
209
+ * Withdraw tokens from planets that have completed their exit process
210
+ *
211
+ * @param planetIds - Array of planet location IDs to withdraw from
212
+ * @returns Transaction hash and list of planet IDs for which withdrawals were processed
213
+ */
214
+ async withdraw(planetIds: bigint[]): Promise<{hash: `0x${string}`; planetsWithdrawn: bigint[]}> {
215
+ const result = await withdrawFromPlanets(
216
+ this.requireWalletClient(),
217
+ this.gameContract,
218
+ planetIds,
219
+ );
220
+
221
+ // Mark the exits as withdrawn in storage
222
+ const currentTime = Math.floor(Date.now() / 1000);
223
+ for (const planetId of result.planetsWithdrawn) {
224
+ await this.storage.markExitWithdrawn(planetId, currentTime);
225
+ }
226
+
227
+ return result;
228
+ }
229
+
230
+ /**
231
+ * Get exits that are ready to be withdrawn
232
+ *
233
+ * Returns all pending exits that:
234
+ * - Have completed (exit time has passed)
235
+ * - Were not interrupted
236
+ * - Have not been withdrawn yet
237
+ *
238
+ * @returns Array of pending exits ready for withdrawal
239
+ */
240
+ async getWithdrawableExits(): Promise<PendingExit[]> {
241
+ const sender = this.requireWalletClient().walletClient.account!.address;
242
+ const allExits = await this.storage.getPendingExitsByPlayer(sender);
243
+ const currentTime = Math.floor(Date.now() / 1000);
244
+
245
+ return allExits.filter((exit) => {
246
+ // Must be past exit complete time
247
+ const isPastExitTime = currentTime >= exit.exitCompleteTime;
248
+ // Must not be interrupted
249
+ const notInterrupted = !exit.interrupted;
250
+ // Must not already be withdrawn
251
+ const notWithdrawn = !exit.withdrawn;
252
+
253
+ return isPastExitTime && notInterrupted && notWithdrawn;
254
+ });
255
+ }
256
+
257
+ /**
258
+ * Withdraw all tokens from planets that have completed their exit process
259
+ *
260
+ * This method automatically finds all pending exits that are:
261
+ * - Past their completion time
262
+ * - Not interrupted
263
+ * - Not already withdrawn
264
+ *
265
+ * @returns Transaction hash and list of planet IDs for which withdrawals were processed, or null if no withdrawable exits found
266
+ */
267
+ async withdrawAll(): Promise<{hash: `0x${string}`; planetsWithdrawn: bigint[]} | null> {
268
+ const withdrawableExits = await this.getWithdrawableExits();
269
+
270
+ if (withdrawableExits.length === 0) {
271
+ return null;
272
+ }
273
+
274
+ const planetIds = withdrawableExits.map((exit) => exit.planetId);
275
+ return this.withdraw(planetIds);
276
+ }
277
+
115
278
  /**
116
279
  * Get planet info by location ID
117
280
  */
@@ -0,0 +1,33 @@
1
+ import type {Clients, GameContract} from '../types.js';
2
+
3
+ /**
4
+ * Withdraw tokens from planets that have completed their exit process
5
+ *
6
+ * Uses the fetchAndWithdrawFor contract function which fetches any completed
7
+ * exits and withdraws the staked tokens to the owner's wallet.
8
+ *
9
+ * @param clients - Viem clients (publicClient and walletClient)
10
+ * @param gameContract - The game contract instance with address and ABI
11
+ * @param planetIds - Array of planet location IDs to withdraw from
12
+ * @returns Transaction hash and list of planet IDs for which withdrawals were processed
13
+ */
14
+ export async function withdrawFromPlanets(
15
+ clients: Clients,
16
+ gameContract: GameContract,
17
+ planetIds: bigint[],
18
+ ): Promise<{hash: `0x${string}`; planetsWithdrawn: bigint[]}> {
19
+ const sender = clients.walletClient.account!.address;
20
+
21
+ // Simulate the fetchAndWithdrawFor transaction
22
+ const simulation = await clients.publicClient.simulateContract({
23
+ ...gameContract,
24
+ functionName: 'fetchAndWithdrawFor',
25
+ args: [sender, planetIds],
26
+ account: sender,
27
+ });
28
+
29
+ // Send the transaction
30
+ const hash = await clients.walletClient.writeContract(simulation.request);
31
+
32
+ return {hash, planetsWithdrawn: planetIds};
33
+ }
@@ -97,6 +97,13 @@ export interface FleetStorage {
97
97
  */
98
98
  markExitInterrupted(planetId: bigint, interruptedAt: number, newOwner: Address): Promise<void>;
99
99
 
100
+ /**
101
+ * Mark an exit as withdrawn (tokens claimed)
102
+ * @param planetId - The planet location ID
103
+ * @param withdrawnAt - The timestamp when the tokens were withdrawn
104
+ */
105
+ markExitWithdrawn(planetId: bigint, withdrawnAt: number): Promise<void>;
106
+
100
107
  /**
101
108
  * Clean up old completed exits from storage
102
109
  * @param olderThan - Unix timestamp; exits completed before this time will be removed
@@ -3,7 +3,7 @@ import path from 'path';
3
3
  import type {Address} from 'viem';
4
4
  import type {FleetStorage} from './interface.js';
5
5
  import {PendingExit, PendingFleet} from '../types.js';
6
- import {stringifyWithBigInt} from '../helpers/index.js';
6
+ import {stringifyWithBigInt} from '../tool-handling/index.js';
7
7
 
8
8
  interface StorageData {
9
9
  fleets: Record<string, PendingFleet>;
@@ -165,6 +165,16 @@ export class JsonFleetStorage implements FleetStorage {
165
165
  }
166
166
  }
167
167
 
168
+ async markExitWithdrawn(planetId: bigint, withdrawnAt: number): Promise<void> {
169
+ await this.ensureInitialized();
170
+ const exit = this.data.exits[planetId.toString()];
171
+ if (exit) {
172
+ exit.withdrawn = true;
173
+ exit.withdrawnAt = withdrawnAt;
174
+ await this.save();
175
+ }
176
+ }
177
+
168
178
  async cleanupOldCompletedExits(olderThan: number): Promise<void> {
169
179
  await this.ensureInitialized();
170
180
  const now = Math.floor(Date.now() / 1000);