Back to Home

Solidity with CryptoZombies

1. Contracts

2. Version Pragma

3. State Variables

4. uint

5. public

// example public array
Person[] public people;

6. Arrays

7. Functions

function eatHamburgers(string memory _name, uint _amount) public {}
function _addToArray(uint _number) private {
  numbers.push(_number);
}
string greeting = "What's up dog";

function sayHello() public returns (string memory) {
  return greeting;
}
function sayHello() public view returns (string memory) {}
function _multiply(uint a, uint b) private pure returns (uint) {
  return a * b;
}

8. Keccak256 and Typecasting

//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256(abi.encodePacked("aaaab"));
uint8 a = 5;
uint b = 6;
// throws an error because a * b returns a uint, not uint8:
uint8 c = a * b;
// we have to typecast b as a uint8 to make it work:
uint8 c = a * uint8(b);

9. Events

// declare the event
event IntegersAdded(uint x, uint y, uint result);

function add(uint _x, uint _y) public returns (uint) {
  uint result = _x + _y;
  // fire an event to let the app know the function was called:
  emit IntegersAdded(_x, _y, result);
  return result;
}
YourContract.IntegersAdded(function(error, result) {
  // do something with the result
})

10. Accounts

11. Mappings

// For a financial app, storing a uint that holds the user's account balance:
mapping (address => uint) public accountBalance;
// Or could be used to store / lookup usernames based on userId
mapping (uint => string) userIdToName;

12. msg.sender

13. require()

14. Inheritance

contract Doge {
  function catchphrase() public returns (string memory) {
    return "So Wow CryptoDoge";
  }
}

contract BabyDoge is Doge {
  function anotherCatchphrase() public returns (string memory) {
    return "Such Moon BabyDoge";
  }
}

// contract can inherit from multiple contracts
contract SatoshiNakamoto is NickSzabo, HalFinney {
  // Omg, the secrets of the universe revealed!
}

15. Imports

When you have multiple files and you want to import one file into another, Solidity uses the import keyword:

import "./someothercontract.sol";

contract newContract is SomeOtherContract {

}

16. Storage vs Memory (Data location)

contract SandwichFactory {
  struct Sandwich {
    string name;
    string status;
  }

  Sandwich[] sandwiches;

  function eatSandwich(uint _index) public {
    // Sandwich mySandwich = sandwiches[_index];

    // ^ Seems pretty straightforward, but solidity will give you a warning
    // telling you that you should explicitly declare `storage` or `memory` here.

    // So instead, you should declare with the `storage` keyword, like:
    Sandwich storage mySandwich = sandwiches[_index];
    // ...in which case `mySandwich` is a pointer to `sandwiches[_index]`
    // in storage, and...
    mySandwich.status = "Eaten!";
    // ...this will permanently change `sandwiches[_index]` on the blockchain.

    // If you just want a copy, you can use `memory`:
    Sandwich memory anotherSandwich = sandwiches[_index + 1];
    // ...in which case `anotherSandwich` will simply be a copy of the
    // data in memory, and...
    anotherSandwich.status = "Eaten!";
    // ...will just modify the temporary variable and have no effect
    // on `sandwiches[_index + 1]`. But you can do this:
    sandwiches[_index + 1] = anotherSandwich;
    // ...if you want to copy the changes back into blockchain storage.
  }
}
Diagram Description

17. Interfaces

contract NumberInterface {
  function getNum(address _myAddress) public view returns (uint);
}
contract MyContract {
  address NumberInterfaceAddress = 0xab38...
  // ^ The address of the FavoriteNumber contract on Ethereum
  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
  // Now `numberContract` is pointing to the other contract

  function someFunction() public {
    // Now we can call `getNum` from that contract:
    uint num = numberContract.getNum(msg.sender);
    // ...and do something with `num` here
  }
}

18. OpenZeppelin

19. Function Modifiers (modifier)

contract Ownable {
  ...
  modifier onlyOwner() {
    require(isOwner());
    _;
  }
  ...
  function renounceOwnership() public onlyOwner {
    emit OwnershipTransferred(_owner, address(0));
    _owner = address(0);
  }
}
// A mapping to store a user's age:
mapping (uint => uint) public age;

// Modifier that requires this user to be older than a certain age:
modifier olderThan(uint _age, uint _userId) {
  require(age[_userId] >= _age);
  _;
}

// Must be older than 16 to drive a car (in the US, at least).
// We can call the `olderThan` modifier with arguments like so:
function driveCar(uint _userId) public olderThan(16, _userId) {
  // Some function logic
}

20. Gas

21. Passing structs as arguments

You can pass a storage pointer to a struct as an argument to a private or internal function. This way we can pass a reference to our zombie into a function instead of passing in a zombie ID and looking it up:

function _doStuff(Zombie storage _zombie) internal {
  // do stuff with _zombie
}

22. The payable Modifier

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);
  }
}

23. Withdraws

contract GetPaid is Ownable {
  function withdraw() external onlyOwner {
    address payable _owner = address(uint160(owner()));
    _owner.transfer(address(this).balance);
  }
}
uint itemFee = 0.001 ether;
msg.sender.transfer(msg.value - itemFee);

24. Tokens on Ethereum

25. Library in Solidity

using SafeMath for uint256;

uint256 a = 5;
uint256 b = a.add(3); // 5 + 3 = 8
uint256 c = a.mul(2); // 5 * 2 = 10

26. Comments

/// @title A contract for basic math operations
/// @author H4XF13LD MORRIS 💯💯😎💯💯
/// @notice For now, this contract just adds a multiply function
contract Math {
  /// @notice Multiplies 2 numbers together
  /// @param x the first uint.
  /// @param y the second uint.
  /// @return z the product of (x * y)
  /// @dev This function does not currently check for overflows
  function multiply(uint x, uint y) returns (uint z) {
    // This is just a normal comment, and won't get picked up by natspec
    z = x * y;
  }
}

27. CallData

function processArray(uint[] calldata _values) external {
  // _values is stored in calldata
  // No need to copy the array to memory
  for(uint i = 0; i < _values.length; i++) {
    // Process each value
  }
}