Project Eth 3: Making an Auction

What You Need

An Ethereum host that is mining, as you prepared in a previous project.

Purpose

To learn more about Solidity and Contracts.

Starting Mining

If the geth console is not open, execute this command to start it:
geth --mine --datadir eth-data --networkid 123 --nodiscover --maxpeers 0 console 2>>geth.log
To verify that it's mining, execute this command to see the current block. Then wait 30 seconds and execute it again.
eth.blockNumber
The block number should increase, as shown below.

Unlocking your Account

To spend Ether, you must unlock your account. In the geth console, execute these commands:
primary = eth.accounts[0]
personal.unlockAccount(primary)
Enter your password. After a pause of several seconds, the response is "true", as shown below.

Understanding the Auction Contract

Here's the code for an Auction. Don't enter this code into the terminal--it's just presented here so you can read through it more easily.

The owner owns the object being auctioned.

The placeBid() method is called with an amount of Ether. It does nothing unless the bid is larger than the leading bid; if it is, that bid becomes the leader, and the previous bid's Ether is returned.

Only the owner can cann endAuction(), and then the owner collects the Ether from the winning bid.

contract Auction {
    event newBid();
    address owner;
    address public leader;
    address public winner;
    string public item;
    uint public leadingBid;

    function Auction(string name, uint price) {
        owner = msg.sender;
        item = name;
        leadingBid = price;
    }
    function placeBid() {
        if (msg.value > leadingBid) {
            returnPrevBid();
            leader = msg.sender;
            leadingBid = msg.value;
            newBid();
        }
    }
    function returnPrevBid() {
        if (leader != 0) {
            leader.send(leadingBid);
        }
    }
    function endAuction() {
       if (msg.sender == owner) {
           winner = leader;
           owner.send(leadingBid);
       }
   }
}
    

Entering your Contract Source Code

In the geth console, copy and paste in this command. It includes the whole source code of your contract, without carriage returns, on one line.
var auctionSource = 'contract Auction { event newBid(); address owner; address public leader; address public winner; string public item; uint public leadingBid; function Auction(string name, uint price) { owner = msg.sender; item = name; leadingBid = price; } function placeBid() { if (msg.value > leadingBid) { returnPrevBid(); leader = msg.sender; leadingBid = msg.value; newBid(); } } function returnPrevBid() { if (leader != 0) { leader.send(leadingBid); } } function endAuction() { if (msg.sender == owner) { winner = leader; owner.send(leadingBid); } }}'
Only the end of the code is visible, and the reply is "undefined", as shown below.

To see the source, execute this command:

auctionSource
The source code appears, as shown below.

Compiling your Contract

In the geth console, execute this command.
var auctionCompiled = eth.compile.solidity(auctionSource)
The reply is "undefined" again, as shown below.

To see the compiled code, execute this command:

auctionCompiled
The "auctionCompiled" object prints out, as shown below. The attribute auctionCompiled.Auction.code contains a large blob of hexadecimal data, and the other sections like auctionCompiled.info and auctionCompiled.info.source are more readable.

Preparing your Contract for Deployment

In the geth console, paste in these commands.
var auctionContract = web3.eth.contract(auctionCompiled.Auction.info.abiDefinition);
function Auction(name, price) {
    return auctionContract.new(
       name,
       price,
	  {
    	from:web3.eth.accounts[0], 
 	   data:auctionCompiled.Auction.code, 
    	gas: 3000000
 	 }, function(e, contract){
        console.log(e, contract);
        if (typeof contract.address != 'undefined') {
             console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
        }
     })
}
The reply is "undefined" again, as shown below.

To see the autionContract, execute this command:

auctionContract
The contract is 2 or 3 screens long, ending in a long list of functions, as shown below.

Starting an Auction

To start an Auction for a "cat" with a starting bid of 0.5 Ether, execute this command:
var myAuction = Auction("cat", web3.toWei(0.5, "ether"))
After 30 seconds, the contract should be mined, as shown below.

Interacting with the Contract

In the geth console, execute this command:
myAuction
You see the structure of the myAuction object, including functions such as "leader" and "item", as shown below.

To see the current status of the auction, execute these commands:

myAuction.item()
myAuction.leadingBid()
myAuction.leader()
The item is "cat", and the leader is all zeroes, as shown below.

The leading bid is 500,000,000,000,000,000 in "wei" units, which is 0.5 Ether. Ethereum uses far too many units, as shown below.

To see the leading bid in Ether, execute this command:

web3.fromWei(myAuction.leadingBid())
The bid appears in a more readable form, as shown below.

Setting Up a Watcher

The watcher will print a message on the console every time anyone bids on the auction.

In the geth console, execute this command.

var event = myAuction.newBid(function(error, result){
  if (!error)
    console.log("New bid placed for " + web3.fromWei(myAuction.leadingBid(),"ether") + " Ether from " +  myAuction.leader());
});
The reply is "undefined", as shown below.

Placing a Bid

In the geth console, execute this command to place a bid:
myAuction.placeBid({from: personal.listAccounts[0], value: web3.toWei(0.6, "ether")})
The transaction ID appears, and within 30 seconds, the watcher prints out the new bid amount and account number, as shown below.

Creating a New Account

In the geth console, execute these commands to create a new account:
personal.newAccount()
Enter a password twice. Your new account's address appears, as shown below.

Viewing All Accounts

In the geth console, execute this command to see all account numbers.
personal.listAccounts
You now have two or more accounts, as shown below.

Sending Ether to the Second Account

In the geth console, execute this command:
eth.sendTransaction({from:eth.accounts[0], to:eth.accounts[1], value: web3.toWei(5, "ether")})
A transaction ID appears, as shown below.

Unlocking the Second Account

In the geth console, execute this command:
personal.unlockAccount(eth.accounts[1])
Enter your password. After a pause of several seconds, the response is "true", as shown below.

Placing Another Bid

In the geth console, execute this command to check the secondary account balance, place a bid, and check the balance again:
web3.fromWei(eth.getBalance(personal.listAccounts[1]), "ether")
myAuction.placeBid({from: personal.listAccounts[1], value: web3.toWei(2, "ether")})
web3.fromWei(eth.getBalance(personal.listAccounts[1]), "ether")
The transaction ID appears, but the account balance does not fall immediately, as shown below.

After the transaction is mined, repeat this command to see the reduced balance:

web3.fromWei(eth.getBalance(personal.listAccounts[1]), "ether")

Unlocking the Primary Account

In the geth console, execute this command:
personal.unlockAccount(eth.accounts[0])
Enter your password. After a pause of several seconds, the response is "true", as shown below.

Ending the Auction

In the geth console, execute these commands to end the auction and see the winner:
myAuction.endAuction({from: personal.listAccounts[0]})
myAuction.winner()

Sources

Contract Tutorial
Ethereum Frontier Guide
Ethereum hands-on tutorial


Posted 7-11-16 by Sam Bowne