Index

CryptoZombies

  1. Lesson 1: CryptoZombies
    1. Chapter 2 Contracts
    2. Chapter 3: State Variables & Integers
    3. Chapter 4: Math Operations
    4. Chapter 5: Structs
    5. Chapter 6: Arrays
    6. Chapter 7: Function Declarations
    7. Chapter 8: Working With Structs and Arrays
    8. Chapter 9: Private / Public Functions
    9. Chapter 10: More on Functions
    10. Chapter 11: Keccak256 and Typecasting
    11. Chapter 12: Putting It Together
    12. Chapter 13: Events
    13. Chapter 14: Web3.js
  2. Lesson 2: Zombies Attack Their Victims
    1. Chapter 2: Mappings and Addresses
    2. Chapter 3: Msg.sender
    3. Chapter 4: Require
    4. Chapter 5: Inheritance
    5. Chapter 6: Import
    6. Chapter 7: Storage vs Memory
    7. Chapter 8: Zombie DNA
    8. Chapter 9: More on Function Visibility
    9. Chapter 10: What Do Zombies Eat?
    10. Chapter 11: Using an Interface
    11. Chapter 12: Handling Multiple Return Values
    12. Chapter 13: Bonus: Kitty Genes
    13. Chapter 14: Wrapping It Up
  3. Lesson 3: Advanced Solidity Concepts
    1. Chapter 2: Ownable Contracts
    2. Chapter 3: onlyOwner Function Modifier
    3. Chapter 4: Gas
    4. Chapter 5: Time Units
    5. Chapter 6: Zombie Cooldowns
    6. Chapter 7: Public Functions & Security
    7. Chapter 8: More on Function Modifiers
    8. Chapter 9: Zombie Modifiers
    9. Chapter 10: Saving Gas With 'View' Functions
    10. Chapter 11: Storage is Expensive
    11. Chapter 12: For Loops
    12. Chapter 13: Wrapping It Up
  4. Lesson 4: Zombie Battle System
    1. Chapter 1: Payable
    2. Chapter 2: Withdraws
    3. Chapter 3: Zombie Battles
    4. Chapter 4: Random Numbers
    5. Chapter 5: Zombie Fightin'
    6. Chapter 6: Refactoring Common Logic
    7. Chapter 7: More Refactoring
    8. Chapter 8: Back to Attack!
    9. Chapter 9: Zombie Wins and Losses
    10. Chapter 10: Zombie Victory 😄
    11. Chapter 11: Zombie Loss 😞
  5. Lesson 5: ERC721 & Crypto-Collectibles
    1. Chapter 1: Tokens on Ethereum
    2. Chapter 2: ERC721 Standard, Multiple Inheritance
    3. Chapter 3: balanceOf & ownerOf
    4. Chapter 4: Refactoring
    5. Chapter 5: ERC721: Transfer Logic
    6. Chapter 6: ERC721: Transfer Cont'd
    7. Chapter 7: ERC721: Approve
    8. Chapter 8: ERC721: Approve
    9. Chapter 9: Preventing Overflows
    10. Chapter 10: SafeMath Part 2
    11. Chapter 11: SafeMath Part 3
    12. Chapter 12: SafeMath Part 4
    13. Chapter 13: Comments
    14. Chapter 14: Wrapping It Up
  6. App Front-ends & Web3.js
    1. Chapter 1: Intro to Web3.js
    2. Chapter 2: Web3 Providers
    3. Chapter 3: Talking to Contracts
    4. Chapter 4: Calling Contract Functions
    5. Chapter 5: Metamask & Accounts
    6. Chapter 6: Displaying our Zombie Army
    7. Chapter 7: Sending Transactions
    8. Chapter 8: Calling Payable Functions
    9. Chapter 9: Subscribing to Events
    10. Chapter 10: Wrapping It Up

Chapter 4: Require


Chapter 4: Require


In lesson 1, we made it so users can create new zombies by calling createRandomZombie and entering a name. However, if users could keep calling this function to create unlimited zombies in their army, the game wouldn't be very fun.
Let's make it so each player can only call this function once. That way new players will call it when they first start the game in order to create the initial zombie in their army.
How can we make it so this function can only be called once per player?
For that we use require. require makes it so that the function will throw an error and stop executing if some condition is not true:
function sayHiToVitalik(string _name) public returns (string) {
  // Compares if _name equals "Vitalik". Throws an error and exits if not true.
  // (Side note: Solidity doesn't have native string comparison, so we
  // compare their keccak256 hashes to see if the strings are equal)
  require(keccak256(abi.encodePacked(_name)) == keccak256(abi.encodePacked("Vitalik")));
  // If it's true, proceed with the function:
  return "Hi!";
}

If you call this function with sayHiToVitalik("Vitalik"), it will return "Hi!". If you call it with any other input, it will throw an error and not execute.
Thus
require is quite useful for verifying certain conditions that must be true before running a function.

Put it to the test


In our zombie game, we don't want the user to be able to create unlimited zombies in their army by repeatedly calling
createRandomZombie — it would make the game not very fun.
Let's use
require to make sure this function only gets executed one time per user, when they create their first zombie.
1. Put a
require statement at the beginning of createRandomZombie. The function should check to make sure ownerZombieCount[msg.sender] is equal to 0, and throw an error otherwise.
Note: In Solidity, it doesn't matter which term you put first — both orders are equivalent. However, since our answer checker is really basic, it will only accept one answer as correct — it's expecting
ownerZombieCount[msg.sender] to come first.

require(ownerZombieCount[msg.sender] == 0);


pragma solidity ^0.4.25;

contract ZombieFactory {

    event NewZombie(uint zombieId, string name, uint dna);

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    mapping (uint => address) public zombieToOwner;
    mapping (address => uint) ownerZombieCount;

    function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        zombieToOwner[id] = msg.sender;
        ownerZombieCount[msg.sender]++;
        emit NewZombie(id, _name, _dna);
    }

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(abi.encodePacked(_str)));
        return rand % dnaModulus;
    }

    function createRandomZombie(string _name) public {
        require(ownerZombieCount[msg.sender] == 0);
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}