Разработка instant-exchange сервиса

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка instant-exchange сервиса
Средняя
~1-2 недели
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1062
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка KYC/AML для крипто-обменника

KYC (Know Your Customer) и AML (Anti-Money Laundering) — регуляторные требования, которые становятся обязательными для крипто-обменников в большинстве юрисдикций. FATF (Financial Action Task Force) и ЕС требуют верификацию для транзакций выше определённых порогов. Без KYC/AML обменник рискует блокировкой платёжных провайдеров и юридическими проблемами.

Архитектура KYC/AML системы

Уровни верификации (KYC Tiers)

type KYCTier int

const (
    TierUnverified  KYCTier = 0  // без верификации
    TierBasic       KYCTier = 1  // email + телефон
    TierStandard    KYCTier = 2  // ID документ + selfie
    TierEnhanced    KYCTier = 3  // + источник средств
)

type TierLimits struct {
    DailyLimitUSD   decimal.Decimal
    TxLimitUSD      decimal.Decimal
    RequiredKYC     KYCTier
}

var DefaultLimits = map[KYCTier]TierLimits{
    TierUnverified: {DailyLimitUSD: decimal.New(1000, 0),  TxLimitUSD: decimal.New(500, 0)},
    TierBasic:      {DailyLimitUSD: decimal.New(3000, 0),  TxLimitUSD: decimal.New(1500, 0)},
    TierStandard:   {DailyLimitUSD: decimal.New(15000, 0), TxLimitUSD: decimal.New(5000, 0)},
    TierEnhanced:   {DailyLimitUSD: decimal.New(100000, 0), TxLimitUSD: decimal.New(50000, 0)},
}

Интеграция с KYC провайдерами

Разрабатывать OCR документов и liveness detection самостоятельно — нецелесообразно. Используем KYC-as-a-Service:

Sumsub — популярный выбор для крипто. Проверка документов 80+ стран, liveness detection, база данных Watchlist:

import axios from 'axios';
import crypto from 'crypto';

class SumsubKYC {
  private appToken: string;
  private secretKey: string;
  
  private signRequest(method: string, url: string, body?: string): string {
    const ts = Math.floor(Date.now() / 1000).toString();
    const payload = ts + method.toUpperCase() + url + (body || '');
    const hmac = crypto.createHmac('sha256', this.secretKey).update(payload).digest('hex');
    return `${ts}:${hmac}`;
  }
  
  async createApplicant(externalUserId: string, levelName: string = 'basic-kyc-level') {
    const url = '/resources/applicants';
    const body = JSON.stringify({ externalUserId, levelName });
    
    const response = await axios.post(`https://api.sumsub.com${url}`, body, {
      headers: {
        'X-App-Token': this.appToken,
        'X-App-Access-Sig': this.signRequest('POST', url, body),
        'Content-Type': 'application/json',
      },
    });
    
    return response.data;  // applicantId
  }
  
  async generateAccessToken(applicantId: string): Promise<string> {
    const url = `/resources/accessTokens?userId=${applicantId}`;
    const response = await axios.post(`https://api.sumsub.com${url}`, '', {
      headers: {
        'X-App-Token': this.appToken,
        'X-App-Access-Sig': this.signRequest('POST', url),
      },
    });
    return response.data.token;
  }
  
  // Webhook от Sumsub при изменении статуса верификации
  async handleWebhook(payload: SumsubWebhook) {
    const { applicantId, reviewResult } = payload;
    
    switch (reviewResult.reviewAnswer) {
      case 'GREEN':  // верифицирован
        await this.updateUserKYCStatus(applicantId, 'verified');
        break;
      case 'RED':    // отклонён
        const reasons = reviewResult.rejectLabels;
        await this.updateUserKYCStatus(applicantId, 'rejected', reasons);
        break;
    }
  }
}

Frontend интеграция — Sumsub WebSDK встраивается в страницу верификации:

// React компонент верификации
import SumsubWebSdk from '@sumsub/websdk-react';

function KYCVerification({ userId }: { userId: string }) {
  const [accessToken, setAccessToken] = useState<string | null>(null);
  
  useEffect(() => {
    api.getKYCToken(userId).then(setAccessToken);
  }, [userId]);
  
  if (!accessToken) return <Loading />;
  
  return (
    <SumsubWebSdk
      accessToken={accessToken}
      expirationHandler={() => api.getKYCToken(userId)}
      onMessage={(type, payload) => {
        if (type === 'idCheck.applicantReviewComplete') {
          router.push('/kyc/pending');
        }
      }}
      onError={(error) => console.error('KYC error:', error)}
    />
  );
}

AML: мониторинг транзакций

Blockchain аналитика

Для крипто-транзакций нужно проверять происхождение средств. Отправка с миксера, darknet marketplace или sanctioned адреса — красный флаг.

Провайдеры blockchain analytics:

class ChainAnalysisAML {
  async checkAddress(address: string, currency: string): Promise<RiskScore> {
    const response = await this.client.post('/v2/users', {
      userId: `check-${Date.now()}`,
      currency,
      address,
    });
    
    return {
      risk: response.data.risk,          // "low" | "medium" | "high" | "severe"
      riskScore: response.data.riskScore, // 0-10
      exposures: response.data.exposures, // [{category, value}]
      flags: response.data.flags,         // конкретные причины риска
    };
  }
}

// Пример интеграции в процесс обмена
async function checkIncomingDeposit(txHash: string, fromAddress: string, currency: string) {
  const riskScore = await chainAnalysis.checkAddress(fromAddress, currency);
  
  if (riskScore.risk === 'severe') {
    await freezeTransaction(txHash, 'HIGH_RISK_ADDRESS');
    await notifyCompliance(txHash, riskScore);
    return false;
  }
  
  if (riskScore.risk === 'high') {
    await flagForReview(txHash, riskScore);
    // Продолжаем, но помечаем для ручной проверки
  }
  
  return true;
}

Elliptic и TRM Labs — альтернативы Chainalysis, с разными coverage и ценовой политикой.

Правила AML

type AMLRule struct {
    Name      string
    Check     func(tx Transaction, user User) AMLResult
    Action    AMLAction  // ALLOW, FLAG, BLOCK
}

var AMLRules = []AMLRule{
    {
        Name: "structuring_detection",
        Check: func(tx Transaction, user User) AMLResult {
            // Подозрительно: несколько транзакций чуть ниже порога KYC
            recentTxs := db.GetUserTransactions(user.ID, 24*time.Hour)
            totalValue := sum(recentTxs)
            
            // Несколько транзакций ~$990 подряд — попытка обойти KYC лимит
            if len(recentTxs) > 3 && totalValue > KYCThreshold*0.8 {
                return AMLResult{Risk: "high", Reason: "potential_structuring"}
            }
            return AMLResult{Risk: "low"}
        },
        Action: FLAG,
    },
    {
        Name: "high_risk_country",
        Check: func(tx Transaction, user User) AMLResult {
            highRiskCountries := []string{"KP", "IR", "SY", "CU"}
            if contains(highRiskCountries, user.Country) {
                return AMLResult{Risk: "severe", Reason: "sanctioned_jurisdiction"}
            }
            return AMLResult{Risk: "low"}
        },
        Action: BLOCK,
    },
    {
        Name: "pep_screening",
        Check: func(tx Transaction, user User) AMLResult {
            // PEP = Politically Exposed Person
            isPEP := pepDatabase.CheckName(user.FullName, user.DateOfBirth)
            if isPEP {
                return AMLResult{Risk: "medium", Reason: "pep_detected"}
            }
            return AMLResult{Risk: "low"}
        },
        Action: FLAG,
    },
}

Watchlist screening

Проверка по санкционным спискам (OFAC SDN, EU Consolidated List, UN Sanctions):

type WatchlistScreener struct {
    ofacList   []SanctionEntry
    euList     []SanctionEntry
    updateFreq time.Duration
}

func (ws *WatchlistScreener) ScreenName(name, dob string) []SanctionMatch {
    // Fuzzy matching — имена могут быть транслитерированы по-разному
    var matches []SanctionMatch
    
    for _, entry := range append(ws.ofacList, ws.euList...) {
        similarity := fuzzy.MatchScore(name, entry.Name)
        if similarity > 0.85 {  // 85% схожесть
            matches = append(matches, SanctionMatch{
                Entry:      entry,
                Similarity: similarity,
                ListSource: entry.ListSource,
            })
        }
    }
    return matches
}

SAR (Suspicious Activity Report)

При обнаружении подозрительной активности — обязательная подача SAR в регулятора (FinCEN в США, Росфинмониторинг в России):

type SAR struct {
    UserID          int64
    TransactionID   string
    Amount          decimal.Decimal
    Currency        string
    SuspiciousType  string   // structuring, layering, unusual_pattern, etc.
    Description     string
    SupportingDocs  []string
    FiledAt         time.Time
}

// Автоматическая генерация черновика SAR при алерте
func (c *ComplianceEngine) GenerateSARDraft(alert AMLAlert) *SAR {
    user := c.db.GetUser(alert.UserID)
    txHistory := c.db.GetTransactionHistory(alert.UserID, 90*24*time.Hour)
    
    return &SAR{
        UserID:         alert.UserID,
        TransactionID:  alert.TxID,
        SuspiciousType: alert.RuleTriggered,
        Description: fmt.Sprintf(
            "Пользователь %s (KYC: %s) совершил транзакцию на %s %s "+
            "с адреса с высоким риском (score: %.1f). "+
            "История транзакций за 90 дней: %d операций на сумму %s",
            user.FullName, user.KYCTier, alert.Amount, alert.Currency,
            alert.RiskScore, len(txHistory), totalVolume(txHistory),
        ),
    }
}

Compliance Dashboard

Для команды compliance — отдельный интерфейс:

  • Очередь на ручную проверку (high/medium risk транзакции)
  • История всех AML алертов с детализацией
  • Статистика: сколько транзакций заблокировано, сколько SAR подано
  • Управление AML правилами и порогами

Сроки и интеграции

Компонент Срок
KYC тиры + Sumsub интеграция 2–3 недели
AML правила + транзакционный мониторинг 2–3 недели
Blockchain analytics (Chainalysis/Elliptic) 1–2 недели
Watchlist screening 1–2 недели
Compliance dashboard 2–3 недели

Полная KYC/AML система для обменника: 2–3 месяца. Требует юридической консультации по целевым юрисдикциям для настройки порогов и требований.