Smart Contracts at ETHereum

Introduction to Solidity

@tomusdrw

Tomasz Drwięga

Parity Technologies

Disclaimer

Any code presented on those slides is here only for educational purposes and is NOT production ready.

The code was not audited or tested properly and most probably doesn't work.

Never use it with real ETH.

Ethereum?

Smart Contracts?

Solidity?

Dan Finlay's Intro to how Ethereum works
https://youtu.be/-SMliFtoPn8

Ethereum

  • Decentralized

  • Trustless

  • Turing-complete
    Execution Platform

Ethereum

  • Decentralized

  • Trustless

  • Turing-complete
    Execution Platform

  • A platform for ICos

Smart Contracts

Nick Szabo, 1994

"A smart contract is a
computerized transaction protocol that executes the terms of a contract.
The general objectives are to satisfy common contractual conditions (such as payment terms, liens, confidentiality, and even enforcement), minimize exceptions both malicious and accidental, and minimize the need for trusted intermediaries.
Related economic goals include lowering fraud loss, arbitrations and enforcement costs, and other transaction costs."

Smart Contracts

A decentralized program that controls money

and acts according to programmed rules without a trusted 3rd party.

Solidity

pragma solidity ^0.4.11;

contract Burn {
    uint256 public value;
    address public owner;
    
    function Burn() payable {
        value = msg.value;
        owner = msg.sender;
    }
}

A high-level "JavaScript-like" contract-oriented language compiled to EVM bytecode.

Compile Program:
Solidity -> EVM

Run Program:
Transactions (ABI + RLP)

Smart Contracts @ Ethereum

pragma solidity ^0.4.11;

contract Parity {
    uint256 public value;
    address public owner;
    
    function export() payable {
        value += msg.value;
        owner = msg.sender;
    }
}
0xc0de15de4d... at 0x123..456
binary at /usr/bin/parity
$ parity export blocks
from:      0x456..def
to:        0x123..456
value:     5 * 10^18 wei (5 ETH)
gas:       100,000
gasPrice:  4 * 10^9 wei (4 shannon)
nonce:     0
data:      0x444...
           ("call function export")


0x123456... (Transaction RLP)

Lock ether

(Forever)

pragma solidity ^0.4.11;

contract Burn {
    uint256 public value;
    address public owner;
    
    function Burn() payable {
        value = msg.value;
        owner = msg.sender;
    }
}

Lock ether

(For some time)

contract Lock {
    uint256 public value;
    address public owner;
    
    function Lock() payable {
        value = msg.value;
        owner = msg.sender;
    }

    function withdraw() {
        if (msg.sender != owner) {
            throw;
        }
        
        msg.sender.transfer(value);
    }
}

Lock ether

(For some time + modifier)

pragma solidity ^0.4.11;

contract Lock {
    uint256 public value;
    address public owner;

    modifier onlyOwner() {
        if (msg.sender != owner) throw;
        _;
    }
    
    function Lock() payable {
        value = msg.value;
        owner = msg.sender;
    }

    function withdraw() onlyOwner {
        msg.sender.transfer(value);
    }
}

Lock ether

(For some predefined time)

contract Lock {
    uint256 public value;
    address public owner;
    uint256 public lockedUntil;

    modifier onlyOwner() {
        if (msg.sender != owner) throw;
        _;
    }
    
    function Lock() payable {
        value = msg.value;
        owner = msg.sender;
        lockedUntil = now + 5 days;
    }

    function withdraw() onlyOwner {
        if (block.timestamp < lockedUntil) {
            throw;
        }
        msg.sender.transfer(value);
    }
}

Ok, but how to develop or run the contracts?

Browser Solidity / Remix

https://ethereum.github.io/browser-solidity/

 

Parity

https://parity.io/parity.html

Title Text

contract Lock {
    struct LockedFunds {
        uint256 value;
        uint256 until;
    }
    
    mapping(address => LockedFunds) public locked;

    function lock() payable {
        locked[msg.sender].value = msg.value;
        locked[msg.sender].until = block.number + 5;
    }
    
    function unlock() {
        var data = locked[msg.sender];
        if (data.value == 0) throw;
        if (block.number < data.until) throw;
        
        delete locked[msg.sender];
        msg.sender.transfer(data.value);
    }
}

MultiLock

(For some predefined time in blocks)

Title Text

contract Lock {
    struct LockedFunds { uint256 value; uint256 until; }
    
    address public owner;
    mapping(address => LockedFunds) public locked;
    
    function Lock() { owner = msg.sender; }

    function lock() payable {
        locked[msg.sender].value = msg.value;
        locked[msg.sender].until = block.number + 5;
    }
    
    function unlock() {
        var data = locked[msg.sender];
        if (data.value == 0) throw;
        if (block.number < data.until) throw;
        
        delete locked[msg.sender];
        msg.sender.transfer(data.value);
    }
    
    function withdraw() {
        if (msg.sender != owner) throw;
        
        owner.transfer(this.balance);
    }
}

MultiLock with fuse

(For some predefined time in blocks)

Multilock

did you spot any bugs in the code?

Title Text

contract Lock {
    struct LockedFunds { uint256 value; uint256 until; }
    
    address public owner;
    mapping(address => LockedFunds) public locked;
    
    function Lock() { owner = msg.sender; }

    function lock() payable {
        // make sure to increment value here otherwise the funds are lost!
        locked[msg.sender].value += msg.value;
        locked[msg.sender].until = block.number + 5;
    }
    function unlock() {
        // copy the structure to memory
        LockedFunds memory data = locked[msg.sender];
        if (data.value == 0) throw;
        if (data.until < block.number) throw;
        
        delete locked[msg.sender];
        msg.sender.transfer(data.value);
    }

    function withdraw() {
        if (msg.sender != owner) throw;

        owner.transfer(this.balance);
    }
}

MultiLock with fuse

(For some predefined time in blocks)

Title Text

contract SimpleToken { // TODO Use SafeMath!
    uint256 constant rate = 1000;
    event Transfer(address indexed _from, address indexed _to, uint _value);
    
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => uint256) public lockTime;

    function buyTokens() payable {
        var tokens = msg.value * rate;
        var unlockAt = block.number + 256 * 24; // 24h

        totalSupply += tokens;
        balanceOf[msg.sender] += tokens;
        lockTime[msg.sender] = unlockAt;
    }
    function burnTokens(uint256 _value) {
        var tokens = _value * rate;
        require(block.number >= lockTime[msg.sender]);
        require(balanceOf[msg.sender] >= tokens);
        
        balanceOf[msg.sender] -= tokens;
        totalSupply -= tokens;
        delete lockTime[msg.sender];
        
        msg.sender.transfer(_value);
    }
    function transfer(address _to, uint _value) returns (bool success) {
        if (block.number < lockTime[msg.sender]) return false;
        if (balanceOf[msg.sender] < _value) return false;
        if (_value == 0 || balanceOf[_to] + _value <= balanceOf[_to]) return false;
        
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
        
        Transfer(msg.sender, _to, _value);
        
        return true;
    }
}

Token Contract

Token Standard (ERC20)

https://theethereum.wiki/w/index.php/ERC20_Token_Standard

// https://github.com/ethereum/EIPs/issues/20
contract ERC20 {
    function totalSupply()
        constant returns (uint totalSupply);
    function balanceOf(address _owner)
        constant returns (uint balance);
    function transfer(address _to, uint _value)
        returns (bool success);
    function transferFrom(address _from, address _to, uint _value)
        returns (bool success);
    function approve(address _spender, uint _value)
        returns (bool success);
    function allowance(address _owner, address _spender)
        constant returns (uint remaining);

    event Transfer(
        address indexed _from, address indexed _to, uint _value
    );
    event Approval(
        address indexed _owner, address indexed _spender, uint _value
    );
}

Questions to Discuss

How much is one token worth?

Does the lock period change anything?

What if you can do something ONLY if you own that token?

Some More Practical Examples?

Designing contracts is designing economic models around them.

"What are the incentives?"

Remote Purchase

Done wrong

contract Purchase {
    uint public value;
    address public seller;
    address public buyer;
   
    function Purchase(uint _value) {
        seller = msg.sender;
        value = _value;
    }

    /// Confirm the purchase as buyer.
    function confirmPurchase() payable {
        require(msg.value == value);
        buyer = msg.sender;
    }
    
    /// Confirm that you (the buyer) received the item.
    function confirmReceived() {
        require(msg.sender == buyer);
        seller.transfer(this.balance);
    }
}

Safe Remote Purchase

(Simplified)

contract Purchase {
    uint public value;
    address public seller;
    address public buyer;
   
    // Seller needs to deposit double the value of the item.
    function Purchase() payable {
        seller = msg.sender;
        value = msg.value / 2;
        require(value * 2 == msg.value);
    }
    
    function abort() {
        require(msg.sender == seller);
        require(buyer == 0);
        seller.transfer(this.balance);
    }

    /// Confirm the purchase as buyer. Deposit double the value of the item.
    function confirmPurchase() payable {
        require(msg.value == 2 * value);
        buyer = msg.sender;
    }
    
    /// Confirm that you (the buyer) received the item.
    function confirmReceived() {
        require(msg.sender == buyer);
        buyer.transfer(value); // transfer half of the deposit
        seller.transfer(this.balance); // transfer the entire deposit
        delete value;
    }
}

Simple Auction

Done slightly wrong

contract Auction {
    address public beneficiary;
    uint public endBlock;
    bool public ended;

    address public highestBidder;
    uint public highestBid;
    mapping(address => uint) pendingReturns;
   
    function Auction(uint _time) {
        beneficiary = msg.sender; endBlock = block.number + _time;
    }

    function bid() payable {
        require(block.number < endBlock);
        require(highestBid < msg.value);
        if (highestBidder != 0) { pendingReturns[highestBidder] += highestBid; }
        highestBidder = msg.sender;
        highestBid = msg.value;
    }
    
    function endAuction() {
        require(endBlock <= block.number);
        require(!ended);
        ended = true;
        beneficiary.transfer(highestBid);
    }
    
    function withdraw() {
        uint amount = pendingReturns[msg.sender];
        delete pendingReturns[msg.sender];
        msg.sender.transfer(amount);
    }
}

Why is it wrong?

Because Auction Theory

https://en.wikipedia.org/wiki/Auction_theory

"There are many possible designs for an auction and typical issues studied by auction theorists include the efficiency of a given auction design, optimal and equilibrium bidding strategies, and revenue comparison."

Solution?

Blind Auction

https://en.wikipedia.org/wiki/Auction#Primary
https://en.wikipedia.org/wiki/Commitment_scheme

"In this type of auction all bidders simultaneously submit sealed bids so that no bidder knows the bid of any other participant. The highest bidder pays the price they submitted."

address public beneficiary;
uint public bidEndBlock;
uint public revealEndBlock;
bool public ended;

address public highestBidder;
uint public highestBid;
mapping(address => uint) pendingReturns;
mapping(address => bytes32) bids;
mapping(address => uint) deposits;
   
function Auction(uint _time) {
    beneficiary = msg.sender;
    bidEndBlock = block.number + _time;
    revealEndBlock = bidEndBlock + _time;
}
function bid(bytes32 _blindedBid) payable {
    require(block.number < bidEndBlock);
    bids[msg.sender] = _blindedBid;
    deposits[msg.sender] = msg.value;
}
function endAuction() {
    require(revealEndBlock <= block.number);
    require(!ended);
    ended = true;
    beneficiary.transfer(highestBid);
}
function withdraw() {
    uint amount = pendingReturns[msg.sender];
    delete pendingReturns[msg.sender];
    msg.sender.transfer(amount);
}
function reveal(bytes32 _secret, uint _value) {
    require(bidEndBlock <= block.number);
    require(block.number < revealEndBlock);
    require(deposits[msg.sender] > _value);
    require(
        bids[msg.sender] == keccak256(_value, _secret)
    );
    
    var isHighest = placeBid(msg.sender, _value);
    var deposit = deposits[msg.sender];
    
    delete bids[msg.sender];
    delete deposits[msg.sender];
    
    if (!isHighest) {
        msg.sender.transfer(deposit);
    } else {
        msg.sender.transfer(deposit - _value);
    }
}

function placeBid(address _bidder, uint _value) 
    internal returns (bool success)
{
    if (highestBid < _value) return false;
    if (highestBidder != 0) pendingReturns[highestBidder] += highestBid;
    highestBidder = _bidder;
    highestBid = _value;
    return true;
}

Blind auction (simplified)

Smart Contracts

  • Unit Testing
  • Debugging
  • Formal Verification
  • Static Analysis
  • Tooling (IDEs, Visualisation)

Ecosystem

Smart Contracts

  • Unit Testing
    Only via Transactions (tests usually in JS)
  • Debugging
    Remix (EVM debugging)
  • Formal Verification
    Research ongoing (and it's hard)
  • Static Analysis
    Solidity compiler warnings
  • Tooling (IDEs, Visualisation)
    Syntax highlighting for major editors

Ecosystem

In short: IT SUCKS! Please contribute!

Inspired to write some contracts?

Learn Game Theory basics first.

 

And please read this:

"Building a Fun Ethereum Game" by Conrad Barski

http://www.cointagion.com/2016/08/24/part-i/

References

  • Dan Finlay's Intro to how Ethereum works https://youtu.be/-SMliFtoPn8
  • Solidity docs https://solidity.readthedocs.io
  • ERC20 https://theethereum.wiki/w/index.php/ERC20_Token_Standard
  • Browser Solidity / Remix https://ethereum.github.io/browser-solidity/
  • Parity https://github.com/paritytech/parity
  • Safe Remote Purchase http://solidity.readthedocs.io/en/develop/solidity-by-example.html#safe-remote-purchase
  • Auction Theory https://en.wikipedia.org/wiki/Auction_theory
  • Game Theory https://en.wikipedia.org/wiki/Game_theory
  • Commitment Scheme https://en.wikipedia.org/wiki/Commitment_scheme

  • Building a Fun Ethereum Game http://www.cointagion.com/2016/08/24/part-i/

some other features of Solidity

That were not covered here

  • Libraries
  • Inheritance
  • Calling other contracts
  • Memory
  • Encapsulation (visibility modifiers)

https://www.meetup.com/Wroclaw-Blockchain-Meetup/

Tuesday, 27th June 2017

Intro to Solidity

By Tomasz Drwięga

Intro to Solidity

  • 895