|
// SPDX-License-Identifier: GPL-3.0 |
|
|
|
pragma solidity 0.7.5; |
|
|
|
|
|
/** |
|
* @title A simle auction smart-contract |
|
* @author Kumar Abhishek |
|
*/ |
|
contract SimpleAuction { |
|
|
|
/// The contract owner (auctioneer) |
|
address public auctioneer; |
|
|
|
/// The beneficiary address for receiving the highest bid amount |
|
address payable public beneficiary; |
|
|
|
/// Current highest bidder |
|
address public highestBidder; |
|
|
|
/// Current highest bid amount |
|
uint public highestBid; |
|
|
|
/// Timestamp after which the bidding period is over |
|
uint public auctionEndTime; |
|
|
|
/// Has the auction ended? |
|
bool public hasAuctionEnded; |
|
|
|
// Allow previous bidders (who didn't win) to withdraw their bid amount |
|
// after the auction ends |
|
mapping (address => uint) pendingReturns; |
|
|
|
/** |
|
* @param _biddingTime The bidding period in seconds |
|
* @param _beneficiary The beneficiary address that will receive the final highest bid amount |
|
*/ |
|
constructor (uint _biddingTime, address payable _beneficiary) { |
|
auctioneer = msg.sender; |
|
beneficiary = _beneficiary; |
|
auctionEndTime = block.timestamp + _biddingTime; |
|
} |
|
|
|
|
|
/** |
|
* Notify whenever a new highest bid is made |
|
* @param bidder Who made the highest bid |
|
* @param amount The highest bid amount |
|
*/ |
|
event HighestBidIncreased(address bidder, uint amount); |
|
|
|
/** |
|
* Notify when the auction has ended |
|
* @param winner The address of the bidder who won the auction |
|
* @param amount The winning bid amount |
|
*/ |
|
event AuctionEnded(address winner, uint amount); |
|
|
|
// Allowed only by the owner/auctioneer |
|
modifier onlyAuctioneer { |
|
require(msg.sender == auctioneer, "Only the auctioneer is allowed to do this!"); |
|
_; |
|
} |
|
|
|
// Allow only if the auction has not ended |
|
modifier ifAuctionNotEnded { |
|
require(!hasAuctionEnded, "Auction has ended!"); |
|
_; |
|
} |
|
|
|
// Allow only if the bidding period is not over |
|
modifier ifBiddingPeriodNotOver { |
|
require(block.timestamp <= auctionEndTime, "Bidding period is over!"); |
|
_; |
|
} |
|
|
|
// Allow only if the bidding period is over |
|
modifier ifBiddingPeriodOver { |
|
require(block.timestamp > auctionEndTime, "Bidding period not yet over!"); |
|
_; |
|
} |
|
|
|
|
|
/** |
|
* Get total funds currently collected by the auction contract |
|
* @dev Only the auctioneer (contract owner) is allowed to see the total funds |
|
* @return total funds |
|
*/ |
|
function getFunds() view public onlyAuctioneer returns(uint) { |
|
return address(this).balance; |
|
} |
|
|
|
|
|
/** |
|
* Make a bid for this auction. |
|
* Bid amount must be more than the current highest bid amount. |
|
* @dev Allowed only if the auction has not ended |
|
* @dev Allowed only if the bidding-period is not over |
|
* @dev If the last highest bid is outbid, it is marked for withdrawal |
|
*/ |
|
function bid() public payable ifAuctionNotEnded ifBiddingPeriodNotOver { |
|
// Condition: Bid amount should be higher than the current highestBid |
|
require(msg.value > highestBid, "Bid too low!"); |
|
|
|
// Mark the last highest-bid for withdrawal (if any) |
|
if (highestBid > 0) { |
|
// The highest bidder might already have an older bid amount pending for return. |
|
// Add highestBidder's latest bid amount to any previous pending return |
|
pendingReturns[highestBidder] = pendingReturns[highestBidder] + highestBid; |
|
} |
|
|
|
// Store the current highest bidder |
|
highestBidder = msg.sender; |
|
highestBid = msg.value; |
|
|
|
// Notify that a new highest bid has been made |
|
emit HighestBidIncreased(msg.sender, msg.value); |
|
} |
|
|
|
|
|
/** |
|
* Allow bidders to withdraw their earlier bid amount |
|
* if they have been outbidded by others |
|
* @return whether the withdrawal was successful |
|
*/ |
|
function withdraw() public returns (bool) { |
|
uint amount = pendingReturns[msg.sender]; |
|
|
|
if (amount > 0) { |
|
pendingReturns[msg.sender] = 0; |
|
|
|
if (!msg.sender.send(amount)) { |
|
pendingReturns[msg.sender] = amount; |
|
return false; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
/** |
|
* End auction |
|
* @dev Only the Auctioneer is allowed to end the auction |
|
* @dev Allowed only if the auction has not already ended |
|
* @dev Allowed only if the bidding period is over |
|
*/ |
|
function endAuction() public onlyAuctioneer ifAuctionNotEnded ifBiddingPeriodOver { |
|
// Mark the auction as ended to avoid multiple transfers to the beneficiary |
|
hasAuctionEnded = true; |
|
emit AuctionEnded(highestBidder, highestBid); |
|
|
|
// Transfer the highest bid amount to the beneficiary |
|
beneficiary.transfer(highestBid); |
|
} |
|
|
|
} |