aboutsummaryrefslogtreecommitdiffstats
path: root/docs/solidity-by-example.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/solidity-by-example.rst')
-rw-r--r--docs/solidity-by-example.rst342
1 files changed, 1 insertions, 341 deletions
diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst
index 0e7d507d..ddead4d5 100644
--- a/docs/solidity-by-example.rst
+++ b/docs/solidity-by-example.rst
@@ -3,347 +3,7 @@ Solidity by Example
###################
.. include:: examples/voting.rst
-
-.. index:: auction;blind, auction;open, blind auction, open auction
-
-*************
-Blind Auction
-*************
-
-In this section, we will show how easy it is to create a
-completely blind auction contract on Ethereum.
-We will start with an open auction where everyone
-can see the bids that are made and then extend this
-contract into a blind auction where it is not
-possible to see the actual bid until the bidding
-period ends.
-
-.. _simple_auction:
-
-Simple Open Auction
-===================
-
-The general idea of the following simple auction contract
-is that everyone can send their bids during
-a bidding period. The bids already include sending
-money / ether in order to bind the bidders to their
-bid. If the highest bid is raised, the previously
-highest bidder gets her money back.
-After the end of the bidding period, the
-contract has to be called manually for the
-beneficiary to receive their money - contracts cannot
-activate themselves.
-
-::
-
- pragma solidity >=0.4.22 <0.6.0;
-
- contract SimpleAuction {
- // Parameters of the auction. Times are either
- // absolute unix timestamps (seconds since 1970-01-01)
- // or time periods in seconds.
- address payable public beneficiary;
- uint public auctionEndTime;
-
- // Current state of the auction.
- address public highestBidder;
- uint public highestBid;
-
- // Allowed withdrawals of previous bids
- mapping(address => uint) pendingReturns;
-
- // Set to true at the end, disallows any change.
- // By default initialized to `false`.
- bool ended;
-
- // Events that will be emitted on changes.
- event HighestBidIncreased(address bidder, uint amount);
- event AuctionEnded(address winner, uint amount);
-
- // The following is a so-called natspec comment,
- // recognizable by the three slashes.
- // It will be shown when the user is asked to
- // confirm a transaction.
-
- /// Create a simple auction with `_biddingTime`
- /// seconds bidding time on behalf of the
- /// beneficiary address `_beneficiary`.
- constructor(
- uint _biddingTime,
- address payable _beneficiary
- ) public {
- beneficiary = _beneficiary;
- auctionEndTime = now + _biddingTime;
- }
-
- /// Bid on the auction with the value sent
- /// together with this transaction.
- /// The value will only be refunded if the
- /// auction is not won.
- function bid() public payable {
- // No arguments are necessary, all
- // information is already part of
- // the transaction. The keyword payable
- // is required for the function to
- // be able to receive Ether.
-
- // Revert the call if the bidding
- // period is over.
- require(
- now <= auctionEndTime,
- "Auction already ended."
- );
-
- // If the bid is not higher, send the
- // money back.
- require(
- msg.value > highestBid,
- "There already is a higher bid."
- );
-
- if (highestBid != 0) {
- // Sending back the money by simply using
- // highestBidder.send(highestBid) is a security risk
- // because it could execute an untrusted contract.
- // It is always safer to let the recipients
- // withdraw their money themselves.
- pendingReturns[highestBidder] += highestBid;
- }
- highestBidder = msg.sender;
- highestBid = msg.value;
- emit HighestBidIncreased(msg.sender, msg.value);
- }
-
- /// Withdraw a bid that was overbid.
- function withdraw() public returns (bool) {
- uint amount = pendingReturns[msg.sender];
- if (amount > 0) {
- // 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)) {
- // No need to call throw here, just reset the amount owing
- pendingReturns[msg.sender] = amount;
- return false;
- }
- }
- return true;
- }
-
- /// End the auction and send the highest bid
- /// to the beneficiary.
- function auctionEnd() public {
- // 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
- require(now >= auctionEndTime, "Auction not yet ended.");
- require(!ended, "auctionEnd has already been called.");
-
- // 2. Effects
- ended = true;
- emit AuctionEnded(highestBidder, highestBid);
-
- // 3. Interaction
- beneficiary.transfer(highestBid);
- }
- }
-
-Blind Auction
-=============
-
-The previous open auction is extended to a blind auction
-in the following. The advantage of a blind auction is
-that there is no time pressure towards the end of
-the bidding period. Creating a blind auction on a
-transparent computing platform might sound like a
-contradiction, but cryptography comes to the rescue.
-
-During the **bidding period**, a bidder does not
-actually send her bid, but only a hashed version of it.
-Since it is currently considered practically impossible
-to find two (sufficiently long) values whose hash
-values are equal, the bidder commits to the bid by that.
-After the end of the bidding period, the bidders have
-to reveal their bids: They send their values
-unencrypted and the contract checks that the hash value
-is the same as the one provided during the bidding period.
-
-Another challenge is how to make the auction
-**binding and blind** at the same time: The only way to
-prevent the bidder from just not sending the money
-after they won the auction is to make her send it
-together with the bid. Since value transfers cannot
-be blinded in Ethereum, anyone can see the value.
-
-The following contract solves this problem by
-accepting any value that is larger than the highest
-bid. Since this can of course only be checked during
-the reveal phase, some bids might be **invalid**, and
-this is on purpose (it even provides an explicit
-flag to place invalid bids with high value transfers):
-Bidders can confuse competition by placing several
-high or low invalid bids.
-
-
-::
-
- pragma solidity >0.4.23 <0.6.0;
-
- contract BlindAuction {
- struct Bid {
- bytes32 blindedBid;
- uint deposit;
- }
-
- address payable public beneficiary;
- uint public biddingEnd;
- uint public revealEnd;
- bool public ended;
-
- mapping(address => Bid[]) public bids;
-
- address public highestBidder;
- uint public highestBid;
-
- // Allowed withdrawals of previous bids
- mapping(address => uint) pendingReturns;
-
- event AuctionEnded(address winner, uint highestBid);
-
- /// Modifiers are a convenient way to validate inputs to
- /// functions. `onlyBefore` is applied to `bid` below:
- /// The new function body is the modifier's body where
- /// `_` is replaced by the old function body.
- modifier onlyBefore(uint _time) { require(now < _time); _; }
- modifier onlyAfter(uint _time) { require(now > _time); _; }
-
- constructor(
- uint _biddingTime,
- uint _revealTime,
- address payable _beneficiary
- ) public {
- beneficiary = _beneficiary;
- biddingEnd = now + _biddingTime;
- revealEnd = biddingEnd + _revealTime;
- }
-
- /// Place a blinded bid with `_blindedBid` =
- /// keccak256(abi.encodePacked(value, fake, secret)).
- /// The sent ether is only refunded if the bid is correctly
- /// revealed in the revealing phase. The bid is valid if the
- /// ether sent together with the bid is at least "value" and
- /// "fake" is not true. Setting "fake" to true and sending
- /// not the exact amount are ways to hide the real bid but
- /// still make the required deposit. The same address can
- /// place multiple bids.
- function bid(bytes32 _blindedBid)
- public
- payable
- onlyBefore(biddingEnd)
- {
- bids[msg.sender].push(Bid({
- blindedBid: _blindedBid,
- deposit: msg.value
- }));
- }
-
- /// Reveal your blinded bids. You will get a refund for all
- /// correctly blinded invalid bids and for all bids except for
- /// the totally highest.
- function reveal(
- uint[] memory _values,
- bool[] memory _fake,
- bytes32[] memory _secret
- )
- public
- onlyAfter(biddingEnd)
- onlyBefore(revealEnd)
- {
- uint length = bids[msg.sender].length;
- require(_values.length == length);
- require(_fake.length == length);
- require(_secret.length == length);
-
- uint refund;
- for (uint i = 0; i < length; i++) {
- Bid storage bidToCheck = bids[msg.sender][i];
- (uint value, bool fake, bytes32 secret) =
- (_values[i], _fake[i], _secret[i]);
- if (bidToCheck.blindedBid != keccak256(abi.encodePacked(value, fake, secret))) {
- // Bid was not actually revealed.
- // Do not refund deposit.
- continue;
- }
- refund += bidToCheck.deposit;
- if (!fake && bidToCheck.deposit >= value) {
- if (placeBid(msg.sender, value))
- refund -= value;
- }
- // Make it impossible for the sender to re-claim
- // the same deposit.
- bidToCheck.blindedBid = bytes32(0);
- }
- msg.sender.transfer(refund);
- }
-
- // This is an "internal" function which means that it
- // can only be called from the contract itself (or from
- // derived contracts).
- function placeBid(address bidder, uint value) internal
- returns (bool success)
- {
- if (value <= highestBid) {
- return false;
- }
- if (highestBidder != address(0)) {
- // Refund the previously highest bidder.
- pendingReturns[highestBidder] += highestBid;
- }
- highestBid = value;
- highestBidder = bidder;
- return true;
- }
-
- /// Withdraw a bid that was overbid.
- function withdraw() public {
- uint amount = pendingReturns[msg.sender];
- if (amount > 0) {
- // It is important to set this to zero because the recipient
- // can call this function again as part of the receiving call
- // before `transfer` returns (see the remark above about
- // conditions -> effects -> interaction).
- pendingReturns[msg.sender] = 0;
-
- msg.sender.transfer(amount);
- }
- }
-
- /// End the auction and send the highest bid
- /// to the beneficiary.
- function auctionEnd()
- public
- onlyAfter(revealEnd)
- {
- require(!ended);
- emit AuctionEnded(highestBidder, highestBid);
- ended = true;
- beneficiary.transfer(highestBid);
- }
- }
-
+.. include:: examples/blind-auction.rst
.. index:: purchase, remote purchase, escrow