Типичная проблема на криптобирже: трейдеры жалуются на высокие и негибкие комиссии, партнёры не видят своих отчислений, а API-ключи либо отсутствуют, либо хранятся в открытом виде. Мы решили это для десятка бирж — вот как. Мы разрабатываем гибкие системы комиссий для криптобирж. API-ключи — это программный аналог логина/пароля, который позволяет трейдерам и партнёрам управлять комиссионными уровнями. Правильная система API-ключей — это гибкие разрешения, надёжное хранение и детальный audit log. За 5 лет мы реализовали более 50 проектов для бирж и DeFi-платформ. Внедрение гибкой системы позволяет трейдерам с оборотами от 100 BTC экономить до $5000 в месяц на комиссиях, а партнёры получают отчисления до 30% от комиссий привлечённых пользователей.
Модель данных комиссий и API-ключей
type APIKey struct {
ID string // публичный ключ (например: "ak_prod_a1b2c3d4...")
Secret string // хэш секрета (NEVER хранить 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 или на почту. Получите консультацию по архитектуре и оценку стоимости в течение дня.







