← back to kyawgyi13122-ship-it__launchpad

Function bodies 1,118 total

All specs Real LLM only Function bodies
NewAuthHandler function · go · L23-L29 (7 LOC)
internal/handlers/auth.go
func NewAuthHandler(authService *auth.Service, validator *validators.Validator, logger *zap.Logger) *AuthHandler {
	return &AuthHandler{
		authService: authService,
		validator:   validator,
		logger:      logger,
	}
}
SendEmailCode method · go · L32-L67 (36 LOC)
internal/handlers/auth.go
func (h *AuthHandler) SendEmailCode(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	var req models.EmailAuthRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Generate and send verification code
	code, err := h.authService.SendEmailCode(ctx, req.Email)
	if err != nil {
		middleware.GetLogger(ctx).Error("failed to send email code",
			zap.Error(err),
			zap.String("email", req.Email),
		)
		response.InternalServerError(w, "Failed to send verification code")
		return
	}

	// In development, we might want to return the code for testing
	// In production, this should NOT be returned
	response.Success(w, http.StatusOK, map[string]interface{}{
		"message": "Verification code sent successfully",
		
VerifyEmailCode method · go · L70-L138 (69 LOC)
internal/handlers/auth.go
func (h *AuthHandler) VerifyEmailCode(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	var req models.VerifyEmailCodeRequest

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Verify code
	if err := h.authService.VerifyCode(req.Email, req.Code); err != nil {
		if err == auth.ErrInvalidCode {
			response.BadRequest(w, "Invalid verification code", nil)
			return
		}
		if err == auth.ErrCodeExpired {
			response.BadRequest(w, "Verification code has expired", nil)
			return
		}
		middleware.GetLogger(ctx).Error("failed to verify code",
			zap.Error(err),
			zap.String("email", req.Email),
		)
		response.InternalServerError(w, "Failed to verify code")
		return
	}

	// Get user agent and IP address for se
Logout method · go · L141-L163 (23 LOC)
internal/handlers/auth.go
func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Get token from Authorization header
	token := extractTokenFromHeader(r)
	if token == "" {
		response.BadRequest(w, "Missing authorization token", nil)
		return
	}

	// Revoke the token
	if err := h.authService.RevokeSession(ctx, token); err != nil {
		middleware.GetLogger(ctx).Error("failed to revoke session",
			zap.Error(err),
		)
		response.InternalServerError(w, "Failed to logout")
		return
	}

	response.Success(w, http.StatusOK, map[string]interface{}{
		"message": "Logged out successfully",
	})
}
GetSessions method · go · L166-L214 (49 LOC)
internal/handlers/auth.go
func (h *AuthHandler) GetSessions(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Get user ID from context (set by auth middleware)
	userID, ok := ctx.Value("userID").(string)
	if !ok {
		response.Unauthorized(w, "User not authenticated")
		return
	}

	userUUID, err := uuid.Parse(userID)
	if err != nil {
		response.BadRequest(w, "Invalid user ID", nil)
		return
	}

	// Get current session token to mark it in the response
	currentToken := extractTokenFromHeader(r)
	var currentSessionID string
	if currentToken != "" {
		_, currentSession, err := h.authService.ValidateToken(ctx, currentToken)
		if err == nil && currentSession != nil {
			currentSessionID = currentSession.ID.String()
		}
	}

	// Get all active sessions
	sessions, err := h.authService.GetActiveSessions(ctx, userUUID)
	if err != nil {
		middleware.GetLogger(ctx).Error("failed to get sessions",
			zap.Error(err),
			zap.String("user_id", userID),
		)
		response.InternalServerError(w, "Failed to retrieve ses
RevokeSession method · go · L217-L279 (63 LOC)
internal/handlers/auth.go
func (h *AuthHandler) RevokeSession(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Get session ID from URL
	sessionIDStr := chi.URLParam(r, "id")
	sessionID, err := uuid.Parse(sessionIDStr)
	if err != nil {
		response.BadRequest(w, "Invalid session ID", nil)
		return
	}

	// Get user ID from context
	userID, ok := ctx.Value("userID").(string)
	if !ok {
		response.Unauthorized(w, "User not authenticated")
		return
	}

	userUUID, err := uuid.Parse(userID)
	if err != nil {
		response.BadRequest(w, "Invalid user ID", nil)
		return
	}

	// Verify the session belongs to the user (security check)
	sessions, err := h.authService.GetActiveSessions(ctx, userUUID)
	if err != nil {
		middleware.GetLogger(ctx).Error("failed to get sessions",
			zap.Error(err),
			zap.String("user_id", userID),
		)
		response.InternalServerError(w, "Failed to revoke session")
		return
	}

	found := false
	for _, session := range sessions {
		if session.ID == sessionID {
			found = true
			break
	
extractTokenFromHeader function · go · L282-L294 (13 LOC)
internal/handlers/auth.go
func extractTokenFromHeader(r *http.Request) string {
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		return ""
	}

	// Bearer token format: "Bearer <token>"
	if len(authHeader) > 7 && authHeader[:7] == "Bearer " {
		return authHeader[7:]
	}

	return ""
}
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
extractIPAddress function · go · L297-L309 (13 LOC)
internal/handlers/auth.go
func extractIPAddress(r *http.Request) string {
	ipAddress := r.RemoteAddr
	// Strip port from IP address
	if colonIdx := len(ipAddress) - 1; colonIdx > 0 {
		for i := colonIdx; i >= 0; i-- {
			if ipAddress[i] == ':' {
				ipAddress = ipAddress[:i]
				break
			}
		}
	}
	return ipAddress
}
GetSIWENonce method · go · L315-L345 (31 LOC)
internal/handlers/auth.go
func (h *AuthHandler) GetSIWENonce(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	var req models.SIWENonceRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Generate nonce for this wallet address
	nonce, err := h.authService.GenerateSIWENonce(req.Address)
	if err != nil {
		middleware.GetLogger(ctx).Error("failed to generate SIWE nonce",
			zap.Error(err),
			zap.String("address", req.Address),
		)
		response.InternalServerError(w, "Failed to generate nonce")
		return
	}

	response.Success(w, http.StatusOK, models.SIWENonceResponse{
		Nonce: nonce,
	})
}
VerifySIWE method · go · L349-L403 (55 LOC)
internal/handlers/auth.go
func (h *AuthHandler) VerifySIWE(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	var req models.SIWEVerifyRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Get user agent and IP address for session tracking
	userAgent := r.Header.Get("User-Agent")
	ipAddress := extractIPAddress(r)

	// Complete SIWE login flow
	loginResponse, err := h.authService.CompleteSIWELogin(ctx, req.Message, req.Signature, userAgent, ipAddress)
	if err != nil {
		// Handle specific SIWE errors
		switch err {
		case auth.ErrInvalidNonce:
			response.BadRequest(w, "Invalid or expired nonce", nil)
			return
		case auth.ErrInvalidSignature:
			response.BadRequest(w, "Invalid signature", nil)
			return
		case auth.ErrInva
LinkWallet method · go · L407-L470 (64 LOC)
internal/handlers/auth.go
func (h *AuthHandler) LinkWallet(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Get user ID from context (set by auth middleware)
	userID, ok := ctx.Value("userID").(string)
	if !ok {
		response.Unauthorized(w, "User not authenticated")
		return
	}

	userUUID, err := uuid.Parse(userID)
	if err != nil {
		response.BadRequest(w, "Invalid user ID", nil)
		return
	}

	var req models.WalletLinkRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Link wallet to user
	walletAddress, err := h.authService.LinkWalletToUser(ctx, userUUID, req.Message, req.Signature)
	if err != nil {
		// Handle specific errors
		switch err {
		case auth.ErrInvalidNonce:
			response.BadRequest(w, "Invalid or expired n
NewChainHandler function · go · L31-L39 (9 LOC)
internal/handlers/chains.go
func NewChainHandler(chainService *chainsvc.Service, virtualPoolService *virtualpool.Service, rpcClient *canopy.Client, validator *validators.Validator, logger *zap.Logger) *ChainHandler {
	return &ChainHandler{
		chainService:       chainService,
		virtualPoolService: virtualPoolService,
		rpcClient:          rpcClient,
		validator:          validator,
		logger:             logger,
	}
}
GetChains method · go · L42-L102 (61 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetChains(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Parse query parameters
	var params models.ChainsQueryParams
	if err := h.parseQueryParams(r, &params); err != nil {
		response.BadRequest(w, "Invalid query parameters", err.Error())
		return
	}

	// Validate query parameters
	if err := h.validator.Validate(&params); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Set defaults
	if params.Page == 0 {
		params.Page = 1
	}
	if params.Limit == 0 {
		params.Limit = 20
	}

	// Parse include relations
	include := []string{}
	if params.Include != "" {
		parts := strings.Split(params.Include, ",")
		for _, part := range parts {
			trimmed := strings.TrimSpace(part)
			if trimmed != "" {
				include = append(include, trimmed)
			}
		}
	}

	// Get chains
	chains, pagination, err := h.chainService.GetChains(
		ctx,
		params.Status,
		params.CreatedBy,
		params.TemplateC
GetChain method · go · L105-L126 (22 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetChain(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainID := chi.URLParam(r, "id")
	include := r.URL.Query().Get("include")

	chain, err := h.chainService.GetChainByID(ctx, chainID, include)
	if err != nil {
		if err == chainsvc.ErrChainNotFound {
			response.NotFound(w, "Chain not found")
			return
		}
		middleware.GetLogger(ctx).Error("failed to retrieve chain",
			zap.Error(err),
			zap.String("chain_id", chainID),
			zap.String("include", include),
		)
		response.InternalServerError(w, "Failed to retrieve chain")
		return
	}

	response.Success(w, http.StatusOK, chain)
}
CreateChain method · go · L129-L167 (39 LOC)
internal/handlers/chains.go
func (h *ChainHandler) CreateChain(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	userID := h.getUserIDFromContext(ctx)

	var req models.CreateChainRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Create chain
	chain, err := h.chainService.CreateChain(ctx, &req, userID)
	if err != nil {
		if err == chainsvc.ErrChainAlreadyExists {
			middleware.GetLogger(ctx).Warn("create chain failed - chain already exists",
				zap.Error(err),
				zap.String("user_id", userID),
				zap.String("chain_name", req.ChainName),
			)
			response.Conflict(w, "Chain name already exists", nil)
			return
		}
		middleware.GetLogger(ctx).Error("failed to create chain",
			zap.Error(err),
			zap.String("user_id", user
Same scanner, your repo: https://repobility.com — Repobility
DeleteChain method · go · L170-L189 (20 LOC)
internal/handlers/chains.go
func (h *ChainHandler) DeleteChain(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}
	userID := h.getUserIDFromContext(ctx)

	err = h.chainService.DeleteChain(ctx, chainID, userID)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, map[string]string{
		"message": "Chain deleted successfully",
	})
}
UpdateChainDescription method · go · L192-L223 (32 LOC)
internal/handlers/chains.go
func (h *ChainHandler) UpdateChainDescription(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}
	userID := h.getUserIDFromContext(ctx)

	var req models.UpdateChainDescriptionRequest
	if err = json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Update chain description
	chain, err := h.chainService.UpdateChainDescription(ctx, chainID, userID, &req)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, chain)
}
GetRepository method · go · L226-L242 (17 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetRepository(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	repo, err := h.chainService.GetRepositoryByChainID(ctx, chainID)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, repo)
}
CreateRepository method · go · L245-L276 (32 LOC)
internal/handlers/chains.go
func (h *ChainHandler) CreateRepository(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}
	userID := h.getUserIDFromContext(ctx)

	var req models.CreateChainRepositoryRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Create repository
	repo, err := h.chainService.CreateRepositoryByChainID(ctx, chainID, userID, &req)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusCreated, repo)
}
UpdateRepository method · go · L279-L310 (32 LOC)
internal/handlers/chains.go
func (h *ChainHandler) UpdateRepository(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}
	userID := h.getUserIDFromContext(ctx)

	var req models.UpdateChainRepositoryRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Update repository
	repo, err := h.chainService.UpdateRepositoryByChainID(ctx, chainID, userID, &req)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, repo)
}
GetTransactions method · go · L313-L359 (47 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetTransactions(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	// Parse query parameters
	var params models.TransactionsQueryParams
	if err := h.parseQueryParams(r, &params); err != nil {
		response.BadRequest(w, "Invalid query parameters", err.Error())
		return
	}

	// Validate query parameters
	if err := h.validator.Validate(&params); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Set defaults
	if params.Page == 0 {
		params.Page = 1
	}
	if params.Limit == 0 {
		params.Limit = 20
	}

	// Get transactions
	transactions, pagination, err := h.chainService.GetTransactions(
		ctx,
		chainID,
		params.UserID,
		params.TransactionType,
		params.Page,
		params.Limit,
	)
	if err != nil {
GetPriceHistory method · go · L362-L386 (25 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetPriceHistory(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	// Parse query parameters
	var params models.PriceHistoryQueryParams
	if err := h.parsePriceHistoryParams(r, &params); err != nil {
		response.BadRequest(w, "Invalid query parameters", err.Error())
		return
	}

	// Get price history from service
	candles, err := h.chainService.GetPriceHistory(ctx, chainID, params.StartTime, params.EndTime)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, candles)
}
GetMarketCapHistory method · go · L389-L413 (25 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetMarketCapHistory(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	// Parse query parameters (reuse the same parser as price history)
	var params models.MarketCapHistoryQueryParams
	if err := h.parseMarketCapHistoryParams(r, &params); err != nil {
		response.BadRequest(w, "Invalid query parameters", err.Error())
		return
	}

	// Get market cap history from service
	candles, err := h.chainService.GetMarketCapHistory(ctx, chainID, params.StartTime, params.EndTime)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, candles)
}
Source: Repobility analyzer · https://repobility.com
GetAssets method · go · L416-L432 (17 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetAssets(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	assets, err := h.chainService.GetAssets(ctx, chainID)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, assets)
}
CreateAsset method · go · L435-L466 (32 LOC)
internal/handlers/chains.go
func (h *ChainHandler) CreateAsset(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}
	userID := h.getUserIDFromContext(ctx)

	var req models.CreateChainAssetRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Create asset
	asset, err := h.chainService.CreateAsset(ctx, chainID, userID, &req)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusCreated, asset)
}
UpdateAsset method · go · L469-L501 (33 LOC)
internal/handlers/chains.go
func (h *ChainHandler) UpdateAsset(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}
	assetID := chi.URLParam(r, "asset_id")
	userID := h.getUserIDFromContext(ctx)

	var req models.UpdateChainAssetRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Update asset
	asset, err := h.chainService.UpdateAsset(ctx, chainID, assetID, userID, &req)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, asset)
}
GetSocials method · go · L504-L520 (17 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetSocials(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	socials, err := h.chainService.GetSocials(ctx, chainID)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, socials)
}
CreateSocial method · go · L523-L554 (32 LOC)
internal/handlers/chains.go
func (h *ChainHandler) CreateSocial(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}
	userID := h.getUserIDFromContext(ctx)

	var req models.CreateChainSocialLinkRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Create social link
	social, err := h.chainService.CreateSocial(ctx, chainID, userID, &req)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusCreated, social)
}
UpdateSocial method · go · L557-L589 (33 LOC)
internal/handlers/chains.go
func (h *ChainHandler) UpdateSocial(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}
	socialID := chi.URLParam(r, "social_id")
	userID := h.getUserIDFromContext(ctx)

	var req models.UpdateChainSocialLinkRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		response.BadRequest(w, "Invalid JSON payload", err.Error())
		return
	}

	// Validate request
	if err := h.validator.Validate(&req); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Update social link
	social, err := h.chainService.UpdateSocial(ctx, chainID, socialID, userID, &req)
	if err != nil {
		h.handleServiceError(w, err)
		return
	}

	response.Success(w, http.StatusOK, social)
}
getUserIDFromContext method · go · L592-L599 (8 LOC)
internal/handlers/chains.go
func (h *ChainHandler) getUserIDFromContext(ctx context.Context) string {
	// This would be set by the auth middleware
	userID, ok := ctx.Value("userID").(string)
	if !ok {
		return ""
	}
	return userID
}
parseQueryParams method · go · L601-L659 (59 LOC)
internal/handlers/chains.go
func (h *ChainHandler) parseQueryParams(r *http.Request, params interface{}) error {
	// This would typically use a library like gorilla/schema or similar
	// For now, we'll parse manually based on the request type
	switch p := params.(type) {
	case *models.ChainsQueryParams:
		p.Status = r.URL.Query().Get("status")
		p.CreatedBy = r.URL.Query().Get("created_by")
		p.TemplateID = r.URL.Query().Get("template_id")
		p.TemplateCategory = r.URL.Query().Get("template_category")
		p.TemplateSupportedLanguage = r.URL.Query().Get("template_supported_language")
		p.Include = r.URL.Query().Get("include")

		if pageStr := r.URL.Query().Get("page"); pageStr != "" {
			if page, err := strconv.Atoi(pageStr); err == nil {
				p.Page = page
			}
		}

		if limitStr := r.URL.Query().Get("limit"); limitStr != "" {
			if limit, err := strconv.Atoi(limitStr); err == nil {
				p.Limit = limit
			}
		}

	case *models.TransactionsQueryParams:
		p.UserID = r.URL.Query().Get("user_id")
		p.TransactionType = r.U
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
parsePriceHistoryParams method · go · L661-L681 (21 LOC)
internal/handlers/chains.go
func (h *ChainHandler) parsePriceHistoryParams(r *http.Request, params *models.PriceHistoryQueryParams) error {
	// Parse start_time if provided
	if startTimeStr := r.URL.Query().Get("start_time"); startTimeStr != "" {
		startTime, err := parseTime(startTimeStr)
		if err != nil {
			return err
		}
		params.StartTime = &startTime
	}

	// Parse end_time if provided
	if endTimeStr := r.URL.Query().Get("end_time"); endTimeStr != "" {
		endTime, err := parseTime(endTimeStr)
		if err != nil {
			return err
		}
		params.EndTime = &endTime
	}

	return nil
}
parseMarketCapHistoryParams method · go · L683-L703 (21 LOC)
internal/handlers/chains.go
func (h *ChainHandler) parseMarketCapHistoryParams(r *http.Request, params *models.MarketCapHistoryQueryParams) error {
	// Parse start_time if provided
	if startTimeStr := r.URL.Query().Get("start_time"); startTimeStr != "" {
		startTime, err := parseTime(startTimeStr)
		if err != nil {
			return err
		}
		params.StartTime = &startTime
	}

	// Parse end_time if provided
	if endTimeStr := r.URL.Query().Get("end_time"); endTimeStr != "" {
		endTime, err := parseTime(endTimeStr)
		if err != nil {
			return err
		}
		params.EndTime = &endTime
	}

	return nil
}
parseTime function · go · L706-L720 (15 LOC)
internal/handlers/chains.go
func parseTime(timeStr string) (time.Time, error) {
	// Try RFC3339 format first (standard format)
	t, err := time.Parse(time.RFC3339, timeStr)
	if err == nil {
		return t, nil
	}

	// Try RFC3339Nano as fallback
	t, err = time.Parse(time.RFC3339Nano, timeStr)
	if err == nil {
		return t, nil
	}

	return time.Time{}, fmt.Errorf("invalid time format, expected RFC3339/ISO 8601 (e.g., 2006-01-02T15:04:05Z)")
}
GetHolders method · go · L723-L781 (59 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetHolders(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	// Parse query parameters
	var params models.HoldersQueryParams
	if err := h.parseQueryParams(r, &params); err != nil {
		response.BadRequest(w, "Invalid query parameters", err.Error())
		return
	}

	// Validate query parameters
	if err := h.validator.Validate(&params); err != nil {
		validationErrors := h.validator.FormatErrors(err)
		response.ValidationError(w, validationErrors)
		return
	}

	// Set defaults
	if params.Page == 0 {
		params.Page = 1
	}
	if params.Limit == 0 {
		params.Limit = 20
	}
	if params.SortBy == "" {
		params.SortBy = "balance"
	}
	if params.Order == "" {
		params.Order = "desc"
	}

	// Get holders
	holders, pagination, err := h.virtualPoolService.GetHolders(
		ctx,
		chainID,
		p
GetChainAccolades method · go · L784-L804 (21 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetChainAccolades(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	accolades, err := h.chainService.GetChainAccolades(ctx, chainID)
	if err != nil {
		middleware.GetLogger(ctx).Error("failed to retrieve accolades",
			zap.Error(err),
			zap.Uint64("chain_id", chainID),
		)
		response.InternalServerError(w, "Failed to retrieve accolades")
		return
	}

	response.Success(w, http.StatusOK, accolades)
}
ValidateChainAvailability method · go · L807-L835 (29 LOC)
internal/handlers/chains.go
func (h *ChainHandler) ValidateChainAvailability(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Parse query parameters
	name := r.URL.Query().Get("name")
	symbol := r.URL.Query().Get("symbol")
	tokenName := r.URL.Query().Get("token_name")

	// At least one parameter must be provided
	if name == "" && symbol == "" && tokenName == "" {
		response.BadRequest(w, "At least one parameter (name, symbol, or token_name) must be provided", "")
		return
	}

	// Check availability
	result, err := h.chainService.CheckAvailability(ctx, name, symbol, tokenName)
	if err != nil {
		middleware.GetLogger(ctx).Error("failed to check availability",
			zap.Error(err),
			zap.String("name", name),
			zap.String("symbol", symbol),
			zap.String("token_name", tokenName),
		)
		response.InternalServerError(w, "Failed to check availability")
		return
	}

	response.Success(w, http.StatusOK, result)
}
GetChainStatistics method · go · L838-L859 (22 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetChainStatistics(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	// Get comprehensive statistics from indexer
	stats, err := h.chainService.GetChainStatistics(ctx, chainID)
	if err != nil {
		middleware.GetLogger(ctx).Error("failed to retrieve chain statistics",
			zap.Error(err),
			zap.Uint64("chain_id", chainID),
		)
		response.InternalServerError(w, "Failed to retrieve chain statistics")
		return
	}

	response.Success(w, http.StatusOK, stats)
}
GetChainBondingCurve method · go · L862-L883 (22 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetChainBondingCurve(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	chainIDStr := chi.URLParam(r, "id")
	chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
	if err != nil {
		response.Error(w, http.StatusBadRequest, "Invalid chain ID", "")
		return
	}

	// Get bonding curve data (works for both virtual and graduated chains)
	data, err := h.chainService.GetBondingCurveData(ctx, chainID)
	if err != nil {
		middleware.GetLogger(ctx).Error("failed to retrieve bonding curve data",
			zap.Error(err),
			zap.Uint64("chain_id", chainID),
		)
		response.InternalServerError(w, "Failed to retrieve bonding curve data")
		return
	}

	response.Success(w, http.StatusOK, data)
}
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
GetChainHeight method · go · L886-L931 (46 LOC)
internal/handlers/chains.go
func (h *ChainHandler) GetChainHeight(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Get chain ID from URL
	chainID := chi.URLParam(r, "id")

	// Verify chain exists
	_, err := h.chainService.GetChainByID(ctx, chainID, "")
	if err != nil {
		if err == chainsvc.ErrChainNotFound {
			response.NotFound(w, "Chain not found")
			return
		}
		middleware.GetLogger(ctx).Error("failed to retrieve chain",
			zap.Error(err),
			zap.String("chain_id", chainID),
		)
		response.InternalServerError(w, "Failed to retrieve chain")
		return
	}

	// Query the Canopy node for current block height
	heightPtr, libErr := h.rpcClient.Height()
	if libErr != nil {
		middleware.GetLogger(ctx).Error("failed to query block height from Canopy node",
			zap.Error(libErr),
			zap.String("chain_id", chainID),
		)
		response.InternalServerError(w, "Failed to query block height")
		return
	}

	if heightPtr == nil {
		middleware.GetLogger(ctx).Error("received nil height from Canopy node",
			zap.Strin
handleServiceError method · go · L933-L957 (25 LOC)
internal/handlers/chains.go
func (h *ChainHandler) handleServiceError(w http.ResponseWriter, err error) {
	switch err {
	case chainsvc.ErrChainNotFound:
		response.NotFound(w, "Chain not found")
	case chainsvc.ErrChainAlreadyExists:
		response.Conflict(w, "Chain already exists", nil)
	case chainsvc.ErrChainNotInDraftStatus:
		response.UnprocessableEntity(w, "Chain is not in draft status", nil)
	case chainsvc.ErrUnauthorized:
		response.Forbidden(w, "Access denied")
	case chainsvc.ErrRepositoryNotFound:
		response.NotFound(w, "Repository not found")
	case chainsvc.ErrRepositoryAlreadyExists:
		response.Conflict(w, "Repository already exists for this chain", nil)
	case chainsvc.ErrAssetNotFound:
		response.NotFound(w, "Asset not found")
	case chainsvc.ErrSocialLinkNotFound:
		response.NotFound(w, "Social link not found")
	case chainsvc.ErrSocialLinkAlreadyExists:
		response.Conflict(w, "Social link for this platform already exists for this chain", nil)
	default:
		h.logger.Error("unhandled service error", zap.Error
NewExplorerHandler function · go · L57-L69 (13 LOC)
internal/handlers/explorer.go
func NewExplorerHandler(
	indexerRepo ExplorerHandlerIndexer,
	explorerSvc *explorer.Service,
	validator *validators.Validator,
	logger *zap.Logger,
) *ExplorerHandler {
	return &ExplorerHandler{
		indexerRepo: indexerRepo,
		explorerSvc: explorerSvc,
		validator:   validator,
		logger:      logger,
	}
}
GetBlocks method · go · L73-L165 (93 LOC)
internal/handlers/explorer.go
func (h *ExplorerHandler) GetBlocks(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := middleware.GetLogger(ctx)

	// Parse query parameters
	req, err := h.parseBlocksRequest(r)
	if err != nil {
		response.BadRequest(w, "Invalid query parameters", err.Error())
		return
	}
	if req == nil {
		logger.Error("parseBlocksRequest returned nil request")
		response.InternalServerError(w, "Failed to parse request")
		return
	}

	// Default to root chain if no chain specified
	chainID := uint64(1)
	if req.ChainID != nil {
		chainID = *req.ChainID
	}

	// Set default limit
	if req.Limit == 0 {
		req.Limit = 20
	}
	if req.Limit > 100 {
		req.Limit = 100
	}

	// Default sort to descending (most recent first)
	if req.Sort == "" {
		req.Sort = "desc"
	}

	// Fetch blocks from indexer
	blocks, pagination, err := h.indexerRepo.ListBlocks(ctx, chainID, req.Cursor, req.Limit, req.Sort)
	if err != nil {
		logger.Error("failed to list blocks",
			zap.Error(err),
			zap.Uint64("chain_id
GetBlock method · go · L169-L220 (52 LOC)
internal/handlers/explorer.go
func (h *ExplorerHandler) GetBlock(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := middleware.GetLogger(ctx)

	// Parse height from URL
	heightStr := chi.URLParam(r, "height")
	height, err := strconv.ParseUint(heightStr, 10, 64)
	if err != nil {
		response.BadRequest(w, "Invalid block height", err.Error())
		return
	}

	// Parse chain_id from query (default to root chain)
	chainID := uint64(1)
	if chainIDStr := r.URL.Query().Get("chain_id"); chainIDStr != "" {
		parsedChainID, err := strconv.ParseUint(chainIDStr, 10, 64)
		if err != nil {
			response.BadRequest(w, "Invalid chain_id", err.Error())
			return
		}
		chainID = parsedChainID
	}

	// Fetch block from indexer
	block, err := h.indexerRepo.GetBlock(ctx, chainID, height)
	if err != nil {
		logger.Error("failed to get block",
			zap.Error(err),
			zap.Uint64("chain_id", chainID),
			zap.Uint64("height", height),
		)
		response.NotFound(w, "Block not found")
		return
	}

	// Fetch block summary for transact
GetTransactions method · go · L224-L298 (75 LOC)
internal/handlers/explorer.go
func (h *ExplorerHandler) GetTransactions(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := middleware.GetLogger(ctx)

	// Parse query parameters
	req, err := h.parseTransactionsRequest(r)
	if err != nil {
		response.BadRequest(w, "Invalid query parameters", err.Error())
		return
	}
	if req == nil {
		logger.Error("parseTransactionsRequest returned nil request")
		response.InternalServerError(w, "Failed to parse request")
		return
	}

	// Default to root chain if no chain specified
	chainID := uint64(1)
	if req.ChainID != nil {
		chainID = *req.ChainID
	}

	// Set default limit
	if req.Limit == 0 {
		req.Limit = 20
	}
	if req.Limit > 100 {
		req.Limit = 100
	}

	// Default sort to descending (most recent first)
	if req.Sort == "" {
		req.Sort = "desc"
	}

	// Fetch transactions from indexer
	txs, pagination, err := h.indexerRepo.ListTransactions(ctx, chainID, req.Cursor, req.Limit, req.Sort, req.MessageType)
	if err != nil {
		logger.Error("failed to list transac
GetTransaction method · go · L302-L340 (39 LOC)
internal/handlers/explorer.go
func (h *ExplorerHandler) GetTransaction(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := middleware.GetLogger(ctx)

	// Parse hash from URL
	txHash := chi.URLParam(r, "hash")
	if txHash == "" {
		response.BadRequest(w, "Transaction hash is required", "")
		return
	}

	// Parse chain_id from query (default to root chain)
	chainID := uint64(1)
	if chainIDStr := r.URL.Query().Get("chain_id"); chainIDStr != "" {
		parsedChainID, err := strconv.ParseUint(chainIDStr, 10, 64)
		if err != nil {
			response.BadRequest(w, "Invalid chain_id", err.Error())
			return
		}
		chainID = parsedChainID
	}

	// Fetch transaction from indexer
	tx, err := h.indexerRepo.GetTransaction(ctx, chainID, txHash)
	if err != nil {
		logger.Error("failed to get transaction",
			zap.Error(err),
			zap.Uint64("chain_id", chainID),
			zap.String("tx_hash", txHash),
		)
		response.NotFound(w, "Transaction not found")
		return
	}

	// Transform to DTO with full message JSON
	txDTO := h.transaction
GetSwaps method · go · L344-L442 (99 LOC)
internal/handlers/explorer.go
func (h *ExplorerHandler) GetSwaps(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := middleware.GetLogger(ctx)

	// Parse query parameters
	req, err := h.parseSwapsRequest(r)
	if err != nil {
		response.BadRequest(w, "Invalid query parameters", err.Error())
		return
	}
	if req == nil {
		logger.Error("parseSwapsRequest returned nil request")
		response.InternalServerError(w, "Failed to parse request")
		return
	}

	// Default to root chain if no chain specified
	chainID := uint64(1)
	if req.ChainID != nil {
		chainID = *req.ChainID
	}

	// Set default limit
	if req.Limit == 0 {
		req.Limit = 20
	}
	if req.Limit > 100 {
		req.Limit = 100
	}

	// Default sort to descending (most recent first)
	if req.Sort == "" {
		req.Sort = "desc"
	}

	// Fetch transactions filtered by swap message types
	// We'll query for dexLimitOrder transactions which represent swaps
	messageType := "dexLimitOrder"
	txs, pagination, err := h.indexerRepo.ListTransactions(ctx, chainID, req.Cur
Same scanner, your repo: https://repobility.com — Repobility
Search method · go · L446-L548 (103 LOC)
internal/handlers/explorer.go
func (h *ExplorerHandler) Search(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := middleware.GetLogger(ctx)

	// Parse query parameters
	req, err := h.parseSearchRequest(r)
	if err != nil {
		response.BadRequest(w, "Invalid search query", err.Error())
		return
	}
	if req == nil {
		logger.Error("parseSearchRequest returned nil request")
		response.InternalServerError(w, "Failed to parse request")
		return
	}

	// Validate request
	if err := h.validator.Validate(req); err != nil {
		response.BadRequest(w, "Invalid search query", err.Error())
		return
	}

	// Default to root chain if no chain specified
	chainID := uint64(1)
	if req.ChainID != nil {
		chainID = *req.ChainID
	}

	// Set default limit
	if req.Limit == 0 {
		req.Limit = 10
	}
	if req.Limit > 50 {
		req.Limit = 50
	}

	// Detect query type and search accordingly
	results := []models.SearchResultDTO{}

	// Check if query is a block height (numeric)
	if height, err := strconv.ParseUint(req.Query, 10, 64)
parseBlocksRequest method · go · L552-L585 (34 LOC)
internal/handlers/explorer.go
func (h *ExplorerHandler) parseBlocksRequest(r *http.Request) (*models.BlocksRequest, error) {
	req := &models.BlocksRequest{}
	query := r.URL.Query()

	if chainIDStr := query.Get("chain_id"); chainIDStr != "" {
		chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
		if err != nil {
			return nil, err
		}
		req.ChainID = &chainID
	}

	if limitStr := query.Get("limit"); limitStr != "" {
		limit, err := strconv.Atoi(limitStr)
		if err != nil {
			return nil, err
		}
		req.Limit = limit
	}

	if cursorStr := query.Get("cursor"); cursorStr != "" {
		cursor, err := strconv.ParseUint(cursorStr, 10, 64)
		if err != nil {
			return nil, err
		}
		req.Cursor = &cursor
	}

	if sort := query.Get("sort"); sort != "" {
		req.Sort = sort
	}

	return req, nil
}
parseTransactionsRequest method · go · L587-L632 (46 LOC)
internal/handlers/explorer.go
func (h *ExplorerHandler) parseTransactionsRequest(r *http.Request) (*models.TransactionsRequest, error) {
	req := &models.TransactionsRequest{}
	query := r.URL.Query()

	if chainIDStr := query.Get("chain_id"); chainIDStr != "" {
		chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
		if err != nil {
			return nil, err
		}
		req.ChainID = &chainID
	}

	if messageType := query.Get("message_type"); messageType != "" {
		req.MessageType = &messageType
	}

	if signer := query.Get("signer"); signer != "" {
		req.Signer = &signer
	}

	if counterparty := query.Get("counterparty"); counterparty != "" {
		req.Counterparty = &counterparty
	}

	if limitStr := query.Get("limit"); limitStr != "" {
		limit, err := strconv.Atoi(limitStr)
		if err != nil {
			return nil, err
		}
		req.Limit = limit
	}

	if cursorStr := query.Get("cursor"); cursorStr != "" {
		cursor, err := strconv.ParseUint(cursorStr, 10, 64)
		if err != nil {
			return nil, err
		}
		req.Cursor = &cursor
	}

	if sort := query.Get(
‹ prevpage 5 / 23next ›