solforge 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agi/agi.sqlite +0 -0
- package/.claude/settings.local.json +9 -0
- package/.github/workflows/release-binaries.yml +133 -0
- package/.tmp/.787ebcdbf7b8fde8-00000000.hm +0 -0
- package/.tmp/.bffe6efebdf8aedc-00000000.hm +0 -0
- package/AGENTS.md +271 -0
- package/CLAUDE.md +106 -0
- package/PROJECT_STRUCTURE.md +124 -0
- package/README.md +367 -393
- package/SOLANA_KIT_GUIDE.md +251 -0
- package/SOLFORGE.md +119 -0
- package/biome.json +34 -0
- package/bun.lock +743 -0
- package/docs/bun-single-file-executable.md +585 -0
- package/docs/cli-plan.md +154 -0
- package/docs/data-indexing-plan.md +214 -0
- package/docs/gui-roadmap.md +202 -0
- package/drizzle/0000_friendly_millenium_guard.sql +53 -0
- package/drizzle/0001_stale_sentinels.sql +2 -0
- package/drizzle/meta/0000_snapshot.json +329 -0
- package/drizzle/meta/0001_snapshot.json +345 -0
- package/drizzle/meta/_journal.json +20 -0
- package/drizzle.config.ts +12 -0
- package/index.ts +21 -0
- package/mint.sh +47 -0
- package/package.json +45 -69
- package/postcss.config.js +6 -0
- package/rpc-server.ts.backup +519 -0
- package/server/index.ts +5 -0
- package/server/lib/base58.ts +33 -0
- package/server/lib/faucet.ts +110 -0
- package/server/lib/spl-token.ts +57 -0
- package/server/methods/TEMPLATE.md +117 -0
- package/server/methods/account/get-account-info.ts +90 -0
- package/server/methods/account/get-balance.ts +27 -0
- package/server/methods/account/get-multiple-accounts.ts +83 -0
- package/server/methods/account/get-parsed-account-info.ts +21 -0
- package/server/methods/account/index.ts +12 -0
- package/server/methods/account/parsers/index.ts +52 -0
- package/server/methods/account/parsers/loader-upgradeable.ts +66 -0
- package/server/methods/account/parsers/spl-token.ts +237 -0
- package/server/methods/account/parsers/system.ts +4 -0
- package/server/methods/account/request-airdrop.ts +219 -0
- package/server/methods/admin/adopt-mint-authority.ts +94 -0
- package/server/methods/admin/clone-program-accounts.ts +55 -0
- package/server/methods/admin/clone-program.ts +152 -0
- package/server/methods/admin/clone-token-accounts.ts +117 -0
- package/server/methods/admin/clone-token-mint.ts +82 -0
- package/server/methods/admin/create-mint.ts +114 -0
- package/server/methods/admin/create-token-account.ts +137 -0
- package/server/methods/admin/helpers.ts +70 -0
- package/server/methods/admin/index.ts +10 -0
- package/server/methods/admin/list-mints.ts +21 -0
- package/server/methods/admin/load-program.ts +52 -0
- package/server/methods/admin/mint-to.ts +278 -0
- package/server/methods/block/get-block-height.ts +5 -0
- package/server/methods/block/get-block.ts +35 -0
- package/server/methods/block/get-blocks-with-limit.ts +23 -0
- package/server/methods/block/get-latest-blockhash.ts +12 -0
- package/server/methods/block/get-slot.ts +5 -0
- package/server/methods/block/index.ts +6 -0
- package/server/methods/block/is-blockhash-valid.ts +23 -0
- package/server/methods/epoch/get-cluster-nodes.ts +17 -0
- package/server/methods/epoch/get-epoch-info.ts +16 -0
- package/server/methods/epoch/get-epoch-schedule.ts +15 -0
- package/server/methods/epoch/get-highest-snapshot-slot.ts +9 -0
- package/server/methods/epoch/get-leader-schedule.ts +8 -0
- package/server/methods/epoch/get-max-retransmit-slot.ts +9 -0
- package/server/methods/epoch/get-max-shred-insert-slot.ts +9 -0
- package/server/methods/epoch/get-slot-leader.ts +6 -0
- package/server/methods/epoch/get-slot-leaders.ts +9 -0
- package/server/methods/epoch/get-stake-activation.ts +9 -0
- package/server/methods/epoch/get-stake-minimum-delegation.ts +9 -0
- package/server/methods/epoch/get-vote-accounts.ts +19 -0
- package/server/methods/epoch/index.ts +13 -0
- package/server/methods/epoch/minimum-ledger-slot.ts +5 -0
- package/server/methods/fee/get-fee-calculator-for-blockhash.ts +12 -0
- package/server/methods/fee/get-fee-for-message.ts +8 -0
- package/server/methods/fee/get-fee-rate-governor.ts +16 -0
- package/server/methods/fee/get-fees.ts +14 -0
- package/server/methods/fee/get-recent-prioritization-fees.ts +22 -0
- package/server/methods/fee/index.ts +5 -0
- package/server/methods/get-address-lookup-table.ts +31 -0
- package/server/methods/index.ts +265 -0
- package/server/methods/performance/get-recent-performance-samples.ts +25 -0
- package/server/methods/performance/get-transaction-count.ts +5 -0
- package/server/methods/performance/index.ts +2 -0
- package/server/methods/program/get-block-commitment.ts +9 -0
- package/server/methods/program/get-block-production.ts +14 -0
- package/server/methods/program/get-block-time.ts +21 -0
- package/server/methods/program/get-blocks.ts +11 -0
- package/server/methods/program/get-first-available-block.ts +9 -0
- package/server/methods/program/get-genesis-hash.ts +6 -0
- package/server/methods/program/get-identity.ts +6 -0
- package/server/methods/program/get-inflation-governor.ts +15 -0
- package/server/methods/program/get-inflation-rate.ts +10 -0
- package/server/methods/program/get-inflation-reward.ts +12 -0
- package/server/methods/program/get-largest-accounts.ts +8 -0
- package/server/methods/program/get-parsed-program-accounts.ts +12 -0
- package/server/methods/program/get-parsed-token-accounts-by-delegate.ts +12 -0
- package/server/methods/program/get-parsed-token-accounts-by-owner.ts +12 -0
- package/server/methods/program/get-program-accounts.ts +221 -0
- package/server/methods/program/get-supply.ts +13 -0
- package/server/methods/program/get-token-account-balance.ts +64 -0
- package/server/methods/program/get-token-accounts-by-delegate.ts +81 -0
- package/server/methods/program/get-token-accounts-by-owner.ts +390 -0
- package/server/methods/program/get-token-largest-accounts.ts +80 -0
- package/server/methods/program/get-token-supply.ts +38 -0
- package/server/methods/program/index.ts +21 -0
- package/server/methods/solforge/index.ts +155 -0
- package/server/methods/system/get-health.ts +5 -0
- package/server/methods/system/get-minimum-balance-for-rent-exemption.ts +13 -0
- package/server/methods/system/get-version.ts +9 -0
- package/server/methods/system/index.ts +3 -0
- package/server/methods/transaction/get-confirmed-transaction.ts +11 -0
- package/server/methods/transaction/get-parsed-transaction.ts +21 -0
- package/server/methods/transaction/get-signature-statuses.ts +72 -0
- package/server/methods/transaction/get-signatures-for-address.ts +45 -0
- package/server/methods/transaction/get-transaction.ts +428 -0
- package/server/methods/transaction/index.ts +7 -0
- package/server/methods/transaction/send-transaction.ts +232 -0
- package/server/methods/transaction/simulate-transaction.ts +56 -0
- package/server/rpc-server.ts +474 -0
- package/server/types.ts +74 -0
- package/server/ws-server.ts +171 -0
- package/sf.config.json +38 -0
- package/src/cli/bootstrap.ts +67 -0
- package/src/cli/commands/airdrop.ts +37 -0
- package/src/cli/commands/config.ts +39 -0
- package/src/cli/commands/mint.ts +187 -0
- package/src/cli/commands/program-clone.ts +124 -0
- package/src/cli/commands/program-load.ts +64 -0
- package/src/cli/commands/rpc-start.ts +46 -0
- package/src/cli/commands/token-adopt-authority.ts +37 -0
- package/src/cli/commands/token-clone.ts +113 -0
- package/src/cli/commands/token-create.ts +81 -0
- package/src/cli/main.ts +130 -0
- package/src/cli/run-solforge.ts +98 -0
- package/src/cli/setup-utils.ts +54 -0
- package/src/cli/setup-wizard.ts +256 -0
- package/src/cli/utils/args.ts +15 -0
- package/src/config/index.ts +130 -0
- package/src/db/index.ts +83 -0
- package/src/db/schema/accounts.ts +23 -0
- package/src/db/schema/address-signatures.ts +31 -0
- package/src/db/schema/index.ts +5 -0
- package/src/db/schema/meta-kv.ts +9 -0
- package/src/db/schema/transactions.ts +29 -0
- package/src/db/schema/tx-accounts.ts +33 -0
- package/src/db/tx-store.ts +229 -0
- package/src/gui/public/app.css +1 -0
- package/src/gui/public/index.html +19 -0
- package/src/gui/server.ts +297 -0
- package/src/gui/src/api.ts +127 -0
- package/src/gui/src/app.tsx +390 -0
- package/src/gui/src/components/airdrop-mint-form.tsx +216 -0
- package/src/gui/src/components/clone-program-modal.tsx +183 -0
- package/src/gui/src/components/clone-token-modal.tsx +211 -0
- package/src/gui/src/components/modal.tsx +127 -0
- package/src/gui/src/components/programs-panel.tsx +112 -0
- package/src/gui/src/components/status-panel.tsx +122 -0
- package/src/gui/src/components/tokens-panel.tsx +116 -0
- package/src/gui/src/hooks/use-interval.ts +17 -0
- package/src/gui/src/index.css +529 -0
- package/src/gui/src/main.tsx +17 -0
- package/src/migrations-bundled.ts +17 -0
- package/src/rpc/start.ts +44 -0
- package/tailwind.config.js +27 -0
- package/test-client.ts +120 -0
- package/tmp/inspect-html.ts +4 -0
- package/tmp/response-test.ts +5 -0
- package/tmp/test-html.ts +5 -0
- package/tmp/test-server.ts +13 -0
- package/tsconfig.json +24 -23
- package/LICENSE +0 -21
- package/scripts/postinstall.cjs +0 -103
- package/src/api-server-entry.ts +0 -109
- package/src/commands/add-program.ts +0 -337
- package/src/commands/init.ts +0 -122
- package/src/commands/list.ts +0 -136
- package/src/commands/mint.ts +0 -336
- package/src/commands/start.ts +0 -878
- package/src/commands/status.ts +0 -99
- package/src/commands/stop.ts +0 -406
- package/src/config/manager.ts +0 -157
- package/src/index.ts +0 -188
- package/src/services/api-server.ts +0 -532
- package/src/services/port-manager.ts +0 -177
- package/src/services/process-registry.ts +0 -154
- package/src/services/program-cloner.ts +0 -317
- package/src/services/token-cloner.ts +0 -809
- package/src/services/validator.ts +0 -295
- package/src/types/config.ts +0 -110
- package/src/utils/shell.ts +0 -110
package/docs/cli-plan.md
ADDED
|
@@ -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
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
CREATE TABLE `accounts` (
|
|
2
|
+
`address` text PRIMARY KEY NOT NULL,
|
|
3
|
+
`lamports` integer NOT NULL,
|
|
4
|
+
`owner_program` text NOT NULL,
|
|
5
|
+
`executable` integer NOT NULL,
|
|
6
|
+
`rent_epoch` integer NOT NULL,
|
|
7
|
+
`data_len` integer NOT NULL,
|
|
8
|
+
`data_base64` text,
|
|
9
|
+
`last_slot` integer NOT NULL
|
|
10
|
+
);
|
|
11
|
+
--> statement-breakpoint
|
|
12
|
+
CREATE INDEX `idx_accounts_owner` ON `accounts` (`owner_program`);--> statement-breakpoint
|
|
13
|
+
CREATE INDEX `idx_accounts_last_slot` ON `accounts` (`last_slot`);--> statement-breakpoint
|
|
14
|
+
CREATE TABLE `address_signatures` (
|
|
15
|
+
`address` text NOT NULL,
|
|
16
|
+
`signature` text NOT NULL,
|
|
17
|
+
`slot` integer NOT NULL,
|
|
18
|
+
`err` integer NOT NULL,
|
|
19
|
+
`block_time` integer,
|
|
20
|
+
PRIMARY KEY(`address`, `signature`)
|
|
21
|
+
);
|
|
22
|
+
--> statement-breakpoint
|
|
23
|
+
CREATE INDEX `idx_address_signatures_addr_slot` ON `address_signatures` (`address`,`slot`);--> statement-breakpoint
|
|
24
|
+
CREATE TABLE `transactions` (
|
|
25
|
+
`signature` text PRIMARY KEY NOT NULL,
|
|
26
|
+
`slot` integer NOT NULL,
|
|
27
|
+
`block_time` integer,
|
|
28
|
+
`version` text NOT NULL,
|
|
29
|
+
`err_json` text,
|
|
30
|
+
`fee` integer NOT NULL,
|
|
31
|
+
`raw_base64` text NOT NULL,
|
|
32
|
+
`pre_balances_json` text NOT NULL,
|
|
33
|
+
`post_balances_json` text NOT NULL,
|
|
34
|
+
`logs_json` text NOT NULL
|
|
35
|
+
);
|
|
36
|
+
--> statement-breakpoint
|
|
37
|
+
CREATE INDEX `idx_transactions_slot` ON `transactions` (`slot`);--> statement-breakpoint
|
|
38
|
+
CREATE TABLE `tx_accounts` (
|
|
39
|
+
`signature` text NOT NULL,
|
|
40
|
+
`account_index` integer NOT NULL,
|
|
41
|
+
`address` text NOT NULL,
|
|
42
|
+
`signer` integer NOT NULL,
|
|
43
|
+
`writable` integer NOT NULL,
|
|
44
|
+
`program_id_index` integer,
|
|
45
|
+
PRIMARY KEY(`signature`, `account_index`)
|
|
46
|
+
);
|
|
47
|
+
--> statement-breakpoint
|
|
48
|
+
CREATE INDEX `idx_tx_accounts_address` ON `tx_accounts` (`address`);--> statement-breakpoint
|
|
49
|
+
CREATE INDEX `idx_tx_accounts_address_signature` ON `tx_accounts` (`address`,`signature`);--> statement-breakpoint
|
|
50
|
+
CREATE TABLE `meta_kv` (
|
|
51
|
+
`key` text PRIMARY KEY NOT NULL,
|
|
52
|
+
`value` text NOT NULL
|
|
53
|
+
);
|