# Open Auction # Auction params # Beneficiary receives money from the highest bidder beneficiary: public(address) auctionStart: public(uint256) auctionEnd: public(uint256) # Current state of auction highestBidder: public(address) highestBid: public(uint256) # Set to true at the end, disallows any change ended: public(bool) # Keep track of refunded bids so we can follow the withdraw pattern pendingReturns: public(HashMap[address, uint256]) # Create a simple auction with `_bidding_time` # seconds bidding time on behalf of the # beneficiary address `_beneficiary`. @external def __init__(_beneficiary: address, _bidding_time: uint256): self.beneficiary = _beneficiary self.auctionStart = block.timestamp self.auctionEnd = self.auctionStart + _bidding_time # Bid on the auction with the value sent # together with this transaction. # The value will only be refunded if the # auction is not won. @external @payable def bid(): # Check if bidding period is over. assert block.timestamp < self.auctionEnd # Check if bid is high enough assert msg.value > self.highestBid # Track the refund for the previous high bidder self.pendingReturns[self.highestBidder] += self.highestBid # Track new high bid self.highestBidder = msg.sender self.highestBid = msg.value # Withdraw a previously refunded bid. The withdraw pattern is # used here to avoid a security issue. If refunds were directly # sent as part of bid(), a malicious bidding contract could block # those refunds and thus block new higher bids from coming in. @external def withdraw(): pending_amount: uint256 = self.pendingReturns[msg.sender] self.pendingReturns[msg.sender] = 0 send(msg.sender, pending_amount) # End the auction and send the highest bid # to the beneficiary. @external def endAuction(): # It is a good guideline to structure functions that interact # with other contracts (i.e. they call functions or send Ether) # into three phases: # 1. checking conditions # 2. performing actions (potentially changing conditions) # 3. interacting with other contracts # If these phases are mixed up, the other contract could call # back into the current contract and modify the state or cause # effects (Ether payout) to be performed multiple times. # If functions called internally include interaction with external # contracts, they also have to be considered interaction with # external contracts. # 1. Conditions # Check if auction endtime has been reached assert block.timestamp >= self.auctionEnd # Check if this function has already been called assert not self.ended # 2. Effects self.ended = True # 3. Interaction send(self.beneficiary, self.highestBid)