diff options
author | chriseth <c@ethdev.com> | 2016-09-05 22:29:08 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2016-09-07 01:11:41 +0800 |
commit | 4f5a95d569408e6a0a94c54b1eb39ea62b873c5e (patch) | |
tree | e0624ae19d837fb8e2acf9f828c4464e9e788c60 /docs | |
parent | fbe0edb32c973166efbd5c0ac556f37fd38584d6 (diff) | |
download | dexon-solidity-4f5a95d569408e6a0a94c54b1eb39ea62b873c5e.tar dexon-solidity-4f5a95d569408e6a0a94c54b1eb39ea62b873c5e.tar.gz dexon-solidity-4f5a95d569408e6a0a94c54b1eb39ea62b873c5e.tar.bz2 dexon-solidity-4f5a95d569408e6a0a94c54b1eb39ea62b873c5e.tar.lz dexon-solidity-4f5a95d569408e6a0a94c54b1eb39ea62b873c5e.tar.xz dexon-solidity-4f5a95d569408e6a0a94c54b1eb39ea62b873c5e.tar.zst dexon-solidity-4f5a95d569408e6a0a94c54b1eb39ea62b873c5e.zip |
Update documentation to version 0.4.0.
Diffstat (limited to 'docs')
-rw-r--r-- | docs/common-patterns.rst | 32 | ||||
-rw-r--r-- | docs/contracts.rst | 68 | ||||
-rw-r--r-- | docs/contributing.rst | 8 | ||||
-rw-r--r-- | docs/control-structures.rst | 31 | ||||
-rw-r--r-- | docs/frequently-asked-questions.rst | 13 | ||||
-rw-r--r-- | docs/index.rst | 3 | ||||
-rw-r--r-- | docs/introduction-to-smart-contracts.rst | 5 | ||||
-rw-r--r-- | docs/miscellaneous.rst | 2 | ||||
-rw-r--r-- | docs/security-considerations.rst | 12 | ||||
-rw-r--r-- | docs/solidity-by-example.rst | 36 | ||||
-rw-r--r-- | docs/structure-of-a-contract.rst | 6 | ||||
-rw-r--r-- | docs/style-guide.rst | 2 | ||||
-rw-r--r-- | docs/types.rst | 9 |
13 files changed, 139 insertions, 88 deletions
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index e56e7a6c..fa5e68a6 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -36,12 +36,12 @@ become the new richest. mapping (address => uint) pendingWithdrawals; - function WithdrawalContract() { + function WithdrawalContract() payable { richest = msg.sender; mostSent = msg.value; } - function becomeRichest() returns (bool) { + function becomeRichest() payable returns (bool) { if (msg.value > mostSent) { pendingWithdrawals[richest] += msg.value; richest = msg.sender; @@ -66,7 +66,7 @@ become the new richest. } } -This is as opposed to the more intuitive sending pattern. +This is as opposed to the more intuitive sending pattern: :: @@ -76,7 +76,7 @@ This is as opposed to the more intuitive sending pattern. address public richest; uint public mostSent; - function SendContract() { + function SendContract() payable { richest = msg.sender; mostSent = msg.value; } @@ -156,7 +156,7 @@ restrictions highly readable. throw; // Do not forget the "_;"! It will // be replaced by the actual function - // body when the modifier is invoked. + // body when the modifier is used. _; } @@ -187,9 +187,8 @@ restrictions highly readable. // fee being associated with a function call. // If the caller sent too much, he or she is // refunded, but only after the function body. - // This is dangerous, because if the function - // uses `return` explicitly, this will not be - // done! This behavior will be fixed in Version 0.4.0. + // This was dangerous before Solidity version 0.4.0, + // where it was possible to skip the part after `_;`. modifier costs(uint _amount) { if (msg.value < _amount) throw; @@ -204,10 +203,10 @@ restrictions highly readable. owner = _newOwner; // just some example condition if (uint(owner) & 0 == 1) - // in this case, overpaid fees will not - // be refunded + // This did not refund for Solidity + // before version 0.4.0. return; - // otherwise, refund overpaid fees + // refund overpaid fees } } @@ -265,13 +264,14 @@ function finishes. .. note:: **Modifier May be Skipped**. + This only applies to Solidity before version 0.4.0: Since modifiers are applied by simply replacing code and not by using a function call, the code in the transitionNext modifier can be skipped if the function itself uses return. If you want to do that, make sure - to call nextStage manually from those functions. - With version 0.4.0 (unreleased), modifier code + to call nextStage manually from those functions. + Starting with version 0.4.0, modifier code will run even if the function explicitly returns. :: @@ -317,6 +317,7 @@ function finishes. // Order of the modifiers matters here! function bid() + payable timedTransitions atStage(Stages.AcceptingBlindedBids) { @@ -331,9 +332,6 @@ function finishes. // This modifier goes to the next stage // after the function is done. - // If you use `return` in the function, - // `nextStage` will not be called - // automatically. modifier transitionNext() { _; @@ -345,8 +343,6 @@ function finishes. atStage(Stages.AnotherStage) transitionNext { - // If you want to use `return` here, - // you have to call `nextStage()` manually. } function h() diff --git a/docs/contracts.rst b/docs/contracts.rst index 4fe046ed..ef29a686 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -4,7 +4,7 @@ Contracts ########## -Contracts in Solidity are what classes are in object oriented languages. They +Contracts in Solidity are similar to classes in object-oriented languages. They contain persistent data in state variables and functions that can modify these variables. Calling a function on a different contract (instance) will perform an EVM function call and thus switch the context such that state variables are @@ -78,6 +78,11 @@ This means that cyclic creation dependencies are impossible. // This is the constructor which registers the // creator and the assigned name. function OwnedToken(bytes32 _name) { + // State variables are accessed via their name + // and not via e.g. this.owner. This also applies + // to functions and especially in the constructors, + // you can only call them like that ("internall"), + // because the contract itself does not exist yet. owner = msg.sender; // We do an explicit type conversion from `address` // to `TokenCreator` and assume that the type of @@ -241,7 +246,7 @@ Accessor Functions ================== The compiler automatically creates accessor functions for -all public state variables. For the contract given below, the compiler will +all **public** state variables. For the contract given below, the compiler will generate a function called ``data`` that does not take any arguments and returns a ``uint``, the value of the state variable ``data``. The initialization of state variables can @@ -328,7 +333,7 @@ inheritable properties of contracts and may be overridden by derived contracts. // This contract only defines a modifier but does not use // it - it will be used in derived contracts. // The function body is inserted where the special symbol - // "_" in the definition of a modifier appears. + // "_;" in the definition of a modifier appears. // This means that if the owner calls this function, the // function is executed and otherwise, an exception is // thrown. @@ -367,7 +372,10 @@ inheritable properties of contracts and may be overridden by derived contracts. function Register(uint initialPrice) { price = initialPrice; } - function register() costs(price) { + // It is important to also provide the + // "payable" keyword here, otherwise the function will + // automatically reject all Ether sent to it. + function register() payable costs(price) { registeredAddresses[msg.sender] = true; } @@ -450,7 +458,7 @@ functions matches the given function identifier (or if no data was supplied at all). Furthermore, this function is executed whenever the contract receives plain -Ether (without data). In such a context, there is very little gas available to +Ether (without data). In such a context, there is usually very little gas available to the function call (to be precise, 2300 gas), so it is important to make fallback functions as cheap as possible. @@ -474,26 +482,31 @@ Please ensure you test your fallback function thoroughly to ensure the execution pragma solidity ^0.4.0; contract Test { + // This function is called for all messages sent to + // this contract (there is no other function). + // Sending Ether to this contract will cause an exception, + // because the fallback function does not have the "payable" + // modifier. function() { x = 1; } uint x; } - // This contract rejects any Ether sent to it. It is good - // practise to include such a function for every contract - // in order not to lose Ether. - contract Rejector { - function() { throw; } + // This contract keeps all Ether sent to it with no way + // to get it back. + contract Sink { + function() payable { } } contract Caller { - function callTest(address testAddress) { - Test(testAddress).call(0xabcdef01); // hash does not exist - // results in Test(testAddress).x becoming == 1. - Rejector r = Rejector(0x123); - r.send(2 ether); - // results in r.balance == 0 + function callTest(Test test) { + test.call(0xabcdef01); // hash does not exist + // results in test.x becoming == 1. + + // The following call will fail, reject the + // Ether and return false: + test.send(2 ether); } } @@ -539,6 +552,11 @@ not possible to filter for specific anonymous events by name. All non-indexed arguments will be stored in the data part of the log. +.. note:: + Indexed arguments will not be stored themselves, you can only + search for the values, but it is impossible to retrieve the + values themselves. + :: pragma solidity ^0.4.0; @@ -622,7 +640,7 @@ Inheritance Solidity supports multiple inheritance by copying code including polymorphism. All function calls are virtual, which means that the most derived function -is called, except when the contract is explicitly given. +is called, except when the contract name is explicitly given. Even if a contract inherits from multiple other contracts, only a single contract is created on the blockchain, the code from the base contracts @@ -636,6 +654,8 @@ Details are given in the following example. :: + pragma solidity ^0.4.0; + contract owned { function owned() { owner = msg.sender; } address owner; @@ -709,6 +729,8 @@ Note that above, we call ``mortal.kill()`` to "forward" the destruction request. The way this is done is problematic, as seen in the following example:: + pragma solidity ^0.4.0; + contract mortal is owned { function kill() { if (msg.sender == owner) selfdestruct(owner); @@ -734,6 +756,8 @@ derived override, but this function will bypass ``Base1.kill``, basically because it does not even know about ``Base1``. The way around this is to use ``super``:: + pragma solidity ^0.4.0; + contract mortal is owned { function kill() { if (msg.sender == owner) selfdestruct(owner); @@ -773,6 +797,8 @@ Arguments for Base Constructors Derived contracts need to provide all arguments needed for the base constructors. This can be done at two places:: + pragma solidity ^0.4.0; + contract Base { uint x; function Base(uint _x) { x = _x; } @@ -833,12 +859,16 @@ Abstract Contracts Contract functions can lack an implementation as in the following example (note that the function declaration header is terminated by ``;``):: + pragma solidity ^0.4.0; + contract Feline { function utterance() returns (bytes32); } Such contracts cannot be compiled (even if they contain implemented functions alongside non-implemented functions), but they can be used as base contracts:: + pragma solidity ^0.4.0; + contract Cat is Feline { function utterance() returns (bytes32) { return "miaow"; } } @@ -1060,6 +1090,8 @@ available without having to add further code. Let us rewrite the set example from the :ref:`libraries` in this way:: + pragma solidity ^0.4.0; + // This is the same code as before, just without comments library Set { struct Data { mapping(uint => bool) flags; } @@ -1106,6 +1138,8 @@ Let us rewrite the set example from the It is also possible to extend elementary types in that way:: + pragma solidity ^0.4.0; + library Search { function indexOf(uint[] storage self, uint value) returns (uint) { for (uint i = 0; i < self.length; i++) diff --git a/docs/contributing.rst b/docs/contributing.rst index cef6dfd2..a316abd6 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -25,17 +25,21 @@ To report an issue, please use the reporting issues, please mention the following details: * Which version of Solidity you are using +* What was the source code (if applicable) * Which platform are you running on * How to reproduce the issue * What was the result of the issue * What the expected behaviour is +Reducing the source code that caused the issue to a bare minimum is always +very helpful and sometimes even clarifies a misunderstanding. + Workflow for Pull Requests ========================== In order to contribute, please fork off of the ``develop`` branch and make your -changes there. Your commit messages should detail *why* you made your change, as -opposed to *what* you did. +changes there. Your commit messages should detail *why* you made your change +in addition to *what* you did (unless it is a tiny change). If you need to pull in any changes from ``develop`` after making your fork (for example, to resolve potential merge conflicts), please avoid using ``git merge`` diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 61a8611e..c7e17e2d 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -44,8 +44,12 @@ contract can be called internally. External Function Calls ----------------------- -The expression ``this.g(8);`` is also a valid function call, but this time, the function +The expressions ``this.g(8);`` and ``c.g(2);`` (where ``g`` is a contract +instance) are also valid function calls, but this time, the function will be called "externally", via a message call and not directly via jumps. +Please note that function calls on ``this`` cannot be used in the constructor, as the +actual contract has not been created yet. + Functions of other contracts have to be called externally. For an external call, all function arguments have to be copied to memory. @@ -53,7 +57,7 @@ When calling functions of other contracts, the amount of Wei sent with the call and the gas can be specified:: contract InfoFeed { - function info() returns (uint ret) { return 42; } + function info() payable returns (uint ret) { return 42; } } @@ -63,9 +67,17 @@ of other contracts, the amount of Wei sent with the call and the gas can be spec function callFeed() { feed.info.value(10).gas(800)(); } } +The modifier ``payable`` has to be used for ``info``, because otherwise, +we would not be able to send Ether to it in the call ``feed.info.value(10).gas(800)()``. + Note that the expression ``InfoFeed(addr)`` performs an explicit type conversion stating that "we know that the type of the contract at the given address is ``InfoFeed``" and -this does not execute a constructor. We could also have used ``function setFeed(InfoFeed _feed) { feed = _feed; }`` directly. Be careful about the fact that ``feed.info.value(10).gas(800)`` +this does not execute a constructor. Explicit type conversions have to be +handled with extreme caution. Never call a function on a contract where you +are not sure about its type. + +We could also have used ``function setFeed(InfoFeed _feed) { feed = _feed; }`` directly. +Be careful about the fact that ``feed.info.value(10).gas(800)`` only (locally) sets the value and amount of gas sent with the function call and only the parentheses at the end perform the actual call. @@ -144,7 +156,7 @@ creation-dependencies are now possible. contract D { uint x; - function D(uint a) { + function D(uint a) payable { x = a; } } @@ -241,6 +253,8 @@ This happens because Solidity inherits its scoping rules from JavaScript. This is in contrast to many languages where variables are only scoped where they are declared until the end of the semantic block. As a result, the following code is illegal and cause the compiler to throw an error, ``Identifier already declared``:: + pragma solidity ^0.4.0; + contract ScopingErrors { function scoping() { uint i = 0; @@ -298,8 +312,10 @@ Catching exceptions is not yet possible. In the following example, we show how ``throw`` can be used to easily revert an Ether transfer and also how to check the return value of ``send``:: + pragma solidity ^0.4.0; + contract Sharer { - function sendHalf(address addr) returns (uint balance) { + function sendHalf(address addr) payable returns (uint balance) { if (!addr.send(msg.value / 2)) throw; // also reverts the transfer to Sharer return this.balance; @@ -337,8 +353,9 @@ arising when writing manual assembly by the following features: We now want to describe the inline assembly language in detail. .. warning:: - Inline assembly is still a relatively new feature and might change if it does not prove useful, - so please try to keep up to date. + Inline assembly is a way to access the Ethereum Virtual Machine + at a low level. This discards and allows you to bypass several safety + features of Solidity. Example ------- diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst index 7e69093f..acc0c106 100644 --- a/docs/frequently-asked-questions.rst +++ b/docs/frequently-asked-questions.rst @@ -317,17 +317,12 @@ providing any data or if someone messed up the types so that they tried to call a function that does not exist. The default behaviour (if no fallback function is explicitly given) in -these situations is to just accept the call and do nothing. -This is desireable in many cases, but should only be used if there is -a way to pull out Ether from a contract. +these situations is to throw an exception. -If the contract is not meant to receive Ether with simple transfers, you +If the contract is meant to receive Ether with simple transfers, you should implement the fallback function as -``function() { throw; }`` - -this will cause all transactions to this contract that do not call an -existing function to be reverted, so that all Ether is sent back. +``function() payable { }`` Another use of the fallback function is to e.g. register that your contract received ether by using an event. @@ -488,6 +483,8 @@ What happens if you send ether along with a function call to a contract? ======================================================================== It gets added to the total balance of the contract, just like when you send ether when creating a contract. +You can only send ether along to a function that has the ``payable`` modifier, +otherwise an exception is thrown. Is it possible to get a tx receipt for a transaction executed contract-to-contract? =================================================================================== diff --git a/docs/index.rst b/docs/index.rst index 4e90dd43..4cf75282 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -71,6 +71,9 @@ Discontinued: Solidity Tools -------------- +* `Dapple <https://github.com/nexusdev/dapple>`_ + Package and deployment manager for Solidity. + * `Solidity REPL <https://github.com/raineorshine/solidity-repl>`_ Try Solidity instantly with a command-line Solidity console. diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index de126a5a..922056ec 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -30,6 +30,11 @@ Storage } } +The first line simply tells that the source code is written for +Solidity version 0.4.0 or anything newer that does not break functionality +(up to, but not including, version 0.5.0). This is to ensure that the +contract does not suddenly behave differently with a new compiler version. + A contract in the sense of Solidity is a collection of code (its functions) and data (its *state*) that resides at a specific address on the Ethereum blockchain. The line ``uint storedData;`` declares a state variable called ``storedData`` of diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 8d1452b4..7d4cedb6 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -212,7 +212,6 @@ Tips and Tricks * Make your state variables public - the compiler will create :ref:`getters <visibility-and-accessors>` for you for free. * If you end up checking conditions on input or state a lot at the beginning of your functions, try using :ref:`modifiers`. * If your contract has a function called ``send`` but you want to use the built-in send-function, use ``address(contractVariable).send(amount)``. -* If you do **not** want your contracts to receive ether when called via ``send``, you can add a throwing fallback function ``function() { throw; }``. * Initialise storage structs with a single assignment: ``x = MyStruct({a: 1, b: 2});`` ********** @@ -338,3 +337,4 @@ Modifiers - ``constant`` for functions: Disallows modification of state - this is not enforced yet. - ``anonymous`` for events: Does not store event signature as topic. - ``indexed`` for event parameters: Stores the parameter as topic. +- ``payable`` for functions: Allows them to receive Ether together with a call. diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 8800487c..4ada8545 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -51,7 +51,7 @@ complete contract): :: - pragma solidity ^0.4.0; + pragma solidity ^0.4.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE contract Fund { @@ -75,7 +75,7 @@ outlined further below: :: - pragma solidity ^0.4.0; + pragma solidity ^0.4.0; contract Fund { /// Mapping of ether shares of the contract. @@ -134,6 +134,11 @@ Sending and Receiving Ether means for the recipient to block progress in the sending contract. Again, the best practice here is to use a :ref:`"withdraw" pattern instead of a "send" pattern <withdrawal_pattern>`. +- Contracts currently cannot prevent that someone sends them Ether. + They can react on and reject a regular transfer, but there are ways + to move Ether without creating a message call. One way is to simply "mine to" + the contract address and the second way is using ``selfdestruct(x)``. + Callstack Depth =============== @@ -155,6 +160,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like pragma solidity ^0.4.0; + // THIS CONTRACT CONTAINS A BUG - DO NOT USE contract TxUserWallet { address owner; @@ -186,7 +192,7 @@ Now someone tricks you into sending ether to the address of this attack wallet: } } -If your wallet had checked msg.sender for authorization, it would get the address of the attack wallet, instead of the owner address. But by checking tx.origin, it gets the original address that kicked off the transaction, which is still the owner address. The attack wallet instantly drains all your funds. +If your wallet had checked ``msg.sender`` for authorization, it would get the address of the attack wallet, instead of the owner address. But by checking tx.origin, it gets the original address that kicked off the transaction, which is still the owner address. The attack wallet instantly drains all your funds. Minor Details diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 1eefa4d4..9d3dd6f6 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -255,10 +255,12 @@ activate themselves. /// together with this transaction. /// The value will only be refunded if the /// auction is not won. - function bid() { + function bid() payable { // No arguments are necessary, all // information is already part of - // the transaction. + // the transaction. The keyword payable + // is required for the function to + // be able to receive Ether. if (now > auctionStart + biddingTime) { // Revert the call if the bidding // period is over. @@ -330,16 +332,6 @@ activate themselves. if (!beneficiary.send(highestBid)) throw; } - - function () { - // This function gets executed if a - // transaction with invalid data is sent to - // the contract or just ether without data. - // We revert the send so that no-one - // accidentally loses money when using the - // contract. - throw; - } } Blind Auction @@ -433,6 +425,7 @@ high or low invalid bids. /// still make the required deposit. The same address can /// place multiple bids. function bid(bytes32 _blindedBid) + payable onlyBefore(biddingEnd) { bids[msg.sender].push(Bid({ @@ -535,10 +528,6 @@ high or low invalid bids. if (!beneficiary.send(this.balance)) throw; } - - function () { - throw; - } } .. index:: purchase, remote purchase, escrow @@ -558,7 +547,7 @@ Safe Remote Purchase enum State { Created, Locked, Inactive } State public state; - function Purchase() { + function Purchase() payable { seller = msg.sender; value = msg.value / 2; if (2 * value != msg.value) throw; @@ -566,22 +555,22 @@ Safe Remote Purchase modifier require(bool _condition) { if (!_condition) throw; - _ + _; } modifier onlyBuyer() { if (msg.sender != buyer) throw; - _ + _; } modifier onlySeller() { if (msg.sender != seller) throw; - _ + _; } modifier inState(State _state) { if (state != _state) throw; - _ + _; } event aborted(); @@ -608,6 +597,7 @@ Safe Remote Purchase function confirmPurchase() inState(State.Created) require(msg.value == 2 * value) + payable { purchaseConfirmed(); buyer = msg.sender; @@ -630,10 +620,6 @@ Safe Remote Purchase if (!buyer.send(value) || !seller.send(this.balance)) throw; } - - function() { - throw; - } } ******************** diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index 1036289a..c7af0c8c 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -43,7 +43,7 @@ Functions are the executable units of code within a contract. pragma solidity ^0.4.0; contract SimpleAuction { - function bid() { // Function + function bid() payable { // Function // ... } } @@ -69,7 +69,7 @@ Function modifiers can be used to amend the semantics of functions in a declarat modifier onlySeller() { // Modifier if (msg.sender != seller) throw; - _ + _; } function abort() onlySeller { // Modifier usage @@ -91,7 +91,7 @@ Events are convenience interfaces with the EVM logging facilities. contract SimpleAuction { event HighestBidIncreased(address bidder, uint amount); // Event - function bid() { + function bid() payable { // ... HighestBidIncreased(msg.sender, msg.value); // Triggering event } diff --git a/docs/style-guide.rst b/docs/style-guide.rst index d2d922df..272a1b31 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -615,7 +615,7 @@ indistinguishable from the numerals one and zero. Contract and Library Names ========================== -Contracts should be named using the CapWords style. +Contracts and libraries should be named using the CapWords style. Events diff --git a/docs/types.rst b/docs/types.rst index 988a0ed0..9d7ebec9 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -559,7 +559,7 @@ shown in the following example: campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0); } - function contribute(uint campaignID) { + function contribute(uint campaignID) payable { Campaign c = campaigns[campaignID]; // Creates a new temporary memory struct, initialised with the given values // and copies it over to storage. @@ -572,9 +572,10 @@ shown in the following example: Campaign c = campaigns[campaignID]; if (c.amount < c.fundingGoal) return false; - if (!c.beneficiary.send(c.amount)) - throw; + uint amount = c.amount; c.amount = 0; + if (!c.beneficiary.send(amount)) + throw; return true; } } @@ -636,6 +637,8 @@ It is important to note that ``delete a`` really behaves like an assignment to ` :: + pragma solidity ^0.4.0; + contract DeleteExample { uint data; uint[] dataArray; |