|
| 1 | +pragma solidity ^0.4.22; |
| 2 | + |
| 3 | +contract SimpleAuction { |
| 4 | + // Parameters of the auction. Times are either |
| 5 | + // absolute unix timestamps (seconds since 1970-01-01) |
| 6 | + // or time periods in seconds. |
| 7 | + address public beneficiary; |
| 8 | + uint public auctionEnd; |
| 9 | + |
| 10 | + // Current state of the auction. |
| 11 | + address public highestBidder; |
| 12 | + uint public highestBid; |
| 13 | + |
| 14 | + // Allowed withdrawals of previous bids |
| 15 | + mapping(address => uint) pendingReturns; |
| 16 | + |
| 17 | + // Set to true at the end, disallows any change |
| 18 | + bool ended; |
| 19 | + |
| 20 | + // Events that will be fired on changes. |
| 21 | + event HighestBidIncreased(address bidder, uint amount); |
| 22 | + event AuctionEnded(address winner, uint amount); |
| 23 | + |
| 24 | + // The following is a so-called natspec comment, |
| 25 | + // recognizable by the three slashes. |
| 26 | + // It will be shown when the user is asked to |
| 27 | + // confirm a transaction. |
| 28 | + |
| 29 | + /// Create a simple auction with `_biddingTime` |
| 30 | + /// seconds bidding time on behalf of the |
| 31 | + /// beneficiary address `_beneficiary`. |
| 32 | + constructor( |
| 33 | + uint _biddingTime, |
| 34 | + address _beneficiary |
| 35 | + ) public { |
| 36 | + beneficiary = _beneficiary; |
| 37 | + auctionEnd = now + _biddingTime; |
| 38 | + } |
| 39 | + |
| 40 | + /// Bid on the auction with the value sent |
| 41 | + /// together with this transaction. |
| 42 | + /// The value will only be refunded if the |
| 43 | + /// auction is not won. |
| 44 | + function bid() public payable { |
| 45 | + // No arguments are necessary, all |
| 46 | + // information is already part of |
| 47 | + // the transaction. The keyword payable |
| 48 | + // is required for the function to |
| 49 | + // be able to receive Ether. |
| 50 | + |
| 51 | + // Revert the call if the bidding |
| 52 | + // period is over. |
| 53 | + require( |
| 54 | + now <= auctionEnd, |
| 55 | + "Auction already ended." |
| 56 | + ); |
| 57 | + |
| 58 | + // If the bid is not higher, send the |
| 59 | + // money back. |
| 60 | + require( |
| 61 | + msg.value > highestBid, |
| 62 | + "There already is a higher bid." |
| 63 | + ); |
| 64 | + |
| 65 | + if (highestBid != 0) { |
| 66 | + // Sending back the money by simply using |
| 67 | + // highestBidder.send(highestBid) is a security risk |
| 68 | + // because it could execute an untrusted contract. |
| 69 | + // It is always safer to let the recipients |
| 70 | + // withdraw their money themselves. |
| 71 | + pendingReturns[highestBidder] += highestBid; |
| 72 | + } |
| 73 | + highestBidder = msg.sender; |
| 74 | + highestBid = msg.value; |
| 75 | + emit HighestBidIncreased(msg.sender, msg.value); |
| 76 | + } |
| 77 | + |
| 78 | + /// Withdraw a bid that was overbid. |
| 79 | + function withdraw() public returns (bool) { |
| 80 | + uint amount = pendingReturns[msg.sender]; |
| 81 | + if (amount > 0) { |
| 82 | + // It is important to set this to zero because the recipient |
| 83 | + // can call this function again as part of the receiving call |
| 84 | + // before `send` returns. |
| 85 | + pendingReturns[msg.sender] = 0; |
| 86 | + |
| 87 | + if (!msg.sender.send(amount)) { |
| 88 | + // No need to call throw here, just reset the amount owing |
| 89 | + pendingReturns[msg.sender] = amount; |
| 90 | + return false; |
| 91 | + } |
| 92 | + } |
| 93 | + return true; |
| 94 | + } |
| 95 | + |
| 96 | + /// End the auction and send the highest bid |
| 97 | + /// to the beneficiary. |
| 98 | + function auctionEnd() public { |
| 99 | + // It is a good guideline to structure functions that interact |
| 100 | + // with other contracts (i.e. they call functions or send Ether) |
| 101 | + // into three phases: |
| 102 | + // 1. checking conditions |
| 103 | + // 2. performing actions (potentially changing conditions) |
| 104 | + // 3. interacting with other contracts |
| 105 | + // If these phases are mixed up, the other contract could call |
| 106 | + // back into the current contract and modify the state or cause |
| 107 | + // effects (ether payout) to be performed multiple times. |
| 108 | + // If functions called internally include interaction with external |
| 109 | + // contracts, they also have to be considered interaction with |
| 110 | + // external contracts. |
| 111 | + |
| 112 | + // 1. Conditions |
| 113 | + require(now >= auctionEnd, "Auction not yet ended."); |
| 114 | + require(!ended, "auctionEnd has already been called."); |
| 115 | + |
| 116 | + // 2. Effects |
| 117 | + ended = true; |
| 118 | + emit AuctionEnded(highestBidder, highestBid); |
| 119 | + |
| 120 | + // 3. Interaction |
| 121 | + beneficiary.transfer(highestBid); |
| 122 | + } |
| 123 | +} |
0 commit comments