solforge 0.2.0 → 0.2.2
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/LICENSE +21 -0
- package/docs/API.md +379 -0
- package/docs/CONFIGURATION.md +407 -0
- package/package.json +67 -45
- package/src/api-server-entry.ts +109 -0
- package/src/commands/add-program.ts +337 -0
- package/src/commands/init.ts +122 -0
- package/src/commands/list.ts +136 -0
- package/src/commands/mint.ts +288 -0
- package/src/commands/start.ts +877 -0
- package/src/commands/status.ts +99 -0
- package/src/commands/stop.ts +406 -0
- package/src/config/manager.ts +157 -0
- package/src/gui/public/build/main.css +1 -0
- package/src/gui/public/build/main.js +303 -0
- package/src/gui/public/build/main.js.txt +231 -0
- package/src/index.ts +188 -0
- package/src/services/api-server.ts +485 -0
- package/src/services/port-manager.ts +177 -0
- package/src/services/process-registry.ts +154 -0
- package/src/services/program-cloner.ts +317 -0
- package/src/services/token-cloner.ts +809 -0
- package/src/services/validator.ts +295 -0
- package/src/types/config.ts +110 -0
- package/src/utils/shell.ts +110 -0
- package/src/utils/token-loader.ts +115 -0
- package/.agi/agi.sqlite +0 -0
- package/.claude/settings.local.json +0 -9
- package/.github/workflows/release-binaries.yml +0 -133
- package/.tmp/.787ebcdbf7b8fde8-00000000.hm +0 -0
- package/.tmp/.bffe6efebdf8aedc-00000000.hm +0 -0
- package/AGENTS.md +0 -271
- package/CLAUDE.md +0 -106
- package/PROJECT_STRUCTURE.md +0 -124
- package/SOLANA_KIT_GUIDE.md +0 -251
- package/SOLFORGE.md +0 -119
- package/biome.json +0 -34
- package/bun.lock +0 -743
- package/drizzle/0000_friendly_millenium_guard.sql +0 -53
- package/drizzle/0001_stale_sentinels.sql +0 -2
- package/drizzle/meta/0000_snapshot.json +0 -329
- package/drizzle/meta/0001_snapshot.json +0 -345
- package/drizzle/meta/_journal.json +0 -20
- package/drizzle.config.ts +0 -12
- package/index.ts +0 -21
- package/mint.sh +0 -47
- package/postcss.config.js +0 -6
- package/rpc-server.ts.backup +0 -519
- package/sf.config.json +0 -38
- package/tailwind.config.js +0 -27
- package/test-client.ts +0 -120
- package/tmp/inspect-html.ts +0 -4
- package/tmp/response-test.ts +0 -5
- package/tmp/test-html.ts +0 -5
- package/tmp/test-server.ts +0 -13
- package/tsconfig.json +0 -29
package/rpc-server.ts.backup
DELETED
|
@@ -1,519 +0,0 @@
|
|
|
1
|
-
import { LiteSVM } from "litesvm";
|
|
2
|
-
import {
|
|
3
|
-
PublicKey,
|
|
4
|
-
VersionedTransaction
|
|
5
|
-
} from "@solana/web3.js";
|
|
6
|
-
|
|
7
|
-
interface JsonRpcRequest {
|
|
8
|
-
jsonrpc: "2.0";
|
|
9
|
-
id: string | number;
|
|
10
|
-
method: string;
|
|
11
|
-
params?: any;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface JsonRpcResponse {
|
|
15
|
-
jsonrpc: "2.0";
|
|
16
|
-
id: string | number;
|
|
17
|
-
result?: any;
|
|
18
|
-
error?: {
|
|
19
|
-
code: number;
|
|
20
|
-
message: string;
|
|
21
|
-
data?: any;
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
class LiteSVMRpcServer {
|
|
26
|
-
private svm: LiteSVM;
|
|
27
|
-
private slot: bigint = 1n;
|
|
28
|
-
private blockHeight: bigint = 1n;
|
|
29
|
-
|
|
30
|
-
constructor() {
|
|
31
|
-
this.svm = new LiteSVM()
|
|
32
|
-
.withSysvars()
|
|
33
|
-
.withBuiltins()
|
|
34
|
-
.withDefaultPrograms()
|
|
35
|
-
.withLamports(1000000000000n)
|
|
36
|
-
.withBlockhashCheck(false)
|
|
37
|
-
.withTransactionHistory(0n)
|
|
38
|
-
.withSigverify(false);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private encodeBase58(bytes: Uint8Array): string {
|
|
42
|
-
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
43
|
-
const base = BigInt(ALPHABET.length);
|
|
44
|
-
|
|
45
|
-
let num = 0n;
|
|
46
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
47
|
-
num = num * 256n + BigInt(bytes[i] || 0);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let encoded = "";
|
|
51
|
-
while (num > 0n) {
|
|
52
|
-
const remainder = num % base;
|
|
53
|
-
num = num / base;
|
|
54
|
-
encoded = ALPHABET[Number(remainder)] + encoded;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
|
|
58
|
-
encoded = "1" + encoded;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return encoded || "1";
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private decodeBase58(str: string): Uint8Array {
|
|
65
|
-
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
66
|
-
const base = BigInt(ALPHABET.length);
|
|
67
|
-
|
|
68
|
-
let num = 0n;
|
|
69
|
-
for (const char of str) {
|
|
70
|
-
const index = ALPHABET.indexOf(char);
|
|
71
|
-
if (index === -1) throw new Error("Invalid base58 character");
|
|
72
|
-
num = num * base + BigInt(index);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const bytes = [];
|
|
76
|
-
while (num > 0n) {
|
|
77
|
-
bytes.unshift(Number(num % 256n));
|
|
78
|
-
num = num / 256n;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
for (let i = 0; i < str.length && str[i] === "1"; i++) {
|
|
82
|
-
bytes.unshift(0);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return new Uint8Array(bytes.length > 0 ? bytes : [0]);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private createSuccessResponse(id: string | number, result: any): JsonRpcResponse {
|
|
89
|
-
return {
|
|
90
|
-
jsonrpc: "2.0",
|
|
91
|
-
id,
|
|
92
|
-
result
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private createErrorResponse(
|
|
97
|
-
id: string | number,
|
|
98
|
-
code: number,
|
|
99
|
-
message: string,
|
|
100
|
-
data?: any
|
|
101
|
-
): JsonRpcResponse {
|
|
102
|
-
return {
|
|
103
|
-
jsonrpc: "2.0",
|
|
104
|
-
id,
|
|
105
|
-
error: { code, message, data }
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async handleRequest(request: JsonRpcRequest): Promise<JsonRpcResponse> {
|
|
110
|
-
const { method, params, id } = request;
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
switch (method) {
|
|
114
|
-
case "getAccountInfo":
|
|
115
|
-
return this.handleGetAccountInfo(id, params);
|
|
116
|
-
|
|
117
|
-
case "getBalance":
|
|
118
|
-
return this.handleGetBalance(id, params);
|
|
119
|
-
|
|
120
|
-
case "getLatestBlockhash":
|
|
121
|
-
return this.handleGetLatestBlockhash(id, params);
|
|
122
|
-
|
|
123
|
-
case "sendTransaction":
|
|
124
|
-
return this.handleSendTransaction(id, params);
|
|
125
|
-
|
|
126
|
-
case "simulateTransaction":
|
|
127
|
-
return this.handleSimulateTransaction(id, params);
|
|
128
|
-
|
|
129
|
-
case "requestAirdrop":
|
|
130
|
-
return this.handleRequestAirdrop(id, params);
|
|
131
|
-
|
|
132
|
-
case "getSlot":
|
|
133
|
-
return this.handleGetSlot(id, params);
|
|
134
|
-
|
|
135
|
-
case "getBlockHeight":
|
|
136
|
-
return this.handleGetBlockHeight(id, params);
|
|
137
|
-
|
|
138
|
-
case "getTransaction":
|
|
139
|
-
return this.handleGetTransaction(id, params);
|
|
140
|
-
|
|
141
|
-
case "getSignatureStatuses":
|
|
142
|
-
return this.handleGetSignatureStatuses(id, params);
|
|
143
|
-
|
|
144
|
-
case "getMinimumBalanceForRentExemption":
|
|
145
|
-
return this.handleGetMinimumBalanceForRentExemption(id, params);
|
|
146
|
-
|
|
147
|
-
case "getMultipleAccounts":
|
|
148
|
-
return this.handleGetMultipleAccounts(id, params);
|
|
149
|
-
|
|
150
|
-
case "getHealth":
|
|
151
|
-
return this.createSuccessResponse(id, "ok");
|
|
152
|
-
|
|
153
|
-
case "getVersion":
|
|
154
|
-
return this.createSuccessResponse(id, {
|
|
155
|
-
"solana-core": "1.18.0",
|
|
156
|
-
"feature-set": 1
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
default:
|
|
160
|
-
return this.createErrorResponse(
|
|
161
|
-
id,
|
|
162
|
-
-32601,
|
|
163
|
-
`Method not found: ${method}`
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
} catch (error: any) {
|
|
167
|
-
return this.createErrorResponse(
|
|
168
|
-
id,
|
|
169
|
-
-32603,
|
|
170
|
-
"Internal error",
|
|
171
|
-
error.message
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
private handleGetAccountInfo(id: string | number, params: any): JsonRpcResponse {
|
|
177
|
-
const [pubkeyStr, config] = params;
|
|
178
|
-
const encoding = config?.encoding || "base64";
|
|
179
|
-
|
|
180
|
-
try {
|
|
181
|
-
const pubkey = new PublicKey(pubkeyStr);
|
|
182
|
-
const account = this.svm.getAccount(pubkey);
|
|
183
|
-
|
|
184
|
-
if (!account) {
|
|
185
|
-
return this.createSuccessResponse(id, {
|
|
186
|
-
context: { slot: Number(this.slot) },
|
|
187
|
-
value: null
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const accountInfo = {
|
|
192
|
-
lamports: Number(account.lamports),
|
|
193
|
-
owner: new PublicKey(account.owner).toBase58(),
|
|
194
|
-
data: encoding === "base64"
|
|
195
|
-
? [Buffer.from(account.data).toString("base64"), encoding]
|
|
196
|
-
: Array.from(account.data),
|
|
197
|
-
executable: account.executable,
|
|
198
|
-
rentEpoch: Number(account.rentEpoch || 0)
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
return this.createSuccessResponse(id, {
|
|
202
|
-
context: { slot: Number(this.slot) },
|
|
203
|
-
value: accountInfo
|
|
204
|
-
});
|
|
205
|
-
} catch (error: any) {
|
|
206
|
-
return this.createErrorResponse(id, -32602, "Invalid params", error.message);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private handleGetBalance(id: string | number, params: any): JsonRpcResponse {
|
|
211
|
-
const [pubkeyStr] = params;
|
|
212
|
-
|
|
213
|
-
try {
|
|
214
|
-
const pubkey = new PublicKey(pubkeyStr);
|
|
215
|
-
const balance = this.svm.getBalance(pubkey);
|
|
216
|
-
|
|
217
|
-
return this.createSuccessResponse(id, {
|
|
218
|
-
context: { slot: Number(this.slot) },
|
|
219
|
-
value: Number(balance || 0n)
|
|
220
|
-
});
|
|
221
|
-
} catch (error: any) {
|
|
222
|
-
return this.createErrorResponse(id, -32602, "Invalid params", error.message);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
private handleGetLatestBlockhash(id: string | number, params: any): JsonRpcResponse {
|
|
227
|
-
const blockhash = this.svm.latestBlockhash();
|
|
228
|
-
|
|
229
|
-
return this.createSuccessResponse(id, {
|
|
230
|
-
context: { slot: Number(this.slot) },
|
|
231
|
-
value: {
|
|
232
|
-
blockhash,
|
|
233
|
-
lastValidBlockHeight: Number(this.blockHeight + 150n)
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
private handleSendTransaction(id: string | number, params: any): JsonRpcResponse {
|
|
239
|
-
const [encodedTx, config] = params;
|
|
240
|
-
|
|
241
|
-
try {
|
|
242
|
-
const txData = Buffer.from(encodedTx, "base64");
|
|
243
|
-
const tx = VersionedTransaction.deserialize(txData);
|
|
244
|
-
|
|
245
|
-
const result = this.svm.sendTransaction(tx);
|
|
246
|
-
|
|
247
|
-
if ("err" in result) {
|
|
248
|
-
return this.createErrorResponse(
|
|
249
|
-
id,
|
|
250
|
-
-32002,
|
|
251
|
-
"Transaction simulation failed",
|
|
252
|
-
result.err
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const signature = tx.signatures[0] ? this.encodeBase58(tx.signatures[0]) : this.encodeBase58(new Uint8Array(64).fill(0));
|
|
257
|
-
|
|
258
|
-
this.slot += 1n;
|
|
259
|
-
this.blockHeight += 1n;
|
|
260
|
-
|
|
261
|
-
return this.createSuccessResponse(id, signature);
|
|
262
|
-
} catch (error: any) {
|
|
263
|
-
return this.createErrorResponse(
|
|
264
|
-
id,
|
|
265
|
-
-32003,
|
|
266
|
-
"Transaction failed",
|
|
267
|
-
error.message
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
private handleSimulateTransaction(id: string | number, params: any): JsonRpcResponse {
|
|
273
|
-
const [encodedTx, config] = params;
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
const txData = Buffer.from(encodedTx, "base64");
|
|
277
|
-
const tx = VersionedTransaction.deserialize(txData);
|
|
278
|
-
|
|
279
|
-
const result = this.svm.simulateTransaction(tx);
|
|
280
|
-
|
|
281
|
-
if ("err" in result) {
|
|
282
|
-
const errorMeta = result.meta();
|
|
283
|
-
return this.createSuccessResponse(id, {
|
|
284
|
-
context: { slot: Number(this.slot) },
|
|
285
|
-
value: {
|
|
286
|
-
err: result.err(),
|
|
287
|
-
logs: errorMeta.logs(),
|
|
288
|
-
accounts: null,
|
|
289
|
-
unitsConsumed: Number(errorMeta.computeUnitsConsumed()),
|
|
290
|
-
returnData: null
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const meta = result.meta();
|
|
296
|
-
const returnData = meta.returnData();
|
|
297
|
-
|
|
298
|
-
return this.createSuccessResponse(id, {
|
|
299
|
-
context: { slot: Number(this.slot) },
|
|
300
|
-
value: {
|
|
301
|
-
err: null,
|
|
302
|
-
logs: meta.logs(),
|
|
303
|
-
accounts: null,
|
|
304
|
-
unitsConsumed: Number(meta.computeUnitsConsumed()),
|
|
305
|
-
returnData: returnData ? {
|
|
306
|
-
programId: this.encodeBase58(returnData.programId()),
|
|
307
|
-
data: [Buffer.from(returnData.data()).toString("base64"), "base64"]
|
|
308
|
-
} : null
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
} catch (error: any) {
|
|
312
|
-
return this.createErrorResponse(
|
|
313
|
-
id,
|
|
314
|
-
-32003,
|
|
315
|
-
"Simulation failed",
|
|
316
|
-
error.message
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
private handleRequestAirdrop(id: string | number, params: any): JsonRpcResponse {
|
|
322
|
-
const [pubkeyStr, lamports] = params;
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
const pubkey = new PublicKey(pubkeyStr);
|
|
326
|
-
const result = this.svm.airdrop(pubkey, BigInt(lamports));
|
|
327
|
-
|
|
328
|
-
if (!result || "err" in result) {
|
|
329
|
-
return this.createErrorResponse(
|
|
330
|
-
id,
|
|
331
|
-
-32003,
|
|
332
|
-
"Airdrop failed",
|
|
333
|
-
result?.err || "Unknown error"
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const signature = this.encodeBase58(new Uint8Array(64).fill(1));
|
|
338
|
-
|
|
339
|
-
this.slot += 1n;
|
|
340
|
-
this.blockHeight += 1n;
|
|
341
|
-
|
|
342
|
-
return this.createSuccessResponse(id, signature);
|
|
343
|
-
} catch (error: any) {
|
|
344
|
-
return this.createErrorResponse(id, -32602, "Invalid params", error.message);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
private handleGetSlot(id: string | number, params: any): JsonRpcResponse {
|
|
349
|
-
return this.createSuccessResponse(id, Number(this.slot));
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
private handleGetBlockHeight(id: string | number, params: any): JsonRpcResponse {
|
|
353
|
-
return this.createSuccessResponse(id, Number(this.blockHeight));
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
private handleGetTransaction(id: string | number, params: any): JsonRpcResponse {
|
|
357
|
-
const [signature] = params;
|
|
358
|
-
|
|
359
|
-
try {
|
|
360
|
-
const sigBytes = this.decodeBase58(signature);
|
|
361
|
-
const tx = this.svm.getTransaction(sigBytes);
|
|
362
|
-
|
|
363
|
-
if (!tx) {
|
|
364
|
-
return this.createSuccessResponse(id, null);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const isError = "err" in tx;
|
|
368
|
-
const logs = isError ? tx.meta().logs() : tx.logs();
|
|
369
|
-
|
|
370
|
-
return this.createSuccessResponse(id, {
|
|
371
|
-
slot: Number(this.slot),
|
|
372
|
-
transaction: {
|
|
373
|
-
signatures: [signature]
|
|
374
|
-
},
|
|
375
|
-
meta: {
|
|
376
|
-
err: isError ? tx.err() : null,
|
|
377
|
-
fee: 5000,
|
|
378
|
-
preBalances: [],
|
|
379
|
-
postBalances: [],
|
|
380
|
-
innerInstructions: [],
|
|
381
|
-
logMessages: logs,
|
|
382
|
-
preTokenBalances: [],
|
|
383
|
-
postTokenBalances: [],
|
|
384
|
-
rewards: []
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
} catch (error: any) {
|
|
388
|
-
return this.createErrorResponse(id, -32602, "Invalid params", error.message);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
private handleGetSignatureStatuses(id: string | number, params: any): JsonRpcResponse {
|
|
393
|
-
const [signatures, config] = params;
|
|
394
|
-
|
|
395
|
-
const statuses = signatures.map((sig: string) => {
|
|
396
|
-
try {
|
|
397
|
-
const sigBytes = this.decodeBase58(sig);
|
|
398
|
-
const tx = this.svm.getTransaction(sigBytes);
|
|
399
|
-
|
|
400
|
-
if (!tx) {
|
|
401
|
-
return null;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return {
|
|
405
|
-
slot: Number(this.slot),
|
|
406
|
-
confirmations: 0,
|
|
407
|
-
err: "err" in tx ? tx.err : null,
|
|
408
|
-
confirmationStatus: "finalized"
|
|
409
|
-
};
|
|
410
|
-
} catch {
|
|
411
|
-
return null;
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
return this.createSuccessResponse(id, {
|
|
416
|
-
context: { slot: Number(this.slot) },
|
|
417
|
-
value: statuses
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
private handleGetMinimumBalanceForRentExemption(
|
|
422
|
-
id: string | number,
|
|
423
|
-
params: any
|
|
424
|
-
): JsonRpcResponse {
|
|
425
|
-
const [dataLength] = params;
|
|
426
|
-
const minBalance = this.svm.minimumBalanceForRentExemption(BigInt(dataLength));
|
|
427
|
-
|
|
428
|
-
return this.createSuccessResponse(id, Number(minBalance));
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
private handleGetMultipleAccounts(id: string | number, params: any): JsonRpcResponse {
|
|
432
|
-
const [pubkeys, config] = params;
|
|
433
|
-
const encoding = config?.encoding || "base64";
|
|
434
|
-
|
|
435
|
-
const accounts = pubkeys.map((pubkeyStr: string) => {
|
|
436
|
-
try {
|
|
437
|
-
const pubkey = new PublicKey(pubkeyStr);
|
|
438
|
-
const account = this.svm.getAccount(pubkey);
|
|
439
|
-
|
|
440
|
-
if (!account) {
|
|
441
|
-
return null;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
return {
|
|
445
|
-
lamports: Number(account.lamports),
|
|
446
|
-
owner: new PublicKey(account.owner).toBase58(),
|
|
447
|
-
data: encoding === "base64"
|
|
448
|
-
? [Buffer.from(account.data).toString("base64"), encoding]
|
|
449
|
-
: Array.from(account.data),
|
|
450
|
-
executable: account.executable,
|
|
451
|
-
rentEpoch: Number(account.rentEpoch || 0)
|
|
452
|
-
};
|
|
453
|
-
} catch {
|
|
454
|
-
return null;
|
|
455
|
-
}
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
return this.createSuccessResponse(id, {
|
|
459
|
-
context: { slot: Number(this.slot) },
|
|
460
|
-
value: accounts
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
export function createLiteSVMRpcServer(port: number = 8899) {
|
|
466
|
-
const server = new LiteSVMRpcServer();
|
|
467
|
-
|
|
468
|
-
const bunServer = Bun.serve({
|
|
469
|
-
port,
|
|
470
|
-
async fetch(req) {
|
|
471
|
-
if (req.method === "POST") {
|
|
472
|
-
try {
|
|
473
|
-
const body = await req.json();
|
|
474
|
-
|
|
475
|
-
if (Array.isArray(body)) {
|
|
476
|
-
const responses = await Promise.all(
|
|
477
|
-
body.map(request => server.handleRequest(request))
|
|
478
|
-
);
|
|
479
|
-
return Response.json(responses);
|
|
480
|
-
} else {
|
|
481
|
-
const response = await server.handleRequest(body as JsonRpcRequest);
|
|
482
|
-
return Response.json(response);
|
|
483
|
-
}
|
|
484
|
-
} catch (error) {
|
|
485
|
-
return Response.json({
|
|
486
|
-
jsonrpc: "2.0",
|
|
487
|
-
id: null,
|
|
488
|
-
error: {
|
|
489
|
-
code: -32700,
|
|
490
|
-
message: "Parse error"
|
|
491
|
-
}
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
if (req.method === "OPTIONS") {
|
|
497
|
-
return new Response(null, {
|
|
498
|
-
headers: {
|
|
499
|
-
"Access-Control-Allow-Origin": "*",
|
|
500
|
-
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
501
|
-
"Access-Control-Allow-Headers": "Content-Type"
|
|
502
|
-
}
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
return new Response("Method not allowed", { status: 405 });
|
|
507
|
-
},
|
|
508
|
-
error(error) {
|
|
509
|
-
console.error("Server error:", error);
|
|
510
|
-
return new Response("Internal Server Error", { status: 500 });
|
|
511
|
-
}
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
console.log(`🚀 LiteSVM RPC Server running on http://localhost:${port}`);
|
|
515
|
-
console.log(` Compatible with Solana RPC API`);
|
|
516
|
-
console.log(` Use with: solana config set -u http://localhost:${port}`);
|
|
517
|
-
|
|
518
|
-
return bunServer;
|
|
519
|
-
}
|
package/sf.config.json
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"server": {
|
|
3
|
-
"rpcPort": 8899,
|
|
4
|
-
"wsPort": 8900,
|
|
5
|
-
"db": {
|
|
6
|
-
"mode": "ephemeral",
|
|
7
|
-
"path": ".solforge/db.db"
|
|
8
|
-
}
|
|
9
|
-
},
|
|
10
|
-
"svm": {
|
|
11
|
-
"initialLamports": "1000000000000000",
|
|
12
|
-
"faucetSOL": 1000
|
|
13
|
-
},
|
|
14
|
-
"clone": {
|
|
15
|
-
"endpoint": "https://api.mainnet-beta.solana.com",
|
|
16
|
-
"programs": [
|
|
17
|
-
"JARSq9S9RgyynuAwcdWh2yEG6MbhfntWq7zjXjAo87uQ"
|
|
18
|
-
],
|
|
19
|
-
"tokens": [
|
|
20
|
-
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
21
|
-
"XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB",
|
|
22
|
-
"pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn"
|
|
23
|
-
],
|
|
24
|
-
"programAccounts": []
|
|
25
|
-
},
|
|
26
|
-
"gui": {
|
|
27
|
-
"enabled": true,
|
|
28
|
-
"port": 42069
|
|
29
|
-
},
|
|
30
|
-
"bootstrap": {
|
|
31
|
-
"airdrops": [
|
|
32
|
-
{
|
|
33
|
-
"address": "JARSnsWXAxUAp6Ny3Td9H1i4wNpesqkcfL1wf82t5tKi",
|
|
34
|
-
"amountSol": 100
|
|
35
|
-
}
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
}
|
package/tailwind.config.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/** @type {import('tailwindcss').Config} */
|
|
2
|
-
export default {
|
|
3
|
-
darkMode: "class",
|
|
4
|
-
content: [
|
|
5
|
-
"./src/gui/public/index.html",
|
|
6
|
-
"./src/gui/src/**/*.{ts,tsx,js,jsx}",
|
|
7
|
-
],
|
|
8
|
-
theme: {
|
|
9
|
-
extend: {
|
|
10
|
-
colors: {
|
|
11
|
-
bg: {
|
|
12
|
-
primary: "#0f172a",
|
|
13
|
-
surface: "#111827",
|
|
14
|
-
elevated: "#1f2937",
|
|
15
|
-
},
|
|
16
|
-
accent: {
|
|
17
|
-
primary: "#22d3ee",
|
|
18
|
-
hover: "#67e8f9",
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
boxShadow: {
|
|
22
|
-
soft: "0 10px 25px -15px rgba(15, 23, 42, 0.9)",
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
plugins: [],
|
|
27
|
-
};
|
package/test-client.ts
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
appendTransactionMessageInstructions,
|
|
3
|
-
createSolanaRpc,
|
|
4
|
-
createTransactionMessage,
|
|
5
|
-
generateKeyPairSigner,
|
|
6
|
-
getBase64EncodedWireTransaction,
|
|
7
|
-
getSignatureFromTransaction,
|
|
8
|
-
lamports,
|
|
9
|
-
pipe,
|
|
10
|
-
setTransactionMessageFeePayerSigner,
|
|
11
|
-
setTransactionMessageLifetimeUsingBlockhash,
|
|
12
|
-
signTransactionMessageWithSigners,
|
|
13
|
-
} from "@solana/kit";
|
|
14
|
-
import { getTransferSolInstruction } from "@solana-program/system";
|
|
15
|
-
|
|
16
|
-
async function testLiteSVMRpc() {
|
|
17
|
-
console.log("🧪 Testing LiteSVM RPC Server...\n");
|
|
18
|
-
|
|
19
|
-
const rpc = createSolanaRpc("http://localhost:8899");
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
console.log("1️⃣ Testing getHealth...");
|
|
23
|
-
const health = await rpc.getHealth().send();
|
|
24
|
-
console.log(" Health:", health, "\n");
|
|
25
|
-
|
|
26
|
-
console.log("2️⃣ Testing getVersion...");
|
|
27
|
-
const version = await rpc.getVersion().send();
|
|
28
|
-
console.log(" Version:", version, "\n");
|
|
29
|
-
|
|
30
|
-
console.log("3️⃣ Creating test wallets...");
|
|
31
|
-
const payer = await generateKeyPairSigner();
|
|
32
|
-
const recipient = await generateKeyPairSigner();
|
|
33
|
-
console.log(" Payer:", payer.address);
|
|
34
|
-
console.log(" Recipient:", recipient.address, "\n");
|
|
35
|
-
|
|
36
|
-
console.log("4️⃣ Requesting airdrop to payer...");
|
|
37
|
-
const airdropAmount = lamports(2_000_000_000n);
|
|
38
|
-
const airdropSig = await rpc
|
|
39
|
-
.requestAirdrop(payer.address, airdropAmount, { commitment: "confirmed" })
|
|
40
|
-
.send();
|
|
41
|
-
console.log(" Airdrop signature:", airdropSig, "\n");
|
|
42
|
-
|
|
43
|
-
console.log("5️⃣ Checking payer balance...");
|
|
44
|
-
const { value: payerBalance } = await rpc
|
|
45
|
-
.getBalance(payer.address, { commitment: "confirmed" })
|
|
46
|
-
.send();
|
|
47
|
-
console.log(
|
|
48
|
-
" Payer balance:",
|
|
49
|
-
Number(payerBalance) / 1_000_000_000,
|
|
50
|
-
"SOL\n",
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
console.log("6️⃣ Getting latest blockhash...");
|
|
54
|
-
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
55
|
-
console.log(" Blockhash:", latestBlockhash.blockhash, "\n");
|
|
56
|
-
|
|
57
|
-
console.log("7️⃣ Creating transfer transaction...");
|
|
58
|
-
const transferAmount = lamports(500_000_000n);
|
|
59
|
-
const transferInstruction = getTransferSolInstruction({
|
|
60
|
-
source: payer,
|
|
61
|
-
destination: recipient.address,
|
|
62
|
-
amount: transferAmount,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const transactionMessage = pipe(
|
|
66
|
-
createTransactionMessage({ version: 0 }),
|
|
67
|
-
(tx) => setTransactionMessageFeePayerSigner(payer, tx),
|
|
68
|
-
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
|
|
69
|
-
(tx) => appendTransactionMessageInstructions([transferInstruction], tx),
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
console.log("8️⃣ Signing transaction...");
|
|
73
|
-
const signedTransaction =
|
|
74
|
-
await signTransactionMessageWithSigners(transactionMessage);
|
|
75
|
-
const signature = getSignatureFromTransaction(signedTransaction);
|
|
76
|
-
console.log(" Transaction signature:", signature, "\n");
|
|
77
|
-
|
|
78
|
-
console.log("9️⃣ Simulating transaction...");
|
|
79
|
-
const base64Tx = getBase64EncodedWireTransaction(signedTransaction);
|
|
80
|
-
const { value: simulation } = await rpc
|
|
81
|
-
.simulateTransaction(base64Tx, { encoding: "base64" })
|
|
82
|
-
.send();
|
|
83
|
-
console.log(" Simulation result:", simulation.err ? "Failed" : "Success");
|
|
84
|
-
if (simulation.logs) {
|
|
85
|
-
console.log(
|
|
86
|
-
" Logs:",
|
|
87
|
-
simulation.logs.slice(0, 3).join("\n "),
|
|
88
|
-
"\n",
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log("🔟 Sending transaction...");
|
|
93
|
-
const txSig = await rpc
|
|
94
|
-
.sendTransaction(base64Tx, { encoding: "base64" })
|
|
95
|
-
.send();
|
|
96
|
-
console.log(" Transaction sent:", txSig, "\n");
|
|
97
|
-
|
|
98
|
-
console.log("1️⃣1️⃣ Checking recipient balance...");
|
|
99
|
-
const { value: recipientBalance } = await rpc
|
|
100
|
-
.getBalance(recipient.address, { commitment: "confirmed" })
|
|
101
|
-
.send();
|
|
102
|
-
console.log(
|
|
103
|
-
" Recipient balance:",
|
|
104
|
-
Number(recipientBalance) / 1_000_000_000,
|
|
105
|
-
"SOL\n",
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
console.log("1️⃣2️⃣ Getting transaction status...");
|
|
109
|
-
const { value: statuses } = await rpc.getSignatureStatuses([txSig]).send();
|
|
110
|
-
console.log(" Transaction status:", statuses[0], "\n");
|
|
111
|
-
|
|
112
|
-
console.log("✅ All tests passed!");
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error("❌ Test failed:", error);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (import.meta.main) {
|
|
119
|
-
testLiteSVMRpc();
|
|
120
|
-
}
|
package/tmp/inspect-html.ts
DELETED