solforge 0.1.7 → 0.2.1

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 (151) hide show
  1. package/README.md +367 -393
  2. package/docs/API.md +379 -0
  3. package/docs/CONFIGURATION.md +407 -0
  4. package/docs/bun-single-file-executable.md +585 -0
  5. package/docs/cli-plan.md +154 -0
  6. package/docs/data-indexing-plan.md +214 -0
  7. package/docs/gui-roadmap.md +202 -0
  8. package/package.json +38 -51
  9. package/server/index.ts +5 -0
  10. package/server/lib/base58.ts +33 -0
  11. package/server/lib/faucet.ts +110 -0
  12. package/server/lib/spl-token.ts +57 -0
  13. package/server/methods/TEMPLATE.md +117 -0
  14. package/server/methods/account/get-account-info.ts +90 -0
  15. package/server/methods/account/get-balance.ts +27 -0
  16. package/server/methods/account/get-multiple-accounts.ts +83 -0
  17. package/server/methods/account/get-parsed-account-info.ts +21 -0
  18. package/server/methods/account/index.ts +12 -0
  19. package/server/methods/account/parsers/index.ts +52 -0
  20. package/server/methods/account/parsers/loader-upgradeable.ts +66 -0
  21. package/server/methods/account/parsers/spl-token.ts +237 -0
  22. package/server/methods/account/parsers/system.ts +4 -0
  23. package/server/methods/account/request-airdrop.ts +219 -0
  24. package/server/methods/admin/adopt-mint-authority.ts +94 -0
  25. package/server/methods/admin/clone-program-accounts.ts +55 -0
  26. package/server/methods/admin/clone-program.ts +152 -0
  27. package/server/methods/admin/clone-token-accounts.ts +117 -0
  28. package/server/methods/admin/clone-token-mint.ts +82 -0
  29. package/server/methods/admin/create-mint.ts +114 -0
  30. package/server/methods/admin/create-token-account.ts +137 -0
  31. package/server/methods/admin/helpers.ts +70 -0
  32. package/server/methods/admin/index.ts +10 -0
  33. package/server/methods/admin/list-mints.ts +21 -0
  34. package/server/methods/admin/load-program.ts +52 -0
  35. package/server/methods/admin/mint-to.ts +278 -0
  36. package/server/methods/block/get-block-height.ts +5 -0
  37. package/server/methods/block/get-block.ts +35 -0
  38. package/server/methods/block/get-blocks-with-limit.ts +23 -0
  39. package/server/methods/block/get-latest-blockhash.ts +12 -0
  40. package/server/methods/block/get-slot.ts +5 -0
  41. package/server/methods/block/index.ts +6 -0
  42. package/server/methods/block/is-blockhash-valid.ts +23 -0
  43. package/server/methods/epoch/get-cluster-nodes.ts +17 -0
  44. package/server/methods/epoch/get-epoch-info.ts +16 -0
  45. package/server/methods/epoch/get-epoch-schedule.ts +15 -0
  46. package/server/methods/epoch/get-highest-snapshot-slot.ts +9 -0
  47. package/server/methods/epoch/get-leader-schedule.ts +8 -0
  48. package/server/methods/epoch/get-max-retransmit-slot.ts +9 -0
  49. package/server/methods/epoch/get-max-shred-insert-slot.ts +9 -0
  50. package/server/methods/epoch/get-slot-leader.ts +6 -0
  51. package/server/methods/epoch/get-slot-leaders.ts +9 -0
  52. package/server/methods/epoch/get-stake-activation.ts +9 -0
  53. package/server/methods/epoch/get-stake-minimum-delegation.ts +9 -0
  54. package/server/methods/epoch/get-vote-accounts.ts +19 -0
  55. package/server/methods/epoch/index.ts +13 -0
  56. package/server/methods/epoch/minimum-ledger-slot.ts +5 -0
  57. package/server/methods/fee/get-fee-calculator-for-blockhash.ts +12 -0
  58. package/server/methods/fee/get-fee-for-message.ts +8 -0
  59. package/server/methods/fee/get-fee-rate-governor.ts +16 -0
  60. package/server/methods/fee/get-fees.ts +14 -0
  61. package/server/methods/fee/get-recent-prioritization-fees.ts +22 -0
  62. package/server/methods/fee/index.ts +5 -0
  63. package/server/methods/get-address-lookup-table.ts +31 -0
  64. package/server/methods/index.ts +265 -0
  65. package/server/methods/performance/get-recent-performance-samples.ts +25 -0
  66. package/server/methods/performance/get-transaction-count.ts +5 -0
  67. package/server/methods/performance/index.ts +2 -0
  68. package/server/methods/program/get-block-commitment.ts +9 -0
  69. package/server/methods/program/get-block-production.ts +14 -0
  70. package/server/methods/program/get-block-time.ts +21 -0
  71. package/server/methods/program/get-blocks.ts +11 -0
  72. package/server/methods/program/get-first-available-block.ts +9 -0
  73. package/server/methods/program/get-genesis-hash.ts +6 -0
  74. package/server/methods/program/get-identity.ts +6 -0
  75. package/server/methods/program/get-inflation-governor.ts +15 -0
  76. package/server/methods/program/get-inflation-rate.ts +10 -0
  77. package/server/methods/program/get-inflation-reward.ts +12 -0
  78. package/server/methods/program/get-largest-accounts.ts +8 -0
  79. package/server/methods/program/get-parsed-program-accounts.ts +12 -0
  80. package/server/methods/program/get-parsed-token-accounts-by-delegate.ts +12 -0
  81. package/server/methods/program/get-parsed-token-accounts-by-owner.ts +12 -0
  82. package/server/methods/program/get-program-accounts.ts +221 -0
  83. package/server/methods/program/get-supply.ts +13 -0
  84. package/server/methods/program/get-token-account-balance.ts +64 -0
  85. package/server/methods/program/get-token-accounts-by-delegate.ts +81 -0
  86. package/server/methods/program/get-token-accounts-by-owner.ts +390 -0
  87. package/server/methods/program/get-token-largest-accounts.ts +80 -0
  88. package/server/methods/program/get-token-supply.ts +38 -0
  89. package/server/methods/program/index.ts +21 -0
  90. package/server/methods/solforge/index.ts +155 -0
  91. package/server/methods/system/get-health.ts +5 -0
  92. package/server/methods/system/get-minimum-balance-for-rent-exemption.ts +13 -0
  93. package/server/methods/system/get-version.ts +9 -0
  94. package/server/methods/system/index.ts +3 -0
  95. package/server/methods/transaction/get-confirmed-transaction.ts +11 -0
  96. package/server/methods/transaction/get-parsed-transaction.ts +21 -0
  97. package/server/methods/transaction/get-signature-statuses.ts +72 -0
  98. package/server/methods/transaction/get-signatures-for-address.ts +45 -0
  99. package/server/methods/transaction/get-transaction.ts +428 -0
  100. package/server/methods/transaction/index.ts +7 -0
  101. package/server/methods/transaction/send-transaction.ts +232 -0
  102. package/server/methods/transaction/simulate-transaction.ts +56 -0
  103. package/server/rpc-server.ts +474 -0
  104. package/server/types.ts +74 -0
  105. package/server/ws-server.ts +171 -0
  106. package/src/cli/bootstrap.ts +67 -0
  107. package/src/cli/commands/airdrop.ts +37 -0
  108. package/src/cli/commands/config.ts +39 -0
  109. package/src/cli/commands/mint.ts +187 -0
  110. package/src/cli/commands/program-clone.ts +124 -0
  111. package/src/cli/commands/program-load.ts +64 -0
  112. package/src/cli/commands/rpc-start.ts +46 -0
  113. package/src/cli/commands/token-adopt-authority.ts +37 -0
  114. package/src/cli/commands/token-clone.ts +113 -0
  115. package/src/cli/commands/token-create.ts +81 -0
  116. package/src/cli/main.ts +130 -0
  117. package/src/cli/run-solforge.ts +98 -0
  118. package/src/cli/setup-utils.ts +54 -0
  119. package/src/cli/setup-wizard.ts +256 -0
  120. package/src/cli/utils/args.ts +15 -0
  121. package/src/config/index.ts +130 -0
  122. package/src/db/index.ts +83 -0
  123. package/src/db/schema/accounts.ts +23 -0
  124. package/src/db/schema/address-signatures.ts +31 -0
  125. package/src/db/schema/index.ts +5 -0
  126. package/src/db/schema/meta-kv.ts +9 -0
  127. package/src/db/schema/transactions.ts +29 -0
  128. package/src/db/schema/tx-accounts.ts +33 -0
  129. package/src/db/tx-store.ts +229 -0
  130. package/src/gui/public/app.css +1 -0
  131. package/src/gui/public/build/main.css +1 -0
  132. package/src/gui/public/build/main.js +303 -0
  133. package/src/gui/public/build/main.js.txt +231 -0
  134. package/src/gui/public/index.html +19 -0
  135. package/src/gui/server.ts +297 -0
  136. package/src/gui/src/api.ts +127 -0
  137. package/src/gui/src/app.tsx +390 -0
  138. package/src/gui/src/components/airdrop-mint-form.tsx +216 -0
  139. package/src/gui/src/components/clone-program-modal.tsx +183 -0
  140. package/src/gui/src/components/clone-token-modal.tsx +211 -0
  141. package/src/gui/src/components/modal.tsx +127 -0
  142. package/src/gui/src/components/programs-panel.tsx +112 -0
  143. package/src/gui/src/components/status-panel.tsx +122 -0
  144. package/src/gui/src/components/tokens-panel.tsx +116 -0
  145. package/src/gui/src/hooks/use-interval.ts +17 -0
  146. package/src/gui/src/index.css +529 -0
  147. package/src/gui/src/main.tsx +17 -0
  148. package/src/migrations-bundled.ts +17 -0
  149. package/src/rpc/start.ts +44 -0
  150. package/scripts/postinstall.cjs +0 -103
  151. package/tsconfig.json +0 -28
@@ -0,0 +1,154 @@
1
+ # SolForge CLI & GUI Plan
2
+
3
+ ## Goals
4
+ - Ship a single `solforge` CLI with subcommands to manage a local LiteSVM.
5
+ - Provide an optional GUI dashboard (React in Bun) via `solforge gui`.
6
+ - Support a project-local `sf.config.json` for reproducible environments.
7
+ - Add cloning utilities to import programs, program accounts, and tokens from mainnet.
8
+
9
+ ## Command Surface (Phase 1)
10
+
11
+ - `solforge rpc start [options]` (alias: `solforge start`)
12
+ - Starts JSON-RPC server and WS server.
13
+ - Options: `--port <num>` (HTTP), `--ws-port <num>`, `--db-mode <ephemeral|persistent>`, `--db-path <path>`, `--faucet <SOL>`, `--config <path>`.
14
+ - Reads defaults from `sf.config.json` in CWD when present.
15
+
16
+ - `solforge gui [options]`
17
+ - Starts the RPC server and serves a React dashboard via Bun `routes` on the same process.
18
+ - Options: same as `start`, plus `--ui-port <num>` if served separately (fallback if port sharing is problematic).
19
+
20
+ - `solforge config init [--force]`
21
+ - Writes a new `sf.config.json` into CWD with sensible defaults.
22
+
23
+ - `solforge config get <key>`
24
+ - Prints value from config (supports dot-path: e.g. `svm.initialLamports`).
25
+
26
+ - `solforge config set <key> <value>`
27
+ - Updates config keys (creates nested keys as needed).
28
+
29
+ - `solforge token clone <mintAddress> [options]`
30
+ - Clones SPL Token mint and (optionally) selected token accounts from mainnet to LiteSVM.
31
+ - Options: `--endpoint <url>`, `--all-accounts`, `--holders <N>`, `--program <tokenProgramId>`.
32
+
33
+ - `solforge program clone <programId> [options]`
34
+ - Clones an executable program account’s data from mainnet to LiteSVM.
35
+ - Options: `--endpoint <url>`, `--with-accounts`, `--accounts-limit <N>`, `--filters <json>`.
36
+
37
+ - `solforge program accounts clone <programId> [options]`
38
+ - Clones accounts owned by a program from mainnet to LiteSVM (no code).
39
+ - Options: `--endpoint <url>`, `--limit <N>`, `--filters <json>`.
40
+
41
+ ## Configuration: `sf.config.json`
42
+
43
+ ```json
44
+ {
45
+ "$schema": "./docs/sf-config.schema.json",
46
+ "server": {
47
+ "rpcPort": 8899,
48
+ "wsPort": 8900,
49
+ "db": { "mode": "ephemeral", "path": ".solforge/db.db" }
50
+ },
51
+ "svm": {
52
+ "initialLamports": "1000000000000000",
53
+ "faucetSOL": 1000
54
+ },
55
+ "clone": {
56
+ "endpoint": "https://api.mainnet-beta.solana.com",
57
+ "programs": ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
58
+ "tokens": ["So11111111111111111111111111111111111111112"],
59
+ "programAccounts": [
60
+ { "programId": "Tokenkeg...", "limit": 1000, "filters": [] }
61
+ ]
62
+ },
63
+ "gui": {
64
+ "enabled": false,
65
+ "uiPath": "ui/public/index.html",
66
+ "port": null
67
+ }
68
+ }
69
+ ```
70
+
71
+ Notes:
72
+ - Values like `initialLamports` use string BigInt to avoid JSON precision loss.
73
+ - `clone.endpoint` can be overridden per-command with `--endpoint`.
74
+
75
+ ## Architecture & Files
76
+
77
+ - `src/cli/`
78
+ - `main.ts` — CLI entry: parses `Bun.argv`, dispatches subcommands.
79
+ - `commands/start.ts` — start server from config/flags.
80
+ - `commands/gui.ts` — start server with UI routes.
81
+ - `commands/config.ts` — init/get/set helpers.
82
+ - `commands/token-clone.ts` — clone mint + accounts.
83
+ - `commands/program-clone.ts` — clone program code.
84
+ - `commands/program-accounts-clone.ts` — clone owned accounts.
85
+ - `utils/prompts.ts` — wrapper around `@clack/prompts` for consistent UX.
86
+
87
+ - `src/config/`
88
+ - `index.ts` — read/merge/validate config, dot-path get/set, write.
89
+ - `types.ts` — shared config types.
90
+
91
+ - `src/rpc/` (facade over current `server/` initially)
92
+ - `start.ts` — wraps existing RPC/WS start with options: ports, db, gui routes.
93
+ - Reuse `server/rpc-server.ts` and `server/ws-server.ts` (minimal changes). Later we can move code into `src/rpc/`.
94
+
95
+ - `ui/`
96
+ - `public/index.html` — HTML entry (dashboard shell).
97
+ - `src/app.tsx`, `src/main.tsx`, `src/styles.css` — React app.
98
+
99
+ ## Server Integration for GUI
100
+
101
+ - Use `Bun.serve({ routes: { "/": indexHtml, ... }, fetch })` so GET `"/"` serves UI while POST continues to handle JSON-RPC.
102
+ - When `gui` is enabled, inject `routes` and optionally set `development: true` when `NODE_ENV !== 'production'`.
103
+ - Fallback: serve UI on separate port if needed via `--ui-port`.
104
+
105
+ ## Cloning Strategy (Phase 1)
106
+
107
+ - Dependencies: use `@solana/web3.js` or `@solana/kit` for reads only (no new deps).
108
+ - Token clone
109
+ - Fetch mint account data; create in LiteSVM with same address/data/owner.
110
+ - Optionally fetch top-N token accounts by balance and recreate.
111
+ - Program clone
112
+ - Fetch program account; write executable account with original data.
113
+ - Optional: clone owned program accounts (same flow as program-accounts clone).
114
+ - Program accounts clone
115
+ - Use `getProgramAccounts` with filters/limit; recreate in LiteSVM.
116
+
117
+ ## Build & Packaging
118
+
119
+ - Compile `src/cli/main.ts` to single binary: `bun build src/cli/main.ts --compile --outfile dist/solforge`.
120
+ - Drizzle migrations: use the existing `drizzle/` folder. No duplicate embedded SQL.
121
+ - Packaging options:
122
+ - A) Distribute binary alongside the `drizzle/` folder (simple; zero duplication).
123
+ - B) If strict single-file is required, reference the existing SQL files via static imports so Bun bundles them (no duplication), and add a tiny read adapter that feeds them to the migrator. We will only do this if you choose strict single-file.
124
+
125
+ ## Testing (Phase 1)
126
+
127
+ - `bun:test` unit tests for:
128
+ - CLI parsing and dispatch.
129
+ - Config read/write and dot-path set/get.
130
+ - Start command: start on random port, `/health` responds.
131
+ - Light e2e for cloning commands behind a flag (skipped in CI by default).
132
+
133
+ ## Phases & Milestones
134
+
135
+ 1) CLI Scaffold
136
+ - CLI entry + help, `rpc start`, `config init|get|set`.
137
+ 2) GUI Integration
138
+ - React scaffold, route via server, `solforge gui` command.
139
+ 3) Cloning Utilities
140
+ - `token clone`, `program clone`, `program accounts clone`.
141
+ 4) Polish & Packaging
142
+ - Build targets, README docs, usage examples.
143
+
144
+ ## Acceptance Criteria (Phase 1)
145
+
146
+ - `solforge rpc start` (and alias `solforge start`) launches RPC + WS, reading `sf.config.json`.
147
+ - `solforge gui` serves React dashboard and RPC on same process.
148
+ - `solforge config init|get|set` operates on CWD `sf.config.json`.
149
+ - Binaries produced for macOS/Linux/Windows via `bun build --compile`.
150
+
151
+ ## CLI Libraries
152
+
153
+ - Prompts: `@clack/prompts` from the start for interactive flows (init, confirm, selects).
154
+ - Router: minimal zero-dependency command router over `Bun.argv` for speed and clarity.
@@ -0,0 +1,214 @@
1
+ # SolForge Data Indexing Plan (Bun + Drizzle ORM + SQLite)
2
+
3
+ This plan proposes a durable, fast, and simple data indexing layer for SolForge using Bun's native SQLite driver with Drizzle ORM. The goal is to persist and index everything relevant (transactions, accounts, token data, addresses, blocks) so we can power missing RPCs, explorer views, and historical queries that LiteSVM does not natively provide.
4
+
5
+ ## Objectives
6
+
7
+ - Persist all state-changing events and key reads for durability and queryability.
8
+ - Provide fast lookups for explorer-style methods (e.g., getSignaturesForAddress, getProgramAccounts, token queries).
9
+ - Maintain an in-memory hot cache for the most recent N items while SQLite is the source of truth.
10
+ - Keep the implementation simple and Bun-native: Bun + Drizzle + `bun:sqlite`.
11
+
12
+ ## Tech Choices
13
+
14
+ - Storage: SQLite (via Bun's `bun:sqlite`) with WAL mode.
15
+ - ORM / schema: Drizzle ORM for schema definition and migrations.
16
+ - Runtime: Single-writer transaction queue; prepared statements for reads.
17
+ - Optional hot cache: Small LRU for last N transactions and frequently accessed accounts.
18
+
19
+ Reference: https://orm.drizzle.team/docs/connect-bun-sqlite
20
+
21
+ ## High-Level Architecture
22
+
23
+ - Event-driven ingestion:
24
+ - On `sendTransaction`/`requestAirdrop`, capture and store full transaction bundle and touch all involved accounts.
25
+ - On `getAccountInfo`/`getMultipleAccounts`, opportunistically upsert latest account snapshots and update last-seen.
26
+ - Read path:
27
+ - Explorer calls first check in-memory cache, then fall back to SQLite via Drizzle.
28
+ - Durability:
29
+ - Store everything important, including raw wire tx (base64), logs, balances, version, and account snapshots.
30
+
31
+ ## Drizzle Schema (SQLite)
32
+
33
+ - `transactions`
34
+ - `signature` TEXT PRIMARY KEY
35
+ - `slot` INTEGER NOT NULL
36
+ - `block_time` INTEGER NULL
37
+ - `version` TEXT NOT NULL // 0 | "legacy"
38
+ - `err_json` TEXT NULL // JSON or null
39
+ - `fee` INTEGER NOT NULL
40
+ - `raw_base64` TEXT NOT NULL
41
+ - `pre_balances_json` TEXT NOT NULL
42
+ - `post_balances_json` TEXT NOT NULL
43
+ - `logs_json` TEXT NOT NULL
44
+ - Index: `slot DESC`
45
+
46
+ - `tx_accounts`
47
+ - `signature` TEXT NOT NULL
48
+ - `account_index` INTEGER NOT NULL
49
+ - `address` TEXT NOT NULL // base58
50
+ - `signer` INTEGER NOT NULL // 0/1
51
+ - `writable` INTEGER NOT NULL // 0/1
52
+ - `program_id_index` INTEGER NULL
53
+ - PRIMARY KEY (`signature`, `account_index`)
54
+ - Indexes: (`address`), (`address`, `signature`) for joins
55
+
56
+ - `addresses`
57
+ - `address` TEXT PRIMARY KEY
58
+ - `first_seen_slot` INTEGER
59
+ - `last_seen_slot` INTEGER
60
+ - `type` TEXT NULL // "program" | "system" | "user" | "pda" | "token-mint" | "token-account"
61
+
62
+ - `accounts` (latest snapshot)
63
+ - `address` TEXT PRIMARY KEY
64
+ - `lamports` INTEGER NOT NULL
65
+ - `owner_program` TEXT NOT NULL
66
+ - `executable` INTEGER NOT NULL
67
+ - `rent_epoch` INTEGER NOT NULL
68
+ - `data_len` INTEGER NOT NULL
69
+ - `data_base64` TEXT NULL // optional; off by default
70
+ - `last_slot` INTEGER NOT NULL
71
+ - Indexes: (`owner_program`), (`last_slot` DESC)
72
+
73
+ - `account_history` (optional, time-travel)
74
+ - `address` TEXT NOT NULL
75
+ - `slot` INTEGER NOT NULL
76
+ - `lamports` INTEGER
77
+ - `owner_program` TEXT
78
+ - `data_len` INTEGER
79
+ - `data_base64` TEXT NULL
80
+ - PRIMARY KEY (`address`, `slot`)
81
+
82
+ - `address_signatures` (fast address → signatures)
83
+ - `address` TEXT NOT NULL
84
+ - `signature` TEXT NOT NULL
85
+ - `slot` INTEGER NOT NULL
86
+ - `err` INTEGER NOT NULL // 0/1
87
+ - `block_time` INTEGER NULL
88
+ - PRIMARY KEY (`address`, `signature`)
89
+ - Index: (`address`, `slot` DESC)
90
+
91
+ - Token normalization
92
+ - `token_mints`:
93
+ - `mint` TEXT PRIMARY KEY
94
+ - `decimals` INTEGER
95
+ - `supply` TEXT
96
+ - `mint_authority` TEXT NULL
97
+ - `freeze_authority` TEXT NULL
98
+ - `last_slot` INTEGER
99
+ - `token_accounts`:
100
+ - `address` TEXT PRIMARY KEY
101
+ - `mint` TEXT NOT NULL
102
+ - `owner` TEXT NOT NULL
103
+ - `amount` TEXT NOT NULL
104
+ - `delegate` TEXT NULL
105
+ - `delegated_amount` TEXT NULL
106
+ - `state` TEXT NOT NULL
107
+ - `is_native` INTEGER NOT NULL
108
+ - `last_slot` INTEGER
109
+ - Indexes: (`owner`), (`mint`)
110
+
111
+ - `blocks`
112
+ - `slot` INTEGER PRIMARY KEY
113
+ - `blockhash` TEXT
114
+ - `previous_blockhash` TEXT
115
+ - `parent_slot` INTEGER
116
+ - `block_time` INTEGER
117
+
118
+ - `meta_kv`
119
+ - `key` TEXT PRIMARY KEY
120
+ - `value` TEXT
121
+
122
+ Notes:
123
+ - JSON is stored as TEXT in SQLite; parse at the API boundary.
124
+ - Raw transactions stored as base64 TEXT for simplicity.
125
+
126
+ ## PRAGMA and DB Settings
127
+
128
+ - Execute at startup:
129
+ - `PRAGMA journal_mode=WAL;`
130
+ - `PRAGMA synchronous=NORMAL;`
131
+ - `PRAGMA temp_store=MEMORY;`
132
+ - `PRAGMA busy_timeout=1000;`
133
+
134
+ ## Ingestion Pipelines
135
+
136
+ - Transaction ingestion (inside one DB transaction):
137
+ 1. Insert into `transactions` (signature, slot, block_time, version, fee, err_json, raw_base64, pre/post balances, logs).
138
+ 2. Insert into `tx_accounts` (one row per static account key) with signer/writable flags.
139
+ 3. Insert into `address_signatures` for each static account key, joining slot/err.
140
+ 4. For each static account key:
141
+ - Pull latest account from LiteSVM and upsert into `accounts`.
142
+ - Upsert into `addresses` (first_seen_slot if new, update last_seen_slot).
143
+ - If owner is SPL Token program, decode and upsert `token_accounts` / `token_mints`.
144
+ 5. Upsert a `blocks` row tying slot → blockhash/parent_slot/block_time we return via RPC.
145
+
146
+ - Account read ingestion:
147
+ - On `getAccountInfo`/`getMultipleAccounts`, upsert snapshot in `accounts` and update `addresses.last_seen_slot`.
148
+
149
+ ## RPC Backed by Store
150
+
151
+ - `getTransaction` / `getParsedTransaction`:
152
+ - Memory → SQLite by signature; return structured response (with `version`, `loadedAddresses`).
153
+ - `getSignatureStatuses`:
154
+ - Memory → SQLite (when `searchTransactionHistory: true`) for slot/err.
155
+ - `getSignaturesForAddress`:
156
+ - Query `address_signatures` + `transactions` with pagination (before/until/limit) and return explorer-style entries.
157
+ - `getProgramAccounts`:
158
+ - Query `accounts` filtered by `owner_program` and optional data filters.
159
+ - `getTokenAccountsByOwner` / `getTokenAccountsByDelegate`:
160
+ - Query `token_accounts` with appropriate filters.
161
+ - `getTokenSupply` / `getTokenLargestAccounts`:
162
+ - Query `token_mints` and `token_accounts` (by `mint`) with ordering.
163
+
164
+ ## Hot Cache Strategy
165
+
166
+ - Keep last N transactions and M account snapshots in-memory (LRU); always write-through to SQLite.
167
+ - Memory hits satisfy most recent reads; history and scans go to SQLite.
168
+
169
+ ## Retention & Pruning
170
+
171
+ - Default: keep all rows (dev/local usage).
172
+ - Optional: environment-controlled retention by time/slot; prune oldest rows in `transactions` and cascade to `tx_accounts` / `address_signatures`.
173
+
174
+ ## Implementation Phases
175
+
176
+ 1. Drizzle bootstrap
177
+ - Add DB connector (Bun + Drizzle), migrations directory, and PRAGMA setup.
178
+ 2. Schema
179
+ - Implement tables and indexes listed above; generate migrations.
180
+ 3. Store module
181
+ - `TxStore` interface with insert/query helpers; prepared statements; single-writer queue.
182
+ 4. Wire into server
183
+ - Inject store into `RpcMethodContext`; update `recordTransaction` to also persist bundles.
184
+ 5. Replace stubs
185
+ - Implement `getSignaturesForAddress`, `getProgramAccounts`, token endpoints using store.
186
+ 6. Opportunistic account refresh
187
+ - Upsert snapshots on account reads; optional background refresh for hot addresses.
188
+ 7. Tests
189
+ - `bun:test` for ingestion, pagination, filters, and legacy RPC shapes.
190
+ 8. Backfill & durability
191
+ - On boot, import any txs from in-memory records; consider opt-in on-disk WAL retention policy.
192
+ 9. Perf tune
193
+ - Review indexes, batch sizes, and PRAGMAs; add metrics.
194
+
195
+ ## LiteSVM Gaps This Store Covers
196
+
197
+ - Persistent transaction history across restarts.
198
+ - Address → signature lookups (explorer/UX critical).
199
+ - Program account scans by `owner_program`.
200
+ - SPL Token queries by owner, delegate, and mint.
201
+ - Coherent block/time metadata.
202
+
203
+ ## Open Questions
204
+
205
+ - Should we store raw account data (`data_base64`) by default? Proposal: off by default, enable via env for debugging.
206
+ - PDA detection: best-effort tagging (cannot always recover seeds deterministically).
207
+ - Future: add richer program parsers (e.g., SPL Token 2022, other common programs) if needed.
208
+
209
+ ## Next Steps (for implementation later)
210
+
211
+ - Create `storage/tx-store.ts` with Drizzle setup and empty method stubs.
212
+ - Add `context.store` to `RpcMethodContext` and route `recordTransaction` into the store.
213
+ - Land schema/migrations; no behavior change yet.
214
+
@@ -0,0 +1,202 @@
1
+ # SolForge GUI & Endpoint Plan
2
+
3
+ ## Guiding Principles
4
+ - Ship a single Bun executable that boots both RPC and GUI servers; shared runtime, separate ports (RPC defaults to 8899, GUI to 42069).
5
+ - Keep RPC wide open (same surface as CLI); the GUI talks exclusively to JSON-RPC endpoints.
6
+ - Prefer clarity over cleverness: modular files (<200 LOC) and simple data plumbing per SolForge guidelines.
7
+ - Tailwind-first dark UI: clean, minimal styling with excellent readability.
8
+ - Defer WebSockets; begin with fetch/poll flows and iterate later.
9
+
10
+ ## Deployment Model
11
+ - The executable starts the RPC server on the configured port (default 8899) and, in parallel, starts the GUI server on `guiPort` (default 42069, configurable via setup and `sf.config.json`).
12
+ - Initial setup wizard must surface GUI port alongside RPC/WS ports so users can change it up front.
13
+ - GUI assets are bundled into the executable via Bun HTML import; no external build steps at runtime.
14
+ - Cross-origin is local-only, but to simplify fetches expose a small `/api/*` facade on the GUI server that internally forwards JSON-RPC calls to the RPC port (still RPC-backed, keeps browser code clean).
15
+
16
+ ## Data Strategy (RPC-Only)
17
+ - **Initial Page Load**: GUI fetches programs and tokens immediately after mount; repeat on manual refreshes or via light polling.
18
+ - **Programs**: call `getProgramAccounts`/`getParsedProgramAccounts` with executable filtering to list deployed programs; provide an "Add" call-to-action that links into CLI/docs for cloning.
19
+ - **Tokens/Mints**:
20
+ - Enumerate known mints with `solforgeListMints` (always available; no admin gating in this phase).
21
+ - Fetch mint metadata via `getParsedAccountInfo` + SPL decoding for supply/decimals/authority.
22
+ - Fetch token accounts per mint/owner with `getTokenAccountsByOwner` or parsed variant when needed.
23
+ - **RPC Stats**: gather slot, block height, transaction count, latest blockhash, faucet lamports via core RPC calls.
24
+ - **Airdrop & Mint**: use `requestAirdrop` for SOL, `solforgeMintTo` for SPL tokens; confirmation via `getSignatureStatuses`. Mint UI remains enabled even if `SOLFORGE_ADMIN` is unset (we will revisit restrictions later).
25
+
26
+ ## Backend Tasks
27
+ 1. **Server Wiring**
28
+ - Extend startup (e.g., `startRpcServers`) to spin up the existing RPC server plus a new GUI `Bun.serve` instance listening on `guiPort` (default 42069).
29
+ - Ensure routes include `/` (HTML import), static assets, and `/api/*` JSON forwarders that call the RPC server internally (using the same process).
30
+ 2. **Configuration**
31
+ - Update config schema, setup wizard, and CLI parsing to persist/read `guiPort` (default 42069) alongside RPC/WS settings.
32
+ - Document port relationships and how to access both servers.
33
+ 3. **Executable Embedding**
34
+ - Follow `docs/bun-single-file-executable.md`: compile the GUI via HTML import, run Tailwind build prior to `bun build --compile`, ensure assets are in Bun's module graph.
35
+
36
+ ## Frontend Tasks
37
+ 1. **Tailwind Setup**
38
+ - Add Tailwind configuration (dark mode via `class`) and source entry (e.g., `src/gui/src/index.css` with base/utilities/components).
39
+ - Build CSS to `src/gui/public/tailwind.css`; import from `index.html`.
40
+ 2. **App Shell**
41
+ - Layout with dark background, comfortable spacing, responsive columns.
42
+ - Place Airdrop/Mint form at top; below it show RPC detail cards; follow with Programs and Tokens sections, each with "Add" actions.
43
+ 3. **Airdrop/Mint Form**
44
+ - Provide select listing `SOL` plus `solforgeListMints` results; capture amount input.
45
+ - Trigger RPC calls (through `/api/*` or direct JSON-RPC) and display signatures + confirmation status.
46
+ 4. **Data Displays**
47
+ - **RPC Details**: slot, block height, tx count, latest blockhash, faucet balance; auto-refresh every ~5s.
48
+ - **Programs**: cards/table showing program id, owner, executable flag, data length; include refresh control.
49
+ - **Tokens**: similar presentation with supply, decimals, mint authority, quick view of holder count.
50
+ 5. **Hooks & API**
51
+ - Implement `src/gui/src/api.ts` with typed helpers for all RPC calls.
52
+ - Add reusable polling hook to refresh data while keeping components thin (<100 LOC).
53
+
54
+ ## Build & Packaging
55
+ - Tailwind build step (e.g., `bunx tailwindcss -i src/gui/src/index.css -o src/gui/public/tailwind.css --minify`) runs before compiling the executable.
56
+ - Compile the CLI+servers into a single binary: `bun build --compile src/cli/main.ts --outfile dist/solforge` (plus `--target` variants as needed).
57
+ - Document the build pipeline and configuration flags in README.
58
+
59
+ ## Testing & Validation
60
+ - Unit tests for server proxy functions (if `/api/*` implemented).
61
+ - bun/react tests for Airdrop/Mint form logic and API wrappers (mock RPC responses).
62
+ - Manual pass: start binary, verify RPC on configured port, GUI on configured GUI port (default 42069), confirm initial data loads, perform SOL airdrop and SPL mint, observe Tailwind dark theme.
63
+
64
+ ## Open Questions / Follow-Ups
65
+ - Confirm whether hot reload/dev mode is desired for GUI during development (might require separate Bun serve workflow).
66
+ - Define behaviour of "Add program/token" buttons (link to CLI instructions vs. future modals).
67
+ - Revisit WebSocket streaming for real-time updates once base experience lands.
68
+
69
+ ## Phased Milestones
70
+ - MVP (Foundations)
71
+ - Binary boots RPC (8899) and GUI (42069).
72
+ - Static GUI served with Tailwind dark theme.
73
+ - Airdrop SOL and Mint SPL via JSON-RPC proxy; show signature + status.
74
+ - Programs and Tokens lists load via RPC calls; manual refresh works.
75
+ - Config supports `guiPort`; README section for access instructions.
76
+ - Beta (Quality & DX)
77
+ - Polling hooks with backoff and pause-on-visibility-hidden.
78
+ - Error toasts, loading states, empty states across sections.
79
+ - Minimal e2e smoke via `bun:test` + mocked RPC.
80
+ - Basic stats card auto-refresh; faucet balance warning threshold.
81
+ - v1.0 (Polish & Extensibility)
82
+ - Persist lightweight UI prefs (e.g., last-selected mint) in `localStorage`.
83
+ - Optional WS streaming behind flag (no regressions if disabled).
84
+ - Pluggable card registry for future views (accounts, logs, etc.).
85
+
86
+ ## `/api` Facade Spec
87
+ - POST `/api/jsonrpc`
88
+ - Body: JSON-RPC 2.0 request object (single), forwarded to local RPC port.
89
+ - Response: raw JSON-RPC 2.0 response from RPC server.
90
+ - Rationale: keep browser code small; batching can arrive later.
91
+ - GET `/api/stats`
92
+ - Aggregates: `getSlot`, `getBlockHeight`, `getLatestBlockhash`, `getTransactionCount` and faucet balance if available.
93
+ - Response: `{ slot, blockHeight, transactionCount, latestBlockhash, faucetLamports }`.
94
+ - Implementation: executes a few internal JSON-RPC calls and composes result.
95
+
96
+ ## Frontend Layout (kebab-case)
97
+ ```
98
+ src/gui/
99
+ ├── index.html # Bun HTML import target
100
+ ├── public/
101
+ │ └── tailwind.css # built CSS (minified)
102
+ └── src/
103
+ ├── index.tsx # app bootstrap
104
+ ├── api.ts # typed RPC helpers via /api/jsonrpc
105
+ ├── hooks/
106
+ │ ├── use-polling.ts # interval/backoff + visibility handling
107
+ │ └── use-rpc.ts # generic JSON-RPC caller
108
+ ├── components/
109
+ │ ├── app-shell.tsx
110
+ │ ├── airdrop-mint-form.tsx
111
+ │ ├── rpc-stats-card.tsx
112
+ │ ├── programs-list.tsx
113
+ │ └── tokens-list.tsx
114
+ └── types.ts # minimal UI-facing types (no any)
115
+ ```
116
+
117
+ ## Config Additions
118
+ - Extend `sf.config.json` with:
119
+ - `guiPort: number` (default 42069)
120
+ - Type shape (TS):
121
+ ```ts
122
+ export interface SolforgeConfig {
123
+ rpcPort: number;
124
+ wsPort?: number;
125
+ guiPort: number; // new
126
+ // ...existing fields
127
+ }
128
+ ```
129
+ - Setup wizard: prompt for GUI port alongside RPC/WS.
130
+
131
+ ## Server Wiring Sketch (Bun)
132
+ ```ts
133
+ // pseudo-code outline
134
+ const gui = Bun.serve({
135
+ port: config.guiPort ?? 42069,
136
+ async fetch(req) {
137
+ const url = new URL(req.url);
138
+ if (req.method === "POST" && url.pathname === "/api/jsonrpc") {
139
+ // forward body to local RPC server without network hop
140
+ const body = await req.text();
141
+ const resp = await rpcServer.handleJson(body); // call into in-process handler
142
+ return new Response(resp, { headers: { "content-type": "application/json" } });
143
+ }
144
+ if (req.method === "GET" && url.pathname === "/api/stats") {
145
+ const [slot, blockHeight, txCount, bh, faucet] = await Promise.all([
146
+ rpc.call("getSlot"),
147
+ rpc.call("getBlockHeight"),
148
+ rpc.call("getTransactionCount"),
149
+ rpc.call("getLatestBlockhash"),
150
+ rpc.call("getBalance", [faucetPubkey]).catch(() => 0n),
151
+ ]);
152
+ return Response.json({ slot, blockHeight, transactionCount: txCount, latestBlockhash: bh.blockhash, faucetLamports: faucet });
153
+ }
154
+ // static index + assets
155
+ if (url.pathname === "/") return new Response(Bun.file("src/gui/index.html"));
156
+ if (url.pathname === "/tailwind.css") return new Response(Bun.file("src/gui/public/tailwind.css"));
157
+ return new Response("Not found", { status: 404 });
158
+ },
159
+ });
160
+ ```
161
+
162
+ ## API Helpers (browser)
163
+ - `api.jsonrpc<T>(method: string, params: unknown[]): Promise<T>`
164
+ - `api.getStats(): Promise<{ slot: number; blockHeight: number; transactionCount: number; latestBlockhash: string; faucetLamports: bigint }>`
165
+ - Prefer `bigint` for lamports; stringify via custom JSON replacer only at the display boundary.
166
+
167
+ ## Tailwind Build
168
+ - Build once before compile: `bunx tailwindcss -i src/gui/src/index.css -o src/gui/public/tailwind.css --minify`.
169
+ - Ensure the CSS output path is included in the module graph or accessed via `Bun.file()`.
170
+
171
+ ## Testing Plan (bun:test)
172
+ - API facade
173
+ - Forwards JSON-RPC body unchanged; returns response as-is.
174
+ - `/api/stats` composes values and handles RPC failure gracefully.
175
+ - Hooks
176
+ - `use-polling` respects visibility, clears timers on unmount, backs-off on errors.
177
+ - Components
178
+ - Airdrop/Mint: disables submit during in-flight; shows signature; polls `getSignatureStatuses` until "confirmed".
179
+ - Lists: render empty states and error banners.
180
+
181
+ ## Acceptance Criteria (MVP)
182
+ - Binary launches; visiting `http://localhost:42069/` shows GUI without extra build steps.
183
+ - Clicking "Airdrop SOL" on a valid address yields a signature and a confirmed status.
184
+ - Selecting a mint and submitting "Mint Tokens" yields a signature and confirmation.
185
+ - Programs and Tokens sections render data or a clear empty state.
186
+ - Stats card refreshes automatically and never blocks the UI.
187
+
188
+ ## Risks & Constraints
189
+ - Embedding assets: keep the GUI asset set small to avoid bloating the single-file binary.
190
+ - BigInt in JSON: do not leak `bigint` directly through JSON; cast to string only in UI.
191
+ - Cross-origin: prefer same-origin via GUI `/api/*` to avoid CORS complexity.
192
+
193
+ ## Work Checklist
194
+ - [ ] Add `guiPort` to config + setup wizard
195
+ - [ ] Implement GUI `Bun.serve` with `/api/jsonrpc`, `/api/stats`, and static routes
196
+ - [ ] Add Tailwind pipeline and base dark theme
197
+ - [ ] Scaffold frontend layout and components
198
+ - [ ] Implement `api.ts` with JSON-RPC helper
199
+ - [ ] Wire Airdrop/Mint form to RPC
200
+ - [ ] Implement polling hooks and stats card
201
+ - [ ] Write unit tests for facade, hooks, and form logic
202
+ - [ ] Update README with GUI usage and ports