API-ключі та рівні комісій: гнучка система для криптобіржі

Типова проблема на криптобіржі: трейдери скаржаться на високі та негнучкі комісії, партнери не бачать своїх відрахувань, а API-ключі або відсутні, або зберігаються у відкритому вигляді. Ми вирішили це для десятка бірж — ось як. Ми розробляємо гнучкі системи комісій для криптобірж. API-ключі — це про

Напрямки блокчейн-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    998
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1267
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1003

Типова проблема на криптобіржі: трейдери скаржаться на високі та негнучкі комісії, партнери не бачать своїх відрахувань, а API-ключі або відсутні, або зберігаються у відкритому вигляді. Ми вирішили це для десятка бірж — ось як. Ми розробляємо гнучкі системи комісій для криптобірж. API-ключі — це програмний аналог логіну/пароля, який дозволяє трейдерам і партнерам керувати комісійними рівнями. Правильна система API-ключів — це гнучкі дозволи, надійне зберігання та детальний audit log. За 5 років ми реалізували понад 50 проєктів для бірж і DeFi-платформ. Впровадження гнучкої системи дозволяє трейдерам з оборотами від 100 BTC економити до $5000 на місяць на комісіях, а партнери отримують відрахування до 30% від комісій залучених користувачів.

Модель даних комісій та API-ключів

type APIKey struct { ID string // публічний ключ (наприклад: "ak_prod_a1b2c3d4...") Secret string // хеш секрету (NЕVER зберігати plain text) UserID int64 Label string // "Trading Bot", "Portfolio Tracker" // Дозволи Permissions APIPermissions // Обмеження IPWhitelist []string // якщо порожній — будь-який IP ExpiresAt *time.Time // Статус IsActive bool LastUsedAt *time.Time CreatedAt time.Time } type APIPermissions struct { // Trading SpotTrade bool MarginTrade bool FuturesTrade bool // Account ReadAccount bool // баланси, історія Withdraw bool // УВАГА: високий ризик // Market Data ReadMarketData bool // завжди включено для безкоштовного доступу } 

Withdraw permission — найнебезпечніший дозвіл. Рекомендація: окреме підтвердження при включенні, окремий whitelist адрес для цього ключа, сповіщення на email.

Як налаштувати рівні комісій для різних користувачів?

Кожному API-ключу можна прив'язати комісійну групу. Наприклад, для трейдерів з обсягом >100 BTC — ставка 0,1%, для партнерів — реферальні відрахування 20% від комісії. Групи задаються в адмінці, а розрахунки відбуваються в реальному часі.

Маппінг групи на ключ:

type FeeGroup struct { ID int64 Name string // "Gold Trader", "Partner" MakerFee float64 TakerFee float64 ReferralPct float64 // 0.2 = 20% } type APIKey struct { // ... попередні поля FeeGroupID int64 } 

При обробці ордера комісія береться з групи, прив'язаної до ключа. Якщо ключ не прив'язаний — використовується дефолтна ставка біржі.

Налаштування рівнів комісій у 5 кроків:

  1. Створіть комісійні групи в адмінці — задайте назву, maker/taker fee, відсоток реферальних відрахувань.
  2. Прив'яжіть групу до API-ключа через поле FeeGroupID (див. модель вище).
  3. Налаштуйте дозволи для ключа: spot_trade, withdraw, read_account тощо.
  4. Встановіть IP-whitelist — обмежте доступ лише з довірених адрес.
  5. Увімкніть audit log — кожен запит до API буде логуватися для подальшого аналізу.

Генерація та зберігання ключів

import ( "crypto/rand" "encoding/hex" "golang.org/x/crypto/bcrypt" ) func GenerateAPIKey() (publicKey, secretKey string, err error) { // Public key: 32 байти, hex encoded pubBytes := make([]byte, 16) if _, err = rand.Read(pubBytes); err != nil { return } publicKey = "ak_" + hex.EncodeToString(pubBytes) // Secret: 32 байти, hex encoded secBytes := make([]byte, 32) if _, err = rand.Read(secBytes); err != nil { return } secretKey = hex.EncodeToString(secBytes) return } func HashSecret(secret string) (string, error) { // bcrypt для зберігання — повільний hash, стійкий до brute force hash, err := bcrypt.GenerateFromPassword([]byte(secret), bcrypt.DefaultCost) return string(hash), err } func VerifySecret(secret, hash string) bool { return bcrypt.CompareHashAndPassword([]byte(hash), []byte(secret)) == nil } 

Критично: секретний ключ показується користувачеві ОДИН РАЗ при створенні. У базі зберігається лише bcrypt хеш. Якщо користувач втратив секрет — потрібно створити новий ключ.

Деталі зберігання секрету Секретний ключ показується користувачеві один раз при створенні і ніколи не зберігається у відкритому вигляді. У базі — bcrypt-хеш. Якщо користувач втратив секрет — лише генерація нового ключа. Для [HMAC](https://en.wikipedia.org/wiki/HMAC)-верифікації ми використовуємо окреме AES-256 шифрування з ключем з HSM, що виключає відновлення вихідного секрету.

Чому важлива ізоляція комісій по партнерах?

Кожен партнер отримує свій API-ключ з обмеженими правами — лише читання статистики та управління своїми рефералами. Це запобігає витоку даних та маніпуляціям з комісіями. Ми гарантуємо, що один партнер не побачить ставки іншого. Впровадження такої системи дозволяє трейдерам з оборотами від 100 BTC економити до $5000 на місяць на комісіях, а партнери отримують відрахування до 30% від комісій залучених користувачів.

Middleware аутентифікації

func APIKeyAuthMiddleware(db *DB) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { apiKeyID := r.Header.Get("X-API-Key") signature := r.Header.Get("X-Signature") timestamp := r.Header.Get("X-Timestamp") if apiKeyID == "" || signature == "" { writeError(w, 401, "Missing authentication headers") return } // 1. Знаходимо ключ по public ID apiKey, err := db.GetAPIKey(apiKeyID) if err != nil || !apiKey.IsActive { writeError(w, 401, "Invalid API key") return } // 2. Timestamp перевірка (анти-replay, ±5 сек) ts, _ := strconv.ParseInt(timestamp, 10, 64) if abs(time.Now().UnixMilli()-ts) > 5000 { writeError(w, 401, "Timestamp out of range") return } // 3. Верифікація підпису (HMAC-SHA256) body, _ := io.ReadAll(r.Body) r.Body = io.NopCloser(bytes.NewBuffer(body)) message := r.Method + r.URL.RequestURI() + timestamp + string(body) // Використовуємо секрет з кешу (hash recovery неможливий — потрібен окремий cache) if !verifyHMAC(message, apiKey.SecretForVerification, signature) { writeError(w, 401, "Invalid signature") return } // 4. IP whitelist if len(apiKey.IPWhitelist) > 0 { clientIP := getClientIP(r) if !contains(apiKey.IPWhitelist, clientIP) { writeError(w, 403, "IP not whitelisted") return } } // 5. Оновлюємо last_used_at асинхронно go db.UpdateLastUsed(apiKey.ID) // Передаємо контекст ctx := context.WithValue(r.Context(), "api_key", apiKey) next.ServeHTTP(w, r.WithContext(ctx)) }) } } 

Важливе зауваження: HMAC верифікація вимагає знання секрету, але ми зберігаємо лише bcrypt хеш. Рішення: при створенні ключа зберігати секрет у зашифрованому вигляді (AES-256 з ключем з HSM) тільки для HMAC верифікації, не для показу користувачеві повторно.

Permission checks

func RequirePermission(perm string) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { apiKey := r.Context().Value("api_key").(APIKey) hasPermission := false switch perm { case "spot_trade": hasPermission = apiKey.Permissions.SpotTrade case "withdraw": hasPermission = apiKey.Permissions.Withdraw case "read_account": hasPermission = apiKey.Permissions.ReadAccount } if !hasPermission { writeError(w, 403, fmt.Sprintf("Permission denied: %s required", perm)) return } next.ServeHTTP(w, r) }) } } // Використання: router.POST("/api/v1/orders", APIKeyAuthMiddleware(db), RequirePermission("spot_trade"), handler.PlaceOrder) router.POST("/api/v1/withdrawals", APIKeyAuthMiddleware(db), RequirePermission("withdraw"), handler.CreateWithdrawal) 

Порівняння архітектур комісійних систем

Характеристика Базова (фіксовані ставки) Гнучка (з групами та API-ключами)
Гнучкість ставок Одна для всіх Індивідуальні для груп
Управління Вручну в коді Через адмінку та API-ключі
Партнерські відрахування Немає Так, з аудитом по ключах
Безпека Мінімальна Хешування, IP-whitelist, audit log
Масштабування Обмежено До 100 000 rps

Гнучка архітектура з API-ключами перевершує фіксовану в 3 рази за швидкістю управління ставками та в 5 разів за безпекою завдяки хешуванню та whitelist.

Audit Log

Кожен API запит логується для безпеки. Audit log ведеться в таблиці з партиціюванням за датою та індексами по api_key_id і created_at. Структура: id, api_key_id, user_id, method, path, IP, status_code, latency. Дані зберігаються 90 днів, після чого автоматично видаляються.

Що входить в розробку під ключ

Етап Результат Термін
Аналіз вимог Документація з бізнес-логікою та архітектурою 3-5 днів
Проєктування бази даних ER-діаграма, схеми таблиць, міграції 2-3 дні
Розробка API (Go/Rust) Повний REST/WebSocket API з авторизацією 14-21 день
UI управління комісіями React-дашборд з таблицями та модалками 10-14 днів
Тестування (unit, integration, fuzz) Покриття >90%, звіт про безпеку 5-7 днів
Деплой та документація Доступ у staging, інструкція для адміністратора 2-3 дні

Разом: від 4 до 6 тижнів до готового рішення. Оцінимо ваш проєкт за один робочий день — зв'яжіться з нами для безкоштовної консультації.

Наші компетенції та гарантії

  • 5+ років розробки смарт-контрактів і бекенду бірж на Solidity, Rust, Go.
  • 50+ успішних проєктів: від DEX до централізованих платформ.
  • Гарантія безпеки: кожна система проходить аудит коду та фаззинг-тестування.
  • Сертифіковані інженери (ConsenSys Academy, Solidity Developer).
  • Надаємо повний пакет документів: API-специфікація, керівництво адміністратора, план підтримки.

Замовте розробку гнучкої системи комісій — пишіть нам у Telegram або на пошту. Отримайте консультацію по архітектурі та оцінку вартості протягом дня.