package rest import ( "fmt" "net/http" "strings" ) // SetupRoutes sets up all API routes func (s *Server) SetupRoutes(mux *http.ServeMux) { // Block routes mux.HandleFunc("/api/v1/blocks", s.handleListBlocks) mux.HandleFunc("/api/v1/blocks/", s.handleBlockDetail) // Transaction routes mux.HandleFunc("/api/v1/transactions", s.handleListTransactions) mux.HandleFunc("/api/v1/transactions/", s.handleTransactionDetail) // Address routes mux.HandleFunc("/api/v1/addresses", s.handleListAddresses) mux.HandleFunc("/api/v1/addresses/", s.handleAddressDetail) // Search route mux.HandleFunc("/api/v1/search", s.handleSearch) // Stats route mux.HandleFunc("/api/v2/stats", s.handleStats) // Etherscan-compatible API route mux.HandleFunc("/api", s.handleEtherscanAPI) // Health check mux.HandleFunc("/health", s.handleHealth) // MetaMask / dual-chain config (Chain 138 + Ethereum Mainnet) mux.HandleFunc("/api/config/networks", s.handleConfigNetworks) mux.HandleFunc("/api/config/token-list", s.handleConfigTokenList) // Feature flags endpoint mux.HandleFunc("/api/v1/features", s.handleFeatures) // Explorer AI endpoints mux.HandleFunc("/api/v1/ai/context", s.handleAIContext) mux.HandleFunc("/api/v1/ai/chat", s.handleAIChat) mux.HandleFunc("/api/v1/ai/metrics", s.handleAIMetrics) // Route decision tree proxy mux.HandleFunc("/api/v1/routes/tree", s.handleRouteDecisionTree) mux.HandleFunc("/api/v1/routes/depth", s.handleRouteDepth) // Auth endpoints mux.HandleFunc("/api/v1/auth/nonce", s.handleAuthNonce) mux.HandleFunc("/api/v1/auth/wallet", s.handleAuthWallet) // Track 1 routes (public, optional auth) // Note: Track 1 endpoints should be registered with OptionalAuth middleware // mux.HandleFunc("/api/v1/track1/blocks/latest", s.track1Server.handleLatestBlocks) // mux.HandleFunc("/api/v1/track1/txs/latest", s.track1Server.handleLatestTransactions) // mux.HandleFunc("/api/v1/track1/block/", s.track1Server.handleBlockDetail) // mux.HandleFunc("/api/v1/track1/tx/", s.track1Server.handleTransactionDetail) // mux.HandleFunc("/api/v1/track1/address/", s.track1Server.handleAddressBalance) // mux.HandleFunc("/api/v1/track1/bridge/status", s.track1Server.handleBridgeStatus) // Track 2 routes (require Track 2+) // Note: Track 2 endpoints should be registered with RequireAuth + RequireTrack(2) middleware // mux.HandleFunc("/api/v1/track2/address/", s.track2Server.handleAddressTransactions) // mux.HandleFunc("/api/v1/track2/token/", s.track2Server.handleTokenInfo) // mux.HandleFunc("/api/v1/track2/search", s.track2Server.handleSearch) // Track 3 routes (require Track 3+) // Note: Track 3 endpoints should be registered with RequireAuth + RequireTrack(3) middleware // mux.HandleFunc("/api/v1/track3/analytics/flows", s.track3Server.handleFlows) // mux.HandleFunc("/api/v1/track3/analytics/bridge", s.track3Server.handleBridge) // mux.HandleFunc("/api/v1/track3/analytics/token-distribution/", s.track3Server.handleTokenDistribution) // mux.HandleFunc("/api/v1/track3/analytics/address-risk/", s.track3Server.handleAddressRisk) // Track 4 routes (require Track 4) // Note: Track 4 endpoints should be registered with RequireAuth + RequireTrack(4) + IP whitelist middleware // mux.HandleFunc("/api/v1/track4/operator/bridge/events", s.track4Server.handleBridgeEvents) // mux.HandleFunc("/api/v1/track4/operator/validators", s.track4Server.handleValidators) // mux.HandleFunc("/api/v1/track4/operator/contracts", s.track4Server.handleContracts) // mux.HandleFunc("/api/v1/track4/operator/protocol-state", s.track4Server.handleProtocolState) } // handleBlockDetail handles GET /api/v1/blocks/{chain_id}/{number} or /api/v1/blocks/{chain_id}/hash/{hash} func (s *Server) handleBlockDetail(w http.ResponseWriter, r *http.Request) { if !s.requireDB(w) { return } path := strings.TrimPrefix(r.URL.Path, "/api/v1/blocks/") parts := strings.Split(path, "/") if len(parts) < 2 { writeValidationError(w, fmt.Errorf("invalid block path")) return } // Validate chain ID if err := validateChainID(parts[0], s.chainID); err != nil { writeValidationError(w, err) return } if parts[1] == "hash" && len(parts) == 3 { // Validate hash format if !isValidHash(parts[2]) { writeValidationError(w, ErrInvalidHash) return } // Get by hash s.handleGetBlockByHash(w, r, parts[2]) } else { // Validate and parse block number blockNumber, err := validateBlockNumber(parts[1]) if err != nil { writeValidationError(w, err) return } s.handleGetBlockByNumber(w, r, blockNumber) } } // handleGetBlockByNumber and handleGetBlockByHash are in blocks.go // handleTransactionDetail handles GET /api/v1/transactions/{chain_id}/{hash} func (s *Server) handleTransactionDetail(w http.ResponseWriter, r *http.Request) { if !s.requireDB(w) { return } path := strings.TrimPrefix(r.URL.Path, "/api/v1/transactions/") parts := strings.Split(path, "/") if len(parts) < 2 { writeValidationError(w, fmt.Errorf("invalid transaction path")) return } // Validate chain ID if err := validateChainID(parts[0], s.chainID); err != nil { writeValidationError(w, err) return } // Validate hash format hash := parts[1] if !isValidHash(hash) { writeValidationError(w, ErrInvalidHash) return } s.handleGetTransactionByHash(w, r, hash) } // handleGetTransactionByHash is implemented in transactions.go // handleAddressDetail handles GET /api/v1/addresses/{chain_id}/{address} func (s *Server) handleAddressDetail(w http.ResponseWriter, r *http.Request) { if !s.requireDB(w) { return } path := strings.TrimPrefix(r.URL.Path, "/api/v1/addresses/") parts := strings.Split(path, "/") if len(parts) < 2 { writeValidationError(w, fmt.Errorf("invalid address path")) return } // Validate chain ID if err := validateChainID(parts[0], s.chainID); err != nil { writeValidationError(w, err) return } // Validate address format address := parts[1] if !isValidAddress(address) { writeValidationError(w, ErrInvalidAddress) return } // Set address in query and call handler r.URL.RawQuery = "address=" + address s.handleGetAddress(w, r) }