• O Duel está aberto na Robinhood Chain
  • Lance um duelo dois tokens, três pools, uma transação
  • A rodada fecha em --:--:--
  • Rodadas de quatro horas a recompra do vencedor tem limite de preço
  • Liquidez travada para sempre, sem tokens da equipe

Segurança

O que tem valor

  • O ETH e os tokens dos pools, em posições que ninguém pode retirar. O ETH de um lado só sai do pool quando esse lado é vendido nele: por um trader, ou pelo realinhamento do hook depois que uma negociação afastou os três preços.
  • Os potes, as taxas do criador e as taxas do protocolo, guardados pelo hook como créditos de ETH no PoolManager da Uniswap V4, contabilizados separadamente para cada duelo.

O que o protege

  • Liquidez travada. Só a fábrica pode abrir pools registrados ou adicionar a liquidez de lançamento deles; saques e doações revertem.
  • Destinatários limitados. Um pote só compra o vencedor do próprio duelo; as taxas do criador só vão para o criador do duelo: a carteira que o lançou ou um endereço para o qual ela passou o papel e que o aceitou. As taxas do protocolo vão para a tesouraria atual, que o dono da fábrica pode mudar depois de 48 horas, inclusive para as taxas do protocolo já acumuladas.
  • Poderes limitados da fábrica. Os tokens não têm dono nem função de mint, e o hook não pode ser atualizado nem pausado. O dono da fábrica pode pausar novos lançamentos, propor termos limitados para duelos futuros ou mudar a tesouraria depois do prazo. Ele também pode reduzir na hora a parte do protocolo na taxa de swap de todos os duelos, até zero, ou aumentá-la de novo, nunca acima dos termos do duelo: o que o protocolo não retém vai para os potes. O dono pode renunciar ao papel de vez (renounceOwnership): os termos, a tesouraria, a alíquota do protocolo e uma pausa ficam então como estão, exceto uma mudança já proposta, que qualquer pessoa ainda pode aplicar depois do prazo.
  • Liquidação antes do swap. O primeiro swap depois de um fechamento liquida a média encerrada antes de negociar. O teto de uma recompra fica cerca de 10% acima de uma referência guardada com precisão de frações de tick: uma média exponencial de 30 minutos dos ticks do pool de ETH, limitada ao tick atual quando o ultrapassa, para que acompanhe o preço para baixo na hora.
  • Rodadas só em ETH. A divisão e a média da rodada usam os dois pools de ETH. Uma troca A/B que não move nenhum preço em ETH não muda nem o sinal nem a atividade de uma rodada que, de outra forma, estaria parada.
  • Taxas só com execução completa. Swaps cobrados antecipadamente revertem se não conseguirem completar o valor pedido. O gás da rede é à parte.
  • Realinhamento isolado. Só são mantidos os loops lucrativos, limitados pelo ETH do pool vendedor. Uma tentativa que falha é revertida e pulada; por falta de gás, quem reverte é o swap (ArbitrageStarved), para que quem chama não possa pulá-la segurando gás. Isso não garante que os preços coincidam nem protege contra todas as perdas de negociação.
  • As mesmas regras em todas as rotas. O hook cobra taxas, impostos e queimas seja o router o do Duel ou outro router V4.

A fábrica começa com os lançamentos pausados. Enquanto paused() for true, só owner() pode lançar um duelo; as chamadas dos demais revertem com CreationPaused. O dono abre os lançamentos com setPaused(false). Os duelos existentes continuam sendo negociados.

O que o site mostra

  • Imagens só do site. As páginas mostram as imagens de um duelo só a partir do próprio endereço do Duel, e só imagens que o site processou: um JPEG, PNG ou WebP lido primeiro pelo cabeçalho (1536 × 1536 pixels e 5 MB no máximo), decodificado em WebAssembly, ajustado a 1024 pixels e codificado de novo como WebP, sem os metadados. A política de segurança das páginas não deixa que elas carreguem imagens de nenhum outro lugar.
  • Codecs isolados. As imagens são decodificadas em um Worker próprio, que só o site acessa e que não guarda nada: nem chave, nem armazenamento. Uma falha em um codec atingiria só a imagem que ele lê. O site verifica o que esse Worker responde (um WebP estático do tamanho esperado) antes de guardá-lo, e os decodificadores em C recomeçam do zero a cada imagem.
  • Duelos lançados direto pelo contrato. Os dados deles podem indicar qualquer endereço. O site não mostra imagens https; ele busca uma imagem IPFS uma única vez, em um gateway público (5 MB e 10 segundos no máximo), processa-a como um upload e mostra a própria cópia, ou as iniciais do lado.
  • Uploads com limites. O site só aceita imagens das próprias páginas: dez por minuto de um mesmo endereço e um número limitado por dia. Uma imagem que nenhum duelo usa é apagada depois de um dia.

Como foi verificado

  • Testes automatizados cobrem o comportamento dos contratos, o app web e o bot de alertas. A cobertura é uma métrica de testes, não a prova de que todo comportamento possível é seguro.
  • Testes em fork exercitam a integração com os contratos da Uniswap V4 implantados na Robinhood Chain, incluindo o Universal Router, o Permit2 e o V4 Quoter.
  • Testes de regressão guardam os casos encontrados durante a revisão interna, como a contabilidade das taxas, casos-limite do lançamento, a liquidação e pools esgotados.
  • Testes de invariantes verificam a contabilidade ao longo de sequências aleatórias de negociações, liquidações e resgates: os créditos de ETH devem bater com os valores devidos, e nenhum token intermediário deve ficar no hook, na fábrica ou no router. Passar nas execuções configuradas não garante a segurança para toda sequência possível.

A revisão interna encontrou e corrigiu uma rota de saída exata que escapava do imposto antissnipe, uma divisão que não acompanhava um lado comprado sozinho, pools esgotados lidos errado pela referência de preço da recompra e links inseguros nos metadados de um duelo.

Reportar uma vulnerabilidade

Se você acha que encontrou uma vulnerabilidade, obrigado por dedicar seu tempo para reportá-la. Escreva para nós em privado no Telegram, em @chatwithdivine, contando o que encontrou e, se puder, como reproduzir, e nos dê tempo para investigar antes de divulgar qualquer coisa publicamente. Responderemos rápido e manteremos você informado.

Nunca escrevemos primeiro: confie apenas em @chatwithdivine.