INTRO to Smart contracts

Toptal academy Blockchain lectures #6

2018-03-12

ivan.voras@toptal.com

Today's agenda

  • Ethereum blockchain & smart contracts
  • The web3 idea
  • DAPPS
  • The ERC20 interface
  • Setting up a development environment
  • Remix IDE for smart contracts
  • Solidity: syntax, operation
  • Vyper: syntax, examples
  • Truffle
  • OpenZeppelin libraries

Ethereum smart contracts

  • Strictly speaking, "smart contracts" are just program code stored in a blockchain
  • They exist as data in the Ethereum blockchain, with some special properties, like an ABI
  • Smart contracts are compiled to byte-code and run on the Ethereum Virtual Machine (EVM)
  • Transactions which call methods of smart contracts contain data which describes what is being called and with what arguments
  • Smart contract functions can call functions from other smart contracts

The idea of web3

  • Aka "Web 3.0"
  • "Serverless" of sorts, the "server" is the blockchain
  • The front-end (usually JS) interacts with the blockchain by using the "web3" API in JS.

 

Intended use:

  • A browser implements the "web3" interface (and a few others...) so that the JS code running in it can interface with the blockchain
  • Some browser add-ons / extensions like Metamask inject the web3 interface into the browser

DAPPS

  • "Distributed apps", light-weight
  • JavaScript based applications running in the browser, using the web3 interface to access the blockchain

 

They can also use other features / interfaces such as:

  • "Swarm" for peer-to-peer data storage (similar to IPFS but integrated with Ethereum)
  • "Whisper" for peer-to-peer communication between DAPPS

 

Basically, "let's re-invent everything, on the Blockchain."

The ERC20 interface for creating cryptocurrency tokens

  • totalSupply() : total token supply
  • balanceOf(addr): get token's balance at address
  • allowance(owner_addr, spender_addr, n): how many tokens can the spender just withdraw without asking

 

  • approve(addr, n): returns true if the address can withdraw this amount of tokens
  • transfer(addr, n): returns true if a transfer from the original owner to the address has been made
  • transferFrom(from_addr, to_addr, n): returns true of a transfer from any token owner to any token owner (if approved) has been made

A dev environment with geth and Mist

  1. Download / install "geth" (Ethereum implementation in Go)
  2. Make a folder for the development blockchain, e.g. c:\EthDev
  3. Run:
    geth --dev --ipcpath geth.ipc --datadir c:\EthDev --rpc
    --rpcapi admin,eth,miner,personal,web3,net console
  4. In the geth console, run:
    personal.newAccount()
    miner.start()

 

This will create a new development blockchain just for you, disconnected from the network, with a huge number of Ether in a "default" address, and also create you a new address for testing.

The password for the big account is the empty string.

Geth running

Note: in dev mode, blocks are mined only if there are txs ready to be included in a new block, to conserve CPU time and disk space for empty blocks. This is what "block sealing failed" means.

A dev environment with geth and Mist

  1. Download / install "mist" (Ethereum wallet+dev env)
  2. Run:
    mist --rpc http://localhost:8545

 

This will connect Mist with the geth instance running the private development blockchain.

 

On Windows, I've had bad luck doing it with IPC, this is why I'm using JSON-RPC in the example above.

Mist running with 2 accounts

You should test this setup by sending some Ether back and forth. In dev mode, blocks are mined only if there are txs ready.

The Remix IDE

  • In the Mist menus, Develop -> Open Remix IDE
  • (or https://remix.ethereum.org in a generic browser ... but then you don't get the connection to your dev geth node)

 

The Remix IDE is an "DAPP", a front-end-only, JS-based application using the Ethereum blockchain for everything.

 

It can optionally (i.e. if started in a browser without a connection to a running node) emulate a blockchain,
for testing & debugging purposes only.

Hello, world in Solidity

Note what's going on in geth, and the increase in block count in mist.

The Solidity language

  • Similar to JS, to fit in the "web3" idea
  • Statically typed, supports inheritance, overloading, libraries, custom structured objects
pragma solidity ^0.4.21;

contract HelloWorld {
    
    uint256 count = 0; // stored in the blockchain!
    
    // inc() and dec() change the state of the blockchain, i.e. cost gas
    function inc() public { 
        count++;
    }
    
    function dec() public {
        count--;
    }
    
    // a read-only function, doesn't change the blockchain, free
    function get() public view returns (uint256) {
        return count;
    }
 
}
pragma solidity ^0.4.21;

contract HelloWorld {
    
    // declaration of an "event" (or log message) outputted by the contract
    event PowerOf10(uint256 which); 
    
    uint256 count = 0;
    
    function _check() internal {
        if (count % 10 == 0) {
            emit PowerOf10(count); // emits the event / log
        }
        if (count % 13 == 0) { revert(); } // fail the tx

    }
    
    function inc() public {
        count++;
        _check();
    }
    
    function dec() public {
        count--;
        _check();
    }
    
    function get() public view returns (uint256) {
        return count;
    }
    
    // "default" or "fallback" handler, receives payments to the contract address
    function () public payable {
        count += msg.value;
        _check();
    }
}

A basic ERC20 token contract

pragma solidity ^0.4.21;

import "github.com/OpenZeppelin/zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";

contract HelloToken is StandardToken {

    string public name = "HelloToken";
    string public symbol = "HT";
    uint8 public decimals = 4;
    uint public INITIAL_SUPPLY = 1000 * (10 ** uint(decimals));

    // constructor
    function HelloToken() public {
        totalSupply_ = INITIAL_SUPPLY;
        balances[msg.sender] = INITIAL_SUPPLY;
    }
}

This is a complete ERC20 token contract.

You can use its address in Mist to monitor the number of tokens you have, use it in "smarter" wallets to transfer tokens, etc.

As the owner, you can send the tokens anywhere with .transfer()

"database" of who has how  many tokens

The ERC20 interface revisited

  • totalSupply() : total token supply
  • balanceOf(addr): get token's balance at address
  • allowance(owner_addr, spender_addr, n): how many tokens can the spender just withdraw without asking
  • approve(addr, n): returns true if the address can withdraw this amount of tokens
  • transfer(addr, n): returns true if a transfer from the original owner to the address has been made
  • transferFrom(from_addr, to_addr, n): returns true of a transfer from any token owner to any token owner (if approved) has been made

Homework

 

Create your own token, using Remix with Mist. Name the token by including your own name, deploy it on the private network, transfer some token values between accounts.

Solidity gotchas

  • There are no decimal data types, everything by default is a 256-bit integer (payments are in wei...)
  • Overflows and underflows are possible. OpenZeppelin's SafeMath library helps (and costs gas...)
  • The fallback function may fail, so any sending to an address may fail
  • Strings are bytes (i.e. not unicode), and poorly supported, e.g. no build-in library functions to e.g. convert int to string
  • Mist+Remix sometimes cannot read the address of a newly deployed contract, see geth console for the address
  • Arguments for function calls in Remix must be quoted in double quotes, even if numbers

Mist/Remix contract function call

Useful links

Vyper language

Like Solidity, but inspired by Python... so if you like Python's syntax more, it may be a good solution. It is somewhat inspired by the older "Serpent" whose future is uncertain.

OTOH, Vyper is currently considered "experimental".

@public
def transferFrom(_from: address, _to: address, _value: int128(uint256)) -> bool:

    if _value <= self.allowed[_from][msg.sender] and \
       _value <= self.balances[_from]:

        self.balances[_from] -= _value  # decrease balance of from address.
        self.allowed[_from][msg.sender] -= _value  # decrease allowance.
        self.balances[_to] += _value  # incease balance of to address.
        log.Transfer(_from, _to, convert(_value, 'uint256'))  # log transfer event.

        return True
    else:
        return False

Working with Truffle

NodeJS / npm based environment.

 

npm install truffle

 

To start a new project:

 

mkdir ProjectName
cd ProjectName
truffle init
npm install zeppelin-solidity

Configuring the network

In truffle.js, add the dev network:

module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
  networks: {
    development: {
    host: "localhost",
    port: 8545,
    network_id: "*", // Match any network id
    gas: 5000000 // give enough gas for contracts 
   }
  }
};

Create the contract

We'll use the same example HelloToken, placed in the
"contracts" folder. Note the different path for the import, and the different compiler version!

pragma solidity ^0.4.19;

import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";

contract HelloToken is StandardToken {

    string public name = "HelloToken";
    string public symbol = "HT";
    uint8 public decimals = 4;
    uint public INITIAL_SUPPLY = 1000 * (10 ** uint(decimals));

    // constructor
    function HelloToken() public {
        totalSupply_ = INITIAL_SUPPLY;
        balances[msg.sender] = INITIAL_SUPPLY;
    }
}

Compile the contract

In the project directory, run:

truffle compile

 

(if you're running Windows, it might try to load truffle.js from the current directory; if so, go to

 

C:\Users\USERNAME\AppData\Roaming\npm

 

and make a copy of truffle.bat to truf.bat or something similar, then use "truf" instead of "truffle).

Deploy the contract

In the project directory, run:

truffle deploy

 

The result should be something like:

E:\TruffleExample>truf migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xeaa8b652d6245a37c4cfcab05aef12aa96c06f0756872ff604ee9a724f1aa2bc
  Migrations: 0x8fc64ca3bf5d7530c1a54493fe0d69444cb70e96
Saving successful migration to network...
  ... 0x1580562d92f3c536ea143537579e21b584a938039bd7b61196fae85e231e39c7
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying HelloToken...
  ... 0x08db67ee2a56ac6d1eff528cd7102d3fabe68c51990803b82535c097e1629fbf
  HelloToken: 0xb6f65e6702539c2ecfe3350bfb362fc565818427
Saving successful migration to network...
  ... 0x9fb54fbe4c870a8fe7c35e1d32561aa4971f84d9fdf4fa6a527fb428f76c9cc3
Saving artifacts...

Contract address

Debugging with Truffle

Useful links

OpenZeppelin

"Zeppelin Solutions" is one of the earliest companies doing smart contracts professionally. Its library "OpenZeppelin" is one of the best and most commonly used for creating smart contracts.

 

https://github.com/OpenZeppelin

 

In the same sense of "don't invent your own cryptography", it is best to use established, tested solutions. There are many pitfalls and unexpected interactions which this library solves.

THE END

ivan.voras@toptal.com

Blockchain lecture #6: Smart Contracts

March 2018

Q&A?

Blockchain lectures #6: Intro to smart contracts

By Ivan Voras

Blockchain lectures #6: Intro to smart contracts

Introduction into smart contract and their relationship to blockchain. High level overview of the major smart contract platforms and where to get started with them. Bit more details about Ethereum virtual machine (EVM) and Solidity.

  • 740