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ón | KYC Básico | KYC Avanzado | KYC 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 bancarias | 0 | 3 | 10 |
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
| Problema | Causa Probable | Solución |
|---|---|---|
| Depósito no aparece | Referencia incorrecta | Contactar soporte con comprobante |
| Retiro rechazado | Cuenta no verificada | Completar verificación micro-depósitos |
| Límite excedido | KYC insuficiente | Subir a KYC avanzado |
| Retiro en revisión | AML flag | Esperar 1-2 días hábiles |
| Cuenta bancaria no se agrega | Plaid no soporta el banco | Usar verificación manual |
| Fee inesperado | Ya usó 3 retiros gratis | Esperar 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ón | Límite | Ventana | Razón |
|---|---|---|---|
| Agregar cuenta | 3 cuentas | 1 hora | Prevenir abuso |
| Verificar cuenta | 5 intentos | 1 día | Prevenir fuerza bruta |
| Solicitar depósito | 10 solicitudes | 1 hora | Prevenir spam |
| Solicitar retiro | 5 retiros | 1 día | Seguridad |
| Ver historial | 30 requests | 1 minuto | Proteger DB |
Compliance Crítico
Regulaciones que DEBES cumplir:
- Know Your Customer (KYC): Verificar identidad de usuarios antes de permitir retiros
- Anti-Money Laundering (AML): Detectar y reportar actividad sospechosa
- Bank Secrecy Act (BSA): Reportar transacciones > $10,000 USD
- OFAC Sanctions: No procesar transacciones de países/personas sancionadas
- 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
}