Skip to content

ederjohn/solidity-examples

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Solidity Smart Contract Examples

Solidity smart contracts examples and Ethereum setup information for the Blockchains and Overlay Networks class at the University of Zurich. Repository forked from the CSG official Repostory, thanks @tbocek 👍

Click here for the full Solidity Documentation.

Click here for a video explaining the Application Binary Interface (ABI) of Ethereum Smart Contracts (Useful for interacting with the Smart Contract)

First steps

Make sure you have geth and the Solidity Compiler installed in your computer. We are going to be using the geth console, so get familiar with it 😃

PS: All the commands in the repository were executed and tested in a Ubuntu 16.04 "xenial".

PS2: You can create a Virtual Machine (VM) using Virtual Box and install Ubuntu 16.04 if you don't want to change any boot configuration in your PC. For a tutorial on how to perfom the install refer here.

Version information

Before geth 1.6, a Solidity file could be compiled from within geth. The file had to be prepared and newlines had to be removed

#old, does not work anymore since geth 1.6
$ grep -o '^[^//]*' example1.sol | tr --delete '\n\t' > /tmp/test.js

Since geth 1.6 it can be done with the following command

$ echo "var testOutput=`solc --optimize --combined-json abi,bin,interface Test.sol`" > test.js

As reported here. The issue is reported here.

Setting up your private Ethereum testnet

To allow the rapid development of smart contracts and not have to download the entire public Ethereum testnet, we are going go to create a private testnet. The instructions were retrieved from here, so refer there for more information.

Creating the custom Data Directory

The data directory is where all the information regarding the blockchain (including the blockchain) is going to be stored.

$ cd ~ 
$ mkdir privateEthTestnet
$ cd privateEthTestNet

Creating the genesis block

Copy the genesisBlock.json file to the privateEthTestnet directory.

$ cp genesisBlock.json ~/privateEthTestnet/

Creating the blockchain

Now we create a database using the genesis block.

$ cd ~/privateEthTestNet/
$ geth --datadir ~/privateEthTestnet/ init genesisBlock.json

If everything went fine you should see something like this

INFO Writing custom genesis block
INFO Successfully wrote genesis state         database=lightchaindata                                   hash=ab944c…55600c

Creating Accounts

We are going to have two accounts. Both with password "123456", as we are in a private testnet we don't need strong passwords, but mind to use strong passwords in the real world 😉

Start geth in one terminal

$ geth --datadir ~/privateEthTestnet --networkid 3107 --fast --rpc --rpcapi eth,web3,personal,net,miner,admin

Attach another instance of the geth console in another terminal

$ geth attach http://127.0.0.1:8545

> eth.accounts
[]
> personal.newAccount()
Passphrase: 123456
Repeat passphrase: 123456 
"0x41e26b3c7...43dd30cfb11"
> personal.newAccount()
Passphrase: 123456
Repeat passphrase: 123456
"0x844268de3...c988eecc4f2"
> eth.accounts
["0x41e26b3c7...43dd30cfb11", "0x844268de3...c988eecc4f2"]

Great! Now we have two accounts in the blockchain! unfortunately, they don't have ether yet, so let's mine a couple of ether.

Mining some ether ⛏️

On the geth console, set the account that will receive the ether from the mining

> miner.setEtherbase(eth.accounts[0])
true

Start the miner with 4 threads

> miner.start(4)
null

You should see some CPU activity and in the other geth console something like this:

INFO Commit new mining work                   number=1 txs=0 uncles=0 elapsed=225.785µs
INFO Generating DAG in progress               epoch=0 percentage=80 elapsed=2m4.249s
...
INFO 🔗 block reached canonical chain          number=40 hash=32e77d…f9aac3
INFO 🔨 mined potential block                  number=45 hash=29be2c…e74788
INFO Commit new mining work

You can check the balance of your account

> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")

Once you have a couple of ethers you can stop the mining

> miner.stop()
true

⚠️ Important information ⚠️

  • You must mine every transaction in your private test network.

Thus, it is good to always leave the miner running:

> miner.start(2)
true

First Example

The first example is a very simple contract

pragma solidity ^0.4.10;

//the very first example
contract Example1 {
        uint stateVar;
}

Make sure you have started geth before

$ geth --datadir ~/privateEthTestnet --fast --rpc --rpcapi eth,web3,personal,net,miner,admin
$ geth attach http://127.0.0.1:8545

run the deploy script deploy.sh

$ ./deploy.sh examples/example1.sol

Now switch to the attached geth console and load the resulting script

> loadScript("/tmp/test.js")

Eventually, you'll see something like this

Contract mined! address: 0xfb821bf9e66a5decb43a92fc615bbbdb296df462 transactionHash: 0xda816929b1764fa9736f02505e94bfdeace098a4348057ddacb0baf466dfda5e

You have mined you first contract!

Now we'll store a state and access the state.

Deploy the contract by running (you have to do this to every new contract):

$ ./deploy.sh examples/example2.sol

Now switch to the attached geth console and load the resulting script

> loadScript("/tmp/test.js")

Once the contract has been mined you can interact with it

> test.push("someString")

If you see something like this

Error: invalid address

Set the default account of the wallet and try the push command again

> eth.defaultAccount=eth.accounts[0]
"0x41e26b3c7b...420000ae9643dd30cfb11"
> test.push("someString")
"0x58fbadf2567f43aa443623d5c237dbcaa387b01757c84586251f035e12f323ee"

Now we can retrieve the value:

> test.get(0)
"someString"

In the third example we are going to work with structs. This contract has a struct named "Account" that stores an address and an amount. Calling the function creates(address) creates an entry in the accounts list and sets the owner of the contract to be the address that called the function.

> test.create(eth.accounts[0],{gas:2100000})

⚠️ Every transaction that modifies a state in the Smart Contract consumes what Ethereum calls "gas", so that is the reason why we pass as argument an amount of "gas". This amount, in wei, is deducted from your account, and if the function does not consume all the gas, the difference will be returned. If you specify too little gas, the function will not run. Thus, if your function does not run, maybe you need to specify more gas when calling the function. Refer here for more information about gas and gas price.

If we call the get function passing as argument 1 we should get the address that was stored in the function Example3:

> test.get(1)
"0x41e26b3c7b...420000ae9643dd30cfb11"

We can also create entries to new addresses and specify the amount that the address will have. This function contains a condition that specify that only the owner of the contract (i.e., the address that called the Example3 function) can create new entries and amounts.

> test.set(66, eth.accounts[1],{gas:2100000})
true

Now if we call the getAmount function we can see the amount of the second address in the accounts list.

> test.getAmount(2) #second account
66
> test.getAmount(1) #first account
42

This example introduces the concept of Events in Solidity. Events are signals that the smart contract can issue and applications can listen to these events. To implement an application that listens/watches to a specific Event of a contract, please refer to this brief course. Events are important when implementing Distributed Applications based on Solidity.

Regarding the Example 4, everytime the function set is called, if the sender of the message is the owner of the contract, then an event of the type Message is called.

	event Message(
        string msg
    );
    .
    .
    .
    function set(uint nr, string addr) returns (bool) {
	if(owner == msg.sender) {
            accounts[counter++] = Account(addr, nr);
            Message("all set!");
            return true;
        } else {
            return false;
        }
    }

In this example we are going to store some amount of Ethers in the smart contrat and we will be able to withdraw an arbitrary amount from our account. We can deposit an amount of ether by calling the deposit function, note that the value is in Wei not Ether (see EtherConverter.online):

> test.deposit({from: eth.accounts[0], value: web3.toWei(1,"ether")})
> test.balance()
1000000000000000000

Now that we have some amount deposit in the smart contract, we can withdraw a specific amount:

> test.withdraw(web3.toWei(0.5,"ether"))
true
> test.balance()
500000000000000000
> test.withdraw(web3.toWei(0.5,"ether"))
true
> test.balance()
0

You tell me, what do you think that this contract is implementing?

How about this one?

This contract implements a contract where you can send the content of a file, which will be hashed and stored in the Smart Contract with your address as the owner of the file. Thus, if someone wants to store the same file, it will not be able to store it because the hash of the file's content is already registered to a address.

Releases

No releases published

Packages

No packages published

Languages

  • Shell 100.0%