Типова проблема на криптобіржі: трейдери скаржаться на високі та негнучкі комісії, партнери не бачать своїх відрахувань, а 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 кроків:
- Створіть комісійні групи в адмінці — задайте назву, maker/taker fee, відсоток реферальних відрахувань.
- Прив'яжіть групу до API-ключа через поле
FeeGroupID(див. модель вище). - Налаштуйте дозволи для ключа: spot_trade, withdraw, read_account тощо.
- Встановіть IP-whitelist — обмежте доступ лише з довірених адрес.
- Увімкніть 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 або на пошту. Отримайте консультацію по архітектурі та оцінку вартості протягом дня.







