- Updated branding from "SolaceScanScout" to "Solace" across various files including deployment scripts, API responses, and documentation. - Changed default base URL for Playwright tests and updated security headers to reflect the new branding. - Enhanced README and API documentation to include new authentication endpoints and product access details. This refactor aligns the project branding and improves clarity in the API documentation.
202 lines
7.0 KiB
Go
202 lines
7.0 KiB
Go
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)
|
|
mux.HandleFunc("/api/config/capabilities", s.handleConfigCapabilities)
|
|
|
|
// 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)
|
|
mux.HandleFunc("/api/v1/auth/register", s.handleAuthRegister)
|
|
mux.HandleFunc("/api/v1/auth/login", s.handleAuthLogin)
|
|
mux.HandleFunc("/api/v1/access/me", s.handleAccessMe)
|
|
mux.HandleFunc("/api/v1/access/products", s.handleAccessProducts)
|
|
mux.HandleFunc("/api/v1/access/subscriptions", s.handleAccessSubscriptions)
|
|
mux.HandleFunc("/api/v1/access/admin/subscriptions", s.handleAccessAdminSubscriptions)
|
|
mux.HandleFunc("/api/v1/access/admin/audit", s.handleAccessAdminAudit)
|
|
mux.HandleFunc("/api/v1/access/internal/validate-key", s.handleAccessInternalValidateAPIKey)
|
|
mux.HandleFunc("/api/v1/access/api-keys", s.handleAccessAPIKeys)
|
|
mux.HandleFunc("/api/v1/access/api-keys/", s.handleAccessAPIKeyAction)
|
|
mux.HandleFunc("/api/v1/access/usage", s.handleAccessUsage)
|
|
mux.HandleFunc("/api/v1/access/audit", s.handleAccessAudit)
|
|
|
|
// 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
|
|
hash := normalizeHash(parts[2])
|
|
if !isValidHash(hash) {
|
|
writeValidationError(w, ErrInvalidHash)
|
|
return
|
|
}
|
|
// Get by hash
|
|
s.handleGetBlockByHash(w, r, hash)
|
|
} 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 := normalizeHash(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 := normalizeAddress(parts[1])
|
|
if !isValidAddress(address) {
|
|
writeValidationError(w, ErrInvalidAddress)
|
|
return
|
|
}
|
|
|
|
// Set address in query and call handler
|
|
query := r.URL.Query()
|
|
query.Set("address", address)
|
|
r.URL.RawQuery = query.Encode()
|
|
s.handleGetAddress(w, r)
|
|
}
|