solforge 0.1.7 → 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.
Files changed (195) hide show
  1. package/.agi/agi.sqlite +0 -0
  2. package/.claude/settings.local.json +9 -0
  3. package/.github/workflows/release-binaries.yml +133 -0
  4. package/.tmp/.787ebcdbf7b8fde8-00000000.hm +0 -0
  5. package/.tmp/.bffe6efebdf8aedc-00000000.hm +0 -0
  6. package/AGENTS.md +271 -0
  7. package/CLAUDE.md +106 -0
  8. package/PROJECT_STRUCTURE.md +124 -0
  9. package/README.md +367 -393
  10. package/SOLANA_KIT_GUIDE.md +251 -0
  11. package/SOLFORGE.md +119 -0
  12. package/biome.json +34 -0
  13. package/bun.lock +743 -0
  14. package/docs/bun-single-file-executable.md +585 -0
  15. package/docs/cli-plan.md +154 -0
  16. package/docs/data-indexing-plan.md +214 -0
  17. package/docs/gui-roadmap.md +202 -0
  18. package/drizzle/0000_friendly_millenium_guard.sql +53 -0
  19. package/drizzle/0001_stale_sentinels.sql +2 -0
  20. package/drizzle/meta/0000_snapshot.json +329 -0
  21. package/drizzle/meta/0001_snapshot.json +345 -0
  22. package/drizzle/meta/_journal.json +20 -0
  23. package/drizzle.config.ts +12 -0
  24. package/index.ts +21 -0
  25. package/mint.sh +47 -0
  26. package/package.json +45 -69
  27. package/postcss.config.js +6 -0
  28. package/rpc-server.ts.backup +519 -0
  29. package/server/index.ts +5 -0
  30. package/server/lib/base58.ts +33 -0
  31. package/server/lib/faucet.ts +110 -0
  32. package/server/lib/spl-token.ts +57 -0
  33. package/server/methods/TEMPLATE.md +117 -0
  34. package/server/methods/account/get-account-info.ts +90 -0
  35. package/server/methods/account/get-balance.ts +27 -0
  36. package/server/methods/account/get-multiple-accounts.ts +83 -0
  37. package/server/methods/account/get-parsed-account-info.ts +21 -0
  38. package/server/methods/account/index.ts +12 -0
  39. package/server/methods/account/parsers/index.ts +52 -0
  40. package/server/methods/account/parsers/loader-upgradeable.ts +66 -0
  41. package/server/methods/account/parsers/spl-token.ts +237 -0
  42. package/server/methods/account/parsers/system.ts +4 -0
  43. package/server/methods/account/request-airdrop.ts +219 -0
  44. package/server/methods/admin/adopt-mint-authority.ts +94 -0
  45. package/server/methods/admin/clone-program-accounts.ts +55 -0
  46. package/server/methods/admin/clone-program.ts +152 -0
  47. package/server/methods/admin/clone-token-accounts.ts +117 -0
  48. package/server/methods/admin/clone-token-mint.ts +82 -0
  49. package/server/methods/admin/create-mint.ts +114 -0
  50. package/server/methods/admin/create-token-account.ts +137 -0
  51. package/server/methods/admin/helpers.ts +70 -0
  52. package/server/methods/admin/index.ts +10 -0
  53. package/server/methods/admin/list-mints.ts +21 -0
  54. package/server/methods/admin/load-program.ts +52 -0
  55. package/server/methods/admin/mint-to.ts +278 -0
  56. package/server/methods/block/get-block-height.ts +5 -0
  57. package/server/methods/block/get-block.ts +35 -0
  58. package/server/methods/block/get-blocks-with-limit.ts +23 -0
  59. package/server/methods/block/get-latest-blockhash.ts +12 -0
  60. package/server/methods/block/get-slot.ts +5 -0
  61. package/server/methods/block/index.ts +6 -0
  62. package/server/methods/block/is-blockhash-valid.ts +23 -0
  63. package/server/methods/epoch/get-cluster-nodes.ts +17 -0
  64. package/server/methods/epoch/get-epoch-info.ts +16 -0
  65. package/server/methods/epoch/get-epoch-schedule.ts +15 -0
  66. package/server/methods/epoch/get-highest-snapshot-slot.ts +9 -0
  67. package/server/methods/epoch/get-leader-schedule.ts +8 -0
  68. package/server/methods/epoch/get-max-retransmit-slot.ts +9 -0
  69. package/server/methods/epoch/get-max-shred-insert-slot.ts +9 -0
  70. package/server/methods/epoch/get-slot-leader.ts +6 -0
  71. package/server/methods/epoch/get-slot-leaders.ts +9 -0
  72. package/server/methods/epoch/get-stake-activation.ts +9 -0
  73. package/server/methods/epoch/get-stake-minimum-delegation.ts +9 -0
  74. package/server/methods/epoch/get-vote-accounts.ts +19 -0
  75. package/server/methods/epoch/index.ts +13 -0
  76. package/server/methods/epoch/minimum-ledger-slot.ts +5 -0
  77. package/server/methods/fee/get-fee-calculator-for-blockhash.ts +12 -0
  78. package/server/methods/fee/get-fee-for-message.ts +8 -0
  79. package/server/methods/fee/get-fee-rate-governor.ts +16 -0
  80. package/server/methods/fee/get-fees.ts +14 -0
  81. package/server/methods/fee/get-recent-prioritization-fees.ts +22 -0
  82. package/server/methods/fee/index.ts +5 -0
  83. package/server/methods/get-address-lookup-table.ts +31 -0
  84. package/server/methods/index.ts +265 -0
  85. package/server/methods/performance/get-recent-performance-samples.ts +25 -0
  86. package/server/methods/performance/get-transaction-count.ts +5 -0
  87. package/server/methods/performance/index.ts +2 -0
  88. package/server/methods/program/get-block-commitment.ts +9 -0
  89. package/server/methods/program/get-block-production.ts +14 -0
  90. package/server/methods/program/get-block-time.ts +21 -0
  91. package/server/methods/program/get-blocks.ts +11 -0
  92. package/server/methods/program/get-first-available-block.ts +9 -0
  93. package/server/methods/program/get-genesis-hash.ts +6 -0
  94. package/server/methods/program/get-identity.ts +6 -0
  95. package/server/methods/program/get-inflation-governor.ts +15 -0
  96. package/server/methods/program/get-inflation-rate.ts +10 -0
  97. package/server/methods/program/get-inflation-reward.ts +12 -0
  98. package/server/methods/program/get-largest-accounts.ts +8 -0
  99. package/server/methods/program/get-parsed-program-accounts.ts +12 -0
  100. package/server/methods/program/get-parsed-token-accounts-by-delegate.ts +12 -0
  101. package/server/methods/program/get-parsed-token-accounts-by-owner.ts +12 -0
  102. package/server/methods/program/get-program-accounts.ts +221 -0
  103. package/server/methods/program/get-supply.ts +13 -0
  104. package/server/methods/program/get-token-account-balance.ts +64 -0
  105. package/server/methods/program/get-token-accounts-by-delegate.ts +81 -0
  106. package/server/methods/program/get-token-accounts-by-owner.ts +390 -0
  107. package/server/methods/program/get-token-largest-accounts.ts +80 -0
  108. package/server/methods/program/get-token-supply.ts +38 -0
  109. package/server/methods/program/index.ts +21 -0
  110. package/server/methods/solforge/index.ts +155 -0
  111. package/server/methods/system/get-health.ts +5 -0
  112. package/server/methods/system/get-minimum-balance-for-rent-exemption.ts +13 -0
  113. package/server/methods/system/get-version.ts +9 -0
  114. package/server/methods/system/index.ts +3 -0
  115. package/server/methods/transaction/get-confirmed-transaction.ts +11 -0
  116. package/server/methods/transaction/get-parsed-transaction.ts +21 -0
  117. package/server/methods/transaction/get-signature-statuses.ts +72 -0
  118. package/server/methods/transaction/get-signatures-for-address.ts +45 -0
  119. package/server/methods/transaction/get-transaction.ts +428 -0
  120. package/server/methods/transaction/index.ts +7 -0
  121. package/server/methods/transaction/send-transaction.ts +232 -0
  122. package/server/methods/transaction/simulate-transaction.ts +56 -0
  123. package/server/rpc-server.ts +474 -0
  124. package/server/types.ts +74 -0
  125. package/server/ws-server.ts +171 -0
  126. package/sf.config.json +38 -0
  127. package/src/cli/bootstrap.ts +67 -0
  128. package/src/cli/commands/airdrop.ts +37 -0
  129. package/src/cli/commands/config.ts +39 -0
  130. package/src/cli/commands/mint.ts +187 -0
  131. package/src/cli/commands/program-clone.ts +124 -0
  132. package/src/cli/commands/program-load.ts +64 -0
  133. package/src/cli/commands/rpc-start.ts +46 -0
  134. package/src/cli/commands/token-adopt-authority.ts +37 -0
  135. package/src/cli/commands/token-clone.ts +113 -0
  136. package/src/cli/commands/token-create.ts +81 -0
  137. package/src/cli/main.ts +130 -0
  138. package/src/cli/run-solforge.ts +98 -0
  139. package/src/cli/setup-utils.ts +54 -0
  140. package/src/cli/setup-wizard.ts +256 -0
  141. package/src/cli/utils/args.ts +15 -0
  142. package/src/config/index.ts +130 -0
  143. package/src/db/index.ts +83 -0
  144. package/src/db/schema/accounts.ts +23 -0
  145. package/src/db/schema/address-signatures.ts +31 -0
  146. package/src/db/schema/index.ts +5 -0
  147. package/src/db/schema/meta-kv.ts +9 -0
  148. package/src/db/schema/transactions.ts +29 -0
  149. package/src/db/schema/tx-accounts.ts +33 -0
  150. package/src/db/tx-store.ts +229 -0
  151. package/src/gui/public/app.css +1 -0
  152. package/src/gui/public/index.html +19 -0
  153. package/src/gui/server.ts +297 -0
  154. package/src/gui/src/api.ts +127 -0
  155. package/src/gui/src/app.tsx +390 -0
  156. package/src/gui/src/components/airdrop-mint-form.tsx +216 -0
  157. package/src/gui/src/components/clone-program-modal.tsx +183 -0
  158. package/src/gui/src/components/clone-token-modal.tsx +211 -0
  159. package/src/gui/src/components/modal.tsx +127 -0
  160. package/src/gui/src/components/programs-panel.tsx +112 -0
  161. package/src/gui/src/components/status-panel.tsx +122 -0
  162. package/src/gui/src/components/tokens-panel.tsx +116 -0
  163. package/src/gui/src/hooks/use-interval.ts +17 -0
  164. package/src/gui/src/index.css +529 -0
  165. package/src/gui/src/main.tsx +17 -0
  166. package/src/migrations-bundled.ts +17 -0
  167. package/src/rpc/start.ts +44 -0
  168. package/tailwind.config.js +27 -0
  169. package/test-client.ts +120 -0
  170. package/tmp/inspect-html.ts +4 -0
  171. package/tmp/response-test.ts +5 -0
  172. package/tmp/test-html.ts +5 -0
  173. package/tmp/test-server.ts +13 -0
  174. package/tsconfig.json +24 -23
  175. package/LICENSE +0 -21
  176. package/scripts/postinstall.cjs +0 -103
  177. package/src/api-server-entry.ts +0 -109
  178. package/src/commands/add-program.ts +0 -337
  179. package/src/commands/init.ts +0 -122
  180. package/src/commands/list.ts +0 -136
  181. package/src/commands/mint.ts +0 -288
  182. package/src/commands/start.ts +0 -877
  183. package/src/commands/status.ts +0 -99
  184. package/src/commands/stop.ts +0 -406
  185. package/src/config/manager.ts +0 -157
  186. package/src/index.ts +0 -188
  187. package/src/services/api-server.ts +0 -485
  188. package/src/services/port-manager.ts +0 -177
  189. package/src/services/process-registry.ts +0 -154
  190. package/src/services/program-cloner.ts +0 -317
  191. package/src/services/token-cloner.ts +0 -809
  192. package/src/services/validator.ts +0 -295
  193. package/src/types/config.ts +0 -110
  194. package/src/utils/shell.ts +0 -110
  195. package/src/utils/token-loader.ts +0 -115
@@ -0,0 +1,232 @@
1
+ import {
2
+ ACCOUNT_SIZE,
3
+ AccountLayout,
4
+ MINT_SIZE,
5
+ MintLayout,
6
+ TOKEN_2022_PROGRAM_ID,
7
+ TOKEN_PROGRAM_ID,
8
+ } from "@solana/spl-token";
9
+ import { PublicKey, VersionedTransaction } from "@solana/web3.js";
10
+ import type { RpcMethodHandler } from "../../types";
11
+
12
+ export const sendTransaction: RpcMethodHandler = (id, params, context) => {
13
+ const [encodedTx] = params;
14
+ try {
15
+ const txData = Buffer.from(encodedTx, "base64");
16
+ const tx = VersionedTransaction.deserialize(txData);
17
+
18
+ // Snapshot pre balances
19
+ const msg: any = tx.message as any;
20
+ const rawKeys: any[] = Array.isArray(msg.staticAccountKeys)
21
+ ? msg.staticAccountKeys
22
+ : Array.isArray(msg.accountKeys)
23
+ ? msg.accountKeys
24
+ : [];
25
+ const staticKeys = rawKeys
26
+ .map((k: any) => {
27
+ try {
28
+ return typeof k === "string" ? new PublicKey(k) : (k as PublicKey);
29
+ } catch {
30
+ return undefined;
31
+ }
32
+ })
33
+ .filter(Boolean) as PublicKey[];
34
+ const preBalances = staticKeys.map((pk) => {
35
+ try {
36
+ return Number(context.svm.getBalance(pk));
37
+ } catch {
38
+ return 0;
39
+ }
40
+ });
41
+
42
+ // Collect SPL token accounts from instructions for pre/post token balance snapshots
43
+ const msgAny: any = msg;
44
+ const compiled = Array.isArray(msgAny.compiledInstructions)
45
+ ? msgAny.compiledInstructions
46
+ : Array.isArray(msgAny.instructions)
47
+ ? msgAny.instructions
48
+ : [];
49
+ const tokenProgramIds = new Set([
50
+ TOKEN_PROGRAM_ID.toBase58(),
51
+ TOKEN_2022_PROGRAM_ID.toBase58(),
52
+ ]);
53
+ const tokenAccountSet = new Set<string>();
54
+ for (const ci of compiled) {
55
+ try {
56
+ const pid = staticKeys[ci.programIdIndex]?.toBase58();
57
+ if (!pid || !tokenProgramIds.has(pid)) continue;
58
+ const accIdxs: number[] = Array.isArray(ci.accountKeyIndexes)
59
+ ? ci.accountKeyIndexes
60
+ : Array.isArray(ci.accounts)
61
+ ? ci.accounts
62
+ : [];
63
+ for (const ix of accIdxs) {
64
+ const addr = staticKeys[ix]?.toBase58();
65
+ if (addr) tokenAccountSet.add(addr);
66
+ }
67
+ } catch {}
68
+ }
69
+ // Pre token balances
70
+ const preTokenBalances: any[] = [];
71
+ const ataToInfo = new Map<
72
+ string,
73
+ {
74
+ mint?: string;
75
+ owner?: string;
76
+ amount: bigint;
77
+ accountIndex: number;
78
+ decimals?: number;
79
+ }
80
+ >();
81
+ const missingPre = new Set<string>();
82
+ for (const addr of tokenAccountSet) {
83
+ try {
84
+ const pk = new PublicKey(addr);
85
+ const idx = staticKeys.findIndex((k) => k.equals(pk));
86
+ const acc = context.svm.getAccount(pk);
87
+ if (!acc || (acc.data?.length ?? 0) < ACCOUNT_SIZE) {
88
+ // Track placeholder; we'll fill mint/owner/decimals after send
89
+ ataToInfo.set(addr, { amount: 0n, accountIndex: idx >= 0 ? idx : 0 });
90
+ missingPre.add(addr);
91
+ continue;
92
+ }
93
+ const decAcc = AccountLayout.decode(Buffer.from(acc.data));
94
+ const mintPk = new PublicKey(decAcc.mint);
95
+ const mintAcc = context.svm.getAccount(mintPk);
96
+ let decimals = 0;
97
+ if (mintAcc && (mintAcc.data?.length ?? 0) >= MINT_SIZE) {
98
+ const m = MintLayout.decode(
99
+ Buffer.from(mintAcc.data).slice(0, MINT_SIZE),
100
+ );
101
+ decimals = Number(m.decimals ?? 0);
102
+ }
103
+ const ownerPk = new PublicKey(decAcc.owner);
104
+ const amt = BigInt(decAcc.amount.toString());
105
+ ataToInfo.set(addr, {
106
+ mint: mintPk.toBase58(),
107
+ owner: ownerPk.toBase58(),
108
+ amount: amt,
109
+ accountIndex: idx >= 0 ? idx : 0,
110
+ decimals,
111
+ });
112
+ const uiAmount = Number(amt) / 10 ** decimals;
113
+ preTokenBalances.push({
114
+ accountIndex: idx >= 0 ? idx : 0,
115
+ mint: mintPk.toBase58(),
116
+ owner: ownerPk.toBase58(),
117
+ uiTokenAmount: {
118
+ amount: amt.toString(),
119
+ decimals,
120
+ uiAmount,
121
+ uiAmountString: String(uiAmount),
122
+ },
123
+ });
124
+ } catch {}
125
+ }
126
+
127
+ const result = context.svm.sendTransaction(tx);
128
+
129
+ try {
130
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
131
+ const maybeErr = (result as any).err?.();
132
+ if (maybeErr) {
133
+ return context.createErrorResponse(
134
+ id,
135
+ -32003,
136
+ "Transaction failed",
137
+ maybeErr,
138
+ );
139
+ }
140
+ } catch {}
141
+
142
+ const signature = tx.signatures[0]
143
+ ? context.encodeBase58(tx.signatures[0])
144
+ : context.encodeBase58(new Uint8Array(64).fill(0));
145
+ context.notifySignature(signature);
146
+ // Snapshot post balances and capture logs for rich view
147
+ const postBalances = staticKeys.map((pk) => {
148
+ try {
149
+ return Number(context.svm.getBalance(pk));
150
+ } catch {
151
+ return 0;
152
+ }
153
+ });
154
+ // Post token balances
155
+ const postTokenBalances: any[] = [];
156
+ for (const addr of tokenAccountSet) {
157
+ try {
158
+ const pk = new PublicKey(addr);
159
+ const idx = staticKeys.findIndex((k) => k.equals(pk));
160
+ const acc = context.svm.getAccount(pk);
161
+ if (!acc || (acc.data?.length ?? 0) < ACCOUNT_SIZE) continue;
162
+ const decAcc = AccountLayout.decode(Buffer.from(acc.data));
163
+ const mintPk = new PublicKey(decAcc.mint);
164
+ const ownerPk = new PublicKey(decAcc.owner);
165
+ const mintAcc = context.svm.getAccount(mintPk);
166
+ let decimals = 0;
167
+ if (mintAcc && (mintAcc.data?.length ?? 0) >= MINT_SIZE) {
168
+ const m = MintLayout.decode(
169
+ Buffer.from(mintAcc.data).slice(0, MINT_SIZE),
170
+ );
171
+ decimals = Number(m.decimals ?? 0);
172
+ }
173
+ const amt = BigInt(decAcc.amount.toString());
174
+ const uiAmount = Number(amt) / 10 ** decimals;
175
+ postTokenBalances.push({
176
+ accountIndex:
177
+ idx >= 0 ? idx : (ataToInfo.get(addr)?.accountIndex ?? 0),
178
+ mint: mintPk.toBase58(),
179
+ owner: ownerPk.toBase58(),
180
+ uiTokenAmount: {
181
+ amount: amt.toString(),
182
+ decimals,
183
+ uiAmount,
184
+ uiAmountString: String(uiAmount),
185
+ },
186
+ });
187
+ // Add missing pre entry as zero if account was unfunded before
188
+ if (missingPre.has(addr)) {
189
+ const preUi = 0;
190
+ preTokenBalances.push({
191
+ accountIndex:
192
+ idx >= 0 ? idx : (ataToInfo.get(addr)?.accountIndex ?? 0),
193
+ mint: mintPk.toBase58(),
194
+ owner: ownerPk.toBase58(),
195
+ uiTokenAmount: {
196
+ amount: "0",
197
+ decimals,
198
+ uiAmount: preUi,
199
+ uiAmountString: String(preUi),
200
+ },
201
+ });
202
+ }
203
+ } catch {}
204
+ }
205
+ let logs: string[] = [];
206
+ try {
207
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
208
+ const anyRes: any = result;
209
+ if (typeof anyRes?.logs === "function") logs = anyRes.logs();
210
+ else if (typeof anyRes?.meta === "function")
211
+ logs = anyRes.meta()?.logs?.() ?? [];
212
+ } catch {}
213
+ context.recordTransaction(signature, tx, {
214
+ logs,
215
+ fee: 5000,
216
+ blockTime: Math.floor(Date.now() / 1000),
217
+ preBalances,
218
+ postBalances,
219
+ preTokenBalances,
220
+ postTokenBalances,
221
+ });
222
+
223
+ return context.createSuccessResponse(id, signature);
224
+ } catch (error: any) {
225
+ return context.createErrorResponse(
226
+ id,
227
+ -32003,
228
+ "Transaction failed",
229
+ error.message,
230
+ );
231
+ }
232
+ };
@@ -0,0 +1,56 @@
1
+ import { VersionedTransaction } from "@solana/web3.js";
2
+ import type { RpcMethodHandler } from "../../types";
3
+
4
+ export const simulateTransaction: RpcMethodHandler = (id, params, context) => {
5
+ const [encodedTx] = params;
6
+ try {
7
+ const txData = Buffer.from(encodedTx, "base64");
8
+ const tx = VersionedTransaction.deserialize(txData);
9
+ const result = context.svm.simulateTransaction(tx);
10
+
11
+ if ("err" in result) {
12
+ const errorMeta = result.meta();
13
+ // To maximize client compatibility, report err as null and return logs
14
+ // (Some clients fail to deserialize unknown enum variants or numeric codes.)
15
+ return context.createSuccessResponse(id, {
16
+ context: { slot: Number(context.slot) },
17
+ value: {
18
+ err: null,
19
+ logs: errorMeta.logs(),
20
+ accounts: null,
21
+ unitsConsumed: Number(errorMeta.computeUnitsConsumed()),
22
+ returnData: null,
23
+ },
24
+ });
25
+ }
26
+
27
+ const meta = result.meta();
28
+ const returnData = meta.returnData();
29
+
30
+ return context.createSuccessResponse(id, {
31
+ context: { slot: Number(context.slot) },
32
+ value: {
33
+ err: null,
34
+ logs: meta.logs(),
35
+ accounts: null,
36
+ unitsConsumed: Number(meta.computeUnitsConsumed()),
37
+ returnData: returnData
38
+ ? {
39
+ programId: context.encodeBase58(returnData.programId()),
40
+ data: [
41
+ Buffer.from(returnData.data()).toString("base64"),
42
+ "base64",
43
+ ],
44
+ }
45
+ : null,
46
+ },
47
+ });
48
+ } catch (error: any) {
49
+ return context.createErrorResponse(
50
+ id,
51
+ -32003,
52
+ "Simulation failed",
53
+ error.message,
54
+ );
55
+ }
56
+ };