1+ # Open Auction
2+
3+ # Auction params
4+ # Beneficiary receives money from the highest bidder
5+ beneficiary: public (address )
6+ auctionStart: public (uint256 )
7+ auctionEnd: public (uint256 )
8+
9+ # Current state of auction
10+ highestBidder: public (address )
11+ highestBid: public (uint256 )
12+
13+ # Set to true at the end, disallows any change
14+ ended: public (bool )
15+
16+ # Keep track of refunded bids so we can follow the withdraw pattern
17+ pendingReturns: public (HashMap[address , uint256 ])
18+
19+ # Create a simple auction with `_bidding_time`
20+ # seconds bidding time on behalf of the
21+ # beneficiary address `_beneficiary`.
22+ @external
23+ def __init__ (_beneficiary: address , _bidding_time: uint256 ):
24+ self .beneficiary = _beneficiary
25+ self .auctionStart = block .timestamp
26+ self .auctionEnd = self .auctionStart + _bidding_time
27+
28+ # Bid on the auction with the value sent
29+ # together with this transaction.
30+ # The value will only be refunded if the
31+ # auction is not won.
32+ @external
33+ @payable
34+ def bid ():
35+ # Check if bidding period is over.
36+ assert block .timestamp < self .auctionEnd
37+ # Check if bid is high enough
38+ assert msg .value > self .highestBid
39+ # Track the refund for the previous high bidder
40+ self .pendingReturns[self .highestBidder] += self .highestBid
41+ # Track new high bid
42+ self .highestBidder = msg .sender
43+ self .highestBid = msg .value
44+
45+ # Withdraw a previously refunded bid. The withdraw pattern is
46+ # used here to avoid a security issue. If refunds were directly
47+ # sent as part of bid(), a malicious bidding contract could block
48+ # those refunds and thus block new higher bids from coming in.
49+ @external
50+ def withdraw ():
51+ pending_amount: uint256 = self .pendingReturns[msg .sender ]
52+ self .pendingReturns[msg .sender ] = 0
53+ send (msg .sender , pending_amount)
54+
55+ # End the auction and send the highest bid
56+ # to the beneficiary.
57+ @external
58+ def endAuction ():
59+ # It is a good guideline to structure functions that interact
60+ # with other contracts (i.e. they call functions or send Ether)
61+ # into three phases:
62+ # 1. checking conditions
63+ # 2. performing actions (potentially changing conditions)
64+ # 3. interacting with other contracts
65+ # If these phases are mixed up, the other contract could call
66+ # back into the current contract and modify the state or cause
67+ # effects (Ether payout) to be performed multiple times.
68+ # If functions called internally include interaction with external
69+ # contracts, they also have to be considered interaction with
70+ # external contracts.
71+
72+ # 1. Conditions
73+ # Check if auction endtime has been reached
74+ assert block .timestamp >= self .auctionEnd
75+ # Check if this function has already been called
76+ assert not self .ended
77+
78+ # 2. Effects
79+ self .ended = True
80+
81+ # 3. Interaction
82+ send (self .beneficiary, self .highestBid)
0 commit comments