solforge 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/package.json +1 -5
  2. package/start.cjs +19 -23
  3. package/docs/API.md +0 -379
  4. package/docs/CONFIGURATION.md +0 -407
  5. package/docs/bun-single-file-executable.md +0 -585
  6. package/docs/cli-plan.md +0 -154
  7. package/docs/data-indexing-plan.md +0 -214
  8. package/docs/gui-roadmap.md +0 -202
  9. package/scripts/decode-b58.ts +0 -10
  10. package/scripts/install.sh +0 -112
  11. package/server/index.ts +0 -5
  12. package/server/lib/base58.ts +0 -33
  13. package/server/lib/faucet.ts +0 -110
  14. package/server/lib/instruction-parser.ts +0 -328
  15. package/server/lib/parsers/spl-associated-token-account.ts +0 -50
  16. package/server/lib/parsers/spl-token.ts +0 -340
  17. package/server/lib/spl-token.ts +0 -57
  18. package/server/methods/TEMPLATE.md +0 -117
  19. package/server/methods/account/get-account-info.ts +0 -86
  20. package/server/methods/account/get-balance.ts +0 -23
  21. package/server/methods/account/get-multiple-accounts.ts +0 -84
  22. package/server/methods/account/get-parsed-account-info.ts +0 -17
  23. package/server/methods/account/index.ts +0 -12
  24. package/server/methods/account/parsers/index.ts +0 -52
  25. package/server/methods/account/parsers/loader-upgradeable.ts +0 -79
  26. package/server/methods/account/parsers/spl-token.ts +0 -256
  27. package/server/methods/account/parsers/system.ts +0 -4
  28. package/server/methods/account/request-airdrop.ts +0 -271
  29. package/server/methods/admin/adopt-mint-authority.ts +0 -94
  30. package/server/methods/admin/clone-program-accounts.ts +0 -55
  31. package/server/methods/admin/clone-program.ts +0 -152
  32. package/server/methods/admin/clone-token-accounts.ts +0 -117
  33. package/server/methods/admin/clone-token-mint.ts +0 -82
  34. package/server/methods/admin/create-mint.ts +0 -114
  35. package/server/methods/admin/create-token-account.ts +0 -137
  36. package/server/methods/admin/helpers.ts +0 -70
  37. package/server/methods/admin/index.ts +0 -10
  38. package/server/methods/admin/list-mints.ts +0 -21
  39. package/server/methods/admin/load-program.ts +0 -52
  40. package/server/methods/admin/mint-to.ts +0 -266
  41. package/server/methods/block/get-block-height.ts +0 -5
  42. package/server/methods/block/get-block.ts +0 -31
  43. package/server/methods/block/get-blocks-with-limit.ts +0 -19
  44. package/server/methods/block/get-latest-blockhash.ts +0 -12
  45. package/server/methods/block/get-slot.ts +0 -5
  46. package/server/methods/block/index.ts +0 -6
  47. package/server/methods/block/is-blockhash-valid.ts +0 -19
  48. package/server/methods/epoch/get-cluster-nodes.ts +0 -17
  49. package/server/methods/epoch/get-epoch-info.ts +0 -16
  50. package/server/methods/epoch/get-epoch-schedule.ts +0 -15
  51. package/server/methods/epoch/get-highest-snapshot-slot.ts +0 -9
  52. package/server/methods/epoch/get-leader-schedule.ts +0 -8
  53. package/server/methods/epoch/get-max-retransmit-slot.ts +0 -9
  54. package/server/methods/epoch/get-max-shred-insert-slot.ts +0 -9
  55. package/server/methods/epoch/get-slot-leader.ts +0 -6
  56. package/server/methods/epoch/get-slot-leaders.ts +0 -9
  57. package/server/methods/epoch/get-stake-activation.ts +0 -9
  58. package/server/methods/epoch/get-stake-minimum-delegation.ts +0 -9
  59. package/server/methods/epoch/get-vote-accounts.ts +0 -19
  60. package/server/methods/epoch/index.ts +0 -13
  61. package/server/methods/epoch/minimum-ledger-slot.ts +0 -5
  62. package/server/methods/fee/get-fee-calculator-for-blockhash.ts +0 -12
  63. package/server/methods/fee/get-fee-for-message.ts +0 -8
  64. package/server/methods/fee/get-fee-rate-governor.ts +0 -16
  65. package/server/methods/fee/get-fees.ts +0 -14
  66. package/server/methods/fee/get-recent-prioritization-fees.ts +0 -22
  67. package/server/methods/fee/index.ts +0 -5
  68. package/server/methods/get-address-lookup-table.ts +0 -27
  69. package/server/methods/index.ts +0 -265
  70. package/server/methods/performance/get-recent-performance-samples.ts +0 -25
  71. package/server/methods/performance/get-transaction-count.ts +0 -5
  72. package/server/methods/performance/index.ts +0 -2
  73. package/server/methods/program/get-block-commitment.ts +0 -9
  74. package/server/methods/program/get-block-production.ts +0 -14
  75. package/server/methods/program/get-block-time.ts +0 -21
  76. package/server/methods/program/get-blocks.ts +0 -11
  77. package/server/methods/program/get-first-available-block.ts +0 -9
  78. package/server/methods/program/get-genesis-hash.ts +0 -6
  79. package/server/methods/program/get-identity.ts +0 -6
  80. package/server/methods/program/get-inflation-governor.ts +0 -15
  81. package/server/methods/program/get-inflation-rate.ts +0 -10
  82. package/server/methods/program/get-inflation-reward.ts +0 -12
  83. package/server/methods/program/get-largest-accounts.ts +0 -8
  84. package/server/methods/program/get-parsed-program-accounts.ts +0 -12
  85. package/server/methods/program/get-parsed-token-accounts-by-delegate.ts +0 -12
  86. package/server/methods/program/get-parsed-token-accounts-by-owner.ts +0 -12
  87. package/server/methods/program/get-program-accounts.ts +0 -221
  88. package/server/methods/program/get-supply.ts +0 -13
  89. package/server/methods/program/get-token-account-balance.ts +0 -60
  90. package/server/methods/program/get-token-accounts-by-delegate.ts +0 -82
  91. package/server/methods/program/get-token-accounts-by-owner.ts +0 -416
  92. package/server/methods/program/get-token-largest-accounts.ts +0 -81
  93. package/server/methods/program/get-token-supply.ts +0 -39
  94. package/server/methods/program/index.ts +0 -21
  95. package/server/methods/solforge/index.ts +0 -158
  96. package/server/methods/system/get-health.ts +0 -5
  97. package/server/methods/system/get-minimum-balance-for-rent-exemption.ts +0 -13
  98. package/server/methods/system/get-version.ts +0 -9
  99. package/server/methods/system/index.ts +0 -3
  100. package/server/methods/transaction/get-confirmed-transaction.ts +0 -11
  101. package/server/methods/transaction/get-parsed-transaction.ts +0 -17
  102. package/server/methods/transaction/get-signature-statuses.ts +0 -79
  103. package/server/methods/transaction/get-signatures-for-address.ts +0 -41
  104. package/server/methods/transaction/get-transaction.ts +0 -639
  105. package/server/methods/transaction/index.ts +0 -7
  106. package/server/methods/transaction/inner-instructions.test.ts +0 -104
  107. package/server/methods/transaction/send-transaction.ts +0 -469
  108. package/server/methods/transaction/simulate-transaction.ts +0 -57
  109. package/server/rpc-server.ts +0 -521
  110. package/server/types.ts +0 -109
  111. package/server/ws-server.ts +0 -178
  112. package/src/api-server-entry.ts +0 -109
  113. package/src/cli/bootstrap.ts +0 -67
  114. package/src/cli/commands/airdrop.ts +0 -37
  115. package/src/cli/commands/config.ts +0 -39
  116. package/src/cli/commands/mint.ts +0 -187
  117. package/src/cli/commands/program-clone.ts +0 -122
  118. package/src/cli/commands/program-load.ts +0 -64
  119. package/src/cli/commands/rpc-start.ts +0 -49
  120. package/src/cli/commands/token-adopt-authority.ts +0 -37
  121. package/src/cli/commands/token-clone.ts +0 -112
  122. package/src/cli/commands/token-create.ts +0 -81
  123. package/src/cli/main.ts +0 -158
  124. package/src/cli/run-solforge.ts +0 -112
  125. package/src/cli/setup-utils.ts +0 -54
  126. package/src/cli/setup-wizard.ts +0 -258
  127. package/src/cli/utils/args.ts +0 -15
  128. package/src/commands/add-program.ts +0 -333
  129. package/src/commands/init.ts +0 -122
  130. package/src/commands/list.ts +0 -136
  131. package/src/commands/mint.ts +0 -287
  132. package/src/commands/start.ts +0 -881
  133. package/src/commands/status.ts +0 -99
  134. package/src/commands/stop.ts +0 -405
  135. package/src/config/index.ts +0 -146
  136. package/src/config/manager.ts +0 -157
  137. package/src/db/index.ts +0 -83
  138. package/src/db/schema/accounts.ts +0 -23
  139. package/src/db/schema/address-signatures.ts +0 -31
  140. package/src/db/schema/index.ts +0 -6
  141. package/src/db/schema/meta-kv.ts +0 -9
  142. package/src/db/schema/transactions.ts +0 -36
  143. package/src/db/schema/tx-account-states.ts +0 -23
  144. package/src/db/schema/tx-accounts.ts +0 -33
  145. package/src/db/tx-store.ts +0 -264
  146. package/src/gui/public/app.css +0 -1556
  147. package/src/gui/public/build/main.css +0 -1569
  148. package/src/gui/public/build/main.js +0 -303
  149. package/src/gui/public/build/main.js.txt +0 -231
  150. package/src/gui/public/index.html +0 -19
  151. package/src/gui/server.ts +0 -296
  152. package/src/gui/src/api.ts +0 -127
  153. package/src/gui/src/app.tsx +0 -441
  154. package/src/gui/src/components/airdrop-mint-form.tsx +0 -246
  155. package/src/gui/src/components/clone-program-modal.tsx +0 -202
  156. package/src/gui/src/components/clone-token-modal.tsx +0 -230
  157. package/src/gui/src/components/modal.tsx +0 -134
  158. package/src/gui/src/components/programs-panel.tsx +0 -124
  159. package/src/gui/src/components/status-panel.tsx +0 -136
  160. package/src/gui/src/components/tokens-panel.tsx +0 -122
  161. package/src/gui/src/hooks/use-interval.ts +0 -17
  162. package/src/gui/src/index.css +0 -557
  163. package/src/gui/src/main.tsx +0 -17
  164. package/src/index.ts +0 -216
  165. package/src/migrations-bundled.ts +0 -23
  166. package/src/rpc/start.ts +0 -44
  167. package/src/services/api-server.ts +0 -504
  168. package/src/services/port-manager.ts +0 -174
  169. package/src/services/process-registry.ts +0 -153
  170. package/src/services/program-cloner.ts +0 -317
  171. package/src/services/token-cloner.ts +0 -811
  172. package/src/services/validator.ts +0 -293
  173. package/src/types/config.ts +0 -110
  174. package/src/utils/shell.ts +0 -110
  175. package/src/utils/token-loader.ts +0 -115
@@ -1,122 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { readConfig, writeConfig } from "../../config";
3
- import { parseFlags } from "../utils/args";
4
-
5
- export async function programCloneCommand(args: string[]) {
6
- const { flags, rest } = parseFlags(args);
7
- const programId = (
8
- (rest[0] as string) ||
9
- (flags.program as string) ||
10
- ""
11
- ).trim();
12
- const configPath = flags.config as string | undefined;
13
- const cfg = await readConfig(configPath);
14
- const endpoint = (flags.endpoint as string) || cfg.clone.endpoint;
15
- const withAccounts = !!flags["with-accounts"];
16
- const accountsLimit = flags["accounts-limit"]
17
- ? Number(flags["accounts-limit"])
18
- : undefined;
19
- if (!programId) {
20
- p.log.error(
21
- "Usage: solforge program clone <programId> [--endpoint URL] [--with-accounts] [--accounts-limit N]",
22
- );
23
- return;
24
- }
25
- const url = `http://localhost:${cfg.server.rpcPort}`;
26
- const s = p.spinner();
27
- s.start("Cloning program...");
28
- try {
29
- const res = await fetch(url, {
30
- method: "POST",
31
- headers: { "content-type": "application/json" },
32
- body: JSON.stringify({
33
- jsonrpc: "2.0",
34
- id: 1,
35
- method: "solforgeAdminCloneProgram",
36
- params: [programId, { endpoint, withAccounts, accountsLimit }],
37
- }),
38
- });
39
- const json = await res.json();
40
- if (json.error) {
41
- const details = json.error.data
42
- ? `\nDetails: ${JSON.stringify(json.error.data)}`
43
- : "";
44
- throw new Error((json.error.message || "program clone failed") + details);
45
- }
46
- s.stop("Program cloned");
47
- console.log(JSON.stringify(json.result, null, 2));
48
- await recordProgramClone(configPath, programId);
49
- } catch (e) {
50
- s.stop("Clone failed");
51
- p.log.error(String(e));
52
- }
53
- }
54
-
55
- export async function programAccountsCloneCommand(args: string[]) {
56
- const { flags, rest } = parseFlags(args);
57
- const programId = (
58
- (rest[0] as string) ||
59
- (flags.program as string) ||
60
- ""
61
- ).trim();
62
- const configPath = flags.config as string | undefined;
63
- const cfg = await readConfig(configPath);
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;
67
- if (!programId) {
68
- p.log.error(
69
- "Usage: solforge program accounts clone <programId> [--endpoint URL] [--limit N] [--filters JSON]",
70
- );
71
- return;
72
- }
73
- const url = `http://localhost:${cfg.server.rpcPort}`;
74
- const s = p.spinner();
75
- s.start("Cloning program accounts...");
76
- try {
77
- const res = await fetch(url, {
78
- method: "POST",
79
- headers: { "content-type": "application/json" },
80
- body: JSON.stringify({
81
- jsonrpc: "2.0",
82
- id: 1,
83
- method: "solforgeAdminCloneProgramAccounts",
84
- params: [programId, { endpoint, limit, filters }],
85
- }),
86
- });
87
- const json = await res.json();
88
- if (json.error)
89
- throw new Error(json.error.message || "program accounts clone failed");
90
- s.stop("Program accounts cloned");
91
- console.log(JSON.stringify(json.result, null, 2));
92
- } catch (e) {
93
- s.stop("Clone failed");
94
- p.log.error(String(e));
95
- }
96
- }
97
-
98
- function safeJson(s: string): unknown {
99
- try {
100
- return JSON.parse(s);
101
- } catch {
102
- return undefined;
103
- }
104
- }
105
-
106
- async function recordProgramClone(
107
- configPath: string | undefined,
108
- programId: string,
109
- ) {
110
- try {
111
- const cfg = await readConfig(configPath);
112
- const next = new Set(cfg.clone.programs ?? []);
113
- if (!next.has(programId)) {
114
- next.add(programId);
115
- cfg.clone.programs = Array.from(next);
116
- await writeConfig(cfg, configPath ?? "sf.config.json");
117
- p.log.info(`Added ${programId} to clone programs in config`);
118
- }
119
- } catch (error) {
120
- console.warn(`[config] Failed to update clone programs: ${String(error)}`);
121
- }
122
- }
@@ -1,64 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { Connection, PublicKey } from "@solana/web3.js";
3
- import { readConfig } from "../../config";
4
- import { parseFlags } from "../utils/args";
5
-
6
- export async function programLoadCommand(args: string[]) {
7
- const { flags, rest } = parseFlags(args);
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
- if (!programId) {
12
- p.log.error(
13
- "Usage: solforge program load <programId> [--file PATH | --endpoint URL]",
14
- );
15
- return;
16
- }
17
- let base64: string | undefined;
18
- try {
19
- if (fromFile) {
20
- const bytes = await Bun.file(fromFile).arrayBuffer();
21
- base64 = Buffer.from(bytes).toString("base64");
22
- } else if (endpoint) {
23
- // Fetch ProgramData from endpoint
24
- const conn = new Connection(endpoint, "confirmed");
25
- const pid = new PublicKey(programId);
26
- const info = await conn.getAccountInfo(pid, "confirmed");
27
- if (!info) throw new Error("Program account not found on endpoint");
28
- // Program account should be upgradeable; fetch ProgramData and extract bytes after header
29
- // Heuristic: delegate parsing to server if unsure. Here, try raw first.
30
- base64 = Buffer.from(info.data as Buffer).toString("base64");
31
- } else {
32
- p.log.error("Either --file or --endpoint must be provided");
33
- return;
34
- }
35
- } catch (e) {
36
- p.log.error(`Failed to read ELF: ${String(e)}`);
37
- return;
38
- }
39
-
40
- const cfg = await readConfig();
41
- const url = `http://localhost:${cfg.server.rpcPort}`;
42
- const s = p.spinner();
43
- s.start("Loading program into LiteSVM...");
44
- try {
45
- const res = await fetch(url, {
46
- method: "POST",
47
- headers: { "content-type": "application/json" },
48
- body: JSON.stringify({
49
- jsonrpc: "2.0",
50
- id: 1,
51
- method: "solforgeLoadProgram",
52
- params: [programId, base64],
53
- }),
54
- });
55
- const json = await res.json();
56
- if (json.error)
57
- throw new Error(json.error.message || "program load failed");
58
- s.stop("Program loaded");
59
- console.log(JSON.stringify(json.result, null, 2));
60
- } catch (e) {
61
- s.stop("Load failed");
62
- p.log.error(String(e));
63
- }
64
- }
@@ -1,49 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { readConfig } from "../../config";
3
- import { startRpcServers } from "../../rpc/start";
4
- import { parseFlags } from "../utils/args";
5
-
6
- export async function rpcStartCommand(args: string[]) {
7
- const { flags } = parseFlags(args);
8
- const cfg = await readConfig(flags.config as string | undefined);
9
- const rpcPort = Number(flags.port ?? cfg.server.rpcPort ?? 8899);
10
- const wsPort = Number(flags["ws-port"] ?? cfg.server.wsPort ?? rpcPort + 1);
11
- const host =
12
- flags.network === true ? "0.0.0.0" : (flags.host as string) || "127.0.0.1";
13
- const dbMode =
14
- (flags["db-mode"] as string) || cfg.server.db.mode || "ephemeral";
15
- const dbPath =
16
- (flags["db-path"] as string) || cfg.server.db.path || ".solforge/db.db";
17
- const guiPort = Number(flags["gui-port"] ?? cfg.gui.port ?? 42069);
18
- const guiEnabled =
19
- flags["no-gui"] === true
20
- ? false
21
- : flags.gui === true
22
- ? true
23
- : cfg.gui.enabled !== false;
24
-
25
- const s = p.spinner();
26
- const guiMsg = guiEnabled ? `, GUI on ${guiPort}` : "";
27
- s.start(`Starting RPC on ${host}:${rpcPort}, WS on ${wsPort}${guiMsg}...`);
28
- try {
29
- const mode: "ephemeral" | "persistent" =
30
- dbMode === "persistent" ? "persistent" : "ephemeral";
31
- const started = startRpcServers({
32
- rpcPort,
33
- wsPort,
34
- dbMode: mode,
35
- dbPath,
36
- host,
37
- guiEnabled,
38
- guiPort,
39
- });
40
- s.stop("RPC started");
41
- console.log(`HTTP: http://${host}:${started.rpcPort}`);
42
- console.log(`WS: ws://${host}:${started.wsPort}`);
43
- if (started.guiPort) console.log(`GUI: http://${host}:${started.guiPort}`);
44
- } catch (e) {
45
- s.stop("Failed to start RPC");
46
- p.log.error(String(e));
47
- process.exitCode = 1;
48
- }
49
- }
@@ -1,37 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { readConfig } from "../../config";
3
- import { parseFlags } from "../utils/args";
4
-
5
- // Set the faucet as mint authority for an existing mint in LiteSVM (local-only)
6
- export async function tokenAdoptAuthorityCommand(args: string[]) {
7
- const { flags, rest } = parseFlags(args);
8
- const mint = (rest[0] as string) || (flags.mint as string);
9
- if (!mint) {
10
- p.log.error("Usage: solforge token adopt-authority <mint>");
11
- return;
12
- }
13
- const cfg = await readConfig();
14
- const url = `http://localhost:${cfg.server.rpcPort}`;
15
- const s = p.spinner();
16
- s.start("Adopting faucet as mint authority...");
17
- try {
18
- const res = await fetch(url, {
19
- method: "POST",
20
- headers: { "content-type": "application/json" },
21
- body: JSON.stringify({
22
- jsonrpc: "2.0",
23
- id: 1,
24
- method: "solforgeAdoptMintAuthority",
25
- params: [mint],
26
- }),
27
- });
28
- const json = await res.json();
29
- if (json.error)
30
- throw new Error(json.error.message || "adopt authority failed");
31
- s.stop("Authority updated");
32
- console.log(JSON.stringify(json.result, null, 2));
33
- } catch (e) {
34
- s.stop("Failed");
35
- p.log.error(String(e));
36
- }
37
- }
@@ -1,112 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { readConfig, writeConfig } from "../../config";
3
- import { parseFlags } from "../utils/args";
4
-
5
- // Simplified token "clone": create an ATA locally with the requested amount.
6
- // Usage:
7
- // solforge token clone <mint> --to <owner> --amount <baseUnits>
8
- // solforge token clone <mint> --to <owner> --ui-amount <num> --decimals <d>
9
- export async function tokenCloneCommand(args: string[]) {
10
- const { flags, rest } = parseFlags(args);
11
- const mint = ((rest[0] as string) || (flags.mint as string) || "").trim();
12
- if (!mint) {
13
- p.log.error(
14
- "Usage: solforge token clone <mint> [--amount <baseUnits> | --ui-amount <num>] [--endpoint URL]",
15
- );
16
- return;
17
- }
18
-
19
- const _owner = flags.to as string | undefined; // optional; defaults to faucet on server
20
- const configPath = flags.config as string | undefined;
21
- const cfg = await readConfig(configPath);
22
- const endpoint = (flags.endpoint as string) || cfg.clone.endpoint;
23
- const url = `http://localhost:${cfg.server.rpcPort}`;
24
- const s = p.spinner();
25
- s.start("Cloning mint into LiteSVM...");
26
- try {
27
- // First, mirror the mint account so downstream reads work
28
- const resMint = await fetch(url, {
29
- method: "POST",
30
- headers: { "content-type": "application/json" },
31
- body: JSON.stringify({
32
- jsonrpc: "2.0",
33
- id: 1,
34
- method: "solforgeAdminCloneTokenMint",
35
- params: [mint, { endpoint }],
36
- }),
37
- });
38
- const jsonMint = await resMint.json();
39
- if (jsonMint.error) {
40
- const data = jsonMint.error.data
41
- ? `\nDetails: ${JSON.stringify(jsonMint.error.data)}`
42
- : "";
43
- throw new Error((jsonMint.error.message || "clone mint failed") + data);
44
- }
45
- // Record mint in config immediately after a successful clone
46
- await recordTokenClone(configPath, mint);
47
- // Try to adopt faucet as mint authority for local usage (do not fail the command if this step fails)
48
- try {
49
- s.message("Adopting faucet as authority...");
50
- const resAdopt = await fetch(url, {
51
- method: "POST",
52
- headers: { "content-type": "application/json" },
53
- body: JSON.stringify({
54
- jsonrpc: "2.0",
55
- id: 3,
56
- method: "solforgeAdoptMintAuthority",
57
- params: [mint],
58
- }),
59
- });
60
- const jsonAdopt = await resAdopt.json();
61
- if (jsonAdopt.error) {
62
- p.log.warn(jsonAdopt.error.message || "adopt authority failed");
63
- s.stop("Mint cloned (authority unchanged)");
64
- console.log(
65
- JSON.stringify({ mint: jsonMint.result, adopt: null }, null, 2),
66
- );
67
- return;
68
- }
69
- s.stop("Mint cloned and authority adopted");
70
- console.log(
71
- JSON.stringify(
72
- { mint: jsonMint.result, adopt: jsonAdopt.result },
73
- null,
74
- 2,
75
- ),
76
- );
77
- return;
78
- } catch (adoptErr: unknown) {
79
- p.log.warn(
80
- `Adopt authority failed: ${adoptErr?.message || String(adoptErr)}`,
81
- );
82
- s.stop("Mint cloned (authority unchanged)");
83
- console.log(
84
- JSON.stringify({ mint: jsonMint.result, adopt: null }, null, 2),
85
- );
86
- return;
87
- }
88
- } catch (e) {
89
- s.stop("Clone failed");
90
- p.log.error(String(e));
91
- p.log.info(
92
- "Token clone mirrors an on-chain mint and requires network access to --endpoint. For an offline token, use 'solforge token create'.",
93
- );
94
- }
95
- }
96
-
97
- // intentionally no UI conversion here; clone mirrors the on-chain mint only
98
-
99
- async function recordTokenClone(configPath: string | undefined, mint: string) {
100
- try {
101
- const cfg = await readConfig(configPath);
102
- const next = new Set(cfg.clone.tokens ?? []);
103
- if (!next.has(mint)) {
104
- next.add(mint);
105
- cfg.clone.tokens = Array.from(next);
106
- await writeConfig(cfg, configPath ?? "sf.config.json");
107
- p.log.info(`Added ${mint} to clone tokens in config`);
108
- }
109
- } catch (error) {
110
- console.warn(`[config] Failed to update clone tokens: ${String(error)}`);
111
- }
112
- }
@@ -1,81 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { readConfig } from "../../config";
3
- import { parseFlags } from "../utils/args";
4
-
5
- // Create a new local SPL mint with given decimals and (optional) owner authority.
6
- // Also optionally create the owner's ATA with a starting balance (base units or UI amount).
7
- // Usage:
8
- // solforge token create --decimals <d> --owner <pubkey> [--mint <pubkey>] [--amount <baseUnits> | --ui-amount <num>]
9
- export async function tokenCreateCommand(args: string[]) {
10
- const { flags } = parseFlags(args);
11
- const decimals = flags.decimals ? Number(flags.decimals) : NaN;
12
- const owner = flags.owner as string | undefined;
13
- const mint = flags.mint as string | undefined;
14
- const amountBase = flags.amount as string | undefined;
15
- const uiAmount = flags["ui-amount"] as string | undefined;
16
-
17
- if (!Number.isFinite(decimals)) {
18
- p.log.error("--decimals is required (0-18)");
19
- return;
20
- }
21
- if (!owner) {
22
- p.log.error("--owner <pubkey> is required");
23
- return;
24
- }
25
-
26
- const cfg = await readConfig();
27
- const url = `http://localhost:${cfg.server.rpcPort}`;
28
- const s = p.spinner();
29
- s.start("Creating mint...");
30
- try {
31
- const res = await fetch(url, {
32
- method: "POST",
33
- headers: { "content-type": "application/json" },
34
- body: JSON.stringify({
35
- jsonrpc: "2.0",
36
- id: 1,
37
- method: "solforgeCreateMint",
38
- params: [mint ?? null, Number(decimals), owner],
39
- }),
40
- });
41
- const json = await res.json();
42
- if (json.error) throw new Error(json.error.message || "create mint failed");
43
- const createdMint = json.result.mint as string;
44
-
45
- if (amountBase || uiAmount) {
46
- s.message("Creating owner ATA with balance...");
47
- const base =
48
- amountBase ??
49
- (uiAmount ? toBaseUnits(uiAmount, Number(decimals)) : undefined);
50
- const res2 = await fetch(url, {
51
- method: "POST",
52
- headers: { "content-type": "application/json" },
53
- body: JSON.stringify({
54
- jsonrpc: "2.0",
55
- id: 2,
56
- method: "solforgeCreateTokenAccount",
57
- params: [createdMint, owner, String(base)],
58
- }),
59
- });
60
- const json2 = await res2.json();
61
- if (json2.error)
62
- throw new Error(json2.error.message || "create token account failed");
63
- s.stop("Token created");
64
- console.log(
65
- JSON.stringify({ mint: json.result, account: json2.result }, null, 2),
66
- );
67
- return;
68
- }
69
- s.stop("Mint created");
70
- console.log(JSON.stringify(json.result, null, 2));
71
- } catch (e) {
72
- s.stop("Create failed");
73
- p.log.error(String(e));
74
- }
75
- }
76
-
77
- function toBaseUnits(ui: string, decimals: number): string {
78
- const [i, f = ""] = String(ui).split(".");
79
- const frac = (f + "0".repeat(decimals)).slice(0, decimals);
80
- return BigInt(i + (decimals ? frac : "")).toString();
81
- }
package/src/cli/main.ts DELETED
@@ -1,158 +0,0 @@
1
- // Minimal, fast CLI router with @clack/prompts for UX
2
- import * as p from "@clack/prompts";
3
- import { readFileSync } from "fs";
4
- import { join, dirname } from "path";
5
- import { fileURLToPath } from "url";
6
-
7
- const __dirname = dirname(fileURLToPath(import.meta.url));
8
- const pkgPath = join(__dirname, "../../package.json");
9
- const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
10
- const VERSION = pkg.version;
11
-
12
- // Robust arg parsing for both bun script and compiled binary
13
- const known = new Set([
14
- "help",
15
- "-h",
16
- "--help",
17
- "version",
18
- "-v",
19
- "--version",
20
- "rpc",
21
- "start",
22
- "config",
23
- "airdrop",
24
- "mint",
25
- "token",
26
- "program",
27
- ]);
28
- const raw = Bun.argv.slice(1);
29
- const firstIdx = raw.findIndex((a) => known.has(String(a)));
30
- const argv = firstIdx >= 0 ? raw.slice(firstIdx) : [];
31
-
32
- async function main() {
33
- const [cmd, sub, ...rest] = argv;
34
-
35
- if (!cmd) {
36
- const { runSolforge } = await import("./run-solforge");
37
- // Pass through any flags provided when no explicit command was given
38
- await runSolforge(raw);
39
- return;
40
- }
41
-
42
- if (cmd === "help" || cmd === "-h" || cmd === "--help") {
43
- printHelp();
44
- return;
45
- }
46
-
47
- if (cmd === "version" || cmd === "-v" || cmd === "--version") {
48
- printVersion();
49
- return;
50
- }
51
-
52
- // Alias: solforge start -> solforge rpc start
53
- if (cmd === "start") {
54
- // Run the full Solforge flow (config ensure + bootstrap + servers)
55
- const { runSolforge } = await import("./run-solforge");
56
- await runSolforge(rest);
57
- return;
58
- }
59
-
60
- switch (cmd) {
61
- case "rpc": {
62
- if (sub === "start") {
63
- const { rpcStartCommand } = await import("./commands/rpc-start");
64
- return rpcStartCommand(rest);
65
- }
66
- return unknownCommand([cmd, sub]);
67
- }
68
- case "config": {
69
- const { configCommand } = await import("./commands/config");
70
- return configCommand(sub, rest);
71
- }
72
- case "airdrop": {
73
- const { airdropCommand } = await import("./commands/airdrop");
74
- return airdropCommand(rest);
75
- }
76
- case "mint": {
77
- const { mintCommand } = await import("./commands/mint");
78
- return mintCommand(rest);
79
- }
80
- case "token": {
81
- if (sub === "clone") {
82
- const { tokenCloneCommand } = await import("./commands/token-clone");
83
- return tokenCloneCommand(rest);
84
- }
85
- if (sub === "create") {
86
- const { tokenCreateCommand } = await import("./commands/token-create");
87
- return tokenCreateCommand(rest);
88
- }
89
- if (sub === "adopt-authority") {
90
- const { tokenAdoptAuthorityCommand } = await import(
91
- "./commands/token-adopt-authority"
92
- );
93
- return tokenAdoptAuthorityCommand(rest);
94
- }
95
- return unknownCommand([cmd, sub]);
96
- }
97
- case "program": {
98
- if (sub === "clone") {
99
- const { programCloneCommand } = await import(
100
- "./commands/program-clone"
101
- );
102
- return programCloneCommand(rest);
103
- }
104
- if (sub === "load") {
105
- const { programLoadCommand } = await import("./commands/program-load");
106
- return programLoadCommand(rest);
107
- }
108
- if (sub === "accounts") {
109
- const [_, __, ...tail] = argv.slice(2); // re-read to check deep subcommand
110
- if (tail[0] === "clone") {
111
- const { programAccountsCloneCommand } = await import(
112
- "./commands/program-clone"
113
- );
114
- return programAccountsCloneCommand(tail.slice(1));
115
- }
116
- }
117
- return unknownCommand([cmd, sub]);
118
- }
119
- default:
120
- return unknownCommand([cmd, sub]);
121
- }
122
- }
123
-
124
- function printHelp() {
125
- console.log(`
126
- solforge <command>
127
-
128
- Commands:
129
- (no command) Run setup then start RPC & WS servers
130
- rpc start Start RPC & WS servers
131
- start Alias for 'rpc start'
132
- config init Create sf.config.json in CWD
133
- config get <key> Read a config value (dot path)
134
- config set <k> <v> Set a config value
135
- airdrop --to <pubkey> --sol <amount> Airdrop SOL via RPC faucet
136
- mint Interactive: pick mint, receiver, amount
137
- token clone <mint> Clone SPL token mint + accounts
138
- program clone <programId> Clone program code (and optionally accounts)
139
- program accounts clone <programId> Clone accounts owned by program
140
-
141
- Options:
142
- -h, --help Show help
143
- -v, --version Show version
144
- --network Bind servers to 0.0.0.0 (LAN access)
145
- -y, --ci Non-interactive; auto-accept prompts (use existing config)
146
- `);
147
- }
148
-
149
- async function unknownCommand(parts: (string | undefined)[]) {
150
- p.log.error(`Unknown command: ${parts.filter(Boolean).join(" ")}`);
151
- printHelp();
152
- }
153
-
154
- function printVersion() {
155
- console.log(String(VERSION));
156
- }
157
-
158
- main();