Write in front: The HiBlock blockchain community has set up a translation group (Ethereum Chinese community) to translate technical documents and information on blockchain. This is the third part of the Solidity document translation titled “Learn Solidity from examples” for public review. You can add wechat baobaotalk_com, verify and enter “solidity” and send us your views and suggestions, or leave a comment in the “comments” area at the end of the article. If you have valid ideas we will incorporate them into the next version and send you a small gift to show your appreciation.

1

vote

The following contract is quite complex but shows a lot of Solidity functionality. It implements a voting contract. Of course, the main problems with electronic voting are how to allocate votes to the right people and how to prevent manipulation. We’re not going to solve all the problems here, but at least we’re going to show how to do a proxy vote, and at the same time, the count is automatic and completely transparent.

The idea is to create a contract for each vote, providing acronyms for each option. Then as the creator of the contract, the chairman, would give each individual address a vote.

The people behind the address can choose to vote themselves, or entrust the vote to someone they trust.

At the end of voting time, winningProposal() returns the proposal that received the most votes.

Pragma solidity ^ 0.4.16;

/// @title proxy vote

Contract Ballot {* // Here a new compound type is declared for later variables ** // it is used to represent a Voter ** struct** Voter {uint weight; ** * bool** commented; // If true, the delegate has voted. // Client ** uint** vote; // Index of ballot proposals}

Struct Proposal {bytes32 name; ** uint** voteCount; // Get the vote}

**  address** public chairperson;

* // This declares a state variable that stores a Voter for each possible address. * mapping(address => Voter) public voters;

* // A Proposal structure type dynamic array * Proposal[] public proposals;

/// For each proposalNames in the proposalNames, create a new (vote) function Ballot(bytes32[] proposalNames) public {Chairperson = msG.sender; voters[chairperson].weight = 1; * // For each Proposal name provided, * * // creates a new Proposal object and adds it to the end of the array. * ** for** (uint i = 0; i < proposalNames.length; i**++**) { * // Proposal({… }) create a temporary Proposal object, * * // proposals. Push (…) Proposals * proposals. Push (Proposal({name: proposalNames[I], voteCount: 0})); }}

// Authorizes voter to vote on this (voting) // Only Chairperson can call this function. ** function** giveRightToVote(address voter) public {* / And it doesn’t consume gas. // If the function is called incorrectly, it is a good choice to use require. * require( (msg.sender == chairperson) && ! voters[voter].voted && (voters[voter].weight == 0) ); voters[voter].weight = 1; }

/// delegate your vote to the voter. Function delegate(address to) *public {Voter storage sender = Voter [msg.sender]; require(! **sender.voted);

* // Require (to**! =** msg.sender);

* // Delegates can be passed as long as the principal to also sets the delegate. // In general, this kind of circular delegation is dangerous. Because if the chain is too long, // it may consume more gas than is left in the block (greater than the gasLimit set by the block), in which case the delegate will not be executed. // In other cases, a closed loop makes the contract completely stuck. * while (voters[to].delegate ! = address(0)) { to = voters[to].delegate;

* // do not allow closed loop delegate * require(to! = msg.sender); }

“> < div style =” box-sizing: border-box; margin-top: 0px; margin-bottom: 0px; sender.delegate = to; Voter storage delegate_ = voters[to]; **if (delegate_.vote) {* // if (delegate_.vote) {if (delegate_.vote) {* // if (delegate_.vote) {if (delegate_.vote) {if (delegate_.vote) {if (delegate_.vote) {if (delegate_.vote) { } else {* // Add delegate_.weight += sender.weight; }}

* // put your tickets (including those entrusted to you), Public {Voter storage sender = Voter [MSG. Sender]; require(**! **sender.voted); sender.voted = true; sender.vote = proposal;

VoteCount ** +=** Sender.weight; * // If the proposal exceeds the scope of the array, an exception will be automatically raised and all changes will be restored. }

/// @dev combined with all previous votes, ** Function ** winningProposal() public view ** returns** (uint winningProposal_) {** uint** winningVoteCount = 0; ** for** (uint p = 0; p < proposals.length; p**++) { ** if (proposals[p].voteCount > winningVoteCount) { winningVoteCount = proposals[p].voteCount; winningProposal_ = p; }}}

// Call the winningProposal() function to get the index of the winners in the proposal array, Function ** winnerName() public view ** returns** (bytes32 winnerName_) {winnerName_ **= **proposals[winningProposal()].name; }

}

Possible optimization

Currently, many transactions need to be executed to distribute voting rights to all participants. Do you have a better idea?

2

Secret auction (blind auction)

In this section, we will show how to easily create a secret bidding contract on Ethereum. We will start with an open auction where everyone can see the bids, and then extend this contract to blind auctions where actual bids cannot be seen until the bidding period is over.

A simple public auction

The general idea of the following simple auction contract is that everyone can send their bid within the bidding period. Bids already contain money/Ether to bind bidders to their bids. If the highest bid is raised (outbid by another bidder), the previous highest bidder gets her money back. At the end of the bidding period, the beneficiary needs to manually invoke the contract to receive his money – the contract cannot activate the receipt itself.

Pragma solidity ^ 0.4.21;

Contract SimpleAuction {* // Auction parameters. * address public beneficiary; * // Time is a Unix absolute timestamp (seconds since 1970-01-01) // or a time period in seconds. * uint public auctionEnd;

** * Address ** public highestBidder; uint public highestBid;

** mapping(address => uint) pendingReturns;

* // Set to true after the auction ends to disable all changes * bool ended;

** * event** HighestBidIncreased(address bidder, uint amount); event AuctionEnded(address winner, uint amount);

// The following are so-called natSpec comments, which can be identified by three slashes. // will be displayed when the user is asked to confirm the transaction. Free secondary school free secondary school free secondary school free secondary school free secondary school free secondary school free secondary school free secondary school * ** function** SimpleAuction( ** uint** _biddingTime, address _beneficiary ) public { beneficiary = _beneficiary; auctionEnd **= **now + _biddingTime; }

/// Bids are made on the auction, and specific bids are sent along with the transaction. /// If you do not win the auction, the bid is returned. ** function** bid() public payable {* // the parameter is not necessary. Because all the information is already included in the transaction. // The keyword payable is required for functions that can receive Ethereum.

// If the auction has ended, cancel the function call. * require(now <= auctionEnd);

* require(msg.value > highestBid);

** if** (highestBid ! = 0) {* // Simply calling highestBidder. Send (highestBid) is a security risk because it may execute a non-trust contract. // It is safer to let the recipient withdraw the money himself. * pendingReturns[highestBidder] += highestBid; } highestBidder = msg.sender; highestBid = msg.value; emit HighestBidIncreased(msg.sender, msg.value); }

** * function** withdraw() public returns (bool) {uint amount = pendingReturns[MSG. Sender]; ** if **(amount **> *0) {* // It is important to set zero first. As part of the receiving call, the receiver can call the function again before sending returns. pendingReturns[msg.sender] = 0;

** if** (*! PendingReturns [MSG. Sender] = amount; pendingReturns[MSG. Sender] = amount; return false; } } ** return true; }

** * Function ** auctionEnd() public {* // For functions that can interact with other contracts (meaning it calls other functions or sends ether), // A good guideline is to divide the structure into three phases: // 1. Check condition // 2. Perform action (condition may change) // 3. Interacting with other contracts // If these phases are mixed, other contracts may call back the current contract and modify the state, // or cause some effect (such as payment of Ether) to take effect multiple times. // If a function called within a contract contains an interaction with an external contract, // it is also considered to interact with the external contract.

// condition * require(now >= auctionEnd); // Require (**! *ended); // This function has been called * // 2. emit AuctionEnded(highestBidder, highestBid);

* // 3. Secondary education * secondary education (highestBid); }

}

Secret auction (blind auction)

The previous public auction will be expanded into a secret auction. The advantage of a secret auction is that there is no time pressure before the bidding closes. Secret bidding on a transparent computing platform may sound like a contradiction, but cryptography can make it happen.

During bidding, the bidder does not actually send her bid, but only a hash version of the bid. Since it is currently nearly impossible to find two values (long enough) whose hashes are equal, bidders can submit their bids this way. After the bidding closes, bidders must make their bids public: they send their bids unencrypted, and the contract checks whether the hash of the bid is the same as that provided during the bidding.

Another challenge is how to make auctions both binding and secret: the only way to stop a bidder from not paying if she wins the auction is for her to send the money along with her bid. But since money transfers cannot be hidden in Ethereum, anyone can see the money being transferred.

The following contract solves this problem by accepting any value greater than the highest bid. Of course, because this can only be checked at the disclosure stage, some bids may be invalid, and this is intentional (along with the overbid, it even provides a clear flag to flag an invalid bid): bidders can confuse competitors by setting up several invalid bids that are either high or low.

Pragma solidity ^ 0.4.21;

contract BlindAuction {    struct Bid {        bytes32 blindedBid;        uint deposit;    }

address public beneficiary;    uint** public** biddingEnd;   ** uint**** public** revealEnd;    bool** public** ended;

** mapping**(address => Bid[]) **public **bids;

address public highestBidder;   ** uint** **public **highestBid;

Mapping (address =>** uint**) pendingReturns;

event AuctionEnded(address winner, uint highestBid);

* /// Use the modifier to more easily check the input parameter of the function. /// the new function body is the function body of the modifier itself, and _ is replaced with the original function body; Statement. * modifier onlyBefore(**uint **_time) { require(now **< **_time); _; } modifier onlyAfter(uint _time) { require(now > _time); _; }

** function** BlindAuction(        uint _biddingTime,      **  uint **_revealTime,        address _beneficiary    ) public {        beneficiary = _beneficiary;        biddingEnd = now + _biddingTime;        revealEnd = biddingEnd + _revealTime;    }

_blindedBid = keccak256(value, fake, secret) // set up a secret auction. // The sent Ether will only be returned if it is properly disclosed during the bid disclosure phase. /// If the ethereum sent with the bid is at least “value” and “fake” is not true, the bid is valid. /// Setting “fake” to true and sending an amount that meets the deposit amount but is not the same as the bid is a way to hide the actual bid. // multiple bids can be placed on the same address. * function bid(bytes32 _blindedBid) ** public payable** onlyBefore(biddingEnd) { bids[msg.sender].push(Bid({ blindedBid: _blindedBid, deposit: msg.value })); }

* /// Disclose your secret auction bid. /// You will be refunded for all correctly disclosed invalid bids and for all bids except the highest bid. * ** function** reveal( uint[] _values, ** bool**[] _fake, ** bytes32**[] _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++) { ** var bid = bids[msg.sender][i]; var (value, fake, secret)** =** (_values[i], _fake[i], _secret[i]); if (bid.blindedBid ! = keccAK256 (value, fake, secret)) {* // Bid failed to disclose correctly // deposit not returned * continue; } refund += bid.deposit; ** if** (**! **fake && bid.deposit >= value) { *if (placeBid(msg.sender, value)) refund -= value; } * // make it impossible for the sender to claim the same deposit bid.blindedbid =**bytes32(0); } msg.sender.transfer(refund); }

* // This is an “internal” function, ** * function** placeBid means it can only be called in this contract (or succession contract) uint value) internal ** returns (bool success) { ** if (value <= highestBid) { ** return false; ** } ** if** (highestBidder ! PendingReturns [highestBidder] += highestBid; } highestBid = value; highestBidder = bidder; ** return true; * *}

* function withdraw() public {** uint** amount = pendingReturns[MSG. Sender]; ** if** (amount > 0) {* // It is important to set the value to zero. Because, as part of the receiving call, // the receiver can re-call the function before the Transfer returns. PendingReturns [msg.sender] = 0; pendingReturns[msg.sender] = 0;

msg.sender.transfer(amount); }}

* /// Close 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); }

Secure remote purchases

Pragma solidity ^ 0.4.21;

contract Purchase {   ** uint public value;    address public** seller;   ** address **public buyer;    enum State { Created, Locked, Inactive }    State public state;

* // Make sure msg.value is an even number. // If it is an odd number, it is truncated. // Check by multiplication that it is not odd. * ** function** Purchase() public payable { seller = msg.sender; value = msg.value / 2; require((2** *** value) == msg.value); }

modifier condition(bool _condition) {        require(_condition);        _;    }

modifier onlyBuyer() {        require(msg.sender** ==** buyer);        _;    }

modifier onlySeller() {        require(msg.sender **== **seller);        _;    }

modifier inState(State _state) {        require(state == _state);        _;    }

event Aborted(); **   event **PurchaseConfirmed();   ** event **ItemReceived();

* /// Abort the purchase and reclaim the Ether. /// can only be called by the seller before the contract is locked. * function abort() ** public** onlySeller inState(State.Created) { emit Aborted(); state = State.Inactive; seller.transfer(this.balance); }

* /// Buyer confirms purchase. /// The transaction must contain 2 * value ether. /// Ether is locked until confirmReceived is called. * ** function** confirmPurchase() public inState(State.Created) condition(msg.value == (2 * value)) ** payable** { emit PurchaseConfirmed(); buyer = msg.sender; state = State.Locked; }

/// Confirm that you (buyer) have received the goods. /// This releases the locked ether. ** function** confirmReceived() ** public** onlyBuyer inState(State.Locked) { emit ItemReceived(); * // It is important to change the state first, otherwise the contract invoked by transfer can be called back here (again to receive ether). * state = State.Inactive;

* // Note: This actually allows the buyer and seller to block refunds – the retrieve mode should be used. * buyer.transfer(value); seller.transfer(this.balance); }

}

Micropayment channel

To be written.

Note: This is the third part of the solidity translator “Learn Solidity from examples”. For public proofreading, you can add wechat baobaotalk_com, enter “solidity”, and send us your opinions and suggestions. You can also leave a comment in the comments area at the end of this article, or visit our Github via the original link. Valid suggestions will be accepted and improved in time, and a small gift will be sent to you to show our gratitude.

This article is from HiBlock Blockchain community translation group – Ethereum Chinese community, thank all translators for their hard work.

Activity recommendation: technical Sharon | millions yearly salary recruit block chain developer, block chain heat when cool? (Free registration)

Click “Read the original” to see the original translation.