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,112 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import {
3
- defaultConfig,
4
- readConfig,
5
- type SolforgeConfig,
6
- writeConfig,
7
- } from "../config";
8
- import { startRpcServers } from "../rpc/start";
9
- import { bootstrapEnvironment } from "./bootstrap";
10
- import { cancelSetup } from "./setup-utils";
11
- import { runSetupWizard } from "./setup-wizard";
12
- import { parseFlags } from "./utils/args";
13
-
14
- const CONFIG_PATH = "sf.config.json";
15
-
16
- export async function runSolforge(args: string[] = []) {
17
- const { flags } = parseFlags(args);
18
- const ci = flags.ci === true || flags.y === true;
19
- const config = await ensureConfig(ci);
20
- await startWithConfig(config, args);
21
- }
22
-
23
- async function ensureConfig(ci = false): Promise<SolforgeConfig> {
24
- const exists = await Bun.file(CONFIG_PATH).exists();
25
- if (!exists) {
26
- if (ci) {
27
- // Non-interactive: write defaults and continue
28
- await saveConfig(defaultConfig);
29
- return defaultConfig;
30
- }
31
- p.intro("Solforge setup");
32
- const config = await runSetupWizard();
33
- await saveConfig(config);
34
- p.outro("Configuration saved");
35
- return config;
36
- }
37
-
38
- const current = await readConfig(CONFIG_PATH);
39
- if (ci) return current; // Non-interactive: always reuse existing config
40
- const reuse = await p.confirm({
41
- message: `Use existing config at ${CONFIG_PATH}?`,
42
- initialValue: true,
43
- });
44
- if (p.isCancel(reuse)) cancelSetup();
45
-
46
- if (reuse) return current;
47
-
48
- const updated = await runSetupWizard(current);
49
- await saveConfig(updated);
50
- return updated;
51
- }
52
-
53
- async function startWithConfig(config: SolforgeConfig, args: string[] = []) {
54
- const { flags } = parseFlags(args);
55
- const host = String(
56
- flags.network === true
57
- ? "0.0.0.0"
58
- : ((flags.host as string) ?? process.env.RPC_HOST ?? "127.0.0.1"),
59
- );
60
- const rpcPort = Number(config.server.rpcPort || defaultConfig.server.rpcPort);
61
- const wsPort = Number(config.server.wsPort || rpcPort + 1);
62
- const guiEnabled = config.gui?.enabled !== false;
63
- const guiPort = Number(config.gui?.port ?? defaultConfig.gui.port);
64
-
65
- const spinner = p.spinner();
66
- const guiPart = guiEnabled ? `, GUI ${guiPort}` : "";
67
- spinner.start(
68
- `Starting RPC on ${host}:${rpcPort} (WS ${wsPort}${guiPart})...`,
69
- );
70
- try {
71
- const started = startRpcServers({
72
- rpcPort,
73
- wsPort,
74
- dbMode: config.server.db.mode,
75
- dbPath: config.server.db.path,
76
- host,
77
- guiEnabled,
78
- guiPort,
79
- });
80
- spinner.stop("RPC started");
81
-
82
- await waitForRpc(`http://${host}:${started.rpcPort}`);
83
- await bootstrapEnvironment(config, host, started.rpcPort);
84
-
85
- p.log.success(
86
- `Solforge ready ➜ HTTP http://${host}:${started.rpcPort} | WS ws://${host}:${started.wsPort}${
87
- started.guiPort ? ` | GUI http://${host}:${started.guiPort}` : ""
88
- }`,
89
- );
90
- } catch (error) {
91
- spinner.stop("Failed to start RPC");
92
- p.log.error(String(error));
93
- process.exitCode = 1;
94
- }
95
- }
96
-
97
- async function waitForRpc(url: string, timeoutMs = 10_000) {
98
- const start = Date.now();
99
- while (Date.now() - start < timeoutMs) {
100
- try {
101
- const res = await fetch(`${url}/health`);
102
- if (res.ok) return;
103
- } catch {}
104
- await Bun.sleep(200);
105
- }
106
- throw new Error("RPC server did not become ready in time");
107
- }
108
-
109
- async function saveConfig(config: SolforgeConfig) {
110
- await writeConfig(config, CONFIG_PATH);
111
- p.log.success(`Updated ${CONFIG_PATH}`);
112
- }
@@ -1,54 +0,0 @@
1
- import * as p from "@clack/prompts";
2
-
3
- const CANCEL_MESSAGE = "Setup cancelled";
4
-
5
- export function cancelSetup(): never {
6
- p.cancel(CANCEL_MESSAGE);
7
- process.exit(0);
8
- }
9
-
10
- export function ensure<T>(value: T | symbol): T {
11
- if (p.isCancel(value)) cancelSetup();
12
- return value as T;
13
- }
14
-
15
- export function validatePort(value: string | number | undefined) {
16
- const num = Number(value);
17
- if (!Number.isInteger(num)) return "Port must be an integer";
18
- if (num < 1 || num > 65535) return "Port must be between 1 and 65535";
19
- return undefined;
20
- }
21
-
22
- export function validatePositiveNumber(value: string) {
23
- const num = Number(value);
24
- if (!Number.isFinite(num)) return "Enter a number";
25
- if (num <= 0) return "Enter a positive number";
26
- return undefined;
27
- }
28
-
29
- export function validatePubkey(value: string | undefined) {
30
- if (!value) return "Value is required";
31
- const trimmed = value.trim();
32
- if (trimmed.length < 32 || trimmed.length > 44)
33
- return "Expected base58 address";
34
- return undefined;
35
- }
36
-
37
- export async function collectCustomEntries(label: string) {
38
- const results: string[] = [];
39
- while (true) {
40
- const value = await p.text({
41
- message: `Enter ${label} (leave blank to finish)`,
42
- });
43
- if (p.isCancel(value)) cancelSetup();
44
- const trimmed = typeof value === "string" ? value.trim() : "";
45
- if (!trimmed) break;
46
- const error = validatePubkey(trimmed);
47
- if (error) {
48
- p.log.error(error);
49
- continue;
50
- }
51
- results.push(trimmed);
52
- }
53
- return results;
54
- }
@@ -1,258 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { defaultConfig, type SolforgeConfig } from "../config";
3
- import {
4
- cancelSetup,
5
- collectCustomEntries,
6
- ensure,
7
- validatePort,
8
- validatePositiveNumber,
9
- validatePubkey,
10
- } from "./setup-utils";
11
-
12
- const TOKEN_PRESETS = [
13
- {
14
- value: "usdc",
15
- label: "USDC",
16
- mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
17
- },
18
- {
19
- value: "usdt",
20
- label: "USDT",
21
- mint: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
22
- },
23
- ];
24
- const PROGRAM_PRESETS = [
25
- {
26
- value: "jupiter",
27
- label: "Jupiter",
28
- programId: "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
29
- },
30
- {
31
- value: "pump",
32
- label: "Pump core",
33
- programId: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
34
- },
35
- {
36
- value: "pump-amm",
37
- label: "Pump AMM",
38
- programId: "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
39
- },
40
- {
41
- value: "pump-fees",
42
- label: "Pump fees",
43
- programId: "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ",
44
- },
45
- ];
46
- export async function runSetupWizard(existing: SolforgeConfig = defaultConfig) {
47
- const base: SolforgeConfig = JSON.parse(JSON.stringify(existing));
48
-
49
- const rpcPort = Number(
50
- ensure(
51
- await p.text({
52
- message: "RPC port",
53
- initialValue: String(
54
- base.server.rpcPort ?? defaultConfig.server.rpcPort,
55
- ),
56
- validate: validatePort,
57
- }),
58
- ),
59
- );
60
-
61
- const wsPort = Number(
62
- ensure(
63
- await p.text({
64
- message: "WebSocket port",
65
- initialValue: String(base.server.wsPort ?? rpcPort + 1),
66
- validate: validatePort,
67
- }),
68
- ),
69
- );
70
-
71
- const guiEnabledResp = await p.confirm({
72
- message: "Enable GUI server?",
73
- initialValue: base.gui?.enabled ?? defaultConfig.gui.enabled,
74
- });
75
- if (p.isCancel(guiEnabledResp)) cancelSetup();
76
- const guiEnabled = guiEnabledResp !== false;
77
-
78
- let guiPort = base.gui?.port ?? defaultConfig.gui.port;
79
- if (guiEnabled) {
80
- guiPort = Number(
81
- ensure(
82
- await p.text({
83
- message: "GUI port",
84
- initialValue: String(guiPort ?? defaultConfig.gui.port),
85
- validate: validatePort,
86
- }),
87
- ),
88
- );
89
- }
90
-
91
- const endpoint = ensure(
92
- await p.text({
93
- message: "Source RPC endpoint for cloning",
94
- initialValue: base.clone.endpoint || defaultConfig.clone.endpoint,
95
- placeholder: defaultConfig.clone.endpoint,
96
- validate: (value) => (value ? undefined : "Endpoint is required"),
97
- }),
98
- ).trim();
99
-
100
- const tokenSelection = ensure(
101
- await p.multiselect({
102
- message: "Which tokens should be cloned into LiteSVM?",
103
- options: [
104
- ...TOKEN_PRESETS.map((token) => ({
105
- value: token.value,
106
- label: `${token.label} (${token.mint})`,
107
- })),
108
- { value: "__custom__", label: "Add custom token mint" },
109
- ],
110
- initialValues: TOKEN_PRESETS.filter((preset) =>
111
- base.clone.tokens?.includes(preset.mint),
112
- ).map((preset) => preset.value),
113
- required: false,
114
- }),
115
- ) as string[];
116
- let tokenSeed: string[] = [];
117
- if ((base.clone.tokens?.length ?? 0) > 0) {
118
- const keep = await p.confirm({
119
- message: `Keep existing token list (${base.clone.tokens.length})?`,
120
- initialValue: true,
121
- });
122
- if (p.isCancel(keep)) cancelSetup();
123
- if (keep) tokenSeed = [...base.clone.tokens];
124
- }
125
-
126
- const tokens = await resolveTokens(tokenSelection, tokenSeed);
127
-
128
- const programSelection = ensure(
129
- await p.multiselect({
130
- message: "Clone any on-chain programs?",
131
- options: [
132
- ...PROGRAM_PRESETS.map((program) => ({
133
- value: program.value,
134
- label: `${program.label} (${program.programId})`,
135
- })),
136
- { value: "__custom__", label: "Add custom program" },
137
- ],
138
- initialValues: PROGRAM_PRESETS.filter((preset) =>
139
- base.clone.programs?.includes(preset.programId),
140
- ).map((preset) => preset.value),
141
- required: false,
142
- }),
143
- ) as string[];
144
- let programSeed: string[] = [];
145
- if ((base.clone.programs?.length ?? 0) > 0) {
146
- const keepPrograms = await p.confirm({
147
- message: `Keep existing program list (${base.clone.programs.length})?`,
148
- initialValue: true,
149
- });
150
- if (p.isCancel(keepPrograms)) cancelSetup();
151
- if (keepPrograms) programSeed = [...base.clone.programs];
152
- }
153
-
154
- const programs = await resolvePrograms(programSelection, programSeed);
155
-
156
- const airdrops = await collectAirdrops(base.bootstrap?.airdrops ?? []);
157
-
158
- base.server.rpcPort = rpcPort;
159
- base.server.wsPort = wsPort;
160
- base.gui = { enabled: guiEnabled, port: guiPort ?? defaultConfig.gui.port };
161
- base.clone.endpoint = endpoint;
162
- base.clone.tokens = tokens;
163
- base.clone.programs = programs;
164
- base.bootstrap = { airdrops };
165
-
166
- return base;
167
- }
168
-
169
- async function resolveTokens(selections: string[], existing: string[] = []) {
170
- const set = new Set(existing);
171
- for (const selection of selections) {
172
- if (selection === "__custom__") {
173
- {
174
- const values = await collectCustomEntries("token mint address");
175
- for (const value of values) set.add(value);
176
- }
177
- continue;
178
- }
179
- const preset = TOKEN_PRESETS.find((token) => token.value === selection);
180
- if (!preset) continue;
181
- const mint = ensure(
182
- await p.text({
183
- message: `Mint address for ${preset.label}`,
184
- initialValue: preset.mint,
185
- validate: validatePubkey,
186
- }),
187
- ).trim();
188
- set.add(mint);
189
- }
190
- return Array.from(set);
191
- }
192
-
193
- async function resolvePrograms(selections: string[], existing: string[] = []) {
194
- const set = new Set(existing);
195
- for (const selection of selections) {
196
- if (selection === "__custom__") {
197
- {
198
- const values = await collectCustomEntries("program id");
199
- for (const value of values) set.add(value);
200
- }
201
- continue;
202
- }
203
- const preset = PROGRAM_PRESETS.find(
204
- (program) => program.value === selection,
205
- );
206
- if (!preset) continue;
207
- const programId = ensure(
208
- await p.text({
209
- message: `Program ID for ${preset.label}`,
210
- initialValue: preset.programId,
211
- validate: validatePubkey,
212
- }),
213
- ).trim();
214
- set.add(programId);
215
- }
216
- return Array.from(set);
217
- }
218
-
219
- async function collectAirdrops(
220
- existing: Array<{ address: string; amountSol: number }>,
221
- ) {
222
- const entries: Array<{ address: string; amountSol: number }> = [];
223
- if (existing.length > 0) {
224
- const keep = await p.confirm({
225
- message: `Keep existing airdrop recipients (${existing.length})?`,
226
- initialValue: true,
227
- });
228
- if (p.isCancel(keep)) cancelSetup();
229
- if (keep) entries.push(...existing);
230
- }
231
-
232
- while (true) {
233
- const address = await p.text({
234
- message:
235
- entries.length === 0
236
- ? "Airdrop recipient address (leave blank to skip)"
237
- : "Add another airdrop recipient (leave blank to finish)",
238
- });
239
- if (p.isCancel(address)) cancelSetup();
240
- const trimmed = typeof address === "string" ? address.trim() : "";
241
- if (!trimmed) break;
242
- const error = validatePubkey(trimmed);
243
- if (error) {
244
- p.log.error(error);
245
- continue;
246
- }
247
- const amount = ensure(
248
- await p.text({
249
- message: `Amount of SOL to airdrop to ${trimmed}`,
250
- initialValue: "100",
251
- validate: validatePositiveNumber,
252
- }),
253
- );
254
- entries.push({ address: trimmed, amountSol: Number(amount) });
255
- }
256
-
257
- return entries;
258
- }
@@ -1,15 +0,0 @@
1
- export function parseFlags(args: string[]) {
2
- const flags: Record<string, string | boolean> = {};
3
- const rest: string[] = [];
4
- for (let i = 0; i < args.length; i++) {
5
- const a = args[i];
6
- if (a.startsWith("--")) {
7
- const [k, v] = a.slice(2).split("=");
8
- if (typeof v === "string" && v.length > 0) flags[k] = v;
9
- else if (i + 1 < args.length && !args[i + 1].startsWith("-"))
10
- flags[k] = args[++i];
11
- else flags[k] = true;
12
- } else rest.push(a);
13
- }
14
- return { flags, rest };
15
- }