20230313SimpleAuction代码及相关注释反思
//SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.17;
///@title for Auction
///@dev rongqiang.li
contract SimpleAuction{
//定义了一个可以支付的公共状态变量,受益人
address payable public beneficiary;
//定了一个公共的状态变量,拍卖结束时间,uint类型
uint public auctionEndTime;
//定义了一个公共状态变量,地址类型,用于记录最高出价者的账户地址
address public highestBidder;
//定义了一个公共状态变量,uint类型,用于记录最高出价
uint public highestBid;
//定义了一个mapping,key为地址类型,value为uint类型,用于记录拍卖未得者的地址以及该返回金额
mapping(address =>uint)pendingReturns;
// 定义了一个bool类型的变量,用于记录拍卖是否结束
bool ended;
//定义了一个事件,当最高单价提高时,通知当前最高价出价者,以及出价金额
event HighestBidIncreased(address bidder,uint amount);
// 定义了一个事件,用于当拍卖结束时,通知当前获胜者的地址,以及出价金额
event AuctionEnded(address winner,uint amount);
// 定义了一个错误,用于判断拍卖已经结束时,如果还有人继续拍卖,则获得这个异常提醒
error AuctionAlreadyEnded();
//定义了一个出价不足,没有超过当前最高价的错误,用于当有人出价时,如果出价并没有超过当前出的最高价,则获得这个错误提醒.
error BidNotHighEnough(uint highest);
// 定义了一个拍卖未结束的error
error AuctionNotYetEnded();
//如果拍卖已经结束,但是还是有人试图再次调用拍卖结束方法时,抛出这个错误
error AuctionEndAlreadyCalled();
/*
该合约的构造函数,接收两个参数,一个是拍卖时间,以秒计算,一个是受益人地址,必须要可以接受转账*/
constructor(uint biddTime,address payable beneficiaryAddress){
beneficiary = beneficiaryAddress;
auctionEndTime = block.timestamp + biddTime;// 将当前的区块时间戳+加上拍卖总时长,得到拍卖的结束时间
}
function bid()external payable{
//判断当前区块时间是否大于拍卖结束时间,如果拍卖已经结束,则抛出AuctionAlreadyEnded 错误
if(block.timestamp > auctionEndTime)
revert AuctionAlreadyEnded();
//判断当前调用房的出价,如果小于等于当前的最高出价,则抛出BidNotHighEnough,并把当前最高出价作为参数传递
if(msg.value <= highestBid)
revert BidNotHighEnough(highestBid);
if(highestBid!=0){
//如果highestBid!=0 说明已经有人第一次出价,并且高于之前的最高价,那么就应该把之前最高价的出价人的资金返还到它的地址上
pendingReturns[highestBidder] += highestBid;
}
//走到这里说明当前合约调用方的出价是符合要求的,那么就记录下当前合约调用方的地址作为当前最高价的出价人,以及当前最高价
highestBidder = msg.sender;
highestBid = msg.value;
//同时发送一个最高价提高的一个事件,将最新的最高价出价人,以及出价金额告知所有在监听的人
emit HighestBidIncreased(msg.sender,msg.value);
}
function withdraw()external returns (bool){
//根据调用方地址从mapping中取出其已经出价的总金额,作为提现金额
uint amount = pendingReturns[msg.sender];
if(amount<=0){
//如果取出当前调用方的待领取金额为0,说明他没有参与过这个拍卖或者它就是拍卖的赢家,那么就不需要提款,直接返回提款成功.
return true;
}
//如果退回金额大于0,说明这个地址要进行提款,首先提款之前,将其待提款金额归零.
//然后调用转账函数,将该合约中的金额,转账给调用方的地址,金额就是之前我们取出的金额.
if(payable(msg.sender).send(amount)){
pendingReturns[msg.sender] =0;
return true;
}
//如果转账失败,则将带提取金额重新设置为之前的金额,返回false,告诉对方提款失败
//同时payable函数是将当前msg.sender转换为可转账函数,从而去执行send方法,如果转换失败,也会返回false,则还是转账失败
pendingReturns[msg.sender] = amount;
return false;
}
function auctionEnd()external {
//如果当前时间戳没有到结束时间,而有调用方调用了合约结束的函数,那么就抛出AuctionNotYetEnded error
if(block.timestamp < auctionEndTime){
revert AuctionNotYetEnded();
}
//如果已经结束了,还有人调用这个结束函数,则抛出AuctionEndAlreadyCalled error
if(ended){
revert AuctionEndAlreadyCalled();
}
//到了这里说明时间也到了,并且结束标志还没有设置为结束,则将结束标志设置为结束,并且发出拍卖结束事件,告诉当前拍卖的最高价以及拍卖获得人.
ended =true;
emit AuctionEnded(highestBidder,highestBid);
beneficiary.transfer(highestBid);// 最后将当前拍卖金额转账给收益人.
}
}