0% found this document useful (0 votes)
105 views

Ethereum Smart Contract Programming 101

This document provides an overview and examples of key Solidity concepts including: - Creating a basic "Hello World" smart contract with state variables and getter/setter functions. - Examples of different data types like strings, integers, booleans, addresses, arrays, and structs. - How to use mappings as a key-value store for looking up values quickly. - Control flow with if/else statements. - The different visibility levels (public, private, internal, external) and what they restrict access to.

Uploaded by

luca pisani
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
105 views

Ethereum Smart Contract Programming 101

This document provides an overview and examples of key Solidity concepts including: - Creating a basic "Hello World" smart contract with state variables and getter/setter functions. - Examples of different data types like strings, integers, booleans, addresses, arrays, and structs. - How to use mappings as a key-value store for looking up values quickly. - Control flow with if/else statements. - The different visibility levels (public, private, internal, external) and what they restrict access to.

Uploaded by

luca pisani
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

7/7/2020 Preview

Build Tools - Remix Walkthrough


Solidity Basics

Link to Remix: https://remix.ethereum.org

Forum Discussion: https://forum.ivanontech.com/t/solidity-basics/9637

Hello World
Solidity Basics

Forum Discussion: https://forum.ivanontech.com/t/solidity-basics/9637

Contract code available here. 

WorldHello.sol

pragma solidity 0.5.12;

contract HelloWorld{
    // State Variables
    string public message = "Hello World";
    
    // Functions
    function getMessage() public view returns(string memory){
        return message;
  }
    
    function setMessage(string memory newMessage) public {
        message = newMessage;
  }
}

@filip Seems using quotes on text in set function is not required. When pressing message with and without
quotes result is the same.

Maybe it does. I can remember some time I had issues with that and I had to use quotes in remix. Maybe it has
changed. However, it’s a good habit to have to put quotes around your strings. In truffle you would have to, for
example.

Types & Arrays


Solidity Basics

Forum Discussion: https://forum.ivanontech.com/t/solidity-basics/9637

Contract code available here. 


1/35
7/7/2020 Preview

Mark As Complete

uint = unsigned integer


bool = boolean
address = eth address
string = string

Array:

uint[] = array of int


string[] = array of strings

pragma solidity 0.5.12;

contract HelloWorld{
    // State Variables
    string public message = "Hello World";
    uint public number = 123;
    bool public isHappy = true;
    address public contractCreator = 0xAFED31ee923Fea479708a2669E7C6777c55A08b3;
    uint[] public numbers = [1, 20, 45];
    uint[2] public fixArrayNumbers = [1, 2]; // Only two values size=2 and can't be modified
    string[] public messages = ["hello", "world"];
    
    // Functions
    function getMessage() public view returns(string memory){
        return message;
  }
    
    function setMessage(string memory newMessage) public {
        message = newMessage;
  }
    
    function getNumber(uint index) public view returns(uint) {
        return numbers[index];
  }
    
    function setNumber(uint newNumber, uint index) public {
        numbers[index] = newNumber;
  }
    
    function addNumber(uint newNumber) public {
        numbers.push(newNumber);
  }
}

 
2/35
7/7/2020 Preview

Structs
struct per definire strutture.

pragma solidity 0.5.12;

contract HelloWorld{
  
    struct Person {
        uint id;
        string name;
        uint age;
        uint height;
        //address walletAddress;
  }
    
    Person[] public people;
    
    function createPerson(string memory name, uint age, uint height) public {
        
        // Add a Person to the people array
        //people.push( Person(people.length, name, age, height) );
        
        // Or you can do in this way
        
        Person memory newPerson;
        newPerson.id = people.length;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        people.push( newPerson );
  }
 
}

Introduction to Mappings
Mapping = dictionary or key -> values storage

mapping in solidity:

mapping(keytype => valtype) name


ex:

3/35
7/7/2020 Preview

mapping(address => uint) balance

to assign:
balance[address] = 10
to get it:
balance[address] 

pragma solidity 0.5.12;

contract Mapping{
  
    struct Person {
        //uint id;
        string name;
        uint age;
        uint height;
        //address walletAddress;
  }
    
    //Person[] public people;
    mapping(address => Person) private people; 
    
    
    function createPerson(string memory name, uint age, uint height) public {
        address creator = msg.sender;
        
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        people[creator] = newPerson;
  }
    
    function getPerson() public view returns(string memory name, uint age, uint height) {
        return (people[msg.sender].name, people[msg.sender].age, people[msg.sender].height );
  }
 
}

4/35
7/7/2020 Preview

Results Breakdown - 100%


check_circle

What best describes a Key-Value datatype?

Your Answer

check_boxData records that can be quickly retrieved using a key that uniquely identifies the record

check_circle

How do I set the value 50, for the key Bob, in the mapping age?

Your Answer

check_boxage["Bob"] = 50

check_circle

Is it possible to find all values entered into a mapping in solidity?

Your Answer

check_boxNo

check_circle

Is it possible to find all keys entered into a mapping in solidity?

Your Answer

check_boxNo

check_circle

What's the main benefit of mappings compared to arrays?

Your Answer

check_boxQuick lookups if key is known

If & Else - Control Flow


if(age > 65) {
            newPerson.senior = true;
} else if (age<3) {
            // Do something !!
} else {
5/35
7/7/2020 Preview

            newPerson.senior = false;
}

pragma solidity 0.5.12;

contract Mapping{
  
    struct Person {
        //uint id;
        string name;
        uint age;
        uint height;
        bool senior;
        //address walletAddress;
  }
    
    //Person[] public people;
    mapping(address => Person) private people; 
    
    
    function createPerson(string memory name, uint age, uint height) public {
        address creator = msg.sender;
        
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        if(age > 65) {
            newPerson.senior = true;
        } else {
            newPerson.senior = false;
    }
        
        people[creator] = newPerson;
  }
    
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior) {
        return (people[msg.sender].name, people[msg.sender].age, people[msg.sender].height,
people[msg.sender].senior );
  }
 
}
 

6/35
7/7/2020 Preview

Introduction to Visibility
Visibility is a way to restrain access to functions and state variables.

1) Public (from everyone)


2) Private (only from within the contract)
    This functions and state can be seen in the blockchain. Are priivate in the sense that are not accesible in the
same way like public state and func, you can't directly query them
This 3,4 only when you make contracts inherited from others.
3) Internal ( Private and only deriving from it)
4) External (a function can be only executed from outside from other contracts)
https://solidity.readthedocs.io/en/v0.5.3/contracts.html

pragma solidity 0.5.12;

contract Mapping{
  
    struct Person {
        //uint id;
        string name;
        uint age;
        uint height;
        bool senior;
        //address walletAddress;
  }
    
    //Person[] public people;
    mapping(address => Person) private people; 
    
    
    function createPerson(string memory name, uint age, uint height) public {
        
        
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        if(age > 65) {
            newPerson.senior = true;
        } else {
            newPerson.senior = false;
    }

7/35
7/7/2020 Preview

        
        insertPerson(newPerson);
        
  }
    
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
  }
    
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior) {
        return (people[msg.sender].name, people[msg.sender].age, people[msg.sender].height,
people[msg.sender].senior );
  }
 
}

Results Breakdown - 100%


check_circle

What does the visibility level private do to a function?

Your Answer

check_box"Private" limits a functions visibility to the contract only

check_circle

What does the visibility level internal do to a function?

Your Answer

check_box"Internal" limits a functions visibility to the contract and all contracts that inherit from it.

check_circle

Where do we specify a functions visibility level?

Your Answer

check_boxIn the function header

check_circle

For which visibility levels will solidity automatically create a getter function for us?

Your Answer

check_boxPublic

8/35
7/7/2020 Preview

Ethereum Gas
Solidity Basics

Operation Costs in Gas (Advanced): https://docs.google.com/spreadsheets/d/1m89CVujrQe5LAFJ8-


YAUCcNK950dUzMQPMJBxRtGCqs/edit

GAS:

- Powers the EVM


- Cost of execution
- Payed by sender

Gas comsumption is fixed


Price is not fixed

With Gas there is an incentive to run a program (smart contract) and a disincentive to spam the network (the
sender pays)

Operations has to be done in the more efficient way and specially for storage that is the most expansive

Error Handling Intro Part 1 - Require


require()
- check for valid condition
a token contract a condition is when I have to have tokens to to something. transfer trokens if I have enough
balance. if is not true it thows an exception
- check input
try to transfer a negative number of tokens
- revert
if a require fails it call the revert that means all the operation will be reverted

ex:
require (inputnumber > 0)

require (msg.sender == owner) to make possible to do some operation only by the contract owner.

Error Handling Intro Part 2 - Assert


Assert()
- test for internal error

9/35
7/7/2020 Preview

only throw if an interal error occurs.


Ex: tranfert 100 token only if the balance is >100. with assert we make sure that when the transfer occours the
condition is valid even if our code is in error?
- check invariance
Invariants
A concept
Condition that is always true at a particular point in code

Ex: 
There is a funcion in a contract withdrawAll that transfer all coins to another address. At the end of a function the
balance should be 0 but if it is not the case (maybe for a programming error) with assert we throw an error
because our concept (account empty after transfering all coins) is not proved (condition not true)

Programming with Require()


the constractor() function is called ones when the contract is created (by the owner)

pragma solidity 0.5.12;

contract Mapping{
  
    struct Person {
        //uint id;
        string name;
        uint age;
        uint height;
        bool senior;
        //address walletAddress;
  }
    
    address owner;
    
    constructor() public {
        owner = msg.sender;
  }
    
    //Person[] public people;
    mapping(address => Person) private people; 
    
    address[] private creators;
    
    function createPerson(string memory name, uint age, uint height) public {
        
        require(age < 150, "age needs to be below 150!");
        Person memory newPerson;

10/35
7/7/2020 Preview

        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        if(age > 65) {
            newPerson.senior = true;
        } else {
            newPerson.senior = false;
    }
        
        insertPerson(newPerson);
        creators.push(msg.sender);
        
  }
    
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
  }
    
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior) {
        return (people[msg.sender].name, people[msg.sender].age, people[msg.sender].height,
people[msg.sender].senior );
  }
    
    function deletePerson(address creator) public {
        require(msg.sender == owner, "Caller needs to be owner");
        delete people[creator];
  }
    
    function getCreator(uint index) public view returns(address) {
        require(msg.sender == owner, "Caller needs to be owner");
        return creators[index];
  }
 
}
 

--------------------------

Programming with Assert()


if an assert fail the code reverse (to the previous state) and all gas is depleted

pragma solidity 0.5.12;

11/35
7/7/2020 Preview

contract Mapping{
  
    struct Person {
        //uint id;
        string name;
        uint age;
        uint height;
        bool senior;
        //address walletAddress;
  }
    
    address owner;
    
    constructor() public {
        owner = msg.sender;
  }
    
    //Person[] public people;
    mapping(address => Person) private people; 
    
    address[] private creators;
    
    function createPerson(string memory name, uint age, uint height) public {
        
        require(age < 150, "age needs to be below 150!");
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        if(age > 65) {
            newPerson.senior = true;
        } else {
            newPerson.senior = false;
    }
        
        insertPerson(newPerson);
        creators.push(msg.sender);
        // Invariance
        // people[msg.sender] == newPerson
        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name, 

12/35
7/7/2020 Preview

                    people[msg.sender].age, 
                    people[msg.sender].height, 
                    people[msg.sender].senior
        )
            ) 
            == 
            keccak256(
                abi.encodePacked(
                    newPerson.name, 
                    newPerson.age, 
                    newPerson.height, 
                    newPerson.senior
        )
            ) 
        );
        
  }
    
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
  }
    
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior) {
        return (people[msg.sender].name, people[msg.sender].age, people[msg.sender].height,
people[msg.sender].senior );
  }
    
    function deletePerson(address creator) public {
        require(msg.sender == owner, "Caller needs to be owner");
        delete people[creator];
        // Invariance
        // people[creator].age == 0
        assert( people[creator].age == 0 );
  }
    
    function getCreator(uint index) public view returns(address) {
        require(msg.sender == owner, "Caller needs to be owner");
        return creators[index];
  }
 
}
 

13/35
7/7/2020 Preview

------------------------------

Quiz: Error Handling

Results Breakdown - 100%


check_circle

When should you use assert?

Your Answer

check_boxTo avoid conditions which should never, ever be possible

check_circle

When should you use require?

Your Answer

check_boxTo validate that the caller is the owner

check_boxTo validate inputs

check_circle

Which of the two cases will consume all of the remaining gas in a function call: assert(false) or require(false)?

Your Answer

check_boxassert(false)

----------------------------------------

Modifiers
Modifiers are a way to call a code before a function call . Like to call a require code before a function.

every modifier needs to end with:


_; 
that means continue execution

The modifier is to be inserted almost at the end of funcions:

modifier onlyOwner() {
        require(msg.sender == owner);
        _; // Continue execution
}

function deletePerson(address creator) public onlyOwner {

14/35
7/7/2020 Preview

function getCreator(uint index) public view onlyOwner returns(address) {

All source with modifier:

pragma solidity 0.5.12;

contract Mapping{
  
    struct Person {
        //uint id;
        string name;
        uint age;
        uint height;
        bool senior;
        //address walletAddress;
  }
    
    address owner;
    
    modifier onlyOwner() {
        require(msg.sender == owner);
        _; // Continue execution
  }
    
    constructor() public {
        owner = msg.sender;
  }
    
    //Person[] public people;
    mapping(address => Person) private people; 
    
    address[] private creators;
    
    function createPerson(string memory name, uint age, uint height) public {
        
        require(age < 150, "age needs to be below 150!");
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        if(age > 65) {
            newPerson.senior = true;
        } else {
            newPerson.senior = false;

15/35
7/7/2020 Preview

    }
        
        insertPerson(newPerson);
        creators.push(msg.sender);
        // Invariance
        // people[msg.sender] == newPerson
        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name, 
                    people[msg.sender].age, 
                    people[msg.sender].height, 
                    people[msg.sender].senior
        )
            ) 
            == 
            keccak256(
                abi.encodePacked(
                    newPerson.name, 
                    newPerson.age, 
                    newPerson.height, 
                    newPerson.senior
        )
            ) 
        );
        
  }
    
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
  }
    
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior) {
        return (people[msg.sender].name, people[msg.sender].age, people[msg.sender].height,
people[msg.sender].senior );
  }
    
    function deletePerson(address creator) public onlyOwner {
        //require(msg.sender == owner, "Caller needs to be owner");
        delete people[creator];
        // Invariance
        // people[creator].age == 0
        assert( people[creator].age == 0 );

16/35
7/7/2020 Preview

  }
    
    function getCreator(uint index) public view onlyOwner returns(address) {
        //require(msg.sender == owner, "Caller needs to be owner");
        return creators[index];
  }
 
}
 

-------------------------------------------------------------------

Quiz: Modifiers
 

Results Breakdown - 100%


check_circle

When is the function modifiers code executed?

Your Answer

check_boxBefore the function

check_circle

What does the _ (underscore) mean within a function modifier?

Your Answer

check_boxExecute the function body

------------------------------------------------------------------------------------

Data Location
Data location is where we tell solidity to save the data
There are three different data location:
- storage
data is stored permanently
ex: 
address public owner;
mapping(address => Person) private people; 
are stored permanently (until the contract is destroyed)

17/35
7/7/2020 Preview

- memory
data is only saved during a function execution
ex:
function createPerson(string memory name, uint age, uint height) public {
the var name will terminate to exists when the function createPerson is terminated.

- stack
stack is for hold local variabiles of value types
value types are integers, boolean values that are lower of 256bit in size
if inside a funcion I write:
uint score = 1
Is defaulted to stack

The function parameters are always defaulted to memory. But for more complex types like strings and struct and
arrays we need to specify their data location.

----------------------------------------

Data Location Assignment


https://github.com/filipmartinsson/solidity-0.5.12-course/blob/master/memory-assignment.sol

pragma solidity 0.5.1;


contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
uint id;
uint balance;
}

function addUser(uint id, uint balance) public {


users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {


User memory user = users[id];
user.balance = balance;
}

function getBalance(uint id) view public returns (uint) {


return users[id].balance;
}

}
18/35
7/7/2020 Preview

Fixed with:

Hi. I had to change pragma solidity to 0.5.12 otherwise with google-chrome it won’t compile.

To differentiate addUser and updateBalance I added some constraint.

pragma solidity 0.5.12;

contract MemoryAndStorage {

    mapping(uint => User) users;

    struct User{
        uint id;
        uint balance;
  }
    
  
    modifier newUser(uint id) {
        require( id > 0, "User id must be > 0" );
        require( id != users[id].id, "User id is already used" );
        _;
  }
    
    modifier userMustExist(uint id) {
        require( id > 0, "User id must be > 0" );
        require( id == users[id].id, "User doesn't exist" );
        _;
  }
    
    function addUser(uint id, uint balance) public newUser(id) {
          users[id] = User(id, balance);
  }

    function updateBalance(uint id, uint balance) public userMustExist(id) {


         //User memory user = users[id];
         //user.balance = balance;
         //users[id] = User(id, balance); // First solution
        users[id].balance = balance;
  }

    function getBalance(uint id) view public userMustExist(id) returns (uint) {


        return users[id].balance;
  }

---------------------------------------------------------

19/35
7/7/2020 Preview

Quiz: Data Location


Results Breakdown - 100%
check_circle

Which of these are data locations in Solidity?

Your Answer

check_boxMemory

check_boxStorage

check_boxStack

check_circle

Do we need to specify a data location for  value-type variables?

Your Answer

check_boxNo

check_circle

What can happen if we use data location memory instead of storage?

Your Answer

check_boxChanges are lost

---------------------------------------------

Events
Small notification you can send from your contract that get included in the blockchain,  to notify people of
important events
So if a dapp is listening it can update the website with the "news" (like user added)
An event need first to be declared like this:
event personCreated(string name, bool senior);
Note there is no memory in name in this case is implicit (why??)

emit personCreated(newPerson.name, newPerson.senior);


with emit we fire the event
You can find the event in the transaction in the field log:
[
    {
        "from": "0xc4e0650c6c6b5d323d165665965e7bb69e149d75",
20/35
7/7/2020 Preview

        "topic": "0x483a95908cf8068144f424e2adef59ae102592afd2706bb3d37a620b6a2304e7",


        "event": "personCreated",
        "args": {
            "0": "luca",
            "1": false,
            "name": "luca",
            "senior": false,
            "length": 2
        }
    }
]

pragma solidity 0.5.12;

contract Mapping{
  
    struct Person {
        //uint id;
        string name;
        uint age;
        uint height;
        bool senior;
        //address walletAddress;
  }
    
    event personCreated(string name, bool senior);
    event personDeleted(string name, bool senior, address deletedBy);
    
    address owner;
    
    modifier onlyOwner() {
        require(msg.sender == owner);
        _; // Continue execution
  }
    
    constructor() public {
        owner = msg.sender;
  }
    
    //Person[] public people;
    mapping(address => Person) private people; 
    
    address[] private creators;
    
    function createPerson(string memory name, uint age, uint height) public {

21/35
7/7/2020 Preview

        
        require(age < 150, "age needs to be below 150!");
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        if(age > 65) {
            newPerson.senior = true;
        } else {
            newPerson.senior = false;
    }
        
        insertPerson(newPerson);
        creators.push(msg.sender);
        // Invariance
        // people[msg.sender] == newPerson
        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name, 
                    people[msg.sender].age, 
                    people[msg.sender].height, 
                    people[msg.sender].senior
        )
            ) 
            == 
            keccak256(
                abi.encodePacked(
                    newPerson.name, 
                    newPerson.age, 
                    newPerson.height, 
                    newPerson.senior
        )
            ) 
        );
        
        emit personCreated(newPerson.name, newPerson.senior);
        
  }
    
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;

22/35
7/7/2020 Preview

  }
    
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior) {
        return (people[msg.sender].name, people[msg.sender].age, people[msg.sender].height,
people[msg.sender].senior );
  }
    
    function deletePerson(address creator) public onlyOwner {
        //require(msg.sender == owner, "Caller needs to be owner");
        string memory name = people[creator].name;
        bool senior = people[creator].senior;
        
        delete people[creator];
        // Invariance
        // people[creator].age == 0
        assert( people[creator].age == 0 );
        emit personDeleted(name,senior,creator);
        //emit personDeleted(name, senior, msg.sender);
  }
    
    function getCreator(uint index) public view onlyOwner returns(address) {
        //require(msg.sender == owner, "Caller needs to be owner");
        return creators[index];
  }
 
}

[
    {
        "from": "0xd920953bb51535e6f1263c093ee34727039ee936",
        "topic": "0xce505ea5e5a360ed968bacfdf5b52e168dfe627776422d678cb12143ebe187c8",
        "event": "personDeleted",
        "args": {
            "0": "",
            "1": false,
            "2": "0xD920953bb51535e6f1263C093EE34727039eE936",
            "name": "",
            "senior": false,
            "deletedBy": "0xD920953bb51535e6f1263C093EE34727039eE936",
            "length": 3
        }
    }
]

23/35
7/7/2020 Preview

----------------------------------------------------

Quiz: Events
 

Results Breakdown - 100%


check_circle

How are events declared in Solidity?

Your Answer

check_boxevent Example(uint number, address from)

check_circle

Why is it useful to be able to listen for Solidity events being fired?

Your Answer

check_boxBecause frontends in dapps can react to changes in our contracts.

------------------------------------

Receiving money
in smart contract we can manage money.
To tell solidity this we can say that a function can receive money adding the work payable
function createPerson(string memory name, uint age, uint height) public payable {
and inside the function check it with msg.value that contains the ethers (money)
for the amount we have to specify the unit of account (wei is default like satoshi in bitcoin) ether for ether.
wei, gwei, finney, ether

require(msg.value >=1 ether);


The function createPerson will be red and remember to put the ether (1) in value field with the right unit (ether)

A smart contract has a balance similar to a normal account

24/35
7/7/2020 Preview

Solution & Modifier


We can add a modifier costs(uint cost) so we can set a price (cost) for each function and it will be very readable
cause the modifier will be in the funcions declaration.
If inside a function you need to charge differents costs you need to use require (cause you need different
conditions) and you can't use a simple modifier.

pragma solidity 0.5.12;

contract Mapping{
  
    struct Person {
        //uint id;
        string name;
        uint age;
        uint height;
        bool senior;
        //address walletAddress;
  }
    
    event personCreated(string name, bool senior);
    event personDeleted(string name, bool senior, address deletedBy);
    
    address owner;
    
    modifier onlyOwner() {
        require(msg.sender == owner);
        _; // Continue execution
  }
    
    modifier costs(uint cost) {
        require(msg.value >= cost);
        _;
  }
    
    constructor() public {
        owner = msg.sender;
  }
    
    //Person[] public people;
    mapping(address => Person) private people; 
    
    address[] private creators;
    
    uint private balance;
25/35
7/7/2020 Preview

    
    function getBalance() public view onlyOwner returns(uint balanc) {
        return balance;
  }
    
    function createPerson(string memory name, uint age, uint height) public payable costs(1 ether) {
        
        require(age < 150, "age needs to be below 150!");
        // Check if payment >= 1 ether
        //require(msg.value >=1 ether);
        
        
        
        
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        
        if(age > 65) {
            newPerson.senior = true;
        } else {
            newPerson.senior = false;
    }
        
        insertPerson(newPerson);
        creators.push(msg.sender);
        // Invariance
        // people[msg.sender] == newPerson
        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name, 
                    people[msg.sender].age, 
                    people[msg.sender].height, 
                    people[msg.sender].senior
        )
            ) 
            == 
            keccak256(
                abi.encodePacked(
                    newPerson.name, 
                    newPerson.age, 
                    newPerson.height, 

26/35
7/7/2020 Preview

                    newPerson.senior
        )
            ) 
        );
        
        emit personCreated(newPerson.name, newPerson.senior);
        balance += msg.value;
        
  }
    
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
  }
    
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior) {
        return (people[msg.sender].name, people[msg.sender].age, people[msg.sender].height,
people[msg.sender].senior );
  }
    
    function deletePerson(address creator) public onlyOwner {
        //require(msg.sender == owner, "Caller needs to be owner");
        string memory name = people[creator].name;
        bool senior = people[creator].senior;
        
        delete people[creator];
        // Invariance
        // people[creator].age == 0
        assert( people[creator].age == 0 );
        emit personDeleted(name,senior,creator);
        //emit personDeleted(name, senior, msg.sender);
  }
    
    function getCreator(uint index) public view onlyOwner returns(address) {
        //require(msg.sender == owner, "Caller needs to be owner");
        return creators[index];
  }
 
}

-------------------------------

Send & Transfer


27/35
7/7/2020 Preview

You can send money with transfer funcition

<address>.transfer(qta_to_transfer)

ex:

    function withdrawAll() public onlyOwner returns (uint) {


        uint toTransfer = balance;
        balance = 0;
        msg.sender.transfer(toTransfer);
        return toTransfer;
        
  }

you can also use the send function with the same syntax.


The difference is that if transfer fails it revert the transaction while send it just retuns false and continue the
contract execution.
 

This is not safe to do for reentrance problem you will see it in security course in ethereum.

    function withdrawAll() public onlyOwner returns (uint) {


        if(msg.sender.send(balance)) {
           uint toTransfer = balance;
           balance = 0;
           return toTransfer;   
        } else {
            return 0;
    }
  }

You have to do like this:


// withdrawAll with send 
    function AlternativeWithdrawAll() public onlyOwner returns (uint) {
        uint toTransfer = balance;
        balance = 0;
        if(msg.sender.send(toTransfer)) {
            return toTransfer;
        } else {
            balance = toTransfer;
            return 0;
    }
  }

----------------------------------

28/35
7/7/2020 Preview

Payable Addresses vs Normal Addresses


address owner;
can't receive money cause it is not a payable address (just a normal address)
you have to declare like this:
address payable owner;
It is conceived like this to limit errors; don't make payable address that can receive money and you didn't think
about that, and make functions to retreive that money?;
To go from a normal address to a payable address you can do:

address creator = msg.sender;


address payable test = address(uint160(creator));

------------------------------

Quiz: Payable Functions


Results Breakdown - 100%
check_circle

What keyword do we need to put in our function header in order to be able to receive money to that function?

Your Answer

check_boxpayable

check_circle

Why is it useful to have a balance variable in our contract?

Your Answer

check_boxSo that our contract can query for its own balance

check_circle

What is the main difference between send() and transfer()?

Your Answer

check_boxtransfer() will throw an error on failure

check_circle

How do we convert the payable address addressPayable to a non-payable address?

Your Answer

29/35
7/7/2020 Preview

check_boxNo conversion necessary

check_circle

How do we convert the non-payable address addressNonPayable to a payable address?

Your Answer

check_boxaddress(uint160(addressNonPayable))

------------------------------------------------------------

Inheritance Reading Assignment


Inheritance & External Contracts

To learn the basics of inheritance in solidity, before we start to code, read through this blog post. The article goes
into quite deep detail, and unless you are curious, you can stop when you get to the section about
Polymorphism. 

https://solidity.readthedocs.io/en/v0.5.3/contracts.html

Then answer the following questions. Post your answers in this forum thread. 

1. What is the base contract?


The base contract is like the parent contract and a child inherits from the father.

2. Which functions are available for derived contracts?


public, internal

3. What is hierarchical inheritance?


a single contract acts as a base contract for multiple derived contracts.

----------------------------------

Inheritance in Solidity
import "./Ownable1.sol";
pragma solidity 0.5.12;

contract Mapping is Ownable {

................

Inheritance Assignment

30/35
7/7/2020 Preview

Read more about how to destroy contracts: https://articles.caster.io/blockchain/self-destructing-smart-contracts-


in-ethereum/

Post your solution here: https://forum.ivanontech.com/t/inheritance-assignment/9643

import "Ownable.sol";
pragma solidity 0.5.12;

contract Destroyable is Ownable {


    function close() public onlyOwner { //onlyOwner is custom modifier
        selfdestruct(msg.sender);  // `owner` is the owners address
  }
}

-----------------

Using Internal Visibility Level

pragma solidity 0.5.12;

contract Ownable {
    address internal owner;
    
    constructor() public {
        owner = msg.sender;
  }
    modifier onlyOwner() {
        require(msg.sender == owner);
        _; // Continue execution
  }
}

User keyword internal to make the owner var visibile in child contracts.

-----------------------

Quiz: Inheritance
Results Breakdown - 100%
check_circle

31/35
7/7/2020 Preview

How do we indicate that a Contract A inherits from Contract B in solidity?

Your Answer

check_boxcontract A is contract B

check_circle

What are some benefits of using inheritance as part of your code?

Your Answer

check_boxReduces code duplication

check_boxCreates a clear code structure

check_circle

Can a child contract inherit from multiple parent contracts?

Your Answer

check_boxYes

check_circle

Can a parent contract have multiple child contracts?

Your Answer

check_boxYes

check_circle

Contract A inherits from Contract B. Contract B has a public function called getBalance. 

Can I run the getBalance function inside contract A?

Your Answer

check_boxYes

check_circle

Contract A inherits from Contract B. Contract B has a private function called getBalance. 

Can I run the getBalance function inside contract A?

Your Answer

check_boxNo

32/35
7/7/2020 Preview

---------------------------------------------

External Contracts
 
user -> Conract A -> Contract B

Remeber msg.sender in called contract B will be the address of the caller A not the msg.sender (user) that is
using the contract A

contract ExternalContract is A
contract Mapping is B

pragma solidity 0.5.12;

// Inserface
contract Mapping {
    // Insert only functions header
    function createPerson(string memory name, uint age, uint height) public payable;
}

contract ExternalContract { 
    
    Mapping instance = Mapping(0x985B1a6fc1B41213BE06cD4DdA4B91f6Dc001f20);

    function externalCreatePerson(string memory name, uint age, uint height) public payable {
        // call createPerson in HelloWorld contract
        // forward any ether to HelloWorld contract
        
        // instance.createPerson(name,age,height); // This would be the straigh forward way but since it is
a payable function 
        // we have to send ether so:
        instance.createPerson.value(msg.value)(name,age,height);
  }  
}

-----------------------------------------

Quiz: External Contracts

Results Breakdown - 100%

33/35
7/7/2020 Preview

check_circle

What 2 things do we need in order for our contract to interact with other (external) contracts?

Your Answer

check_boxThe contracts address

check_boxThe contract Interface

check_circle

Why are interfaces necessary?

Your Answer

check_boxBecause your contract needs to be aware of the function headers in order for you to interact
with the external contract.

check_circle

If you call a function in contract A, which calls a function in Contract B, what will msg.sender be in
Contract B's function?

Your Answer

check_boxContract A's Address

------------------------------------------------------------------

Metamask setup
Deploying to the Testnet

Link to metamask: https://metamask.io

Link to faucet: https://faucet.metamask.io
Alternative: https://faucet.ropsten.be/

Forum Discussion: https://forum.ivanontech.com/t/deploying-to-testnet-discussion/9642

----------------------------------

Deploying our Contract


Deploying to the Testnet

34/35
7/7/2020 Preview

Forum Discussion: https://forum.ivanontech.com/t/deploying-to-testnet-discussion/9642

Remember to select in Remix in Environment the voice "Injected Web3" (from the original "Javascript VM") and
to put 100 wei as the cost of transaction createPerson

---------------------------------

Congratulations & Next Steps


Congratulations & Next Steps

Courses to take after this: 

1. Solidity Smart Contract Programming 201 (coming in November)

This is the direct follow up course to this one. You will learn how to develop, test and deploy contracts using
Truffle and how to build dapps. 

2. Ethereum Smart Contract Security

Learn the best security practices when building smart contracts and avoid the most common bugs and security
flaws. This is a must-take course for all looking to work as a professional developer.

All of these courses are available for our Premium Plan members. You can enroll in the Premium Plan and get
access to these courses by clicking here. 

35/35

You might also like