Somente para fins educacionais; não constitui aconselhamento de investimento. Investir pode causar perdas.
Resposta direta
delegatecall executa o código de um contrato de destino no contexto do contrato chamador. O chamador mantém seu próprio armazenamento, saldo e address(this), enquanto msg.sender e msg.value preservam os valores da chamada original.
Esse comportamento viabiliza proxies, bibliotecas e módulos de carteiras inteligentes, mas também concede ao código delegado a autoridade efetiva do chamador. Uma gravação no armazenamento, transferência de ativos, aprovação ou chamada externa é realizada como o chamador, não como o destino que forneceu o código.
Trate todo destino acessível por delegatecall como código privilegiado. A segurança depende das regras de seleção do destino, da compatibilidade dos layouts de armazenamento, do estado de inicialização, dos controles de atualização e da implementação exata que estiver ativa para a transação.
Como funciona
Em uma chamada externa comum, o contrato chamado lê e grava em seu próprio armazenamento. Com delegatecall, o bytecode do destino é executado sobre o armazenamento do chamador: uma instrução SSTORE altera um slot pertencente ao chamador. Os nomes das variáveis do destino não importam durante a execução; somente as posições calculadas dos slots importam.
Isso cria quatro limites que devem ser auditados:
- Controle do destino: determine se o destino é fixo, selecionado por um usuário, resolvido por meio de um registro ou alterável por um administrador.
- Compatibilidade do armazenamento: compare a ordem e os tipos das variáveis, a herança, as lacunas de armazenamento e os slots com namespace ou padronizados entre todas as versões da implementação.
- Inicialização e autorização: confirme que os inicializadores não possam ser executados novamente e que as funções de atualização ou gerenciamento de módulos exijam o chamador previsto e o atraso de governança definido.
- Tratamento de retornos: verifique se as falhas são propagadas e se os dados retornados são decodificados como o tipo esperado; chamadas de baixo nível não fornecem as verificações usuais do Solidity sobre o tipo de contrato.
O ERC-1967 reduz colisões em proxies ao armazenar endereços de implementação, beacon e administrador em slots padronizados, fora da alocação normal do compilador. Ele não comprova que uma implementação seja segura nem que uma atualização autorizada seja inofensiva.
Exemplo
Suponha que uma carteira armazene owner em slot 0. Um plug-in compilado com counter em slot 0 incrementa o contador quando a carteira o acessa por meio de delegatecall.
A gravação altera o valor owner da carteira porque o armazenamento pertence à carteira. Se a palavra resultante codificar um endereço controlado por um invasor, verificações de autorização posteriores poderão reconhecer o invasor como proprietário, embora o plug-in nunca tenha mantido sob custódia os ativos da carteira.
Um recibo bem-sucedido não distingue alterações de estado intencionais de alterações prejudiciais. Portanto, a simulação da transação deve inspecionar as diferenças de armazenamento, as mudanças em ativos e aprovações, os eventos emitidos e as chamadas subsequentes em relação aos endereços exatos do proxy e da implementação.
Riscos
- Execução em destino arbitrário: destinos controlados por usuários ou validados de forma insuficiente podem executar código malicioso com as permissões do chamador.
- Colisão de armazenamento: uma implementação pode sobrescrever propriedade, saldos, estado de pausa ou até mesmo o slot que seleciona a próxima implementação.
- Atualização insegura: um administrador ou processo de governança comprometido pode substituir código revisado anteriormente depois que os usuários depositaram ativos ou concederam aprovações.
- Falha de inicialização: um proxy ou uma implementação não inicializados podem permitir que outra conta reivindique funções privilegiadas ou configure dependências perigosas.
- Inspeção enganosa: verificar apenas o código-fonte do proxy, a implementação atual ou a interface pode deixar passar um beacon, uma atualização pendente, um registro de módulos ou um caminho de execução alternativo.
Antes de assinar, identifique a implementação em um bloco recente, verifique quem pode alterá-la e com qual atraso, inspecione o bytecode verificado e o layout de armazenamento do destino, simule todos os calldata e compare o armazenamento sensível e as aprovações de tokens antes e depois da execução. Para uma carteira inteligente, verifique também como os módulos são habilitados e desabilitados e quais destinos eles podem escolher.
Equívocos comuns
- “O destino não pode tocar nos ativos do chamador.” O código delegado é executado como o chamador e pode invocar contratos externos, transferir ativos ou criar aprovações se o chamador tiver essas capacidades.
- “Nomes de variáveis correspondentes evitam colisões.” A EVM usa slots de armazenamento, não nomes do código-fonte. A ordem do layout, a herança e os tipos devem permanecer compatíveis.
- “O código verificado do proxy significa que o sistema está verificado.” A implementação ativa, o beacon, o administrador de atualizações, o estado de inicialização e as permissões dos módulos são partes distintas do limite de confiança.
Tópicos relacionados
- Segurança criptoeconômica
- RPC de transação privada
- Contrato proxy
- Contrato inteligente
- Simulação de transações
Fontes
- Introduction to Smart Contracts - Solidity Documentation (acessado em: 2026-08-20)
- Units and Globally Available Variables - Solidity Documentation (acessado em: 2026-08-20)
- ERC-1967: Proxy Storage Slots - Ethereum Improvement Proposals (acessado em: 2026-08-20)