Перейти к содержанию

API Rate Limits and Business Strategy

Business Context

API rate limiting в Saga служит нескольким критическим бизнес-целям:

  1. Fair Resource Allocation - равномерное распределение ресурсов между пользователями
  2. Anti-Abuse Protection - защита от злоупотреблений и DoS атак
  3. Cost Management - контроль расходов на blockchain gas и infrastructure
  4. Quality of Service - гарантированная производительность для всех пользователей
  5. Scalability Planning - управляемый рост нагрузки на систему

🔢 API Rate Limits Configuration

1. Faucet Limits

Business Logic:

  • Daily Limit: 1,000 USDC per wallet per 24 hours
  • Cooldown Period: 24 hours между requests
  • Purpose: Prevent faucet abuse while allowing testing

Configuration:

# config/limits.yaml
faucet:
  amount_usdc: "1000.00"
  cooldown_hours: 24
  max_daily_requests: 1
  blockchain:
    gas_limit_usdc: 100000
    gas_limit_staking: 200000

Implementation:

// backend/shared/services/faucet_service.go
func (s *FaucetService) ValidateRequest(walletAddress string) error {
    // Check last request time
    lastRequest, err := s.repo.GetLastFaucetRequest(walletAddress)
    if err == nil && time.Since(lastRequest) < 24*time.Hour {
        remainingTime := 24*time.Hour - time.Since(lastRequest)
        return fmt.Errorf("cooldown active: %s remaining", remainingTime)
    }

    // Check daily limit
    dailyCount, err := s.repo.GetDailyFaucetCount(walletAddress)
    if dailyCount >= 1 {
        return errors.New("daily limit exceeded")
    }

    return nil
}

Business Rationale:

  • ✅ 1,000 USDC достаточно для comprehensive testing
  • ✅ 24h cooldown предотвращает sybil attacks
  • ✅ Один request в день = reasonable usage pattern
  • ✅ Можно создать multiple wallets для дополнительных средств

2. Investment Strategy Limits

Amount Limits per Strategy:

Strategy Min Amount Max Amount Business Reason
Conservative (5%) $10 $10,000 Entry barrier low, cap для risk management
Balanced (10%) $10 $10,000 Same limits для consistency
Aggressive (20%) $10 $10,000 Same limits для consistency

Configuration:

# config/limits.yaml
limits:
  investment_strategies:
    - id: 1
      name: "Conservative"
      min_amount: "10.00"
      max_amount: "10000.00"
      apy: 5.0
    - id: 2
      name: "Balanced"
      min_amount: "10.00"
      max_amount: "10000.00"
      apy: 10.0
    - id: 3
      name: "Aggressive"
      min_amount: "10.00"
      max_amount: "10000.00"
      apy: 20.0

Validation Logic:

func (s *InvestmentService) ValidateAmount(strategyID int, amount SafeDecimal) error {
    strategy := s.config.GetInvestmentStrategy(strategyID)

    if amount.LessThan(strategy.MinAmount) {
        return fmt.Errorf("amount below minimum: $%s (min: $%s)",
            amount.String(),
            strategy.MinAmount.String(),
        )
    }

    if amount.GreaterThan(strategy.MaxAmount) {
        return fmt.Errorf("amount exceeds maximum: $%s (max: $%s)",
            amount.String(),
            strategy.MaxAmount.String(),
        )
    }

    return nil
}

Business Rationale:

  • $10 minimum: Low entry barrier для новых пользователей
  • $10,000 maximum: Risk management (testnet MVP limits)
  • Uniform limits: Simplicity для пользователей
  • Future expansion: Можно увеличить для mainnet production

3. Withdrawal Limits

Daily Withdrawal Limits:

# config/limits.yaml
withdrawal:
  min_amount: "1.00"
  max_amount_per_request: "10000.00"
  max_daily_amount: "50000.00"
  cooldown_between_requests_minutes: 5

Validation:

func (s *WithdrawalService) ValidateWithdrawal(userID int64, amount SafeDecimal) error {
    // 1. Check minimum
    if amount.LessThan(NewSafeDecimal("1.00")) {
        return errors.New("withdrawal amount below minimum $1")
    }

    // 2. Check per-request maximum
    if amount.GreaterThan(NewSafeDecimal("10000.00")) {
        return errors.New("withdrawal exceeds $10,000 per-request limit")
    }

    // 3. Check daily total
    dailyTotal, err := s.repo.GetDailyWithdrawalTotal(userID)
    if err != nil {
        return err
    }

    if dailyTotal.Add(amount).GreaterThan(NewSafeDecimal("50000.00")) {
        return errors.New("daily withdrawal limit exceeded ($50,000)")
    }

    // 4. Check cooldown
    lastWithdrawal, err := s.repo.GetLastWithdrawal(userID)
    if err == nil && time.Since(lastWithdrawal.CreatedAt) < 5*time.Minute {
        return errors.New("5-minute cooldown between withdrawals")
    }

    return nil
}

Business Rationale:

  • $1 minimum: Avoid dust withdrawals (gas costs)
  • $10,000 per request: Anti-fraud limit
  • $50,000 daily: Risk management cap
  • 5-minute cooldown: Prevent accidental double-withdrawals

4. API Request Rate Limits

Global Rate Limits:

# config/monitoring.yaml
rate_limiting:
  global:
    requests_per_second: 100
    burst_size: 200

  per_user:
    requests_per_minute: 60
    requests_per_hour: 1000

  per_endpoint:
    auth:
      requests_per_minute: 10
    faucet:
      requests_per_minute: 1
    balance:
      requests_per_minute: 30
    investments:
      requests_per_minute: 20
    withdrawals:
      requests_per_minute: 5

Implementation (Chi Middleware):

import "github.com/go-chi/httprate"

func SetupRateLimiting(r chi.Router, cfg *config.UnifiedConfig) {
    // Global rate limit
    r.Use(httprate.LimitByIP(100, 1*time.Second))

    // Per-endpoint limits
    r.Group(func(r chi.Router) {
        r.Use(httprate.LimitByIP(10, 1*time.Minute))
        r.Post("/api/auth/wallet/authenticate", authHandler.Authenticate)
    })

    r.Group(func(r chi.Router) {
        r.Use(httprate.LimitByIP(1, 1*time.Minute))
        r.Post("/api/faucet/request", faucetHandler.RequestFunds)
    })

    r.Group(func(r chi.Router) {
        r.Use(httprate.LimitByIP(30, 1*time.Minute))
        r.Get("/api/user/balance", userHandler.GetBalance)
    })
}

Business Rationale:

  • 100 req/sec global: Reasonable server capacity
  • 60 req/min per user: Normal usage pattern
  • Endpoint-specific: Critical endpoints более строгие limits
  • Burst allowance: Accommodate legitimate traffic spikes

Business Strategy per Limit Category

Strategy 1: Faucet Anti-Abuse

Problem: Faucet может быть использован для бесплатного farming testnet токенов.

Solution Strategy:

  1. One-per-day limit - prevents repeat abuse
  2. Wallet-based tracking - sybil resistance
  3. Amount cap (1,000 USDC) - limits total exposure
  4. Future enhancement: CAPTCHA для дополнительной защиты

Metrics to Monitor:

  • Unique wallets per day
  • Total USDC distributed
  • Repeat offenders (multiple wallets from same IP)
  • Faucet request patterns

Success Criteria:

  • Average 50-100 unique wallets per day
  • <5% repeat requestors per IP
  • Total daily distribution <100,000 USDC

Strategy 2: Investment Volume Management

Problem: Неограниченные investments создают operational risks.

Solution Strategy:

  1. $10,000 cap per investment - manageable risk per transaction
  2. No total portfolio limit - allow accumulation over time
  3. Strategy-based limits - same limits для consistency
  4. Admin override capability - для exceptional cases

Metrics to Monitor:

  • Average investment size per strategy
  • Total Value Locked (TVL) growth rate
  • Distribution across strategies (5%, 10%, 20%)
  • Large investments (>$5,000) frequency

Success Criteria:

  • Average investment: $100-500
  • TVL growth: 10-20% monthly
  • Strategy distribution: 40% Conservative, 40% Balanced, 20% Aggressive

Strategy 3: Withdrawal Flow Control

Problem: Неконтролируемые withdrawals угрожают liquidity.

Solution Strategy:

  1. Daily limit ($50,000) - prevents bank run
  2. Per-request limit ($10,000) - fraud protection
  3. Admin approval for >$1,000 - manual review для крупных сумм
  4. 5-minute cooldown - prevents accidental duplicates

Metrics to Monitor:

  • Daily withdrawal volume
  • Withdrawal approval rate (admin)
  • Average processing time
  • Failed withdrawal reasons

Success Criteria:

  • <10% of TVL withdrawn daily
  • 95% approval rate для small withdrawals

  • <1 hour average processing time
  • <1% failed withdrawals due to limits

Strategy 4: API Rate Limiting for Stability

Problem: Неограниченный API access может перегрузить систему.

Solution Strategy:

  1. Tiered limits - global → per-user → per-endpoint
  2. Burst allowance - accommodate legitimate spikes
  3. Endpoint-specific - critical endpoints stricter
  4. 429 Too Many Requests - clear error messaging

Metrics to Monitor:

  • API requests per second (RPS)
  • Rate limit violations per hour
  • Endpoint distribution (which endpoints hit most)
  • User behavior patterns

Success Criteria:

  • <80% of rate limit capacity used
  • <5% requests result in 429 errors
  • No single user >20% of total traffic
  • Average latency <100ms

Dynamic Limit Adjustment

Automatic Scaling

Load-based Adjustment:

func (s *RateLimiter) AdjustLimits(ctx context.Context) {
    currentLoad := s.metrics.GetCurrentLoad()

    if currentLoad > 0.8 {
        // High load: reduce limits
        s.config.GlobalRPS = 80
        s.config.PerUserRPM = 50

        logger.WarnStructured("Rate limits reduced due to high load",
            "load", currentLoad,
            "new_global_rps", 80,
        )
    } else if currentLoad < 0.5 {
        // Low load: restore normal limits
        s.config.GlobalRPS = 100
        s.config.PerUserRPM = 60

        logger.InfoStructured("Rate limits restored",
            "load", currentLoad,
        )
    }
}

Time-based Adjustment:

func (s *RateLimiter) GetPeakHourLimits(hour int) RateLimits {
    // Peak hours: 9am-5pm UTC (reduce by 20%)
    if hour >= 9 && hour <= 17 {
        return RateLimits{
            GlobalRPS: 80,
            PerUserRPM: 48,
        }
    }

    // Off-peak: normal limits
    return RateLimits{
        GlobalRPS: 100,
        PerUserRPM: 60,
    }
}

Manual Override (Admin)

Admin Endpoint для Manual Adjustment:

// POST /api/admin/limits/adjust
type LimitAdjustRequest struct {
    LimitType string  `json:"limit_type"`  // "global", "faucet", "withdrawal"
    Value     float64 `json:"value"`
    Reason    string  `json:"reason"`
}

func (h *AdminHandler) AdjustLimits(w http.ResponseWriter, r *http.Request) {
    var req LimitAdjustRequest
    json.NewDecoder(r.Body).Decode(&req)

    // Validate admin
    adminEmail := r.Context().Value("admin_email").(string)

    // Apply adjustment
    err := h.limiter.SetLimit(req.LimitType, req.Value)
    if err != nil {
        http_helpers.SendError(w, http.StatusBadRequest, err.Error())
        return
    }

    // Audit log
    logger.InfoStructured("Rate limit manually adjusted",
        "admin", adminEmail,
        "limit_type", req.LimitType,
        "new_value", req.Value,
        "reason", req.Reason,
    )

    http_helpers.SendSuccess(w, map[string]interface{}{
        "message": "Limit adjusted successfully",
        "limit_type": req.LimitType,
        "new_value": req.Value,
    })
}

Business Metrics and KPIs

Key Performance Indicators

User Experience KPIs:

  • API Latency: <100ms average (target: 50ms)
  • Rate Limit Hit Rate: <5% of requests
  • Error Rate: <1% of total requests
  • Successful Transactions: >99% success rate

Business Health KPIs:

  • TVL Growth: 10-20% monthly
  • Active Users: 100-500 daily active wallets
  • Faucet Efficiency: 50-100 unique users per day
  • Withdrawal Approval Rate: >95% for small amounts

Operational KPIs:

  • Server Load: <80% capacity
  • Gas Costs: <$500/day for blockchain operations
  • Database Performance: <50ms query time
  • Uptime: >99.9%

Monitoring Dashboard

Prometheus Metrics:

var (
    apiRequestsTotal = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "api_requests_total",
            Help: "Total API requests",
        },
        []string{"endpoint", "status"},
    )

    rateLimitViolations = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "rate_limit_violations_total",
            Help: "Rate limit violations",
        },
        []string{"limit_type"},
    )

    withdrawalVolume = promauto.NewGaugeVec(
        prometheus.GaugeOpts{
            Name: "withdrawal_volume_usdc",
            Help: "Withdrawal volume in USDC",
        },
        []string{"period"}, // "hourly", "daily"
    )
)

Grafana Dashboard Panels:

  1. API Performance
  2. Requests per second (time series)
  3. Latency distribution (histogram)
  4. Error rate (gauge)

  5. Rate Limiting

  6. Violations by endpoint (bar chart)
  7. Top violators (table)
  8. Limit utilization (gauge)

  9. Business Metrics

  10. TVL growth (time series)
  11. Investment distribution (pie chart)
  12. Withdrawal volume (time series)

Alerting Strategy

Critical Alerts (PagerDuty)

High Priority:

alerts:
  - name: RateLimitViolationSpike
    condition: rate_limit_violations > 100 per minute
    action: Page on-call engineer
    severity: critical

  - name: WithdrawalLimitBreach
    condition: daily_withdrawals > $50,000
    action: Alert admin team
    severity: high

  - name: APILatencyHigh
    condition: avg_latency > 500ms for 5 minutes
    action: Page on-call engineer
    severity: critical

Medium Priority:

  - name: FaucetAbuseDetected
    condition: same_ip_multiple_wallets > 5
    action: Notify security team
    severity: medium

  - name: InvestmentCapApproaching
    condition: single_investment > $8,000
    action: Notify business team
    severity: medium

Email Notifications

Business Events:

  • New user registration (>10 per hour)
  • Large investment (>$5,000)
  • Withdrawal approval pending
  • Daily summary reports

System Events:

  • Rate limit adjustments
  • Configuration changes
  • Deployment events

Technical Implementation:

Business Decision Framework

When to Adjust Limits

Increase Limits When:

  • ✅ Server capacity underutilized (<50%)
  • ✅ User complaints about restrictiveness
  • ✅ Business growth requires higher throughput
  • ✅ No security incidents in past 30 days

Decrease Limits When:

  • ⚠️ Server load consistently >80%
  • ⚠️ Security incidents detected
  • ⚠️ Abuse patterns identified
  • ⚠️ Cost overruns (gas, infrastructure)

Temporary Adjustments:

  • 🔧 Marketing campaigns (higher traffic expected)
  • 🔧 Maintenance windows (reduce load)
  • 🔧 Security incidents (temporary lockdown)
  • 🔧 Testing new features (gradual rollout)

Approval Process

Permanent Limit Changes:

  1. Business proposal with rationale
  2. Technical feasibility review
  3. Security impact assessment
  4. Executive approval (for significant changes)
  5. Phased rollout with monitoring

Temporary Adjustments:

  1. Admin authorization
  2. Audit log entry
  3. Duration specification
  4. Automatic revert after period



📋 Метаданные

Версия: 2.4.82

Обновлено: 2025-10-21

Статус: Published