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
package/server/rpc-server.ts
CHANGED
|
@@ -35,8 +35,8 @@ export class LiteSVMRpcServer {
|
|
|
35
35
|
blockTime?: number;
|
|
36
36
|
preBalances?: number[];
|
|
37
37
|
postBalances?: number[];
|
|
38
|
-
preTokenBalances?:
|
|
39
|
-
postTokenBalances?:
|
|
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:
|
|
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?:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
170
|
-
|
|
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
|
|
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
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
316
|
-
let errVal: any = null;
|
|
356
|
+
let errVal: unknown = null;
|
|
317
357
|
try {
|
|
318
|
-
|
|
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:
|
|
354
|
-
|
|
355
|
-
|
|
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:
|
|
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 (
|
|
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?:
|
|
9
|
+
params?: unknown;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface JsonRpcResponse {
|
|
13
13
|
jsonrpc: "2.0";
|
|
14
14
|
id: string | number;
|
|
15
|
-
result?:
|
|
15
|
+
result?: unknown;
|
|
16
16
|
error?: {
|
|
17
17
|
code: number;
|
|
18
18
|
message: string;
|
|
19
|
-
data?:
|
|
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: (
|
|
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?:
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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:
|
|
107
|
+
params: unknown[] | undefined,
|
|
73
108
|
context: RpcMethodContext,
|
|
74
109
|
) => JsonRpcResponse | Promise<JsonRpcResponse>;
|
package/server/ws-server.ts
CHANGED
|
@@ -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 = (
|
|
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
|
-
|
|
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
|
|
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?:
|
|
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 (
|
|
154
|
+
} catch (_e) {
|
|
151
155
|
try {
|
|
152
156
|
ws.send(
|
|
153
157
|
JSON.stringify({
|
package/src/api-server-entry.ts
CHANGED
|
@@ -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
|
|
8
|
-
const sol = Number(flags
|
|
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
|
|
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)
|
|
31
|
+
`${JSON.stringify(updated, null, 2)}\n`,
|
|
32
32
|
);
|
|
33
33
|
p.log.success(`Updated ${key}`);
|
|
34
34
|
return;
|
package/src/cli/commands/mint.ts
CHANGED
|
@@ -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
|
|
11
|
-
let receiver = flags
|
|
12
|
-
let amountBase = flags
|
|
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
|
|
9
|
+
(flags.program as string) ||
|
|
10
10
|
""
|
|
11
11
|
).trim();
|
|
12
|
-
const configPath = flags
|
|
12
|
+
const configPath = flags.config as string | undefined;
|
|
13
13
|
const cfg = await readConfig(configPath);
|
|
14
|
-
const endpoint = (flags
|
|
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
|
|
59
|
+
(flags.program as string) ||
|
|
60
60
|
""
|
|
61
61
|
).trim();
|
|
62
|
-
const configPath = flags
|
|
62
|
+
const configPath = flags.config as string | undefined;
|
|
63
63
|
const cfg = await readConfig(configPath);
|
|
64
|
-
const endpoint = (flags
|
|
65
|
-
const limit = flags
|
|
66
|
-
const filters = flags
|
|
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):
|
|
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
|
|
9
|
-
const fromFile = flags
|
|
10
|
-
const endpoint = flags
|
|
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
|
|
9
|
-
const rpcPort = Number(flags
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
20
|
-
const configPath = flags
|
|
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
|
|
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:
|
|
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));
|