create-stylus-ide 1.0.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 (135) hide show
  1. package/Readme.MD +1515 -0
  2. package/cli.js +28 -0
  3. package/frontend/.vscode/settings.json +9 -0
  4. package/frontend/app/api/chat/route.ts +101 -0
  5. package/frontend/app/api/check-setup/route.ts +93 -0
  6. package/frontend/app/api/cleanup/route.ts +14 -0
  7. package/frontend/app/api/compile/route.ts +95 -0
  8. package/frontend/app/api/compile-stream/route.ts +98 -0
  9. package/frontend/app/api/complete/route.ts +86 -0
  10. package/frontend/app/api/deploy/route.ts +118 -0
  11. package/frontend/app/api/export-abi/route.ts +58 -0
  12. package/frontend/app/favicon.ico +0 -0
  13. package/frontend/app/globals.css +177 -0
  14. package/frontend/app/layout.tsx +29 -0
  15. package/frontend/app/ml/page.tsx +694 -0
  16. package/frontend/app/page.tsx +1132 -0
  17. package/frontend/app/providers.tsx +18 -0
  18. package/frontend/app/qlearning/page.tsx +188 -0
  19. package/frontend/app/raytracing/page.tsx +268 -0
  20. package/frontend/components/abi/ABIDialog.tsx +132 -0
  21. package/frontend/components/ai/AICompletionPopup.tsx +76 -0
  22. package/frontend/components/ai/ChatPanel.tsx +292 -0
  23. package/frontend/components/ai/QuickActions.tsx +128 -0
  24. package/frontend/components/blockchain/BlockchainContractBanner.tsx +64 -0
  25. package/frontend/components/blockchain/BlockchainLoadingDialog.tsx +188 -0
  26. package/frontend/components/deploy/DeployDialog.tsx +334 -0
  27. package/frontend/components/editor/FileTabs.tsx +181 -0
  28. package/frontend/components/editor/MonacoEditor.tsx +306 -0
  29. package/frontend/components/file-tree/ContextMenu.tsx +110 -0
  30. package/frontend/components/file-tree/DeleteConfirmDialog.tsx +61 -0
  31. package/frontend/components/file-tree/FileInputDialog.tsx +97 -0
  32. package/frontend/components/file-tree/FileNode.tsx +60 -0
  33. package/frontend/components/file-tree/FileTree.tsx +259 -0
  34. package/frontend/components/file-tree/FileTreeSkeleton.tsx +26 -0
  35. package/frontend/components/file-tree/FolderNode.tsx +105 -0
  36. package/frontend/components/github/GitHubLoadingDialog.tsx +201 -0
  37. package/frontend/components/github/GitHubMetadataBanner.tsx +61 -0
  38. package/frontend/components/github/LoadFromGitHubDialog.tsx +125 -0
  39. package/frontend/components/github/URLCopyButton.tsx +60 -0
  40. package/frontend/components/interact/ContractInteraction.tsx +323 -0
  41. package/frontend/components/interact/ContractPlaceholder.tsx +41 -0
  42. package/frontend/components/orbit/BenchmarkDialog.tsx +342 -0
  43. package/frontend/components/orbit/OrbitExplorer.tsx +273 -0
  44. package/frontend/components/project/ProjectActions.tsx +176 -0
  45. package/frontend/components/q-learning/ContractConfig.tsx +172 -0
  46. package/frontend/components/q-learning/MazeGrid.tsx +346 -0
  47. package/frontend/components/q-learning/PathAnimation.tsx +384 -0
  48. package/frontend/components/q-learning/QTableHeatmap.tsx +300 -0
  49. package/frontend/components/q-learning/TrainingForm.tsx +349 -0
  50. package/frontend/components/ray-tracing/ContractConfig.tsx +245 -0
  51. package/frontend/components/ray-tracing/MintingForm.tsx +280 -0
  52. package/frontend/components/ray-tracing/RenderCanvas.tsx +228 -0
  53. package/frontend/components/ray-tracing/RenderingPanel.tsx +259 -0
  54. package/frontend/components/ray-tracing/StyleControls.tsx +217 -0
  55. package/frontend/components/setup/SetupGuide.tsx +290 -0
  56. package/frontend/components/ui/KeyboardShortcutHint.tsx +74 -0
  57. package/frontend/components/ui/alert-dialog.tsx +157 -0
  58. package/frontend/components/ui/alert.tsx +66 -0
  59. package/frontend/components/ui/badge.tsx +46 -0
  60. package/frontend/components/ui/button.tsx +62 -0
  61. package/frontend/components/ui/card.tsx +92 -0
  62. package/frontend/components/ui/context-menu.tsx +252 -0
  63. package/frontend/components/ui/dialog.tsx +143 -0
  64. package/frontend/components/ui/dropdown-menu.tsx +257 -0
  65. package/frontend/components/ui/input.tsx +21 -0
  66. package/frontend/components/ui/label.tsx +24 -0
  67. package/frontend/components/ui/progress.tsx +31 -0
  68. package/frontend/components/ui/scroll-area.tsx +58 -0
  69. package/frontend/components/ui/select.tsx +190 -0
  70. package/frontend/components/ui/separator.tsx +28 -0
  71. package/frontend/components/ui/sheet.tsx +139 -0
  72. package/frontend/components/ui/skeleton.tsx +13 -0
  73. package/frontend/components/ui/slider.tsx +63 -0
  74. package/frontend/components/ui/sonner.tsx +40 -0
  75. package/frontend/components/ui/tabs.tsx +66 -0
  76. package/frontend/components/ui/textarea.tsx +18 -0
  77. package/frontend/components/wallet/ConnectButton.tsx +167 -0
  78. package/frontend/components/wallet/FaucetButton.tsx +256 -0
  79. package/frontend/components.json +22 -0
  80. package/frontend/eslint.config.mjs +18 -0
  81. package/frontend/hooks/useAICompletion.ts +75 -0
  82. package/frontend/hooks/useBlockchainLoader.ts +58 -0
  83. package/frontend/hooks/useChats.ts +137 -0
  84. package/frontend/hooks/useCompilation.ts +173 -0
  85. package/frontend/hooks/useFileTabs.ts +178 -0
  86. package/frontend/hooks/useGitHubLoader.ts +50 -0
  87. package/frontend/hooks/useKeyboardShortcuts.ts +47 -0
  88. package/frontend/hooks/usePanelState.ts +115 -0
  89. package/frontend/hooks/useProjectState.ts +276 -0
  90. package/frontend/hooks/useResponsive.ts +29 -0
  91. package/frontend/lib/abi-parser.ts +58 -0
  92. package/frontend/lib/blockchain-api.ts +374 -0
  93. package/frontend/lib/blockchain-explorers.ts +75 -0
  94. package/frontend/lib/blockchain-loader.ts +112 -0
  95. package/frontend/lib/cargo-template.ts +64 -0
  96. package/frontend/lib/compilation.ts +529 -0
  97. package/frontend/lib/constants.ts +31 -0
  98. package/frontend/lib/deployment.ts +176 -0
  99. package/frontend/lib/file-utils.ts +83 -0
  100. package/frontend/lib/github-api.ts +246 -0
  101. package/frontend/lib/github-loader.ts +369 -0
  102. package/frontend/lib/ml-contract-template.txt +900 -0
  103. package/frontend/lib/orbit-chains.ts +181 -0
  104. package/frontend/lib/output-formatter.ts +68 -0
  105. package/frontend/lib/project-manager.ts +632 -0
  106. package/frontend/lib/ray-tracing-abi.ts +206 -0
  107. package/frontend/lib/storage.ts +189 -0
  108. package/frontend/lib/templates.ts +1662 -0
  109. package/frontend/lib/url-parser.ts +188 -0
  110. package/frontend/lib/utils.ts +6 -0
  111. package/frontend/lib/wagmi-config.ts +24 -0
  112. package/frontend/next.config.ts +7 -0
  113. package/frontend/package-lock.json +16259 -0
  114. package/frontend/package.json +60 -0
  115. package/frontend/postcss.config.mjs +7 -0
  116. package/frontend/public/file.svg +1 -0
  117. package/frontend/public/globe.svg +1 -0
  118. package/frontend/public/ml-weights/.gitkeep +0 -0
  119. package/frontend/public/ml-weights/model.pkl +0 -0
  120. package/frontend/public/ml-weights/model_weights.json +27102 -0
  121. package/frontend/public/ml-weights/test_samples.json +7888 -0
  122. package/frontend/public/next.svg +1 -0
  123. package/frontend/public/vercel.svg +1 -0
  124. package/frontend/public/window.svg +1 -0
  125. package/frontend/scripts/check-env.js +52 -0
  126. package/frontend/scripts/setup.js +285 -0
  127. package/frontend/tailwind.config.ts +64 -0
  128. package/frontend/tsconfig.json +34 -0
  129. package/frontend/types/blockchain.ts +63 -0
  130. package/frontend/types/github.ts +54 -0
  131. package/frontend/types/project.ts +106 -0
  132. package/ml-training/README.md +56 -0
  133. package/ml-training/train_tiny_model.py +325 -0
  134. package/ml-training/update_template.py +59 -0
  135. package/package.json +30 -0
@@ -0,0 +1,349 @@
1
+ // trainingform.tsx
2
+ 'use client';
3
+
4
+ import { useEffect, useMemo, useRef, useState } from 'react';
5
+ import { Button } from '@/components/ui/button';
6
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
7
+ import { Input } from '@/components/ui/input';
8
+ import { Label } from '@/components/ui/label';
9
+ import { Loader2, Zap, ExternalLink, AlertTriangle } from 'lucide-react';
10
+ import { useAccount, useWriteContract, useWaitForTransactionReceipt } from 'wagmi';
11
+ import { parseAbi } from 'viem';
12
+ import { arbitrumSepolia } from 'wagmi/chains';
13
+
14
+ const QLEARNING_ABI = parseAbi([
15
+ 'function train(uint256 episodes, uint256 max_steps, uint256 epsilon, uint256 alpha, uint256 gamma) external',
16
+ ]);
17
+
18
+ interface TrainingFormProps {
19
+ contractAddress: string;
20
+ isConnected: boolean;
21
+ onTrainingComplete: () => void;
22
+ }
23
+
24
+ function clampInt(value: string, min: number, max: number, fallback: number) {
25
+ const n = Number.parseInt(value, 10);
26
+ if (!Number.isFinite(n)) return fallback;
27
+ return Math.min(max, Math.max(min, n));
28
+ }
29
+
30
+ export function TrainingForm({ contractAddress, isConnected, onTrainingComplete }: TrainingFormProps) {
31
+ const { isConnected: walletConnected } = useAccount();
32
+
33
+ // Defaults (scaled params are /10000 in your contract)
34
+ const [episodes, setEpisodes] = useState('50'); // 10-100 recommended
35
+ const [maxSteps, setMaxSteps] = useState('50'); // 20-100 recommended
36
+ const [epsilon, setEpsilon] = useState('2000'); // 0.2
37
+ const [alpha, setAlpha] = useState('2000'); // 0.2
38
+ const [gamma, setGamma] = useState('9000'); // 0.9
39
+
40
+ const {
41
+ writeContract,
42
+ data: hash,
43
+ isPending,
44
+ error: writeError,
45
+ } = useWriteContract();
46
+
47
+ const {
48
+ isLoading: isConfirming,
49
+ isSuccess,
50
+ error: receiptError,
51
+ } = useWaitForTransactionReceipt({
52
+ hash,
53
+ // If your whole dApp is always on Arbitrum Sepolia, keep this.
54
+ // If not, remove it.
55
+ chainId: arbitrumSepolia.id,
56
+ });
57
+
58
+ // --- one-shot completion latch ---
59
+ const notifiedHashRef = useRef<`0x${string}` | null>(null);
60
+ const onCompleteRef = useRef(onTrainingComplete);
61
+
62
+ useEffect(() => {
63
+ onCompleteRef.current = onTrainingComplete;
64
+ }, [onTrainingComplete]);
65
+
66
+ const LATCH_KEY = useMemo(
67
+ () => `qlearning:train:completed:${contractAddress.toLowerCase()}`,
68
+ [contractAddress],
69
+ );
70
+
71
+ // Reset latch whenever user changes contract
72
+ useEffect(() => {
73
+ notifiedHashRef.current = null;
74
+ try {
75
+ sessionStorage.removeItem(LATCH_KEY);
76
+ } catch {
77
+ // ignore
78
+ }
79
+ }, [LATCH_KEY]);
80
+
81
+ useEffect(() => {
82
+ if (!isSuccess || !hash) return;
83
+
84
+ // In-component latch
85
+ if (notifiedHashRef.current === hash) return;
86
+
87
+ // Session latch (survives StrictMode dev remounts)
88
+ try {
89
+ const prev = sessionStorage.getItem(LATCH_KEY);
90
+ if (prev === hash) return;
91
+ sessionStorage.setItem(LATCH_KEY, hash);
92
+ } catch {
93
+ // ignore (private mode, etc.)
94
+ }
95
+
96
+ notifiedHashRef.current = hash;
97
+
98
+ const t = window.setTimeout(() => {
99
+ onCompleteRef.current();
100
+ }, 800);
101
+
102
+ return () => window.clearTimeout(t);
103
+ }, [isSuccess, hash, LATCH_KEY]);
104
+
105
+ const gasEstimate = useMemo(() => {
106
+ const eps = clampInt(episodes, 1, 1000, 50);
107
+ const steps = clampInt(maxSteps, 1, 200, 50);
108
+ const totalOps = eps * steps;
109
+
110
+ // This is just a heuristic display. Don’t treat as exact.
111
+ const estimatedGas = totalOps * 1000;
112
+ const safe = estimatedGas <= 25_000_000; // ~25M heuristic safety
113
+
114
+ return { operations: totalOps, estimatedGas, safe };
115
+ }, [episodes, maxSteps]);
116
+
117
+ const handleTrain = async () => {
118
+ if (!walletConnected) {
119
+ alert('Please connect your wallet first.');
120
+ return;
121
+ }
122
+ if (!contractAddress) {
123
+ alert('Please enter a contract address.');
124
+ return;
125
+ }
126
+
127
+ // Clamp inputs to sane ranges before sending
128
+ const eps = clampInt(episodes, 1, 1000, 50);
129
+ const steps = clampInt(maxSteps, 1, 200, 50);
130
+ const e = clampInt(epsilon, 0, 10000, 2000);
131
+ const a = clampInt(alpha, 0, 10000, 2000);
132
+ const g = clampInt(gamma, 0, 10000, 9000);
133
+
134
+ if (!gasEstimate.safe) {
135
+ const ok = window.confirm(
136
+ `⚠️ High Gas Warning\n\n` +
137
+ `Approx operations: ${gasEstimate.operations.toLocaleString()}\n` +
138
+ `Heuristic gas: ${gasEstimate.estimatedGas.toLocaleString()}\n\n` +
139
+ `This might fail due to gas limits.\n\nContinue anyway?`,
140
+ );
141
+ if (!ok) return;
142
+ }
143
+
144
+ // Reset latches for a new training tx
145
+ notifiedHashRef.current = null;
146
+ try {
147
+ sessionStorage.removeItem(LATCH_KEY);
148
+ } catch {
149
+ // ignore
150
+ }
151
+
152
+ writeContract({
153
+ address: contractAddress as `0x${string}`,
154
+ abi: QLEARNING_ABI,
155
+ functionName: 'train',
156
+ args: [BigInt(eps), BigInt(steps), BigInt(e), BigInt(a), BigInt(g)],
157
+ gas: BigInt(30_000_000),
158
+ });
159
+ };
160
+
161
+ const explorerUrl = hash
162
+ ? `${arbitrumSepolia.blockExplorers.default.url}/tx/${hash}`
163
+ : null;
164
+
165
+ const combinedError = writeError ?? receiptError;
166
+
167
+ return (
168
+ <Card>
169
+ <CardHeader>
170
+ <CardTitle>Train Agent</CardTitle>
171
+ <CardDescription>
172
+ Configure Q-learning parameters and train the agent on-chain
173
+ </CardDescription>
174
+ </CardHeader>
175
+
176
+ <CardContent className="space-y-4">
177
+ {!gasEstimate.safe && (
178
+ <div className="bg-yellow-500/10 border border-yellow-500/20 p-3 rounded-md text-sm text-yellow-400">
179
+ <div className="flex items-start gap-2">
180
+ <AlertTriangle className="h-4 w-4 mt-0.5 shrink-0" />
181
+ <div>
182
+ <p className="font-medium">⚠️ High Gas Warning</p>
183
+ <p className="text-xs mt-1">
184
+ Heuristic estimate suggests this may exceed gas limits. Reduce episodes or max steps.
185
+ </p>
186
+ </div>
187
+ </div>
188
+ </div>
189
+ )}
190
+
191
+ <div className="space-y-2">
192
+ <Label htmlFor="episodes">
193
+ Episodes <span className="ml-2 text-xs text-muted-foreground">(10–100)</span>
194
+ </Label>
195
+ <Input
196
+ id="episodes"
197
+ type="number"
198
+ value={episodes}
199
+ onChange={(e) => setEpisodes(e.target.value)}
200
+ disabled={isPending || isConfirming}
201
+ min="1"
202
+ max="1000"
203
+ />
204
+ <p className="text-xs text-muted-foreground">Number of complete runs from start to goal</p>
205
+ </div>
206
+
207
+ <div className="space-y-2">
208
+ <Label htmlFor="maxSteps">
209
+ Max Steps per Episode <span className="ml-2 text-xs text-muted-foreground">(20–100)</span>
210
+ </Label>
211
+ <Input
212
+ id="maxSteps"
213
+ type="number"
214
+ value={maxSteps}
215
+ onChange={(e) => setMaxSteps(e.target.value)}
216
+ disabled={isPending || isConfirming}
217
+ min="1"
218
+ max="200"
219
+ />
220
+ <p className="text-xs text-muted-foreground">Maximum moves before episode ends</p>
221
+ </div>
222
+
223
+ <div className="space-y-2">
224
+ <Label htmlFor="epsilon">
225
+ Epsilon (Exploration) — scaled <span className="ml-2 text-xs text-muted-foreground">(0–10000)</span>
226
+ </Label>
227
+ <Input
228
+ id="epsilon"
229
+ type="number"
230
+ value={epsilon}
231
+ onChange={(e) => setEpsilon(e.target.value)}
232
+ disabled={isPending || isConfirming}
233
+ min="0"
234
+ max="10000"
235
+ />
236
+ <p className="text-xs text-muted-foreground">Random action chance (e.g., 2000 = 0.2)</p>
237
+ </div>
238
+
239
+ <div className="space-y-2">
240
+ <Label htmlFor="alpha">
241
+ Alpha (Learning Rate) — scaled <span className="ml-2 text-xs text-muted-foreground">(0–10000)</span>
242
+ </Label>
243
+ <Input
244
+ id="alpha"
245
+ type="number"
246
+ value={alpha}
247
+ onChange={(e) => setAlpha(e.target.value)}
248
+ disabled={isPending || isConfirming}
249
+ min="0"
250
+ max="10000"
251
+ />
252
+ <p className="text-xs text-muted-foreground">Update strength (e.g., 2000 = 0.2)</p>
253
+ </div>
254
+
255
+ <div className="space-y-2">
256
+ <Label htmlFor="gamma">
257
+ Gamma (Discount) — scaled <span className="ml-2 text-xs text-muted-foreground">(0–10000)</span>
258
+ </Label>
259
+ <Input
260
+ id="gamma"
261
+ type="number"
262
+ value={gamma}
263
+ onChange={(e) => setGamma(e.target.value)}
264
+ disabled={isPending || isConfirming}
265
+ min="0"
266
+ max="10000"
267
+ />
268
+ <p className="text-xs text-muted-foreground">Future reward importance (e.g., 9000 = 0.9)</p>
269
+ </div>
270
+
271
+ <div className="bg-muted p-3 rounded-md text-xs space-y-1">
272
+ <div className="flex justify-between">
273
+ <span className="text-muted-foreground">Est. Operations:</span>
274
+ <span className="font-mono">{gasEstimate.operations.toLocaleString()}</span>
275
+ </div>
276
+ <div className="flex justify-between">
277
+ <span className="text-muted-foreground">Heuristic Gas:</span>
278
+ <span className="font-mono">{gasEstimate.estimatedGas.toLocaleString()}</span>
279
+ </div>
280
+ <div className="flex justify-between">
281
+ <span className="text-muted-foreground">Safety:</span>
282
+ <span className={gasEstimate.safe ? 'text-green-500' : 'text-yellow-500'}>
283
+ {gasEstimate.safe ? '✓ Likely OK' : '⚠ Risky'}
284
+ </span>
285
+ </div>
286
+ </div>
287
+
288
+ <Button
289
+ onClick={handleTrain}
290
+ disabled={!walletConnected || !isConnected || isPending || isConfirming}
291
+ className="w-full"
292
+ size="lg"
293
+ >
294
+ {isPending || isConfirming ? (
295
+ <>
296
+ <Loader2 className="h-4 w-4 mr-2 animate-spin" />
297
+ {isPending ? 'Waiting for signature...' : 'Training on-chain...'}
298
+ </>
299
+ ) : (
300
+ <>
301
+ <Zap className="h-4 w-4 mr-2" />
302
+ Train Agent
303
+ </>
304
+ )}
305
+ </Button>
306
+
307
+ {hash && (
308
+ <div className="space-y-2 pt-4 border-t border-border">
309
+ <div className="flex items-center justify-between text-sm">
310
+ <span className="text-muted-foreground">Transaction:</span>
311
+ <a
312
+ href={explorerUrl || '#'}
313
+ target="_blank"
314
+ rel="noopener noreferrer"
315
+ className="flex items-center gap-1 text-primary hover:underline"
316
+ >
317
+ {hash.slice(0, 6)}...{hash.slice(-4)}
318
+ <ExternalLink className="h-3 w-3" />
319
+ </a>
320
+ </div>
321
+ <div className="flex items-center justify-between text-sm">
322
+ <span className="text-muted-foreground">Status:</span>
323
+ <span className={isSuccess ? 'text-green-500' : 'text-yellow-500'}>
324
+ {isSuccess ? '✓ Success' : '⏳ Confirming...'}
325
+ </span>
326
+ </div>
327
+ </div>
328
+ )}
329
+
330
+ {isSuccess && (
331
+ <div className="bg-green-500/10 border border-green-500/20 p-3 rounded-md text-sm text-green-400">
332
+ <p className="font-medium">🎉 Training Complete!</p>
333
+ <p className="text-xs mt-1">Refreshing the maze policy…</p>
334
+ </div>
335
+ )}
336
+
337
+ {combinedError && (
338
+ <div className="bg-red-500/10 border border-red-500/20 p-3 rounded-md text-sm text-red-400">
339
+ <p className="font-medium">Training Failed</p>
340
+ <p className="text-xs mt-1">{combinedError.message}</p>
341
+ {combinedError.message.toLowerCase().includes('gas') && (
342
+ <p className="text-xs mt-2">💡 Try reducing episodes or max_steps</p>
343
+ )}
344
+ </div>
345
+ )}
346
+ </CardContent>
347
+ </Card>
348
+ );
349
+ }
@@ -0,0 +1,245 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Button } from '@/components/ui/button';
5
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
6
+ import { Input } from '@/components/ui/input';
7
+ import { Label } from '@/components/ui/label';
8
+ import { CheckCircle2, XCircle, Loader2 } from 'lucide-react';
9
+ import { usePublicClient } from 'wagmi';
10
+ import { arbitrumSepolia } from 'wagmi/chains';
11
+ import { MNN_ABI, RAY_TRACING_ABI } from '@/lib/ray-tracing-abi';
12
+
13
+ interface ContractConfigProps {
14
+ mnnAddress: string;
15
+ setMnnAddress: (address: string) => void;
16
+ nftAddress: string;
17
+ setNftAddress: (address: string) => void;
18
+ isMnnConnected: boolean;
19
+ setIsMnnConnected: (connected: boolean) => void;
20
+ isNftConnected: boolean;
21
+ setIsNftConnected: (connected: boolean) => void;
22
+ }
23
+
24
+ export function ContractConfig({
25
+ mnnAddress,
26
+ setMnnAddress,
27
+ nftAddress,
28
+ setNftAddress,
29
+ isMnnConnected,
30
+ setIsMnnConnected,
31
+ isNftConnected,
32
+ setIsNftConnected,
33
+ }: ContractConfigProps) {
34
+ const [isLoadingMnn, setIsLoadingMnn] = useState(false);
35
+ const [isLoadingNft, setIsLoadingNft] = useState(false);
36
+ const [mnnInfo, setMnnInfo] = useState<{ inputs: number; hidden: number; outputs: number } | null>(null);
37
+ const [nftInfo, setNftInfo] = useState<{ totalSupply: number; width: number; height: number } | null>(null);
38
+ const publicClient = usePublicClient({ chainId: arbitrumSepolia.id });
39
+
40
+ const handleConnectMnn = async () => {
41
+ if (!mnnAddress || !publicClient) {
42
+ alert('Please enter MNN contract address');
43
+ return;
44
+ }
45
+
46
+ setIsLoadingMnn(true);
47
+
48
+ try {
49
+ const result = await publicClient.readContract({
50
+ address: mnnAddress as `0x${string}`,
51
+ abi: MNN_ABI as any,
52
+ functionName: 'getNetworkInfo',
53
+ args: [], // Added empty args
54
+ });
55
+
56
+ const [inputs, hidden, outputs] = result as [bigint, bigint, bigint];
57
+
58
+ setMnnInfo({
59
+ inputs: Number(inputs),
60
+ hidden: Number(hidden),
61
+ outputs: Number(outputs),
62
+ });
63
+
64
+ setIsMnnConnected(true);
65
+ } catch (error) {
66
+ console.error('MNN connection failed:', error);
67
+ alert('Failed to connect to MNN contract. Please check the address.');
68
+ setIsMnnConnected(false);
69
+ } finally {
70
+ setIsLoadingMnn(false);
71
+ }
72
+ };
73
+
74
+ const handleConnectNft = async () => {
75
+ if (!nftAddress || !publicClient) {
76
+ alert('Please enter NFT contract address');
77
+ return;
78
+ }
79
+
80
+ setIsLoadingNft(true);
81
+
82
+ try {
83
+ const totalSupply = await publicClient.readContract({
84
+ address: nftAddress as `0x${string}`,
85
+ abi: RAY_TRACING_ABI as any,
86
+ functionName: 'totalSupply',
87
+ args: [], // Added empty args
88
+ });
89
+
90
+ const resolution = await publicClient.readContract({
91
+ address: nftAddress as `0x${string}`,
92
+ abi: RAY_TRACING_ABI as any,
93
+ functionName: 'getResolution',
94
+ args: [], // Added empty args
95
+ });
96
+
97
+ const [width, height] = resolution as [bigint, bigint];
98
+
99
+ setNftInfo({
100
+ totalSupply: Number(totalSupply as bigint),
101
+ width: Number(width),
102
+ height: Number(height),
103
+ });
104
+
105
+ setIsNftConnected(true);
106
+ } catch (error) {
107
+ console.error('NFT connection failed:', error);
108
+ alert('Failed to connect to NFT contract. Please check the address.');
109
+ setIsNftConnected(false);
110
+ } finally {
111
+ setIsLoadingNft(false);
112
+ }
113
+ };
114
+
115
+ return (
116
+ <Card>
117
+ <CardHeader>
118
+ <CardTitle>Contract Configuration</CardTitle>
119
+ <CardDescription>
120
+ Connect to deployed MNN and Ray Tracing contracts
121
+ </CardDescription>
122
+ </CardHeader>
123
+ <CardContent className="space-y-6">
124
+ {/* MNN Contract */}
125
+ <div className="space-y-3">
126
+ <h4 className="text-sm font-semibold">Mini Neural Network (MNN)</h4>
127
+ <div className="space-y-2">
128
+ <Label htmlFor="mnn-address">Contract Address</Label>
129
+ <Input
130
+ id="mnn-address"
131
+ placeholder="0x..."
132
+ value={mnnAddress}
133
+ onChange={(e) => setMnnAddress(e.target.value)}
134
+ disabled={isLoadingMnn}
135
+ />
136
+ </div>
137
+
138
+ <Button
139
+ onClick={handleConnectMnn}
140
+ disabled={isLoadingMnn || !mnnAddress}
141
+ className="w-full"
142
+ size="sm"
143
+ >
144
+ {isLoadingMnn ? (
145
+ <>
146
+ <Loader2 className="h-4 w-4 mr-2 animate-spin" />
147
+ Connecting...
148
+ </>
149
+ ) : (
150
+ <>
151
+ {isMnnConnected ? (
152
+ <CheckCircle2 className="h-4 w-4 mr-2" />
153
+ ) : (
154
+ <XCircle className="h-4 w-4 mr-2" />
155
+ )}
156
+ {isMnnConnected ? 'Connected' : 'Connect MNN'}
157
+ </>
158
+ )}
159
+ </Button>
160
+
161
+ {isMnnConnected && mnnInfo && (
162
+ <div className="bg-muted p-3 rounded-md text-xs space-y-1">
163
+ <div className="flex justify-between">
164
+ <span className="text-muted-foreground">Architecture:</span>
165
+ <span className="font-mono">{mnnInfo.inputs}→{mnnInfo.hidden}→{mnnInfo.outputs}</span>
166
+ </div>
167
+ <div className="flex justify-between">
168
+ <span className="text-muted-foreground">Status:</span>
169
+ <span className="text-green-500">✓ Ready</span>
170
+ </div>
171
+ </div>
172
+ )}
173
+ </div>
174
+
175
+ {/* NFT Contract */}
176
+ <div className="space-y-3">
177
+ <h4 className="text-sm font-semibold">Ray Tracing NFT</h4>
178
+ <div className="space-y-2">
179
+ <Label htmlFor="nft-address">Contract Address</Label>
180
+ <Input
181
+ id="nft-address"
182
+ placeholder="0x..."
183
+ value={nftAddress}
184
+ onChange={(e) => setNftAddress(e.target.value)}
185
+ disabled={isLoadingNft}
186
+ />
187
+ </div>
188
+
189
+ <Button
190
+ onClick={handleConnectNft}
191
+ disabled={isLoadingNft || !nftAddress}
192
+ className="w-full"
193
+ size="sm"
194
+ >
195
+ {isLoadingNft ? (
196
+ <>
197
+ <Loader2 className="h-4 w-4 mr-2 animate-spin" />
198
+ Connecting...
199
+ </>
200
+ ) : (
201
+ <>
202
+ {isNftConnected ? (
203
+ <CheckCircle2 className="h-4 w-4 mr-2" />
204
+ ) : (
205
+ <XCircle className="h-4 w-4 mr-2" />
206
+ )}
207
+ {isNftConnected ? 'Connected' : 'Connect NFT'}
208
+ </>
209
+ )}
210
+ </Button>
211
+
212
+ {isNftConnected && nftInfo && (
213
+ <div className="bg-muted p-3 rounded-md text-xs space-y-1">
214
+ <div className="flex justify-between">
215
+ <span className="text-muted-foreground">Resolution:</span>
216
+ <span className="font-mono">{nftInfo.width}×{nftInfo.height}</span>
217
+ </div>
218
+ <div className="flex justify-between">
219
+ <span className="text-muted-foreground">Total Minted:</span>
220
+ <span>{nftInfo.totalSupply}</span>
221
+ </div>
222
+ <div className="flex justify-between">
223
+ <span className="text-muted-foreground">Status:</span>
224
+ <span className="text-green-500">✓ Ready</span>
225
+ </div>
226
+ </div>
227
+ )}
228
+ </div>
229
+
230
+ {/* Quick Start Guide */}
231
+ {!isMnnConnected && !isNftConnected && (
232
+ <div className="bg-blue-500/10 border border-blue-500/20 p-3 rounded-md text-sm text-blue-400">
233
+ <p className="font-medium mb-1">Quick Start:</p>
234
+ <ol className="list-decimal list-inside space-y-1 text-xs">
235
+ <li>Load templates in IDE (MNN + Ray Tracing)</li>
236
+ <li>Compile both contracts</li>
237
+ <li>Deploy to Arbitrum Sepolia</li>
238
+ <li>Paste addresses here</li>
239
+ </ol>
240
+ </div>
241
+ )}
242
+ </CardContent>
243
+ </Card>
244
+ );
245
+ }