Разработка системы конвертации крипто в фиат при оплате картой

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы конвертации крипто в фиат при оплате картой
Сложная
~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
    1058
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы конвертации крипто в фиат при оплате картой

Пользователь держит USDC, хочет заплатить картой в обычном магазине. В момент транзакции по карте: USDC списывается с крипто-баланса, конвертируется в USD/EUR, и процессинг карты проходит как обычная фиатная оплата. С точки зрения терминала — обычная Visa/Mastercard транзакция. Это не теория, это работающая архитектура за такими продуктами как Crypto.com Card, Binance Card, Coinbase Card.

Построить такую систему с нуля — значит решить несколько независимых инженерных задач: эмиссия карт, real-time конвертация, BIN спонсорство и лицензирование, compliance. Каждая из них — отдельный трек работы.

Архитектурные компоненты

BIN спонсорство и эмиссия карт

BIN (Bank Identification Number) — первые 6–8 цифр карты, определяют эмитента. Без собственной банковской лицензии работают через BIN sponsor: лицензированный банк-эмитент, который выпускает карты под своим BIN, но по вашей логике. Вы — program manager.

Основные BIN sponsors и card issuing платформы:

Провайдер Сети Регионы API
Marqeta Visa, Mastercard US, EU, UK REST + Webhooks
Galileo Visa US, LATAM REST
Stripe Issuing Visa, Mastercard US, EU REST
Moorwand Mastercard EU/EEA REST
Railsbank (Railsr) Visa, Mastercard EU, UK REST

Marqeta — наиболее распространён в crypto-card проектах (Coinbase Card использует Marqeta). Just-In-Time (JIT) funding — ключевая фича: Marqeta вызывает ваш webhook в момент авторизации, вы подтверждаете или отклоняете транзакцию с конвертацией в реальном времени.

Just-In-Time funding: логика в реальном времени

JIT — сердце архитектуры. Схема:

Карточный терминал → Visa/MC network → Marqeta → ваш JIT webhook (< 2 сек) → 
[вы конвертируете крипто → фиат] → ответ approve/decline → Marqeta → терминал

Время ответа на JIT webhook: строго менее 2 секунд. Это аппаратный таймаут карточных сетей. Пропустил — транзакция автоматически отклоняется.

// JIT webhook handler
import { FastifyRequest, FastifyReply } from 'fastify';
import { MarqetaJITPayload } from './types';

export async function handleJITFunding(
  req: FastifyRequest<{ Body: MarqetaJITPayload }>,
  reply: FastifyReply,
) {
  const startTime = Date.now();
  const { transaction, card_token } = req.body;
  
  try {
    // 1. Идентификация пользователя по card_token
    const user = await userService.findByCardToken(card_token);
    if (!user) return reply.send({ result: 'DECLINED', memo: 'USER_NOT_FOUND' });
    
    // 2. Получаем сумму в фиат валюте
    const { currency_code, amount } = transaction;
    
    // 3. Рассчитываем крипто-сумму для списания
    const cryptoAmount = await pricingService.fiatToCrypto({
      fiatAmount: amount,
      fiatCurrency: currency_code,
      cryptoCurrency: user.primaryAsset, // USDC, BTC, ETH
    });
    
    // 4. Проверяем баланс
    const balance = await walletService.getBalance(user.id, user.primaryAsset);
    if (balance < cryptoAmount.amountWithFee) {
      return reply.send({ result: 'DECLINED', memo: 'INSUFFICIENT_FUNDS' });
    }
    
    // 5. Резервируем крипто (hold, не списываем сразу)
    const holdId = await walletService.createHold({
      userId: user.id,
      asset: user.primaryAsset,
      amount: cryptoAmount.amountWithFee,
      expiresAt: new Date(Date.now() + 30 * 60 * 1000), // 30 мин
      transactionRef: transaction.token,
    });
    
    // Проверяем что укладываемся в таймаут
    if (Date.now() - startTime > 1500) {
      await walletService.releaseHold(holdId);
      return reply.send({ result: 'DECLINED', memo: 'TIMEOUT' });
    }
    
    return reply.send({
      result: 'APPROVED',
      funding: { amount, currency_code },
    });
    
  } catch (error) {
    logger.error({ error, transaction }, 'JIT funding error');
    return reply.send({ result: 'DECLINED', memo: 'INTERNAL_ERROR' });
  }
}

Hold механизм критически важен. Авторизация карты и фактическое списание (clearing) — разные события. Между ними может пройти до 5 дней (особенно для оффлайн транзакций). Hold резервирует крипто-баланс, реальная конвертация происходит при clearing.

Конвертация крипто → фиат

В момент clearing нужно реально конвертировать криптовалюту в фиат для пополнения карточного счёта. Два подхода:

Pre-funded fiat float. Вы держите фиатный баланс на счету BIN-спонсора. При clearing — списываете из float, параллельно конвертируете крипто и пополняете float. Преимущество: декоуплинг от скорости крипто-конвертации. Недостаток: нужен significant рабочий капитал (float).

Real-time liquidation. При clearing немедленно продаёте крипто через CEX или liquidity провайдера. Деньги идут напрямую на карточный счёт.

// Clearing handler (вызывается webhook от Marqeta при settlement)
export async function handleClearing(clearingEvent: MarqetaClearingEvent) {
  const { original_jit_funding_token, clearing_amount, currency_code } = clearingEvent;
  
  // Найти original hold по JIT token
  const hold = await holdRepository.findByTransactionRef(original_jit_funding_token);
  
  // Рассчитать финальную крипто-сумму (курс мог измениться)
  const finalCryptoAmount = await pricingService.fiatToCrypto({
    fiatAmount: clearing_amount,
    fiatCurrency: currency_code,
    cryptoCurrency: hold.asset,
    slippage: 0.005, // 0.5% slippage tolerance
  });
  
  // Выполнить конвертацию через liquidity провайдера
  const conversion = await liquidityService.convert({
    fromAsset: hold.asset,
    toFiat: currency_code,
    amount: finalCryptoAmount.amount,
    destinationAccount: BIN_SPONSOR_ACCOUNT_ID,
  });
  
  // Финальное списание с крипто-баланса пользователя
  await walletService.finalizeConversion({
    userId: hold.userId,
    holdId: hold.id,
    cryptoAmount: finalCryptoAmount.amount,
    fiatAmount: clearing_amount,
    conversionRate: conversion.rate,
    fee: finalCryptoAmount.fee,
  });
  
  // Уведомление пользователю
  await notificationService.sendPushNotification(hold.userId, {
    type: 'card_payment_settled',
    amount: clearing_amount,
    currency: currency_code,
    cryptoSpent: finalCryptoAmount.amount,
    cryptoAsset: hold.asset,
    merchantName: clearingEvent.merchant_name,
  });
}

Liquidity providers и FX

Для конвертации крипто → фиат в автоматическом режиме:

CEX через API: Binance, Coinbase Prime, Kraken. Подходит для средних объёмов. Риск: API latency, биржа может быть недоступна. Нужен failover на второй provider.

OTC / Prime Brokers: Galaxy Digital, FalconX, Cumberland. Для крупных объёмов ($100k+) дают лучшие ставки, работают через API или RFQ (Request for Quote). Минимальная сделка обычно $10k–$50k — не подходит для розничных транзакций напрямую, но хорошо для пополнения float.

Embedded liquidity: интеграция с Fireblocks Settlement Network или B2C2. Программный доступ, фиксированные спреды, enterprise SLA.

// Абстракция для multi-provider liquidity
interface LiquidityProvider {
  getQuote(params: QuoteParams): Promise<Quote>;
  executeConversion(quoteId: string): Promise<ConversionResult>;
  getBalance(currency: string): Promise<Decimal>;
}

class LiquidityRouter implements LiquidityProvider {
  private providers: LiquidityProvider[];
  
  async getQuote(params: QuoteParams): Promise<Quote> {
    // Запрашиваем котировки у всех провайдеров параллельно
    const quotes = await Promise.allSettled(
      this.providers.map(p => p.getQuote(params))
    );
    
    // Выбираем лучшую котировку (по rate с учётом fee)
    const validQuotes = quotes
      .filter(q => q.status === 'fulfilled')
      .map(q => (q as PromiseFulfilledResult<Quote>).value);
    
    return validQuotes.sort((a, b) => b.netRate - a.netRate)[0];
  }
}

Compliance и KYC/AML

Обязательные компоненты

KYC (Know Your Customer). Обязателен для карточного продукта. Минимум: проверка личности (паспорт/ID), proof of address, OFAC screening. Провайдеры: Sumsub, Jumio, Onfido. Уровни верификации влияют на лимиты (базовый: $500/день, enhanced: $10,000/день).

Transaction monitoring. AML требования: мониторинг подозрительных паттернов, structuring detection (дробление на малые суммы), unusual merchant categories. Провайдеры: Chainalysis, Elliptic для крипто-стороны; ComplyAdvantage для фиат-стороны.

Лицензирование. В EU: EMI лицензия (Electronic Money Institution) или партнёрство с лицензированным EMI. В US: Money Transmitter Licence в каждом штате, или партнёрство с licensed issuer. Получение лицензии: 6–18 месяцев, $100k–$500k. Альтернатива: работа под лицензией BIN-спонсора (быстрее, но ограниченнее).

Налоговые последствия для пользователей

Конвертация крипто при оплате картой — taxable event во многих юрисдикциях (US, UK, большинство EU). Система должна:

// Генерация tax-lot записей для каждой конвертации
interface TaxLot {
  userId: string;
  asset: string;
  acquiredDate: Date;
  acquiredCostBasis: Decimal; // цена покупки в фиат
  disposedDate: Date;
  disposalProceeds: Decimal;  // сумма транзакции по карте
  gainLoss: Decimal;          // прибыль/убыток
  transactionRef: string;
}

Предоставление tax report (1099 в US, аналогичное в EU) — не опционально для лицензированных операций.

Карточные механики: физические и виртуальные

Виртуальные карты — выпускаются мгновенно через Marqeta API, используются для Apple Pay / Google Pay. Приоритет для быстрого MVP.

Физические карты — нужен card personalisation bureau (Matica, Entrust). Срок производства: 5–14 дней. Delivery tracking интеграция.

// Marqeta: создание виртуальной карты
const card = await marqeta.cards.create({
  user_token: marqetaUserId,
  card_product_token: CARD_PRODUCT_TOKEN,
  fulfillment: { shipping: { method: 'GROUND' } }, // для физических
});

// Provisioning в Apple Pay / Google Pay
const tokenizationData = await marqeta.digitalWallets.provisionApplePay({
  card_token: card.token,
  provisioning_payload: applePayProvisioningRequest,
  certificates: [...],
});

Freeze/unfreeze — пользователь должен мочь мгновенно заморозить карту через приложение. Marqeta API: cards/{token}/transitions с state: SUSPENDED.

Этапы и сроки разработки

Фаза Содержание Срок
Setup & licensing Выбор BIN-спонсора, юридическая структура, KYC провайдер 4–8 нед
Core wallet Крипто-кошелёк, балансы, holds 3–4 нед
JIT funding Webhook, pricing engine, hold механизм 3–4 нед
Liquidity FX интеграция, конвертация при clearing 2–3 нед
Card management Виртуальные карты, Marqeta integration 3–4 нед
Compliance AML мониторинг, tax reporting 3–4 нед
Physical cards Производство, delivery 2–3 нед
Testing & launch End-to-end, UAT, soft launch 3–4 нед

Реалистичный срок от нуля до рабочего продукта с виртуальными картами: 6–9 месяцев. Основные блокеры — legal/compliance onboarding с BIN-спонсором и KYC провайдером, а не разработка.