Transferências de Ether
Solidity oferece várias formas de enviar Ether de um contrato para um endereço externo, cada uma com suas próprias implicações em termos de segurança, gás e comportamento em caso de falha. Essas formas são transfer
, send
e chamadas de baixo nível (call
).
Transfer
O método transfer
é uma forma segura de enviar Ether, pois reverte automaticamente toda a transação se a transferência falhar por qualquer motivo. É a maneira recomendada de enviar Ether quando se deseja que toda a transação falhe caso a transferência de Ether não possa ser concluída.
address payable receiver = payable(0x123...);
receiver.transfer(amount);
Se a transferência falhar, a execução é interrompida e revertida.
Send
O método send
é semelhante ao transfer
, mas em vez de reverter automaticamente, retorna um valor booleano (true
ou false
) indicando o sucesso ou falha da operação. Isso permite que o contrato lide com a falha de transferência de uma maneira mais flexível.
address payable receiver = payable(0x123...);
bool sent = receiver.send(amount);
if (!sent) {
// Lidar com a falha
}
O send
é menos utilizado devido à necessidade de lidar manualmente com o caso de falha, mas pode ser útil quando se deseja uma lógica específica para tratar erros.
Call
O método call
é ainda mais flexível e é recomendado nas versões mais recentes do Solidity para enviar Ether. call
retorna um valor booleano indicando sucesso ou falha e permite especificar dados adicionais para a chamada, tornando-o compatível com a execução de funções no contrato receptor de Ether. No entanto, essa flexibilidade traz a responsabilidade de lidar corretamente com a segurança.
(address payable receiver).call{value: amount}("");
É importante tomar precauções de segurança ao usar call
para transferir Ether, especialmente para evitar reentrância, um tipo de vulnerabilidade em que um atacante pode forçar o contrato a executar certas funções de forma recursiva.
Considerações de Segurança
Prevenção de Reentrância: Ao transferir Ether, especialmente usando
call
, é crucial proteger o contrato contra ataques de reentrância. Padrões como o de checagem-efeitos-interação e o uso de modificadores de reentrância podem ajudar a mitigar esse risco.Verificar o Sucesso da Transferência: Sempre verifique o resultado de uma transferência de Ether e trate adequadamente o caso de falha, especialmente ao usar
send
ecall
.Gás para Chamadas Externas: Ao enviar Ether, é fornecida uma quantidade fixa de gás (2300 de gás ao usar
transfer
ousend
), o que é suficiente para eventos de log, mas não para executar código no contrato receptor. Comcall
, é possível especificar uma quantidade maior de gás, mas isso deve ser feito com cuidado.
Exemplo
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ReceiveEther {
// Função para receber Ether. msg.data deve estar vazio.
receive() external payable {}
// Função Fallback é chamada quando msg.data não é vazio.
fallback() external payable {}
function getBalance() public view returns (uint) {
return address(this).balance;
}
}
contract SendEther {
function sendViaTransfer(address payable _to) public payable {
// Essa função não é mais recomendada para enviar Ether.
_to.transfer(msg.value);
}
function sendViaSend(address payable _to) public payable {
// Função retorna uma booleana indicando successo ou falha.
// Essa função não é mais recomendada para enviar Ether.
bool sent = _to.send(msg.value);
require(sent, "Failed to send Ether");
}
function sendViaCall(address payable _to) public payable {
// Função retorna uma booleana indicando successo ou falha.
// Esse é o método recomendado para enviar Ether.
(bool sent, bytes memory data) = _to.call{value: msg.value}("");
require(sent, "Failed to send Ether");
}
}
Last updated