Dapps Development Intro
Tomasz Drwięga
@tomusdrw
http://tomusdrw.github.io/parity-dapp-example
http://localhost:8080/d39f5f496d13282fe84d95299c4a00b929eb49183e773840b857c1167c094599/
# 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
# 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/
<!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>
# 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
{
"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"
}
}
# Create icon.png file
$ curl \
https://raw.githubusercontent.com/tomusdrw/eth.wallet/master/icon.png \
-O ~/.parity/my-dapp/icon.png
# ~/.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"
}
Get some Ropsten eth from:
http://icarus.parity.io/make_it_rain/<address>
http://localhost:8080/99506fde795f7faeb5706a16742813ed7ee0d17f7ae67bf1c210023475d8969e/
You can now access the dapp using hash of content bundle!
# 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)
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>)