Ecossistema
Esta pagina documenta o fluxo de ponta a ponta da plataforma ProCases: desde o momento em que o usuario deposita dinheiro real ate a entrega de uma skin CS2 real na conta Steam do usuario.
Visao Macro: De Dinheiro Real a Skin Real
O Ciclo Completo
| Etapa | Acao | De | Para | Comunicacao |
|---|---|---|---|---|
| 1 | Usuario paga via PIX | Banco | HorsePay | PIX (instantaneo) |
| 2 | HorsePay confirma pagamento | HorsePay | Backend | Webhook HTTP |
| 3 | Usuario aposta (caixa, batalha, upgrade) | Saldo | Motor PF | Interno (Redlock + Double-Entry) |
| 4 | Resultado provably fair gera item | Motor PF | Inventario | Interno (Prisma Transaction) |
| 5 | Usuario solicita saque de item | Inventario | Waxpeer | REST API |
| 6 | Vendedor envia trade offer no Steam | Waxpeer | Steam | WebSocket + Polling |
O dinheiro real entra (HorsePay), transforma-se em saldo digital, o saldo gera items virtuais via sistema provably fair, e os items virtuais sao convertidos em skins reais via Waxpeer.
Etapa 1: Deposito (HorsePay PIX)
Como funciona
Iniciacao: Usuario escolhe valor e metodo PIX. Backend cria pedido na HorsePay via OAuth e recebe codigo PIX + QR code.
Pagamento: Usuario paga no app do banco. HorsePay processa instantaneamente.
Confirmacao: HorsePay envia webhook para nosso endpoint publico (
POST /payment/deposit/webhook/horsepay). Backend valida o payload, encontra o deposito peloclient_reference_id, e confirma.Creditacao: Dentro de uma transacao atomica com distributed lock:
- Cria double-entry (CREDIT para usuario, DEBIT para sistema)
- Aplica bonus de cupom quando aplicavel (valor x bonusPercentage)
- Distribui tickets de sorteio (1 por R$ 30)
- Distribui tickets de evento (250 por ticket de sorteio)
- Atualiza cache de saldo
Notificacao: WebSocket emite saldo atualizado e confirmacao para o frontend em tempo real.
Integridade garantida por
- Distributed Lock: Previne processamento duplo do mesmo webhook
- Double-Entry: Credito ao usuario = Debito ao sistema (soma zero)
- Status PENDING → CONFIRMED: Deposito so e processado uma vez
- Unique constraint:
Deposit.externalIdprevine duplicatas do HorsePay
Etapa 2: Aposta (Motor Provably Fair)
Modos de aposta
| Modo | Fluxo | Provably Fair |
|---|---|---|
| Abertura de Caixa | Paga preco → Roll → Item | 1 roll por abertura |
| Sistema FLIP | Roll ≥ flipThreshold da caixa → tier raro (roleta dupla é visual) | 1 roll único (threshold por caixa) |
| Batalha PvP | N jogadores abrem mesmas caixas → Time com maior valor vence | 1 roll por jogador por round |
| Upgrade | Investe item/saldo → Roll determina sucesso | 1 roll, threshold baseado na chance |
| Sorteio | Compra tickets → Draw provably fair | 1 roll por premio |
O que torna provably fair
- Antes do jogo: Backend gera
serverSeede envia o commitmentHMAC-SHA256(serverSeed, '')ao usuario - Usuario define:
clientSeed(qualquer texto) - Roll:
HMAC-SHA256(serverSeed, clientSeed:nonce)→ numero de 1 a 10.000.000 - Apos o jogo:
serverSeede revelado. Qualquer pessoa pode recalcular e verificar
Ninguem pode manipular: Backend nao conhece o clientSeed antes de gerar o serverSeed. Usuario nao conhece o serverSeed antes de definir o clientSeed.
Integridade garantida por
- Distributed Lock: Uma operacao de saldo por usuario por vez
- Double-Entry: Debito do preco da caixa e atomico com o resultado
- BIGINT centavos: Zero erro de ponto flutuante nos calculos
- Hash ranges: Cada item tem range fixo (1 a 10.000.000), probabilidades verificaveis
- Seeds salvos no banco: Auditoria completa de cada resultado
Etapa 3: Item no Inventario Virtual
O inventario virtual e o elo entre o sistema de apostas e o mundo real. Cada item tem um marketHashName que corresponde exatamente ao nome do item no marketplace da Steam/Waxpeer.
O que o usuario pode fazer com um item
| Acao | Resultado | Reversivel |
|---|---|---|
| Vender | Recebe saldo em BRL | Nao |
| Sacar | Recebe skin real no Steam | Nao (apos trade aceita) |
| Usar em Upgrade | Combina com saldo para item melhor | Nao |
| Usar em Batalha | Compete com outros jogadores | Nao |
| Oferecer em Swap | Troca por item do site | Sim (ate aceitar) |
Integridade garantida por
- 7 status via Enum: Transicoes de estado controladas pelo banco
- Locks distribuidos: Previne uso simultaneo do mesmo item
- Unique constraints: Mesmo item nao pode estar em dois lugares
- Cascade deletes: Integridade referencial automatica
Etapa 4: Saque - De Item Virtual a Skin Real (Waxpeer)
Esta e a etapa mais complexa do sistema. O item virtual precisa ser convertido em uma skin CS2 real e entregue na conta Steam do usuario.
Comunicacao bidirecional com Waxpeer
O sistema usa dois canais simultaneos para rastrear o status do saque:
Canal 1: WebSocket (tempo real)
Backend ←→ wss://waxpeer.com (Socket.io)
Evento: 'steamTrade'
Payload: {
type: 'create' | 'update',
data: {
id: string, // waxpeerId
stage: 0-9, // estagio do trade
done: boolean, // trade concluida
is_released: boolean // item liberado
}
}O WebSocket recebe atualizacoes em tempo real assim que o status muda no Waxpeer. Conecta automaticamente ao iniciar o servico e reconecta em caso de desconexao (ate 10 tentativas com backoff exponencial).
Canal 2: Polling (fallback)
A cada 30 segundos:
1. Busca withdrawals pendentes no banco (max 100)
2. GET /v1/check-many-steam?id=123&id=456...
3. Compara status atual com status salvo
4. Atualiza se mudouO polling garante que nenhum saque fique "perdido" mesmo se o WebSocket desconectar ou perder um evento.
Mapeamento de status Waxpeer → Sistema
| Codigo Waxpeer | Significado | Status no Sistema |
|---|---|---|
| 0 | Criado | WAITING_SELLER |
| 1 | Aguardando vendedor | WAITING_SELLER |
| 2 | Trade offer enviada | TRADE_SENT |
| 3 | Trade aceita | TRADE_SENT |
| 4 | Trade concluida no Steam | COMPLETED |
| 5 | Liberado (confirmado) | COMPLETED |
| 6 | Falha/Cancelamento | FAILED ou CANCELLED |
| done: true | Concluido | COMPLETED |
| is_released: true | Item liberado | COMPLETED |
Protecao de preco
Antes de comprar no Waxpeer, o sistema verifica:
1. Nome exato do item (marketHashName) bate com o Waxpeer
2. Item tem estoque disponivel (count >= 1)
3. Preco no Waxpeer <= nosso preco original de compraSe o preco subiu significativamente desde a compra original, o saque e bloqueado para proteger a casa de prejuizo.
Fluxo de estados do saque
PENDING → Item locked, compra iniciada
WAITING_SELLER → Compra OK, aguardando vendedor enviar trade
TRADE_SENT → Trade offer enviada ao usuario no Steam
COMPLETED → Trade aceita, item entregue ✓
FAILED → Compra falhou (sem estoque, preco invalido)
CANCELLED → Vendedor cancelou tradeEm caso de falha/cancelamento: Item retorna automaticamente ao inventario do usuario com status AVAILABLE.
Integridade garantida por
- Distributed Lock (30s TTL): Previne saque duplicado do mesmo item
- Status LOCKED: Item nao pode ser vendido/usado enquanto saque em andamento
- Dual tracking: WebSocket + Polling garante que nenhum status e perdido
- Protecao de preco: Verifica preco antes de comprar
- Rollback automatico: Falha → item volta ao inventario
Por que Zero Gaps
O sistema e projetado para que nenhum dado se perca em nenhuma etapa:
Deposito
| Cenario de falha | Protecao |
|---|---|
| Webhook recebido 2x | Deposit.externalId unique constraint |
| Crash durante creditacao | Prisma transaction faz rollback automatico |
| Redis cai durante lock | Operacao nao inicia (seguro por design) |
| HorsePay fora do ar | Deposito fica PENDING ate webhook chegar |
Aposta
| Cenario de falha | Protecao |
|---|---|
| Saldo insuficiente | Verificado dentro da transacao atomica |
| Dois cliques simultaneos | Distributed lock por usuario |
| Crash apos debito | Transacao atomica: debito + resultado sao uma unica operacao |
| Roll manipulado | HMAC-SHA256 com seeds publicos verificaveis |
Saque
| Cenario de falha | Protecao |
|---|---|
| Waxpeer fora do ar | Item permanece AVAILABLE, usuario tenta depois |
| Compra falha | Item volta de LOCKED para AVAILABLE |
| WebSocket desconecta | Polling a cada 30s como fallback |
| Trade cancelada pelo vendedor | Status atualizado, item volta ao inventario |
| Trade expira (sendUntil) | Waxpeer cancela automaticamente, polling detecta |
Integridade financeira
| Cenario de falha | Protecao |
|---|---|
| Saldo negativo | Impossivel: verificacao atomica dentro da transacao |
| Dinheiro "sumiu" | Impossivel: double-entry garante soma zero no sistema |
| Saldo divergente | Source of truth = SUM de transacoes (recalculavel) |
| Cache desatualizado | Cache e complementar, saldo real sempre verificavel |
Fluxo de Dados Completo
Tecnologias por Etapa
| Etapa | Tecnologias | Protecoes |
|---|---|---|
| Deposito | HorsePay REST + Webhook, Redis Lock, Prisma TX | Double-entry, unique constraint, lock |
| Aposta | HMAC-SHA256, BigInt, Prisma TX, Redis Lock | Provably fair, range 1-10M, seeds verificaveis |
| Inventario | PostgreSQL Enums, Partial Indexes | 7 status, locks distribuidos, cascade deletes |
| Saque | Waxpeer REST + WebSocket + Polling | Lock 30s, dual tracking, protecao de preco |
| Auditoria | SHA-256 hash chaining | Cadeia imutavel, verificacao automatica |
| Comunicacao | Socket.io + Redis Adapter | Broadcast multi-instancia, reconexao automatica |
Arquivos Fonte
Deposito
src/application/services/deposit.service.tssrc/infrastructure/payment/horsepay.provider.tssrc/presentation/controllers/payment.controller.ts
Motor de Apostas
src/application/services/provably-fair.service.tssrc/application/use-cases/case-opening/open-case.use-case.tssrc/application/use-cases/battle/execute-battle.use-case.tssrc/application/use-cases/upgrade/perform-upgrade.use-case.ts
Saque (Waxpeer)
src/application/use-cases/inventory/request-withdraw-item.use-case.tssrc/application/services/waxpeer-withdrawal-tracker.service.tssrc/infrastructure/external-apis/waxpeer.service.tssrc/infrastructure/external-apis/waxpeer-websocket.service.ts
Integridade
src/application/services/transaction.service.tssrc/infrastructure/locks/lock.service.tssrc/infrastructure/audit/audit.service.ts
