Saltar al contenido principal

Operaciones Bancarias (Fiat ↔ Crypto)

Este documento explica los flujos de operaciones bancarias: depósitos fiat, retiros fiat, y conversión cripto↔fiat.


Arquitectura Bancaria


1. Depósito Fiat (Bank Transfer)

Flujo Completo de Depósito

Datos de Depósito Generados

interface DepositInfo {
// Para transferencia bancaria
bankTransfer: {
bankName: string; // "Chase Bank"
accountNumber: string; // "123456789"
routingNumber: string; // "021000021"
accountName: string; // "SwapBits LLC"
reference: string; // "SB-USER-123456" (ÚNICO)
swift?: string; // Para internacionales
};

// Instrucciones
instructions: [
"Use EXACTLY this reference: SB-USER-123456",
"Deposits are processed within 1-3 business days",
"Minimum deposit: $100 USD"
];

// Límites
limits: {
min: 100,
max: 10000, // Sin KYC avanzado
maxWithKYC: 50000
};
}

Depósito Guardado en MongoDB

{
_id: ObjectId("..."),
userId: ObjectId("user_123"),
type: "deposit",
method: "bank_transfer",

// Montos
fiatAmount: 500,
fiatCurrency: "USD",
cryptoAmount: 500,
cryptoCurrency: "USDT",
exchangeRate: 1.0,

// Tracking
reference: "SB-USER-123456",
externalTxId: "TRX-ABC123", // ID del proveedor

// Estados
status: "completed",

// Timestamps
createdAt: ISODate("2025-10-20T10:00:00Z"),
receivedAt: ISODate("2025-10-20T14:30:00Z"), // Cuando proveedor recibe
confirmedAt: ISODate("2025-10-20T14:35:00Z"), // Cuando acreditamos al usuario

// Compliance
kycLevel: "advanced",
amlChecked: true,
ipAddress: "192.168.1.1",

// Auditoría
providerFee: 2.50, // Fee del proveedor
swapbitsFee: 0, // Sin fee para depósitos
netAmount: 500
}

2. Retiro Fiat (Bank Withdrawal)

Flujo Completo de Retiro

Validaciones de Retiro

async validateWithdrawal(dto: WithdrawalDto, user: User) {

// 1. KYC avanzado requerido
if (user.kycLevel !== 'advanced') {
throw new ForbiddenException('Advanced KYC required for withdrawals');
}

// 2. Cuenta bancaria verificada
const bankAccount = await this.bankAccountsRepo.findOne({
_id: dto.bankAccountId,
userId: user._id,
isVerified: true
});

if (!bankAccount) {
throw new BadRequestException('Bank account not verified');
}

// 3. Balance suficiente
const wallet = await this.walletsRepo.findOne({
userId: user._id,
coin: 'USDT'
});

if (wallet.balance < dto.amount) {
throw new BadRequestException('Insufficient USDT balance');
}

// 4. Monto dentro de límites
if (dto.amount < 50 || dto.amount > 10000) {
throw new BadRequestException('Amount must be between $50 and $10,000');
}

// 5. Límites diarios
const todayWithdrawals = await this.getTodayWithdrawals(user._id);
if (todayWithdrawals + dto.amount > 10000) {
throw new BadRequestException('Daily withdrawal limit exceeded ($10,000)');
}

// 6. Límites mensuales
const monthWithdrawals = await this.getMonthWithdrawals(user._id);
if (monthWithdrawals + dto.amount > 50000) {
throw new BadRequestException('Monthly withdrawal limit exceeded ($50,000)');
}

// 7. Rate limiting
await this.rateLimit.check(`withdraw:${user._id}`, 5, 86400000); // 5/día

// 8. Cuenta no bloqueada
if (user.withdrawalsBlocked) {
throw new ForbiddenException('Withdrawals are blocked for your account');
}

// 9. Anti-fraude
await this.fraudService.analyzeWithdrawal(user, dto);
}

3. Agregar/Verificar Cuenta Bancaria

Flujo de Verificación de Cuenta

Cuenta Bancaria en MongoDB

{
_id: ObjectId("..."),
userId: ObjectId("user_123"),

// Datos de la cuenta
bankName: "Chase Bank",
accountType: "checking", // checking o savings
accountNumberLast4: "1234", // Solo últimos 4 dígitos
routingNumber: "021000021",
accountHolderName: "John Doe",

// Plaid
plaidAccountId: "plaid_acc_123",
plaidAccessTokenEncrypted: "U2FsdGVkX1...", // Encriptado

// Verificación
isVerified: true,
verifiedAt: ISODate("2025-10-20T10:00:00Z"),
verificationMethod: "micro_deposits",

// Estado
isActive: true,
isPrimary: true, // Cuenta principal para retiros

// Auditoría
createdAt: ISODate("2025-10-18T14:00:00Z"),
lastUsedAt: ISODate("2025-10-20T16:00:00Z")
}

4. Conversión Automática (Auto-Convert)

Flujo de Auto-Conversión

Configuración de Auto-Convert

interface AutoConvertSettings {
enabled: boolean;
targetCrypto: 'BTC' | 'ETH' | 'USDT'; // A qué cripto convertir
minAmount: number; // Monto mínimo para auto-convert ($100)
slippageTolerance: number; // 0.5% default
}

5. Límites y Niveles KYC

Límites por Nivel KYC

OperaciónKYC BásicoKYC AvanzadoKYC Premium
Depósito/día$1,000$10,000$50,000
Depósito/mes$5,000$50,000$500,000
Retiro/día❌ No permitido$5,000$25,000
Retiro/mes❌ No permitido$25,000$250,000
Cuentas bancarias0310

KYC Requerido para Retiros

interface KYCLevel {
basic: {
required: ['email', 'phone', 'fullName', 'dateOfBirth'];
canDeposit: true;
canWithdraw: false;
};

advanced: {
required: ['basic', 'governmentID', 'addressProof', 'selfie'];
canDeposit: true;
canWithdraw: true;
maxWithdrawal: 5000; // Por día
};

premium: {
required: ['advanced', 'incomeProof', 'videoVerification'];
canDeposit: true;
canWithdraw: true;
maxWithdrawal: 25000; // Por día
};
}

6. Estados de Transacción Bancaria

Estados de Depósito

enum DepositStatus {
PENDING = 'pending', // Usuario inició depósito
AWAITING_FUNDS = 'awaiting_funds', // Esperando transferencia
RECEIVED = 'received', // Proveedor recibió fondos
PROCESSING = 'processing', // Verificando y convirtiendo
COMPLETED = 'completed', // Acreditado al usuario
FAILED = 'failed', // Falló el depósito
REFUNDED = 'refunded' // Fondos devueltos
}

Estados de Retiro

enum WithdrawalStatus {
PENDING = 'pending', // Retiro solicitado
PENDING_REVIEW = 'pending_review', // Revisión manual (AML)
APPROVED = 'approved', // Aprobado, pendiente envío
PROCESSING = 'processing', // Proveedor procesando
SENT = 'sent', // Enviado al banco del usuario
COMPLETED = 'completed', // Usuario recibió fondos
FAILED = 'failed', // Falló el retiro
CANCELLED = 'cancelled' // Usuario canceló
}

7. Compliance y AML

Verificaciones Anti-Money Laundering

Factores de Riesgo AML

interface AMLRiskFactors {
// Patrones de transacción
frequentLargeWithdrawals: boolean; // > 3 retiros grandes/semana
rapidMovement: boolean; // Deposita y retira inmediatamente
roundNumbers: boolean; // Siempre montos redondos ($5000, $10000)

// Comportamiento del usuario
newAccount: boolean; // Cuenta < 30 días
noHistoryDeposits: boolean; // Primer depósito grande
inconsistentLocation: boolean; // IPs de diferentes países

// Red flags específicos
matchesSanctions: boolean; // En listas de sanciones
highRiskCountry: boolean; // País de alto riesgo
structuring: boolean; // Múltiples tx < $10k (evitar reportes)

// Score final
riskScore: number; // 0-100 (100 = sin riesgo)
}

8. Fees Bancarios

Estructura de Comisiones

interface BankingFees {
// Depósitos
deposit: {
bankTransfer: 0, // Gratis
creditCard: 0.029, // 2.9% + $0.30
debitCard: 0.015, // 1.5%
};

// Retiros
withdrawal: {
domestic: 0, // Gratis (primeros 3/mes)
domesticAfter3: 2.00, // $2 después de 3 retiros/mes
international: 15.00, // $15 por retiro internacional
expedited: 25.00 // $25 retiro rápido (same day)
};

// Otros
monthlyMaintenance: 0; // Sin fee mensual
inactivityFee: 5.00; // $5/mes si no hay actividad por 6 meses
}

Cálculo de Fees

function calculateWithdrawalFee(withdrawal: Withdrawal, user: User): number {
// 1. Contar retiros del mes
const monthlyWithdrawals = await this.getMonthWithdrawals(user._id);

// 2. Primeros 3 gratis
if (monthlyWithdrawals < 3) {
return 0;
}

// 3. Determinar tipo de retiro
if (withdrawal.bankAccount.country !== 'US') {
return 15.00; // Internacional
}

if (withdrawal.expedited) {
return 25.00; // Same day
}

return 2.00; // Doméstico estándar
}

9. Historial Bancario

Consulta de Historial

Resumen Bancario

interface BankingSummary {
// Totales
totalDeposited: number; // $15,000 (lifetime)
totalWithdrawn: number; // $8,000 (lifetime)
netBalance: number; // $7,000

// Este mes
depositsThisMonth: number; // $2,000
withdrawalsThisMonth: number; // $500
feesThisMonth: number; // $10

// Límites disponibles
remainingDailyDeposit: number; // $8,000
remainingDailyWithdrawal: number; // $4,500

// Próximos retiros gratis
freeWithdrawalsLeft: number; // 2
}

10. Métodos de Pago Alternativos

Otros Métodos Soportados

interface PaymentMethods {
// ACH (Automated Clearing House)
ach: {
enabled: true;
processingTime: '1-3 business days';
fee: 0;
limits: { min: 10, max: 10000 };
};

// Wire Transfer
wire: {
enabled: true;
processingTime: 'Same day';
fee: 15;
limits: { min: 1000, max: 50000 };
};

// Debit Card (instant)
debitCard: {
enabled: true;
processingTime: 'Instant';
fee: 0.015; // 1.5%
limits: { min: 20, max: 1000 };
};

// Credit Card
creditCard: {
enabled: true;
processingTime: 'Instant';
fee: 0.029; // 2.9% + $0.30
limits: { min: 20, max: 1000 };
};

// PayPal (futuro)
paypal: {
enabled: false;
processingTime: 'Instant';
fee: 0.029;
limits: { min: 10, max: 5000 };
};
}

11. Notificaciones Bancarias

Eventos de Notificación

// Notificaciones push/email para eventos bancarios
const bankingNotifications = {
// Depósitos
'deposit.received': {
title: '💰 Depósito Recibido',
body: 'Recibimos tu depósito de $500 USD',
email: true,
push: true
},

'deposit.completed': {
title: '✅ Depósito Completado',
body: 'Se acreditaron 500 USDT a tu wallet',
email: true,
push: true
},

// Retiros
'withdrawal.sent': {
title: '📤 Retiro Enviado',
body: 'Tu retiro de $1,000 fue enviado a tu banco',
email: true,
push: true
},

'withdrawal.completed': {
title: '✅ Retiro Completado',
body: 'Los fondos ya están disponibles en tu cuenta',
email: true,
push: true
},

'withdrawal.failed': {
title: '❌ Retiro Fallido',
body: 'Tu retiro falló. Fondos devueltos a tu wallet.',
email: true,
push: true,
sms: true // También por SMS
},

// Alertas
'limit.approaching': {
title: '⚠️ Acercándote al Límite',
body: 'Has usado $9,500 de tu límite diario de $10,000',
email: false,
push: true
}
};

12. Troubleshooting Bancario

ProblemaCausa ProbableSolución
Depósito no apareceReferencia incorrectaContactar soporte con comprobante
Retiro rechazadoCuenta no verificadaCompletar verificación micro-depósitos
Límite excedidoKYC insuficienteSubir a KYC avanzado
Retiro en revisiónAML flagEsperar 1-2 días hábiles
Cuenta bancaria no se agregaPlaid no soporta el bancoUsar verificación manual
Fee inesperadoYa usó 3 retiros gratisEsperar al próximo mes

13. Seguridad Bancaria

Medidas de Seguridad

// Seguridad implementada
const bankingSecurity = {
// Encriptación
encryption: {
accountNumbers: 'AES-256-GCM',
plaidTokens: 'AES-256-GCM',
sensitiveData: 'Always encrypted at rest'
},

// Autenticación
auth: {
pinRequired: true, // PIN para retiros
twoFactorOptional: true, // 2FA recomendado
deviceFingerprint: true // Detectar nuevos dispositivos
},

// Rate limiting
rateLimits: {
addAccount: '3 per hour',
withdraw: '5 per day',
getHistory: '30 per minute'
},

// Auditoría
audit: {
logAllTransactions: true,
logIPAddress: true,
logDeviceInfo: true,
retentionPeriod: '7 years' // Requerimiento legal
},

// Compliance
compliance: {
amlChecks: true,
sanctionsScreening: true,
pep Screening: true, // Politically Exposed Persons
adverseMediaScreening: true
}
};

Rate Limiting Bancario

OperaciónLímiteVentanaRazón
Agregar cuenta3 cuentas1 horaPrevenir abuso
Verificar cuenta5 intentos1 díaPrevenir fuerza bruta
Solicitar depósito10 solicitudes1 horaPrevenir spam
Solicitar retiro5 retiros1 díaSeguridad
Ver historial30 requests1 minutoProteger DB

Compliance Crítico

Regulaciones que DEBES cumplir:

  1. Know Your Customer (KYC): Verificar identidad de usuarios antes de permitir retiros
  2. Anti-Money Laundering (AML): Detectar y reportar actividad sospechosa
  3. Bank Secrecy Act (BSA): Reportar transacciones > $10,000 USD
  4. OFAC Sanctions: No procesar transacciones de países/personas sancionadas
  5. Data Retention: Guardar registros por mínimo 7 años

Red Flags AML:

  • ❌ Estructuración (muchas tx < $10k)
  • ❌ Deposita y retira inmediatamente
  • ❌ Retiros a diferentes cuentas bancarias
  • ❌ Usuario de país de alto riesgo
  • ❌ Patrón inusual comparado con su perfil

En caso de duda, SIEMPRE: Marcar para revisión manual.


Métricas de Monitoreo

interface BankingMetrics {
// Volumen
dailyDepositVolume: number; // $50,000
dailyWithdrawalVolume: number; // $30,000
pendingReviewAmount: number; // $5,000

// Performance
averageDepositTime: number; // 2.5 días
averageWithdrawalTime: number; // 1.8 días
successRate: number; // 98.5%

// AML
transactionsFlagged: number; // 12
transactionsUnderReview: number; // 3
transactionsBlocked: number; // 1

// Usuarios
usersWithBankAccounts: number; // 1,500
newBankAccountsToday: number; // 25
verifiedAccountsToday: number; // 20
}