Segurança do Hook do Uniswap v4: Arquitetura, Vulnerabilidades Comuns e Melhores Práticas

iconMetaEra
Compartilhar
AI summary iconResumo
O Uniswap v4 implementa liquidez programável por meio de Hooks, mas devido a falhas em codificação de permissões e controle de acesso, tornou-se um alvo frequente de ataques; fique atento aos riscos de uso incorreto de Hooks Async e lógica contábil.

Autor e fonte do artigo: Beosin

Após o lançamento da mainnet do Uniswap v4, o mecanismo Hook tornou-se uma das inovações mais comentadas no DeFi. A plataforma de lançamento de memecoins na cadeia Base, Flaunch, utiliza o Hook para implementar preço fixo de pré-venda e mecanismo automático de liquidação ao lançamento; o protocolo de liquidez Bunni v2 emprega o Hook para construir modelos de liquidez programável e de remarcação; neste ano, tokens como SATO, uPEG (Unipeg) e Slonks, baseados em玩法 Hook, também registraram aumentos de dezenas de vezes em curto prazo.

Do lado oposto do florescimento do ecossistema Hook, os ataques explorando falhas na implementação do Hook também estão aumentando significativamente. Este artigo começará com o mecanismo Hook do Uniswap v4, analisando gradualmente sua pilha de chamadas principal, ajudando os projetos a compreender as possíveis vulnerabilidades presentes.

Segurança do Hook do Uniswap v4

1. Introdução

A mudança arquitetônica mais significativa do Uniswap v4 em relação ao v3 é a introdução do mecanismo Hook: permite que desenvolvedores anexem contratos personalizados a eventos do ciclo de vida do pool de liquidez, injetando lógica arbitrária em pontos como swap, adição/remoção de liquidez e inicialização.

As principais alterações da v4 são as seguintes:

Padrão Singleton: o estado de todos os pools é gerenciado centralmente pelo contrato PoolManager, sem a necessidade de implantar contratos independentes para cada pool.

- Contabilidade em tempo real: as alterações de saldo intermediárias durante o processo de negociação são registradas apenas no armazenamento transitório e são liquidadas em conjunto apenas ao final da transação.

Mecanismo Hook: Cada pool pode ser vinculado a um contrato Hook, e o PoolManager fará chamadas de retorno para esse contrato em pontos-chave (beforeInitialize, beforeSwap, afterAddLiquidity, etc.)

- O Hook não pode ser alterado: após a inicialização do pool, o endereço do Hook vinculado é permanentemente fixo (o endereço do Hook vinculado ao pool não pode ser modificado, mas se o contrato do Hook pode ser atualizado depende da sua implementação).

Na era v3, os desenvolvedores precisavam confiar apenas no próprio protocolo Uniswap; já na era v4, a segurança de cada pool depende do Hook ao qual está vinculado. Os Hooks transformaram o AMM de um primitivo financeiro fixo em uma infraestrutura financeira programável, mas o modelo de segurança passou de “nível de protocolo” para “nível de pool”.

2. Estrutura do Hook 2.1 PoolManager e modelo unlock/callback

O contrato principal da v4 é o PoolManager singleton. Qualquer operação de alteração de estado do pool (swap, adicionar ou remover liquidez) deve primeiro chamar PoolManager.unlock() para obter permissão de retorno única, e então concluir a ação específica em unlockCallback(). Ao final do processo, o PoolManager verifica se o livro está equilibrado:

Quando NonzeroDeltaCount != 0, reverta imediatamente; essa é a restrição central do flash accounting v4. Qualquer Hook pode temporariamente desequilibrar a contabilidade durante a execução, mas deve compensar automaticamente antes do término da transação; caso contrário, toda a transação será revertida.

Cada pool é identificado unicamente pela estrutura PoolKey, que contém o campo hooks:

O PoolId é calculado por keccak256(PoolKey), portanto, endereços de hooks diferentes produzem pools diferentes. Isso também significa que o PoolManager não verifica se um endereço de hook já foi usado em outro pool; o mesmo contrato de hook pode ser vinculado simultaneamente a vários pools.

2.2 Código de permissão Hook codificado no endereço

Um design não intuitivo do v4 é: as permissões do Hook não são determinadas por alguma variável interna ao contrato, mas sim pelo endereço de implantação do contrato Hook.

O PoolManager verifica os 14 bits menos significativos do endereço Hook para determinar se esse Hook precisa ser chamado em um determinado ponto do ciclo de vida:

Por exemplo, BEFORE_SWAP_FLAG = 1 << 7. Se o bit 7 do endereço do Hook estiver definido como 1, o PoolManager chamará o beforeSwap() desse Hook antes da troca; caso contrário, mesmo que o contrato do Hook implemente beforeSwap(), ele nunca será chamado pelo PoolManager.

Isso significa que, ao implantar o Hook, o endereço deve ser calculado usando CREATE2 + salt, de forma a construir um endereço cujos bits menos significativos correspondam exatamente às permissões desejadas. A Uniswap fornece oficialmente a ferramenta HookMiner para esse propósito:

Quando os bits de permissão não estão alinhados com a implementação da função, surgem dois tipos de problemas:

(1) Um hook foi implementado, mas o endereço não foi codificado com os bits de permissão correspondentes — o PoolManager nunca chamará essa função, tornando a lógica inválida

(2) O endereço codifica um bit de permissão, mas o hook não implementa a função correspondente — o PoolManager pode sofrer revert durante o retorno, resultando em DOS ou falha na validação do valor de retorno, impedindo a execução da operação relacionada.

Isso também é um obstáculo natural para a atualização do Hook: se o Hook puder ser atualizado por meio de um proxy, o endereço de implantação permanece inalterado durante a atualização, portanto, após a atualização, apenas a implementação das funções Hook existentes pode ser modificada, mas novos tipos de Hook não podem ser adicionados. Para reservar capacidade de expansão futura, todos os bits de permissão possivelmente necessários devem ser pré-alocados no momento da implantação inicial.

2.3 BaseHook e uma armadilha de controle de acesso frequentemente ignorada

O contrato abstrato BaseHook fornecido pela periferia do Uniswap v4 permite que desenvolvedores o herdem para implementar hooks personalizados. Um papel importante do BaseHook é fornecer o modificador onlyPoolManager para a função unlockCallback():

Mas — aqui existe uma armadilha de design facilmente negligenciada — a versão inicial do BaseHook adicionou onlyPoolManager apenas ao unlockCallback, sem qualquer proteção para outras funções de callback do hook (beforeSwap, afterSwap, beforeAddLiquidity, etc.). O controle de acesso a essas funções deve ser adicionado explicitamente pelo desenvolvedor do hook.

3. Leitura do código do ciclo de vida do Hook

Por exemplo, com uma troca exact-input, abaixo está analisada a pilha de chamadas completa desde o início da transação pelo usuário até o encerramento.

3.1 Inicialização do pool e vinculação do Hook

Qualquer pessoa pode chamar PoolManager.initialize() para criar um novo pool:

isValidHookAddress verifica apenas a compatibilidade entre o bit de permissão do endereço e o campo fee, não verifica se o Hook já está sendo usado em outro pool nem se o Hook "deseja" aceitar esse PoolKey. Se o Hook não tiver implementado lógica de whitelist ou vinculação a um único pool em beforeInitialize, qualquer pessoa pode criar um novo pool usando o mesmo Hook, mas com qualquer par de tokens, e acionar todos os callbacks subsequentes do Hook.

3.2 beforeSwap e BeforeSwapDelta

A entrada do processo de swap é PoolManager.swap(), que chama Hooks.beforeSwap() antes de executar a lógica central de swap:

O valor de retorno de beforeSwap é uma tupla (bytes4, BeforeSwapDelta, uint24):

- bytes4: deve ser igual a IHooks.beforeSwap.selector, caso contrário, o PoolManager reverterá diretamente

- BeforeSwapDelta: O hook ajusta o delta para o token especificado e o token não especificado nesta swap

- uint24: valor de cobertura da taxa de LP dinâmica (apenas válido quando a pool tiver a taxa dinâmica ativada)

BeforeSwapDelta é um alias de int256, onde os 128 bits mais altos representam o delta do token especificado (ou seja, o token cuja quantidade o usuário especificou) e os 128 bits mais baixos representam o delta do token não especificado:

Observe que o significado de BeforeSwapDelta é que o Hook deve retornar um valor positivo ao cobrar taxas e um valor negativo ao reembolsar tokens. Desenvolvedores facilmente confundem os sinais; além disso, a correspondência entre specified e unspecified depende do sinal de params.zeroForOne e amountSpecified, e uma pequena incorreção na implementação pode causar deslocamento de tokens.

O PoolManager adicionará diretamente o specifiedDelta retornado por beforeSwap ao amountToSwap:

Esta linha implica um significado chave: o Hook pode interceptar o valor do swap. Quando hookDeltaSpecified é igual a -params.amountSpecified, amountToSwap é diretamente definido como zero, o que equivale ao Hook assumindo completamente esse swap — isso é conhecido como Async Hook ou Custom Curve Hook.

Async Hook é um padrão de design com o maior risco na versão 4: ele substitui essencialmente a lógica de swap da Uniswap pela lógica própria do Hook. Se o Hook contiver vulnerabilidades ou for malicioso por natureza, os fundos dos usuários não serão mais protegidos pela lógica de precificação nativa da Uniswap, passando a depender principalmente da correção da implementação do Hook.

3.3 Liquidação de Delta e NonzeroDeltaCount

O delta retornado por beforeSwap e afterSwap não aciona imediatamente a transferência, mas é registrado no livro-razão interno do PoolManager:

Sempre que o delta acumulado de um token mudar de zero para não zero, NonzeroDeltaCount é incrementado; quando voltar a zero, é decrementado. Conforme mencionado em 2.1, ao final de unlock(), se NonzeroDeltaCount != 0, toda a transação é revertida.

Hook equilibra seu delta por meio das ações settle() (transferindo para o PoolManager) e take() (retirando do PoolManager):

A semântica de segurança trazida por este mecanismo é clara: todos eventualmente precisam fechar suas posições. No entanto, ele garante apenas a “conservação de contas”, não a “correção das contas”. Se o Hook retornar um delta maliciosamente construído no beforeSwap, o PoolManager registrará fielmente esse delta, e desde que seja finalmente liquidado, a transação será considerada bem-sucedida — mesmo que isso signifique que o Hook possa, por meio da falsificação do estado de negócios, fazer com que o sistema erroneamente acredite que o atacante possui certos direitos sobre ativos, e o PoolManager não consiga identificar esse erro de nível de negócio.

O evento de segurança anterior do Cork Protocol ocorreu devido a uma vulnerabilidade em seu Hook, e ele já havia sido auditado por quatro empresas de auditoria antes do ataque. Após o incidente, constatamos:

Três das quatro auditorias não incluíram o contrato CorkHook no escopo.

A única auditoria realizada no CorkHook identificou alguns problemas no código e apresentou sugestões de melhoria, mas não abordou completamente os problemas de controle de acesso.

Outro auditor também recomendou explicitamente em seu relatório: “um acompanhamento interessante seria provar os invariantes das funções CorkHook que são invocadas por diferentes componentes verificados dentro do escopo deste engajamento”. Essa recomendação, sob a perspectiva de uma análise pós-evento, possui um alto grau de relevância.

Isso revela uma nova cegueira de auditoria na era dos v4 Hooks: o crescimento exponencial da complexidade do protocolo torna a definição do escopo em si uma decisão de segurança. A cadeia de interações entre o Hook e os outros contratos do protocolo é muito longa; auditar apenas o contrato Hook não é suficiente para identificar problemas de composição entre contratos; por outro lado, auditar os contratos circundantes enquanto exclui o Hook do escopo resulta na omissão da maior superfície de ataque da era v4.

5. Reflexão

Ao comparar lado a lado o mecanismo do protocolo e o ataque Cork, podem-se identificar alguns pontos-chave do modelo de segurança v4 Hook:

(1) Se a função de retorno de chamada Hook depender do contexto de chamada fornecido pelo PoolManager, deve-se limitar explicitamente que apenas o PoolManager possa chamá-la. O BaseHook não fará isso em nome do desenvolvedor; este é o armadilha de design mais fácil de entrar em conflito com a experiência geral de auditoria de contratos na versão 4.

(2) A relação de vinculação entre o Hook e o pool não é restrita pelo PoolManager. Os desenvolvedores devem implementar manualmente a lista branca de pools ou a vinculação de pool único no beforeInitialize.

(3) As permissões do endereço Hook devem corresponder exatamente à implementação da função. O endereço calculado deve incluir antecipadamente todas as permissões que possam ser expandidas no futuro.

(4) O hook Async / Custom Curve é, essencialmente, uma implementação totalmente personalizada de swap. Ele não possui nenhuma proteção ao nível do protocolo Uniswap e deve ser auditado conforme o padrão de “contrato financeiro totalmente autônomo”.

(5) A "conservação" na contabilidade de delta não é igual à "corretude". NonzeroDeltaCount == 0 apenas garante que o livro-razão esteja equilibrado no final, mas não garante que o conteúdo do livro-razão não tenha sido manipulado maliciosamente.

(6) A confusão do tipo de token entre mercados é uma nova superfície de ataque na era v4. Quando o protocolo permite que os usuários criem mercados, a validação semântica dos tokens é obrigatória e não pode depender apenas da verificação da interface.

Cada Hook é um domínio de confiança independente, e a segurança de cada pool é determinada pelo Hook associado. A complexidade da auditoria de segurança do Hook, portanto, não é mais “auditar um único código”, mas sim “auditar um subprotocolo completo” — essa mudança representa uma atualização metodológica tanto para os projetos quanto para as equipes de auditoria.

Referências

(1) Cork Protocol. “May 28 2025 Exploit Post-Mortem.” 2025-06-04. https://www.cork.tech/blog/post-mortem

(2) OWASP Top 10 de Segurança de Contratos Inteligentes 2026, SC01: Vulnerabilidades de Controle de Acesso. https://scs.owasp.org/sctop10/SC01-AccessControlVulnerabilities/

(3) Whitepaper do Uniswap v4. https://app.uniswap.org/whitepaper-v4.pdf

(4) Uniswap v4-core. https://github.com/Uniswap/v4-core

(5) Uniswap v4-periphery. https://github.com/Uniswap/v4-periphery

A Beosin, uma das primeiras empresas globais de segurança blockchain a atuar com verificação formal, oferece um ecossistema completo de serviços “segurança + conformidade”, com escritórios em mais de 10 países e regiões. Seus serviços abrangem auditoria de segurança de código antes da listagem de projetos, monitoramento e bloqueio de riscos de segurança durante a operação, recuperação de ativos roubados, anti-lavagem de dinheiro (AML) para ativos virtuais e avaliações de conformidade alinhadas às exigências regulatórias locais — tudo em um pacote “tudo-em-um” de produtos e serviços de conformidade blockchain. Entre em contato conosco por meio da caixa de mensagens do nosso公众号.

Aviso legal: as informações nesta página podem ter sido obtidas de terceiros e não refletem necessariamente os pontos de vista ou opiniões da KuCoin. Este conteúdo é fornecido apenas para fins informativos gerais, sem qualquer representação ou garantia de qualquer tipo, nem deve ser interpretado como aconselhamento financeiro ou de investimento. A KuCoin não é responsável por quaisquer erros ou omissões, ou por quaisquer resultados do uso destas informações. Os investimentos em ativos digitais podem ser arriscados. Avalie cuidadosamente os riscos de um produto e a sua tolerância ao risco com base nas suas próprias circunstâncias financeiras. Para mais informações, consulte nossos termos de uso e divulgação de risco.