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

Solidity basic value types

NameDescriptionExample
stringSet of characters that can also contain spaces and numbers“Decentralized Future"
intBoth positive and negative integers (256 bits)1532, -35000, -42
uintPositive Integers (256 bits)1000, 5, 2024
boolBoolean valuetrue, false
addressHolds a 20 byte value (size of an Ethereum address)0x72bA7d8E73Fe8Eb666Ea66babC8116a41bFb10e2

Solidity reference types

NameDescriptionExample
Fixed arrayArray with a single type of element.
It has a fixed length.
string[2] -> [“BTC”, “Ether”]

int[5] -> [1, 6, 3, 2, 5]
Dynamic arrayArray with a single type of element.

Length can change.
address[] -> [
0xEF4d0D58334df71aBF12e5041C6FEcAFdA861bF,
0x72bd7d8E73Fe8db666da66babC8116a41bFb10e2]
mappingKey value pairs. Such as Dictionaries in Python.mapping(address => boolean)

mapping(string => string)
structCollection 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

501501
  • .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:
485485
  • We now proceed to define our contract as Lottery.
377377
  • 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.

255255

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:
273273

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.
299299

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.

624624

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:
465465
  • Time to work in the function to enter the Lottery Contest:
507507

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.

513513

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.

573573

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.

701701
  • 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.

141141

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.

224224

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.

505505

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:

512512

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

677677

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.

743743

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.

746746

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.
490490

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:

568568

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.

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