mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8010 from ethereum/docs_solidity_by_example
Docs Solidity by example
This commit is contained in:
commit
6a065bc982
@ -4,12 +4,10 @@
|
|||||||
Blind Auction
|
Blind Auction
|
||||||
*************
|
*************
|
||||||
|
|
||||||
In this section, we will show how easy it is to create a
|
In this section, we will show how easy it is to create a completely blind
|
||||||
completely blind auction contract on Ethereum.
|
auction contract on Ethereum. We will start with an open auction where
|
||||||
We will start with an open auction where everyone
|
everyone can see the bids that are made and then extend this contract into a
|
||||||
can see the bids that are made and then extend this
|
blind auction where it is not possible to see the actual bid until the bidding
|
||||||
contract into a blind auction where it is not
|
|
||||||
possible to see the actual bid until the bidding
|
|
||||||
period ends.
|
period ends.
|
||||||
|
|
||||||
.. _simple_auction:
|
.. _simple_auction:
|
||||||
@ -17,16 +15,12 @@ period ends.
|
|||||||
Simple Open Auction
|
Simple Open Auction
|
||||||
===================
|
===================
|
||||||
|
|
||||||
The general idea of the following simple auction contract
|
The general idea of the following simple auction contract is that everyone can
|
||||||
is that everyone can send their bids during
|
send their bids during a bidding period. The bids already include sending money
|
||||||
a bidding period. The bids already include sending
|
/ Ether in order to bind the bidders to their bid. If the highest bid is
|
||||||
money / ether in order to bind the bidders to their
|
raised, the previously highest bidder gets their money back. After the end of
|
||||||
bid. If the highest bid is raised, the previously
|
the bidding period, the contract has to be called manually for the beneficiary
|
||||||
highest bidder gets her money back.
|
to receive their money - contracts cannot activate themselves.
|
||||||
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.
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -161,38 +155,31 @@ activate themselves.
|
|||||||
Blind Auction
|
Blind Auction
|
||||||
=============
|
=============
|
||||||
|
|
||||||
The previous open auction is extended to a blind auction
|
The previous open auction is extended to a blind auction in the following. The
|
||||||
in the following. The advantage of a blind auction is
|
advantage of a blind auction is that there is no time pressure towards the end
|
||||||
that there is no time pressure towards the end of
|
of the bidding period. Creating a blind auction on a transparent computing
|
||||||
the bidding period. Creating a blind auction on a
|
platform might sound like a contradiction, but cryptography comes to the
|
||||||
transparent computing platform might sound like a
|
rescue.
|
||||||
contradiction, but cryptography comes to the rescue.
|
|
||||||
|
|
||||||
During the **bidding period**, a bidder does not
|
During the **bidding period**, a bidder does not actually send their bid, but
|
||||||
actually send her bid, but only a hashed version of it.
|
only a hashed version of it. Since it is currently considered practically
|
||||||
Since it is currently considered practically impossible
|
impossible to find two (sufficiently long) values whose hash values are equal,
|
||||||
to find two (sufficiently long) values whose hash
|
the bidder commits to the bid by that. After the end of the bidding period,
|
||||||
values are equal, the bidder commits to the bid by that.
|
the bidders have to reveal their bids: They send their values unencrypted and
|
||||||
After the end of the bidding period, the bidders have
|
the contract checks that the hash value is the same as the one provided during
|
||||||
to reveal their bids: They send their values
|
the bidding period.
|
||||||
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
|
Another challenge is how to make the auction **binding and blind** at the same
|
||||||
**binding and blind** at the same time: The only way to
|
time: The only way to prevent the bidder from just not sending the money after
|
||||||
prevent the bidder from just not sending the money
|
they won the auction is to make them send it together with the bid. Since value
|
||||||
after they won the auction is to make her send it
|
transfers cannot be blinded in Ethereum, anyone can see the value.
|
||||||
together with the bid. Since value transfers cannot
|
|
||||||
be blinded in Ethereum, anyone can see the value.
|
|
||||||
|
|
||||||
The following contract solves this problem by
|
The following contract solves this problem by accepting any value that is
|
||||||
accepting any value that is larger than the highest
|
larger than the highest bid. Since this can of course only be checked during
|
||||||
bid. Since this can of course only be checked during
|
the reveal phase, some bids might be **invalid**, and this is on purpose (it
|
||||||
the reveal phase, some bids might be **invalid**, and
|
even provides an explicit flag to place invalid bids with high value
|
||||||
this is on purpose (it even provides an explicit
|
transfers): Bidders can confuse competition by placing several high or low
|
||||||
flag to place invalid bids with high value transfers):
|
invalid bids.
|
||||||
Bidders can confuse competition by placing several
|
|
||||||
high or low invalid bids.
|
|
||||||
|
|
||||||
|
|
||||||
::
|
::
|
||||||
@ -296,24 +283,6 @@ high or low invalid bids.
|
|||||||
msg.sender.transfer(refund);
|
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.
|
/// Withdraw a bid that was overbid.
|
||||||
function withdraw() public {
|
function withdraw() public {
|
||||||
uint amount = pendingReturns[msg.sender];
|
uint amount = pendingReturns[msg.sender];
|
||||||
@ -339,4 +308,22 @@ high or low invalid bids.
|
|||||||
ended = true;
|
ended = true;
|
||||||
beneficiary.transfer(highestBid);
|
beneficiary.transfer(highestBid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -354,17 +354,6 @@ The full contract
|
|||||||
expiration = now + duration;
|
expiration = now + duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidSignature(uint256 amount, bytes memory signature)
|
|
||||||
internal
|
|
||||||
view
|
|
||||||
returns (bool)
|
|
||||||
{
|
|
||||||
bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));
|
|
||||||
|
|
||||||
// check that the signature is from the payment sender
|
|
||||||
return recoverSigner(message, signature) == sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// the recipient can close the channel at any time by presenting a
|
/// the recipient can close the channel at any time by presenting a
|
||||||
/// signed amount from the sender. the recipient will be sent that amount,
|
/// signed amount from the sender. the recipient will be sent that amount,
|
||||||
/// and the remainder will go back to the sender
|
/// and the remainder will go back to the sender
|
||||||
@ -391,6 +380,17 @@ The full contract
|
|||||||
selfdestruct(sender);
|
selfdestruct(sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isValidSignature(uint256 amount, bytes memory signature)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));
|
||||||
|
|
||||||
|
// check that the signature is from the payment sender
|
||||||
|
return recoverSigner(message, signature) == sender;
|
||||||
|
}
|
||||||
|
|
||||||
/// All functions below this are just taken from the chapter
|
/// All functions below this are just taken from the chapter
|
||||||
/// 'creating and verifying signatures' chapter.
|
/// 'creating and verifying signatures' chapter.
|
||||||
|
|
||||||
|
@ -38,9 +38,6 @@ and the sum of all balances is an invariant across the lifetime of the contract.
|
|||||||
event Transfer(address from, address to, uint amount);
|
event Transfer(address from, address to, uint amount);
|
||||||
event Approval(address owner, address spender, uint amount);
|
event Approval(address owner, address spender, uint amount);
|
||||||
|
|
||||||
function balanceOf(address tokenOwner) public view returns (uint balance) {
|
|
||||||
return balances[tokenOwner];
|
|
||||||
}
|
|
||||||
function transfer(address to, uint amount) public returns (bool success) {
|
function transfer(address to, uint amount) public returns (bool success) {
|
||||||
balances.move(msg.sender, to, amount);
|
balances.move(msg.sender, to, amount);
|
||||||
emit Transfer(msg.sender, to, amount);
|
emit Transfer(msg.sender, to, amount);
|
||||||
@ -62,4 +59,8 @@ and the sum of all balances is an invariant across the lifetime of the contract.
|
|||||||
emit Approval(msg.sender, spender, tokens);
|
emit Approval(msg.sender, spender, tokens);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function balanceOf(address tokenOwner) public view returns (uint balance) {
|
||||||
|
return balances[tokenOwner];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,19 +31,11 @@ you can use state machine-like constructs inside a contract.
|
|||||||
uint public value;
|
uint public value;
|
||||||
address payable public seller;
|
address payable public seller;
|
||||||
address payable public buyer;
|
address payable public buyer;
|
||||||
|
|
||||||
enum State { Created, Locked, Release, Inactive }
|
enum State { Created, Locked, Release, Inactive }
|
||||||
// The state variable has a default value of the first member, `State.created`
|
// The state variable has a default value of the first member, `State.created`
|
||||||
State public state;
|
State public state;
|
||||||
|
|
||||||
// Ensure that `msg.value` is an even number.
|
|
||||||
// Division will truncate if it is an odd number.
|
|
||||||
// Check via multiplication that it wasn't an odd number.
|
|
||||||
constructor() public payable {
|
|
||||||
seller = msg.sender;
|
|
||||||
value = msg.value / 2;
|
|
||||||
require((2 * value) == msg.value, "Value has to be even.");
|
|
||||||
}
|
|
||||||
|
|
||||||
modifier condition(bool _condition) {
|
modifier condition(bool _condition) {
|
||||||
require(_condition);
|
require(_condition);
|
||||||
_;
|
_;
|
||||||
@ -78,6 +70,15 @@ you can use state machine-like constructs inside a contract.
|
|||||||
event ItemReceived();
|
event ItemReceived();
|
||||||
event SellerRefunded();
|
event SellerRefunded();
|
||||||
|
|
||||||
|
// Ensure that `msg.value` is an even number.
|
||||||
|
// Division will truncate if it is an odd number.
|
||||||
|
// Check via multiplication that it wasn't an odd number.
|
||||||
|
constructor() public payable {
|
||||||
|
seller = msg.sender;
|
||||||
|
value = msg.value / 2;
|
||||||
|
require((2 * value) == msg.value, "Value has to be even.");
|
||||||
|
}
|
||||||
|
|
||||||
/// Abort the purchase and reclaim the ether.
|
/// Abort the purchase and reclaim the ether.
|
||||||
/// Can only be called by the seller before
|
/// Can only be called by the seller before
|
||||||
/// the contract is locked.
|
/// the contract is locked.
|
||||||
|
Loading…
Reference in New Issue
Block a user