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 1: Payable

Chapter 1: Payable


Up until now, we've covered quite a few function modifiers. It can be difficult to try to remember everything, so let's run through a quick review:
1. We have visibility modifiers that control when and where the function can be called from: private means it's only callable from other functions inside the contract; internal is like private but can also be called by contracts that inherit from this one; external can only be called outside the contract; and finally public can be called anywhere, both internally and externally.

2. We also have state modifiers, which tell us how the function interacts with the BlockChain: view tells us that by running the function, no data will be saved/changed. pure tells us that not only does the function not save any data to the blockchain, but it also doesn't read any data from the blockchain. Both of these don't cost any gas to call if they're called externally from outside the contract (but they do cost gas if called internally by another function).

3. Then we have custom modifiers, which we learned about in Lesson 3: onlyOwner and aboveLevel, for example. For these we can define custom logic to determine how they affect a function.

These modifiers can all be stacked together on a function definition as follows:
function test() external view onlyOwner anotherModifier { /* ... */ }


In this chapter, we're going to introduce one more function modifier: payable.

The

payable

Modifier


payable functions are part of what makes Solidity and Ethereum so cool — they are a special type of function that can receive Ether.
Let that sink in for a minute. When you call an API function on a normal web server, you can't send US dollars along with your function call — nor can you send Bitcoin.
But in Ethereum, because both the money (Ether), the data (transaction payload), and the contract code itself all live on Ethereum, it's possible for you to call a function and pay money to the contract at the same time.
This allows for some really interesting logic, like requiring a certain payment to the contract in order to execute a function.

Let's look at an example


contract OnlineStore {
  function buySomething() external payable {
    // Check to make sure 0.001 ether was sent to the function call:
    require(msg.value == 0.001 ether);
    // If so, some logic to transfer the digital item to the caller of the function:
    transferThing(msg.sender);
  }
}

Here, msg.value is a way to see how much Ether was sent to the contract, and ether is a built-in unit.
What happens here is that someone would call the function from web3.js (from the DApp's JavaScript front-end) as follows:
// Assuming `OnlineStore` points to your contract on Ethereum:
OnlineStore.buySomething({from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001)})

Notice the value field, where the javascript function call specifies how much ether to send (0.001). If you think of the transaction like an envelope, and the parameters you send to the function call are the contents of the letter you put inside, then adding a value is like putting cash inside the envelope — the letter and the money get delivered together to the recipient.
Note: If a function is not marked payable and you try to send Ether to it as above, the function will reject your transaction.

Putting it to the Test


Let's create a payable function in our zombie game.
Let's say our game has a feature where users can pay ETH to level up their zombies. The ETH will get stored in the contract, which you own — this a simple example of how you could make money on your games!
1. Define a uint named levelUpFee, and set it equal to 0.001 ether.

2. Create a function named levelUp. It will take one parameter, _zombieId, a uint. It should be external and payable.

3. The function should first require that msg.value is equal to levelUpFee.

4. It should then increment this zombie's level: zombies[_zombieId].level++.


pragma solidity ^0.4.25;

import "./zombiefeeding.sol";

contract ZombieHelper is ZombieFeeding {

  // 1. Define levelUpFee here
  uint levelUpFee = 0.001 ether;

  modifier aboveLevel(uint _level, uint _zombieId) {
    require(zombies[_zombieId].level >= _level);
    _;
  }

  // 2. Insert levelUp function here
  function levelUp(uint _zombieId) external payable {
    require(msg.value == levelUpFee);
    zombies[_zombieId].level++;
  }

  function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) {
    require(msg.sender == zombieToOwner[_zombieId]);
    zombies[_zombieId].name = _newName;
  }

  function changeDna(uint _zombieId, uint _newDna) external aboveLevel(20, _zombieId) {
    require(msg.sender == zombieToOwner[_zombieId]);
    zombies[_zombieId].dna = _newDna;
  }

  function getZombiesByOwner(address _owner) external view returns(uint[]) {
    uint[] memory result = new uint[](ownerZombieCount[_owner]);
    uint counter = 0;
    for (uint i = 0; i < zombies.length; i++) {
      if (zombieToOwner[i] == _owner) {
        result[counter] = i;
        counter++;
      }
    }
    return result;
  }

}