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.
- package/package.json +1 -1
- package/scripts/postinstall.cjs +3 -3
- package/server/lib/base58.ts +1 -1
- package/server/lib/instruction-parser.ts +242 -0
- 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 +122 -86
- package/server/methods/admin/mint-to.ts +11 -38
- 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 +434 -287
- package/server/methods/transaction/inner-instructions.test.ts +63 -0
- package/server/methods/transaction/send-transaction.ts +248 -56
- package/server/methods/transaction/simulate-transaction.ts +3 -2
- package/server/rpc-server.ts +98 -61
- package/server/types.ts +65 -30
- 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/schema/index.ts +1 -0
- package/src/db/schema/transactions.ts +29 -22
- package/src/db/schema/tx-account-states.ts +21 -0
- package/src/db/tx-store.ts +113 -76
- 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/migrations-bundled.ts +8 -2
- 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
|
@@ -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,
|
|
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
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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:
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
};
|
|
@@ -32,7 +32,8 @@ export const getTokenSupply: RpcMethodHandler = (id, params, context) => {
|
|
|
32
32
|
uiAmountString: ui.toString(),
|
|
33
33
|
},
|
|
34
34
|
});
|
|
35
|
-
} catch (e:
|
|
36
|
-
|
|
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
|
};
|