solforge 0.2.5 → 0.2.6
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.
- package/package.json +1 -1
- package/scripts/postinstall.cjs +3 -3
- package/server/lib/base58.ts +1 -1
- package/server/methods/account/get-account-info.ts +3 -7
- package/server/methods/account/get-balance.ts +3 -7
- package/server/methods/account/get-multiple-accounts.ts +2 -1
- package/server/methods/account/get-parsed-account-info.ts +3 -7
- package/server/methods/account/parsers/index.ts +2 -2
- package/server/methods/account/parsers/loader-upgradeable.ts +14 -1
- package/server/methods/account/parsers/spl-token.ts +29 -10
- package/server/methods/account/request-airdrop.ts +44 -31
- package/server/methods/block/get-block.ts +3 -7
- package/server/methods/block/get-blocks-with-limit.ts +3 -7
- package/server/methods/block/is-blockhash-valid.ts +3 -7
- package/server/methods/get-address-lookup-table.ts +3 -7
- package/server/methods/program/get-program-accounts.ts +9 -9
- package/server/methods/program/get-token-account-balance.ts +3 -7
- package/server/methods/program/get-token-accounts-by-delegate.ts +4 -3
- package/server/methods/program/get-token-accounts-by-owner.ts +54 -33
- package/server/methods/program/get-token-largest-accounts.ts +3 -2
- package/server/methods/program/get-token-supply.ts +3 -2
- package/server/methods/solforge/index.ts +9 -6
- package/server/methods/transaction/get-parsed-transaction.ts +3 -7
- package/server/methods/transaction/get-signature-statuses.ts +14 -7
- package/server/methods/transaction/get-signatures-for-address.ts +3 -7
- package/server/methods/transaction/get-transaction.ts +167 -81
- package/server/methods/transaction/send-transaction.ts +29 -16
- package/server/methods/transaction/simulate-transaction.ts +3 -2
- package/server/rpc-server.ts +47 -34
- package/server/types.ts +9 -6
- package/server/ws-server.ts +11 -7
- package/src/api-server-entry.ts +5 -5
- package/src/cli/commands/airdrop.ts +2 -2
- package/src/cli/commands/config.ts +2 -2
- package/src/cli/commands/mint.ts +3 -3
- package/src/cli/commands/program-clone.ts +9 -11
- package/src/cli/commands/program-load.ts +3 -3
- package/src/cli/commands/rpc-start.ts +7 -7
- package/src/cli/commands/token-adopt-authority.ts +1 -1
- package/src/cli/commands/token-clone.ts +5 -6
- package/src/cli/commands/token-create.ts +5 -5
- package/src/cli/main.ts +33 -36
- package/src/cli/run-solforge.ts +3 -3
- package/src/cli/setup-wizard.ts +8 -6
- package/src/commands/add-program.ts +1 -1
- package/src/commands/init.ts +2 -2
- package/src/commands/mint.ts +5 -6
- package/src/commands/start.ts +10 -9
- package/src/commands/status.ts +1 -1
- package/src/commands/stop.ts +1 -1
- package/src/config/index.ts +33 -17
- package/src/config/manager.ts +3 -3
- package/src/db/index.ts +2 -2
- package/src/db/tx-store.ts +12 -8
- package/src/gui/public/app.css +13 -13
- package/src/gui/server.ts +1 -1
- package/src/gui/src/api.ts +1 -1
- package/src/gui/src/app.tsx +49 -17
- package/src/gui/src/components/airdrop-mint-form.tsx +32 -8
- package/src/gui/src/components/clone-program-modal.tsx +25 -6
- package/src/gui/src/components/clone-token-modal.tsx +25 -6
- package/src/gui/src/components/modal.tsx +6 -1
- package/src/gui/src/components/status-panel.tsx +1 -1
- package/src/index.ts +19 -6
- package/src/services/api-server.ts +41 -19
- package/src/services/port-manager.ts +7 -10
- package/src/services/process-registry.ts +4 -5
- package/src/services/program-cloner.ts +4 -4
- package/src/services/token-cloner.ts +4 -4
- package/src/services/validator.ts +2 -4
- package/src/types/config.ts +2 -2
- package/src/utils/shell.ts +1 -1
- package/src/utils/token-loader.ts +2 -2
package/package.json
CHANGED
package/scripts/postinstall.cjs
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
- Skips if SOLFORGE_SKIP_DOWNLOAD=true
|
|
5
5
|
- Falls back silently on errors (CLI will still work via Bun if installed)
|
|
6
6
|
*/
|
|
7
|
-
const fs = require("fs");
|
|
8
|
-
const path = require("path");
|
|
9
|
-
const https = require("https");
|
|
7
|
+
const fs = require("node:fs");
|
|
8
|
+
const path = require("node:path");
|
|
9
|
+
const https = require("node:https");
|
|
10
10
|
|
|
11
11
|
function log(msg) {
|
|
12
12
|
console.log(`[solforge] ${msg}`);
|
package/server/lib/base58.ts
CHANGED
|
@@ -12,7 +12,7 @@ export function encodeBase58(bytes: Uint8Array): string {
|
|
|
12
12
|
encoded = ALPHABET[Number(remainder)] + encoded;
|
|
13
13
|
}
|
|
14
14
|
for (let i = 0; i < bytes.length && bytes[i] === 0; i++)
|
|
15
|
-
encoded =
|
|
15
|
+
encoded = `1${encoded}`;
|
|
16
16
|
return encoded || "1";
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -79,12 +79,8 @@ export const getAccountInfo: RpcMethodHandler = async (id, params, context) => {
|
|
|
79
79
|
context: { slot: Number(context.slot) },
|
|
80
80
|
value: accountInfo,
|
|
81
81
|
});
|
|
82
|
-
} catch (error:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-32602,
|
|
86
|
-
"Invalid params",
|
|
87
|
-
error.message,
|
|
88
|
-
);
|
|
82
|
+
} catch (error: unknown) {
|
|
83
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
84
|
+
return context.createErrorResponse(id, -32602, "Invalid params", message);
|
|
89
85
|
}
|
|
90
86
|
};
|
|
@@ -16,12 +16,8 @@ export const getBalance: RpcMethodHandler = (id, params, context) => {
|
|
|
16
16
|
context: { slot: Number(context.slot) },
|
|
17
17
|
value: Number(balance || 0n),
|
|
18
18
|
});
|
|
19
|
-
} catch (error:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-32602,
|
|
23
|
-
"Invalid params",
|
|
24
|
-
error.message,
|
|
25
|
-
);
|
|
19
|
+
} catch (error: unknown) {
|
|
20
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
21
|
+
return context.createErrorResponse(id, -32602, "Invalid params", message);
|
|
26
22
|
}
|
|
27
23
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
|
2
2
|
import type { RpcMethodHandler } from "../../types";
|
|
3
|
+
import type { AccountSnapshot } from "../../../src/db/tx-store";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Implements the getMultipleAccounts RPC method
|
|
@@ -54,7 +55,7 @@ export const getMultipleAccounts: RpcMethodHandler = async (
|
|
|
54
55
|
|
|
55
56
|
// Opportunistic index update
|
|
56
57
|
try {
|
|
57
|
-
const snaps:
|
|
58
|
+
const snaps: AccountSnapshot[] = [];
|
|
58
59
|
for (const pubkeyStr of pubkeys) {
|
|
59
60
|
try {
|
|
60
61
|
const pubkey = new PublicKey(pubkeyStr);
|
|
@@ -10,12 +10,8 @@ export const getParsedAccountInfo: RpcMethodHandler = async (
|
|
|
10
10
|
const cfg = { ...(config || {}), encoding: "jsonParsed" };
|
|
11
11
|
try {
|
|
12
12
|
return await getAccountInfo(id, [pubkey, cfg], context);
|
|
13
|
-
} catch (error:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-32603,
|
|
17
|
-
"Internal error",
|
|
18
|
-
error.message,
|
|
19
|
-
);
|
|
13
|
+
} catch (error: unknown) {
|
|
14
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15
|
+
return context.createErrorResponse(id, -32603, "Internal error", message);
|
|
20
16
|
}
|
|
21
17
|
};
|
|
@@ -6,7 +6,7 @@ import { parseSystemAccount } from "./system";
|
|
|
6
6
|
|
|
7
7
|
export type ParsedAccountData = {
|
|
8
8
|
program: string;
|
|
9
|
-
parsed:
|
|
9
|
+
parsed: unknown; // match Solana RPC jsonParsed payloads
|
|
10
10
|
space: number;
|
|
11
11
|
} | null;
|
|
12
12
|
|
|
@@ -32,7 +32,7 @@ export function parseAccountJson(
|
|
|
32
32
|
const dataBytes =
|
|
33
33
|
account.data instanceof Uint8Array
|
|
34
34
|
? account.data
|
|
35
|
-
: Buffer.from(account.data as
|
|
35
|
+
: Buffer.from(account.data as ReadonlyArray<number>);
|
|
36
36
|
const space = dataBytes.length;
|
|
37
37
|
|
|
38
38
|
// 1) System program
|
|
@@ -12,7 +12,20 @@ export function parseUpgradeableLoader(
|
|
|
12
12
|
const bytes = data;
|
|
13
13
|
const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
14
14
|
const space = bytes.length;
|
|
15
|
-
|
|
15
|
+
type UpgradeableParsed =
|
|
16
|
+
| { type: "program"; info: { programData: string } }
|
|
17
|
+
| {
|
|
18
|
+
type: "programData";
|
|
19
|
+
info: {
|
|
20
|
+
slot: number;
|
|
21
|
+
upgradeAuthority: string | null;
|
|
22
|
+
authority: string | null;
|
|
23
|
+
data: [string, "base64"];
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
| { type: "buffer"; info: { authority: string | null } }
|
|
27
|
+
| null;
|
|
28
|
+
let parsed: UpgradeableParsed = null;
|
|
16
29
|
try {
|
|
17
30
|
if (bytes.length >= 4) {
|
|
18
31
|
const tag = dv.getUint32(0, true);
|
|
@@ -51,10 +51,17 @@ export function parseSplTokenAccountOrMint(
|
|
|
51
51
|
try {
|
|
52
52
|
const mintAcc = context.svm.getAccount(dec.mint);
|
|
53
53
|
if (mintAcc) {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
const rawOwner = (mintAcc as { owner?: unknown }).owner;
|
|
55
|
+
const mintOwner = ((): PublicKey => {
|
|
56
|
+
if (
|
|
57
|
+
rawOwner &&
|
|
58
|
+
typeof (rawOwner as { toBase58?: unknown }).toBase58 ===
|
|
59
|
+
"function"
|
|
60
|
+
) {
|
|
61
|
+
return rawOwner as PublicKey;
|
|
62
|
+
}
|
|
63
|
+
return new PublicKey(String(rawOwner));
|
|
64
|
+
})();
|
|
58
65
|
const mintProg = mintOwner.equals(TOKEN_2022_PROGRAM_ID)
|
|
59
66
|
? TOKEN_2022_PROGRAM_ID
|
|
60
67
|
: TOKEN_PROGRAM_ID;
|
|
@@ -176,18 +183,18 @@ function buildAccountExtensions(account: {
|
|
|
176
183
|
|
|
177
184
|
function buildMintExtensions(mint: {
|
|
178
185
|
tlvData: Buffer;
|
|
179
|
-
}): Array<Record<string,
|
|
186
|
+
}): Array<Record<string, unknown>> | undefined {
|
|
180
187
|
if (!mint.tlvData || mint.tlvData.length === 0) return undefined;
|
|
181
188
|
const types = getExtensionTypes(mint.tlvData);
|
|
182
189
|
if (!types.length) return undefined;
|
|
183
|
-
const out: Array<Record<string,
|
|
190
|
+
const out: Array<Record<string, unknown>> = [];
|
|
184
191
|
for (const ext of types) {
|
|
185
|
-
const entry: Record<string,
|
|
192
|
+
const entry: Record<string, unknown> = {
|
|
186
193
|
type: ExtensionType[ext] ?? String(ext),
|
|
187
194
|
};
|
|
188
195
|
try {
|
|
189
196
|
if (ext === ExtensionType.MetadataPointer) {
|
|
190
|
-
const state = getMetadataPointerState(mint as
|
|
197
|
+
const state = getMetadataPointerState(mint as { tlvData: Buffer });
|
|
191
198
|
if (state) {
|
|
192
199
|
entry.info = {
|
|
193
200
|
authority: state.authority ? state.authority.toBase58() : null,
|
|
@@ -222,9 +229,21 @@ function buildMintExtensions(mint: {
|
|
|
222
229
|
return out.length ? out : undefined;
|
|
223
230
|
}
|
|
224
231
|
|
|
225
|
-
function toAccountInfo(
|
|
232
|
+
function toAccountInfo(
|
|
233
|
+
raw: {
|
|
234
|
+
data?: Buffer | Uint8Array | number[];
|
|
235
|
+
lamports?: number | bigint;
|
|
236
|
+
executable?: boolean;
|
|
237
|
+
rentEpoch?: number | bigint;
|
|
238
|
+
},
|
|
239
|
+
owner: PublicKey,
|
|
240
|
+
): AccountInfo<Buffer> {
|
|
226
241
|
const data =
|
|
227
|
-
raw.data instanceof Buffer
|
|
242
|
+
raw.data instanceof Buffer
|
|
243
|
+
? raw.data
|
|
244
|
+
: raw.data instanceof Uint8Array
|
|
245
|
+
? Buffer.from(raw.data)
|
|
246
|
+
: Buffer.from((raw.data ?? []) as number[]);
|
|
228
247
|
return {
|
|
229
248
|
data,
|
|
230
249
|
executable: !!raw.executable,
|
|
@@ -12,7 +12,7 @@ import type { RpcMethodHandler } from "../../types";
|
|
|
12
12
|
* @see https://docs.solana.com/api/http#requestairdrop
|
|
13
13
|
*/
|
|
14
14
|
export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
|
|
15
|
-
const [pubkeyStr, lamports,
|
|
15
|
+
const [pubkeyStr, lamports, _config] = params || [];
|
|
16
16
|
|
|
17
17
|
try {
|
|
18
18
|
const toPubkey = new PublicKey(pubkeyStr);
|
|
@@ -59,13 +59,16 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
|
|
|
59
59
|
tx.sign([faucet]);
|
|
60
60
|
|
|
61
61
|
// Compute pre balances for all static account keys
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
const msg = tx.message as unknown as {
|
|
63
|
+
staticAccountKeys?: unknown;
|
|
64
|
+
accountKeys?: unknown;
|
|
65
|
+
};
|
|
66
|
+
const rawKeys = Array.isArray(msg.staticAccountKeys)
|
|
67
|
+
? (msg.staticAccountKeys as unknown[])
|
|
68
|
+
: Array.isArray(msg.accountKeys)
|
|
69
|
+
? (msg.accountKeys as unknown[])
|
|
67
70
|
: [];
|
|
68
|
-
const staticKeys = rawKeys.map((k
|
|
71
|
+
const staticKeys = rawKeys.map((k) => {
|
|
69
72
|
try {
|
|
70
73
|
return typeof k === "string" ? new PublicKey(k) : (k as PublicKey);
|
|
71
74
|
} catch {
|
|
@@ -94,18 +97,22 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
|
|
|
94
97
|
const sendResult = context.svm.sendTransaction(tx);
|
|
95
98
|
// Surface errors to aid debugging
|
|
96
99
|
try {
|
|
97
|
-
|
|
98
|
-
const rawErrFun = (sendResult as any).err;
|
|
100
|
+
const rawErr = (sendResult as { err?: unknown }).err;
|
|
99
101
|
const maybeErr =
|
|
100
|
-
typeof
|
|
102
|
+
typeof rawErr === "function" ? (rawErr as () => unknown)() : rawErr;
|
|
101
103
|
if (maybeErr) {
|
|
102
104
|
let logsForErr: string[] = [];
|
|
103
105
|
try {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
const sr = sendResult as {
|
|
107
|
+
logs?: () => string[];
|
|
108
|
+
meta?: () => { logs?: () => string[] } | undefined;
|
|
109
|
+
};
|
|
110
|
+
if (typeof sr?.logs === "function") logsForErr = sr.logs();
|
|
111
|
+
else if (typeof sr?.meta === "function") {
|
|
112
|
+
const m = sr.meta();
|
|
113
|
+
const lg = m?.logs;
|
|
114
|
+
if (typeof lg === "function") logsForErr = lg();
|
|
115
|
+
}
|
|
109
116
|
} catch {}
|
|
110
117
|
console.warn(
|
|
111
118
|
"[requestAirdrop] transfer failed. err=",
|
|
@@ -130,11 +137,16 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
|
|
|
130
137
|
});
|
|
131
138
|
let logs: string[] = [];
|
|
132
139
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
const sr = sendResult as {
|
|
141
|
+
logs?: () => string[];
|
|
142
|
+
meta?: () => { logs?: () => string[] } | undefined;
|
|
143
|
+
};
|
|
144
|
+
if (typeof sr?.logs === "function") logs = sr.logs();
|
|
145
|
+
else if (typeof sr?.meta === "function") {
|
|
146
|
+
const m = sr.meta();
|
|
147
|
+
const lg = m?.logs;
|
|
148
|
+
if (typeof lg === "function") logs = lg();
|
|
149
|
+
}
|
|
138
150
|
} catch {}
|
|
139
151
|
// Verify recipient received lamports; retry once if not
|
|
140
152
|
const afterTo =
|
|
@@ -175,7 +187,9 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
|
|
|
175
187
|
tx2.sign([faucet]);
|
|
176
188
|
const res2 = context.svm.sendTransaction(tx2);
|
|
177
189
|
try {
|
|
178
|
-
const
|
|
190
|
+
const e2Raw = (res2 as { err?: unknown }).err;
|
|
191
|
+
const e2 =
|
|
192
|
+
typeof e2Raw === "function" ? (e2Raw as () => unknown)() : e2Raw;
|
|
179
193
|
if (e2) console.warn("[requestAirdrop] retry failed:", e2);
|
|
180
194
|
} catch {}
|
|
181
195
|
signature = tx2.signatures[0]
|
|
@@ -193,10 +207,13 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
|
|
|
193
207
|
}
|
|
194
208
|
|
|
195
209
|
// Try to capture error again for accurate status reporting
|
|
196
|
-
let recErr:
|
|
210
|
+
let recErr: unknown = null;
|
|
197
211
|
try {
|
|
198
|
-
const rawErrFun = (sendResult as
|
|
199
|
-
recErr =
|
|
212
|
+
const rawErrFun = (sendResult as { err?: unknown }).err;
|
|
213
|
+
recErr =
|
|
214
|
+
typeof rawErrFun === "function"
|
|
215
|
+
? (rawErrFun as () => unknown)()
|
|
216
|
+
: rawErrFun;
|
|
200
217
|
} catch {}
|
|
201
218
|
context.recordTransaction(signature, tx, {
|
|
202
219
|
logs,
|
|
@@ -208,12 +225,8 @@ export const requestAirdrop: RpcMethodHandler = (id, params, context) => {
|
|
|
208
225
|
});
|
|
209
226
|
|
|
210
227
|
return context.createSuccessResponse(id, signature);
|
|
211
|
-
} catch (error:
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
-32602,
|
|
215
|
-
"Invalid params",
|
|
216
|
-
error.message,
|
|
217
|
-
);
|
|
228
|
+
} catch (error: unknown) {
|
|
229
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
230
|
+
return context.createErrorResponse(id, -32602, "Invalid params", message);
|
|
218
231
|
}
|
|
219
232
|
};
|
|
@@ -24,12 +24,8 @@ export const getBlock: RpcMethodHandler = (id, params, context) => {
|
|
|
24
24
|
rewards: [],
|
|
25
25
|
blockTime,
|
|
26
26
|
});
|
|
27
|
-
} catch (error:
|
|
28
|
-
|
|
29
|
-
|
|
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:
|
|
16
|
-
|
|
17
|
-
|
|
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:
|
|
16
|
-
|
|
17
|
-
|
|
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:
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
214
|
-
|
|
215
|
-
|
|
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:
|
|
57
|
-
|
|
58
|
-
|
|
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:
|
|
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:
|
|
79
|
-
|
|
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 }
|
|
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:
|
|
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
|
|
58
|
+
const rawOwner = (acc as { owner?: unknown }).owner;
|
|
59
59
|
ownerPk =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
?
|
|
84
|
-
|
|
85
|
-
|
|
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
|
|
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
|
-
?
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
typeof
|
|
228
|
-
? (
|
|
229
|
-
: new PublicKey(
|
|
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
|
-
?
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
?
|
|
330
|
-
|
|
331
|
-
|
|
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:
|
|
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:
|
|
409
|
+
} catch (e: unknown) {
|
|
385
410
|
try {
|
|
386
411
|
console.error("[rpc] getTokenAccountsByOwner error", e);
|
|
387
412
|
} catch {}
|
|
388
|
-
|
|
389
|
-
|
|
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:
|
|
78
|
-
|
|
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
|
};
|