Files
explorer-monorepo/backend/api/rest/track_routes.go
defiQUG bdae5a9f6e feat: explorer API, wallet, CCIP scripts, and config refresh
- Backend REST/gateway/track routes, analytics, Blockscout proxy paths.
- Frontend wallet and liquidity surfaces; MetaMask token list alignment.
- Deployment docs, verification scripts, address inventory updates.

Check: go build ./... under backend/ (pass).
Made-with: Cursor
2026-04-07 23:22:12 -07:00

127 lines
4.9 KiB
Go

package rest
import (
"net/http"
"os"
"strings"
"github.com/explorer/backend/api/middleware"
"github.com/explorer/backend/api/track1"
"github.com/explorer/backend/api/track2"
"github.com/explorer/backend/api/track3"
"github.com/explorer/backend/api/track4"
"github.com/explorer/backend/libs/go-rpc-gateway"
)
// SetupTrackRoutes sets up track-specific routes with proper middleware
func (s *Server) SetupTrackRoutes(mux *http.ServeMux, authMiddleware *middleware.AuthMiddleware) {
// Initialize Track 1 (RPC Gateway) using reusable lib
rpcURL := os.Getenv("RPC_URL")
if rpcURL == "" {
rpcURL = "http://localhost:8545"
}
var cache gateway.Cache
if redisURL := os.Getenv("REDIS_URL"); redisURL != "" {
if c, err := gateway.NewRedisCache(redisURL); err == nil {
cache = c
}
}
if cache == nil {
cache = gateway.NewInMemoryCache()
}
rateLimitConfig := gateway.RateLimitConfig{
RequestsPerSecond: 10,
RequestsPerMinute: 100,
BurstSize: 20,
}
var rateLimiter gateway.RateLimiter
if redisURL := os.Getenv("REDIS_URL"); redisURL != "" {
if rl, err := gateway.NewRedisRateLimiter(redisURL, rateLimitConfig); err == nil {
rateLimiter = rl
}
}
if rateLimiter == nil {
rateLimiter = gateway.NewInMemoryRateLimiter(rateLimitConfig)
}
rpcGateway := gateway.NewRPCGateway(rpcURL, cache, rateLimiter)
track1Server := track1.NewServer(rpcGateway)
// Track 1 routes (public, optional auth)
mux.HandleFunc("/api/v1/track1/blocks/latest", track1Server.HandleLatestBlocks)
mux.HandleFunc("/api/v1/track1/txs/latest", track1Server.HandleLatestTransactions)
mux.HandleFunc("/api/v1/track1/block/", track1Server.HandleBlockDetail)
mux.HandleFunc("/api/v1/track1/tx/", track1Server.HandleTransactionDetail)
mux.HandleFunc("/api/v1/track1/address/", track1Server.HandleAddressBalance)
mux.HandleFunc("/api/v1/track1/bridge/status", track1Server.HandleBridgeStatus)
mux.HandleFunc("/api/v1/mission-control/stream", track1Server.HandleMissionControlStream)
mux.HandleFunc("/api/v1/mission-control/liquidity/token/", s.handleMissionControlLiquidityTokenPath)
mux.HandleFunc("/api/v1/mission-control/bridge/trace", s.HandleMissionControlBridgeTrace)
// Initialize Track 2 server
track2Server := track2.NewServer(s.db, s.chainID)
// Track 2 routes (require Track 2+)
track2Middleware := authMiddleware.RequireTrack(2)
// Track 2 route handlers with auth
track2AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
return authMiddleware.RequireAuth(track2Middleware(http.HandlerFunc(handler))).ServeHTTP
}
mux.HandleFunc("/api/v1/track2/search", track2AuthHandler(track2Server.HandleSearch))
// Address routes - need to parse path
mux.HandleFunc("/api/v1/track2/address/", track2AuthHandler(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
parts := strings.Split(strings.TrimPrefix(path, "/api/v1/track2/address/"), "/")
if len(parts) >= 2 {
if parts[1] == "txs" {
track2Server.HandleAddressTransactions(w, r)
return
} else if parts[1] == "tokens" {
track2Server.HandleAddressTokens(w, r)
return
} else if parts[1] == "internal-txs" {
track2Server.HandleInternalTransactions(w, r)
return
}
}
writeError(w, http.StatusBadRequest, "bad_request", "Invalid Track 2 address path")
}))
mux.HandleFunc("/api/v1/track2/token/", track2AuthHandler(track2Server.HandleTokenInfo))
// Initialize Track 3 server
track3Server := track3.NewServer(s.db, s.chainID)
// Track 3 routes (require Track 3+)
track3Middleware := authMiddleware.RequireTrack(3)
track3AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
return authMiddleware.RequireAuth(track3Middleware(http.HandlerFunc(handler))).ServeHTTP
}
mux.HandleFunc("/api/v1/track3/analytics/flows", track3AuthHandler(track3Server.HandleFlows))
mux.HandleFunc("/api/v1/track3/analytics/bridge", track3AuthHandler(track3Server.HandleBridge))
mux.HandleFunc("/api/v1/track3/analytics/token-distribution/", track3AuthHandler(track3Server.HandleTokenDistribution))
mux.HandleFunc("/api/v1/track3/analytics/address-risk/", track3AuthHandler(track3Server.HandleAddressRisk))
// Initialize Track 4 server
track4Server := track4.NewServer(s.db, s.chainID)
// Track 4 routes (require Track 4 + IP whitelist)
track4Middleware := authMiddleware.RequireTrack(4)
track4AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
return authMiddleware.RequireAuth(track4Middleware(http.HandlerFunc(handler))).ServeHTTP
}
mux.HandleFunc("/api/v1/track4/operator/bridge/events", track4AuthHandler(track4Server.HandleBridgeEvents))
mux.HandleFunc("/api/v1/track4/operator/validators", track4AuthHandler(track4Server.HandleValidators))
mux.HandleFunc("/api/v1/track4/operator/contracts", track4AuthHandler(track4Server.HandleContracts))
mux.HandleFunc("/api/v1/track4/operator/protocol-state", track4AuthHandler(track4Server.HandleProtocolState))
mux.HandleFunc("/api/v1/track4/operator/run-script", track4AuthHandler(track4Server.HandleRunScript))
}