Dapps Development Intro

Tomasz Drwięga
@tomusdrw

http://tomusdrw.github.io/parity-dapp-example

http://localhost:8080/d39f5f496d13282fe84d95299c4a00b929eb49183e773840b857c1167c094599/

How to get Parity?

  • https://github.com/ethcore/parity/releases
  • https://ethcore.io
  • git clone https://github.com/ethcore/parity.git

Let's start!

# Check parity version
$ parity --version
2016-11-26 20:09:42  main INFO parity  Parity
  version Parity/v1.5.0-unstable-6d6a2a8-20161124/x86_64-linux-gnu/rustc1.13.0

# Run Parity and connect to new Testnet
$ parity ui --chain ropsten

# `ui` command should open the browser for you

Types of applications

  • Builtins - shiped with Parity
  • Local - on your file system
  • Network - fetched from the network

How to create a local dapp?

# Go to Dapps location
$ cd ~/.parity/dapps/

# Create a new directory...
$ mkdir my-dapp

# ... and index.html file
$ echo "<h1>Hello World!</h1>" > my-dapp/index.html

# (restart Parity)

$ open http://localhost:8080/my-dapp/

Let's do some RPC calls

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>My First Dapp</title>
    <!-- Import parity.js -->
    <script src="/parity-utils/parity.js"></script>
    <!-- Import web3.js -->
    <script src="/parity-utils/web3.js"></script>

    <!-- or fire RPC calls to `/rpc/` with your favourite library -->
  </head>
  <body>
    <h1>Hello World</h1>
    <script>
        window.web3.eth.getAccounts((err, accounts) => {
            console.log(accounts);
        });

        window.parity.api.eth.accounts()
            .then(accounts => {
                console.log(accounts);
            });
    </script>
  </body>
</html>

Why did we make parity.js?

  • Promise-based
  • No sync requests
  • More modular
  • Less "magic" (no conversions)
  • Easier to maintain/extend

React

# Install create-react-app
$ npm install create-react-app -g # sudo?

# Start React app
$ create-react-app react-app

# Start a development server
$ cd react-app
$ npm start

Add the proxy

{
  "name": "react-dapp",
  "version": "0.1.0",
  "private": true,
  "devDependencies": {
    "react-scripts": "0.7.0"
  },
  "proxy": "http://localhost:8080",
  "dependencies": {
    "react": "^15.4.1",
    "react-dom": "^15.4.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

Icon?

# Create icon.png file
$ curl \
    https://raw.githubusercontent.com/tomusdrw/eth.wallet/master/icon.png \
    -O ~/.parity/my-dapp/icon.png

Name and description?

# ~/.parity/dapps/my-dapp/manifest.json
{
  "id": "my-dapp",
  "name": "My Dapp",
  "description": "My First Parity Dapp",
  "version": "0.0.1",
  "author": "todr <[email protected]>",
  "iconUrl": "icon.png"
}

Making the dapp public.

  • Push to Github
  • Register Content
  • Add to DappReg

Get some Ropsten eth from:

http://icarus.parity.io/make_it_rain/<address>

Parity fetchable content

http://localhost:8080/99506fde795f7faeb5706a16742813ed7ee0d17f7ae67bf1c210023475d8969e/

Registration

  • Register your Dapp as "Content Bundle"
    • Use your Github slug
    • Use specific commit hash
  • Register your icon as "File Link" 
  • Register your manifest as "File Link"

You can now access the dapp using hash of content bundle!

Make your dapp discoverable

# DappRegistry dapp is currently in development
# and was not released yet.
# We need to get the bleeding edge UI for this:)

# Start Parity in UI-development mode
$ parity --chain ropsten --ui-no-validation

# Clone Parity repo
$ git clone https://github.com/ethcore/parity.git

# Run UI
$ cd parity/js
$ npm i
$ npm start

Look for "Dapp Registration"

(click "Edit" if it's not visible)

Make your dapp discoverable

Manual approach

// Watch contract (Ropsten)
0x724A8602fc0C2b346f8eC56Df2913710742d3fD0

// ABI
[{"constant":true,"inputs":[{"name":"_id","type":"bytes32"},{"name":"_key","type":"bytes32"}],"name":"meta","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"count","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"bytes32"}],"name":"unregister","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"bytes32"}],"name":"get","outputs":[{"name":"id","type":"bytes32"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"bytes32"},{"name":"_key","type":"bytes32"},{"name":"_value","type":"bytes32"}],"name":"setMeta","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"bytes32"},{"name":"_owner","type":"address"}],"name":"setDappOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"at","outputs":[{"name":"id","type":"bytes32"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"bytes32"}],"name":"register","outputs":[],"payable":true,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"bytes32"},{"indexed":true,"name":"key","type":"bytes32"},{"indexed":false,"name":"value","type":"bytes32"}],"name":"MetaChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"bytes32"},{"indexed":true,"name":"owner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"bytes32"},{"indexed":true,"name":"owner","type":"address"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"bytes32"}],"name":"Unregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]

// Register new ID
register(sha3("App name"))

// Register manifest and icon
setMeta(sha3("App name"), asHex("MANIFEST"), <manifest hash>)
setMeta(sha3("App name"), asHex("IMG"), <icon hash>)

// Register content
setMeta(sha3("App name"), asHex("CONTENT"), <content bundle hash>)

Now your turn!

  1. Task 1: Create Local Dapp
    1. Basic
      1. Display latest block number
      2. Display number of transactions in last 5 blocks
      3. Display sum and avg of value transfered (last 5 blocks)
    2. Advanced
      1. Display transactions from local queue
        (see api.parity.pendingTransactions())
      2. Display data from DappRegistry
        (interact with contract)
    3. Extra
      1. Use React (create-react-app)
  2. Task 2: Icon and Manifest
    1. Add Icon and Manifest and register as "File Link"
  3. Task 3: Publish Dapp
    1. Publish to Github and register as "Content Bundle"
  4. Task 4: Add to the Reg
    1. Make your dapp visible on Parity's home screen

Useful links

  • Dapp Example
    https://github.com/tomusdrw/parity-dapp-example
  • Writing Dapps
    https://github.com/ethcore/parity/wiki/Writing-Dapps-for-Parity
  • Dapps Registry
    https://github.com/ethcore/parity/wiki/Parity-dapp-registry