Index
- Lesson 1: CryptoZombies
 - Chapter 2 Contracts
 - Chapter 3: State Variables & Integers
 - Chapter 4: Math Operations
 - Chapter 5: Structs
 - Chapter 6: Arrays
 - Chapter 7: Function Declarations
 - Chapter 8: Working With Structs and Arrays
 - Chapter 9: Private / Public Functions
 - Chapter 10: More on Functions
 - Chapter 11: Keccak256 and Typecasting
 - Chapter 12: Putting It Together
 - Chapter 13: Events
 - Chapter 14: Web3.js
 - Lesson 2: Zombies Attack Their Victims
 - Chapter 2: Mappings and Addresses
 - Chapter 3: Msg.sender
 - Chapter 4: Require
 - Chapter 5: Inheritance
 - Chapter 6: Import
 - Chapter 7: Storage vs Memory
 - Chapter 8: Zombie DNA
 - Chapter 9: More on Function Visibility
 - Chapter 10: What Do Zombies Eat?
 - Chapter 11: Using an Interface
 - Chapter 12: Handling Multiple Return Values
 - Chapter 13: Bonus: Kitty Genes
 - Chapter 14: Wrapping It Up
 - Lesson 3: Advanced Solidity Concepts
 - Chapter 2: Ownable Contracts
 - Chapter 3: onlyOwner Function Modifier
 - Chapter 4: Gas
 - Chapter 5: Time Units
 - Chapter 6: Zombie Cooldowns
 - Chapter 7: Public Functions & Security
 - Chapter 8: More on Function Modifiers
 - Chapter 9: Zombie Modifiers
 - Chapter 10: Saving Gas With 'View' Functions
 - Chapter 11: Storage is Expensive
 - Chapter 12: For Loops
 - Chapter 13: Wrapping It Up
 - Lesson 4: Zombie Battle System
 - Chapter 1: Payable
 - Chapter 2: Withdraws
 - Chapter 3: Zombie Battles
 - Chapter 4: Random Numbers
 - Chapter 5: Zombie Fightin'
 - Chapter 6: Refactoring Common Logic
 - Chapter 7: More Refactoring
 - Chapter 8: Back to Attack!
 - Chapter 9: Zombie Wins and Losses
 - Chapter 10: Zombie Victory 😄
 - Chapter 11: Zombie Loss 😞
 - Lesson 5: ERC721 & Crypto-Collectibles
 - Chapter 1: Tokens on Ethereum
 - Chapter 2: ERC721 Standard, Multiple Inheritance
 - Chapter 3: balanceOf & ownerOf
 - Chapter 4: Refactoring
 - Chapter 5: ERC721: Transfer Logic
 - Chapter 6: ERC721: Transfer Cont'd
 - Chapter 7: ERC721: Approve
 - Chapter 8: ERC721: Approve
 - Chapter 9: Preventing Overflows
 - Chapter 10: SafeMath Part 2
 - Chapter 11: SafeMath Part 3
 - Chapter 12: SafeMath Part 4
 - Chapter 13: Comments
 - Chapter 14: Wrapping It Up
 - App Front-ends & Web3.js
 - Chapter 1: Intro to Web3.js
 - Chapter 2: Web3 Providers
 - Chapter 3: Talking to Contracts
 - Chapter 4: Calling Contract Functions
 - Chapter 5: Metamask & Accounts
 - Chapter 6: Displaying our Zombie Army
 - Chapter 7: Sending Transactions
 - Chapter 8: Calling Payable Functions
 - Chapter 9: Subscribing to Events
 - Chapter 10: Wrapping It Up
 
Chapter 12: SafeMath Part 4
Chapter 12: SafeMath Part 4
Great, now we can implement SafeMath on all the types of
uints we used in our DApp!Let's fix all those potential issues in
ZombieAttack. (There was also one zombies[_zombieId].level++; that needed to be fixed in ZombieHelper, but we've taken care of that one for you so we don't take an extra chapter to do so 😉).Putting it to the Test
Go ahead and implement SafeMath methods on all the
++ increments in ZombieAttack. We've left comments in the code to make them easy to find.pragma solidity ^0.4.25;
import "./zombiehelper.sol";
contract ZombieAttack is ZombieHelper {
uint randNonce = 0;
uint attackVictoryProbability = 70;
function randMod(uint _modulus) internal returns(uint) {
// Here's one!
// randNonce++;
randNonce = randNonce.add(1);
return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus;
}
function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) {
Zombie storage myZombie = zombies[_zombieId];
Zombie storage enemyZombie = zombies[_targetId];
uint rand = randMod(100);
if (rand <= attackVictoryProbability) {
// Here's 3 more!
// myZombie.winCount++;
myZombie.winCount = myZombie.winCount.add(1);
myZombie.level = myZombie.level.add(1);
enemyZombie.lossCount = enemyZombie.lossCount.add(1);
feedAndMultiply(_zombieId, enemyZombie.dna, "zombie");
} else {
// ...annnnd another 2!
myZombie.lossCount = myZombie.lossCount.add(1);
enemyZombie.winCount = enemyZombie.winCount.add(1);
_triggerCooldown(myZombie);
}
}
}
import "./zombiehelper.sol";
contract ZombieAttack is ZombieHelper {
uint randNonce = 0;
uint attackVictoryProbability = 70;
function randMod(uint _modulus) internal returns(uint) {
// Here's one!
// randNonce++;
randNonce = randNonce.add(1);
return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus;
}
function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) {
Zombie storage myZombie = zombies[_zombieId];
Zombie storage enemyZombie = zombies[_targetId];
uint rand = randMod(100);
if (rand <= attackVictoryProbability) {
// Here's 3 more!
// myZombie.winCount++;
myZombie.winCount = myZombie.winCount.add(1);
myZombie.level = myZombie.level.add(1);
enemyZombie.lossCount = enemyZombie.lossCount.add(1);
feedAndMultiply(_zombieId, enemyZombie.dna, "zombie");
} else {
// ...annnnd another 2!
myZombie.lossCount = myZombie.lossCount.add(1);
enemyZombie.winCount = enemyZombie.winCount.add(1);
_triggerCooldown(myZombie);
}
}
}