Falha de arredondamento no Balancer V2 permitiu drenagem de US$ 128,64 milhões

Exploração em contratos ComposableStablePool manipulou o cálculo do invariante, reduziu artificialmente o preço de BPT e extraiu ativos em seis redes em menos de 30 minutos.

ComponenteContratos ComposableStablePool do Balancer V2, com ativos custodiados pelo Vault 0xBA12222222228d8Ba445958a75a0704d566BF2C8.
VetorSequências atômicas de batchSwap posicionaram saldos em faixas de 8 a 9 wei e exploraram perda de precisão em _upscaleArray e mulDown.
ImpactoDrenagem de US$ 128,64 milhões em seis redes, com manipulação do preço de BPT e crédito indevido de ativos no sistema de balanço interno do Vault.
PrioridadePausar ou restringir pools afetados, revisar cálculos de arredondamento, validar variação de invariante em operações em lote e auditar eventos InternalBalanceChanged.
ArtefatosContrato explorador 0x54B53503c0e2173Df29f8da735fBd45Ee8aBa30d, transações 0x6ed07db1a9fe5c0794d44cd36081d6a6df103fab868cdd75d581e3bd23bc9742 e 0xd155207261712c35fa3d472ed1e51bfcd816e616dd4f517fa5959836f5b48569.
MitigaçãoAplicar proteção contra perda acumulada de precisão, impor limites para saldos mínimos em cálculos de invariante e bloquear ciclos de compra e resgate que gerem preço artificial de BPT.
Resumo técnico

Em 3 de novembro de 2025, um explorador automatizado abusou de perda de precisão aritmética em contratos ComposableStablePool do Balancer V2 para retirar US$ 128,64 milhões em menos de 30 minutos. A exploração atingiu seis redes blockchain e concentrou-se na forma como saldos de tokens são escalados antes do cálculo do invariante usado para precificar BPT. O problema não dependia de roubo prévio de chave, aprovação administrativa ou comprometimento direto do contrato Vault; o ganho surgiu da diferença entre o valor econômico real dos ativos e o valor subestimado produzido por arredondamento em operações de divisão inteira.

O ponto crítico estava na combinação entre _upscaleArray, mulDown e chamadas batchSwap cuidadosamente montadas. Quando um saldo de token era levado para uma faixa muito baixa, entre 8 e 9 wei, o arredondamento para baixo deixava de ser desprezível em termos relativos. Em vez de produzir apenas uma diferença residual, a perda de precisão distorcia o cálculo do invariante D, que representa o valor agregado do pool. Como o preço de BPT depende de D dividido pelo fornecimento total, a redução artificial de D permitia comprar ou emitir BPT por um preço inferior ao valor de resgate dos ativos subjacentes.

A exploração foi executada principalmente durante a implantação do contrato atacante 0x54B53503c0e2173Df29f8da735fBd45Ee8aBa30d. O construtor do contrato disparou mais de 65 microtrocas, acumulando erros de arredondamento dentro de transações atômicas. Essa escolha reduziu a janela de intervenção, pois a sequência de posicionamento de saldo, manipulação de preço e extração de valor ocorreu como uma unidade lógica: se alguma etapa falhasse, a transação inteira seria revertida.

Fluxo técnico

O Balancer V2 usa um contrato Vault centralizado para custodiar tokens de múltiplos pools e separar armazenamento de ativos da lógica específica de cada pool. Esse desenho reduz transferências ERC-20 repetidas e habilita o mecanismo de balanço interno, no qual uma conta pode manter créditos dentro do Vault e usá-los em várias operações. Na exploração, essa arquitetura foi relevante porque os ativos drenados não precisaram sair fisicamente do Vault no primeiro momento; eventos InternalBalanceChanged registraram que o saldo interno do contrato atacante passou a reconhecer a posse dos ativos extraídos.

A sequência observada seguiu três fases dentro de chamadas batchSwap. Primeiro, o atacante trocou grandes quantidades de BPT por tokens subjacentes para levar um dos saldos do pool ao limite no qual o arredondamento se tornava economicamente significativo. Em seguida, executou pequenas trocas envolvendo o token posicionado na faixa crítica. Nessas operações, _upscaleArray e mulDown produziam arredondamento para baixo e faziam o invariante calculado ficar menor que o valor efetivo do pool. Por fim, o atacante adquiria ou emitia BPT com o preço deprimido e resgatava ativos subjacentes com base no valor econômico real, capturando a diferença.

A falha se tornou severa porque o erro não foi validado como uma alteração anômala de invariante ao longo de uma sequência em lote. Uma troca isolada geraria perda pequena demais para justificar a exploração, mas dezenas de operações no mesmo fluxo atômico amplificaram o efeito. A transação 0x6ed07db1a9fe5c0794d44cd36081d6a6df103fab868cdd75d581e3bd23bc9742 mostra a drenagem de aproximadamente US$ 63 milhões em dois pools durante a implantação do contrato. Os registros indicaram aumento de balanço interno de 4.623 WETH e 6.851 osETH em um pool, além de 1.963 WETH e 4.259 wstETH em outro.

Depois da etapa de acumulação, a função identificada por 0x8a4f75d6 retirou o saldo interno do contrato explorador. A transação 0xd155207261712c35fa3d472ed1e51bfcd816e616dd4f517fa5959836f5b48569 confirmou a transferência de 6.586 WETH do balanço interno para outro endereço controlado pelo operador. A distinção entre transferências de taxas e saldo roubado é importante: os 65 repasses ao coletor de taxas do protocolo refletiam custos e resíduos das trocas manipuladas, enquanto o valor apropriado aparecia nos créditos de balanço interno associados ao contrato explorador.

Superfície afetada

A superfície exposta envolveu pools ComposableStablePool do Balancer V2 que dependiam do mesmo padrão de cálculo de invariante e de escalonamento de saldos. Como o Vault concentrava a custódia dos tokens e permitia operações em lote sobre múltiplos pools, uma falha matemática em lógica de pool tinha potencial para afetar várias posições de liquidez sem exigir exploração separada de cada token. O risco foi maior em pools com ativos de valor correlacionado, como combinações envolvendo WETH, osETH, wstETH e BPT, porque o modelo de StableSwap tenta manter paridade e liquidez eficiente entre ativos similares.

As pré-condições técnicas não exigiam permissão privilegiada. O atacante precisava conseguir chamar batchSwap, construir uma sequência que empurrasse saldos para limites de arredondamento e manter a execução dentro de uma transação que não violasse as verificações existentes. Essa característica transforma a falha em risco de lógica econômica, não em uma corrupção clássica de memória ou falha de autenticação. Testes unitários que validam apenas operações individuais tendem a não detectar o comportamento acumulado, pois cada chamada isolada respeita a aritmética inteira esperada, enquanto a composição adversarial altera o estado econômico do pool.

Operadores de protocolos que reutilizam fórmulas de StableSwap, mecanismos de escalonamento decimal ou balanço interno semelhante devem tratar o caso como padrão de vulnerabilidade. O elemento central é qualquer fluxo em que o preço de um token de pool seja derivado de um invariante sensível a arredondamento e, ao mesmo tempo, possa ser usado imediatamente para emissão, compra ou resgate. A presença de lotes atômicos, roteamento entre ativos e ausência de limites para variação acumulada de D aumenta o risco.

  • Contratos ComposableStablePool com cálculo de preço de BPT baseado no invariante D.
  • Chamadas batchSwap que permitem dezenas de trocas encadeadas em uma única transação.
  • Saldos de token levados a faixas muito baixas, especialmente entre 8 e 9 wei, antes do escalonamento.
  • Pools de ativos correlacionados nos quais pequena distorção de preço pode ser convertida em resgate de valor real.
Hunting e telemetria

A investigação deve priorizar telemetria on-chain do Vault, eventos de balanço interno e padrões de chamadas durante implantação de contratos. O caso demonstra que a execução do construtor pode conter toda a lógica de exploração, então buscas limitadas a chamadas posteriores ao contrato podem perder a etapa principal. Em redes compatíveis com EVM, analistas devem reconstruir rastros de transação e separar eventos de taxa, transferências ERC-20 e alterações internas de conta, porque o valor drenado pode aparecer como crédito contábil antes de qualquer saque visível para uma carteira externa.

Sinais fortes incluem sequências extensas de microtrocas em batchSwap, redução progressiva de valores transferidos como taxa, saldos de pool empurrados para valores de poucos wei e divergência entre o preço implícito de BPT e o valor de resgate dos tokens subjacentes. Também é necessário correlacionar InternalBalanceChanged com UserBalanceOp, pois a retirada final pode parecer uma operação legítima de saque do próprio saldo interno do contrato. O critério de anomalia deve considerar o fluxo completo: posicionamento de saldo, subestimação do invariante, aquisição de BPT e resgate.

Para monitoramento preventivo, modelos de detecção devem calcular limites de variação de invariante por transação e por lote, não apenas por troca. Uma sequência com dezenas de swaps de baixo valor envolvendo o mesmo token, especialmente quando o saldo residual se aproxima de limites de arredondamento, deve ser tratada como evento crítico. A simulação local da transação contra o estado anterior do bloco ajuda a confirmar se o lucro depende de distorção matemática em vez de arbitragem comum de mercado.

  • Implantação de contrato seguida de chamadas internas a batchSwap com 65 ou mais operações.
  • Eventos InternalBalanceChanged que creditam grandes volumes de WETH, osETH ou wstETH a um contrato recém-criado.
  • Transferências repetidas ao coletor de taxas com valores decrescentes até quantidades próximas de poucos wei.
  • Uso posterior de UserBalanceOp para retirar saldo interno acumulado pelo contrato explorador.
  • Queda abrupta do preço calculado de BPT sem perda correspondente nos ativos reais do pool.
Mitigação

A resposta imediata deve bloquear novas explorações antes da análise econômica completa. Para protocolos com governança ou mecanismos de emergência, a ordem prática é pausar pools vulneráveis, desabilitar rotas de batchSwap que atravessem os contratos afetados e impedir emissão ou resgate de BPT enquanto o cálculo do invariante estiver sujeito a manipulação. Em paralelo, a equipe deve extrair rastros de todas as redes envolvidas, identificar contratos que repetiram o mesmo padrão e preservar dados de eventos para eventual recuperação, comunicação com validadores, exchanges e provedores de infraestrutura.

A correção técnica deve eliminar dependência de arredondamento acumulável em estados extremos. Isso pode envolver arredondamento conservador na direção que não beneficie o chamador, limites mínimos para saldos usados no cálculo, validação explícita de variação máxima do invariante em operações em lote e testes adversariais que executem dezenas ou centenas de trocas dentro da mesma transação. O controle deve ser aplicado ao fluxo composto, pois validar apenas _upscaleArray ou mulDown de forma isolada não garante que a composição econômica permaneça segura.

Depois da contenção, a validação precisa incluir simulações com saldos próximos de zero, fuzzing orientado por lucro econômico e invariantes que comparem preço de emissão, preço de resgate e valor real dos tokens. Equipes que mantêm integrações com Balancer ou protocolos semelhantes devem revisar exposição indireta em cofres, agregadores, estratégias automatizadas e contratos que aceitam BPT como colateral. A rotação de parâmetros, a retirada de liquidez e o bloqueio de depósitos devem ser avaliados conforme a dependência de cada aplicação em relação aos pools afetados.

  • Pausar pools ComposableStablePool afetados e restringir chamadas batchSwap até correção validada.
  • Adicionar verificação de variação acumulada do invariante D durante operações em lote.
  • Revisar _upscaleArray, mulDown e demais rotinas de escalonamento para impedir ganho por arredondamento direcional.
  • Executar fuzzing com saldos em faixas de poucos wei e cenários de 65 ou mais operações atômicas.
  • Auditar eventos InternalBalanceChanged e UserBalanceOp para localizar créditos anômalos e retiradas subsequentes.