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 <tomasz@ethcore.io>",
"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!
- Task 1: Create Local Dapp
- Basic
- Display latest block number
- Display number of transactions in last 5 blocks
- Display sum and avg of value transfered (last 5 blocks)
- Advanced
- Display transactions from local queue
(see api.parity.pendingTransactions()) - Display data from DappRegistry
(interact with contract)
- Display transactions from local queue
- Extra
- Use React (create-react-app)
- Basic
- Task 2: Icon and Manifest
- Add Icon and Manifest and register as "File Link"
- Task 3: Publish Dapp
- Publish to Github and register as "Content Bundle"
- Task 4: Add to the Reg
- 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
Parity Dapps
By Tomasz Drwięga
Parity Dapps
- 835