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
@@ -6,13 +6,14 @@ import {
6
6
  VersionedTransaction,
7
7
  } from "@solana/web3.js";
8
8
  import type { RpcMethodHandler } from "../../types";
9
+ import { sendTransaction as sendTxRpc } from "../transaction/send-transaction";
9
10
 
10
11
  /**
11
12
  * Implements the requestAirdrop RPC method
12
13
  * @see https://docs.solana.com/api/http#requestairdrop
13
14
  */
14
- export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
15
- const [pubkeyStr, lamports, config] = params || [];
15
+ export const requestAirdrop: RpcMethodHandler = async (id, params, context) => {
16
+ const [pubkeyStr, lamports, _config] = params || [];
16
17
 
17
18
  try {
18
19
  const toPubkey = new PublicKey(pubkeyStr);
@@ -59,26 +60,57 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
59
60
  tx.sign([faucet]);
60
61
 
61
62
  // Compute pre balances for all static account keys
62
- const txMsg: any = tx.message as any;
63
- const rawKeys: any[] = Array.isArray(txMsg.staticAccountKeys)
64
- ? txMsg.staticAccountKeys
65
- : Array.isArray(txMsg.accountKeys)
66
- ? txMsg.accountKeys
63
+ const msg = tx.message as unknown as {
64
+ staticAccountKeys?: unknown;
65
+ accountKeys?: unknown;
66
+ };
67
+ const rawKeys = Array.isArray(msg.staticAccountKeys)
68
+ ? (msg.staticAccountKeys as unknown[])
69
+ : Array.isArray(msg.accountKeys)
70
+ ? (msg.accountKeys as unknown[])
67
71
  : [];
68
- const staticKeys = rawKeys.map((k: any) => {
69
- try {
70
- return typeof k === "string" ? new PublicKey(k) : (k as PublicKey);
71
- } catch {
72
- return faucet.publicKey;
73
- }
74
- });
75
- const preBalances = staticKeys.map((pk) => {
76
- try {
77
- return Number(context.svm.getBalance(pk));
78
- } catch {
79
- return 0;
80
- }
81
- });
72
+ const staticKeys = rawKeys.map((k) => {
73
+ try {
74
+ return typeof k === "string" ? new PublicKey(k) : (k as PublicKey);
75
+ } catch {
76
+ return faucet.publicKey;
77
+ }
78
+ });
79
+ const preBalances = staticKeys.map((pk) => {
80
+ try {
81
+ return Number(context.svm.getBalance(pk));
82
+ } catch {
83
+ return 0;
84
+ }
85
+ });
86
+ const preAccountStates = staticKeys.map((pk) => {
87
+ try {
88
+ const addr = pk.toBase58();
89
+ const acc = context.svm.getAccount(pk);
90
+ if (!acc) return { address: addr, pre: null } as const;
91
+ return {
92
+ address: addr,
93
+ pre: {
94
+ lamports: Number(acc.lamports || 0n),
95
+ ownerProgram: new PublicKey(acc.owner).toBase58(),
96
+ executable: !!acc.executable,
97
+ rentEpoch: Number(acc.rentEpoch || 0),
98
+ dataLen: acc.data?.length ?? 0,
99
+ dataBase64: undefined,
100
+ lastSlot: Number(context.slot),
101
+ },
102
+ } as const;
103
+ } catch {
104
+ return { address: pk.toBase58(), pre: null } as const;
105
+ }
106
+ });
107
+ try {
108
+ if (process.env.DEBUG_TX_CAPTURE === "1") {
109
+ console.debug(
110
+ `[tx-capture] pre snapshots: keys=${staticKeys.length} captured=${preAccountStates.length}`,
111
+ );
112
+ }
113
+ } catch {}
82
114
  const toIndex = staticKeys.findIndex((pk) => pk.equals(toPubkey));
83
115
  const beforeTo =
84
116
  toIndex >= 0
@@ -91,51 +123,58 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
91
123
  }
92
124
  })();
93
125
 
94
- const sendResult = context.svm.sendTransaction(tx);
95
- // Surface errors to aid debugging
96
- try {
97
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
- const rawErrFun = (sendResult as any).err;
99
- const maybeErr =
100
- typeof rawErrFun === "function" ? rawErrFun() : rawErrFun;
101
- if (maybeErr) {
102
- let logsForErr: string[] = [];
103
- try {
104
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
- const anyRes: any = sendResult;
106
- if (typeof anyRes?.logs === "function") logsForErr = anyRes.logs();
107
- else if (typeof anyRes?.meta === "function")
108
- logsForErr = anyRes.meta()?.logs?.() ?? [];
109
- } catch {}
110
- console.warn(
111
- "[requestAirdrop] transfer failed. err=",
112
- maybeErr,
113
- " logs=\n",
114
- logsForErr.join("\n"),
115
- );
116
- }
117
- } catch {}
126
+ // Send via standard sendTransaction RPC to unify capture + persistence
127
+ const rawB64 = Buffer.from(tx.serialize()).toString("base64");
128
+ const resp = await (sendTxRpc as RpcMethodHandler)(id, [rawB64], context);
129
+ if ((resp as any)?.error) return resp;
130
+ // Surface errors to aid debugging
131
+ const sendResult = undefined as unknown as { err?: unknown };
132
+ // Any send errors would have been returned by send-transaction already
118
133
 
119
- let signature = tx.signatures[0]
120
- ? context.encodeBase58(tx.signatures[0])
121
- : context.encodeBase58(new Uint8Array(64).fill(0));
122
- context.notifySignature(signature);
123
- // Compute post balances and capture logs if available for explorer detail view
124
- let postBalances = staticKeys.map((pk) => {
125
- try {
126
- return Number(context.svm.getBalance(pk));
127
- } catch {
128
- return 0;
129
- }
130
- });
131
- let logs: string[] = [];
132
- try {
133
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
134
- const anyRes: any = sendResult;
135
- if (typeof anyRes?.logs === "function") logs = anyRes.logs();
136
- else if (typeof anyRes?.meta === "function")
137
- logs = anyRes.meta()?.logs?.() ?? [];
138
- } catch {}
134
+ let signature = String((resp as any)?.result || "");
135
+ if (!signature) {
136
+ signature = tx.signatures[0]
137
+ ? context.encodeBase58(tx.signatures[0])
138
+ : context.encodeBase58(new Uint8Array(64).fill(0));
139
+ }
140
+ try { context.notifySignature(signature); } catch {}
141
+ // Compute post balances and capture logs if available for explorer detail view
142
+ let postBalances = staticKeys.map((pk) => {
143
+ try {
144
+ return Number(context.svm.getBalance(pk));
145
+ } catch {
146
+ return 0;
147
+ }
148
+ });
149
+ const postAccountStates = staticKeys.map((pk) => {
150
+ try {
151
+ const addr = pk.toBase58();
152
+ const acc = context.svm.getAccount(pk);
153
+ if (!acc) return { address: addr, post: null } as const;
154
+ return {
155
+ address: addr,
156
+ post: {
157
+ lamports: Number(acc.lamports || 0n),
158
+ ownerProgram: new PublicKey(acc.owner).toBase58(),
159
+ executable: !!acc.executable,
160
+ rentEpoch: Number(acc.rentEpoch || 0),
161
+ dataLen: acc.data?.length ?? 0,
162
+ dataBase64: undefined,
163
+ lastSlot: Number(context.slot),
164
+ },
165
+ } as const;
166
+ } catch {
167
+ return { address: pk.toBase58(), post: null } as const;
168
+ }
169
+ });
170
+ try {
171
+ if (process.env.DEBUG_TX_CAPTURE === "1") {
172
+ console.debug(
173
+ `[tx-capture] post snapshots: keys=${staticKeys.length} captured=${postAccountStates.length}`,
174
+ );
175
+ }
176
+ } catch {}
177
+ // Parsing, recording etc. are performed by send-transaction
139
178
  // Verify recipient received lamports; retry once if not
140
179
  const afterTo =
141
180
  toIndex >= 0
@@ -175,7 +214,9 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
175
214
  tx2.sign([faucet]);
176
215
  const res2 = context.svm.sendTransaction(tx2);
177
216
  try {
178
- const e2 = (res2 as any).err?.() ?? (res2 as any).err;
217
+ const e2Raw = (res2 as { err?: unknown }).err;
218
+ const e2 =
219
+ typeof e2Raw === "function" ? (e2Raw as () => unknown)() : e2Raw;
179
220
  if (e2) console.warn("[requestAirdrop] retry failed:", e2);
180
221
  } catch {}
181
222
  signature = tx2.signatures[0]
@@ -193,27 +234,22 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
193
234
  }
194
235
 
195
236
  // Try to capture error again for accurate status reporting
196
- let recErr: any = null;
197
- try {
198
- const rawErrFun = (sendResult as any).err;
199
- recErr = typeof rawErrFun === "function" ? rawErrFun() : rawErrFun;
200
- } catch {}
201
- context.recordTransaction(signature, tx, {
202
- logs,
203
- fee: 5000,
204
- blockTime: Math.floor(Date.now() / 1000),
205
- preBalances,
206
- postBalances,
207
- err: recErr,
208
- });
237
+ // No additional error capture; send-transaction has already recorded it
238
+ // Pre/post snapshots are still useful for account cache; we can upsert
239
+ try {
240
+ const snapshots = new Map<string, { pre?: any; post?: any }>();
241
+ for (const s of preAccountStates) snapshots.set(s.address, { pre: s.pre || null });
242
+ for (const s of postAccountStates) {
243
+ const e = snapshots.get(s.address) || {};
244
+ e.post = s.post || null;
245
+ snapshots.set(s.address, e);
246
+ }
247
+ // Not persisted here; DB already has the transaction via send-transaction
248
+ } catch {}
209
249
 
210
250
  return context.createSuccessResponse(id, signature);
211
- } catch (error: any) {
212
- return context.createErrorResponse(
213
- id,
214
- -32602,
215
- "Invalid params",
216
- error.message,
217
- );
251
+ } catch (error: unknown) {
252
+ const message = error instanceof Error ? error.message : String(error);
253
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
218
254
  }
219
255
  };
@@ -16,6 +16,7 @@ import {
16
16
  VersionedTransaction,
17
17
  } from "@solana/web3.js";
18
18
  import type { RpcMethodHandler } from "../../types";
19
+ import { sendTransaction as sendTxRpc } from "../transaction/send-transaction";
19
20
 
20
21
  // Mint via a real SPL Token transaction signed by faucet (must be mint authority)
21
22
  export const solforgeMintTo: RpcMethodHandler = async (id, params, context) => {
@@ -148,16 +149,15 @@ export const solforgeMintTo: RpcMethodHandler = async (id, params, context) => {
148
149
  }
149
150
  } catch {}
150
151
 
151
- // Send transaction via svm
152
- const _res = context.svm.sendTransaction(vtx);
153
- // Compute signature (base58) from the signed transaction
154
- let signatureStr = "";
155
- try {
156
- const sigBytes = vtx.signatures?.[0];
157
- if (sigBytes)
158
- signatureStr = context.encodeBase58(new Uint8Array(sigBytes));
159
- } catch {}
160
- if (!signatureStr) signatureStr = `mint:${ata.toBase58()}:${Date.now()}`;
152
+ // Send via the standard RPC sendTransaction path to unify capture/parsing
153
+ const rawBase64ForRpc = Buffer.from(vtx.serialize()).toString("base64");
154
+ const rpcResp = await (sendTxRpc as RpcMethodHandler)(
155
+ id,
156
+ [rawBase64ForRpc],
157
+ context,
158
+ );
159
+ if ((rpcResp as any)?.error) return rpcResp;
160
+ const signatureStr = String((rpcResp as any)?.result || "");
161
161
 
162
162
  // Token balance deltas (pre/post) for ATA
163
163
  type UiTokenAmount = {
@@ -229,34 +229,7 @@ export const solforgeMintTo: RpcMethodHandler = async (id, params, context) => {
229
229
  ];
230
230
  } catch {}
231
231
 
232
- // Insert into DB for explorer via context.recordTransaction for richer details
233
- try {
234
- const rawBase64 = Buffer.from(vtx.serialize()).toString("base64");
235
- const postBalances = trackedKeys.map((pk) => {
236
- try {
237
- return Number(context.svm.getBalance(pk) || 0n);
238
- } catch {
239
- return 0;
240
- }
241
- });
242
- const logs: string[] = ["spl-token mintToChecked"];
243
- try {
244
- (vtx as unknown as { serialize: () => Uint8Array }).serialize = () =>
245
- Buffer.from(rawBase64, "base64");
246
- } catch {}
247
- context.recordTransaction(signatureStr, vtx, {
248
- logs,
249
- fee: 0,
250
- blockTime: Math.floor(Date.now() / 1000),
251
- preBalances,
252
- postBalances,
253
- preTokenBalances,
254
- postTokenBalances,
255
- });
256
- } catch {}
257
- try {
258
- context.notifySignature(signatureStr);
259
- } catch {}
232
+ // send-transaction already records/announces signature and persists to DB
260
233
 
261
234
  return context.createSuccessResponse(id, {
262
235
  ok: true,
@@ -24,12 +24,8 @@ export const getBlock: RpcMethodHandler = (id, params, context) => {
24
24
  rewards: [],
25
25
  blockTime,
26
26
  });
27
- } catch (error: any) {
28
- return context.createErrorResponse(
29
- id,
30
- -32602,
31
- "Invalid params",
32
- error.message,
33
- );
27
+ } catch (error: unknown) {
28
+ const message = error instanceof Error ? error.message : String(error);
29
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
34
30
  }
35
31
  };
@@ -12,12 +12,8 @@ export const getBlocksWithLimit: RpcMethodHandler = (id, params, context) => {
12
12
  const blocks: number[] = [];
13
13
  for (let s = start; s <= end; s++) blocks.push(s);
14
14
  return context.createSuccessResponse(id, blocks);
15
- } catch (error: any) {
16
- return context.createErrorResponse(
17
- id,
18
- -32602,
19
- "Invalid params",
20
- error.message,
21
- );
15
+ } catch (error: unknown) {
16
+ const message = error instanceof Error ? error.message : String(error);
17
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
22
18
  }
23
19
  };
@@ -12,12 +12,8 @@ export const isBlockhashValid: RpcMethodHandler = (id, params, context) => {
12
12
  context: { slot: Number(context.slot) },
13
13
  value: isValid,
14
14
  });
15
- } catch (error: any) {
16
- return context.createErrorResponse(
17
- id,
18
- -32602,
19
- "Invalid params",
20
- error.message,
21
- );
15
+ } catch (error: unknown) {
16
+ const message = error instanceof Error ? error.message : String(error);
17
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
22
18
  }
23
19
  };
@@ -20,12 +20,8 @@ export const getAddressLookupTable: RpcMethodHandler = (
20
20
  context: { slot: Number(context.slot) },
21
21
  value: null,
22
22
  });
23
- } catch (error: any) {
24
- return context.createErrorResponse(
25
- id,
26
- -32602,
27
- "Invalid params",
28
- error.message,
29
- );
23
+ } catch (error: unknown) {
24
+ const message = error instanceof Error ? error.message : String(error);
25
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
30
26
  }
31
27
  };
@@ -21,7 +21,11 @@ export const getProgramAccounts: RpcMethodHandler = async (
21
21
  const dataSlice = cfg?.dataSlice as
22
22
  | { offset: number; length: number }
23
23
  | undefined;
24
- const filters = (cfg?.filters || []) as Array<any>;
24
+ type GpaFilter = {
25
+ dataSize?: number;
26
+ memcmp?: { offset?: number; bytes?: string };
27
+ };
28
+ const filters: GpaFilter[] = (cfg?.filters as unknown as GpaFilter[]) || [];
25
29
  const limit = Math.max(1, Math.min(Number(cfg?.limit ?? 10000), 50000));
26
30
 
27
31
  let rows: Array<{ address: string }> = [];
@@ -29,7 +33,7 @@ export const getProgramAccounts: RpcMethodHandler = async (
29
33
  rows = (await context.store?.getAccountsByOwner(programStr, limit)) || [];
30
34
  } catch {}
31
35
 
32
- const out: any[] = [];
36
+ const out: unknown[] = [];
33
37
  for (const r of rows) {
34
38
  try {
35
39
  const pk = new PublicKey(r.address);
@@ -210,12 +214,8 @@ export const getProgramAccounts: RpcMethodHandler = async (
210
214
  }
211
215
 
212
216
  return context.createSuccessResponse(id, out);
213
- } catch (error: any) {
214
- return context.createErrorResponse(
215
- id,
216
- -32602,
217
- "Invalid params",
218
- error.message,
219
- );
217
+ } catch (error: unknown) {
218
+ const message = error instanceof Error ? error.message : String(error);
219
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
220
220
  }
221
221
  };
@@ -53,12 +53,8 @@ export const getTokenAccountBalance: RpcMethodHandler = (
53
53
  uiAmountString: ui.toString(),
54
54
  },
55
55
  });
56
- } catch (error: any) {
57
- return context.createErrorResponse(
58
- id,
59
- -32602,
60
- "Invalid params",
61
- error.message,
62
- );
56
+ } catch (error: unknown) {
57
+ const message = error instanceof Error ? error.message : String(error);
58
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
63
59
  }
64
60
  };
@@ -23,7 +23,7 @@ export const getTokenAccountsByDelegate: RpcMethodHandler = async (
23
23
  requestedProgramId === token2022Id ? token2022Id : classicId;
24
24
  const rows =
25
25
  (await context.store?.getAccountsByOwner(programFilter, 50_000)) || [];
26
- const out: any[] = [];
26
+ const out: unknown[] = [];
27
27
  for (const r of rows) {
28
28
  try {
29
29
  const acc = context.svm.getAccount(new PublicKey(r.address));
@@ -75,7 +75,8 @@ export const getTokenAccountsByDelegate: RpcMethodHandler = async (
75
75
  context: { slot: Number(context.slot) },
76
76
  value: out,
77
77
  });
78
- } catch (e: any) {
79
- return context.createErrorResponse(id, -32602, "Invalid params", e.message);
78
+ } catch (e: unknown) {
79
+ const message = e instanceof Error ? e.message : String(e);
80
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
80
81
  }
81
82
  };
@@ -30,7 +30,7 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
30
30
  : [classicId, token2022Id];
31
31
 
32
32
  // Query DB for accounts owned by both SPL Token programs (classic + 2022)
33
- const rows: Array<{ address: string; lastSlot: number } & any> = [];
33
+ const rows: Array<{ address: string; lastSlot: number }> = [];
34
34
  for (const programId of programIds) {
35
35
  try {
36
36
  const found =
@@ -43,7 +43,7 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
43
43
  }
44
44
  }
45
45
 
46
- const out: any[] = [];
46
+ const out: unknown[] = [];
47
47
  const seen = new Set<string>();
48
48
  for (const r of rows) {
49
49
  if (seen.has(r.address)) continue;
@@ -55,11 +55,12 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
55
55
  let ownerPk: PublicKey;
56
56
  try {
57
57
  // acc.owner may already be a PublicKey in LiteSVM
58
- const anyOwner: any = (acc as any).owner;
58
+ const rawOwner = (acc as { owner?: unknown }).owner;
59
59
  ownerPk =
60
- typeof anyOwner?.toBase58 === "function"
61
- ? (anyOwner as PublicKey)
62
- : new PublicKey(anyOwner);
60
+ rawOwner &&
61
+ typeof (rawOwner as { toBase58?: unknown }).toBase58 === "function"
62
+ ? (rawOwner as PublicKey)
63
+ : new PublicKey(String(rawOwner));
63
64
  } catch {
64
65
  ownerPk = TOKEN_PROGRAM_ID; // fallback avoids throw; unpackAccount will fail if wrong and be skipped
65
66
  }
@@ -80,9 +81,14 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
80
81
  try {
81
82
  const mintAcc = context.svm.getAccount(dec.mint);
82
83
  const mintOwnerPk = mintAcc
83
- ? typeof (mintAcc as any).owner?.toBase58 === "function"
84
- ? (mintAcc as any).owner
85
- : new PublicKey(mintAcc.owner)
84
+ ? ((): PublicKey => {
85
+ const ro = (mintAcc as { owner?: unknown }).owner;
86
+ return ro &&
87
+ typeof (ro as { toBase58?: unknown }).toBase58 ===
88
+ "function"
89
+ ? (ro as PublicKey)
90
+ : new PublicKey(String(ro));
91
+ })()
86
92
  : programPk;
87
93
  const info = mintAcc
88
94
  ? unpackMint(
@@ -122,7 +128,12 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
122
128
  uiAmountString: (delegatedUiAmount ?? 0).toString(),
123
129
  };
124
130
  // rentExemptReserve only for native (wrapped SOL) accounts; value in lamports (9 decimals)
125
- let rentExemptReserve = null as any;
131
+ let rentExemptReserve: {
132
+ amount: string;
133
+ decimals: number;
134
+ uiAmount: number | null;
135
+ uiAmountString: string;
136
+ } | null = null;
126
137
  if (dec.isNative) {
127
138
  const lamports = BigInt(
128
139
  dec.rentExemptReserve?.toString?.() ??
@@ -196,9 +207,13 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
196
207
  const mintPk = new PublicKey(m);
197
208
  const mintAcc = context.svm.getAccount(mintPk);
198
209
  const mintOwnerPk = mintAcc
199
- ? typeof (mintAcc as any).owner?.toBase58 === "function"
200
- ? (mintAcc as any).owner
201
- : new PublicKey(mintAcc.owner)
210
+ ? ((): PublicKey => {
211
+ const ro = (mintAcc as { owner?: unknown }).owner;
212
+ return ro &&
213
+ typeof (ro as { toBase58?: unknown }).toBase58 === "function"
214
+ ? (ro as PublicKey)
215
+ : new PublicKey(String(ro));
216
+ })()
202
217
  : TOKEN_PROGRAM_ID;
203
218
  // Determine which token program this mint belongs to
204
219
  const programForMint = mintOwnerPk.equals(TOKEN_2022_PROGRAM_ID)
@@ -221,12 +236,12 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
221
236
  const acc = context.svm.getAccount(ata);
222
237
  if (!acc || (acc.data?.length ?? 0) < ACCOUNT_SIZE) continue;
223
238
  if (seen.has(ata.toBase58())) continue;
224
- let ownerPk: PublicKey;
225
- const anyOwner: any = (acc as any).owner;
226
- ownerPk =
227
- typeof anyOwner?.toBase58 === "function"
228
- ? (anyOwner as PublicKey)
229
- : new PublicKey(anyOwner);
239
+ const rawOwner = (acc as { owner?: unknown }).owner;
240
+ const ownerPk: PublicKey =
241
+ rawOwner &&
242
+ typeof (rawOwner as { toBase58?: unknown }).toBase58 === "function"
243
+ ? (rawOwner as PublicKey)
244
+ : new PublicKey(String(rawOwner));
230
245
  const programPk = ownerPk.equals(TOKEN_2022_PROGRAM_ID)
231
246
  ? TOKEN_2022_PROGRAM_ID
232
247
  : TOKEN_PROGRAM_ID;
@@ -249,9 +264,14 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
249
264
  try {
250
265
  const mintAcc = context.svm.getAccount(dec.mint);
251
266
  const mintOwnerPk = mintAcc
252
- ? typeof (mintAcc as any).owner?.toBase58 === "function"
253
- ? (mintAcc as any).owner
254
- : new PublicKey(mintAcc.owner)
267
+ ? ((): PublicKey => {
268
+ const ro = (mintAcc as { owner?: unknown }).owner;
269
+ return ro &&
270
+ typeof (ro as { toBase58?: unknown }).toBase58 ===
271
+ "function"
272
+ ? (ro as PublicKey)
273
+ : new PublicKey(String(ro));
274
+ })()
255
275
  : programPk;
256
276
  const info = mintAcc
257
277
  ? unpackMint(
@@ -326,9 +346,14 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
326
346
  const ownerPk = new PublicKey(ownerStr);
327
347
  const mintAcc = context.svm.getAccount(mintPk);
328
348
  const mintOwnerPk = mintAcc
329
- ? typeof (mintAcc as any).owner?.toBase58 === "function"
330
- ? (mintAcc as any).owner
331
- : new PublicKey(mintAcc.owner)
349
+ ? ((): PublicKey => {
350
+ const ro = (mintAcc as { owner?: unknown }).owner;
351
+ return ro &&
352
+ typeof (ro as { toBase58?: unknown }).toBase58 ===
353
+ "function"
354
+ ? (ro as PublicKey)
355
+ : new PublicKey(String(ro));
356
+ })()
332
357
  : TOKEN_PROGRAM_ID;
333
358
  const programForMint = mintOwnerPk.equals(TOKEN_2022_PROGRAM_ID)
334
359
  ? TOKEN_2022_PROGRAM_ID
@@ -364,7 +389,7 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
364
389
  (v) => typeof v === "number" && v >= 0,
365
390
  ),
366
391
  );
367
- const filtered: any[] = [];
392
+ const filtered: unknown[] = [];
368
393
  for (let i = 0; i < out.length; i++) {
369
394
  const e = out[i];
370
395
  const info = e.account?.data?.parsed?.info;
@@ -381,15 +406,11 @@ export const getTokenAccountsByOwner: RpcMethodHandler = async (
381
406
  context: { slot: Number(context.slot) },
382
407
  value: out,
383
408
  });
384
- } catch (e: any) {
409
+ } catch (e: unknown) {
385
410
  try {
386
411
  console.error("[rpc] getTokenAccountsByOwner error", e);
387
412
  } catch {}
388
- return context.createErrorResponse(
389
- id,
390
- -32603,
391
- "Internal error",
392
- e?.message || String(e),
393
- );
413
+ const message = e instanceof Error ? e.message : String(e);
414
+ return context.createErrorResponse(id, -32603, "Internal error", message);
394
415
  }
395
416
  };
@@ -74,7 +74,8 @@ export const getTokenLargestAccounts: RpcMethodHandler = async (
74
74
  context: { slot: Number(context.slot) },
75
75
  value: top,
76
76
  });
77
- } catch (e: any) {
78
- return context.createErrorResponse(id, -32602, "Invalid params", e.message);
77
+ } catch (e: unknown) {
78
+ const message = e instanceof Error ? e.message : String(e);
79
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
79
80
  }
80
81
  };
@@ -32,7 +32,8 @@ export const getTokenSupply: RpcMethodHandler = (id, params, context) => {
32
32
  uiAmountString: ui.toString(),
33
33
  },
34
34
  });
35
- } catch (e: any) {
36
- return context.createErrorResponse(id, -32602, "Invalid params", e.message);
35
+ } catch (e: unknown) {
36
+ const message = e instanceof Error ? e.message : String(e);
37
+ return context.createErrorResponse(id, -32602, "Invalid params", message);
37
38
  }
38
39
  };