package rest import ( "context" "database/sql" "encoding/json" "fmt" "net/http" "time" ) // handleGetAddress handles GET /api/v1/addresses/{chain_id}/{address} func (s *Server) handleGetAddress(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeMethodNotAllowed(w) return } // Parse address from URL address := r.URL.Query().Get("address") if address == "" { writeValidationError(w, fmt.Errorf("address required")) return } // Validate address format if !isValidAddress(address) { writeValidationError(w, ErrInvalidAddress) return } // Add query timeout ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // Get transaction count var txCount int64 err := s.db.QueryRow(ctx, `SELECT COUNT(*) FROM transactions WHERE chain_id = $1 AND (from_address = $2 OR to_address = $2)`, s.chainID, address, ).Scan(&txCount) if err != nil { writeInternalError(w, "Database error") return } // Get token count var tokenCount int err = s.db.QueryRow(ctx, `SELECT COUNT(DISTINCT token_address) FROM token_transfers WHERE chain_id = $1 AND (from_address = $2 OR to_address = $2)`, s.chainID, address, ).Scan(&tokenCount) if err != nil { tokenCount = 0 } // Get label var label sql.NullString s.db.QueryRow(ctx, `SELECT label FROM address_labels WHERE chain_id = $1 AND address = $2 AND label_type = 'public' LIMIT 1`, s.chainID, address, ).Scan(&label) // Get tags rows, _ := s.db.Query(ctx, `SELECT tag FROM address_tags WHERE chain_id = $1 AND address = $2`, s.chainID, address, ) defer rows.Close() tags := []string{} for rows.Next() { var tag string if err := rows.Scan(&tag); err == nil { tags = append(tags, tag) } } // Check if contract var isContract bool s.db.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM contracts WHERE chain_id = $1 AND address = $2)`, s.chainID, address, ).Scan(&isContract) // Get balance (if we have RPC access, otherwise 0) balance := "0" // TODO: Add RPC call to get balance if needed response := map[string]interface{}{ "address": address, "chain_id": s.chainID, "balance": balance, "transaction_count": txCount, "token_count": tokenCount, "is_contract": isContract, "tags": tags, } if label.Valid { response["label"] = label.String } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "data": response, }) }