Solidez - Patrón de abstinencia
El patrón de retiro garantiza que no se realice una llamada de transferencia directa que represente una amenaza para la seguridad. El siguiente contrato muestra el uso inseguro de la transferencia de llamadas para enviar ether.
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;
}
}
}
El contrato anterior se puede convertir en un estado inutilizable haciendo que el más rico sea un contrato con una función de respaldo fallida. Cuando la función de reserva falla, la función BecomeRichest () también falla y el contrato se bloqueará para siempre. Para mitigar este problema, podemos utilizar el patrón de retirada.
En el patrón de retiro, restableceremos el monto pendiente antes de cada transferencia. Se asegurará de que solo falle el contrato de la persona que llama.
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);
}
}