Solidez - Padrão de Retirada
O padrão de retirada garante que a chamada de transferência direta não seja feita, o que representa uma ameaça à segurança. O contrato a seguir está mostrando o uso inseguro de transferência de chamadas para enviar éter.
pragma solidity ^0.5.0;
contract Test {
address payable public richest;
uint public mostSent;
constructor() public payable {
richest = msg.sender;
mostSent = msg.value;
}
function becomeRichest() public payable returns (bool) {
if (msg.value > mostSent) {
// Insecure practice
richest.transfer(msg.value);
richest = msg.sender;
mostSent = msg.value;
return true;
} else {
return false;
}
}
}
O contrato acima pode ser processado em estado inutilizável, fazendo com que o mais rico seja um contrato de função de fallback em falha. Quando a função fallback falha, a função BecomeRichest () também falha e o contrato fica preso para sempre. Para mitigar esse problema, podemos usar o padrão de retirada.
No padrão de retirada, redefiniremos o valor pendente antes de cada transferência. Isso garantirá que apenas o contrato do chamador falhe.
pragma solidity ^0.5.0;
contract Test {
address public richest;
uint public mostSent;
mapping (address => uint) pendingWithdrawals;
constructor() public payable {
richest = msg.sender;
mostSent = msg.value;
}
function becomeRichest() public payable returns (bool) {
if (msg.value > mostSent) {
pendingWithdrawals[richest] += msg.value;
richest = msg.sender;
mostSent = msg.value;
return true;
} else {
return false;
}
}
function withdraw() public {
uint amount = pendingWithdrawals[msg.sender];
pendingWithdrawals[msg.sender] = 0;
msg.sender.transfer(amount);
}
}