solforge 0.2.11 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/package.json +4 -8
  2. package/docs/API.md +0 -379
  3. package/docs/CONFIGURATION.md +0 -407
  4. package/docs/bun-single-file-executable.md +0 -585
  5. package/docs/cli-plan.md +0 -154
  6. package/docs/data-indexing-plan.md +0 -214
  7. package/docs/gui-roadmap.md +0 -202
  8. package/scripts/decode-b58.ts +0 -10
  9. package/scripts/install.sh +0 -112
  10. package/server/index.ts +0 -5
  11. package/server/lib/base58.ts +0 -33
  12. package/server/lib/faucet.ts +0 -110
  13. package/server/lib/instruction-parser.ts +0 -328
  14. package/server/lib/parsers/spl-associated-token-account.ts +0 -50
  15. package/server/lib/parsers/spl-token.ts +0 -340
  16. package/server/lib/spl-token.ts +0 -57
  17. package/server/methods/TEMPLATE.md +0 -117
  18. package/server/methods/account/get-account-info.ts +0 -86
  19. package/server/methods/account/get-balance.ts +0 -23
  20. package/server/methods/account/get-multiple-accounts.ts +0 -84
  21. package/server/methods/account/get-parsed-account-info.ts +0 -17
  22. package/server/methods/account/index.ts +0 -12
  23. package/server/methods/account/parsers/index.ts +0 -52
  24. package/server/methods/account/parsers/loader-upgradeable.ts +0 -79
  25. package/server/methods/account/parsers/spl-token.ts +0 -256
  26. package/server/methods/account/parsers/system.ts +0 -4
  27. package/server/methods/account/request-airdrop.ts +0 -271
  28. package/server/methods/admin/adopt-mint-authority.ts +0 -94
  29. package/server/methods/admin/clone-program-accounts.ts +0 -55
  30. package/server/methods/admin/clone-program.ts +0 -152
  31. package/server/methods/admin/clone-token-accounts.ts +0 -117
  32. package/server/methods/admin/clone-token-mint.ts +0 -82
  33. package/server/methods/admin/create-mint.ts +0 -114
  34. package/server/methods/admin/create-token-account.ts +0 -137
  35. package/server/methods/admin/helpers.ts +0 -70
  36. package/server/methods/admin/index.ts +0 -10
  37. package/server/methods/admin/list-mints.ts +0 -21
  38. package/server/methods/admin/load-program.ts +0 -52
  39. package/server/methods/admin/mint-to.ts +0 -266
  40. package/server/methods/block/get-block-height.ts +0 -5
  41. package/server/methods/block/get-block.ts +0 -31
  42. package/server/methods/block/get-blocks-with-limit.ts +0 -19
  43. package/server/methods/block/get-latest-blockhash.ts +0 -12
  44. package/server/methods/block/get-slot.ts +0 -5
  45. package/server/methods/block/index.ts +0 -6
  46. package/server/methods/block/is-blockhash-valid.ts +0 -19
  47. package/server/methods/epoch/get-cluster-nodes.ts +0 -17
  48. package/server/methods/epoch/get-epoch-info.ts +0 -16
  49. package/server/methods/epoch/get-epoch-schedule.ts +0 -15
  50. package/server/methods/epoch/get-highest-snapshot-slot.ts +0 -9
  51. package/server/methods/epoch/get-leader-schedule.ts +0 -8
  52. package/server/methods/epoch/get-max-retransmit-slot.ts +0 -9
  53. package/server/methods/epoch/get-max-shred-insert-slot.ts +0 -9
  54. package/server/methods/epoch/get-slot-leader.ts +0 -6
  55. package/server/methods/epoch/get-slot-leaders.ts +0 -9
  56. package/server/methods/epoch/get-stake-activation.ts +0 -9
  57. package/server/methods/epoch/get-stake-minimum-delegation.ts +0 -9
  58. package/server/methods/epoch/get-vote-accounts.ts +0 -19
  59. package/server/methods/epoch/index.ts +0 -13
  60. package/server/methods/epoch/minimum-ledger-slot.ts +0 -5
  61. package/server/methods/fee/get-fee-calculator-for-blockhash.ts +0 -12
  62. package/server/methods/fee/get-fee-for-message.ts +0 -8
  63. package/server/methods/fee/get-fee-rate-governor.ts +0 -16
  64. package/server/methods/fee/get-fees.ts +0 -14
  65. package/server/methods/fee/get-recent-prioritization-fees.ts +0 -22
  66. package/server/methods/fee/index.ts +0 -5
  67. package/server/methods/get-address-lookup-table.ts +0 -27
  68. package/server/methods/index.ts +0 -265
  69. package/server/methods/performance/get-recent-performance-samples.ts +0 -25
  70. package/server/methods/performance/get-transaction-count.ts +0 -5
  71. package/server/methods/performance/index.ts +0 -2
  72. package/server/methods/program/get-block-commitment.ts +0 -9
  73. package/server/methods/program/get-block-production.ts +0 -14
  74. package/server/methods/program/get-block-time.ts +0 -21
  75. package/server/methods/program/get-blocks.ts +0 -11
  76. package/server/methods/program/get-first-available-block.ts +0 -9
  77. package/server/methods/program/get-genesis-hash.ts +0 -6
  78. package/server/methods/program/get-identity.ts +0 -6
  79. package/server/methods/program/get-inflation-governor.ts +0 -15
  80. package/server/methods/program/get-inflation-rate.ts +0 -10
  81. package/server/methods/program/get-inflation-reward.ts +0 -12
  82. package/server/methods/program/get-largest-accounts.ts +0 -8
  83. package/server/methods/program/get-parsed-program-accounts.ts +0 -12
  84. package/server/methods/program/get-parsed-token-accounts-by-delegate.ts +0 -12
  85. package/server/methods/program/get-parsed-token-accounts-by-owner.ts +0 -12
  86. package/server/methods/program/get-program-accounts.ts +0 -221
  87. package/server/methods/program/get-supply.ts +0 -13
  88. package/server/methods/program/get-token-account-balance.ts +0 -60
  89. package/server/methods/program/get-token-accounts-by-delegate.ts +0 -82
  90. package/server/methods/program/get-token-accounts-by-owner.ts +0 -416
  91. package/server/methods/program/get-token-largest-accounts.ts +0 -81
  92. package/server/methods/program/get-token-supply.ts +0 -39
  93. package/server/methods/program/index.ts +0 -21
  94. package/server/methods/solforge/index.ts +0 -158
  95. package/server/methods/system/get-health.ts +0 -5
  96. package/server/methods/system/get-minimum-balance-for-rent-exemption.ts +0 -13
  97. package/server/methods/system/get-version.ts +0 -9
  98. package/server/methods/system/index.ts +0 -3
  99. package/server/methods/transaction/get-confirmed-transaction.ts +0 -11
  100. package/server/methods/transaction/get-parsed-transaction.ts +0 -17
  101. package/server/methods/transaction/get-signature-statuses.ts +0 -79
  102. package/server/methods/transaction/get-signatures-for-address.ts +0 -41
  103. package/server/methods/transaction/get-transaction.ts +0 -639
  104. package/server/methods/transaction/index.ts +0 -7
  105. package/server/methods/transaction/inner-instructions.test.ts +0 -104
  106. package/server/methods/transaction/send-transaction.ts +0 -469
  107. package/server/methods/transaction/simulate-transaction.ts +0 -57
  108. package/server/rpc-server.ts +0 -521
  109. package/server/types.ts +0 -109
  110. package/server/ws-server.ts +0 -178
  111. package/src/api-server-entry.ts +0 -109
  112. package/src/cli/bootstrap.ts +0 -67
  113. package/src/cli/commands/airdrop.ts +0 -37
  114. package/src/cli/commands/config.ts +0 -39
  115. package/src/cli/commands/mint.ts +0 -187
  116. package/src/cli/commands/program-clone.ts +0 -122
  117. package/src/cli/commands/program-load.ts +0 -64
  118. package/src/cli/commands/rpc-start.ts +0 -49
  119. package/src/cli/commands/token-adopt-authority.ts +0 -37
  120. package/src/cli/commands/token-clone.ts +0 -112
  121. package/src/cli/commands/token-create.ts +0 -81
  122. package/src/cli/main.ts +0 -152
  123. package/src/cli/run-solforge.ts +0 -112
  124. package/src/cli/setup-utils.ts +0 -54
  125. package/src/cli/setup-wizard.ts +0 -258
  126. package/src/cli/utils/args.ts +0 -15
  127. package/src/commands/add-program.ts +0 -333
  128. package/src/commands/init.ts +0 -122
  129. package/src/commands/list.ts +0 -136
  130. package/src/commands/mint.ts +0 -287
  131. package/src/commands/start.ts +0 -881
  132. package/src/commands/status.ts +0 -99
  133. package/src/commands/stop.ts +0 -405
  134. package/src/config/index.ts +0 -146
  135. package/src/config/manager.ts +0 -157
  136. package/src/db/index.ts +0 -83
  137. package/src/db/schema/accounts.ts +0 -23
  138. package/src/db/schema/address-signatures.ts +0 -31
  139. package/src/db/schema/index.ts +0 -6
  140. package/src/db/schema/meta-kv.ts +0 -9
  141. package/src/db/schema/transactions.ts +0 -36
  142. package/src/db/schema/tx-account-states.ts +0 -23
  143. package/src/db/schema/tx-accounts.ts +0 -33
  144. package/src/db/tx-store.ts +0 -264
  145. package/src/gui/public/app.css +0 -1556
  146. package/src/gui/public/build/main.css +0 -1569
  147. package/src/gui/public/build/main.js +0 -303
  148. package/src/gui/public/build/main.js.txt +0 -231
  149. package/src/gui/public/index.html +0 -19
  150. package/src/gui/server.ts +0 -296
  151. package/src/gui/src/api.ts +0 -127
  152. package/src/gui/src/app.tsx +0 -441
  153. package/src/gui/src/components/airdrop-mint-form.tsx +0 -246
  154. package/src/gui/src/components/clone-program-modal.tsx +0 -202
  155. package/src/gui/src/components/clone-token-modal.tsx +0 -230
  156. package/src/gui/src/components/modal.tsx +0 -134
  157. package/src/gui/src/components/programs-panel.tsx +0 -124
  158. package/src/gui/src/components/status-panel.tsx +0 -136
  159. package/src/gui/src/components/tokens-panel.tsx +0 -122
  160. package/src/gui/src/hooks/use-interval.ts +0 -17
  161. package/src/gui/src/index.css +0 -557
  162. package/src/gui/src/main.tsx +0 -17
  163. package/src/index.ts +0 -216
  164. package/src/migrations-bundled.ts +0 -23
  165. package/src/rpc/start.ts +0 -44
  166. package/src/services/api-server.ts +0 -504
  167. package/src/services/port-manager.ts +0 -174
  168. package/src/services/process-registry.ts +0 -153
  169. package/src/services/program-cloner.ts +0 -317
  170. package/src/services/token-cloner.ts +0 -811
  171. package/src/services/validator.ts +0 -293
  172. package/src/types/config.ts +0 -110
  173. package/src/utils/shell.ts +0 -110
  174. package/src/utils/token-loader.ts +0 -115
  175. /package/{start.js → start.cjs} +0 -0
@@ -1,202 +0,0 @@
1
- import { type ChangeEvent, useId, useState } from "react";
2
- import { Modal } from "./modal";
3
-
4
- interface Props {
5
- isOpen: boolean;
6
- onClose: () => void;
7
- onSubmit: (payload: {
8
- programId: string;
9
- endpoint?: string;
10
- withAccounts: boolean;
11
- accountsLimit?: number;
12
- }) => Promise<void>;
13
- }
14
-
15
- export function CloneProgramModal({ isOpen, onClose, onSubmit }: Props) {
16
- const programIdId = useId();
17
- const endpointId = useId();
18
- const accountLimitId = useId();
19
- const [programId, setProgramId] = useState("");
20
- const [endpoint, setEndpoint] = useState("");
21
- const [withAccounts, setWithAccounts] = useState(true);
22
- const [accountsLimit, setAccountsLimit] = useState("100");
23
- const [pending, setPending] = useState(false);
24
- const [error, setError] = useState<string | null>(null);
25
-
26
- const handleSubmit = async () => {
27
- setPending(true);
28
- setError(null);
29
- try {
30
- await onSubmit({
31
- programId: programId.trim(),
32
- endpoint: endpoint.trim() ? endpoint.trim() : undefined,
33
- withAccounts,
34
- accountsLimit:
35
- withAccounts && accountsLimit.trim()
36
- ? Number(accountsLimit)
37
- : undefined,
38
- });
39
- onClose();
40
- setProgramId("");
41
- setEndpoint("");
42
- setAccountsLimit("100");
43
- } catch (err: unknown) {
44
- const message =
45
- err && typeof err === "object" && "message" in err
46
- ? String((err as { message?: unknown }).message)
47
- : String(err);
48
- setError(message);
49
- } finally {
50
- setPending(false);
51
- }
52
- };
53
-
54
- return (
55
- <Modal
56
- isOpen={isOpen}
57
- onClose={() => {
58
- if (!pending) onClose();
59
- }}
60
- title="Clone Program"
61
- icon="fa-code"
62
- iconColor="blue"
63
- footer={
64
- <div className="flex justify-between items-center">
65
- <div className="text-xs text-gray-500">
66
- <i className="fas fa-info-circle mr-1"></i>
67
- Clone from Solana mainnet or custom RPC
68
- </div>
69
- <div className="flex gap-3">
70
- <button
71
- type="button"
72
- onClick={() => !pending && onClose()}
73
- disabled={pending}
74
- className="btn-secondary"
75
- >
76
- Cancel
77
- </button>
78
- <button
79
- type="button"
80
- onClick={handleSubmit}
81
- disabled={pending || programId.trim().length === 0}
82
- className={`btn-primary ${pending || programId.trim().length === 0 ? "opacity-50 cursor-not-allowed" : ""}`}
83
- >
84
- {pending ? (
85
- <>
86
- <div className="spinner"></div>
87
- <span>Cloning Program</span>
88
- </>
89
- ) : (
90
- <>
91
- <i className="fas fa-download"></i>
92
- <span>Clone Program</span>
93
- </>
94
- )}
95
- </button>
96
- </div>
97
- </div>
98
- }
99
- >
100
- <div className="space-y-5">
101
- <div className="space-y-2">
102
- <label
103
- htmlFor={programIdId}
104
- className="block text-xs font-semibold text-gray-400 uppercase tracking-wider"
105
- >
106
- Program ID *
107
- </label>
108
- <div className="relative">
109
- <input
110
- id={programIdId}
111
- value={programId}
112
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
113
- setProgramId(event.target.value)
114
- }
115
- placeholder="Enter program public key (e.g., TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA)"
116
- className="input pl-10 font-mono text-sm"
117
- />
118
- <i className="fas fa-fingerprint absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"></i>
119
- </div>
120
- </div>
121
-
122
- <div className="space-y-2">
123
- <label
124
- htmlFor={endpointId}
125
- className="block text-xs font-semibold text-gray-400 uppercase tracking-wider"
126
- >
127
- RPC Endpoint (Optional)
128
- </label>
129
- <div className="relative">
130
- <input
131
- id={endpointId}
132
- value={endpoint}
133
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
134
- setEndpoint(event.target.value)
135
- }
136
- placeholder="https://api.mainnet-beta.solana.com (default)"
137
- className="input pl-10"
138
- />
139
- <i className="fas fa-globe absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"></i>
140
- </div>
141
- </div>
142
-
143
- <div className="p-4 rounded-xl bg-white/5 border border-white/10 space-y-3">
144
- <label className="flex items-center gap-3 cursor-pointer group">
145
- <input
146
- type="checkbox"
147
- checked={withAccounts}
148
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
149
- setWithAccounts(event.target.checked)
150
- }
151
- className="checkbox"
152
- />
153
- <div>
154
- <span className="text-sm text-white group-hover:text-purple-300 transition-colors">
155
- Clone Program Accounts
156
- </span>
157
- <p className="text-xs text-gray-500 mt-0.5">
158
- Include accounts owned by this program
159
- </p>
160
- </div>
161
- </label>
162
-
163
- {withAccounts && (
164
- <div className="ml-8 space-y-2 pt-2 border-t border-white/5">
165
- <label
166
- htmlFor={accountLimitId}
167
- className="block text-xs font-semibold text-gray-400 uppercase tracking-wider"
168
- >
169
- Account Limit
170
- </label>
171
- <div className="relative">
172
- <input
173
- id={accountLimitId}
174
- value={accountsLimit}
175
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
176
- setAccountsLimit(event.target.value)
177
- }
178
- placeholder="100"
179
- type="number"
180
- min="1"
181
- max="1000"
182
- className="input pl-10"
183
- />
184
- <i className="fas fa-list-ol absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"></i>
185
- </div>
186
- <p className="text-xs text-gray-500">
187
- Maximum number of accounts to clone
188
- </p>
189
- </div>
190
- )}
191
- </div>
192
-
193
- {error && (
194
- <div className="flex items-start gap-2 p-3 rounded-lg bg-red-500/10 border border-red-500/30">
195
- <i className="fas fa-exclamation-circle text-red-400 mt-0.5"></i>
196
- <p className="text-sm text-red-300">{error}</p>
197
- </div>
198
- )}
199
- </div>
200
- </Modal>
201
- );
202
- }
@@ -1,230 +0,0 @@
1
- import { type ChangeEvent, useId, useState } from "react";
2
- import { Modal } from "./modal";
3
-
4
- interface Props {
5
- isOpen: boolean;
6
- onClose: () => void;
7
- onSubmit: (payload: {
8
- mint: string;
9
- endpoint?: string;
10
- cloneAccounts: boolean;
11
- holders?: number;
12
- allAccounts?: boolean;
13
- }) => Promise<void>;
14
- }
15
-
16
- export function CloneTokenModal({ isOpen, onClose, onSubmit }: Props) {
17
- const mintId = useId();
18
- const endpointId = useId();
19
- const holdersId = useId();
20
- const [mint, setMint] = useState("");
21
- const [endpoint, setEndpoint] = useState("");
22
- // Default OFF to avoid hitting public RPC rate limits by cloning holders.
23
- const [cloneAccounts, setCloneAccounts] = useState(false);
24
- const [holders, setHolders] = useState("20");
25
- const [allAccounts, setAllAccounts] = useState(false);
26
- const [pending, setPending] = useState(false);
27
- const [error, setError] = useState<string | null>(null);
28
-
29
- const handleSubmit = async () => {
30
- setPending(true);
31
- setError(null);
32
- try {
33
- await onSubmit({
34
- mint: mint.trim(),
35
- endpoint: endpoint.trim() ? endpoint.trim() : undefined,
36
- cloneAccounts,
37
- holders:
38
- cloneAccounts && !allAccounts && holders.trim()
39
- ? Number(holders)
40
- : undefined,
41
- allAccounts,
42
- });
43
- onClose();
44
- setMint("");
45
- setEndpoint("");
46
- setHolders("20");
47
- setAllAccounts(false);
48
- } catch (err: unknown) {
49
- const message =
50
- err && typeof err === "object" && "message" in err
51
- ? String((err as { message?: unknown }).message)
52
- : String(err);
53
- setError(message);
54
- } finally {
55
- setPending(false);
56
- }
57
- };
58
-
59
- return (
60
- <Modal
61
- isOpen={isOpen}
62
- onClose={() => {
63
- if (!pending) onClose();
64
- }}
65
- title="Clone Token"
66
- icon="fa-coins"
67
- iconColor="amber"
68
- footer={
69
- <div className="flex justify-between items-center">
70
- <div className="text-xs text-gray-500">
71
- <i className="fas fa-info-circle mr-1"></i>
72
- Clone SPL tokens from mainnet
73
- </div>
74
- <div className="flex gap-3">
75
- <button
76
- type="button"
77
- onClick={() => !pending && onClose()}
78
- disabled={pending}
79
- className="btn-secondary"
80
- >
81
- Cancel
82
- </button>
83
- <button
84
- type="button"
85
- onClick={handleSubmit}
86
- disabled={pending || mint.trim().length === 0}
87
- className={`btn-primary ${pending || mint.trim().length === 0 ? "opacity-50 cursor-not-allowed" : ""}`}
88
- >
89
- {pending ? (
90
- <>
91
- <div className="spinner"></div>
92
- <span>Cloning Token</span>
93
- </>
94
- ) : (
95
- <>
96
- <i className="fas fa-download"></i>
97
- <span>Clone Token</span>
98
- </>
99
- )}
100
- </button>
101
- </div>
102
- </div>
103
- }
104
- >
105
- <div className="space-y-5">
106
- <div className="space-y-2">
107
- <label
108
- htmlFor={mintId}
109
- className="block text-xs font-semibold text-gray-400 uppercase tracking-wider"
110
- >
111
- Mint Address *
112
- </label>
113
- <div className="relative">
114
- <input
115
- id={mintId}
116
- value={mint}
117
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
118
- setMint(event.target.value)
119
- }
120
- placeholder="Enter token mint address (e.g., EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v)"
121
- className="input pl-10 font-mono text-sm"
122
- />
123
- <i className="fas fa-coin absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"></i>
124
- </div>
125
- </div>
126
-
127
- <div className="space-y-2">
128
- <label
129
- htmlFor={endpointId}
130
- className="block text-xs font-semibold text-gray-400 uppercase tracking-wider"
131
- >
132
- RPC Endpoint (Optional)
133
- </label>
134
- <div className="relative">
135
- <input
136
- id={endpointId}
137
- value={endpoint}
138
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
139
- setEndpoint(event.target.value)
140
- }
141
- placeholder="https://api.mainnet-beta.solana.com (default)"
142
- className="input pl-10"
143
- />
144
- <i className="fas fa-globe absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"></i>
145
- </div>
146
- </div>
147
-
148
- <div className="p-4 rounded-xl bg-white/5 border border-white/10 space-y-3">
149
- <label className="flex items-center gap-3 cursor-pointer group">
150
- <input
151
- type="checkbox"
152
- checked={cloneAccounts}
153
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
154
- setCloneAccounts(event.target.checked)
155
- }
156
- className="checkbox"
157
- />
158
- <div>
159
- <span className="text-sm text-white group-hover:text-purple-300 transition-colors">
160
- Clone Token Accounts
161
- </span>
162
- <p className="text-xs text-gray-500 mt-0.5">
163
- Include holder accounts for this token
164
- </p>
165
- </div>
166
- </label>
167
-
168
- {cloneAccounts && (
169
- <div className="ml-8 space-y-4 pt-3 border-t border-white/5">
170
- <label className="flex items-center gap-3 cursor-pointer group">
171
- <input
172
- type="checkbox"
173
- checked={allAccounts}
174
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
175
- setAllAccounts(event.target.checked)
176
- }
177
- className="checkbox"
178
- />
179
- <div>
180
- <span className="text-sm text-white group-hover:text-purple-300 transition-colors">
181
- Clone All Accounts
182
- </span>
183
- <p className="text-xs text-gray-500 mt-0.5">
184
- Warning: This may be slow for popular tokens
185
- </p>
186
- </div>
187
- </label>
188
-
189
- {!allAccounts && (
190
- <div className="space-y-2">
191
- <label
192
- htmlFor={holdersId}
193
- className="block text-xs font-semibold text-gray-400 uppercase tracking-wider"
194
- >
195
- Top Holders Limit
196
- </label>
197
- <div className="relative">
198
- <input
199
- id={holdersId}
200
- value={holders}
201
- onChange={(event: ChangeEvent<HTMLInputElement>) =>
202
- setHolders(event.target.value)
203
- }
204
- placeholder="20"
205
- type="number"
206
- min="1"
207
- max="100"
208
- className="input pl-10"
209
- />
210
- <i className="fas fa-users absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"></i>
211
- </div>
212
- <p className="text-xs text-gray-500">
213
- Number of top holders to clone
214
- </p>
215
- </div>
216
- )}
217
- </div>
218
- )}
219
- </div>
220
-
221
- {error && (
222
- <div className="flex items-start gap-2 p-3 rounded-lg bg-red-500/10 border border-red-500/30">
223
- <i className="fas fa-exclamation-circle text-red-400 mt-0.5"></i>
224
- <p className="text-sm text-red-300">{error}</p>
225
- </div>
226
- )}
227
- </div>
228
- </Modal>
229
- );
230
- }
@@ -1,134 +0,0 @@
1
- import { type ReactNode, useEffect } from "react";
2
-
3
- interface ModalProps {
4
- isOpen: boolean;
5
- title: string;
6
- onClose: () => void;
7
- children: ReactNode;
8
- footer?: ReactNode;
9
- icon?: string;
10
- iconColor?: string;
11
- }
12
-
13
- export function Modal({
14
- isOpen,
15
- title,
16
- onClose,
17
- children,
18
- footer,
19
- icon = "fa-window-maximize",
20
- iconColor = "purple",
21
- }: ModalProps) {
22
- useEffect(() => {
23
- if (!isOpen || typeof window === "undefined") return undefined;
24
- const handler = (event: KeyboardEvent) => {
25
- if (event.key === "Escape") onClose();
26
- };
27
- window.addEventListener("keydown", handler);
28
- return () => window.removeEventListener("keydown", handler);
29
- }, [isOpen, onClose]);
30
-
31
- if (!isOpen) return null;
32
-
33
- const colorClasses = {
34
- purple: "from-purple-500/20 to-violet-500/20 text-purple-400",
35
- blue: "from-blue-500/20 to-cyan-500/20 text-blue-400",
36
- amber: "from-amber-500/20 to-orange-500/20 text-amber-400",
37
- green: "from-green-500/20 to-emerald-500/20 text-green-400",
38
- };
39
-
40
- return (
41
- <div className="fixed inset-0 z-50 flex items-center justify-center p-4 animate-fadeIn">
42
- {/* Backdrop */}
43
- <button
44
- type="button"
45
- className="absolute inset-0 bg-black/80 backdrop-blur-sm"
46
- aria-label="Close modal"
47
- onClick={onClose}
48
- onKeyDown={(e) => {
49
- if (e.key === "Enter" || e.key === " ") onClose();
50
- }}
51
- />
52
-
53
- {/* Modal */}
54
- <div className="w-full max-w-lg p-0 relative animate-modalSlideIn overflow-hidden rounded-2xl border border-white/20 bg-gray-900/95 backdrop-blur-xl shadow-2xl">
55
- {/* Header */}
56
- <div className="p-6 border-b border-white/10 bg-gradient-to-r from-white/5 to-transparent">
57
- <div className="flex items-center justify-between">
58
- <div className="flex items-center gap-3">
59
- <div
60
- className={`w-10 h-10 rounded-xl bg-gradient-to-br ${colorClasses[iconColor as keyof typeof colorClasses]} flex items-center justify-center`}
61
- >
62
- <i className={`fas ${icon}`}></i>
63
- </div>
64
- <h3 className="text-xl font-bold text-white">{title}</h3>
65
- </div>
66
- <button
67
- type="button"
68
- onClick={onClose}
69
- className="btn-icon hover:bg-red-500/20 hover:border-red-500/30 hover:text-red-400"
70
- aria-label="Close modal"
71
- >
72
- <i className="fas fa-times"></i>
73
- </button>
74
- </div>
75
- </div>
76
-
77
- {/* Content */}
78
- <div className="p-6 max-h-[60vh] overflow-y-auto custom-scrollbar">
79
- {children}
80
- </div>
81
-
82
- {/* Footer */}
83
- {footer && (
84
- <div className="p-6 border-t border-white/10 bg-gradient-to-r from-white/5 to-transparent">
85
- {footer}
86
- </div>
87
- )}
88
- </div>
89
-
90
- <style jsx>{`
91
- @keyframes fadeIn {
92
- from {
93
- opacity: 0;
94
- }
95
- to {
96
- opacity: 1;
97
- }
98
- }
99
-
100
- @keyframes modalSlideIn {
101
- from {
102
- opacity: 0;
103
- transform: scale(0.95) translateY(20px);
104
- }
105
- to {
106
- opacity: 1;
107
- transform: scale(1) translateY(0);
108
- }
109
- }
110
-
111
- .animate-fadeIn {
112
- animation: fadeIn 0.2s ease-out;
113
- }
114
-
115
- .animate-modalSlideIn {
116
- animation: modalSlideIn 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
117
- }
118
-
119
- .custom-scrollbar::-webkit-scrollbar {
120
- width: 8px;
121
- }
122
-
123
- .custom-scrollbar::-webkit-scrollbar-track {
124
- background: transparent;
125
- }
126
-
127
- .custom-scrollbar::-webkit-scrollbar-thumb {
128
- background: linear-gradient(180deg, var(--color-accent-primary), var(--color-accent-secondary));
129
- border-radius: 4px;
130
- }
131
- `}</style>
132
- </div>
133
- );
134
- }
@@ -1,124 +0,0 @@
1
- import type { ProgramSummary } from "../api";
2
-
3
- interface Props {
4
- programs: ProgramSummary[];
5
- loading: boolean;
6
- onRefresh: () => void;
7
- onAdd: () => void;
8
- }
9
-
10
- export function ProgramsPanel({ programs, loading, onRefresh, onAdd }: Props) {
11
- return (
12
- <section className="glass-panel p-6">
13
- <header className="flex flex-wrap items-center justify-between gap-3 mb-6">
14
- <div className="flex items-center gap-3">
15
- <div className="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-500/20 to-cyan-500/20 flex items-center justify-center">
16
- <i className="fas fa-code text-blue-400"></i>
17
- </div>
18
- <div>
19
- <h2 className="text-xl font-bold text-white">Programs</h2>
20
- <p className="text-xs text-gray-500">
21
- {programs.length} deployed programs
22
- </p>
23
- </div>
24
- </div>
25
- <div className="flex items-center gap-2">
26
- <button
27
- type="button"
28
- onClick={onRefresh}
29
- disabled={loading}
30
- className={`btn-secondary text-sm ${loading ? "opacity-50 cursor-not-allowed" : ""}`}
31
- >
32
- <i
33
- className={`fas fa-sync-alt ${loading ? "animate-spin" : ""}`}
34
- ></i>
35
- <span>{loading ? "Refreshing" : "Refresh"}</span>
36
- </button>
37
- <button type="button" onClick={onAdd} className="btn-primary text-sm">
38
- <i className="fas fa-plus"></i>
39
- <span>Add Program</span>
40
- </button>
41
- </div>
42
- </header>
43
-
44
- <div className="overflow-x-auto rounded-xl">
45
- {programs.length === 0 ? (
46
- <div className="flex flex-col items-center justify-center py-12 text-center">
47
- <div className="w-16 h-16 rounded-full bg-gradient-to-br from-blue-600/20 to-cyan-600/20 flex items-center justify-center mb-4">
48
- <i className="fas fa-code text-blue-500 text-2xl"></i>
49
- </div>
50
- <p className="text-gray-400 mb-2">No programs deployed</p>
51
- <p className="text-sm text-gray-500">
52
- Click "Add Program" to clone from mainnet
53
- </p>
54
- </div>
55
- ) : (
56
- <table className="table-modern">
57
- <thead>
58
- <tr>
59
- <th>Program ID</th>
60
- <th>Owner</th>
61
- <th>Status</th>
62
- <th>Data Size</th>
63
- <th>Balance</th>
64
- </tr>
65
- </thead>
66
- <tbody>
67
- {programs.map((program, index) => (
68
- <tr
69
- key={program.programId}
70
- style={{ animationDelay: `${index * 50}ms` }}
71
- className="animate-fadeIn"
72
- >
73
- <td>
74
- <div className="flex items-center gap-2">
75
- <i className="fas fa-cube text-blue-400 text-xs"></i>
76
- <span className="font-mono text-xs text-blue-300">
77
- {program.programId.slice(0, 8)}...
78
- {program.programId.slice(-6)}
79
- </span>
80
- </div>
81
- </td>
82
- <td>
83
- <span className="font-mono text-xs text-gray-400">
84
- {program.owner.slice(0, 8)}...
85
- </span>
86
- </td>
87
- <td>
88
- <span
89
- className={`badge ${program.executable ? "badge-success" : "badge-warning"}`}
90
- >
91
- <i
92
- className={`fas fa-${program.executable ? "check" : "pause"} text-xs`}
93
- ></i>
94
- <span>
95
- {program.executable ? "Executable" : "Data Only"}
96
- </span>
97
- </span>
98
- </td>
99
- <td>
100
- <div className="flex items-center gap-2">
101
- <i className="fas fa-database text-gray-400 text-xs"></i>
102
- <span className="text-gray-300">
103
- {(program.dataLen / 1024).toFixed(1)} KB
104
- </span>
105
- </div>
106
- </td>
107
- <td>
108
- <div className="flex items-center gap-2">
109
- <i className="fas fa-wallet text-gray-400 text-xs"></i>
110
- <span className="text-gray-300">
111
- {(Number(BigInt(program.lamports)) / 1e9).toFixed(4)}{" "}
112
- SOL
113
- </span>
114
- </div>
115
- </td>
116
- </tr>
117
- ))}
118
- </tbody>
119
- </table>
120
- )}
121
- </div>
122
- </section>
123
- );
124
- }