trading-platform/docs/02-definicion-modulos/OQI-005-payments-stripe/requerimientos/RF-PAY-007-crypto.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
Changes include:
- Updated architecture documentation
- Enhanced module definitions (OQI-001 to OQI-008)
- ML integration documentation updates
- Trading strategies documentation
- Orchestration and inventory updates
- Docker configuration updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:33:35 -06:00

24 KiB

id title type status priority epic project version created_date updated_date
RF-PAY-007 Sistema de Depositos y Retiros en Criptomonedas Requirement Draft Alta OQI-005 trading-platform 1.0.0 2026-01-04 2026-01-04

RF-PAY-007: Sistema de Depositos y Retiros en Criptomonedas

Version: 1.0.0 Fecha: 2026-01-04 Estado: Draft Prioridad: P1 (Alta) Story Points: 13 Epica: OQI-005


Descripcion

El sistema debe permitir a los usuarios realizar depositos y retiros utilizando criptomonedas, integrando con proveedores de pago crypto como Coinbase Commerce o BitPay, soportando multiples monedas y redes blockchain, con conversion automatica a USD para mantener el balance del wallet interno.


Objetivo de Negocio

  • Expandir opciones de pago para usuarios globales sin acceso bancario tradicional
  • Atraer segmento crypto-nativo con preferencia por pagos descentralizados
  • Reducir costos de transaccion en mercados internacionales
  • Ofrecer alternativa a usuarios con restricciones bancarias
  • Habilitar depositos anonimos (hasta limite KYC)

Casos de Uso

  1. Deposito BTC: Usuario envia 0.01 BTC a direccion unica y recibe $450 USD en wallet
  2. Deposito USDT: Usuario envia 100 USDT (TRC-20) y recibe $100 USD en wallet
  3. Retiro ETH: Usuario solicita retiro de $200 USD y recibe 0.08 ETH en su wallet externo
  4. Verificacion KYC: Usuario completa KYC para habilitar retiros crypto
  5. Monitoreo de Confirmaciones: Sistema muestra progreso de confirmaciones on-chain

Monedas y Redes Soportadas

Moneda Simbolo Redes Soportadas Confirmaciones Requeridas
Bitcoin BTC Bitcoin Network 3 confirmaciones
Ethereum ETH Ethereum Mainnet 12 confirmaciones
Tether USDT ERC-20, TRC-20 12 (ERC-20), 20 (TRC-20)
USD Coin USDC ERC-20, Polygon 12 (ERC-20), 30 (Polygon)

Requisitos Funcionales

RF-PAY-007.1: Generacion de Direcciones Unicas

DEBE:

  1. Generar direccion unica de deposito por usuario por moneda/red
  2. Asociar direccion a userId en tabla crypto_addresses
  3. Mostrar QR code y direccion copiable en UI
  4. Detectar red correcta segun direccion (ERC-20 vs TRC-20)
  5. Reutilizar direccion para depositos futuros del mismo usuario

Modelo de datos:

@Entity({ name: 'crypto_addresses', schema: 'billing' })
class CryptoAddress {
  id: string;              // UUID
  userId: string;          // FK a users
  currency: string;        // BTC, ETH, USDT
  network: string;         // bitcoin, ethereum, tron, polygon
  address: string;         // Direccion de deposito unica
  derivationPath?: string; // Para HD wallets
  isActive: boolean;       // true
  createdAt: Date;
  updatedAt: Date;
}

RF-PAY-007.2: Deteccion y Procesamiento de Depositos

DEBE:

  1. Monitorear direcciones via webhooks del proveedor (Coinbase/BitPay)
  2. Detectar transacciones entrantes en tiempo real
  3. Mostrar estado "Pendiente" con contador de confirmaciones
  4. Convertir a USD al alcanzar confirmaciones requeridas
  5. Acreditar al wallet interno del usuario

Flujo de Confirmaciones:

0 confirmaciones  → Estado: DETECTED (detectado)
1 confirmacion    → Estado: PENDING (pendiente)
3+ confirmaciones → Estado: CONFIRMED (BTC)
12+ confirmaciones → Estado: CONFIRMED (ETH/ERC-20)
20+ confirmaciones → Estado: CONFIRMED (TRC-20)

RF-PAY-007.3: Conversion Automatica a USD

DEBE:

  1. Obtener tasa de cambio en tiempo real al momento de confirmacion
  2. Aplicar spread de 0.5% sobre tasa de mercado
  3. Convertir monto crypto a USD equivalente
  4. Acreditar USD al wallet interno
  5. Registrar tasa de cambio usada en transaccion

Calculo:

USD_Amount = Crypto_Amount * Market_Rate * (1 - 0.005)

Ejemplo:
0.01 BTC * $45,000/BTC * 0.995 = $447.75 USD

RF-PAY-007.4: Sistema de Retiros Crypto

DEBE:

  1. Permitir retiros a wallet externo del usuario
  2. Solicitar direccion de destino y red
  3. Validar formato de direccion segun red
  4. Calcular monto crypto segun tasa actual
  5. Procesar retiro via API del proveedor
  6. Enviar notificacion con TX hash

Validaciones:

  • KYC aprobado obligatorio para retiros
  • Monto minimo: $50 USD equivalente
  • Monto maximo: $10,000 USD por transaccion
  • Limite diario: $50,000 USD
  • Cooldown: 24h para nuevas direcciones

RF-PAY-007.5: Verificacion KYC para Retiros

DEBE:

  1. Bloquear retiros crypto hasta completar KYC
  2. Solicitar documentos: ID gubernamental + selfie + comprobante domicilio
  3. Verificar via proveedor KYC (Jumio, Onfido)
  4. Aprobar/rechazar en maximo 24 horas
  5. Permitir retiros una vez aprobado

Niveles KYC:

Nivel Requisitos Limite Retiro
Ninguno Solo email $0 (sin retiros)
Basico ID + Selfie $1,000/dia
Verificado ID + Selfie + Domicilio $50,000/dia

RF-PAY-007.6: Webhooks de Confirmaciones

DEBE:

  1. Recibir webhooks de Coinbase Commerce/BitPay
  2. Validar firma HMAC del webhook
  3. Actualizar estado de transaccion en BD
  4. Emitir evento interno para procesamiento
  5. Responder 200 OK inmediatamente (procesamiento async)

Eventos a manejar:

  • charge:created - Transaccion detectada
  • charge:pending - Esperando confirmaciones
  • charge:confirmed - Confirmaciones completas
  • charge:failed - Transaccion fallida/expirada

Modelo de Datos

Tabla: crypto_transactions

@Entity({ name: 'crypto_transactions', schema: 'billing' })
class CryptoTransaction {
  id: string;                    // UUID
  userId: string;                // FK a users
  walletId: string;              // FK a wallets
  type: 'deposit' | 'withdrawal';
  status: CryptoTxStatus;        // detected, pending, confirmed, failed, expired
  currency: string;              // BTC, ETH, USDT
  network: string;               // bitcoin, ethereum, tron, polygon
  cryptoAmount: Decimal;         // Monto en crypto
  usdAmount: Decimal;            // Monto en USD (convertido)
  exchangeRate: Decimal;         // Tasa de cambio usada
  fromAddress?: string;          // Direccion origen (depositos)
  toAddress: string;             // Direccion destino
  txHash?: string;               // Hash de transaccion on-chain
  confirmations: number;         // Confirmaciones actuales
  requiredConfirmations: number; // Confirmaciones requeridas
  providerRef: string;           // ID en Coinbase/BitPay
  fee?: Decimal;                 // Fee de red
  metadata?: object;
  createdAt: Date;
  confirmedAt?: Date;
  updatedAt: Date;
}

enum CryptoTxStatus {
  DETECTED = 'detected',
  PENDING = 'pending',
  CONFIRMED = 'confirmed',
  FAILED = 'failed',
  EXPIRED = 'expired'
}

Flujo de Deposito Crypto

+-------------+     +-------------+     +-------------+     +-------------+     +-------------+
|   Usuario   |     |  Frontend   |     |   Backend   |     |  Coinbase   |     | Blockchain  |
+------+------+     +------+------+     +------+------+     +------+------+     +------+------+
       |                   |                   |                   |                   |
       | Selecciona        |                   |                   |                   |
       | "Depositar BTC"   |                   |                   |                   |
       |------------------>|                   |                   |                   |
       |                   |                   |                   |                   |
       |                   | GET /crypto/      |                   |                   |
       |                   | address?currency= |                   |                   |
       |                   | BTC&network=bitcoin|                  |                   |
       |                   |------------------>|                   |                   |
       |                   |                   |                   |                   |
       |                   |                   | Get/Create        |                   |
       |                   |                   | unique address    |                   |
       |                   |                   |------------------>|                   |
       |                   |                   |<------------------|                   |
       |                   |                   |                   |                   |
       |                   |<------------------|                   |                   |
       |                   | { address, qrCode }                   |                   |
       |                   |                   |                   |                   |
       |<------------------|                   |                   |                   |
       | Muestra QR +      |                   |                   |                   |
       | direccion         |                   |                   |                   |
       |                   |                   |                   |                   |
       | Usuario envia     |                   |                   |                   |
       | 0.01 BTC desde    |                   |                   |                   |
       | su wallet externo |                   |                   |                   |
       |---------------------------------------------------------->|----------------->|
       |                   |                   |                   |                   |
       |                   |                   |                   | TX broadcast     |
       |                   |                   |                   |<-----------------|
       |                   |                   |                   |                   |
       |                   |                   |<------------------|                   |
       |                   |                   | Webhook:          |                   |
       |                   |                   | charge:created    |                   |
       |                   |                   |                   |                   |
       |                   |                   | Create            |                   |
       |                   |                   | crypto_transaction|                   |
       |                   |                   | status: DETECTED  |                   |
       |                   |                   |                   |                   |
       |<------------------|-------------------|                   |                   |
       | Push: "Deposito   |                   |                   |                   |
       | detectado, 0/3    |                   |                   |                   |
       | confirmaciones"   |                   |                   |                   |
       |                   |                   |                   |                   |
       |                   |                   |<------------------|                   |
       |                   |                   | Webhook:          |                   |
       |                   |                   | charge:confirmed  |                   |
       |                   |                   | (3 confirmations) |                   |
       |                   |                   |                   |                   |
       |                   |                   | BEGIN TX          |                   |
       |                   |                   | 1. Get exchange   |                   |
       |                   |                   |    rate           |                   |
       |                   |                   | 2. Convert to USD |                   |
       |                   |                   | 3. Credit wallet  |                   |
       |                   |                   | 4. Update status  |                   |
       |                   |                   | COMMIT TX         |                   |
       |                   |                   |                   |                   |
       |<------------------|-------------------|                   |                   |
       | Push: "Deposito   |                   |                   |                   |
       | confirmado!       |                   |                   |                   |
       | +$447.75 USD"     |                   |                   |                   |
       |                   |                   |                   |                   |

Flujo de Retiro Crypto

+-------------+     +-------------+     +-------------+     +-------------+
|   Usuario   |     |  Frontend   |     |   Backend   |     |  Coinbase   |
+------+------+     +------+------+     +------+------+     +------+------+
       |                   |                   |                   |
       | Click "Retirar    |                   |                   |
       | a Crypto"         |                   |                   |
       |------------------>|                   |                   |
       |                   |                   |                   |
       |                   | GET /user/kyc     |                   |
       |                   |------------------>|                   |
       |                   |<------------------|                   |
       |                   | { status:         |                   |
       |                   |   "verified" }    |                   |
       |                   |                   |                   |
       | Ingresa:          |                   |                   |
       | - $200 USD        |                   |                   |
       | - BTC             |                   |                   |
       | - bc1q...xyz      |                   |                   |
       |------------------>|                   |                   |
       |                   |                   |                   |
       |                   | POST /crypto/     |                   |
       |                   | withdraw          |                   |
       |                   | { amount: 200,    |                   |
       |                   |   currency: "BTC",|                   |
       |                   |   address: "bc1q..|                   |
       |                   |   network: "bitcoin"}                 |
       |                   |------------------>|                   |
       |                   |                   |                   |
       |                   |                   | 1. Validate KYC   |
       |                   |                   | 2. Validate addr  |
       |                   |                   | 3. Check limits   |
       |                   |                   | 4. Get rate       |
       |                   |                   | 5. Calculate BTC  |
       |                   |                   |    ($200 = 0.0044)|
       |                   |                   |                   |
       |                   |                   | 6. Debit wallet   |
       |                   |                   | 7. Create pending |
       |                   |                   |    withdrawal     |
       |                   |                   |                   |
       |                   |                   | 8. Request payout |
       |                   |                   |------------------>|
       |                   |                   |<------------------|
       |                   |                   | { payoutId }      |
       |                   |                   |                   |
       |                   |<------------------|                   |
       |                   | { status: "pending",                  |
       |                   |   cryptoAmount: 0.0044,               |
       |                   |   estimatedTime: "30min" }            |
       |                   |                   |                   |
       |<------------------|                   |                   |
       | "Retiro procesando|                   |                   |
       | 0.0044 BTC a      |                   |                   |
       | bc1q...xyz"       |                   |                   |
       |                   |                   |                   |
       |                   |                   |<------------------|
       |                   |                   | Webhook:          |
       |                   |                   | payout:completed  |
       |                   |                   | txHash: 0xabc...  |
       |                   |                   |                   |
       |<------------------|-------------------|                   |
       | Email: "Retiro    |                   |                   |
       | completado!       |                   |                   |
       | TX: 0xabc..."     |                   |                   |
       |                   |                   |                   |

Reglas de Negocio

RN-001: Limites de Deposito

Limite Valor
Deposito minimo $10 USD equivalente
Deposito maximo por transaccion $50,000 USD equivalente
Deposito maximo diario $100,000 USD equivalente
Sin limite mensual -

RN-002: Limites de Retiro

Limite Sin KYC KYC Basico KYC Verificado
Por transaccion $0 $1,000 $10,000
Diario $0 $1,000 $50,000
Mensual $0 $5,000 $200,000

RN-003: Fees y Spreads

Concepto Valor
Deposito GRATIS (usuario paga fee de red)
Spread conversion 0.5%
Retiro fee fijo $5 USD
Retiro fee red Variable (estimado mostrado)

RN-004: Expiracion de Transacciones

  • Depositos no confirmados expiran en 72 horas
  • Retiros pendientes expiran en 24 horas
  • Transacciones expiradas se marcan como EXPIRED
  • Fondos de retiros expirados se devuelven al wallet

RN-005: Direcciones de Retiro

  • Primera vez: direccion debe esperar 24h antes de usar
  • Direcciones usadas previamente: retiro inmediato
  • Maximo 5 direcciones guardadas por moneda
  • Cambio de direccion requiere 2FA

Integracion con Proveedores

Coinbase Commerce (Recomendado)

// Configuracion
const coinbase = new CoinbaseCommerce({
  apiKey: process.env.COINBASE_API_KEY,
  webhookSecret: process.env.COINBASE_WEBHOOK_SECRET
});

// Crear charge para deposito
const charge = await coinbase.charges.create({
  name: `Deposito ${userId}`,
  description: 'Deposito a wallet trading-platform',
  pricing_type: 'no_price', // Usuario decide monto
  metadata: {
    userId,
    walletId,
    type: 'deposit'
  }
});

BitPay (Alternativa)

// Configuracion
const bitpay = new BitPayClient({
  token: process.env.BITPAY_TOKEN,
  environment: 'prod'
});

// Crear invoice para deposito
const invoice = await bitpay.createInvoice({
  price: 0, // Variable
  currency: 'USD',
  buyer: { email: user.email },
  posData: JSON.stringify({ userId, walletId })
});

API Endpoints

Depositos

GET /api/v1/crypto/deposit/address:
  description: Obtener direccion de deposito
  query:
    currency: string (BTC, ETH, USDT)
    network: string (bitcoin, ethereum, tron, polygon)
  response:
    address: string
    qrCode: string (base64)
    currency: string
    network: string
    minDeposit: number

GET /api/v1/crypto/deposit/status/{txId}:
  description: Estado de deposito
  response:
    status: string
    confirmations: number
    requiredConfirmations: number
    cryptoAmount: number
    usdAmount: number
    txHash: string

Retiros

POST /api/v1/crypto/withdraw:
  description: Solicitar retiro crypto
  body:
    amount: number (USD)
    currency: string
    network: string
    address: string
  response:
    withdrawalId: string
    cryptoAmount: number
    exchangeRate: number
    fee: number
    estimatedTime: string

GET /api/v1/crypto/withdraw/{id}:
  description: Estado de retiro
  response:
    status: string
    txHash: string
    cryptoAmount: number
    address: string

Direcciones Guardadas

GET /api/v1/crypto/addresses:
  description: Listar direcciones de retiro guardadas

POST /api/v1/crypto/addresses:
  description: Agregar direccion de retiro
  body:
    currency: string
    network: string
    address: string
    label: string

DELETE /api/v1/crypto/addresses/{id}:
  description: Eliminar direccion guardada

Seguridad

Validacion de Direcciones

function validateCryptoAddress(address: string, network: string): boolean {
  switch (network) {
    case 'bitcoin':
      // Legacy (1...), SegWit (3...), Native SegWit (bc1...)
      return /^(1|3)[a-zA-Z0-9]{25,34}$|^bc1[a-z0-9]{39,59}$/.test(address);
    case 'ethereum':
    case 'polygon':
      // ERC-20 format
      return /^0x[a-fA-F0-9]{40}$/.test(address);
    case 'tron':
      // TRC-20 format
      return /^T[a-zA-Z0-9]{33}$/.test(address);
    default:
      return false;
  }
}

Prevencion de Fraude

  • Monitorear patrones de deposito/retiro inusuales
  • Bloquear retiros inmediatos post-deposito (1h cooldown)
  • Verificar consistencia de direcciones (no reutilizar entre usuarios)
  • Alerta si retiro > 50% del deposito reciente
  • Require 2FA para retiros > $1,000

Hot/Cold Wallet

  • Hot wallet: maximo 10% de fondos totales
  • Cold wallet: 90% de fondos en almacenamiento offline
  • Rebalanceo automatico diario
  • Multi-sig para cold wallet (3 de 5 firmas)

Manejo de Errores

Error Codigo Mensaje Usuario
KYC no verificado 403 Completa la verificacion de identidad para retirar
Direccion invalida 400 La direccion ingresada no es valida para {network}
Limite excedido 400 Excedes el limite de ${limit}/dia. Intenta manana.
Saldo insuficiente 400 Saldo insuficiente. Disponible: ${balance}
Red no soportada 400 La red {network} no esta soportada para {currency}
Direccion muy nueva 400 Nueva direccion. Espera 24h antes de usarla.
Proveedor no disponible 503 Servicio temporalmente no disponible. Intenta mas tarde.

Webhooks Recibidos

Evento Accion
charge:created Crear crypto_transaction con status DETECTED
charge:pending Actualizar confirmaciones
charge:confirmed Convertir a USD, acreditar wallet
charge:failed Marcar como FAILED
payout:completed Actualizar retiro con txHash
payout:failed Revertir debito de wallet

Configuracion Requerida

# Coinbase Commerce
COINBASE_API_KEY=xxx
COINBASE_WEBHOOK_SECRET=xxx

# BitPay (alternativo)
BITPAY_TOKEN=xxx
BITPAY_WEBHOOK_SECRET=xxx

# Limites
CRYPTO_DEPOSIT_MIN_USD=10
CRYPTO_DEPOSIT_MAX_USD=50000
CRYPTO_DEPOSIT_MAX_DAILY_USD=100000
CRYPTO_WITHDRAWAL_MIN_USD=50
CRYPTO_WITHDRAWAL_FEE_USD=5
CRYPTO_CONVERSION_SPREAD=0.005

# Confirmaciones
CRYPTO_CONFIRMATIONS_BTC=3
CRYPTO_CONFIRMATIONS_ETH=12
CRYPTO_CONFIRMATIONS_TRC20=20
CRYPTO_CONFIRMATIONS_POLYGON=30

# Seguridad
CRYPTO_NEW_ADDRESS_COOLDOWN_HOURS=24
CRYPTO_POST_DEPOSIT_COOLDOWN_HOURS=1

Criterios de Aceptacion

  • Usuario puede obtener direccion unica de deposito por moneda/red
  • QR code se genera correctamente para cada direccion
  • Depositos se detectan via webhook en tiempo real
  • Contador de confirmaciones se actualiza correctamente
  • Conversion a USD aplica spread de 0.5%
  • Wallet se acredita automaticamente al confirmar deposito
  • Usuario sin KYC no puede retirar
  • Usuario con KYC puede retirar hasta su limite
  • Validacion de direcciones funciona para todas las redes
  • Retiros se procesan y notifican con TX hash
  • Limites diarios se aplican correctamente
  • Cooldown de 24h para nuevas direcciones funciona
  • Transacciones no confirmadas expiran en 72h

Especificacion Tecnica Relacionada

Historias de Usuario Relacionadas