Solidity-withdrawal-pattern

提供:Dev Guides
移動先:案内検索

堅牢性-引き出しパターン

撤回パターンは、セキュリティ上の脅威となる直接転送呼び出しが行われないようにします。 次の契約は、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;
      }
   }
}

上記のコントラクトは、フォールバック機能が失敗したコントラクトを最もリッチにすることにより、使用できない状態でレンダリングできます。 フォールバック関数が失敗すると、becomeRichest()関数も失敗し、コントラクトは永久にスタックします。 この問題を軽減するために、引き出しパターンを使用できます。

引き出しパターンでは、各送金の前に保留金額をリセットします。 呼び出し元の契約のみが失敗するようにします。

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);
   }
}