Solidity Fundamentals — CryptoZombies Lesson One and Two.
What is Solidity?
The following series of articles are a write up on the LOOM network, solidity coding tutorials CryptoZombies. The tutorials cover all the fundamental aspects of building a gamified decentralised application (D-App) that can be deployed to the Ethereum network, and played by everyone with a ether address on all corners of the globe :)
Solidity is a relatively new programming language so there are not a lot of tutorials to help beginners learn how to code- decentralised style. The aim of these articles is to take you through the CryptoZombie tutorials step by step while providing knowledge of how all the code fits together and gels into one big unstoppable open source, smart contract.
Before we get started, I would like to give a quick introduction to Ethereum and smart contracts so everything is up to speed.
What is Ethereum?
Ethereum is a decentralised programmable blockchain protocol. The protocol achieves decentralisation by allowing the users of the network to sync a full copy of the blockchain onto their machine. Once the machine has synced a full copy of the blockchain it is then considered a node by the network.
https://blockgeeks.com/guides/ethereum/
What are Smart Contracts?
Programs(smart contracts) on Ethereum can be written in languages such as vyper, mutan, LLL, and serpant. However their own language Solidity is the most commonly used language that most smart contracts are written in.
Solidity is a contract-oriented, high-level language for implementing smart contracts. It was influenced by C++, Python and JavaScript and is designed to target the Ethereum Virtual Machine (EVM).
Smart contracts are pieces of code that are deployed to the Ethereum blockchain where they live forever and will always execute without hesitation. They are able to be used for many real world applications that support many different industries such as finance, ecommerce, real estate, supply-chain, medical, education and many more.
Note: These lesson recaps are creating for the intention of either learning CryptoZombies / Solidity or revising the fundamentals. Enjoy the apocalypse and please provide any feedback :) Also before you start the chapters in this article the numbers do not match the LOOM tutorials, chapter 1 in the article is always chapter 2 on the website.
Let’s get started — CryptoZombies Lesson 1 🚀
Chapters 1,2,3 and 4 — Contracts, variables and maths.
The first thing you need write when creating a smart contract is the compiler version. This should and will always be at the top on any smart contract in Ethereum. pragma solidity ^0.4.19
tells the Ethereum Virtual Machine (EVM) what version of the compiler that the contract is to be used on. You can use a old compiler version such as 0.4.10
with a contract that is written when the compiler version is above 0.4.10
, you just have to put ^
before the the version. This will let the compiler know that the contract can be compiled with any version above ^0.4.10;
.Once the pragma solidity
compiler version is specified you can then start to create your smart contract. A contract name and state variables are the next thing to be coded into the contract. The contract name is self-explanatary and should always almost refer to the logic of the contract you are writing.
State variables are used through out the whole state of the contract and are also permanently stored in contract storage which means they are saved to the blockchain.
The state variables we want to give our zombies our a dna Length
of 16 digits. And a dnaModulus
of 10 to the power of 16. Both variables are uints
which means that they are value types of only positive numbers.
http://solidity.readthedocs.io/en/v0.4.21/types.html
Chapters 5 and 6 — Structs && Arrays.
Once you have done the first few chapters of lesson one, you will come to chapter 5 struct
. Structs allow you to code complex data types that hold multiple values. In this particular smart contract we are dealing with zombies and we will want our zombies to have names, dna etc. So for this we will use a struct. Everytime we create a new zombie we will refer to the Zombie
struct so that the zombie will have the nessacary values that it needs to be accepted as genuine in the DAPP. When we have defined the values for a zombie we will want to create a place for each zombie to be stored in the contract this will be an array[]
. Array’s allow for storage of a collection of things in our case, these things are Zombies. Arrays are able to have an infinate size or a fixed size, a array with unlimited storage is called a dynamic array and a fixed size array is called a fixed array. (see syntax below for how both types are defined in a contract).
uint[10] -- This is how a "fixed" sized array would be written into a contract. A fixed sized array only allows for a certain number of objects to be stored into the array hense the name "fixed".uint[] -- this is how a dynamic array is written, dynamic arrays can hold a infinite number of objects, meaning they can just keep growing with no capacity limit.
Chapter 7 — Function declarations.
When all this is done we can then start to add functions to our smart contract. A function declaration has a few parts to it 1: the name of the function, 2: parameters that need to be invovled with the function, 3: accessibility of the function (i.e public, private, internal, external) 4: The function may return a value or be modified so that only a certain person can use the function(more on this is later parts of the series). The first function we want to create in our zombie code is a createZombie
function that will take 2 parameters. In the tutorial you will be asked to leave the body of the function empty for now, we will explain the body in the next paragraph. P.s don’t forget functions always need brackets {}
for the body of the function to go in too.
Chapter 8 — Working with structs and arrays.
Now we can start to use the struct and array we coded in the first couple of chapters to build out the body of our function. The first line of the function should push a new zombie into the zombies array while taking both the parameters _name, _dna
with it to be stored against the zombie that will created when the function is called.
Chapter 9 Public/Private functions.
You will then be asked to make the createZombie function private
so that the function is only callable from within another function in our contract. By default functions are public
which means that they can be called by anyone or any contract globally on the Ethereum network. And this is not good for our game as anyone would be able to create a zombie even if they are not playing the game.
Chapter 10 — More on functions.
In this chapter will be asked to create a another function _generateRandomDna
and pass it one parameter _str
(notice that function parameters always use a underscore this is so they are noticeably different from globally declared parameters such as state variables). This function will also be marked as view
as it will view some of our contracts variables but not modify them. Also the function will return a uint
so once you have defined it as view you should then put the return statement (NOTE: that returns on a function are always put after the parameters and the type of useability of the function).
Chapter 11 — Kecca256 && typecasting.
In the body of the _generateRandomDna
function we will start to make use of some of Ethereum’s hashing functionality with keccak256
which is a version of a SHA3 hashing. It will give you a 256bit hash which will be used as the zombies DNA. You will have to store the hash of keccak256
in a uint
variable called rand
while also passing the parameter _str
. Don’t forget the function has a return
statement so the last line of the function will return rand
divided by dnaModulus
.
Chapter 12 — Putting it all together.
If you’re wondering how this all fits together with functions being private and only viewing data from the smart contract, dont worry your about to experience the magic of solidity first hand. Chapter 12 will have you create a function createRandomZombie
:) which is public and will only take one parameter _name
. In the first line of the function you will need to create a uint variable called randDna
and pass it the _generateRandomDna
function with _name
as a parameter. Then the next line should call the _createZombie
function and use the parameters _name, randDna
. This will allow for you to specify a name for your zombie while getting the 256bit hash produced by the kecca256 implementation on _generateRandomDna
function for the zombie’s dna. Once you have completed chapter 12 theres just one more important peice of code which is missing and is one of the main properties that a blockchain offers to it’s users. #TIMESTAMPING.
Chapter 13 — Events.
Events are a very important part of solidity as they can listen for when things are happening within the code and, when a event is called, it is logged on the blockchain with a timestamp and own tx hash. Once a event
is called in any smart contract in Ethereum it will be saved to the blockchain where it is immutable and can not be change’d or alterd in way that will invalidate the event
. This allows for major transparency in what is happening within smart contracts and what time the action was carried out.
You will be asked to define a event
at the top of your smart contract, and pass it in three parameters zombieId, _name, _dna
. These parameters will also be logged on the blockchain when the event
is called. For the event
to be functional we will have to also change a little bit of the code in the _createZombie
function (line 18) where we pushed the new zombie into the array. You will have to store zombies.push in a uint id
, once you have created the new variable you can then fire the NewZombie
event in the line below. So that whenever the _createZombie
function is called it will also create a new event
on the blockchain that a zombie was created.
Conclusion:
Now you hopefully you have succesfully completed lesson of the cryptoZombies tutorials and have the basic knowledge of how to code a simple smart contract that allows you to create a value and concatenate variables to that value. You have also learned a simple way of creating and auditing a trail of values being created through the form of an event.
Please read on for lesson 2 and lets start getting our zombies to feed on other life forms.
Here is the code for the Lesson 1
CryptoZombies Lesson 2
Awesome… Now that you have gone through Lesson 1, we will be moving onto more cool fundamentals of Solidity. In Lesson 2, we will be learning how to allow our zombies to start ‘feeding’ on other lifeforms.
#LetZombiesBeZombies.🧟
This means that we will be creating a zombieFeeding
contract to write the conditions that allow our zombies to feed and grow.
Let’s get started!
Chapter 1: Mappings and addresses
Addresses
As we know, we all have our own bank accounts. They have a certain sets of numbers which are exclusive identifies to us. That is what an ‘address’ is.
The Ethereum blockchain is made up of accounts, which you can think of like bank accounts. An account has a balance of Ether (the currency used on the Ethereum blockchain), and you can send and receive Ether payments to other accounts, just like your bank account can wire transfer money to other bank accounts.
Each account has an
address
, which you can think of like a bank account number. It's a unique identifier that points to that account, and it looks like this: 0x78079fd6d84e05AaB7BBb8990B656a9Dd1D681B1
Overall it is an address for a specific user or smart contract. You will be interacting with addresses (also know as public keys) to send and receive ether, and even interact with smart contracts.
Mapping
Once again, structs are data structure that lists all the variables under one block. Arrays are the collection of objects that are stored away systematically.
Mapping is another way to store data in Solidity and are similar to structs and arrays.
Try the exercise provided.
Here you would have created a mapping structure of keeping track of the address that owns the zombie(zombieToOwner) and the other for how many zombies the owner has (ownerZombieCount).
Chapter 2: Msg. sender
Now we want to update one of our functions _createZombie
by allowing it to interact with the addresses that we declared. For that we will be using msg.sender
which is quite an important global variable in Solidity development. A global variable is one that is visible on the blockchain and called be called anytime throughout the code you write.
The example they provide shows you what happens with the msg.sender
variable through two functions parameters.
Here the function setMyNumber
stores the uint
of _myNumber
into the favouriteNumbber[msg.sender]
variable. After this is stored, it is called in the function whatIsMyNumber
and returned.
Now we will try their exercise they provided. We will be trying to update the zombieToOwner
mapping with the id
we defined earlier. Then increase the ownerZombieCount
whilst updating the mapping data structure.
Chapter 3: Require
Now with our createRandomZombie
function, we want to ensure that an unlimited army of zombies are not called. So what we want to do is put a parameter or boundary using require
.
Require statements allow you to check if a value is of a certain amount, stored in a data structure or the function is being called by the correct address.
With the below example, the function ‘requires’ the string to be “Vitalik” or it will exit. If the input is correctly understand as “Vitalik”, the function will return “Hi”.
Now, let’s use the require
function to put a parameter of ownerZombieCount
mapping to be set to 0
so we don’t have unlimited zombies.
Chapter 4: Inheritance
Writing all this code can be tiring and you don’t want to write it under one specific contract
constructor…. So what Solidity let’s you do is inherit multiple contracts within your code which means you can separate your contract code.
Below, we see BabyDoge
inherit the contract Doge
. It simply makes things much easier to organise and manage.
Now you will attempt to inherit the ZombieFactory
contract into a new ZombieFeeding
contract.
Chapter 5: Import
Import is the next step when looking at organising and having clean code. import
allows you to have access to multiple files in your folder. It is very simple :) Just be careful of the syntax around the file name.
Chapter 6: Storage vs. Memory
Where I personally had some problems, maybe easier for some of you guys…
As per their explanation, storage
refers to the variables stored permanently on the blockchain whereas memory
refers to variables that are stored temporarily and are erased between external function calls.
Now in the exercise, you will be setting parameters around require
and then allocating storage
on the Blockchain through our Zombie
arrays.
Chapter 7: ZombieDna
This chapter has no new learnings, but will focus on enhancing our feedAndMultiply
function with further reiterations to the creation of the newDna
. The below example demonstrates such instances of being able to create a newDna id.
Chapter 8: Function Visibility — Internal and External
Previously we saw that we have public and private calls for our functions. This is self-explanatory to how visible the code is to external stakeholders. However we are going to introduce two new ones internal
and external.
- Internal is the same as private, except it can be called by inherited contracts
- External is the same as public except it can only be called outside the contract
Chapter 9 and 10 : Interacting with other contracts
In the last chapter, we learned how to use the function visibility calls (public, private, internal and external) and now we want to take that a step further and inherit and interact with the other contracts on the blockchain. This is done through an interface
. As per below example. we have set up the NumberInterface to be able to interact with the functions we created in the LuckyNumber
contract.
Chapter 11: Handling Multiple Returns
As our contracts and functions become more advanced, we have to be able to handle multiple returns for different variables so by following the logic below you will be able to understand how we can process these multiple return functions.
Chapter 12: If Statements
Fundamental to coding in any language is the use case of if
statements to be able to assist with our logical reasoning. In the example provided you are able to check IF a certain conditional statement occurs in the function, then perform another action. It’s really really useful and cool :)
Finished !!! 🎉🎉🎉🎉
Congratulations for making it to the end of Lesson 2 where you covered some of the fundamentals of Solidity programming. We hope you are enjoying the tutorials so far. Dont forget to post your code into the online solidity compiler called remix to play with and modifiy it if you wish.
Please don’t forget to give us a clap for CryptoZombie luck 👏👏👏👏