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 4: Refactoring
Chapter 4: Refactoring
Uh oh! We've just introduced an error in our code that will make it not compile. Did you notice it?
In the previous chapter we defined a function called
ownerOf
. But if you recall from Lesson 4, we also created a modifier
with the same name, ownerOf
, in zombiefeeding.sol
.If you tried compiling this code, the compiler would give you an error saying you can't have a modifier and a function with the same name.
So should we just change the function name in
ZombieOwnership
to something else?No, we can't do that!!! Remember, we're using the ERC721 token standard, which means other contracts will expect our contract to have functions with these exact names defined. That's what makes these standards useful — if another contract knows our contract is ERC721-compliant, it can simply talk to us without needing to know anything about our internal implementation decisions.
So that means we'll have to refactor our code from Lesson 4 to change the name of the
modifier
to something else.Putting it to the Test
We're back in
zombiefeeding.sol
. We're going to change the name of our modifier
from ownerOf
to onlyOwnerOf
.1. Change the name of the modifier definition to
onlyOwnerOf
2. Scroll down to the function
feedAndMultiply
, which uses this modifier. We'll need to change the name here as well.Note: We also use this modifier in
zombiehelper.sol
and zombieattack.sol
, but so we don't spend too much of this lesson refactoring, we've gone ahead and changed the modifier names in those files for you.zombiefeeding.sol
pragma solidity ^0.4.25;
import "./zombiefactory.sol";
contract KittyInterface {
function getKitty(uint256 _id) external view returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
);
}
contract ZombieFeeding is ZombieFactory {
KittyInterface kittyContract;
// 1. Change modifier name to `onlyOwnerOf`
modifier onlyOwnerOf(uint _zombieId) {
require(msg.sender == zombieToOwner[_zombieId]);
_;
}
function setKittyContractAddress(address _address) external onlyOwner {
kittyContract = KittyInterface(_address);
}
function _triggerCooldown(Zombie storage _zombie) internal {
_zombie.readyTime = uint32(now + cooldownTime);
}
function _isReady(Zombie storage _zombie) internal view returns (bool) {
return (_zombie.readyTime <= now);
}
// 2. Change modifier name here as well
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) {
Zombie storage myZombie = zombies[_zombieId];
require(_isReady(myZombie));
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) {
newDna = newDna - newDna % 100 + 99;
}
_createZombie("NoName", newDna);
_triggerCooldown(myZombie);
}
function feedOnKitty(uint _zombieId, uint _kittyId) public {
uint kittyDna;
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
feedAndMultiply(_zombieId, kittyDna, "kitty");
}
}
import "./zombiefactory.sol";
contract KittyInterface {
function getKitty(uint256 _id) external view returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
);
}
contract ZombieFeeding is ZombieFactory {
KittyInterface kittyContract;
// 1. Change modifier name to `onlyOwnerOf`
modifier onlyOwnerOf(uint _zombieId) {
require(msg.sender == zombieToOwner[_zombieId]);
_;
}
function setKittyContractAddress(address _address) external onlyOwner {
kittyContract = KittyInterface(_address);
}
function _triggerCooldown(Zombie storage _zombie) internal {
_zombie.readyTime = uint32(now + cooldownTime);
}
function _isReady(Zombie storage _zombie) internal view returns (bool) {
return (_zombie.readyTime <= now);
}
// 2. Change modifier name here as well
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) {
Zombie storage myZombie = zombies[_zombieId];
require(_isReady(myZombie));
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) {
newDna = newDna - newDna % 100 + 99;
}
_createZombie("NoName", newDna);
_triggerCooldown(myZombie);
}
function feedOnKitty(uint _zombieId, uint _kittyId) public {
uint kittyDna;
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
feedAndMultiply(_zombieId, kittyDna, "kitty");
}
}