Solidity - 提款模式
提款模式确保不会造成安全威胁的直接转接呼叫。 以下合约显示了使用转账调用发送以太币的不安全方式。
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; } } }
通过使最富有的合约成为后备功能失败的合约,可以使上述合约处于不可用状态。 当后备函数失败时,becomeRichest()函数也会失败,合约将永远卡住。 为了缓解这个问题,我们可以使用 Withdrawal Pattern。
在提款模式中,我们会在每次转账前重置待处理金额。 它将确保只有调用者合约失败。
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); } }