Lição: 144: Padrão Checagens-Effectos-Interações
No mundo dos contratos inteligentes do Ethereum, a segurança é fundamental. Um dos padrões de design mais recomendados para aumentar a segurança nos seus contratos em Solidity é o padrão Checagens-Effectos-Interações. Este padrão ajuda a prevenir ataques de reentrância, que podem resultar em vulnerabilidades graves no seu contrato inteligente.
Visão Geral
O padrão Checagens-Effectos-Interações é uma metodologia de design que enfatiza a ordem das operações em um contrato inteligente para garantir que as mudanças de estado (efeitos) sejam feitas antes de interagir com contratos externos. O fluxo geral pode ser dividido em três etapas principais:
- Checagens: Valide as condições que precisam ser atendidas (como garantir saldo suficiente).
- Efeitos: Atualize o estado do contrato (como transferir tokens).
- Interações: Interaja com contratos externos (como chamar outro contrato ou transferir Ether).
Essa ordem garante que nenhuma interação externa possa manipular o estado do contrato de forma inesperada.
Exemplo
Vamos ver um contrato de exemplo que implementa o padrão Checagens-Effectos-Interações. Criaremos um contrato de escrow simples que demonstra os princípios desse padrão.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Escrow {
address public comprador;
address public vendedor;
uint256 public preco;
bool public itemEntregue;
// Eventos para registro
event PagamentoRealizado(address indexed comprador, uint256 valor);
event ItemEntregue(address indexed vendedor);
event Retirado(address indexed vendedor);
constructor(address _vendedor, uint256 _preco) {
comprador = msg.sender;
vendedor = _vendedor;
preco = _preco;
}
function realizarPagamento() external payable {
// Checagem: Garantir que o valor do pagamento está correto
require(msg.value == preco, "Valor do pagamento incorreto");
// Efeito: Mudar o estado do contrato para refletir que o pagamento foi realizado
// Você pode querer adicionar mais atualizações de variáveis de estado aqui em um cenário real
emit PagamentoRealizado(msg.sender, msg.value);
}
function confirmarEntrega() external {
// Checagem: Garantir que apenas o vendedor pode confirmar a entrega
require(msg.sender == vendedor, "Apenas o vendedor pode confirmar a entrega");
// Efeito: Atualizar o estado de entrega do item
itemEntregue = true;
emit ItemEntregue(vendedor);
}
function retirar() external {
// Checagem: Garantir que o vendedor só pode retirar se o item estiver entregue
require(msg.sender == vendedor, "Apenas o vendedor pode retirar");
require(itemEntregue, "O item deve ser entregue antes da retirada");
// Efeito: Marcar entrega do item e transferir os fundos
itemEntregue = false; // Redefinir estado para prevenir retirada dupla
uint256 valor = address(this).balance;
// Interação: Transferir fundos para o vendedor
(bool sucesso, ) = vendedor.call{value: valor}("");
require(sucesso, "Transferência falhou");
emit Retirado(vendedor);
}
}
Explicação do Exemplo
-
Checagens:
- Em
realizarPagamento()
, checamos se o valor do pagamento está correto. - Em
confirmarEntrega()
, garantimos que apenas o vendedor pode confirmar a entrega. - Em
retirar()
, verificamos que o vendedor só pode retirar se o item estiver entregue.
- Em
-
Efeitos:
- Em
realizarPagamento()
, este exemplo não muda o estado, além de registrar o evento, mas em uma aplicação real, você pode querer registrar o status do pagamento. - Em
confirmarEntrega()
, atualizamos o estadoitemEntregue
paratrue
. - Em
retirar()
, definimositemEntregue
de volta parafalse
para garantir um estado válido para operações futuras.
- Em
-
Interações:
- A interação real com uma conta externa ocorre na função
retirar()
ao transferir Ether para o vendedor.
- A interação real com uma conta externa ocorre na função
Conclusão
O padrão Checagens-Effectos-Interações é um princípio fundamental para garantir a segurança e a confiabilidade dos seus contratos inteligentes. Ao seguir esse padrão, você mitiga o risco de ataques de reentrância e garante que seus contratos se comportem conforme o esperado, mesmo quando interagem com outros contratos ou usuários.
Sempre lembre-se de pensar criticamente sobre o fluxo do seu contrato inteligente para evitar vulnerabilidades que podem levar a perdas financeiras ou explorabilidade. Boa codificação!