solforge 0.2.12 → 0.2.13

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 (174) hide show
  1. package/package.json +1 -5
  2. package/docs/API.md +0 -379
  3. package/docs/CONFIGURATION.md +0 -407
  4. package/docs/bun-single-file-executable.md +0 -585
  5. package/docs/cli-plan.md +0 -154
  6. package/docs/data-indexing-plan.md +0 -214
  7. package/docs/gui-roadmap.md +0 -202
  8. package/scripts/decode-b58.ts +0 -10
  9. package/scripts/install.sh +0 -112
  10. package/server/index.ts +0 -5
  11. package/server/lib/base58.ts +0 -33
  12. package/server/lib/faucet.ts +0 -110
  13. package/server/lib/instruction-parser.ts +0 -328
  14. package/server/lib/parsers/spl-associated-token-account.ts +0 -50
  15. package/server/lib/parsers/spl-token.ts +0 -340
  16. package/server/lib/spl-token.ts +0 -57
  17. package/server/methods/TEMPLATE.md +0 -117
  18. package/server/methods/account/get-account-info.ts +0 -86
  19. package/server/methods/account/get-balance.ts +0 -23
  20. package/server/methods/account/get-multiple-accounts.ts +0 -84
  21. package/server/methods/account/get-parsed-account-info.ts +0 -17
  22. package/server/methods/account/index.ts +0 -12
  23. package/server/methods/account/parsers/index.ts +0 -52
  24. package/server/methods/account/parsers/loader-upgradeable.ts +0 -79
  25. package/server/methods/account/parsers/spl-token.ts +0 -256
  26. package/server/methods/account/parsers/system.ts +0 -4
  27. package/server/methods/account/request-airdrop.ts +0 -271
  28. package/server/methods/admin/adopt-mint-authority.ts +0 -94
  29. package/server/methods/admin/clone-program-accounts.ts +0 -55
  30. package/server/methods/admin/clone-program.ts +0 -152
  31. package/server/methods/admin/clone-token-accounts.ts +0 -117
  32. package/server/methods/admin/clone-token-mint.ts +0 -82
  33. package/server/methods/admin/create-mint.ts +0 -114
  34. package/server/methods/admin/create-token-account.ts +0 -137
  35. package/server/methods/admin/helpers.ts +0 -70
  36. package/server/methods/admin/index.ts +0 -10
  37. package/server/methods/admin/list-mints.ts +0 -21
  38. package/server/methods/admin/load-program.ts +0 -52
  39. package/server/methods/admin/mint-to.ts +0 -266
  40. package/server/methods/block/get-block-height.ts +0 -5
  41. package/server/methods/block/get-block.ts +0 -31
  42. package/server/methods/block/get-blocks-with-limit.ts +0 -19
  43. package/server/methods/block/get-latest-blockhash.ts +0 -12
  44. package/server/methods/block/get-slot.ts +0 -5
  45. package/server/methods/block/index.ts +0 -6
  46. package/server/methods/block/is-blockhash-valid.ts +0 -19
  47. package/server/methods/epoch/get-cluster-nodes.ts +0 -17
  48. package/server/methods/epoch/get-epoch-info.ts +0 -16
  49. package/server/methods/epoch/get-epoch-schedule.ts +0 -15
  50. package/server/methods/epoch/get-highest-snapshot-slot.ts +0 -9
  51. package/server/methods/epoch/get-leader-schedule.ts +0 -8
  52. package/server/methods/epoch/get-max-retransmit-slot.ts +0 -9
  53. package/server/methods/epoch/get-max-shred-insert-slot.ts +0 -9
  54. package/server/methods/epoch/get-slot-leader.ts +0 -6
  55. package/server/methods/epoch/get-slot-leaders.ts +0 -9
  56. package/server/methods/epoch/get-stake-activation.ts +0 -9
  57. package/server/methods/epoch/get-stake-minimum-delegation.ts +0 -9
  58. package/server/methods/epoch/get-vote-accounts.ts +0 -19
  59. package/server/methods/epoch/index.ts +0 -13
  60. package/server/methods/epoch/minimum-ledger-slot.ts +0 -5
  61. package/server/methods/fee/get-fee-calculator-for-blockhash.ts +0 -12
  62. package/server/methods/fee/get-fee-for-message.ts +0 -8
  63. package/server/methods/fee/get-fee-rate-governor.ts +0 -16
  64. package/server/methods/fee/get-fees.ts +0 -14
  65. package/server/methods/fee/get-recent-prioritization-fees.ts +0 -22
  66. package/server/methods/fee/index.ts +0 -5
  67. package/server/methods/get-address-lookup-table.ts +0 -27
  68. package/server/methods/index.ts +0 -265
  69. package/server/methods/performance/get-recent-performance-samples.ts +0 -25
  70. package/server/methods/performance/get-transaction-count.ts +0 -5
  71. package/server/methods/performance/index.ts +0 -2
  72. package/server/methods/program/get-block-commitment.ts +0 -9
  73. package/server/methods/program/get-block-production.ts +0 -14
  74. package/server/methods/program/get-block-time.ts +0 -21
  75. package/server/methods/program/get-blocks.ts +0 -11
  76. package/server/methods/program/get-first-available-block.ts +0 -9
  77. package/server/methods/program/get-genesis-hash.ts +0 -6
  78. package/server/methods/program/get-identity.ts +0 -6
  79. package/server/methods/program/get-inflation-governor.ts +0 -15
  80. package/server/methods/program/get-inflation-rate.ts +0 -10
  81. package/server/methods/program/get-inflation-reward.ts +0 -12
  82. package/server/methods/program/get-largest-accounts.ts +0 -8
  83. package/server/methods/program/get-parsed-program-accounts.ts +0 -12
  84. package/server/methods/program/get-parsed-token-accounts-by-delegate.ts +0 -12
  85. package/server/methods/program/get-parsed-token-accounts-by-owner.ts +0 -12
  86. package/server/methods/program/get-program-accounts.ts +0 -221
  87. package/server/methods/program/get-supply.ts +0 -13
  88. package/server/methods/program/get-token-account-balance.ts +0 -60
  89. package/server/methods/program/get-token-accounts-by-delegate.ts +0 -82
  90. package/server/methods/program/get-token-accounts-by-owner.ts +0 -416
  91. package/server/methods/program/get-token-largest-accounts.ts +0 -81
  92. package/server/methods/program/get-token-supply.ts +0 -39
  93. package/server/methods/program/index.ts +0 -21
  94. package/server/methods/solforge/index.ts +0 -158
  95. package/server/methods/system/get-health.ts +0 -5
  96. package/server/methods/system/get-minimum-balance-for-rent-exemption.ts +0 -13
  97. package/server/methods/system/get-version.ts +0 -9
  98. package/server/methods/system/index.ts +0 -3
  99. package/server/methods/transaction/get-confirmed-transaction.ts +0 -11
  100. package/server/methods/transaction/get-parsed-transaction.ts +0 -17
  101. package/server/methods/transaction/get-signature-statuses.ts +0 -79
  102. package/server/methods/transaction/get-signatures-for-address.ts +0 -41
  103. package/server/methods/transaction/get-transaction.ts +0 -639
  104. package/server/methods/transaction/index.ts +0 -7
  105. package/server/methods/transaction/inner-instructions.test.ts +0 -104
  106. package/server/methods/transaction/send-transaction.ts +0 -469
  107. package/server/methods/transaction/simulate-transaction.ts +0 -57
  108. package/server/rpc-server.ts +0 -521
  109. package/server/types.ts +0 -109
  110. package/server/ws-server.ts +0 -178
  111. package/src/api-server-entry.ts +0 -109
  112. package/src/cli/bootstrap.ts +0 -67
  113. package/src/cli/commands/airdrop.ts +0 -37
  114. package/src/cli/commands/config.ts +0 -39
  115. package/src/cli/commands/mint.ts +0 -187
  116. package/src/cli/commands/program-clone.ts +0 -122
  117. package/src/cli/commands/program-load.ts +0 -64
  118. package/src/cli/commands/rpc-start.ts +0 -49
  119. package/src/cli/commands/token-adopt-authority.ts +0 -37
  120. package/src/cli/commands/token-clone.ts +0 -112
  121. package/src/cli/commands/token-create.ts +0 -81
  122. package/src/cli/main.ts +0 -158
  123. package/src/cli/run-solforge.ts +0 -112
  124. package/src/cli/setup-utils.ts +0 -54
  125. package/src/cli/setup-wizard.ts +0 -258
  126. package/src/cli/utils/args.ts +0 -15
  127. package/src/commands/add-program.ts +0 -333
  128. package/src/commands/init.ts +0 -122
  129. package/src/commands/list.ts +0 -136
  130. package/src/commands/mint.ts +0 -287
  131. package/src/commands/start.ts +0 -881
  132. package/src/commands/status.ts +0 -99
  133. package/src/commands/stop.ts +0 -405
  134. package/src/config/index.ts +0 -146
  135. package/src/config/manager.ts +0 -157
  136. package/src/db/index.ts +0 -83
  137. package/src/db/schema/accounts.ts +0 -23
  138. package/src/db/schema/address-signatures.ts +0 -31
  139. package/src/db/schema/index.ts +0 -6
  140. package/src/db/schema/meta-kv.ts +0 -9
  141. package/src/db/schema/transactions.ts +0 -36
  142. package/src/db/schema/tx-account-states.ts +0 -23
  143. package/src/db/schema/tx-accounts.ts +0 -33
  144. package/src/db/tx-store.ts +0 -264
  145. package/src/gui/public/app.css +0 -1556
  146. package/src/gui/public/build/main.css +0 -1569
  147. package/src/gui/public/build/main.js +0 -303
  148. package/src/gui/public/build/main.js.txt +0 -231
  149. package/src/gui/public/index.html +0 -19
  150. package/src/gui/server.ts +0 -296
  151. package/src/gui/src/api.ts +0 -127
  152. package/src/gui/src/app.tsx +0 -441
  153. package/src/gui/src/components/airdrop-mint-form.tsx +0 -246
  154. package/src/gui/src/components/clone-program-modal.tsx +0 -202
  155. package/src/gui/src/components/clone-token-modal.tsx +0 -230
  156. package/src/gui/src/components/modal.tsx +0 -134
  157. package/src/gui/src/components/programs-panel.tsx +0 -124
  158. package/src/gui/src/components/status-panel.tsx +0 -136
  159. package/src/gui/src/components/tokens-panel.tsx +0 -122
  160. package/src/gui/src/hooks/use-interval.ts +0 -17
  161. package/src/gui/src/index.css +0 -557
  162. package/src/gui/src/main.tsx +0 -17
  163. package/src/index.ts +0 -216
  164. package/src/migrations-bundled.ts +0 -23
  165. package/src/rpc/start.ts +0 -44
  166. package/src/services/api-server.ts +0 -504
  167. package/src/services/port-manager.ts +0 -174
  168. package/src/services/process-registry.ts +0 -153
  169. package/src/services/program-cloner.ts +0 -317
  170. package/src/services/token-cloner.ts +0 -811
  171. package/src/services/validator.ts +0 -293
  172. package/src/types/config.ts +0 -110
  173. package/src/utils/shell.ts +0 -110
  174. 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();