diff options
author | chriseth <chris@ethereum.org> | 2016-08-20 08:57:07 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-08-20 08:57:07 +0800 |
commit | 0d736fde6d1e04f02bb36183906b5e522aab8725 (patch) | |
tree | feba91bfeb315739130134d449489c001e5354cf /docs/common-patterns.rst | |
parent | 64cec9793a881e5a8ee77cb73e3f3599f330c044 (diff) | |
parent | e27493aa8306da65d4cfc464b7867f1faaf72a9f (diff) | |
download | dexon-solidity-0d736fde6d1e04f02bb36183906b5e522aab8725.tar.gz dexon-solidity-0d736fde6d1e04f02bb36183906b5e522aab8725.tar.zst dexon-solidity-0d736fde6d1e04f02bb36183906b5e522aab8725.zip |
Merge pull request #706 from Denton-L/withdrawal-pattern
Add Withdrawal Pattern Example
Diffstat (limited to 'docs/common-patterns.rst')
-rw-r--r-- | docs/common-patterns.rst | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index 322be3ef..74f9c078 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -2,6 +2,110 @@ Common Patterns ############### +.. index:: withdrawal + +.. _withdrawal_pattern: + +************************* +Withdrawal from Contracts +************************* + +The recommended method of sending funds after an effect +is using the withdrawal pattern. Although the most intuitive +method of sending Ether, as a result of an effect, is a +direct ``send`` call, this is not recommended as it +introduces a potential security risk. You may read +more about this on the :ref:`security_considerations` page. + +This is an example of the withdrawal pattern in practice in +a contract where the goal is to send the most money to the +contract in order to become the "richest", inspired by +`King of the Ether <https://www.kingoftheether.com/>`_. + +In the following contract, if you are usurped as the richest, +you will recieve the funds of the person who has gone on to +become the new richest. + +:: + + contract WithdrawalContract { + address public richest; + uint public mostSent; + + mapping (address => uint) pendingWithdrawals; + + function WithdrawalContract() { + richest = msg.sender; + mostSent = msg.value; + } + + function becomeRichest() returns (bool) { + if (msg.value > mostSent) { + pendingWithdrawals[richest] += msg.value; + richest = msg.sender; + mostSent = msg.value; + return true; + } + else { + return false; + } + } + + function withdraw() returns (bool) { + uint amount = pendingWithdrawals[msg.sender]; + // Remember to zero the pending refund before + // sending to prevent re-entrancy attacks + pendingWithdrawals[msg.sender] = 0; + if (msg.sender.send(amount)) { + return true; + } + else { + pendingWithdrawals[msg.sender] = amount; + return false; + } + } + } + +This is as opposed to the more intuitive sending pattern. + +:: + + contract SendContract { + address public richest; + uint public mostSent; + + function SendContract() { + richest = msg.sender; + mostSent = msg.value; + } + + function becomeRichest() returns (bool) { + if (msg.value > mostSent) { + // Check if call succeeds to prevent an attacker + // from trapping the previous person's funds in + // this contract through a callstack attack + if (!richest.send(msg.value)) { + throw; + } + richest = msg.sender; + mostSent = msg.value; + return true; + } + else { + return false; + } + } + } + +Notice that, in this example, an attacker could trap the +contract into an unusable state by causing ``richest`` to be +the address of a contract that has a fallback function +which consumes more than the 2300 gas stipend. That way, +whenever ``send`` is called to deliver funds to the +"poisoned" contract, it will cause execution to always fail +because there will not be enough gas to finish the execution +of the fallback function. + .. index:: access;restricting ****************** |