solforge 0.2.5 → 0.2.7

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 (80) hide show
  1. package/package.json +1 -1
  2. package/scripts/postinstall.cjs +3 -3
  3. package/server/lib/base58.ts +1 -1
  4. package/server/lib/instruction-parser.ts +242 -0
  5. package/server/methods/account/get-account-info.ts +3 -7
  6. package/server/methods/account/get-balance.ts +3 -7
  7. package/server/methods/account/get-multiple-accounts.ts +2 -1
  8. package/server/methods/account/get-parsed-account-info.ts +3 -7
  9. package/server/methods/account/parsers/index.ts +2 -2
  10. package/server/methods/account/parsers/loader-upgradeable.ts +14 -1
  11. package/server/methods/account/parsers/spl-token.ts +29 -10
  12. package/server/methods/account/request-airdrop.ts +122 -86
  13. package/server/methods/admin/mint-to.ts +11 -38
  14. package/server/methods/block/get-block.ts +3 -7
  15. package/server/methods/block/get-blocks-with-limit.ts +3 -7
  16. package/server/methods/block/is-blockhash-valid.ts +3 -7
  17. package/server/methods/get-address-lookup-table.ts +3 -7
  18. package/server/methods/program/get-program-accounts.ts +9 -9
  19. package/server/methods/program/get-token-account-balance.ts +3 -7
  20. package/server/methods/program/get-token-accounts-by-delegate.ts +4 -3
  21. package/server/methods/program/get-token-accounts-by-owner.ts +54 -33
  22. package/server/methods/program/get-token-largest-accounts.ts +3 -2
  23. package/server/methods/program/get-token-supply.ts +3 -2
  24. package/server/methods/solforge/index.ts +9 -6
  25. package/server/methods/transaction/get-parsed-transaction.ts +3 -7
  26. package/server/methods/transaction/get-signature-statuses.ts +14 -7
  27. package/server/methods/transaction/get-signatures-for-address.ts +3 -7
  28. package/server/methods/transaction/get-transaction.ts +434 -287
  29. package/server/methods/transaction/inner-instructions.test.ts +63 -0
  30. package/server/methods/transaction/send-transaction.ts +248 -56
  31. package/server/methods/transaction/simulate-transaction.ts +3 -2
  32. package/server/rpc-server.ts +98 -61
  33. package/server/types.ts +65 -30
  34. package/server/ws-server.ts +11 -7
  35. package/src/api-server-entry.ts +5 -5
  36. package/src/cli/commands/airdrop.ts +2 -2
  37. package/src/cli/commands/config.ts +2 -2
  38. package/src/cli/commands/mint.ts +3 -3
  39. package/src/cli/commands/program-clone.ts +9 -11
  40. package/src/cli/commands/program-load.ts +3 -3
  41. package/src/cli/commands/rpc-start.ts +7 -7
  42. package/src/cli/commands/token-adopt-authority.ts +1 -1
  43. package/src/cli/commands/token-clone.ts +5 -6
  44. package/src/cli/commands/token-create.ts +5 -5
  45. package/src/cli/main.ts +33 -36
  46. package/src/cli/run-solforge.ts +3 -3
  47. package/src/cli/setup-wizard.ts +8 -6
  48. package/src/commands/add-program.ts +1 -1
  49. package/src/commands/init.ts +2 -2
  50. package/src/commands/mint.ts +5 -6
  51. package/src/commands/start.ts +10 -9
  52. package/src/commands/status.ts +1 -1
  53. package/src/commands/stop.ts +1 -1
  54. package/src/config/index.ts +33 -17
  55. package/src/config/manager.ts +3 -3
  56. package/src/db/index.ts +2 -2
  57. package/src/db/schema/index.ts +1 -0
  58. package/src/db/schema/transactions.ts +29 -22
  59. package/src/db/schema/tx-account-states.ts +21 -0
  60. package/src/db/tx-store.ts +113 -76
  61. package/src/gui/public/app.css +13 -13
  62. package/src/gui/server.ts +1 -1
  63. package/src/gui/src/api.ts +1 -1
  64. package/src/gui/src/app.tsx +49 -17
  65. package/src/gui/src/components/airdrop-mint-form.tsx +32 -8
  66. package/src/gui/src/components/clone-program-modal.tsx +25 -6
  67. package/src/gui/src/components/clone-token-modal.tsx +25 -6
  68. package/src/gui/src/components/modal.tsx +6 -1
  69. package/src/gui/src/components/status-panel.tsx +1 -1
  70. package/src/index.ts +19 -6
  71. package/src/migrations-bundled.ts +8 -2
  72. package/src/services/api-server.ts +41 -19
  73. package/src/services/port-manager.ts +7 -10
  74. package/src/services/process-registry.ts +4 -5
  75. package/src/services/program-cloner.ts +4 -4
  76. package/src/services/token-cloner.ts +4 -4
  77. package/src/services/validator.ts +2 -4
  78. package/src/types/config.ts +2 -2
  79. package/src/utils/shell.ts +1 -1
  80. package/src/utils/token-loader.ts +2 -2
@@ -35,8 +35,8 @@ export class LiteSVMRpcServer {
35
35
  blockTime?: number;
36
36
  preBalances?: number[];
37
37
  postBalances?: number[];
38
- preTokenBalances?: any[];
39
- postTokenBalances?: any[];
38
+ preTokenBalances?: unknown[];
39
+ postTokenBalances?: unknown[];
40
40
  }
41
41
  > = new Map();
42
42
  private store: TxStore;
@@ -95,7 +95,7 @@ export class LiteSVMRpcServer {
95
95
 
96
96
  private createSuccessResponse(
97
97
  id: string | number,
98
- result: any,
98
+ result: unknown,
99
99
  ): JsonRpcResponse {
100
100
  return {
101
101
  jsonrpc: "2.0",
@@ -108,7 +108,7 @@ export class LiteSVMRpcServer {
108
108
  id: string | number,
109
109
  code: number,
110
110
  message: string,
111
- data?: any,
111
+ data?: unknown,
112
112
  ): JsonRpcResponse {
113
113
  return {
114
114
  jsonrpc: "2.0",
@@ -132,7 +132,7 @@ export class LiteSVMRpcServer {
132
132
  },
133
133
  getFaucet: () => this.faucet,
134
134
  getTxCount: () => this.txCount,
135
- registerMint: (mint: any) => {
135
+ registerMint: (mint: PublicKey | string) => {
136
136
  try {
137
137
  const pk =
138
138
  typeof mint === "string" ? mint : new PublicKey(mint).toBase58();
@@ -140,7 +140,7 @@ export class LiteSVMRpcServer {
140
140
  } catch {}
141
141
  },
142
142
  listMints: () => Array.from(this.knownMints),
143
- registerProgram: (program: any) => {
143
+ registerProgram: (program: PublicKey | string) => {
144
144
  try {
145
145
  const pk =
146
146
  typeof program === "string"
@@ -150,29 +150,53 @@ export class LiteSVMRpcServer {
150
150
  } catch {}
151
151
  },
152
152
  listPrograms: () => Array.from(this.knownPrograms),
153
- recordTransaction: (signature, tx, meta) => {
154
- this.txRecords.set(signature, {
155
- tx,
156
- logs: meta?.logs || [],
157
- err: meta?.err ?? null,
158
- fee: meta?.fee ?? 5000,
159
- slot: Number(this.slot),
160
- blockTime: meta?.blockTime,
161
- preBalances: meta?.preBalances,
162
- postBalances: meta?.postBalances,
163
- preTokenBalances: (meta as any)?.preTokenBalances,
164
- postTokenBalances: (meta as any)?.postTokenBalances,
165
- });
153
+ recordTransaction: (signature, tx, meta) => {
154
+ this.txRecords.set(signature, {
155
+ tx,
156
+ logs: meta?.logs || [],
157
+ err: meta?.err ?? null,
158
+ fee: meta?.fee ?? 5000,
159
+ slot: Number(this.slot),
160
+ blockTime: meta?.blockTime,
161
+ preBalances: meta?.preBalances,
162
+ postBalances: meta?.postBalances,
163
+ preTokenBalances: (
164
+ meta as { preTokenBalances?: unknown[] } | undefined
165
+ )?.preTokenBalances,
166
+ postTokenBalances: (
167
+ meta as { postTokenBalances?: unknown[] } | undefined
168
+ )?.postTokenBalances,
169
+ innerInstructions: meta?.innerInstructions || [],
170
+ computeUnits:
171
+ meta?.computeUnits == null
172
+ ? null
173
+ : Number(meta.computeUnits),
174
+ returnData: meta?.returnData ?? null,
175
+ });
176
+ try {
177
+ if (process.env.DEBUG_TX_CAPTURE === "1") {
178
+ console.debug(
179
+ `[tx-capture] recordTransaction: sig=${signature} slot=${this.slot} logs=${meta?.logs?.length || 0} inner=${Array.isArray(meta?.innerInstructions) ? meta?.innerInstructions?.length : 0} cu=${meta?.computeUnits ?? null} returnData=${meta?.returnData ? "yes" : "no"}`,
180
+ );
181
+ }
182
+ } catch {}
166
183
 
167
184
  // Persist to SQLite for durability and history queries
168
185
  try {
169
- const msg: any = tx.message as any;
170
- const rawKeys: any[] = Array.isArray(msg.staticAccountKeys)
186
+ const msg = tx.message as unknown as {
187
+ staticAccountKeys?: unknown[];
188
+ accountKeys?: unknown[];
189
+ header?: unknown;
190
+ isAccountSigner?: (i: number) => boolean;
191
+ isAccountWritable?: (i: number) => boolean;
192
+ version?: number;
193
+ };
194
+ const rawKeys: unknown[] = Array.isArray(msg.staticAccountKeys)
171
195
  ? msg.staticAccountKeys
172
196
  : Array.isArray(msg.accountKeys)
173
197
  ? msg.accountKeys
174
198
  : [];
175
- const keys: string[] = rawKeys.map((k: any) => {
199
+ const keys: string[] = rawKeys.map((k) => {
176
200
  try {
177
201
  return typeof k === "string" ? k : (k as PublicKey).toBase58();
178
202
  } catch {
@@ -216,31 +240,48 @@ export class LiteSVMRpcServer {
216
240
  : "legacy"
217
241
  : 0;
218
242
  const rawBase64 = Buffer.from(tx.serialize()).toString("base64");
219
- this.store
220
- .insertTransactionBundle({
221
- signature,
222
- slot: Number(this.slot),
223
- blockTime: meta?.blockTime,
224
- version,
225
- fee: Number(meta?.fee ?? 5000),
226
- err: meta?.err ?? null,
227
- rawBase64,
228
- preBalances: Array.isArray(meta?.preBalances)
229
- ? meta!.preBalances!
230
- : [],
231
- postBalances: Array.isArray(meta?.postBalances)
232
- ? meta!.postBalances!
233
- : [],
234
- logs: Array.isArray(meta?.logs) ? meta!.logs! : [],
235
- preTokenBalances: Array.isArray((meta as any)?.preTokenBalances)
236
- ? (meta as any).preTokenBalances
237
- : [],
238
- postTokenBalances: Array.isArray((meta as any)?.postTokenBalances)
239
- ? (meta as any).postTokenBalances
240
- : [],
241
- accounts,
242
- })
243
- .catch(() => {});
243
+ this.store
244
+ .insertTransactionBundle({
245
+ signature,
246
+ slot: Number(this.slot),
247
+ blockTime: meta?.blockTime,
248
+ version,
249
+ fee: Number(meta?.fee ?? 5000),
250
+ err: meta?.err ?? null,
251
+ rawBase64,
252
+ preBalances: Array.isArray(meta?.preBalances)
253
+ ? (meta?.preBalances as number[])
254
+ : [],
255
+ postBalances: Array.isArray(meta?.postBalances)
256
+ ? (meta?.postBalances as number[])
257
+ : [],
258
+ logs: Array.isArray(meta?.logs) ? (meta?.logs as string[]) : [],
259
+ preTokenBalances: (() => {
260
+ const arr = (
261
+ meta as { preTokenBalances?: unknown[] } | undefined
262
+ )?.preTokenBalances;
263
+ return Array.isArray(arr) ? arr : [];
264
+ })(),
265
+ postTokenBalances: (() => {
266
+ const arr = (
267
+ meta as { postTokenBalances?: unknown[] } | undefined
268
+ )?.postTokenBalances;
269
+ return Array.isArray(arr) ? arr : [];
270
+ })(),
271
+ innerInstructions: Array.isArray(meta?.innerInstructions)
272
+ ? meta?.innerInstructions
273
+ : [],
274
+ computeUnits:
275
+ meta?.computeUnits == null
276
+ ? null
277
+ : Number(meta.computeUnits),
278
+ returnData: meta?.returnData ?? null,
279
+ accounts,
280
+ accountStates: Array.isArray(meta?.accountStates)
281
+ ? meta?.accountStates
282
+ : [],
283
+ })
284
+ .catch(() => {});
244
285
 
245
286
  // Upsert account snapshots for static keys
246
287
  const snapshots = keys
@@ -262,7 +303,7 @@ export class LiteSVMRpcServer {
262
303
  return null;
263
304
  }
264
305
  })
265
- .filter(Boolean) as any[];
306
+ .filter(Boolean) as import("../src/db/tx-store").AccountSnapshot[];
266
307
  if (snapshots.length > 0)
267
308
  this.store.upsertAccounts(snapshots).catch(() => {});
268
309
  } catch {}
@@ -302,7 +343,7 @@ export class LiteSVMRpcServer {
302
343
 
303
344
  getSignatureStatus(
304
345
  signature: string,
305
- ): { slot: number; err: any | null } | null {
346
+ ): { slot: number; err: unknown | null } | null {
306
347
  // Prefer local record for reliability
307
348
  const rec = this.txRecords.get(signature);
308
349
  if (rec) {
@@ -312,10 +353,10 @@ export class LiteSVMRpcServer {
312
353
  const sigBytes = decodeBase58(signature);
313
354
  const tx = this.svm.getTransaction(sigBytes);
314
355
  if (!tx) return null;
315
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
316
- let errVal: any = null;
356
+ let errVal: unknown = null;
317
357
  try {
318
- errVal = "err" in tx ? (tx as any).err() : null;
358
+ const raw = (tx as { err?: unknown }).err;
359
+ errVal = typeof raw === "function" ? (raw as () => unknown)() : raw;
319
360
  } catch {
320
361
  errVal = null;
321
362
  }
@@ -350,13 +391,9 @@ export class LiteSVMRpcServer {
350
391
  }
351
392
 
352
393
  return result;
353
- } catch (error: any) {
354
- return this.createErrorResponse(
355
- id,
356
- -32603,
357
- "Internal error",
358
- error.message,
359
- );
394
+ } catch (error: unknown) {
395
+ const message = error instanceof Error ? error.message : String(error);
396
+ return this.createErrorResponse(id, -32603, "Internal error", message);
360
397
  }
361
398
  }
362
399
  }
@@ -406,7 +443,7 @@ export function createLiteSVMRpcServer(port: number = 8899, host?: string) {
406
443
  try {
407
444
  console.log(
408
445
  "RPC batch:",
409
- body.map((b: any) => b.method),
446
+ body.map((b: { method?: string }) => b.method),
410
447
  );
411
448
  } catch {}
412
449
  }
@@ -432,7 +469,7 @@ export function createLiteSVMRpcServer(port: number = 8899, host?: string) {
432
469
  headers: { "Content-Type": "application/json", ...corsHeaders },
433
470
  });
434
471
  }
435
- } catch (error) {
472
+ } catch (_error) {
436
473
  return new Response(
437
474
  JSON.stringify({
438
475
  jsonrpc: "2.0",
package/server/types.ts CHANGED
@@ -6,17 +6,17 @@ export interface JsonRpcRequest {
6
6
  jsonrpc: "2.0";
7
7
  id: string | number;
8
8
  method: string;
9
- params?: any;
9
+ params?: unknown;
10
10
  }
11
11
 
12
12
  export interface JsonRpcResponse {
13
13
  jsonrpc: "2.0";
14
14
  id: string | number;
15
- result?: any;
15
+ result?: unknown;
16
16
  error?: {
17
17
  code: number;
18
18
  message: string;
19
- data?: any;
19
+ data?: unknown;
20
20
  };
21
21
  }
22
22
 
@@ -27,12 +27,15 @@ export interface RpcMethodContext {
27
27
  store?: TxStore;
28
28
  encodeBase58: (bytes: Uint8Array) => string;
29
29
  decodeBase58: (str: string) => Uint8Array;
30
- createSuccessResponse: (id: string | number, result: any) => JsonRpcResponse;
30
+ createSuccessResponse: (
31
+ id: string | number,
32
+ result: unknown,
33
+ ) => JsonRpcResponse;
31
34
  createErrorResponse: (
32
35
  id: string | number,
33
36
  code: number,
34
37
  message: string,
35
- data?: any,
38
+ data?: unknown,
36
39
  ) => JsonRpcResponse;
37
40
  notifySignature: (signature: string) => void;
38
41
  getFaucet: () => Keypair;
@@ -41,34 +44,66 @@ export interface RpcMethodContext {
41
44
  listMints?: () => string[];
42
45
  registerProgram?: (program: PublicKey | string) => void;
43
46
  listPrograms?: () => string[];
44
- recordTransaction: (
45
- signature: string,
46
- tx: VersionedTransaction,
47
- meta?: {
48
- logs?: string[];
49
- err?: unknown;
50
- fee?: number;
51
- blockTime?: number;
52
- preBalances?: number[];
53
- postBalances?: number[];
54
- },
55
- ) => void;
56
- getRecordedTransaction: (signature: string) =>
57
- | {
58
- tx: VersionedTransaction;
59
- logs: string[];
60
- err: unknown;
61
- fee: number;
62
- slot: number;
63
- blockTime?: number;
64
- preBalances?: number[];
65
- postBalances?: number[];
66
- }
67
- | undefined;
47
+ recordTransaction: (
48
+ signature: string,
49
+ tx: VersionedTransaction,
50
+ meta?: {
51
+ logs?: string[];
52
+ err?: unknown;
53
+ fee?: number;
54
+ blockTime?: number;
55
+ preBalances?: number[];
56
+ postBalances?: number[];
57
+ preTokenBalances?: unknown[];
58
+ postTokenBalances?: unknown[];
59
+ innerInstructions?: unknown[];
60
+ computeUnits?: number | bigint | null;
61
+ returnData?: { programId: string; dataBase64: string } | null;
62
+ // Optional rich per-account snapshots captured around execution
63
+ accountStates?: Array<{
64
+ address: string;
65
+ pre?: {
66
+ lamports?: number;
67
+ ownerProgram?: string;
68
+ executable?: boolean;
69
+ rentEpoch?: number;
70
+ dataLen?: number;
71
+ dataBase64?: string | null;
72
+ lastSlot?: number;
73
+ } | null;
74
+ post?: {
75
+ lamports?: number;
76
+ ownerProgram?: string;
77
+ executable?: boolean;
78
+ rentEpoch?: number;
79
+ dataLen?: number;
80
+ dataBase64?: string | null;
81
+ lastSlot?: number;
82
+ } | null;
83
+ }>;
84
+ },
85
+ ) => void;
86
+ getRecordedTransaction: (signature: string) =>
87
+ | {
88
+ tx: VersionedTransaction;
89
+ logs: string[];
90
+ err: unknown;
91
+ fee: number;
92
+ slot: number;
93
+ blockTime?: number;
94
+ preBalances?: number[];
95
+ postBalances?: number[];
96
+ preTokenBalances?: unknown[];
97
+ postTokenBalances?: unknown[];
98
+ innerInstructions?: unknown[];
99
+ computeUnits?: number | null;
100
+ returnData?: { programId: string; dataBase64: string } | null;
101
+ }
102
+ | undefined;
68
103
  }
69
104
 
70
105
  export type RpcMethodHandler = (
71
106
  id: string | number,
72
- params: any,
107
+ params: unknown[] | undefined,
73
108
  context: RpcMethodContext,
74
109
  ) => JsonRpcResponse | Promise<JsonRpcResponse>;
@@ -14,7 +14,11 @@ export function createLiteSVMWebSocketServer(
14
14
  const sockets = new Set<WebSocket>();
15
15
  const pendingChecks = new Map<string, number>();
16
16
 
17
- const sendSignatureNotification = (sig: string, slot: number, err: any) => {
17
+ const sendSignatureNotification = (
18
+ sig: string,
19
+ slot: number,
20
+ err: unknown,
21
+ ) => {
18
22
  const payload = {
19
23
  jsonrpc: "2.0",
20
24
  method: "signatureNotification",
@@ -25,14 +29,14 @@ export function createLiteSVMWebSocketServer(
25
29
  for (const [id, sub] of subs.entries()) {
26
30
  if (sub.type === "signature" && sub.signature === sig) {
27
31
  try {
28
- sockets.forEach((s) =>
32
+ for (const s of sockets) {
29
33
  s.send(
30
34
  JSON.stringify({
31
35
  ...payload,
32
36
  params: { ...payload.params, subscription: id },
33
37
  }),
34
- ),
35
- );
38
+ );
39
+ }
36
40
  } catch {}
37
41
  subs.delete(id);
38
42
  }
@@ -70,7 +74,7 @@ export function createLiteSVMWebSocketServer(
70
74
  port,
71
75
  hostname: host || process.env.RPC_HOST || "127.0.0.1",
72
76
  fetch(req, srv) {
73
- if (srv.upgrade(req)) return undefined as any;
77
+ if (srv.upgrade(req)) return undefined as unknown as Response;
74
78
  return new Response("Not a websocket", { status: 400 });
75
79
  },
76
80
  websocket: {
@@ -91,7 +95,7 @@ export function createLiteSVMWebSocketServer(
91
95
  id,
92
96
  method,
93
97
  params = [],
94
- } = msg as { id: number; method: string; params?: any[] };
98
+ } = msg as { id: number; method: string; params?: unknown[] };
95
99
  if (method === "signatureSubscribe") {
96
100
  const [signature] = params;
97
101
  const subId = nextSubId++;
@@ -147,7 +151,7 @@ export function createLiteSVMWebSocketServer(
147
151
  error: { code: -32601, message: `Method not found: ${method}` },
148
152
  }),
149
153
  );
150
- } catch (e) {
154
+ } catch (_e) {
151
155
  try {
152
156
  ws.send(
153
157
  JSON.stringify({
@@ -33,13 +33,13 @@ async function main() {
33
33
  process.exit(1);
34
34
  }
35
35
 
36
- const port = parseInt(args[portIndex + 1]!);
36
+ const port = parseInt(String(args[portIndex + 1]), 10);
37
37
  const host =
38
38
  hostIndex !== -1 && args[hostIndex + 1] ? args[hostIndex + 1] : undefined;
39
- const configPath = args[configIndex + 1]!;
40
- const rpcUrl = args[rpcIndex + 1]!;
41
- const faucetUrl = args[faucetIndex + 1]!;
42
- const workDir = args[workDirIndex + 1]!;
39
+ const configPath = String(args[configIndex + 1]);
40
+ const rpcUrl = String(args[rpcIndex + 1]);
41
+ const faucetUrl = String(args[faucetIndex + 1]);
42
+ const workDir = String(args[workDirIndex + 1]);
43
43
 
44
44
  // Load configuration
45
45
  await configManager.load(configPath);
@@ -4,8 +4,8 @@ import { parseFlags } from "../utils/args";
4
4
 
5
5
  export async function airdropCommand(args: string[]) {
6
6
  const { flags } = parseFlags(args);
7
- const to = String(flags["to"] || "");
8
- const sol = Number(flags["sol"] || 0);
7
+ const to = String(flags.to || "");
8
+ const sol = Number(flags.sol || 0);
9
9
  const cfg = await readConfig();
10
10
  const url = `http://localhost:${cfg.server.rpcPort}`;
11
11
  if (!to || !sol) {
@@ -11,7 +11,7 @@ export async function configCommand(sub: string | undefined, args: string[]) {
11
11
  switch (sub) {
12
12
  case "init": {
13
13
  const { flags } = parseFlags(args);
14
- const force = !!flags["force"];
14
+ const force = !!flags.force;
15
15
  await writeDefaultConfig({ force });
16
16
  p.log.success("Wrote sf.config.json");
17
17
  return;
@@ -28,7 +28,7 @@ export async function configCommand(sub: string | undefined, args: string[]) {
28
28
  const updated = setConfigValue(cfg, key, value);
29
29
  await Bun.write(
30
30
  "sf.config.json",
31
- JSON.stringify(updated, null, 2) + "\n",
31
+ `${JSON.stringify(updated, null, 2)}\n`,
32
32
  );
33
33
  p.log.success(`Updated ${key}`);
34
34
  return;
@@ -7,9 +7,9 @@ import { parseFlags } from "../utils/args";
7
7
  // Usage: solforge mint --mint <mint> --to <owner> --amount <amount>
8
8
  export async function mintCommand(args: string[]) {
9
9
  const { flags } = parseFlags(args);
10
- let mint = flags["mint"] as string | undefined;
11
- let receiver = flags["to"] as string | undefined; // required: receiver address (ATA owner)
12
- let amountBase = flags["amount"] as string | undefined; // optional direct base-units
10
+ let mint = flags.mint as string | undefined;
11
+ let receiver = flags.to as string | undefined; // required: receiver address (ATA owner)
12
+ let amountBase = flags.amount as string | undefined; // optional direct base-units
13
13
  let uiAmount = flags["ui-amount"] as string | undefined; // preferred UI units
14
14
 
15
15
  const cfg = await readConfig();
@@ -6,12 +6,12 @@ export async function programCloneCommand(args: string[]) {
6
6
  const { flags, rest } = parseFlags(args);
7
7
  const programId = (
8
8
  (rest[0] as string) ||
9
- (flags["program"] as string) ||
9
+ (flags.program as string) ||
10
10
  ""
11
11
  ).trim();
12
- const configPath = flags["config"] as string | undefined;
12
+ const configPath = flags.config as string | undefined;
13
13
  const cfg = await readConfig(configPath);
14
- const endpoint = (flags["endpoint"] as string) || cfg.clone.endpoint;
14
+ const endpoint = (flags.endpoint as string) || cfg.clone.endpoint;
15
15
  const withAccounts = !!flags["with-accounts"];
16
16
  const accountsLimit = flags["accounts-limit"]
17
17
  ? Number(flags["accounts-limit"])
@@ -56,16 +56,14 @@ export async function programAccountsCloneCommand(args: string[]) {
56
56
  const { flags, rest } = parseFlags(args);
57
57
  const programId = (
58
58
  (rest[0] as string) ||
59
- (flags["program"] as string) ||
59
+ (flags.program as string) ||
60
60
  ""
61
61
  ).trim();
62
- const configPath = flags["config"] as string | undefined;
62
+ const configPath = flags.config as string | undefined;
63
63
  const cfg = await readConfig(configPath);
64
- const endpoint = (flags["endpoint"] as string) || cfg.clone.endpoint;
65
- const limit = flags["limit"] ? Number(flags["limit"]) : undefined;
66
- const filters = flags["filters"]
67
- ? safeJson(flags["filters"] as string)
68
- : undefined;
64
+ const endpoint = (flags.endpoint as string) || cfg.clone.endpoint;
65
+ const limit = flags.limit ? Number(flags.limit) : undefined;
66
+ const filters = flags.filters ? safeJson(flags.filters as string) : undefined;
69
67
  if (!programId) {
70
68
  p.log.error(
71
69
  "Usage: solforge program accounts clone <programId> [--endpoint URL] [--limit N] [--filters JSON]",
@@ -97,7 +95,7 @@ export async function programAccountsCloneCommand(args: string[]) {
97
95
  }
98
96
  }
99
97
 
100
- function safeJson(s: string): any {
98
+ function safeJson(s: string): unknown {
101
99
  try {
102
100
  return JSON.parse(s);
103
101
  } catch {
@@ -5,9 +5,9 @@ import { parseFlags } from "../utils/args";
5
5
 
6
6
  export async function programLoadCommand(args: string[]) {
7
7
  const { flags, rest } = parseFlags(args);
8
- const programId = (rest[0] as string) || (flags["program"] as string);
9
- const fromFile = flags["file"] as string | undefined;
10
- const endpoint = flags["endpoint"] as string | undefined;
8
+ const programId = (rest[0] as string) || (flags.program as string);
9
+ const fromFile = flags.file as string | undefined;
10
+ const endpoint = flags.endpoint as string | undefined;
11
11
  if (!programId) {
12
12
  p.log.error(
13
13
  "Usage: solforge program load <programId> [--file PATH | --endpoint URL]",
@@ -5,13 +5,11 @@ import { parseFlags } from "../utils/args";
5
5
 
6
6
  export async function rpcStartCommand(args: string[]) {
7
7
  const { flags } = parseFlags(args);
8
- const cfg = await readConfig(flags["config"] as string | undefined);
9
- const rpcPort = Number(flags["port"] ?? cfg.server.rpcPort ?? 8899);
8
+ const cfg = await readConfig(flags.config as string | undefined);
9
+ const rpcPort = Number(flags.port ?? cfg.server.rpcPort ?? 8899);
10
10
  const wsPort = Number(flags["ws-port"] ?? cfg.server.wsPort ?? rpcPort + 1);
11
11
  const host =
12
- flags["network"] === true
13
- ? "0.0.0.0"
14
- : (flags["host"] as string) || "127.0.0.1";
12
+ flags.network === true ? "0.0.0.0" : (flags.host as string) || "127.0.0.1";
15
13
  const dbMode =
16
14
  (flags["db-mode"] as string) || cfg.server.db.mode || "ephemeral";
17
15
  const dbPath =
@@ -20,7 +18,7 @@ export async function rpcStartCommand(args: string[]) {
20
18
  const guiEnabled =
21
19
  flags["no-gui"] === true
22
20
  ? false
23
- : flags["gui"] === true
21
+ : flags.gui === true
24
22
  ? true
25
23
  : cfg.gui.enabled !== false;
26
24
 
@@ -28,10 +26,12 @@ export async function rpcStartCommand(args: string[]) {
28
26
  const guiMsg = guiEnabled ? `, GUI on ${guiPort}` : "";
29
27
  s.start(`Starting RPC on ${host}:${rpcPort}, WS on ${wsPort}${guiMsg}...`);
30
28
  try {
29
+ const mode: "ephemeral" | "persistent" =
30
+ dbMode === "persistent" ? "persistent" : "ephemeral";
31
31
  const started = startRpcServers({
32
32
  rpcPort,
33
33
  wsPort,
34
- dbMode: dbMode as any,
34
+ dbMode: mode,
35
35
  dbPath,
36
36
  host,
37
37
  guiEnabled,
@@ -5,7 +5,7 @@ import { parseFlags } from "../utils/args";
5
5
  // Set the faucet as mint authority for an existing mint in LiteSVM (local-only)
6
6
  export async function tokenAdoptAuthorityCommand(args: string[]) {
7
7
  const { flags, rest } = parseFlags(args);
8
- const mint = (rest[0] as string) || (flags["mint"] as string);
8
+ const mint = (rest[0] as string) || (flags.mint as string);
9
9
  if (!mint) {
10
10
  p.log.error("Usage: solforge token adopt-authority <mint>");
11
11
  return;
@@ -8,7 +8,7 @@ import { parseFlags } from "../utils/args";
8
8
  // solforge token clone <mint> --to <owner> --ui-amount <num> --decimals <d>
9
9
  export async function tokenCloneCommand(args: string[]) {
10
10
  const { flags, rest } = parseFlags(args);
11
- const mint = ((rest[0] as string) || (flags["mint"] as string) || "").trim();
11
+ const mint = ((rest[0] as string) || (flags.mint as string) || "").trim();
12
12
  if (!mint) {
13
13
  p.log.error(
14
14
  "Usage: solforge token clone <mint> [--amount <baseUnits> | --ui-amount <num>] [--endpoint URL]",
@@ -16,10 +16,10 @@ export async function tokenCloneCommand(args: string[]) {
16
16
  return;
17
17
  }
18
18
 
19
- const owner = flags["to"] as string | undefined; // optional; defaults to faucet on server
20
- const configPath = flags["config"] as string | undefined;
19
+ const _owner = flags.to as string | undefined; // optional; defaults to faucet on server
20
+ const configPath = flags.config as string | undefined;
21
21
  const cfg = await readConfig(configPath);
22
- const endpoint = (flags["endpoint"] as string) || cfg.clone.endpoint;
22
+ const endpoint = (flags.endpoint as string) || cfg.clone.endpoint;
23
23
  const url = `http://localhost:${cfg.server.rpcPort}`;
24
24
  const s = p.spinner();
25
25
  s.start("Cloning mint into LiteSVM...");
@@ -75,7 +75,7 @@ export async function tokenCloneCommand(args: string[]) {
75
75
  ),
76
76
  );
77
77
  return;
78
- } catch (adoptErr: any) {
78
+ } catch (adoptErr: unknown) {
79
79
  p.log.warn(
80
80
  `Adopt authority failed: ${adoptErr?.message || String(adoptErr)}`,
81
81
  );
@@ -85,7 +85,6 @@ export async function tokenCloneCommand(args: string[]) {
85
85
  );
86
86
  return;
87
87
  }
88
- return;
89
88
  } catch (e) {
90
89
  s.stop("Clone failed");
91
90
  p.log.error(String(e));