Skip to content

Commit

Permalink
New lessons and path in frontmatter (CryptozombiesHQ#425)
Browse files Browse the repository at this point in the history
New lessons and path in frontmatter
  • Loading branch information
hankxdev authored Oct 24, 2019
2 parents 4487a23 + 9bc1599 commit 18dc702
Show file tree
Hide file tree
Showing 56 changed files with 6,563 additions and 33 deletions.
1 change: 1 addition & 0 deletions en/1/00-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
title: Making the Zombie Factory
header: Welcome, human!
roadmap: roadmap.jpg
path: solidity
---

So you think you have what it takes to become a **CryptoZombie**, huh?
Expand Down
4 changes: 2 additions & 2 deletions en/1/keccak256.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ material:

We want our `_generateRandomDna` function to return a (semi) random `uint`. How can we accomplish this?

Ethereum has the hash function `keccak256` built in, which is a version of SHA3. A hash function basically maps an input into a random 256-bit hexadecimal number. A slight change in the input will cause a large change in the hash.
Ethereum has the hash function `keccak256` built in, which is a version of SHA3. A hash function basically maps an input into a random 256-bit hexidecimal number. A slight change in the input will cause a large change in the hash.

It's useful for many purposes in Ethereum, but for right now we're just going to use it for pseudo-random number generation.

Expand Down Expand Up @@ -97,6 +97,6 @@ In the above, `a * b` returns a `uint`, but we were trying to store it as a `uin

Let's fill in the body of our `_generateRandomDna` function! Here's what it should do:

1. The first line of code should take the `keccak256` hash of `abi.encodePacked(_str)` to generate a pseudo-random hexadecimal, typecast it as a `uint`, and finally store the result in a `uint` called `rand`.
1. The first line of code should take the `keccak256` hash of `abi.encodePacked(_str)` to generate a pseudo-random hexidecimal, typecast it as a `uint`, and finally store the result in a `uint` called `rand`.

2. We want our DNA to only be 16 digits long (remember our `dnaModulus`?). So the second line of code should `return` the above value modulus (`%`) `dnaModulus`.
25 changes: 25 additions & 0 deletions en/10/00-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: "Deploying Ethereum DApps with Truffle"
header: "Deploying Ethereum DApps with Truffle"
roadmap: roadmap.jpg
path: solidity_advanced
position: 2
---

Remember that we promised to teach you how to deploy smart contracts to **_Ethereum_**?

It's been a while, but the time has come!

In this lesson, we will be teaching you how to deploy to **_Ethereum_** using **_Truffle_**.

And this is not all. You are going to learn how to deploy your smart contracts to **Loom**, and how to interact with them using **_web3.js_**.

Why deploy to **Loom**? After all, **_Ethereum_** is the most secure network.

Yes, we totally agree with that. But on Ethereum each transaction costs _gas_, so your users will have to pay fees for each and every transaction. Also, they will have to wait at least 10 seconds for each transaction to be confirmed.

In a nutshell, **_on Ethereum, all transactions benefit from the same security guarantees_**. For something like a game, this level of security isn't a requirement. In fact, it just harms the user experience.

On **Loom**, users will have access to much speedier and gas-free transactions. This makes DAppChains a much better fit for something like a game or a user-facing DApp.

Enough talking! Let's get started😉
53 changes: 53 additions & 0 deletions en/10/01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: Introduction
actions: ['checkAnswer', 'hints']
requireLogin: true
material:
terminal:
help:
You should probably run `npm install truffle -g`.
commands:
"npm install truffle -g":
hint: npm install truffle -g
output: |
/usr/local/bin/truffle -> /usr/local/lib/node_modules/truffle/build/cli.bundled.js
+ [email protected]
added 81 packages from 311 contributors in 5.104s
---

If you're new to **CryptoZombies**, it's highly recommended that you go over the first six lessons before starting this one. Please take the time to get familiar with writing a smart contract and interacting with it using `Web3.js`. Otherwise, it will be quite hard to follow this lesson.

## The Missing Piece

So you've worked your way through our previous lessons. Awesome! This means you've almost mastered the art of building DApps.

But an important piece of the puzzle is still missing.

That's right... you still have to learn how to **_deploy a smart contract to Ethereum_**.

Now, if you have a background in front-end development, you are probably well accustomed to the multitude of tools like *Webpack, Gulp, or Browserify* that make a developer's life simpler.

But what tools do `Solidity` developers use?

## Truffle

`Truffle` is the most popular blockchain development framework for good reason - it's packed with lots of useful features:

- easy smart contract compilation
- automated ABI generation
- integrated smart contract testing - there's even support for `Mocha` and `Chai`!
- support for multiple networks - code can be deployed to Rinkeby, **_Ethereum_** or even to **Loom**. We'll walk you through this later😉

Provided that `npm` and `node` have been installed, we'll want you to install `truffle` and make it available globally.

# Put It to the Test

We'll start with the basics. Fire up a new terminal window, create a directory called "CryptoZombies", and `cd` into it.

1. Now, let's install `truffle` and make it available globally.

>Note: Here's how you can use `npm` to install a package and make it available globally:
```bash
npm install package_name -g
```
85 changes: 85 additions & 0 deletions en/10/02.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: Getting Started with Truffle
actions: ['checkAnswer', 'hints']
requireLogin: true
material:
terminal:
help: |
First, you should probably run `truffle init`. Next, execute `npm install truffle-hdwallet-provider`
commands:
"truffle init":
hint: truffle init
output: |
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
"npm install truffle-hdwallet-provider":
hint: npm install truffle-hdwallet-provider
output: |
+ [email protected]
added 1 package from 1 contributor and audited 71402 packages in 5.612s
found 0 vulnerabilities
---

Now that we've installed `truffle`, it's time to initialize our new project by running `truffle init`. All it is doing is to create a set of folders and config files with the following structure:

```
├── contracts
├── Migrations.sol
├── migrations
├── 1_initial_migration.js
└── test
truffle-config.js
truffle.js
```

Contracts, migrations, tests... this is pretty complicated😟

Don't worry, learning to use `truffle` won't eat your brains. This chapter will walk you through `truffle`'s default project structure, and once you know how to use `truffle`, deploying smart contracts will be a breeze.

## Truffle's Default Directory Structure

So, inside of "CryptoZombies" directory, `truffle init` should create several directories and some JavaScript and Solidity files. Let's have a closer look:

- **_contracts_**: this is the place where `truffle` expects to find all our smart contracts. To keep the code organized, we can even create nested folders such as `contracts/tokens`. Pretty neat😉.
>Note: `truffle init` should automatically add a contract called `Migrations.sol` and the corresponding migration file. We'll explain them a bit later.
- **_migrations_**: a migration is a JavaScript file that tells `truffle` how to deploy the smart contract.

- **_test_**: here we are expected to put the unit tests which will be JavaScript or Solidity files. Remember, once a contract is deployed it can't be changed, making it essential that we test our smart contracts before we deploy them.

- **_truffle.js_** and **_truffle-config.js_**: config files used to store the network settings for deployment. `Truffle` needs two config files because on Windows having both `truffle.js` and `truffle.exe` in the same folder might generate conflicts. Long story short - if you are running Windows, it is advised to delete `truffle.js` and use `truffle-config.js` as the default config file. Check out _Truffle's_ official <a href="https://truffleframework.com/docs/truffle/reference/configuration" target=_blank>documentation</a> to further your understanding.


But why should I use this directory structure? I'm not used to it and it looks complicated...

Well, there's are a few good reasons. First, `Truffle` will not work as expected if you change the names of these folders.

Second, by adhering to this convention your projects will be easily understood by other developers. To put it short, using standard folder structures and code conventions make it easier if you expand or change your team in the future.

## truffle-hdwallet-provider

In this lesson, we will be using _Infura_ to deploy our code to **_Ethereum_**. This way, our users will be allowed to run the application without needing to set up their own **_Ethereum_** node or wallet.
However, to keep things secure, _Infura_ does not manage private keys, which means it can't sign transactions on our behalf. Since deploying a smart contract requires `truffle` to sign transactions, we are going to need a tool called `truffle-hdwallet-provider`. Its only purpose is to handle the transaction signing.

>Note: Maybe you are asking why we chose not to install `truffle-hdwallet-provider` in the previous chapter using something like:
```JavaScript
npm install truffle truffle-hdwallet-provider -g
```

Well... `truffle init` expects to find an empty directory. If there's any file there, it will error out, so we need to do everything in the correct order and install `truffle-hdwallet-provider` after we run `truffle init`.


# Put it to the test:

1. Run `truffle init`. This command generates the directory structure that we've discussed.

2. Run `npm install truffle-hdwallet-provider`.
115 changes: 115 additions & 0 deletions en/10/03.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
title: Compiling the Source Code
actions: ['checkAnswer', 'hints']
requireLogin: true
material:
terminal:
help:
You should probably run `truffle compile`.
commands:
"truffle compile":
hint: truffle compile
output: |
Compiling ./contracts/Migrations.sol...
Compiling ./contracts/CryptoZombies.sol...
Compiling ./contracts/erc721.sol...
Compiling ./contracts/ownable.sol...
Compiling ./contracts/safemath.sol...
Compiling ./contracts/zombieattack.sol...
Compiling ./contracts/zombiefactory.sol...
Compiling ./contracts/zombiefeeding.sol...
Compiling ./contracts/zombiehelper.sol...
Compiling ./contracts/zombieownership.sol...
Writing artifacts to ./build/contracts
---

Congratulations! Now that we've put the project structure in place and set up `truffle-hdwallet-provider`, let's compile our contracts.

Why do we need to compile, you ask?

The _Ethereum Virtual Machine_ can't directly understand Solidity source code as we write it. Thus, we need to run a compiler that will "translate" our smart contract into machine-readable **_bytecode_**. The virtual machine then executes the bytecode, and completes the actions required by our smart contract.

Curious about how does the bytecode look like? Let's take a look:

```
"0x60806040526010600155600154600a0a6002556201518060035566038d7ea4c6800060085560006009556046600a55336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1..."
```

A you can see, a human is about as likely to be able to read bytecode as a real life zombie!

## Using the Solidity Compiler

Now that we're talking about the Solidity compiler, we should mention that the devs managed to bake in some nifty features.

Let's pretend we'd want to modify the definition of the `add` function included in `SafeMath`:

```
function add(uint16 a, uint16 b) internal returns (uint16) {
uint16 c = a + b;
assert(c >= a);
return c;
}
```

If we're going to compile this function, the Solidity compiler will throw a **_warning_**:

```
safemath.sol:110:11: Warning: Function state mutability can be restricted to pure
function add(uint16 a, uint16 b) internal returns (uint16) {
^ (Relevant source part starts here and spans across multiple lines).
```

What the compiler is trying to say is that our function does not read or write to the blockchain and that we should use the `pure` modifier.

Why is this important?

Well, making a function `pure` or `view` will save us gas. Since these functions are not going to modify the state of the blockchain, there is no need for miners to execute them. To put it in a few words, `pure` and `view` functions can be `call`ed for free.


## CryptoZombies- The Game

Remember, we've embedded our logic in a smart contract called `ZombieOwnership.sol`.

Hmmm... not a great name for a game.

Fortunately, this isn't a problem. We can use inheritance to create a smart contract with the same actions and features with whatever name we choose.

Let's create a new smart contract named `CryptoZombies` that inherits from `ZombieOwnership.sol`:

```solidity
pragma solidity ^0.4.24;
import "./zombieownership.sol";
contract CryptoZombies is ZombieOwnership
{
}
```

Next, we copied all our smart contracts into the `./contracts` folder. Now the project structure should look like this:

```
.
├── contracts
├── Migrations.sol
├── CryptoZombies.sol
├── erc721.sol
├── ownable.sol
├── safemath.sol
├── zombieattack.sol
├── zombiefactory.sol
├── zombiefeeding.sol
├── zombiehelper.sol
├── zombieownership.sol
├── migrations
└── test
```

Everything is set up properly. Let's compile our project.

# Put it to the test:

1. Execute `truffle compile`. This command should create the "build artifacts" and place them in the `./build/contracts` directory.

>Note: The build artifacts are comprised of the "bytecode" versions of the smart contracts, ABIs, and some internal data `truffle` is using to correctly deploy the code. Avoid editing these files, or `truffle` might stop working correctly.
58 changes: 58 additions & 0 deletions en/10/04.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: Migrations
actions: ['checkAnswer', 'hints']
requireLogin: true
material:
editor:
language: JavaScript
startingCode:
"./contracts/2_crypto_zombies.js": |
var Migrations = artifacts.require("./Migrations.sol");
module.exports = function(deployer) {
deployer.deploy(Migrations);
};
answer: |
var CryptoZombies = artifacts.require("./CryptoZombies.sol");
module.exports = function(deployer) {
deployer.deploy(CryptoZombies);
};
---

Normally at this point, before deploying to **_Ethereum_**, you would want to test your smart contract locally. You can do this using a tool called <a href="https://truffleframework.com/ganache" target=”_blank”>Ganache</a>, which sets up a local **_Ethereum_** network.

However, while testing is very important, it would require an entire lesson to cover — so we’re just going to stick to deployment in this lesson.

To deploy to **_Ethereum_** we will have to create something called a **migration**.

Migrations are JavaScript files that help `truffle` deploy the code to **_Ethereum_**. Note that `truffle init` created a special contract called `Migrations.sol` that keeps track of the changes you're making to your code. The way it works is that the history of changes is saved onchain. Thus, there's no way you will ever deploy the same code twice.

## Creating a New Migration

We'll start from the file `truffle init` already created for us- `./contracts/1_initial_migration.js`.
Let's take a look at what's inside:

```javascript
var Migrations = artifacts.require("./Migrations.sol");
module.exports = function(deployer) {
deployer.deploy(Migrations);
};
```

Pretty straightforward, isn't it?

First, the script tells `truffle` that we'd want to interact with the `Migrations` contract.

Next, it exports a function that accepts an object called `deployer` as a parameter. This object acts as an interface between you (the developer) and `truffle`'s deployment engine. Even though the `deployer` provides a multitude of useful functions, we won't be using them in the scope of this lesson. Once you've finished, feel free to check out Truffle's <a href="https://truffleframework.com/docs/truffle/getting-started/running-migrations" target=”_blank”>documentation</a> if you're inclined to learn more about _Truffle's_ abilities.

To get everything ready for deployment, we've gone ahead and created a new file `./contracts/2_crypto_zombies.js`, and copied and pasted the content from `./contracts/1_initial_migration.js`.

# Put it to the test:

1. Modify `./contracts/2_crypto_zombies.js` to this:

```JavaScript
var CryptoZombies = artifacts.require("./CryptoZombies.sol");
module.exports = function(deployer) {
deployer.deploy(CryptoZombies);
};
```
Loading

0 comments on commit 18dc702

Please sign in to comment.