Learning to Code Blockchain DApps from CryptoZombies 🧟‍♂️
Tags: solidity, blockchain
Published: 2021-10-24 07:12:50

---
title: Learning to Code Blockchain DApps from CryptoZombies 🧟‍♂️
published: true
date: 2021-10-24 06:22:54 UTC
tags: #solidity, #blockchain
canonical_url: https://swaraj70.com/making-the-zombie-factory
---

The popularity of Blockchain technology is increasing day by day and so are the reasons to learn it.

This is the first article of the series [Learning to Code Blockchain DApps from CryptoZombies](https://swaraj70.com/series/cryptozombies) in which I will be documenting my journey as I go through all the lessons present in the [CryptoZombies](https://cryptozombies.io/) curriculum.

Before getting into the lessons, Let's first understand what is CryptoZombies?

## So, What is CryptoZombies?

[CryptoZombies](https://cryptozombies.io/) is a free resource for aspiring blockchain dApp developers in which users get to learn all the important concepts of dApp development and the Solidity programming language by building their own NFT-style Zombie game.

> CryptoZombies is an interactive school that teaches you all things technical about blockchains. Learn to make smart contracts in Solidity by making your own crypto-collectibles game.

## Why CryptoZombies?

When learning something new I generally try to find resources which are well structured and which walks you through the concepts in a progressive way, so that I am clear with the basics before jumping into more advanced concepts and after browsing through CryptoZombies curriculum I found out it follows a similar structure.

The best part about learning from CryptoZombies is that it's completely browser based and you don't have to install or configure anything.

So, after this little introduction of CryptoZombies let's try to understand the concepts explained in Lesson 1.

## Lesson 1 - Making the Zombie Factory

### Chapter 1: Lesson Overview

In this lesson, we are supposed to build a `Zombie Factory` to make a lot of zombies for our army and in order to do that we have to,

- maintain a database of all zombies in our army.
- make a function for creating new zombies.
- make sure each zombie has a random and unique appearance.

![lesson1a.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633782320758/XW7liU4rc.png)

But before we do that, We should first understand how zombie DNA works as the zombie's appearance is based on its `Zombie DNA`.

`Zombie DNA` is just a simple 16-digit integer, like:

```
8356281049284737

```

So, just like real DNA different parts of this number maps to different traits. The first 2 digits map to the zombie's head type, the second 2 digits to the zombie's eyes, etc. The zombie can have only 7 different types of heads and 8, 3 are the first two digits in the above Zombie DNA sample, to map that to the zombie's head type, we do

```
83 % 7 + 1 = 7

```

Which means this Zombie would have the 7th zombie head type (The Santa hat).

![headgene7.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633789360829/GbgcvJoVF.png)

As we now have a better understanding of what `Zombie DNA` is, let's see how we can build our own Zombie army.

### Chapter 2: Contracts

Solidity's code is encapsulated in **contracts** and to start creating our Zombie army, we have to create a base `Contract` called `ZombieFactory`.

> #### What are Contracts?
> 
> A contract is the fundamental building block of Ethereum applications — all variables and functions belong to a contract, and this will be the starting point of all your projects.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

}

```

In the above code, the first line `pragma solidity >=0.5.0 <0.6.0;` is known as a `Version Pragma`.

> #### What is a Version Pragma?
> 
> All solidity source code starts with a "version pragma". It simply tells the source code is written for which solidity version. This is to prevent issues with future compiler versions potentially introducing changes that would break the code.

Our contract uses solidity version which is greater than or equal to 0.5.0 and less than 0.6.0. Therefore,

```
pragma solidity >=0.5.0 <0.6.0;

```

### Chapter 3: State Variables and Integeres

Now, as our Zombie DNA is going to be determined by a 16-digit number we will create a `State Variable` named `dnaDigits` and set it equal to `16`.

> #### What are State Variables?
> 
> Variables which are permanently stored in contract storage is known as State Variables. These variables are permanently written to the Ethereum blockchain. Think of it as storing values in a database.

We will be using the `uint` data type while defining our state variable `dnaDigits` which means its value must not be negative.

> Note: `uint` is a data type which stands for unsigned integer. There's also an `int` data type for signed integers.

### Chapter 4: Math Operations

To make sure our Zombie's DNA is only 16 characters we will make another `uint` named `dnaModulus` and set it equal to `10^dnaDigits`, since `dnaDigits = 16`. That way we can later use the modulus operator `%` to shorten an integer to 16 digits.

> Note: Math in solidity is pretty straightforward and the operations are almost the same as in most programming languages.

Our solidity code should now look something like this, 👇

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

}

```

### Chapter 5: Structs

Just like us humans, our zombies will also have multiple properties like `name (a string)`, `dna (a uint)` and to club these properties into one single data type solidity provides us with a tool known as `structs`.

> #### What are Structs?
> 
> Structs allow us to create more complicated data types that have multiple properties.

As we are going to want to create some zombies for our app, we will create a `struct` named `Zombie` with two properties `name (a string)` and `dna (a uint)`.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Struct
    struct Zombie {
        string name;
        uint dna;
    }

}

```

> Note: String is a data type which can store a sequence of characters. Ex:
> 
> ```
> string greeting = "Hello world!"
> 
> ```

### Chapter 6: Arrays

In order to store an army of zombies we will need a collection of zombies and in solidity, `arrays` are used to create a collection of something.

> #### What are Arrays?
> 
> Arrays are used to store a collection of something. In solidity, there are two types of arrays - `Fixed arrays` and `Dynamic arrays`.

Ex:

```
// Array with a fixed length of 2 uint elements:
uint[2] fixedArray;

// A dynamic Array - has no fixed size, can keep growing:
uint[] dynamicArray;

```

> We can also declare an array as `public` which enables other contracts to read from this array, but can not write to this array.

Ex:

```
// Person struct
struct Person {
    uint age;
    string name;
}

// Dynamic Public Array named people which can store a lot of persons.
Person[] public people;

```

So, we will now create a public array of `Zombie struct`, and name it `zombies`.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Zombie struct
    struct Zombie {
        string name;
        uint dna;
    }

    // zombies array
    Zombie[] public zombies;

}

```

### Chapter 7: Function Declarations

Now, we will create a `public function` named `createZombie` for creating more zombies. It will take two parameters: `_name (a string)`, and `_dna (a uint)`.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Zombie struct
    struct Zombie {
        string name;
        uint dna;
    }

    // zombies array
    Zombie[] public zombies;

    // createZombie public function
    function createZombie(string memory _name, uint _dna) public {

    }

}

```

> Note: It's convention (but not required) to start function parameter variable names with an underscore (\_) in order to differentiate them from global variables.

For now the body of the function is empty. Note that we're specifying the function visibility as `public`. We're also providing instructions about where the \_name variable should be stored- `in memory`. This is required for all reference types such as arrays, structs, mappings, and strings.

> There are two ways in which you can pass an argument to a Solidity function:
> 
> - By value, which means that the Solidity compiler creates a new copy of the parameter's value and passes it to your function. This allows your function to modify the value without worrying that the value of the initial parameter gets changed.
> - By reference, which means that your function is called with a reference to the original variable. Thus, if your function changes the value of the variable it receives, the value of the original variable gets changed.

### Chapter 8: Working With Structs and Arrays

In the last chapter, we created an empty function named `createZombie` with two parameters: `_name (a string)`, and `_dna (a uint)`. So, in this chapter we will try to fill the function so it can actually create a `zombie` whose name and dna will come from the function arguments and add it to the `zombies` array.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Zombie struct
    struct Zombie {
        string name;
        uint dna;
    }

    // zombies array
    Zombie[] public zombies;

    // createZombie public function
    function createZombie(string memory _name, uint _dna) public {
        // Create a new zombie and push it at the end of zombies array
        zombies.push(Zombie(_name, _dna));
    }

}

```

> Note: array.push() adds something to the end of the array.

### Chapter 9: Private / Public Functions

In solidity, functions are `public` by default which means anyone or any contract can call our contract's function and execute its code this can make our contract vulnerable to attacks.

Our contract's `createZombie` function is currently `public` and anyone could call it and create a new Zombie in our contract which is not desirable. So, we will modify our `createZombie` function and make it private. This will only allow other functions within our contract to call `createZombie` function and add new zombies to the `zombies` array.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Zombie struct
    struct Zombie {
        string name;
        uint dna;
    }

    // zombies array
    Zombie[] public zombies;

    // createZombie PRIVATE function
    function _createZombie(string memory _name, uint _dna) private {
        // Create a new zombie and push it at the end of zombies array
        zombies.push(Zombie(_name, _dna));
    }

}

```

> Note:
> 
> - As with function parameters, it's convention to start private function names with an underscore (\_).
> - It is a good practice to mark your functions as private by default, and then only make those functions public which you want to expose to the world.

### Chapter 10: More on Functions

In this chapter, we have to create a `private view function` called `_generateRandomDna` which takes a single `string` parameter `_str` and it should return a `uint`. We will fill the function body in the next chapter.

A `return` value in solidity functions is a value which gets returned when the function is called. In our case, a `uint` will be returned.

A `view` is a function modifier for a function that only views the data present in our smart and does not modify the data.

> Note: Solidity also contains pure functions, which means the function does not access any data in the app and doesn't even read from the state of the app. Its return value depends only on its function parameters.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Zombie struct
    struct Zombie {
        string name;
        uint dna;
    }

    // zombies array
    Zombie[] public zombies;

    // createZombie PRIVATE function
    function _createZombie(string memory _name, uint _dna) private {
        // Create a new zombie and push it at the end of zombies array
        zombies.push(Zombie(_name, _dna));
    }

    // create private view function _generateRandomDna
    function _generateRandomDna(string memory _str) private view returns (uint) {

    }

}

```

### Chapter 11: Keccak256 and Typecasting

`Keccak256` is a hash function in Ethereum which is a version of [`SHA3`](https://en.wikipedia.org/wiki/SHA-3). A hash function basically converts an input into a random 256-bit hexadecimal number and even if there is just a slight change in the input it will cause a large change in the hash. We will use it for pseudo-random number generation.

`keccak256` expects a single parameter of type bytes. This means that we have to "pack" any parameters before calling `keccak256`.

`Typecasting` is a process to convert between data types. For Eg:

```
uint8 a = 5;
uint b = 6;
// throws an error because a * b returns a uint, not uint8:
uint8 c = a * b;
// we have to typecast b as a uint8 to make it work:
uint8 c = a * uint8(b);

```

Now, ln our `_generateRandomDna` function we have to call the `keccak256` hash function by passing `abi.encodePacked(_str)` as its parameter to generate a pseudo-random hexadecimal, after that typecast it as a `uint`, and finally store the result in a `uint` called `rand`. Also we want our DNA to be only 16 digits long so we will use the `dnaModulus` variable that we created earlier in the lesson and in the end return the result.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Zombie struct
    struct Zombie {
        string name;
        uint dna;
    }

    // zombies array
    Zombie[] public zombies;

    // createZombie PRIVATE function
    function _createZombie(string memory _name, uint _dna) private {
        // Create a new zombie and push it at the end of zombies array
        zombies.push(Zombie(_name, _dna));
    }

    // create private view function _generateRandomDna
    function _generateRandomDna(string memory _str) private view returns (uint) {
        // Keccak256 and Typecasting
        uint rand = uint(keccak256(abi.encodePacked(_str)));
        return rand % dnaModulus;
    }

}

```

### Chapter 12: Putting It Together

To complete our random Zombie generator we will create a `public` function named `createRandomZombie` that takes one parameter named `_name` (a string), then inside this function we will call `_generateRandomDna` by passing `_name` as its parameter and store it in a `uint` named `randDna`. Next, we will call the `_createZombie` function and pass `_name` and `randDna` as its parameters for creating a new zombie.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Zombie struct
    struct Zombie {
        string name;
        uint dna;
    }

    // zombies array
    Zombie[] public zombies;

    // createZombie PRIVATE function
    function _createZombie(string memory _name, uint _dna) private {
        // Create a new zombie and push it at the end of zombies array
        zombies.push(Zombie(_name, _dna));
    }

    // create private view function _generateRandomDna
    function _generateRandomDna(string memory _str) private view returns (uint) {
        // Keccak256 and Typecasting
        uint rand = uint(keccak256(abi.encodePacked(_str)));
        return rand % dnaModulus;
    }

    // create public function createRandomZombie
    function createRandomZombie(string memory _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}

```

### Chapter 13: Events

We want an event to let our front-end know every time a new zombie was created, so the app can display it.

> Events are a way for a contract to communicate that something happened on the blockchain to our app front-end, which can be 'listening' for certain events and take action when they happen.

So, to do that we will declare an event called `NewZombie` and pass `zombieId` (a uint), `name` (a string), `dna` (a uint) as its parameters and then modify the `_createZombie` function to fire the `NewZombie` event after adding the new Zombie to our `zombies` array.

We are also going to need the zombie's id and `array.push()` returns a `uint` of the new length of the array - and since the first item in an array has index 0, `array.push() - 1` will be the index of the zombie we just added. So, we will store the result of `zombies.push() - 1` in a `uint` called `id`, and then use this in the NewZombie event.

```
pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    // declare our NewZombie event
    event NewZombie(uint zombieId, string name, uint name);

    // This will be stored permanently in the blockchain
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits; // equal to 10^16

    // Zombie struct
    struct Zombie {
        string name;
        uint dna;
    }

    // zombies array
    Zombie[] public zombies;

    // createZombie PRIVATE function
    function _createZombie(string memory _name, uint _dna) private {
        // Create a new zombie, 
        // push it at the end of zombies array and 
        // get the id of the zombie we just added.
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        // fire NewZombie event
        emit NewZombie(id, _name, _dna);
    }

    // create private view function _generateRandomDna
    function _generateRandomDna(string memory _str) private view returns (uint) {
        // Keccak256 and Typecasting
        uint rand = uint(keccak256(abi.encodePacked(_str)));
        return rand % dnaModulus;
    }

    // create public function createRandomZombie
    function createRandomZombie(string memory _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}

```

### Chapter 14: Web3.js

We have completed our `solidity` contract. Now we need to write a javascript frontend that interacts with the contract.

Ethereum has a Javascript library called `Web3.js`. In later lessons we will go over in depth how to deploy a contract and set up `Web3.js`. For now CryptoZombies have provided us with some sample code that will help us understand how `Web3.js` would interact with our deployed contract.

```
// Here's how we would access our contract:
var abi = /* abi generated by the compiler */
var ZombieFactoryContract = web3.eth.contract(abi)
var contractAddress = /* our contract address on Ethereum after deploying */
var ZombieFactory = ZombieFactoryContract.at(contractAddress)
// `ZombieFactory` has access to our contract's public functions and events

// some sort of event listener to take the text input:
$("#ourButton").click(function(e) {
  var name = $("#nameInput").val()
  // Call our contract's `createRandomZombie` function:
  ZombieFactory.createRandomZombie(name)
})

// Listen for the `NewZombie` event, and update the UI
var event = ZombieFactory.NewZombie(function(error, result) {
  if (error) return
  generateZombie(result.zombieId, result.name, result.dna)
})

// take the Zombie dna, and update our image
function generateZombie(id, name, dna) {
  let dnaStr = String(dna)
  // pad DNA with leading zeroes if it's less than 16 characters
  while (dnaStr.length < 16)
    dnaStr = "0" + dnaStr

  let zombieDetails = {
    // first 2 digits make up the head. We have 7 possible heads, so % 7
    // to get a number 0 - 6, then add 1 to make it 1 - 7. Then we have 7
    // image files named "head1.png" through "head7.png" we load based on
    // this number:
    headChoice: dnaStr.substring(0, 2) % 7 + 1,
    // 2nd 2 digits make up the eyes, 11 variations:
    eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
    // 6 variations of shirts:
    shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
    // last 6 digits control color. Updated using CSS filter: hue-rotate
    // which has 360 degrees:
    skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
    eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
    clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
    zombieName: name,
    zombieDescription: "A Level 1 CryptoZombie",
  }
  return zombieDetails
}

```

What this javascript code then does is take the values generated in `zombieDetails` above, and use some browser-based javascript magic to swap out the images and apply CSS filters. For Eg:

![swaraj70.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1635054122395/nURnt964M.png)

### Conclusion

We have now successfully completed Lesson 1 of CryptoZombies. In order to complete Lesson 1 of CryptoZombies we have learnt -

- How to write Ethereum smart contracts.
- Basics of Ethereum's smart contract programming language - Solidity

If you are interested in learning how to create your own blockchain dapps on Ethereum like me for FREE, [CryptoZombies](https://cryptozombies.io/) could be a good place to start.

Thank you for reading this article. I am learning more about web 3.0 and blockchain development, if you're interested in being a part of this learning journey feel free to follow me here or on [twitter](https://twitter.com/swaraj70).