Building the smart contract with Solidity, step-by-step

Solidity basic value types

Name

Description

Example

string

Set of characters that can also contain spaces and numbers

“Decentralized Future"

int

Both positive and negative integers (256 bits)

1532, -35000, -42

uint

Positive Integers (256 bits)

1000, 5, 2024

bool

Boolean value

true, false

address

Holds a 20 byte value (size of an Ethereum address)

0x72bA7d8E73Fe8Eb666Ea66babC8116a41bFb10e2

Solidity reference types

Name

Description

Example

Fixed array

Array with a single type of element.
It has a fixed length.

string[2] -> [“BTC”, “Ether”]

int[5] -> [1, 6, 3, 2, 5]

Dynamic array

Array with a single type of element.

Length can change.

address[] -> [
0xEF4d0D58334df71aBF12e5041C6FEcAFdA861bF,
0x72bd7d8E73Fe8db666da66babC8116a41bFb10e2]

mapping

Key value pairs. Such as Dictionaries in Python.

mapping(address => boolean)

mapping(string => string)

struct

Collection of key value pairs with different types.

struct User {
address account;
string name;
int balance;
bool active;
}

You can find more specific details on the Solidity documentation website: *https://solidity.readthedocs.io/en/v0.4.24/

Building the Solidity Smart Contract, Step-by-step

  • .sol refers to a file written in solidity, which is the most widely used programming language to develop contracts for the Ethereum Virtual Machine (EVM), running on every node of the Ethereum network.
  • Every .sol file starts with a line called the pragma, that specifies the version of the Solidity compiler that a source file can work on.
  • For our lottery contract, we will use a version of the solidity compiler that is at least 0.4.24 or more recent. Therefore the first line of our program goes as such:
  • We now proceed to define our contract as Lottery.
  • Inside the curly braces, we will define the state variables, functions and properties of the contract.

A contract in solidity could be thought of as a class.

We will start with the state variables, which will hold the address of the manager (account that deploys the contract), and an array of addresses that contains the players, who participate in the lottery.

This is the way in which we initialize the variable in our contract called manager, that holds a value of type address, and it has a public access property, which means an api, or a WebApp can read it.

  • Now we define the players:

This is a variable named players, that references a dynamic array of addresses, which also has public access, so other smart contracts or apis can read the participants in the lottery contest.

  • In the next step, we create a constructor, or an “initializer” for our contract, once it is deployed in the ethereum blockchain.

Every change of state of the Global Ethereum Virtual Machine (EVM), is triggered by a transaction. A transaction has a sender and a recipient. And each of them can be an Ethereum address or a smart contract.

In Solidity the “msg” object describes the attributes of the transaction. So by accessing its properties, we can find out information about its state.

The msg.sender property holds the address of the account that deployed the contract, and therefore our lottery manager. So the address that deploys the contract will be assigned to the variable manager that we previously initialized.

  • This is how our lottery.sol file should look so far:
  • Time to work in the function to enter the Lottery Contest:

The function is defined with 2 properties:
a) public, which makes it publicly accessible.
b) payable, which allows the function to be triggered by a transaction that sends ether along with it. The ether will be used to fund the pool prize, and finally, reward the winner.

The second line uses the built-in function require, which asserts a condition to be true to continue the execution, or else, escape the function.

In this case, we want to make sure that whoever triggers his function, transfer along with it more than 0.1 ether, as a condition to participate in the lottery.

The third line appends the address of the account that triggered the function to the array of players we initialized at the beginning of the contract.

  • Next function to work on is selectWinner, but before that we must program a function that generates a pseudo-random number from an initial set of conditions.

We will create a function that aims to use different information such as : the block difficulty, current time, and our array of players, to generate a hash, to approximate a pseudo-random number.
The problem of finding a true source of entropy and therefore randomness, is a hard one.
Our pseudo-random number generator is useful for our example, but it must not be used for final-user applications under any circumstance, because some parameters we are using as our source of entropy could be manipulated by miners.

  • The first line defines the function called pseudoRandom, defined with 2 properties:

a) private, which indicates its use by other functions inside the contract.
b) View. It indicates that this function does not change the state of any of the variables of our contract. It can read, but it cannot write.

There is also the keyword returns, followed by the value type, that the function will return, which in our case will be a uint.

We will then make use of the keccak256 built-in function, which is a hashing algorithm, and takes an argument of bytes.

So we will use another built-in function to pack our sources of entropy in an array of bytes.

abi.encodePacked, takes multiple arguments and returns an encoded array of bytes from them. We will pass the difficulty of mining the block where the transaction was inserted, the current time, and our array of players.

Finally we will convert the result of the keccak256 function to uint, and return it, so we can use it later on.

Our function should look like this:

Now we can make use of our pseudoRandom number generator in a new function we will call selectWinner.

In the second line we will initialize a uint variable called winnerIndex, which will be calculated by taking the number from our pseudoRandom function and calculating the reminder (%) of dividing it by the length of our players array.

In the third line, there are different things going on.
a) We get the winner by accessing the players array with the winnerIndex we just calculated.
b) We use the syntax: address(this).balance to read the amount of ether available in this contract, which is equal to the total amount of ether sent by every player to enter the lottery.
c) Finally we use the transfer method on the address of the winner, and we transfer all the ether available in our contract.

Finally we reference the array of players, and set it to a new dynamic array of addresses, with an initial length of 0. Effectively restarting our contract, and making it available for a new set of players.

  • There is a huge security issue in our selectWinner function. As it is written right now, anyone can trigger it and end the contest without the approval of the manager.
  • We should restrict this function. Enter modifiers.
  • Modifiers are like decorators in Python. A function that wraps around another function that references it.

The first line names the modifier as managerOnly.

The second line requires that the address of the account that triggers the function that uses the modifier is equal to the manager address.

The third line, will be replaced by the function where this modifier is referenced.

We will finally add it, in our definition of our selectWinner function:

With that change now our function can only be called by the manager. As the modifier requires it.

As a final helper function, we could create a function called getPlayers, to get the whole array, of the players in our lottery.

  • Our contract should finally look like this and is ready to be tested.