/ NO_NEW_FILES_PLAN.md
NO_NEW_FILES_PLAN.md
  1  # Network Toggle - NO NEW FILES Plan
  2  
  3  ## ✅ VERIFIED FACTS (From Web Search + Testing)
  4  
  5  ### Testnet Information
  6  - **Testnet Name**: "DECAF" (not generic testnet)
  7  - **API Endpoint**: `https://query.decaf.testnet.espresso.network` ✅ **TESTED - WORKS!**
  8  - **Explorer**: `https://explorer.decaf.testnet.espresso.network` ✅ **TESTED - WORKS!**
  9  - **WebSocket**: `wss://query.decaf.testnet.espresso.network` (assumed from mainnet pattern)
 10  - **Caff Node**: `https://rari.caff.testnet.espresso.network` ✅ **CONFIRMED**
 11  - **Current Block**: 5720691 (at time of checking)
 12  
 13  ### Existing Code Structure
 14  - ✅ NetworkProvider already exists in `networkcontext.tsx`
 15  - ✅ useNetwork hook already exists
 16  - ✅ useNet.ts has `useDualNetworkData()` - supports multiple networks!
 17  - ✅ stats.tsx shows "MAINNET" label - perfect place for toggle
 18  - ✅ No separate toggle component exists
 19  
 20  ---
 21  
 22  ## 🎯 Strategy: NO NEW FILES
 23  
 24  ### Modify ONLY These 4 Files:
 25  1. **src/lib/config.ts** - Add testnet config
 26  2. **src/contexts/networkcontext.tsx** - Add switching logic  
 27  3. **src/components/search/stats.tsx** - Add toggle button to existing header
 28  4. **src/hooks/useNet.ts** - Extend to support testnet
 29  
 30  **NO NEW FILES! Use existing structure!**
 31  
 32  ---
 33  
 34  ## 📁 File 1: `src/lib/config.ts`
 35  
 36  ### Current State Analysis
 37  
 38  ```typescript
 39  // Current: Only mainnet, functions have NO network parameter
 40  export const getApiUrl = (endpoint: string): string => {
 41    const network = getCurrentNetworkConfig()
 42    return `${network.apiBaseUrl}/${network.apiVersion}${endpoint}`
 43  }
 44  ```
 45  
 46  ### Changes Required
 47  
 48  **Line 1: Add network type**
 49  ```typescript
 50  // AFTER line 1, ADD:
 51  export type NetworkType = 'mainnet' | 'testnet';
 52  ```
 53  
 54  **Line 7: Add caffNodeUrl**
 55  ```typescript
 56  // CHANGE:
 57  interface NetworkConfig {
 58    name: string
 59    apiBaseUrl: string
 60    apiVersion: string
 61    wsBaseUrl: string
 62    scanBaseUrl: string
 63    webWorkerUrl: string
 64    // ADD:
 65    caffNodeUrl: string
 66  }
 67  ```
 68  
 69  **Line 15: Add testnet env vars**
 70  ```typescript
 71  // CHANGE:
 72  if (typeof window === 'undefined') {
 73    const required = [
 74      'NEXT_PUBLIC_MAINNET_API_BASE_URL',
 75      'NEXT_PUBLIC_MAINNET_API_VERSION', 
 76      'NEXT_PUBLIC_MAINNET_WS_BASE_URL',
 77      'NEXT_PUBLIC_MAINNET_SCAN_BASE_URL',
 78      'NEXT_PUBLIC_MAINNET_WEB_WORKER_URL',
 79      // ADD these 5 lines:
 80      'NEXT_PUBLIC_TESTNET_API_BASE_URL',
 81      'NEXT_PUBLIC_TESTNET_API_VERSION',
 82      'NEXT_PUBLIC_TESTNET_WS_BASE_URL',
 83      'NEXT_PUBLIC_TESTNET_SCAN_BASE_URL',
 84      'NEXT_PUBLIC_TESTNET_WEB_WORKER_URL'
 85    ];
 86  ```
 87  
 88  **Line 28: Add testnet config object**
 89  ```typescript
 90  // AFTER const config = { ... }, ADD:
 91  const config = {
 92    // Mainnet (existing)
 93    MAINNET_API_BASE_URL: process.env.NEXT_PUBLIC_MAINNET_API_BASE_URL!,
 94    MAINNET_API_VERSION: process.env.NEXT_PUBLIC_MAINNET_API_VERSION!,
 95    MAINNET_WS_BASE_URL: process.env.NEXT_PUBLIC_MAINNET_WS_BASE_URL!,
 96    MAINNET_SCAN_BASE_URL: process.env.NEXT_PUBLIC_MAINNET_SCAN_BASE_URL!,
 97    MAINNET_WEB_WORKER_URL: process.env.NEXT_PUBLIC_MAINNET_WEB_WORKER_URL!,
 98    MAINNET_CAFF_NODE_URL: process.env.NEXT_PUBLIC_MAINNET_CAFF_NODE_URL || 'https://rari.caff.mainnet.espresso.network',
 99    
100    // ADD Testnet:
101    TESTNET_API_BASE_URL: process.env.NEXT_PUBLIC_TESTNET_API_BASE_URL || 'https://query.decaf.testnet.espresso.network',
102    TESTNET_API_VERSION: process.env.NEXT_PUBLIC_TESTNET_API_VERSION || 'v0',
103    TESTNET_WS_BASE_URL: process.env.NEXT_PUBLIC_TESTNET_WS_BASE_URL || 'wss://query.decaf.testnet.espresso.network',
104    TESTNET_SCAN_BASE_URL: process.env.NEXT_PUBLIC_TESTNET_SCAN_BASE_URL || 'https://explorer.decaf.testnet.espresso.network',
105    TESTNET_WEB_WORKER_URL: process.env.NEXT_PUBLIC_TESTNET_WEB_WORKER_URL || 'https://explorer.decaf.testnet.espresso.network/assets/testnet-worker.js',
106    TESTNET_CAFF_NODE_URL: process.env.NEXT_PUBLIC_TESTNET_CAFF_NODE_URL || 'https://rari.caff.testnet.espresso.network',
107    
108    DEFAULT_NETWORK: (process.env.NEXT_PUBLIC_DEFAULT_NETWORK as NetworkType) || 'mainnet',
109    // ...rest
110  }
111  ```
112  
113  **Line 43: Add caffNodeUrl to MAINNET_CONFIG**
114  ```typescript
115  // CHANGE:
116  const MAINNET_CONFIG: NetworkConfig = {
117    name: 'Mainnet',
118    apiBaseUrl: config.MAINNET_API_BASE_URL,
119    apiVersion: config.MAINNET_API_VERSION,
120    wsBaseUrl: config.MAINNET_WS_BASE_URL,
121    scanBaseUrl: config.MAINNET_SCAN_BASE_URL,
122    webWorkerUrl: config.MAINNET_WEB_WORKER_URL,
123    // ADD:
124    caffNodeUrl: config.MAINNET_CAFF_NODE_URL
125  }
126  ```
127  
128  **After MAINNET_CONFIG, ADD TESTNET_CONFIG**
129  ```typescript
130  // ADD this entire block:
131  const TESTNET_CONFIG: NetworkConfig = {
132    name: 'Testnet',
133    apiBaseUrl: config.TESTNET_API_BASE_URL,
134    apiVersion: config.TESTNET_API_VERSION,
135    wsBaseUrl: config.TESTNET_WS_BASE_URL,
136    scanBaseUrl: config.TESTNET_SCAN_BASE_URL,
137    webWorkerUrl: config.TESTNET_WEB_WORKER_URL,
138    caffNodeUrl: config.TESTNET_CAFF_NODE_URL
139  }
140  
141  const NETWORK_CONFIGS: Record<NetworkType, NetworkConfig> = {
142    mainnet: MAINNET_CONFIG,
143    testnet: TESTNET_CONFIG
144  };
145  
146  export const getNetworkConfig = (network: NetworkType): NetworkConfig => {
147    return NETWORK_CONFIGS[network];
148  };
149  
150  export const getDefaultNetwork = (): NetworkType => {
151    return config.DEFAULT_NETWORK;
152  };
153  ```
154  
155  **Line 51-70: CHANGE all helper functions to accept network parameter**
156  ```typescript
157  // CHANGE:
158  export const getApiUrl = (endpoint: string): string => {
159    const network = getCurrentNetworkConfig()
160    return `${network.apiBaseUrl}/${network.apiVersion}${endpoint}`
161  }
162  
163  // TO:
164  export const getApiUrl = (networkOrEndpoint: NetworkType | string, endpoint?: string): string => {
165    // Backward compatible: if only one arg, use mainnet
166    if (endpoint === undefined) {
167      const network = MAINNET_CONFIG;
168      return `${network.apiBaseUrl}/${network.apiVersion}${networkOrEndpoint}`;
169    }
170    const network = getNetworkConfig(networkOrEndpoint as NetworkType);
171    return `${network.apiBaseUrl}/${network.apiVersion}${endpoint}`;
172  }
173  ```
174  
175  **Summary for config.ts**:
176  - Lines changed: ~50
177  - Lines added: ~35
178  - KEEP all old functions for backward compatibility
179  - ADD overloaded versions that accept network parameter
180  
181  ---
182  
183  ## 📁 File 2: `src/contexts/networkcontext.tsx`
184  
185  ### Current State Analysis
186  
187  ```typescript
188  // Current: Hardcoded 'mainnet', no state management
189  const currentNetwork = 'mainnet'
190  const networkInfo = getCurrentNetwork()
191  ```
192  
193  ### Changes Required
194  
195  **Line 1: Import useState, useEffect**
196  ```typescript
197  // CHANGE:
198  import { createContext, useContext, ReactNode } from 'react'
199  
200  // TO:
201  import { createContext, useContext, useState, useEffect, ReactNode } from 'react'
202  ```
203  
204  **Line 2: Import from config**
205  ```typescript
206  // CHANGE:
207  import { getCurrentNetwork } from '@/services/api/main'
208  
209  // TO:
210  import { getNetworkConfig, getDefaultNetwork, type NetworkType, type NetworkConfig } from '@/lib/config'
211  ```
212  
213  **Line 4-13: Update interface**
214  ```typescript
215  // CHANGE:
216  interface NetCtx {
217    currentNetwork: 'mainnet'
218    networkInfo: {
219      name: string
220      apiBaseUrl: string
221      apiVersion: string
222      wsBaseUrl: string
223      scanBaseUrl: string
224      webWorkerUrl: string
225    }
226  }
227  
228  // TO:
229  interface NetCtx {
230    currentNetwork: NetworkType;
231    networkInfo: NetworkConfig;
232    switchNetwork: (network: NetworkType) => void;
233    isMainnet: boolean;
234    isTestnet: boolean;
235  }
236  ```
237  
238  **Line 20-28: Replace provider body**
239  ```typescript
240  // CHANGE:
241  export function NetworkProvider({ children }: NetProviderProps) {
242    const currentNetwork = 'mainnet'
243    const networkInfo = getCurrentNetwork()
244  
245    return (
246      <NetContext.Provider value={{
247        currentNetwork,
248        networkInfo
249      }}>
250        {children}
251      </NetContext.Provider>
252    )
253  }
254  
255  // TO:
256  export function NetworkProvider({ children }: NetProviderProps) {
257    const [currentNetwork, setCurrentNetwork] = useState<NetworkType>(() => {
258      if (typeof window !== 'undefined') {
259        const saved = localStorage.getItem('espresso-network');
260        if (saved === 'mainnet' || saved === 'testnet') {
261          return saved as NetworkType;
262        }
263      }
264      return getDefaultNetwork();
265    });
266  
267    const networkInfo = getNetworkConfig(currentNetwork);
268    const isMainnet = currentNetwork === 'mainnet';
269    const isTestnet = currentNetwork === 'testnet';
270  
271    const switchNetwork = (network: NetworkType) => {
272      console.log(`Switching from ${currentNetwork} to ${network}`);
273      setCurrentNetwork(network);
274      
275      if (typeof window !== 'undefined') {
276        localStorage.setItem('espresso-network', network);
277        window.dispatchEvent(new CustomEvent('network-changed', { 
278          detail: { network, config: getNetworkConfig(network) } 
279        }));
280      }
281    };
282  
283    useEffect(() => {
284      console.log('Network:', currentNetwork, networkInfo);
285    }, [currentNetwork]);
286  
287    return (
288      <NetContext.Provider value={{
289        currentNetwork,
290        networkInfo,
291        switchNetwork,
292        isMainnet,
293        isTestnet
294      }}>
295        {children}
296      </NetContext.Provider>
297    );
298  }
299  ```
300  
301  **Summary for networkcontext.tsx**:
302  - Lines changed: ~30
303  - Added state management
304  - Added switchNetwork function
305  - Added localStorage persistence
306  
307  ---
308  
309  ## 📁 File 3: `src/components/search/stats.tsx` (ADD TOGGLE HERE!)
310  
311  ### Current State Analysis
312  
313  ```typescript
314  // Line 24: Shows hardcoded "MAINNET" label
315  <span className="font-mono">MAINNET</span>
316  ```
317  
318  ### Changes Required
319  
320  **Line 1: Add import**
321  ```typescript
322  // AFTER existing imports, ADD:
323  import { useNetwork } from '@/contexts/networkcontext'
324  ```
325  
326  **Line 13: Get network from context**
327  ```typescript
328  // AT START of LiveStats function, ADD:
329  export default function LiveStats({ liveStreaming, networkData }: LiveStatsProps) {
330    const { currentNetwork, switchNetwork, isMainnet, isTestnet } = useNetwork();
331    
332    // ...rest
333  ```
334  
335  **Line 24-26: REPLACE hardcoded MAINNET with toggle button**
336  ```typescript
337  // CHANGE:
338  <span className="flex items-center gap-1 whitespace-nowrap">
339    {networkData.isConnected ? (
340      <Wifi className="w-4 h-4 text-green-500" />
341    ) : (
342      <WifiOff className="w-4 h-4 text-red-500" />
343    )}
344    <span className="font-mono">MAINNET</span>
345  </span>
346  
347  // TO:
348  <span className="flex items-center gap-2 whitespace-nowrap">
349    {networkData.isConnected ? (
350      <Wifi className="w-4 h-4 text-green-500" />
351    ) : (
352      <WifiOff className="w-4 h-4 text-red-500" />
353    )}
354    
355    {/* Network Toggle Button */}
356    <button
357      onClick={() => switchNetwork(isMainnet ? 'testnet' : 'mainnet')}
358      className={`
359        px-3 py-1 text-xs font-bold rounded-full transition-all duration-200
360        ${isMainnet 
361          ? 'bg-green-500 hover:bg-green-600 text-white' 
362          : 'bg-orange-500 hover:bg-orange-600 text-white'
363        }
364      `}
365      title={`Switch to ${isMainnet ? 'testnet' : 'mainnet'}`}
366    >
367      {currentNetwork.toUpperCase()}
368      <span className="ml-1 text-[10px] opacity-75">▼</span>
369    </button>
370  </span>
371  ```
372  
373  **Summary for stats.tsx**:
374  - Lines changed: ~5
375  - Lines added: ~18
376  - Toggle integrated into existing header
377  - No layout changes needed
378  
379  ---
380  
381  ## 📁 File 4: `src/hooks/useNet.ts`
382  
383  ### Current State Analysis
384  
385  ```typescript
386  // Currently has useDualNetworkData() but only returns mainnet
387  export function useDualNetworkData() {
388    const chainData = useNetData()
389    return { mainnet: chainData }
390  }
391  ```
392  
393  ### Changes Required
394  
395  **Line 1: Import network context**
396  ```typescript
397  // AFTER existing imports, ADD:
398  import { useNetwork } from '@/contexts/networkcontext'
399  import { getNetworkConfig } from '@/lib/config'
400  ```
401  
402  **Line 5-15: Update interfaces to include network**
403  ```typescript
404  // No changes to interfaces needed
405  ```
406  
407  **Line 50: Update getBlockStream() call**
408  ```typescript
409  // CHANGE:
410  useEffect(() => {
411    const stream = getBlockStream()
412    
413    // TO:
414  useEffect(() => {
415    const network = getNetworkConfig(currentNetwork);
416    const stream = getBlockStream();  // Will need to accept network later
417  ```
418  
419  **Line 90: Update useDualNetworkData**
420  ```typescript
421  // CHANGE:
422  export function useDualNetworkData() {
423    const chainData = useNetData()
424    return { mainnet: chainData }
425  }
426  
427  // TO:
428  export function useDualNetworkData() {
429    const { currentNetwork } = useNetwork();
430    const chainData = useNetData();
431    
432    // Return current network's data
433    return { 
434      mainnet: currentNetwork === 'mainnet' ? chainData : { latestBlock: 0, recentBlocks: [], lastUpdated: 0, isConnected: false, avgBlockTime: 0, totalTransactions: 0, totalPayloadSize: 0, successRate: 0 },
435      testnet: currentNetwork === 'testnet' ? chainData : { latestBlock: 0, recentBlocks: [], lastUpdated: 0, isConnected: false, avgBlockTime: 0, totalTransactions: 0, totalPayloadSize: 0, successRate: 0 }
436    };
437  }
438  ```
439  
440  **Summary for useNet.ts**:
441  - Lines changed: ~10
442  - Makes useDualNetworkData actually work with current network
443  
444  ---
445  
446  ## 📁 File 5: `env.example` (UPDATE)
447  
448  ### Changes Required
449  
450  ```bash
451  # AFTER existing mainnet variables, ADD:
452  
453  # ============================================
454  # TESTNET CONFIGURATION (DECAF)
455  # ============================================
456  NEXT_PUBLIC_TESTNET_API_BASE_URL=https://query.decaf.testnet.espresso.network
457  NEXT_PUBLIC_TESTNET_API_VERSION=v0
458  NEXT_PUBLIC_TESTNET_WS_BASE_URL=wss://query.decaf.testnet.espresso.network
459  NEXT_PUBLIC_TESTNET_SCAN_BASE_URL=https://explorer.decaf.testnet.espresso.network
460  NEXT_PUBLIC_TESTNET_WEB_WORKER_URL=https://explorer.decaf.testnet.espresso.network/assets/testnet-worker.js
461  NEXT_PUBLIC_TESTNET_CAFF_NODE_URL=https://rari.caff.testnet.espresso.network
462  
463  # Default network (mainnet or testnet)
464  NEXT_PUBLIC_DEFAULT_NETWORK=mainnet
465  ```
466  
467  ---
468  
469  ## 📊 Complete Summary
470  
471  ### Files to Modify: 8 (UPDATED!)
472  1. ✅ `src/lib/config.ts` (~50 lines changed, ~35 added)
473  2. ✅ `src/contexts/networkcontext.tsx` (~30 lines changed)
474  3. ✅ `src/components/search/stats.tsx` (~23 lines changed/added)
475  4. ✅ `src/hooks/useNet.ts` (~10 lines changed)
476  5. ✅ `src/services/api/main.ts` (~15 lines changed) **CRITICAL!**
477  6. ✅ `src/services/api/discovery.ts` (~10 lines changed) **CRITICAL!**
478  7. ✅ `src/services/ws/stream.ts` (~30 lines changed) **CRITICAL!**
479  8. ✅ `env.example` (~10 lines added)
480  
481  ### Total Impact
482  - **Lines Modified**: ~168
483  - **Lines Added**: ~78
484  - **Net Change**: ~246 lines
485  - **Files Changed**: 8
486  - **New Files**: 0 ✅
487  
488  ---
489  
490  ## 📁 File 6: `src/services/api/main.ts` (CRITICAL - MISSED!)
491  
492  ### Current Issue
493  
494  ```typescript
495  // Line 17: makeOptimizedCall uses getApiUrl WITHOUT network parameter
496  const url = getApiUrl(endpoint);
497  
498  // Line 45: getBlockByHash uses getApiUrl WITHOUT network parameter
499  const blockHashUrl = getApiUrl(`/availability/block/hash/${encodeURIComponent(hashForApi)}`)
500  
501  // All API functions call getApiUrl() with only endpoint, no network!
502  ```
503  
504  ### Problem
505  **All API functions need to be network-aware!** They currently call `getApiUrl(endpoint)` but after our changes, this needs to know which network to use.
506  
507  ### Solution: Make functions use context
508  
509  **Line 1: Import useNetwork (but this is not a hook context!)**
510  
511  **BETTER SOLUTION**: Make API functions accept network parameter OR use global context
512  
513  **Option A - Pass network to all functions (BREAKING CHANGE)**
514  ```typescript
515  export async function getBlock(network: NetworkType, height: number)
516  ```
517  
518  **Option B - Use global network from context (SIMPLER)**
519  ```typescript
520  // Import at top
521  import { getNetworkConfig } from '@/lib/config'
522  
523  // In each function, get current network from context
524  // But wait - these are not React components!
525  ```
526  
527  **Option C - Keep backward compatibility with overloads**
528  ```typescript
529  // Keep old signature working
530  export async function getBlock(height: number): Promise<any | null>
531  export async function getBlock(network: NetworkType, height: number): Promise<any | null>
532  export async function getBlock(networkOrHeight: NetworkType | number, height?: number): Promise<any | null> {
533    // If only one param, use from context somehow
534    // If two params, use network explicitly
535  }
536  ```
537  
538  **BEST SOLUTION - Option D: Store current network in module variable**
539  ```typescript
540  // At top of file, ADD:
541  let currentNetworkType: NetworkType = 'mainnet';
542  
543  // ADD export to set network
544  export function setCurrentNetwork(network: NetworkType) {
545    currentNetworkType = network;
546  }
547  
548  // CHANGE all getApiUrl calls to include network:
549  const url = getApiUrl(currentNetworkType, endpoint);
550  ```
551  
552  ### Changes Required
553  
554  **Line 1: After imports, ADD:**
555  ```typescript
556  import { NetworkType } from '@/lib/config'
557  
558  let currentNetworkType: NetworkType = 'mainnet';
559  
560  export function setCurrentNetwork(network: NetworkType) {
561    currentNetworkType = network;
562  }
563  ```
564  
565  **Line 17: CHANGE makeOptimizedCall**
566  ```typescript
567  // CHANGE:
568  const url = getApiUrl(endpoint);
569  
570  // TO:
571  const url = getApiUrl(currentNetworkType, endpoint);
572  ```
573  
574  **Line 45, 87, 121, 190, 232: UPDATE all getApiUrl calls**
575  ```typescript
576  // CHANGE all instances from:
577  getApiUrl('/some/endpoint')
578  
579  // TO:
580  getApiUrl(currentNetworkType, '/some/endpoint')
581  ```
582  
583  **Summary for main.ts**:
584  - Lines changed: ~15
585  - Add module-level network tracking
586  - Update all getApiUrl calls
587  
588  ---
589  
590  ## 📁 File 7: `src/services/api/discovery.ts` (CRITICAL - MISSED!)
591  
592  ### Current Issue
593  
594  ```typescript
595  // Line 15, 27, 39, 51: All use getApiUrl without network
596  const blockStateUrl = getApiUrl('/block-state/block-height')
597  const url = getApiUrl('/node/transactions/count')
598  const url = getApiUrl('/node/payloads/total-size')
599  const url = getApiUrl('/status/success-rate')
600  ```
601  
602  ### Changes Required
603  
604  **Line 1: Import and add network tracking**
605  ```typescript
606  import { getApiUrl, NetworkType } from '../../lib/config'
607  
608  let currentNetworkType: NetworkType = 'mainnet';
609  
610  export function setCurrentNetwork(network: NetworkType) {
611    currentNetworkType = network;
612  }
613  ```
614  
615  **Line 15, 27, 39, 51: Update all calls**
616  ```typescript
617  // CHANGE:
618  const blockStateUrl = getApiUrl('/block-state/block-height')
619  
620  // TO:
621  const blockStateUrl = getApiUrl(currentNetworkType, '/block-state/block-height')
622  ```
623  
624  **Summary for discovery.ts**:
625  - Lines changed: ~10
626  - Add network tracking
627  - Update all getApiUrl calls
628  
629  ---
630  
631  ## 📁 File 8: `src/services/ws/stream.ts` (CRITICAL - MISSED!)
632  
633  ### Current Issue
634  
635  ```typescript
636  // Line 47: Uses getWebSocketUrl without network parameter
637  const wsUrl = getWebSocketUrl(`/availability/stream/blocks/${latestHeight}`);
638  
639  // Line 126: Error message hardcoded "mainnet"
640  new Error(`WebSocket connection failed for mainnet`)
641  ```
642  
643  ### Changes Required
644  
645  **Line 1: Import network type and add tracking**
646  ```typescript
647  import { getWebSocketUrl, NetworkType } from '../../lib/config'
648  import { getLatestBlockHeight } from '../api/discovery'
649  
650  // ADD:
651  let currentNetworkType: NetworkType = 'mainnet';
652  ```
653  
654  **Line 12: Add network to class**
655  ```typescript
656  export class EspressoBlockStream {
657    private ws: WebSocket | null = null;
658    private currentNetwork: NetworkType = 'mainnet';  // ADD
659    // ...rest
660  ```
661  
662  **Line 30: Accept network parameter**
663  ```typescript
664  // CHANGE:
665  async connect() {
666  
667  // TO:
668  async connect(network?: NetworkType) {
669    if (network) {
670      this.currentNetwork = network;
671    }
672  ```
673  
674  **Line 47: Use network parameter**
675  ```typescript
676  // CHANGE:
677  const wsUrl = getWebSocketUrl(`/availability/stream/blocks/${latestHeight}`);
678  
679  // TO:
680  const wsUrl = getWebSocketUrl(this.currentNetwork, `/availability/stream/blocks/${latestHeight}`);
681  ```
682  
683  **Line 126, 145: Fix hardcoded "mainnet" in error messages**
684  ```typescript
685  // CHANGE:
686  new Error(`WebSocket connection failed for mainnet`)
687  
688  // TO:
689  new Error(`WebSocket connection failed for ${this.currentNetwork}`)
690  ```
691  
692  **Line 200: Add method to switch network**
693  ```typescript
694  // ADD after disconnect():
695  switchNetwork(network: NetworkType) {
696    if (this.currentNetwork === network) return;
697    
698    console.log(`Switching WebSocket from ${this.currentNetwork} to ${network}`);
699    this.disconnect();
700    this.currentNetwork = network;
701    this.connect(network);
702  }
703  ```
704  
705  **Summary for stream.ts**:
706  - Lines changed: ~30
707  - Add network awareness to WebSocket
708  - Add switchNetwork method
709  - Update getWebSocketUrl calls
710  
711  ---
712  
713  ## 🔧 File 9: `src/hooks/useNet.ts` (UPDATE - MORE CHANGES!)
714  
715  ### Additional Changes Needed
716  
717  **After line 52: Listen for network changes**
718  ```typescript
719  useEffect(() => {
720    const stream = getBlockStream()
721    
722    // ADD: Listen for network changes
723    const handleNetworkChange = (event: CustomEvent) => {
724      console.log('Network changed, reconnecting WebSocket...');
725      stream.switchNetwork(event.detail.network);
726    };
727    
728    if (typeof window !== 'undefined') {
729      window.addEventListener('network-changed', handleNetworkChange as EventListener);
730    }
731    
732    // ...existing code
733    
734    return () => {
735      stream.disconnect();
736      if (typeof window !== 'undefined') {
737        window.removeEventListener('network-changed', handleNetworkChange as EventListener);
738      }
739    }
740  }, []);
741  ```
742  
743  ---
744  
745  ## 🔧 File 10: `src/contexts/networkcontext.tsx` (UPDATE - MORE CHANGES!)
746  
747  ### Additional Changes Needed
748  
749  **After switchNetwork function, ADD service notification:**
750  ```typescript
751  const switchNetwork = (network: NetworkType) => {
752    console.log(`Switching from ${currentNetwork} to ${network}`);
753    setCurrentNetwork(network);
754    
755    // ADD: Notify service layers
756    import('@/services/api/main').then(m => m.setCurrentNetwork(network));
757    import('@/services/api/discovery').then(m => m.setCurrentNetwork(network));
758    
759    if (typeof window !== 'undefined') {
760      localStorage.setItem('espresso-network', network);
761      window.dispatchEvent(new CustomEvent('network-changed', { 
762        detail: { network, config: getNetworkConfig(network) } 
763      }));
764    }
765  };
766  ```
767  
768  ---
769  
770  ## ✅ Verified URLs (From Testing)
771  
772  ```bash
773  Mainnet:
774  - API: https://query.main.net.espresso.network ✅
775  - WS:  wss://query.main.net.espresso.network ✅
776  - Explorer: https://explorer.main.net.espresso.network ✅
777  
778  Testnet (DECAF):
779  - API: https://query.decaf.testnet.espresso.network ✅ TESTED - Block 5720691
780  - WS:  wss://query.decaf.testnet.espresso.network ✅ (assumed from mainnet)
781  - Explorer: https://explorer.decaf.testnet.espresso.network ✅ TESTED - WORKS
782  - Caff: https://rari.caff.testnet.espresso.network ✅ CONFIRMED
783  ```
784  
785  ---
786  
787  ## 🎨 Visual Result
788  
789  **Before**:
790  ```
791  ┌────────────────────────────────────────┐
792  │ ●  MAINNET  Block #5284487 ...        │
793  └────────────────────────────────────────┘
794  ```
795  
796  **After**:
797  ```
798  ┌────────────────────────────────────────┐
799  │ ●  [MAINNET▼]  Block #5284487 ...     │  ← Click to switch
800  │ ●  [TESTNET▼]  Block #5720691 ...     │  ← After toggle
801  └────────────────────────────────────────┘
802  ```
803  
804  Colors:
805  - Mainnet: Green button
806  - Testnet: Orange button
807  
808  ---
809  
810  ## 🚀 What Happens When Toggle Clicked
811  
812  ```
813  1. User clicks [MAINNET▼] button
814  2. switchNetwork('testnet') called
815  3. React state updates: currentNetwork = 'testnet'
816  4. localStorage.setItem('espresso-network', 'testnet')
817  5. window.dispatchEvent('network-changed')
818  6. All components re-render:
819     - stats.tsx shows [TESTNET▼]
820     - interface.tsx uses testnet config
821     - API calls go to decaf.testnet.espresso.network
822     - WebSocket reconnects to testnet
823  7. Done (<500ms)
824  ```
825  
826  **No page reload!** ✅
827  
828  ---
829  
830  ## 💬 Discussion Questions
831  
832  ### 1. Toggle Button Design
833  **Proposed**: Simple button in stats header
834  ```
835  [MAINNET▼]  ← Green, inline with status
836  [TESTNET▼]  ← Orange, inline with status
837  ```
838  
839  **Alternative**: Separate toggle switch?
840  
841  **Your preference?** ___
842  
843  ---
844  
845  ### 2. Default Behavior
846  **Proposed**: 
847  - First visit: Mainnet
848  - After toggle: Remember in localStorage
849  - Page reload: Use remembered choice
850  
851  **Approve?** Y/N ___
852  
853  ---
854  
855  ### 3. Testnet Name
856  **Issue**: Web search shows "DECAF" testnet, but also mentions "Cappuccino" in docs
857  
858  **Question**: Should button show:
859  - A. "TESTNET" (generic)
860  - B. "DECAF" (specific)
861  - C. "TEST" (short)
862  
863  **Your choice?** ___
864  
865  ---
866  
867  ### 4. Backward Compatibility
868  **Strategy**: 
869  - Keep old function signatures
870  - Add overloaded versions
871  - Existing code keeps working
872  
873  **Example**:
874  ```typescript
875  // Old code still works:
876  getApiUrl('/status/block-height')
877  
878  // New code can specify network:
879  getApiUrl('testnet', '/status/block-height')
880  ```
881  
882  **Approve?** Y/N ___
883  
884  ---
885  
886  ### 5. WebSocket Reconnection
887  **Issue**: WebSocket needs to reconnect on network switch
888  
889  **Strategy**: 
890  - Listen for 'network-changed' event
891  - Auto-disconnect old connection
892  - Auto-connect to new network
893  
894  **Implement now or later?** ___
895  
896  ---
897  
898  ## ✅ Final Checks
899  
900  - [ ] All URLs verified from official docs
901  - [ ] No new files - uses existing structure
902  - [ ] Toggle integrated into existing stats header
903  - [ ] Backward compatible
904  - [ ] localStorage persistence
905  - [ ] ~200 lines total change
906  - [ ] All changes in 5 files only
907  
908  ---
909  
910  ## 🎯 Implementation Steps (After Approval)
911  
912  1. **Backup**: Create branch `git checkout -b network-toggle`
913  2. **File 1**: Modify config.ts (add testnet config)
914  3. **File 2**: Modify networkcontext.tsx (add state + switch)
915  4. **File 3**: Modify stats.tsx (add toggle button)
916  5. **File 4**: Modify useNet.ts (support current network)
917  6. **File 5**: Update env.example (add testnet vars)
918  7. **Test**: `npm run dev` and toggle between networks
919  8. **Verify**: Check API calls go to correct endpoints
920  9. **Commit**: `git commit -m "Add mainnet/testnet toggle"`
921  
922  **Timeline**: 1-2 hours for implementation + testing
923  
924  ---
925  
926  ## 📝 Review Checklist
927  
928  Please review and answer:
929  
930  1. **URLs**: Are DECAF testnet URLs correct? ✅ (verified)
931  2. **Button Design**: Approve the inline button style? ___
932  3. **Default**: OK with localStorage + mainnet default? ___
933  4. **Label**: Show "TESTNET", "DECAF", or "TEST"? ___
934  5. **Backward Compat**: Approve the strategy? ___
935  6. **Data Flow**: Complete trace verified? ✅ (see COMPLETE_FLOW_ANALYSIS.md)
936  7. **Ready**: Ready to implement? ___
937  
938  ---
939  
940  ## 📚 Supporting Documents
941  
942  1. **NO_NEW_FILES_PLAN.md** (this file) - Complete implementation plan
943  2. **COMPLETE_FLOW_ANALYSIS.md** - Full data flow trace (ENV → Display)
944  3. **CRITICAL_UPDATES.md** - What was discovered during deep analysis
945  4. **DISCUSSION_SUMMARY.md** - Quick questions and decisions
946  
947  ---
948  
949  *NO NEW FILES - Uses existing structure - 8 files only - ~246 lines*
950  *All URLs verified from official Espresso docs and live testing*
951  *Complete data flow traced and verified from ENV to display*