Change example to auction

This commit is contained in:
Denton Liu 2016-07-11 15:34:46 -04:00
parent a6c9d85399
commit b688d33055

View File

@ -22,32 +22,70 @@ an Ether storage contract.
:: ::
contract WithdrawalPattern { contract WithdrawalPatternAuction {
address public beneficiary;
uint public auctionStart;
uint public biddingTime;
mapping (address => uint) etherStore; address public highestBidder;
mapping (address => uint) pendingReturns; uint public highestBid;
function sendEther(uint amount) { mapping(address => uint) pendingReturns;
if (amount > etherStore[msg.sender]) {
throw; bool ended;
}
etherStore[msg.sender] -= amount; function WithdrawalPatternAuction(
pendingReturns[msg.sender] += amount; uint _biddingTime,
address _beneficiary
) {
beneficiary = _beneficiary;
auctionStart = now;
biddingTime = _biddingTime;
} }
function withdraw() { function bid() {
uint amount = pendingReturns[msg.sender]; if (now > auctionStart + biddingTime) {
// It is important to zero the mapping entry
// before sending otherwise this could open
// the contract to a re-entrancy attack
pendingReturns[msg.sender] = 0;
if (!msg.sender.send(amount)) {
throw; throw;
} }
if (msg.value <= highestBid) {
throw;
}
// Note that funds for unsucessful
// bids are returned using the
// pendingReturns mapping
if (highestBidder != 0) {
pendingReturns[highestBidder] += highestBid;
}
highestBidder = msg.sender;
highestBid = msg.value;
}
// Withdraw a bid that was overbid.
function withdraw() {
var amount = pendingReturns[msg.sender];
// It is important to set this to zero because the recipient
// can call this function again as part of the receiving call
// before `send` returns.
pendingReturns[msg.sender] = 0;
if (!msg.sender.send(amount))
throw; // If anything fails, this will revert the changes above
}
function auctionEnd() {
if (now <= auctionStart + biddingTime)
throw;
if (ended)
throw;
ended = true;
if (!beneficiary.send(this.balance))
throw;
} }
function () { function () {
etherStore[msg.sender] += msg.value; throw;
} }
} }
@ -55,28 +93,66 @@ This is as opposed to the more intuitive sending pattern.
:: ::
contract SendPattern { contract SendPatternAuction {
address public beneficiary;
uint public auctionStart;
uint public biddingTime;
mapping (address => uint) etherStore; address public highestBidder;
uint public highestBid;
function sendEther(uint amount) { bool ended;
if (amount > etherStore[msg.sender]) {
function WithdrawalPatternAuction(
uint _biddingTime,
address _beneficiary
) {
beneficiary = _beneficiary;
auctionStart = now;
biddingTime = _biddingTime;
}
function bid() {
if (now > auctionStart + biddingTime) {
throw; throw;
} }
etherStore[msg.sender] -= amount; if (msg.value <= highestBid) {
if (!msg.sender.send(amount)) {
throw; throw;
} }
// Note that funds are
// immedietally sent back to
// unsucessful bidders
if (highestBidder != 0) {
msg.sender.send(amount);// DANGER - send is unchecked!
}
highestBidder = msg.sender;
highestBid = msg.value;
}
function auctionEnd() {
if (now <= auctionStart + biddingTime)
throw;
if (ended)
throw;
ended = true;
if (!beneficiary.send(this.balance))
throw;
} }
function () { function () {
etherStore[msg.sender] += msg.value; throw;
} }
} }
An example of this pattern in a less contrived Notice that, in this example, an attacker could trap
application can be found on the :ref:`simple_auction` the previous highest bidder's funds in the contract
example. by causing the execution of `send` to fail.
The full auction example can be found at
:ref:`simple_auction`.
.. index:: access;restricting .. index:: access;restricting