Solidność - wzór wycofania
Wzór wypłaty zapewnia, że bezpośrednie połączenie transferowe nie jest wykonywane, co stanowi zagrożenie dla bezpieczeństwa. Poniższa umowa pokazuje niezabezpieczone użycie połączenia transferowego do wysyłania eteru.
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;
}
}
}
Powyższy kontrakt może stać się bezużyteczny, powodując, że najbogatszy będzie kontraktem z powodu awarii funkcji rezerwowej. Gdy funkcja rezerwowa zawiedzie, funkcja getRichest () również nie powiedzie się, a kontrakt utknie na zawsze. Aby złagodzić ten problem, możemy użyć wzoru wycofania.
We wzorze wypłaty zresetujemy oczekującą kwotę przed każdym przelewem. Zapewni to, że zawiedzie tylko umowa z abonentem wywołującym.
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);
}
}