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 5: ERC721: Transfer Logic


Chapter 5: ERC721: Transfer Logic


Great, we've fixed the conflict!
Now we're going to continue our ERC721 implementation by looking at transfering ownership from one person to another.
Note that the ERC721 spec has 2 different ways to transfer tokens:
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

and
function approve(address _approved, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

1. The first way is the token's owner calls transferFrom with his address as the _from parameter, the address he wants to transfer to as the _to paramater, and the _tokenId of the token he wants to transfer.

2. The second way is the token's owner first calls approve with the address he wants to transfer to, and the _tokenID . The contract then stores who is approved to take a token, usually in a mapping (uint256 => address). Then, when the owner or the approved address calls transferFrom, the contract checks if that msg.sender is the owner or is approved by the owner to take the token, and if so it transfers the token to him.

If you'll notice, both methods will contain the same transfer logic. In one case the sender of the token calls the function; in the other the owner or the approved receiver of the token calls it.
So it makes sense for us to abstract this logic into its own private function, _transfer, which is then called by transferFrom.

Putting it to the Test


Let's define the logic for _transfer.
1. Define a function named _transfer. It will take 3 arguments, address _from, address _to, and uint256 _tokenId. It should be a private function.

2. We have 2 mappings that will change when ownership changes: ownerZombieCount (which keeps track of how many zombies an owner has) and zombieToOwner (which keeps track of who owns what).
The first thing our function should do is increment ownerZombieCount for the person receiving the zombie (address _to). Use ++ to increment.

3. Next, we'll need to decrease the ownerZombieCount for the person sending the zombie (address _from). Use -- to decrement.

4. Lastly, we'll want to change zombieToOwner mapping for this _tokenId so it now points to _to.

5. I lied, that wasn't the last step. There's one more thing we should do.
The ERC721 spec includes a Transfer event. The last line of this function should fire Transfer with the correct information — check erc721.sol to see what arguments it's expecting to be called with and implement it here.

zombieownership.sol
pragma solidity ^0.4.25;

import "./zombieattack.sol";
import "./erc721.sol";

contract ZombieOwnership is ZombieAttack, ERC721 {

  function balanceOf(address _owner) external view returns (uint256) {
    return ownerZombieCount[_owner];
  }

  function ownerOf(uint256 _tokenId) external view returns (address) {
    return zombieToOwner[_tokenId];
  }

  // Define _transfer() here
  function _transfer(address _from, address _to, uint256 _tokenId) private {
      ownerZombieCount[_to]++;
      ownerZombieCount[_from]--;
      zombieToOwner[_tokenId] = _to;
      emit Transfer(_from, _to, _tokenId);
  }

  function transferFrom(address _from, address _to, uint256 _tokenId) external payable {

  }

  function approve(address _approved, uint256 _tokenId) external payable {

  }
}