Documentação
Guia completo do ecossistema BetMesh
Architecture
Visão geral da arquitetura do ecossistema BetMesh, incluindo contratos, oracle e frontend.
O BetMesh é composto por 4 componentes principais:
1. Smart Contract (BetMeshPoolV7.sol)
- Contrato principal que gerencia pools, apostas, resolução e claims
- Herda OracleManager, ReentrancyGuard e Pausable
- Totalmente independente (sem OpenZeppelin)
2. Oracle API (TypeScript)
- Clean Architecture com ports & adapters
- Multi-provider chain com fallback automático
- EIP-712 para assinatura de resultados
- Monitoramento com Prometheus + Grafana
3. Frontend Web (Next.js)
- RainbowKit + Wagmi + Viem para interação com blockchain
- Landing page, Dashboard, Criar Bolão, Detalhes
- Modo demo integrado (mock data quando sem blockchain)
4. Backend (Node.js)
- Cache e indexação de pools
- Estatísticas e ranking
- API REST para consultasSmart Contract
Documentação completa do BetMeshPoolV7 e seus módulos.
BetMeshPoolV7.sol — Principais funções:
createPool(question, optionAText, optionBText, eventStartTime, creatorFeeBps, matchId, allowDraw)
- Cria um pool WINNER: 2 opções (A vs B) ou 3 opções 1X2 (allowDraw=true)
- Taxa máxima do criador: 1000 bps (10%); taxa da plataforma fixa em 500 bps (5%)
- matchId vincula a partida esportiva; eventStartTime deve ser > agora + 2h
createScorePool(...) / createRangePool(...) / createFreeScorePool(...)
- Criam pools de placar exato, faixa (range) e placar livre (bolão de bar)
- Rollover SEMPRE ativo na V7: sem vencedor → pote acumula na reserva do criador
bet(poolId, option, amount) [USDC]
- Aposta em uma opção (1 = OptionA, 2 = OptionB, 3 = Draw quando allowDraw)
- amount em USDC (6 decimais); mínimo global 1 USDC (MIN_BET_AMOUNT)
- 1 aposta por endereço por pool (anti-sybil)
- Prazo fecha 2h antes do evento (BETTING_CLOSE_WINDOW)
betOnScore(poolId, scoreIndex, amount) / betScore(poolId, homeGoals, awayGoals, amount)
- Apostas em faixas e placares exatos (mesmas regras de valor mínimo)
resolvePool(poolId, winningOption) [onlyOracle]
- Oracle resolve o resultado (método simples)
resolvePoolFromMatchData(poolId, matchId, homeGoals, awayGoals, timestamp, signature)
- Resolve com dados esportivos + assinatura EIP-712
- Qualquer wallet pode fazer relay
claim(poolId) / claimScore(poolId) / claimFreeScore(poolId)
- Reclamar prêmio proporcional
- prize = (userBet / winningTotal) * prizePool (floor, sem arredondar a favor)
triggerRefund(poolId)
- Ativado se oracle não resolver em 24h (ORACLE_GRACE_PERIOD)
claimRefund(poolId)
- Reclamar devolução exata do valor apostado (100%, taxa zero)
sweepUnclaimed(poolId)
- Varrer prêmios não reclamados após 7 dias (CLAIM_DEADLINE) → feeWalletOracle Flow
Como os resultados são verificados e resolvidos automaticamente.
──────────────────────────────────────────────
PARA O USUÁRIO
──────────────────────────────────────────────
Os resultados são automáticos e invisíveis. Quando o evento termina:
EVENTO ENCERRADO
↓ RESULTADO EM VERIFICAÇÃO (o Oracle consulta fontes independentes)
↓ RESULTADO CONFIRMADO (fontes concordaram)
↓ POOL RESOLVIDA (registrado na blockchain)
↓ VENCEDOR IDENTIFICADO
↓ CLAIM DISPONÍVEL (você recebe seu prêmio)
Nenhum clique, botão ou atualização manual é necessário.
O status aparece sozinho nas páginas de Resultados e Minhas Apostas.
Se um evento for CANCELADO ou ADIADO, a pool NÃO é resolvida
automaticamente — ela fica marcada para análise e o resultado só
aparece quando for confirmado de forma segura.
──────────────────────────────────────────────
PARA O ADMINISTRADOR
──────────────────────────────────────────────
Monitoramento (endpoints protegidos por chave):
GET /health → Oracle online/offline + chain + scheduler
GET /stats → Pools checadas/resolvidas, erros, chamadas de provider
GET /providers → Saúde de cada fonte (healthy/degraded/unhealthy)
GET /pools/:id → Detalhes de um pool
Alertas automáticos (Telegram/Discord/Email/Console):
- saldo de gas baixo · ciclos vazios · fontes divergentes
- resolução confirmada · erro de pool · falha de sincronia do índice
- evento CANCELADO/ADIADO → PoolWaitingAnalysis (1x por pool, nunca resolve)
⚠️ POST /run-now é um gatilho de DIAGNÓSTICO (roda um ciclo agora).
O fluxo normal é 100% automático (scheduler 60s) — nenhuma ação é
necessária para o Oracle funcionar.
──────────────────────────────────────────────
PARA O DESENVOLVEDOR
──────────────────────────────────────────────
Arquitetura: Clean Architecture (ports & adapters) em betmesh-oracle/src.
Providers (adapters por esporte, com isApplicable(matchId)):
- ApiFootball / FootballData / TheSportsDB → futebol
- EspNet → futebol, basquete, MLB, NHL, UFC
- OpenF1 / ErgastF1 → Fórmula 1
- OpenDota → Dota 2
- CoinGecko → cripto
- Open-Meteo → clima
- ParlayAPI → odds + scores
ProviderChain (infrastructure/providers/ProviderChain.ts):
- Fan-out PARALELO em todas as fontes aplicáveis (com timeout 10s)
- Concordância mínima de 2 fontes (minAgreement) p/ resolver
- Divergência sem quórum → NÃO resolve + alerta onDivergence
- singleSourceFallback: só resolve com 1 fonte em mercados de fonte única
- CircuitBreaker por provider (Closed → Open → HalfOpen, re-teste 60s)
Assinatura EIP-712 (EIP712SignatureService):
- MatchResult(uint256 matchId,uint256 homeGoals,uint256 awayGoals,uint256 timestamp)
- Domain: name="BetMeshPool", version="3.0", chainId=<rede>, verifyingContract=<contrato>
- Os valores LÊEM o contrato real (mesmo domain do OracleManager.sol)
Persistência: PrismaResolutionRepository (PostgreSQL via Prisma) — upsert
por poolId (idempotente). Sem banco configurado, o estado do CONTRATO é
a fonte da verdade (relê a cada ciclo).
──────────────────────────────────────────────
PARA AUDITORIA
──────────────────────────────────────────────
Cada resolução registra:
- poolId + matchId do evento
- resultado (homeGoals × awayGoals / método / placar 1ºT)
- assinatura EIP-712 produzida
- transaction hash + timestamp da confirmação
- fonte(s) consultadas (métricas de provider) e estado on-chain final
Toda a vida das pools é rastreável na blockchain (eventos PoolCreated,
BetPlaced, PoolResolved, Claimed) e no banco de resoluções.
Nenhum secret é armazenado nos registros.API Reference
Referência completa da API REST do Backend e Oracle.
Oracle API (porta 3001):
GET /health
Retorna: { status, oracle, chain, scheduler, providers, uptime }
GET /providers
Retorna: { providerName: { name, status, latencyMs, ... } }
GET /stats
Retorna: { totalPoolsChecked, totalPoolsResolved, totalErrors }
POST /run-now
Aciona um ciclo de resolução manualmente.
GET /pools/:id
Retorna: { pool, resolution }
Backend API (porta 3002):
GET /api/pools
GET /api/pools/:id
GET /api/stats
GET /api/ranking
GET /api/historySecurity
Mecanismos de segurança implementados no protocolo.
Mecanismos de Segurança:
1. CEI (Checks-Effects-Interactions)
Estado atualizado ANTES de transferências externas
2. Non-Reentrancy
Mutex que bloqueia chamadas recursivas
3. EIP-712 Typed Data
Domain separator com chainId + contract address
Previne replay entre chains
4. Circuit Breaker (Pausable)
Admin pode pausar em emergências
emergencyRefund() funciona mesmo pausado
5. Anti-Sybil
1 aposta por endereço por pool
6. Double Claim Protection
Flag booleana claimed previne double claim
7. Nonce Anti-Replay
Nonces incrementais para funções admin
8. Zero External Dependencies
Sem OpenZeppelin, sem contratos de terceirosDeploy Guide
Guia completo para deploy local e em produção.
Deploy Local:
1. Terminal 1: Iniciar Hardhat Node
cd betmesh-core-v3
npx hardhat node
2. Terminal 2: Deploy dos Contratos
cd betmesh-core-v3
node scripts/deploy-local.mjs
(copia o endereço para NEXT_PUBLIC_CONTRACT_ADDRESS no .env.local do web)
3. Terminal 3: Iniciar Oracle
cd betmesh-oracle
npm run dev
4. Terminal 4: Iniciar Frontend
cd BetMesh/apps/web
npm run dev
5. Acessar: http://localhost:3000
Deploy Polygon Mainnet:
forge create src/BetMeshPoolV7.sol:BetMeshPoolV7 \
--constructor-args <ORACLE> <FEE_WALLET> <USDC> \
--rpc-url $POLYGON_RPC_URL \
--private-key $PRIVATE_KEY \
--verify