Initial new UI source code import (#2607)

* address -> name mappings

* expanding, loading all coin details

* send use only actual BasicCoin tokens registered (any reg)

* sending token & accounts

* form styling updates

* send form layout in place

* coin send working as expected

* api subscriptions on multiple addresses

* bring in events

* simplify

* basic events display in-place, functionally complete

* basic functionality in-place

* fix horrible event address issue

* rwork display of events slightly

* test TLA availability

* table for owner -> tokens

* fix signature lookup address

* fix signature lookup address

* basic overview styling

* txhash links

* page layout adjustments

* background import

* adjust colors

* no global registration, simplify color selection

* updated styling

* connection dialog for "busy connecting"

* initial token connection - WIP

* init token updates take place

* basic test for manual token

* rework connection display

* allow updates of the secure token

* first stab at making the build build

* update runner tags

* fix linting issues

* skip tests requiring network (should be e2e, TODO)

* re-enable javascript tag/runner

* release push does the trick

* push to any branch, CI name

* javscript-test runner as well

* swap dependencies build requires test

* revert stages swap

* retrieve images associated with tokens

* remove js build deps order

* null image when hash = 0x0

* 6x64 images (hashes for registries)

* don't pass tokens as prop to IdentityIcon

* check images against content hash pictures

* cleanup signer after connection changes

* fix naming typo

* display unknownImages for balances (not available as content hash)

* unknownImage for transfer dialog

* basic githubhint layout

* single input for commit/filename

* ethcore_hashContent call

* lookup hash

* registration in place

* fixes

* events is using a proper table

* pass value through as-is

* stop wrongly using main app IdentityIcon

* NEVER export class instance functions

* alignment back to normal

* typo  in definition

* set & get images working (mostly)

* show content retrieval info

* set exitcode via ||

* use javascript:latest images

* disable npm progress bar

* rename phase I

* rename phase II

* only send build output to GitHub on major branches

* also run the build step as part of the test (until comprehensive)

* ci-specific build (no webpack progress)

* allow for account creation via recovery phrase

* display account uuid (where available), closes #2546

* connection dialog now shows up in dapps as well, closes #2538

* token images show up as expected

* IdentityName component added and deployed

* fix padding tests

* adjust tests to map to stricter 0x-prefixed hex

* render names via common component for the address -> name

* split lint into seperate script (early exit)

* test phases changed to lint, test & pack

* pack part of test phase

* remove files marked for deletion (cleanup)

* Signer cleanups, start moving in the direction of the rest

* add personal signer methods

* basic signer request subscription

* don't poll blockNumber when not connected

* missing return, creating massive ws queue backlogs

* ΞTH -> ETH

* fix failing tests

* registry uses setAddress to actually set addresses now

* bytes mapping operates on lowerCase hex strings

* sha3 ids for each application

* add dappreg to list of contracts

* adjust alignment of queries

* show gas estimation log

* abi with payable for register function

* add key as required

* image retrieval from dappreg

* use proper Image urls

* embed and link apps from Parity, retrieved via /api/apps

* filter apps that has been replaced

* proxy entry for parity-utils

* add basiccoin abi

* add support for fallback abi type

* capture constructor paramaters

* merge master into js

* move images to assets/images/

* add font assets

* import fonts as part of build

* don't inline woff files

* Revert "merge master into js"

This reverts commit cfcfa81bd26f1b3cbc748d3afa1eb5c670b363fe.

* remove unused npm packages

* information on gas estimates (like almost everywhere else)

* don't pass gas & gasPrice to estimation

* display account passwordhint when available

* signer subscriptions based on polling & function trapping

* pending requests retrieved via jsapi

* update signer middleware

* remove all web3 instances

* remove web3 package

* last web3 dependencies removed

* no need to toChecksumAddress - api takes care of it

* expand description for personal_confirmRequest

* Signer conversion from web3 -> parity.js completed

* explicit in no return

* green circle background

* remove generated background

* convert /api/* paths to localhost:8080/api/* paths (hard-coded, temporary)

* change dapps to load from localhost:8080/ui/*

* remove dangling web3 files

* update manager test for signer

* /api/ping -> /

* additional token images

* additional token images

* add missing styles.css for 8180 error pages

* cater for txhash returning null/empty object

* adjust output directories

* Release merge with origin with ours strategy

* additional token images

* cater for development server

* s/localhost/127.0.0.1/ (cater for origin)

* Fix address selection for contract deployment

* Adjust z-index for error overlay

* better text on unique background pattern

* fix signer rejections

* Don't allow gavcoin transfer with no balance

* fix txhash rendering in signer

* remove unnecessary ParityBackground

* script to update js-precompiled

* Redirect from :8080 to :8180

* Remove extra return

* Dapp logo images
This commit is contained in:
Jaco Greeff
2016-10-18 11:52:56 +02:00
committed by Gav Wood
parent 6c7af57529
commit 1e6a2cb378
969 changed files with 57315 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Basic Token Deployment</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="parity.js"></script>
<script src="basiccoin.js"></script>
</body>
</html>

47
js/src/dapps/basiccoin.js Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import ReactDOM from 'react-dom';
import React from 'react';
import { createHashHistory } from 'history';
import { Redirect, Router, Route, useRouterHistory } from 'react-router';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
import Deploy from './basiccoin/Deploy';
import Application from './basiccoin/Application';
import Overview from './basiccoin/Overview';
import Transfer from './basiccoin/Transfer';
const routerHistory = useRouterHistory(createHashHistory)({});
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './basiccoin.html';
ReactDOM.render(
<Router history={ routerHistory }>
<Redirect from='/' to='/overview' />
<Route path='/' component={ Application }>
<Route path='deploy' component={ Deploy } />
<Route path='overview' component={ Overview } />
<Route path='transfer' component={ Transfer } />
</Route>
</Router>,
document.querySelector('#container')
);

View File

@@ -0,0 +1,23 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.iconMenu {
}
.iconMenu option {
padding-left: 30px;
}

View File

@@ -0,0 +1,93 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { api } from '../parity';
import styles from './addressSelect.css';
export default class AddressSelect extends Component {
static contextTypes = {
accounts: PropTypes.object.isRequired
}
static propTypes = {
addresses: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired
}
state = {
selected: null
}
componentDidMount () {
const { addresses } = this.props;
this.onChange({
target: {
value: addresses[0]
}
});
}
componentWillReceiveProps (newProps) {
const { addresses } = this.props;
let changed = addresses.length !== newProps.addresses.length;
if (!changed) {
changed = addresses.filter((address, index) => newProps.addresses[index] !== address).length;
}
if (changed) {
this.onChange({ target: { value: newProps.addresses[0] } });
}
}
render () {
const { addresses } = this.props;
const { selectedAddress } = this.state;
const style = {
background: `rgba(255, 255, 255, 0.75) url(${api.util.createIdentityImg(selectedAddress, 3)}) no-repeat 98% center`
};
return (
<select
className={ styles.iconMenu }
style={ style }
onChange={ this.onChange }>
{ addresses.map(this.renderOption) }
</select>
);
}
renderOption = (address) => {
const { accounts } = this.context;
const account = accounts[address];
return (
<option
key={ account.address }
value={ account.address }>
{ account.name }
</option>
);
}
onChange = (event) => {
this.setState({ selectedAddress: event.target.value });
this.props.onChange(event);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './addressSelect';

View File

@@ -0,0 +1,71 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.header {
}
.titlebar {
padding: 0.5em 1em;
margin: 0;
color: white;
}
.navigation {
table-layout: fixed;
width: 100%;
border-spacing: 0.25em;
border-collapse: separate;
border-color: white;
background: white;
}
.navigation tr {
height: 10em;
}
.title {
font-size: 1.25em;
margin-bottom: 0.25em;
}
.byline {
font-size: 1em;
opacity: 0.75;
margin-bottom: 0.25em;
}
.description {
font-size: 0.5em;
opacity: 0.5;
line-height: 1.5em;
}
.navNext,
.navCurrent {
color: white;
padding: 1em 2em;
vertical-align: middle;
}
.navNext:hover {
cursor: pointer;
opacity: 0.8;
}
.navCurrent {
font-size: 2em;
}

View File

@@ -0,0 +1,80 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import PAGES from '../pages';
import styles from './header.css';
export default class Header extends Component {
static contextTypes = {
router: PropTypes.object.isRequired
}
render () {
const path = (window.location.hash || '').split('?')[0].split('/')[1];
const offset = PAGES.findIndex((header) => header.path === path);
return (
<div className={ styles.header }>
<table className={ styles.navigation }>
<tbody>
<tr>
{ this.renderHeader(0, offset) }
{ this.renderHeader(1, offset) }
</tr>
<tr>
{ this.renderHeader(2, offset) }
</tr>
</tbody>
</table>
</div>
);
}
renderHeader (position, offset) {
const index = (position + offset) % PAGES.length;
const page = PAGES[index];
const background = `rgba(102, 34, 34, ${1 - (0.1 * position)})`;
return (
<td
className={ position ? styles.navNext : styles.navCurrent }
style={ { background } }
colSpan={ position ? 1 : 2 }
rowSpan={ position ? 1 : 2 }
onClick={ this.onNavigate(page.path) }>
<div className={ styles.title }>
{ page.title }
</div>
<div className={ styles.byline }>
{ page.byline }
</div>
<div className={ styles.description }>
{ position ? null : page.description }
</div>
</td>
);
}
onNavigate = (route) => {
const { router } = this.context;
return (event) => {
router.push(`/${route}`);
};
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './header';

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './loading';

View File

@@ -0,0 +1,24 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.body {
width: 100%;
text-align: center;
padding-top: 5em;
font-size: 2em;
color: #999;
}

View File

@@ -0,0 +1,29 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react';
import styles from './loading.css';
export default class Loading extends Component {
render () {
return (
<div className={ styles.body }>
Attaching to contract ...
</div>
);
}
}

View File

@@ -0,0 +1,28 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.container {
color: #444;
font-family: 'Roboto';
vertical-align: middle;
min-height: 100vh;
position:relative;
}
.body {
padding: 0 0.25em;
}

View File

@@ -0,0 +1,107 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { api } from '../parity';
import { attachInstances } from '../services';
import Header from './Header';
import Loading from './Loading';
import styles from './application.css';
export default class Application extends Component {
static childContextTypes = {
accounts: PropTypes.object,
managerInstance: PropTypes.object,
registryInstance: PropTypes.object,
tokenregInstance: PropTypes.object
}
static propTypes = {
children: PropTypes.node.isRequired
}
state = {
accounts: null,
loading: true,
managerInstance: null,
registryInstance: null,
tokenregInstance: null
}
componentDidMount () {
this.attachInstance();
}
render () {
const { children } = this.props;
const { loading } = this.state;
if (loading) {
return (
<Loading />
);
}
return (
<div className={ styles.container }>
<Header />
<div className={ styles.body }>
{ children }
</div>
</div>
);
}
getChildContext () {
const { accounts, managerInstance, registryInstance, tokenregInstance } = this.state;
return {
accounts,
managerInstance,
registryInstance,
tokenregInstance
};
}
attachInstance () {
Promise
.all([
attachInstances(),
api.personal.accountsInfo()
])
.then(([{ managerInstance, registryInstance, tokenregInstance }, accountsInfo]) => {
this.setState({
loading: false,
managerInstance,
registryInstance,
tokenregInstance,
accounts: Object
.keys(accountsInfo)
.filter((address) => !accountsInfo[address].meta.deleted)
.sort((a, b) => {
return (accountsInfo[b].uuid || '').localeCompare(accountsInfo[a].uuid || '');
})
.reduce((accounts, address) => {
accounts[address] = Object.assign(accountsInfo[address], { address });
return accounts;
}, {})
});
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './application';

View File

@@ -0,0 +1,38 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
const PAGES = [
{
path: 'overview',
title: 'Overview',
byline: 'Display all the current information relating to your own deployed tokens',
description: 'View the total number of tokens in circulation, the number of different tokens associated with your accounts as well as the types of tokens created by you. In addition view the balances associated with your accounts in reltion to the total in circulation.'
},
{
path: 'transfer',
title: 'Transfer',
byline: 'Send tokens associated with your accounts to other addresses',
description: 'Send any tokens created byt you or received from others. In addition have a bird\'s eye view of all events relating to token transfers, be it yours, created byt others, either local or globally available on the network.'
},
{
path: 'deploy',
title: 'Deploy',
byline: 'Deploy a new token to the network',
description: 'Token registration has never been this easy. Select the name for your token, the TLA and the number of tokens in circulation. Start sending the tokens to contacts right from this interface. Optionally you can register the token with the Token Registry which would allow you to transaction in tokens from anywhere these transactions are allowed.'
}
];
export default PAGES;

View File

@@ -0,0 +1,26 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.content {
padding: 4em;
margin-bottom: 0.25em;
text-align: center;
}
.content:nth-child(odd) {
background: rgba(102, 34, 34, 0.075);
}

View File

@@ -0,0 +1,37 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import styles from './container.css';
export default class Container extends Component {
static propTypes = {
className: PropTypes.string,
children: PropTypes.node.isRequired
}
render () {
const { className, children } = this.props;
const classes = `${styles.content} ${className}`;
return (
<div className={ classes }>
{ children }
</div>
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './container';

View File

@@ -0,0 +1,19 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
@import '../../_form.css';
@import '../../_status.css';

View File

@@ -0,0 +1,320 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { api } from '../../parity';
import AddressSelect from '../../AddressSelect';
import Container from '../../Container';
import styles from './deployment.css';
const ERRORS = {
name: 'specify a valid name >2 & <32 characters',
tla: 'specify a valid TLA, 3 characters in length',
usedtla: 'the TLA used is not available for registration',
supply: 'supply needs to be valid >999 & <1 trillion'
};
export default class Deployment extends Component {
static contextTypes = {
accounts: PropTypes.object.isRequired,
router: PropTypes.object.isRequired,
managerInstance: PropTypes.object.isRequired,
registryInstance: PropTypes.object.isRequired,
tokenregInstance: PropTypes.object.isRequired
}
state = {
base: null,
deployBusy: false,
deployDone: false,
deployError: null,
deployState: null,
globalReg: false,
globalFee: 0,
globalFeeText: '1.000',
fromAddress: null,
name: '',
nameError: ERRORS.name,
tla: '',
tlaError: ERRORS.tla,
totalSupply: '5000000',
totalSupplyError: null,
signerRequestId: null,
txHash: null
}
componentDidMount () {
const { managerInstance, tokenregInstance } = this.context;
Promise
.all([
managerInstance.base.call(),
tokenregInstance.fee.call()
])
.then(([base, globalFee]) => {
this.setState({
base,
baseText: base.toFormat(0),
globalFee,
globalFeeText: api.util.fromWei(globalFee).toFormat(3)
});
});
}
render () {
const { deployBusy } = this.state;
return deployBusy
? this.renderDeploying()
: this.renderForm();
}
renderDeploying () {
const { deployDone, deployError, deployState } = this.state;
if (deployDone) {
return (
<Container>
<div className={ styles.statusHeader }>
Your token has been deployed
</div>
</Container>
);
}
if (deployError) {
return (
<Container>
<div className={ styles.statusHeader }>
Your deployment has encountered an error
</div>
<div className={ styles.statusError }>
{ deployError }
</div>
</Container>
);
}
return (
<Container>
<div className={ styles.statusHeader }>
Your token is currently being deployed to the network
</div>
<div className={ styles.statusState }>
{ deployState }
</div>
</Container>
);
}
renderForm () {
const { accounts } = this.context;
const { baseText, name, nameError, tla, tlaError, totalSupply, totalSupplyError } = this.state;
const hasError = !!(nameError || tlaError || totalSupplyError);
const error = `${styles.input} ${styles.error}`;
const addresses = Object.keys(accounts).filter((address) => accounts[address].uuid);
// <div className={ styles.input }>
// <label>global registration</label>
// <select onChange={ this.onChangeRegistrar }>
// <option value='no'>No, only for me</option>
// <option value='yes'>Yes, for everybody</option>
// </select>
// <div className={ styles.hint }>
// register on network (fee: { globalFeeText }ETH)
// </div>
// </div>
return (
<Container>
<div className={ styles.form }>
<div className={ styles.input }>
<label>deployment account</label>
<AddressSelect
addresses={ addresses }
onChange={ this.onChangeFrom } />
<div className={ styles.hint }>
the owner account to eploy from
</div>
</div>
<div className={ nameError ? error : styles.input }>
<label>token name</label>
<input
value={ name }
name='name'
onChange={ this.onChangeName } />
<div className={ styles.hint }>
{ nameError || 'an identifying name for the token' }
</div>
</div>
<div className={ tlaError ? error : styles.input }>
<label>token TLA</label>
<input
className={ styles.small }
name='tla'
value={ tla }
onChange={ this.onChangeTla } />
<div className={ styles.hint }>
{ tlaError || 'unique network acronym for this token' }
</div>
</div>
<div className={ totalSupplyError ? error : styles.input }>
<label>token supply</label>
<input
type='number'
min='1000'
max='999999999999'
name='totalSupply'
value={ totalSupply }
onChange={ this.onChangeSupply } />
<div className={ styles.hint }>
{ totalSupplyError || `number of tokens (base: ${baseText})` }
</div>
</div>
<div className={ styles.input }>
<label />
<div className={ styles.buttonRow }>
<div
className={ styles.button }
disabled={ hasError }
onClick={ this.onDeploy }>
Deploy Token
</div>
</div>
</div>
</div>
</Container>
);
}
onChangeFrom = (event) => {
const fromAddress = event.target.value;
this.setState({ fromAddress });
}
onChangeName = (event) => {
const name = event.target.value;
const nameError = name && (name.length > 2) && (name.length < 32)
? null
: ERRORS.name;
this.setState({ name, nameError });
}
onChangeRegistrar = (event) => {
this.setState({ globalReg: event.target.value === 'yes' }, this.testTlaAvailability);
}
onChangeSupply = (event) => {
const totalSupply = parseInt(event.target.value, 10);
const totalSupplyError = isFinite(totalSupply) && totalSupply > 999
? null
: ERRORS.supply;
this.setState({ totalSupply, totalSupplyError });
}
onChangeTla = (event) => {
const _tla = event.target.value;
const tla = _tla && (_tla.length > 3)
? _tla.substr(0, 3)
: _tla;
const tlaError = tla && (tla.length === 3)
? null
: ERRORS.tla;
this.setState({ tla, tlaError }, this.testTlaAvailability);
}
testTlaAvailability = () => {
const { registryInstance, tokenregInstance } = this.context;
const { globalReg, tla, tlaError } = this.state;
const tokenreg = globalReg ? tokenregInstance : registryInstance;
if (tlaError && tlaError !== ERRORS.usedtla) {
return;
}
tokenreg
.fromTLA.call({}, [tla])
.then(([id, addr, base, name, owner]) => {
if (owner !== '0x0000000000000000000000000000000000000000') {
this.setState({ tlaError: ERRORS.usedtla });
} else if (tlaError === ERRORS.usedtla) {
this.setState({ tlaError: null });
}
})
.catch((error) => {
console.log('testTlaAvailability', error);
});
}
onDeploy = () => {
const { managerInstance, registryInstance, tokenregInstance } = this.context;
const { base, deployBusy, fromAddress, globalReg, globalFee, name, nameError, tla, tlaError, totalSupply, totalSupplyError } = this.state;
const hasError = !!(nameError || tlaError || totalSupplyError);
if (hasError || deployBusy) {
return;
}
const tokenreg = (globalReg ? tokenregInstance : registryInstance).address;
const values = [base.mul(totalSupply), tla, name, tokenreg];
const options = {
from: fromAddress,
value: globalReg ? globalFee : 0
};
this.setState({ deployBusy: true, deployState: 'Estimating gas for the transaction' });
managerInstance
.deploy.estimateGas(options, values)
.then((gas) => {
this.setState({ deployState: 'Gas estimated, Posting transaction to the network' });
const gasPassed = gas.mul(1.2);
options.gas = gasPassed.toFixed(0);
console.log(`gas estimated at ${gas.toFormat(0)}, passing ${gasPassed.toFormat(0)}`);
return managerInstance.deploy.postTransaction(options, values);
})
.then((signerRequestId) => {
this.setState({ signerRequestId, deployState: 'Transaction posted, Waiting for transaction authorization' });
return api.pollMethod('eth_checkRequest', signerRequestId);
})
.then((txHash) => {
this.setState({ txHash, deployState: 'Transaction authorized, Waiting for network confirmations' });
return api.pollMethod('eth_getTransactionReceipt', txHash, (receipt) => {
if (!receipt || !receipt.blockNumber || receipt.blockNumber.eq(0)) {
return false;
}
return true;
});
})
.then((txReceipt) => {
this.setState({ txReceipt, deployDone: true, deployState: 'Network confirmed, Received transaction receipt' });
})
.catch((error) => {
console.error('onDeploy', error);
this.setState({ deployError: error.message });
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './deployment';

View File

@@ -0,0 +1,58 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
a.link, a.link:visited {
text-decoration: none;
}
a.link:hover {
text-decoration: underline;
}
a.link, a.link:hover, a.link:visited {
color: #822;
cursor: pointer;
}
.mined {
}
.pending {
opacity: 0.5;
}
.mined td,
.pending td {
padding: 0.5em 1em;
line-height: 24px;
}
.blocknumber {
text-align: right;
}
.address {
text-align: left;
}
.description {
text-align: left;
}
.center {
text-align: right;
}

View File

@@ -0,0 +1,103 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import moment from 'moment';
import React, { Component, PropTypes } from 'react';
import { api } from '../../parity';
import { getCoin, txLink } from '../../services';
import IdentityIcon from '../../IdentityIcon';
import styles from './event.css';
export default class Event extends Component {
static contextTypes = {
accounts: PropTypes.object.isRequired,
registryInstance: PropTypes.object.isRequired,
tokenregInstance: PropTypes.object.isRequired
}
static propTypes = {
event: PropTypes.object.isRequired
}
state = {
block: null,
coin: {}
}
componentDidMount () {
this.lookup();
}
render () {
const { event } = this.props;
const { block, coin } = this.state;
const isPending = event.type === 'pending';
return (
<tr className={ isPending ? styles.pending : styles.mined }>
<td className={ styles.blocknumber }>
<div>{ (isPending || !block) ? '' : moment(block.timestamp).fromNow() }</div>
<div>{ isPending ? 'Pending' : event.blockNumber.toFormat() }</div>
</td>
<td>{ event.event }</td>
<td className={ styles.description }>
<div>{ isPending ? '' : coin.tla }</div>
<div>{ isPending ? '' : coin.name }</div>
</td>
<td className={ styles.address }>
{ this.renderAddress(event.params.owner) }
<div><a href={ txLink(event.transactionHash) } target='_blank' className={ styles.link }>{ this.renderHash(event.transactionHash) }</a></div>
</td>
<td>{ isPending || !coin.isGlobal ? '' : 'global' }</td>
</tr>
);
}
renderAddress (address) {
const { accounts } = this.context;
const account = accounts[address];
return (
<div>
<IdentityIcon address={ address } />
<span>{ account ? account.name : address }</span>
</div>
);
}
renderHash (hash) {
return `${hash.substr(0, 10)}...${hash.slice(-10)}`;
}
lookup () {
const { event } = this.props;
if (event.type === 'pending') {
return;
}
Promise
.all([
api.eth.getBlockByNumber(event.blockNumber),
getCoin(event.params.tokenreg, event.params.coin)
])
.then(([block, coin]) => {
this.setState({ block, coin });
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './event';

View File

@@ -0,0 +1,33 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.statusHeader {
font-size: 1.25em;
}
.eventList {
border: none;
margin: 0 auto;
border-collapse: collapse;
}
.eventList tr:nth-child(even) {
background: rgba(102, 34, 34, 0.075);
}
.eventList tr:nth-child(odd) {
}

View File

@@ -0,0 +1,141 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { api } from '../../parity';
import Container from '../../Container';
import Event from '../Event';
import styles from './events.css';
export default class Events extends Component {
static contextTypes = {
managerInstance: PropTypes.object.isRequired
}
state = {
blocks: {},
loading: true,
events: [],
minedEvents: [],
pendingEvents: []
}
componentDidMount () {
const { managerInstance } = this.context;
const options = {
fromBlock: 0,
toBlock: 'pending',
limit: 50
};
managerInstance.Created
.subscribe(options, this.receiveCreatedEvents)
.then((subscriptionIdCreated) => {
this.setState({ subscriptionIdCreated });
});
}
componentWillUnmount () {
const { managerInstance } = this.context;
const { subscriptionIdCreated } = this.state;
managerInstance.Created.unsubscribe(subscriptionIdCreated);
}
render () {
const { loading } = this.state;
return (
<Container>
{ loading ? this.renderLoading() : this.renderEvents() }
</Container>
);
}
renderEvents () {
const { events } = this.state;
return events.length
? this.renderEventsList()
: this.renderEventsNone();
}
renderEventsNone () {
return (
<div className={ styles.statusHeader }>
There are currently no events available
</div>
);
}
renderEventsList () {
const { events } = this.state;
const rows = events.map((event) => {
return (
<Event key={ event.key } event={ event } />
);
});
return (
<table className={ styles.eventList }>
<tbody>
{ rows }
</tbody>
</table>
);
}
renderLoading () {
return (
<div className={ styles.statusHeader }>
Loading events
</div>
);
}
logToEvent = (log) => {
log.key = api.util.sha3(JSON.stringify(log));
return log;
}
receiveCreatedEvents = (error, logs) => {
if (error) {
console.error('receiveLogs', error);
return;
}
const { minedEvents, pendingEvents } = this.state;
const minedNew = logs
.filter((log) => log.type === 'mined')
.map(this.logToEvent)
.filter((log) => !minedEvents.find((event) => event.transactionHash === log.transactionHash))
.reverse()
.concat(minedEvents);
const pendingNew = logs
.filter((log) => log.type === 'pending')
.map(this.logToEvent)
.filter((log) => !pendingEvents.find((event) => event.transactionHash === log.transactionHash))
.reverse()
.concat(pendingEvents)
.filter((log) => !minedNew.find((event) => event.transactionHash === log.transactionHash));
const events = [].concat(pendingNew).concat(minedNew);
this.setState({ loading: false, events, minedEvents: minedNew, pendingEvents: pendingNew });
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './events';

View File

@@ -0,0 +1,31 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react';
import Deployment from './Deployment';
import Events from './Events';
export default class Deploy extends Component {
render () {
return (
<div>
<Deployment />
<Events />
</div>
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './deploy';

View File

@@ -0,0 +1,22 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.icon {
width: 24px;
height: 24px;
margin: 0 0.5em -4px 0;
}

View File

@@ -0,0 +1,38 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { api } from '../parity';
import styles from './identityIcon.css';
export default class IdentityIcon extends Component {
static propTypes = {
address: PropTypes.string.isRequired,
className: PropTypes.string
}
render () {
const { address, className } = this.props;
const classes = `${styles.icon} ${className}`;
return (
<img
className={ classes }
src={ api.util.createIdentityImg(address, 3) } />
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './identityIcon';

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './owner';

View File

@@ -0,0 +1,48 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.info {
}
.owner {
vertical-align: top;
text-align: right;
}
.owner>div {
border-radius: 1px;
padding: 1em 2em;
white-space: nowrap;
}
.tokens {
text-align: left;
}
.tokens>div {
border-radius: 1px;
background: #988;
padding: 1em;
margin: 0 0 0.25em 0.25em;
display: inline-block;
white-space: nowrap;
color: white;
}
.icon {
margin: 0 0 -4px 1em;
}

View File

@@ -0,0 +1,74 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import IdentityIcon from '../../IdentityIcon';
import Token from '../Token';
import styles from './owner.css';
export default class Owner extends Component {
static contextTypes = {
accounts: PropTypes.object.isRequired,
managerInstance: PropTypes.object.isRequired
}
static propTypes = {
address: PropTypes.string.isRequired,
tokens: PropTypes.array.isRequired
}
state = {
tokens: []
}
render () {
const { accounts } = this.context;
const { address, tokens } = this.props;
if (!tokens.length) {
return null;
}
return (
<tr className={ styles.info }>
<td className={ styles.owner }>
<div>
<span>{ accounts[address].name }</span>
<IdentityIcon
className={ styles.icon }
address={ address } />
</div>
</td>
<td className={ styles.tokens }>
{ this.renderTokens() }
</td>
</tr>
);
}
renderTokens () {
const { tokens } = this.props;
return tokens.map((token) => (
<div key={ token.address }>
<Token
address={ token.address }
tokenreg={ token.tokenreg } />
</div>
));
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './token';

View File

@@ -0,0 +1,53 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.info {
}
.info>div {
display: inline-block;
padding: 0.25em 0.5em;
vertical-align: middle;
}
.address {
}
.tla {
background: #766;
border-radius: 1px;
}
.name {
}
.supply {
}
.supply div {
display: block;
text-align: center;
}
.supply .info {
font-size: 0.75em;
opacity: 0.75;
}
.global {
font-size: 0.75em;
}

View File

@@ -0,0 +1,68 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { totalSupply, getCoin } from '../../services';
import styles from './token.css';
export default class Token extends Component {
static propTypes = {
address: PropTypes.string.isRequired,
tokenreg: PropTypes.string.isRequired
}
state = {
coin: null,
totalSupply: null
}
componentDidMount () {
this.lookupToken();
}
render () {
const { coin, totalSupply } = this.state;
if (!coin) {
return null;
}
return (
<div className={ styles.info }>
<div className={ styles.tla }>{ coin.tla }</div>
<div className={ styles.name }>{ coin.name }</div>
<div className={ styles.supply }>
<div>{ totalSupply.div(1000000).toFormat(0) }</div>
<div className={ styles.info }>total supply</div>
</div>
</div>
);
}
lookupToken () {
const { address, tokenreg } = this.props;
Promise
.all([
getCoin(tokenreg, address),
totalSupply(address)
])
.then(([coin, totalSupply]) => {
this.setState({ coin, totalSupply });
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './overview';

View File

@@ -0,0 +1,26 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
@import '../_status.css';
.body {
}
.ownerTable {
margin: 0 auto;
border-collapse: collapse;
}

View File

@@ -0,0 +1,107 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import { loadOwnedTokens } from '../services';
import Container from '../Container';
import Owner from './Owner';
import styles from './overview.css';
export default class Overview extends Component {
static contextTypes = {
accounts: PropTypes.object.isRequired,
managerInstance: PropTypes.object.isRequired
}
state = {
loading: true,
total: new BigNumber(0),
tokenOwners: []
}
componentDidMount () {
this.loadOwners();
}
render () {
const { loading } = this.state;
return (
<Container>
{ loading ? this.renderLoading() : this.renderBody() }
</Container>
);
}
renderLoading () {
return (
<div className={ styles.statusHeader }>
Loading tokens
</div>
);
}
renderBody () {
const { total } = this.state;
let owners = null;
if (total.gt(0)) {
owners = (
<table className={ styles.ownerTable }>
<tbody>
{ this.renderOwners() }
</tbody>
</table>
);
}
return (
<div className={ styles.body }>
<div className={ styles.statusHeader }>
You have { total.toFormat(0) } tokens created by your accounts
</div>
{ owners }
</div>
);
}
renderOwners () {
const { tokens } = this.state;
return Object.keys(tokens).map((address) => (
<Owner
key={ address }
tokens={ tokens[address] }
address={ address } />
));
}
loadOwners () {
const { accounts } = this.context;
const addresses = Object
.values(accounts)
.filter((account) => account.uuid)
.map((account) => account.address);
loadOwnedTokens(addresses)
.then(({ tokens, total }) => {
this.setState({ tokens, total, loading: false });
});
}
}

View File

@@ -0,0 +1,106 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// TODO: This is a copy & paste for Deploy/Event -> render() different. Not very DRY
import moment from 'moment';
import React, { Component, PropTypes } from 'react';
import { api } from '../../parity';
import { txLink } from '../../services';
import IdentityIcon from '../../IdentityIcon';
import styles from '../../Deploy/Event/event.css';
export default class Event extends Component {
static contextTypes = {
accounts: PropTypes.object.isRequired,
registryInstance: PropTypes.object.isRequired,
tokenregInstance: PropTypes.object.isRequired
}
static propTypes = {
event: PropTypes.object.isRequired,
token: PropTypes.object.isRequired
}
state = {
block: null
}
componentDidMount () {
this.lookup();
}
render () {
const { event, token } = this.props;
const { block } = this.state;
const isPending = event.type === 'pending';
return (
<tr className={ isPending ? styles.pending : styles.mined }>
<td className={ styles.blocknumber }>
<div>{ (isPending || !block) ? '' : moment(block.timestamp).fromNow() }</div>
<div>{ isPending ? 'Pending' : event.blockNumber.toFormat() }</div>
</td>
<td>{ event.event }</td>
<td className={ styles.description }>
<div>{ isPending ? '' : token.coin.tla }</div>
<div>{ isPending ? '' : token.coin.name }</div>
</td>
<td className={ styles.address }>
{ this.renderAddress(event.params.from) }
</td>
<td className={ styles.value }>
<div>{ event.params.value.div(1000000).toFormat(6) }</div>
<div></div>
<div><a href={ txLink(event.transactionHash) } target='_blank' className={ styles.link }>{ this.renderHash(event.transactionHash) }</a></div>
</td>
<td className={ styles.address }>
{ this.renderAddress(event.params.to) }
</td>
</tr>
);
}
renderAddress (address) {
const { accounts } = this.context;
const account = accounts[address];
return (
<div>
<IdentityIcon address={ address } />
<span>{ account ? account.name : address }</span>
</div>
);
}
renderHash (hash) {
return `${hash.substr(0, 10)}...${hash.slice(-10)}`;
}
lookup () {
const { event } = this.props;
if (event.type === 'pending') {
return;
}
api.eth
.getBlockByNumber(event.blockNumber)
.then((block) => {
this.setState({ block });
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './event';

View File

@@ -0,0 +1,145 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react';
import { api } from '../../parity';
import { loadAllTokens, subscribeEvents, unsubscribeEvents } from '../../services';
import Container from '../../Container';
import Event from '../Event';
import styles from '../../Deploy/Events/events.css';
export default class Events extends Component {
state = {
subscriptionId: 0,
loading: true,
events: [],
pendingEvents: [],
minedEvents: [],
tokens: []
}
componentDidMount () {
loadAllTokens()
.then((tokens) => {
const addresses = tokens.map((token) => token.address);
this.setState({ tokens });
return subscribeEvents(addresses, this.eventCallback);
})
.then((subscriptionId) => {
this.setState({ subscriptionId, loading: false });
})
.catch((error) => {
console.error('componentDidMount', error);
});
}
componentWillUnmount () {
const { subscriptionId } = this.state;
if (subscriptionId) {
unsubscribeEvents(subscriptionId);
}
}
render () {
const { loading } = this.state;
return (
<Container>
{ loading ? this.renderLoading() : this.renderEvents() }
</Container>
);
}
renderLoading () {
return (
<div className={ styles.statusHeader }>
Attaching events
</div>
);
}
renderEvents () {
const { events } = this.state;
return events.length
? this.renderEventsList()
: this.renderEventsNone();
}
renderEventsNone () {
return (
<div className={ styles.statusHeader }>
There are currently no events available
</div>
);
}
renderEventsList () {
const { events, tokens } = this.state;
const rows = events.map((event) => {
const token = tokens.find((token) => token.address === event.address);
return (
<Event
key={ event.key }
token={ token }
event={ event } />
);
});
return (
<table className={ styles.eventList }>
<tbody>
{ rows }
</tbody>
</table>
);
}
logToEvent = (log) => {
log.key = api.util.sha3(JSON.stringify(log));
return log;
}
eventCallback = (error, logs) => {
if (error) {
console.error('eventCallback', error);
return;
}
const { minedEvents, pendingEvents } = this.state;
const minedNew = logs
.filter((log) => log.type === 'mined')
.map(this.logToEvent)
.filter((log) => !minedEvents.find((event) => event.transactionHash === log.transactionHash))
.reverse()
.concat(minedEvents);
const pendingNew = logs
.filter((log) => log.type === 'pending')
.map(this.logToEvent)
.filter((log) => !pendingEvents.find((event) => event.transactionHash === log.transactionHash))
.reverse()
.concat(pendingEvents)
.filter((log) => !minedNew.find((event) => event.transactionHash === log.transactionHash));
const events = [].concat(pendingNew).concat(minedNew);
console.log('*** events', events.map((event) => event.address));
this.setState({ loading: false, events, minedEvents: minedNew, pendingEvents: pendingNew });
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './events';

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './send';

View File

@@ -0,0 +1,19 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
@import '../../_form.css';
@import '../../_status.css';

View File

@@ -0,0 +1,327 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import { eip20 } from '../../../../contracts/abi';
import { api } from '../../parity';
import { loadBalances } from '../../services';
import AddressSelect from '../../AddressSelect';
import Container from '../../Container';
import styles from './send.css';
export default class Send extends Component {
static contextTypes = {
accounts: PropTypes.object.isRequired
}
state = {
loading: true,
tokens: null,
selectedToken: null,
availableBalances: [],
fromAddress: null,
fromBalance: null,
toAddress: null,
toKnown: true,
amount: 0,
amountError: null,
sendBusy: false,
sendError: null,
sendState: null,
sendDone: false,
signerRequestId: null,
txHash: null,
txReceipt: null
}
componentDidMount () {
this.loadBalances();
this.onAmountChange({ target: { value: '0' } });
}
render () {
const { loading } = this.state;
return loading
? this.renderLoading()
: this.renderBody();
}
renderBody () {
const { sendBusy } = this.state;
return sendBusy
? this.renderSending()
: this.renderForm();
}
renderSending () {
const { sendDone, sendError, sendState } = this.state;
if (sendDone) {
return (
<Container>
<div className={ styles.statusHeader }>
Your token value transfer has been completed
</div>
</Container>
);
}
if (sendError) {
return (
<Container>
<div className={ styles.statusHeader }>
Your deployment has encountered an error
</div>
<div className={ styles.statusError }>
{ sendError }
</div>
</Container>
);
}
return (
<Container>
<div className={ styles.statusHeader }>
Your token value is being transferred
</div>
<div className={ styles.statusState }>
{ sendState }
</div>
</Container>
);
}
renderLoading () {
return (
<Container>
<div className={ styles.statusHeader }>
Loading available tokens
</div>
</Container>
);
}
renderForm () {
const { accounts } = this.context;
const { availableBalances, fromAddress, amount, amountError, toKnown, toAddress } = this.state;
const fromBalance = availableBalances.find((balance) => balance.address === fromAddress);
const fromAddresses = availableBalances.map((balance) => balance.address);
const toAddresses = Object.keys(accounts);
const toInput = toKnown
? <AddressSelect addresses={ toAddresses } onChange={ this.onChangeTo } />
: <input value={ toAddress } onChange={ this.onChangeTo } />;
const hasError = amountError;
const error = `${styles.input} ${styles.error}`;
const maxAmountHint = `Value to transfer (max: ${fromBalance ? fromBalance.balance.div(1000000).toFormat(6) : '1'})`;
return (
<Container>
<div className={ styles.form }>
<div className={ styles.input }>
<label>token type</label>
<select onChange={ this.onSelectToken }>
{ this.renderTokens() }
</select>
<div className={ styles.hint }>
type of token to transfer
</div>
</div>
<div className={ styles.input }>
<label>transfer from</label>
<AddressSelect
addresses={ fromAddresses }
onChange={ this.onSelectFrom } />
<div className={ styles.hint }>
account to transfer from
</div>
</div>
<div className={ styles.input }>
<label>transfer to</label>
<select onChange={ this.onChangeToType }>
<option value='known'>Known, Select from list</option>
<option value='unknown'>Unknown, Keyboard input</option>
</select>
<div className={ styles.hint }>
the type of address input
</div>
</div>
<div className={ styles.input }>
<label />
{ toInput }
<div className={ styles.hint }>
account to transfer to
</div>
</div>
<div className={ amountError ? error : styles.input }>
<label>amount</label>
<input
type='number'
min='0'
step='0.1'
value={ amount }
max={ fromBalance ? fromBalance.balance.div(1000000).toFixed(6) : 1 }
onChange={ this.onAmountChange } />
<div className={ styles.hint }>
{ amountError || maxAmountHint }
</div>
</div>
<div className={ styles.input }>
<label />
<div className={ styles.buttonRow }>
<div
className={ styles.button }
disabled={ hasError }
onClick={ this.onSend }>
Transfer Tokens
</div>
</div>
</div>
</div>
</Container>
);
}
renderTokens () {
const { tokens } = this.state;
return tokens.map((token) => (
<option
key={ token.address }
value={ token.address }>
{ token.coin.tla } / { token.coin.name }
</option>
));
}
onSelectFrom = (event) => {
const fromAddress = event.target.value;
this.setState({ fromAddress });
}
onChangeTo = (event) => {
const toAddress = event.target.value;
this.setState({ toAddress });
}
onChangeToType = (event) => {
const toKnown = event.target.value === 'known';
this.setState({ toKnown });
}
onSelectToken = (event) => {
const { tokens } = this.state;
const address = event.target.value;
const selectedToken = tokens.find((_token) => _token.address === address);
const availableBalances = selectedToken.balances.filter((balance) => balance.balance.gt(0));
this.setState({ selectedToken, availableBalances });
this.onSelectFrom({ target: { value: availableBalances[0].address } });
}
onAmountChange = (event) => {
const amount = parseFloat(event.target.value);
const amountError = !isFinite(amount) || amount <= 0
? 'amount needs to be > 0'
: null;
this.setState({ amount, amountError });
}
onSend = () => {
const { amount, fromAddress, toAddress, amountError, selectedToken, sendBusy } = this.state;
const hasError = amountError;
if (hasError || sendBusy) {
return;
}
const values = [toAddress, new BigNumber(amount).mul(1000000).toFixed(0)];
const options = {
from: fromAddress
};
const instance = api.newContract(eip20, selectedToken.address).instance;
this.setState({ sendBusy: true, sendState: 'Estimating gas for the transaction' });
instance
.transfer.estimateGas(options, values)
.then((gas) => {
this.setState({ sendState: 'Gas estimated, Posting transaction to the network' });
const gasPassed = gas.mul(1.2);
options.gas = gasPassed.toFixed(0);
console.log(`gas estimated at ${gas.toFormat(0)}, passing ${gasPassed.toFormat(0)}`);
return instance.transfer.postTransaction(options, values);
})
.then((signerRequestId) => {
this.setState({ signerRequestId, sendState: 'Transaction posted, Waiting for transaction authorization' });
return api.pollMethod('eth_checkRequest', signerRequestId);
})
.then((txHash) => {
this.setState({ txHash, sendState: 'Transaction authorized, Waiting for network confirmations' });
return api.pollMethod('eth_getTransactionReceipt', txHash, (receipt) => {
if (!receipt || !receipt.blockNumber || receipt.blockNumber.eq(0)) {
return false;
}
return true;
});
})
.then((txReceipt) => {
this.setState({ txReceipt, sendDone: true, sendState: 'Network confirmed, Received transaction receipt' });
})
.catch((error) => {
console.error('onSend', error);
this.setState({ sendError: error.message });
});
}
loadBalances () {
const { accounts } = this.context;
const myAccounts = Object
.values(accounts)
.filter((account) => account.uuid)
.map((account) => account.address);
loadBalances(myAccounts)
.then((_tokens) => {
const tokens = _tokens.filter((token) => {
for (let index = 0; index < token.balances.length; index++) {
if (token.balances[index].balance.gt(0)) {
return true;
}
}
return false;
});
this.setState({ tokens, loading: false });
this.onSelectToken({ target: { value: tokens[0].address } });
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './transfer';

View File

@@ -0,0 +1,31 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react';
import Events from './Events';
import Send from './Send';
export default class Transfer extends Component {
render () {
return (
<div>
<Send />
<Events />
</div>
);
}
}

View File

@@ -0,0 +1,105 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.button {
background: #622;
}
.form {
text-align: left;
margin: 0 auto;
display: inline-block;
}
.form .input {
margin-bottom: 1.5em;
}
.form .input * {
display: inline-block;
margin: 0 0.5em;
padding: 0.5em;
font-size: 1em;
}
.form label {
width: 25em;
opacity: 0.8;
text-align: right;
}
.form .hint {
width: 25em;
opacity: 0.5;
}
.form input,
.form select {
width: 18em;
color: #444;
background: rgba(255, 255, 255, 0.75);
border-radius: 1px;
border: 1px solid rgba(0, 0, 0, 0.25);
box-sizing: border-box;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
}
.form select {
height: 36px;
}
.form input.small {
width: 9em;
margin-right: 9.5em;
}
.form .error input {
border: 1px solid rgba(255, 0, 0, 0.5);
color: red;
background: rgba(255, 0, 0, 0.1);
}
.form .error label {
color: red;
}
.form .error .hint {
color: red;
}
.buttonRow {
text-align: right;
width: 18em;
}
.button {
color: white;
border: none;
border-radius: 1px;
padding: 1em 2em !important;
display: inline-block;
margin-left: 1em !important;
cursor: pointer;
position: relative;
}
.button[disabled] {
opacity: 0.5;
cursor: default;
}

View File

@@ -0,0 +1,36 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.statusHeader {
font-size: 1.25em;
margin-bottom: 1.25em;
opacity: 0.75;
}
.statusInfo {
margin-bottom: 0.25em;
}
.statusState {
opacity: 0.75;
margin-top: 1em;
}
.statusError {
color: red;
margin-top: 1em;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@@ -0,0 +1,21 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
const { api } = window.parity;
export {
api
};

View File

@@ -0,0 +1,270 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import * as abis from '../../contracts/abi';
import { api } from './parity';
let managerInstance;
let tokenregInstance;
let registryInstance;
const registries = {};
const subscriptions = {};
let nextSubscriptionId = 1000;
let isTest = false;
export function subscribeEvents (addresses, callback) {
const subscriptionId = nextSubscriptionId++;
const contract = api.newContract(abis.eip20);
const event = contract.events.filter((evt) => evt.name === 'Transfer');
const options = {
address: addresses,
fromBlock: 0,
toBlock: 'pending',
limit: 50,
topics: [event.signature]
};
return api.eth
.newFilter(options)
.then((filterId) => {
subscriptions[subscriptionId] = { subscriptionId, filterId, addresses, callback, contract };
return api.eth.getFilterLogs(filterId);
})
.then((logs) => callback(null, contract.parseEventLogs(logs)))
.then(() => subscriptionId)
.catch((error) => {
console.error('subscribeEvents', error);
throw error;
});
}
export function unsubscribeEvents (subscriptionId) {
api.eth
.uninstallFilter(subscriptions[subscriptionId].filterId)
.catch((error) => {
console.error('unsubscribeEvents', error);
});
delete subscriptions[subscriptionId];
}
function pollEvents () {
const loop = Object.values(subscriptions);
const timeout = () => setTimeout(pollEvents, 1000);
Promise
.all(loop.map((subscription) => api.eth.getFilterChanges(subscription.filterId)))
.then((logsArray) => {
logsArray.forEach((logs, index) => {
const subscription = loop[index];
if (!logs || !logs.length) {
return;
}
try {
subscription.callback(null, subscription.contract.parseEventLogs(logs));
} catch (error) {
unsubscribeEvents(loop.subscriptionId);
console.error('pollEvents', error);
}
});
timeout();
})
.catch((error) => {
console.error('pollEvents', error);
timeout();
});
}
export function attachInstances () {
pollEvents();
return Promise
.all([
api.ethcore.registryAddress(),
api.ethcore.netChain()
])
.then(([registryAddress, netChain]) => {
const registry = api.newContract(abis.registry, registryAddress).instance;
isTest = netChain === 'morden' || netChain === 'testnet';
console.log(`contract was found at registry=${registryAddress}`);
console.log(`running on ${netChain}, isTest=${isTest}`);
return Promise
.all([
registry.getAddress.call({}, [api.util.sha3('playbasiccoinmgr'), 'A']),
registry.getAddress.call({}, [api.util.sha3('basiccoinreg'), 'A']),
registry.getAddress.call({}, [api.util.sha3('tokenreg'), 'A'])
]);
})
.then(([managerAddress, registryAddress, tokenregAddress]) => {
console.log(`contracts were found at basiccoinmgr=${managerAddress}, basiccoinreg=${registryAddress}, tokenreg=${registryAddress}`);
managerInstance = api.newContract(abis.basiccoinmanager, managerAddress).instance;
registryInstance = api.newContract(abis.tokenreg, registryAddress).instance;
tokenregInstance = api.newContract(abis.tokenreg, tokenregAddress).instance;
registries[registryInstance.address] = registryInstance;
registries[tokenregInstance.address] = tokenregInstance;
return {
managerInstance,
registryInstance,
tokenregInstance
};
})
.catch((error) => {
console.error('attachInstances', error);
throw error;
});
}
export function totalSupply (address) {
return api.newContract(abis.eip20, address)
.instance.totalSupply.call();
}
export function getCoin (tokenreg, address) {
return registries[tokenreg].fromAddress
.call({}, [address])
.then(([id, tla, base, name, owner]) => {
return {
id, tla, base, name, owner,
isGlobal: tokenregInstance.address === tokenreg
};
})
.catch((error) => {
console.error('getCoin', error);
throw error;
});
}
export function loadOwnedTokens (addresses) {
let total = new BigNumber(0);
return Promise
.all(
addresses.map((address) => managerInstance.countByOwner.call({}, [address]))
)
.then((counts) => {
return Promise.all(
addresses.reduce((promises, address, index) => {
total = counts[index].add(total);
for (let i = 0; counts[index].gt(i); i++) {
promises.push(managerInstance.getByOwner.call({}, [address, i]));
}
return promises;
}, [])
);
})
.then((_tokens) => {
const tokens = _tokens.reduce((tokens, token) => {
const [address, owner, tokenreg] = token;
tokens[owner] = tokens[owner] || [];
tokens[owner].push({ address, owner, tokenreg });
return tokens;
}, {});
return { tokens, total };
})
.catch((error) => {
console.error('loadTokens', error);
throw error;
});
}
export function loadAllTokens () {
return managerInstance
.count.call()
.then((count) => {
const promises = [];
for (let index = 0; count.gt(index); index++) {
promises.push(managerInstance.get.call({}, [index]));
}
return Promise.all(promises);
})
.then((_tokens) => {
const tokens = [];
return Promise
.all(
_tokens.map(([address, owner, tokenreg]) => {
const isGlobal = tokenreg === tokenregInstance.address;
tokens.push({ address, owner, tokenreg, isGlobal });
return registries[tokenreg].fromAddress.call({}, [address]);
})
)
.then((coins) => {
return tokens.map((token, index) => {
const [id, tla, base, name, owner] = coins[index];
token.coin = { id, tla, base, name, owner };
return token;
});
});
})
.catch((error) => {
console.log('loadAllTokens', error);
throw error;
});
}
export function loadBalances (addresses) {
return loadAllTokens()
.then((tokens) => {
return Promise.all(
tokens.map((token) => {
return Promise.all(
addresses.map((address) => loadTokenBalance(token.address, address))
);
})
)
.then((_balances) => {
return tokens.map((token, tindex) => {
const balances = _balances[tindex];
token.balances = addresses.map((address, aindex) => {
return { address, balance: balances[aindex] };
});
return token;
});
});
})
.catch((error) => {
console.error('loadBalances', error);
throw error;
});
}
export function loadTokenBalance (tokenAddress, address) {
return api.newContract(abis.eip20, tokenAddress).instance
.balanceOf.call({}, [address])
.catch((error) => {
console.error('loadTokenBalance', error);
throw error;
});
}
export function txLink (txHash) {
return `https://${isTest ? 'testnet.' : ''}etherscan.io/tx/${txHash}`;
}

16
js/src/dapps/gavcoin.html Normal file
View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>GAVcoin</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="parity.js"></script>
<script src="gavcoin.js"></script>
</body>
</html>

33
js/src/dapps/gavcoin.js Normal file
View File

@@ -0,0 +1,33 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import ReactDOM from 'react-dom';
import React from 'react';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
import Application from './gavcoin/Application';
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './gavcoin.html';
ReactDOM.render(
<Application />,
document.querySelector('#container')
);

View File

@@ -0,0 +1,45 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.account {
padding: 4px 0 !important;
display: inline-block;
}
.name {
display: inline-block;
margin-right: 1em;
text-transform: uppercase;
}
.balance {
display: inline-block;
text-align: right;
color: #aaa;
font-family: 'Roboto Mono', monospace;
}
.details {
display: inline-block;
}
.image {
display: inline-block;
}
.image img {
margin: 0 1em -11px 0;
}

View File

@@ -0,0 +1,63 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import IdentityIcon from '../../IdentityIcon';
import styles from './accountItem.css';
export default class AccountItem extends Component {
static propTypes = {
account: PropTypes.object,
gavBalance: PropTypes.bool
};
render () {
const { account, gavBalance } = this.props;
let balance;
let token;
if (gavBalance) {
if (account.gavBalance) {
balance = account.gavBalance;
token = 'GAV';
}
} else {
if (account.ethBalance) {
balance = account.ethBalance;
token = 'ETH';
}
}
return (
<div className={ styles.account }>
<div className={ styles.image }>
<IdentityIcon address={ account.address } />
</div>
<div className={ styles.details }>
<div className={ styles.name }>
{ account.name || account.address }
</div>
<div className={ styles.balance }>
{ balance }<small> { token }</small>
</div>
</div>
</div>
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './accountItem';

View File

@@ -0,0 +1,102 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import { MenuItem, SelectField } from 'material-ui';
import AccountItem from './AccountItem';
const NAME_ID = ' ';
let lastSelectedAccount = {};
export default class AccountSelect extends Component {
static propTypes = {
accounts: PropTypes.array,
account: PropTypes.object,
anyAccount: PropTypes.bool,
gavBalance: PropTypes.bool,
onSelect: PropTypes.func,
errorText: PropTypes.string,
floatingLabelText: PropTypes.string,
hintText: PropTypes.string
}
componentDidMount () {
this.props.onSelect(lastSelectedAccount);
}
render () {
const { account, accounts, anyAccount, errorText, floatingLabelText, gavBalance, hintText } = this.props;
return (
<SelectField
autoComplete='off'
floatingLabelFixed
floatingLabelText={ floatingLabelText }
fullWidth
hintText={ hintText }
errorText={ errorText }
name={ NAME_ID }
id={ NAME_ID }
value={ account }
onChange={ this.onSelect }>
{ renderAccounts(accounts, { anyAccount, gavBalance }) }
</SelectField>
);
}
onSelect = (event, idx, account) => {
lastSelectedAccount = account || {};
this.props.onSelect(lastSelectedAccount);
}
}
function isPositive (numberStr) {
return new BigNumber(numberStr.replace(',', '')).gt(0);
}
export function renderAccounts (accounts, options = {}) {
return accounts
.filter((account) => {
if (options.anyAccount) {
return true;
}
if (account.uuid) {
return isPositive(account[options.gavBalance ? 'gavBalance' : 'ethBalance']);
}
return false;
})
.map((account) => {
const item = (
<AccountItem
account={ account }
key={ account.address }
gavBalance={ options.gavBalance || false } />
);
return (
<MenuItem
key={ account.address }
value={ account }
label={ item }>
{ item }
</MenuItem>
);
});
}

View File

@@ -0,0 +1,22 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { renderAccounts } from './accountSelector';
export default from './accountSelector';
export {
renderAccounts
};

View File

@@ -0,0 +1,28 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.addrtext {
position: relative;
}
.input input {
padding-left: 48px !important;
}
.addricon {
position: absolute;
top: 37px;
}

View File

@@ -0,0 +1,106 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { TextField } from 'material-ui';
import IdentityIcon from '../IdentityIcon';
import AccountSelector from '../AccountSelector';
import styles from './accountSelectorText.css';
const NAME_ID = ' ';
export default class AccountSelectorText extends Component {
static propTypes = {
accounts: PropTypes.array,
account: PropTypes.object,
errorText: PropTypes.string,
gavBalance: PropTypes.bool,
anyAccount: PropTypes.bool,
floatingLabelText: PropTypes.string,
hintText: PropTypes.string,
selector: PropTypes.bool,
onChange: PropTypes.func
}
render () {
const { selector } = this.props;
return selector
? this.renderDropDown()
: this.renderTextField();
}
renderDropDown () {
const { account, accounts, anyAccount, errorText, gavBalance, hintText, floatingLabelText, onChange } = this.props;
return (
<AccountSelector
anyAccount={ anyAccount }
gavBalance={ gavBalance }
accounts={ accounts }
account={ account }
errorText={ errorText }
floatingLabelText={ floatingLabelText }
hintText={ hintText }
onSelect={ onChange } />
);
}
renderTextField () {
const { account, errorText, hintText, floatingLabelText } = this.props;
return (
<div className={ styles.addrtext }>
<TextField
className={ styles.input }
autoComplete='off'
floatingLabelFixed
floatingLabelText={ floatingLabelText }
fullWidth
hintText={ hintText }
errorText={ errorText }
name={ NAME_ID }
id={ NAME_ID }
value={ account.address || '' }
onChange={ this.onChangeAddress } />
{ this.renderAddressIcon() }
</div>
);
}
renderAddressIcon () {
const { account } = this.props;
if (!account.address) {
return null;
}
return (
<div className={ styles.addricon }>
<IdentityIcon address={ account.address } />
</div>
);
}
onChangeAddress = (event, address) => {
const lower = address.toLowerCase();
const account = this.props.accounts.find((_account) => _account.address.toLowerCase() === lower);
this.props.onChange(account || { address });
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './accountSelectorText';

View File

@@ -0,0 +1,47 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.accounts {
padding: 4em 2em 0 2em;
text-align: center;
width: 100%;
}
.account {
margin: 0.5em !important;
background: rgb(50, 100, 150) !important;
display: inline-block !important;
}
.account img {
margin-bottom: -11px;
margin-left: -11px;
}
.balance {
font-family: 'Roboto Mono', monospace;
color: rgba(255, 255, 255, 1) !important;
}
.name {
color: rgba(255, 255, 255, 0.7) !important;
margin-right: 1em;
text-transform: uppercase;
}
.none {
color: rgba(255, 255, 255, 0.7);
}

View File

@@ -0,0 +1,83 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { Chip } from 'material-ui';
import IdentityIcon from '../IdentityIcon';
import styles from './accounts.css';
export default class Accounts extends Component {
static contextTypes = {
api: PropTypes.object.isRequired,
instance: PropTypes.object.isRequired
}
static propTypes = {
accounts: PropTypes.array
}
render () {
const has = this._hasAccounts();
return (
<div className={ styles.accounts }>
{ has ? this.renderAccounts() : this.renderEmpty() }
</div>
);
}
renderEmpty () {
return (
<div className={ styles.none }>
You currently do not have any GAVcoin in any of your addresses, buy some
</div>
);
}
renderAccounts () {
const { accounts } = this.props;
return accounts
.filter((account) => account.hasGav)
.map((account) => {
return (
<Chip
className={ styles.account }
key={ account.address }>
<IdentityIcon address={ account.address } />
<span className={ styles.name }>
{ account.name }
</span>
<span className={ styles.balance }>
{ account.gavBalance }
</span>
</Chip>
);
});
}
_hasAccounts () {
const { accounts } = this.props;
if (!accounts || !accounts.length) {
return false;
}
return accounts.filter((account) => account.hasGav).length !== 0;
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './accounts';

View File

@@ -0,0 +1,206 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import { Dialog, FlatButton, TextField } from 'material-ui';
import { api } from '../../parity';
import AccountSelector from '../../AccountSelector';
import { ERRORS, validateAccount, validatePositiveNumber } from '../validation';
import styles from '../actions.css';
const NAME_ID = ' ';
export default class ActionBuyIn extends Component {
static contextTypes = {
instance: PropTypes.object.isRequired
}
static propTypes = {
accounts: PropTypes.array,
price: PropTypes.object,
onClose: PropTypes.func
}
state = {
account: {},
accountError: ERRORS.invalidAccount,
amount: 0,
amountError: ERRORS.invalidAmount,
maxPrice: api.util.fromWei(this.props.price.mul(1.2)).toString(),
maxPriceError: null,
sending: false,
complete: false
}
render () {
const { complete } = this.state;
if (complete) {
return null;
}
return (
<Dialog
title='buy coins for a specific account'
modal open
className={ styles.dialog }
actions={ this.renderActions() }>
{ this.renderFields() }
</Dialog>
);
}
renderActions () {
const { complete } = this.state;
if (complete) {
return (
<FlatButton
label='Done'
primary
onTouchTap={ this.props.onClose } />
);
}
const { accountError, amountError, maxPriceError, sending } = this.state;
const hasError = !!(amountError || accountError || maxPriceError);
return ([
<FlatButton
label='Cancel'
primary
onTouchTap={ this.props.onClose } />,
<FlatButton
label='Buy'
primary
disabled={ hasError || sending }
onTouchTap={ this.onSend } />
]);
}
renderFields () {
const maxPriceLabel = `maximum price in ETH (current ${api.util.fromWei(this.props.price).toFormat(3)})`;
return (
<div>
<AccountSelector
accounts={ this.props.accounts }
account={ this.state.account }
errorText={ this.state.accountError }
floatingLabelText='from account'
hintText='the account the transaction will be made from'
onSelect={ this.onChangeAddress } />
<TextField
autoComplete='off'
floatingLabelFixed
floatingLabelText='amount in ETH'
fullWidth
hintText='the amount of ETH you wish to spend'
errorText={ this.state.amountError }
name={ NAME_ID }
id={ NAME_ID }
value={ this.state.amount }
onChange={ this.onChangeAmount } />
<TextField
autoComplete='off'
floatingLabelFixed
floatingLabelText={ maxPriceLabel }
fullWidth
hintText='the maxium price allowed for buying'
errorText={ this.state.maxPriceError }
name={ NAME_ID }
id={ NAME_ID }
value={ this.state.maxPrice }
onChange={ this.onChangeMaxPrice } />
</div>
);
}
onChangeAddress = (account) => {
this.setState({
account,
accountError: validateAccount(account)
}, this.validateTotal);
}
onChangeAmount = (event, amount) => {
this.setState({
amount,
amountError: validatePositiveNumber(amount)
}, this.validateTotal);
}
onChangeMaxPrice = (event, maxPrice) => {
this.setState({
maxPrice,
maxPriceError: validatePositiveNumber(maxPrice)
});
}
validateTotal = () => {
const { account, accountError, amount, amountError } = this.state;
if (accountError || amountError) {
return;
}
if (new BigNumber(amount).gt(account.ethBalance.replace(',', ''))) {
this.setState({
amountError: ERRORS.invalidTotal
});
}
}
onSend = () => {
const { instance } = this.context;
const maxPrice = api.util.toWei(this.state.maxPrice);
const values = [this.state.account.address, maxPrice.toString()];
const options = {
from: this.state.account.address,
value: api.util.toWei(this.state.amount).toString()
};
this.setState({
sending: true
});
instance.buyin
.estimateGas(options, values)
.then((gasEstimate) => {
options.gas = gasEstimate.mul(1.2).toFixed(0);
console.log(`buyin: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`);
return instance.buyin.postTransaction(options, values);
})
.then(() => {
this.props.onClose();
this.setState({
sending: false,
complete: true
});
})
.catch((error) => {
console.error('error', error);
this.setState({
sending: false
});
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './actionBuyIn';

View File

@@ -0,0 +1,191 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import { Dialog, FlatButton, TextField } from 'material-ui';
import { api } from '../../parity';
import AccountSelector from '../../AccountSelector';
import { ERRORS, validateAccount, validatePositiveNumber } from '../validation';
import styles from '../actions.css';
const DIVISOR = 10 ** 6;
const NAME_ID = ' ';
export default class ActionRefund extends Component {
static contextTypes = {
instance: PropTypes.object.isRequired
}
static propTypes = {
accounts: PropTypes.array,
price: PropTypes.object,
onClose: PropTypes.func
}
state = {
account: {},
accountError: ERRORS.invalidAccount,
complete: false,
sending: false,
amount: 0,
amountError: ERRORS.invalidAmount,
price: api.util.fromWei(this.props.price).toString(),
priceError: null
}
render () {
const { complete } = this.state;
if (complete) {
return null;
}
return (
<Dialog
title='return coins for a refund'
modal open
className={ styles.dialog }
actions={ this.renderActions() }>
{ this.renderFields() }
</Dialog>
);
}
renderActions () {
if (this.state.complete) {
return (
<FlatButton
label='Done'
primary
onTouchTap={ this.props.onClose } />
);
}
const hasError = !!(this.state.priceError || this.state.amountError || this.state.accountError);
return ([
<FlatButton
label='Cancel'
primary
onTouchTap={ this.props.onClose } />,
<FlatButton
label='Refund'
primary
disabled={ hasError || this.state.sending }
onTouchTap={ this.onSend } />
]);
}
renderFields () {
const priceLabel = `price in ETH (current ${api.util.fromWei(this.props.price).toFormat(3)})`;
return (
<div>
<AccountSelector
gavBalance
accounts={ this.props.accounts }
account={ this.state.account }
errorText={ this.state.accountError }
floatingLabelText='from account'
hintText='the account the transaction will be made from'
onSelect={ this.onChangeAddress } />
<TextField
autoComplete='off'
floatingLabelFixed
floatingLabelText='number of coins'
fullWidth
hintText='the number of coins to exchange for an ETH refund'
errorText={ this.state.amountError }
name={ NAME_ID }
id={ NAME_ID }
value={ this.state.amount }
onChange={ this.onChangeAmount } />
<TextField
autoComplete='off'
floatingLabelFixed
floatingLabelText={ priceLabel }
fullWidth
hintText='the price the refund is requested at'
errorText={ this.state.priceError }
name={ NAME_ID }
id={ NAME_ID }
value={ this.state.price }
onChange={ this.onChangePrice } />
</div>
);
}
onChangeAddress = (account) => {
this.setState({
account,
accountError: validateAccount(account)
});
}
onChangeAmount = (event, amount) => {
this.setState({
amount,
amountError: validatePositiveNumber(amount)
});
}
onChangePrice = (event, price) => {
this.setState({
price,
priceError: validatePositiveNumber(price)
});
}
onSend = () => {
const { instance } = this.context;
const price = api.util.toWei(this.state.price);
const amount = new BigNumber(this.state.amount).mul(DIVISOR);
const values = [price.toString(), amount.toFixed(0)];
const options = {
from: this.state.account.address
};
this.setState({
sending: true
});
instance.refund
.estimateGas(options, values)
.then((gasEstimate) => {
options.gas = gasEstimate.mul(1.2).toFixed(0);
console.log(`refund: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`);
return instance.refund.postTransaction(options, values);
})
.then(() => {
this.props.onClose();
this.setState({
sending: false,
complete: true
});
})
.catch((error) => {
console.error('error', error);
this.setState({
sending: false
});
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './actionRefund';

View File

@@ -0,0 +1,220 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import { Dialog, FlatButton, TextField, Toggle } from 'material-ui';
import AccountSelector from '../../AccountSelector';
import AccountSelectorText from '../../AccountSelectorText';
import { ERRORS, validateAccount, validatePositiveNumber } from '../validation';
import styles from '../actions.css';
const DIVISOR = 10 ** 6;
const NAME_ID = ' ';
export default class ActionTransfer extends Component {
static contextTypes = {
instance: PropTypes.object.isRequired
}
static propTypes = {
accounts: PropTypes.array,
price: PropTypes.object,
onClose: PropTypes.func
}
state = {
fromAccount: {},
fromAccountError: ERRORS.invalidAccount,
toAccount: {},
toAccountError: ERRORS.invalidRecipient,
inputAccount: false,
complete: false,
sending: false,
amount: 0,
amountError: ERRORS.invalidAmount
}
render () {
const { complete } = this.state;
if (complete) {
return null;
}
return (
<Dialog
title='send coins to another account'
modal open
className={ styles.dialog }
actions={ this.renderActions() }>
{ this.renderFields() }
</Dialog>
);
}
renderActions () {
const { complete, sending, amountError, fromAccountError, toAccountError } = this.state;
if (complete) {
return (
<FlatButton
label='Done'
primary
onTouchTap={ this.props.onClose } />
);
}
const hasError = !!(amountError || fromAccountError || toAccountError);
return ([
<FlatButton
label='Cancel'
primary
onTouchTap={ this.props.onClose } />,
<FlatButton
label='Transfer'
primary
disabled={ hasError || sending }
onTouchTap={ this.onSend } />
]);
}
renderFields () {
const { accounts } = this.props;
const { fromAccount, fromAccountError, toAccount, toAccountError, inputAccount, amount, amountError } = this.state;
return (
<div>
<AccountSelector
gavBalance
accounts={ accounts }
account={ fromAccount }
errorText={ fromAccountError }
floatingLabelText='from account'
hintText='the account the transaction will be made from'
onSelect={ this.onChangeFromAccount } />
<div className={ styles.overlay }>
<AccountSelectorText
gavBalance anyAccount
selector={ !inputAccount }
accounts={ accounts }
account={ toAccount }
errorText={ toAccountError }
floatingLabelText='to account'
hintText='the account the coins will be sent to'
onChange={ this.onChangeToAccount } />
<Toggle
className={ styles.overlaytoggle }
label='Edit'
labelPosition='right'
toggled={ inputAccount }
onToggle={ this.onChangeToInput } />
</div>
<TextField
autoComplete='off'
floatingLabelFixed
floatingLabelText='number of coins'
fullWidth
hintText='the number of coins to transfer'
errorText={ amountError }
name={ NAME_ID }
id={ NAME_ID }
value={ amount }
onChange={ this.onChangeAmount } />
</div>
);
}
onChangeFromAccount = (fromAccount) => {
this.setState({
fromAccount,
fromAccountError: validateAccount(fromAccount)
}, this.validateTotal);
}
onChangeToAccount = (toAccount) => {
this.setState({
toAccount,
toAccountError: validateAccount(toAccount)
});
}
onChangeToInput = () => {
this.setState({
inputAccount: !this.state.inputAccount
});
}
onChangeAmount = (event, amount) => {
this.setState({
amount,
amountError: validatePositiveNumber(amount)
}, this.validateTotal);
}
validateTotal = () => {
const { fromAccount, fromAccountError, amount, amountError } = this.state;
if (fromAccountError || amountError) {
return;
}
if (new BigNumber(amount).gt(fromAccount.gavBalance.replace(',', ''))) {
this.setState({
amountError: ERRORS.invalidTotal
});
}
}
onSend = () => {
const { instance } = this.context;
const amount = new BigNumber(this.state.amount).mul(DIVISOR);
const values = [this.state.toAccount.address, amount.toFixed(0)];
const options = {
from: this.state.fromAccount.address
};
this.setState({
sending: true
});
instance.transfer
.estimateGas(options, values)
.then((gasEstimate) => {
options.gas = gasEstimate.mul(1.2).toFixed(0);
console.log(`transfer: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`);
return instance.transfer.postTransaction(options, values);
})
.then(() => {
this.props.onClose();
this.setState({
sending: false,
complete: true
});
})
.catch((error) => {
console.error('error', error);
this.setState({
sending: false
});
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './actionTransfer';

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './stepComplete';

View File

@@ -0,0 +1,29 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react';
import styles from '../actions.css';
export default class StepComplete extends Component {
render () {
return (
<div className={ styles.dialogtext }>
Your transaction has been posted. Please visit the <a href='http://127.0.0.1:8080/#/signer' className={ styles.link } target='_blank'>Parity Signer</a> to authenticate the transfer.
</div>
);
}
}

View File

@@ -0,0 +1,72 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.actions {
text-align: center;
padding: 2em 2em 0 2em;
width: 100%;
}
.button {
margin: 0 0.5em;
}
.button button {
background-color: rgba(50, 100, 150, 1) !important;
height: 56px !important;
padding: 0 10px !important;
}
.button button[disabled] {
background-color: rgba(50, 50, 50, 0.25) !important;
}
.dialog {
}
.dialog h3 {
color: rgba(50, 100, 150, 1) !important;
text-transform: uppercase;
}
.dialogtext {
padding-top: 1em;
}
.link, .link:hover, .link:visited {
color: rgb(0, 188, 212);
text-decoration: none;
}
.overlay {
position: relative;
}
.overlay svg {
opacity: 0;
}
.toggle {
text-align: right;
}
.overlaytoggle {
position: absolute !important;
top: 40px;
right: 0;
display: inline-block !important;
width: auto !important;
}

View File

@@ -0,0 +1,76 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { RaisedButton } from 'material-ui';
import ActionAddShoppingCart from 'material-ui/svg-icons/action/add-shopping-cart';
// import AvReplay from 'material-ui/svg-icons/av/replay';
import ContentSend from 'material-ui/svg-icons/content/send';
import styles from './actions.css';
export default class Actions extends Component {
static propTypes = {
onAction: PropTypes.func.isRequired,
gavBalance: PropTypes.object.isRequired
}
render () {
const { gavBalance } = this.props;
return (
<div className={ styles.actions }>
<RaisedButton
className={ styles.button }
icon={ <ActionAddShoppingCart /> }
label='buy coins'
primary
onTouchTap={ this.onBuyIn } />
<RaisedButton
disabled={ !gavBalance || gavBalance.eq(0) }
className={ styles.button }
icon={ <ContentSend /> }
label='send coins'
primary
onTouchTap={ this.onTransfer } />
</div>
);
// <RaisedButton
// className={ styles.button }
// icon={ <AvReplay /> }
// label='claim refund'
// primary
// onTouchTap={ this.onRefund } />
}
onBuyIn = () => {
this.props.onAction('BuyIn');
}
onTransfer = () => {
const { gavBalance } = this.props;
if (gavBalance && gavBalance.gt(0)) {
this.props.onAction('Transfer');
}
}
onRefund = () => {
this.props.onAction('Refund');
}
}

View File

@@ -0,0 +1,27 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import ActionBuyIn from './ActionBuyIn';
import ActionRefund from './ActionRefund';
import ActionTransfer from './ActionTransfer';
export default from './actions';
export {
ActionBuyIn,
ActionRefund,
ActionTransfer
};

View File

@@ -0,0 +1,56 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import { api } from '../parity';
export const ERRORS = {
invalidAccount: 'please select an account to transact with',
invalidRecipient: 'please select an account to send to',
invalidAddress: 'the address is not in the correct format',
invalidAmount: 'please enter a positive amount > 0',
invalidTotal: 'the amount is greater than the availale balance'
};
export function validatePositiveNumber (value) {
let bn = null;
try {
bn = new BigNumber(value);
} catch (e) {
}
if (!bn || !bn.gt(0)) {
return ERRORS.invalidAmount;
}
return null;
}
export function validateAccount (account) {
if (!account || !account.address) {
return ERRORS.invalidAccount;
}
if (!api.util.isAddressValid(account.address)) {
return ERRORS.invalidAddress;
}
account.address = api.util.toChecksumAddress(account.address);
return null;
}

View File

@@ -0,0 +1,239 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
const muiTheme = getMuiTheme(lightBaseTheme);
import { api } from '../parity';
import * as abis from '../../../contracts/abi';
import Accounts from '../Accounts';
import Actions, { ActionBuyIn, ActionRefund, ActionTransfer } from '../Actions';
import Events from '../Events';
import Loading from '../Loading';
import Status from '../Status';
const DIVISOR = 10 ** 6;
export default class Application extends Component {
static childContextTypes = {
api: PropTypes.object,
contract: PropTypes.object,
instance: PropTypes.object,
muiTheme: PropTypes.object
};
state = {
action: null,
address: null,
accounts: [],
blockNumber: new BigNumber(-1),
ethBalance: new BigNumber(0),
gavBalance: new BigNumber(0),
instance: null,
loading: true,
price: null,
remaining: null,
totalSupply: null
}
componentDidMount () {
this.attachInterface();
}
render () {
const { accounts, address, blockNumber, gavBalance, loading, price, remaining, totalSupply } = this.state;
if (loading) {
return (
<Loading />
);
}
return (
<div>
{ this.renderModals() }
<Status
address={ address }
blockNumber={ blockNumber }
gavBalance={ gavBalance }
price={ price }
remaining={ remaining }
totalSupply={ totalSupply }>
<Accounts
accounts={ accounts } />
</Status>
<Actions
gavBalance={ gavBalance }
onAction={ this.onAction } />
<Events
accounts={ accounts } />
</div>
);
}
renderModals () {
const { action, accounts, price } = this.state;
switch (action) {
case 'BuyIn':
return (
<ActionBuyIn
accounts={ accounts }
price={ price }
onClose={ this.onActionClose } />
);
case 'Refund':
return (
<ActionRefund
accounts={ accounts }
price={ price }
onClose={ this.onActionClose } />
);
case 'Transfer':
return (
<ActionTransfer
accounts={ accounts }
onClose={ this.onActionClose } />
);
default:
return null;
}
}
getChildContext () {
const { contract, instance } = this.state;
return {
api,
contract,
instance,
muiTheme
};
}
onAction = (action) => {
this.setState({
action
});
}
onActionClose = () => {
this.setState({
action: null
});
}
onNewBlockNumber = (_error, blockNumber) => {
const { instance, accounts } = this.state;
if (_error) {
console.error('onNewBlockNumber', _error);
return;
}
Promise
.all([
instance.totalSupply.call(),
instance.remaining.call(),
instance.price.call()
])
.then(([totalSupply, remaining, price]) => {
this.setState({
blockNumber,
totalSupply,
remaining,
price
});
const gavQueries = accounts.map((account) => instance.balanceOf.call({}, [account.address]));
const ethQueries = accounts.map((account) => api.eth.getBalance(account.address));
return Promise.all([
Promise.all(gavQueries),
Promise.all(ethQueries)
]);
})
.then(([gavBalances, ethBalances]) => {
this.setState({
ethBalance: ethBalances.reduce((total, balance) => total.add(balance), new BigNumber(0)),
gavBalance: gavBalances.reduce((total, balance) => total.add(balance), new BigNumber(0)),
accounts: accounts.map((account, idx) => {
const ethBalance = ethBalances[idx];
const gavBalance = gavBalances[idx];
account.ethBalance = api.util.fromWei(ethBalance).toFormat(3);
account.gavBalance = gavBalance.div(DIVISOR).toFormat(6);
account.hasGav = gavBalance.gt(0);
return account;
})
});
})
.catch((error) => {
console.error('onNewBlockNumber', error);
});
}
attachInterface = () => {
api.ethcore
.registryAddress()
.then((registryAddress) => {
console.log(`the registry was found at ${registryAddress}`);
const registry = api.newContract(abis.registry, registryAddress).instance;
return Promise
.all([
registry.getAddress.call({}, [api.util.sha3('gavcoin'), 'A']),
api.personal.listAccounts(),
api.personal.accountsInfo()
]);
})
.then(([address, addresses, infos]) => {
console.log(`gavcoin was found at ${address}`);
const contract = api.newContract(abis.gavcoin, address);
this.setState({
loading: false,
address,
contract,
instance: contract.instance,
accounts: addresses.map((address) => {
const info = infos[address];
return {
address,
name: info.name || 'Unnamed',
uuid: info.uuid
};
})
});
api.subscribe('eth_blockNumber', this.onNewBlockNumber);
})
.catch((error) => {
console.error('attachInterface', error);
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './application';

View File

@@ -0,0 +1,129 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import IdentityIcon from '../../IdentityIcon';
import { formatBlockNumber, formatCoins, formatEth } from '../../format';
import styles from '../events.css';
const EMPTY_COLUMN = (
<td></td>
);
export default class Event extends Component {
static contextTypes = {
accounts: PropTypes.array.isRequired
}
static propTypes = {
event: PropTypes.object,
value: PropTypes.object,
price: PropTypes.object,
fromAddress: PropTypes.string,
toAddress: PropTypes.string
}
render () {
const { event, fromAddress, toAddress, price, value } = this.props;
const { blockNumber, state, type } = event;
const cls = `${styles.event} ${styles[state]} ${styles[type.toLowerCase()]}`;
return (
<tr className={ cls }>
{ this.renderBlockNumber(blockNumber) }
{ this.renderType(type) }
{ this.renderValue(value) }
{ this.renderPrice(price) }
{ this.renderAddress(fromAddress) }
{ this.renderAddress(toAddress) }
</tr>
);
}
renderBlockNumber (blockNumber) {
return (
<td className={ styles.blocknumber }>
{ formatBlockNumber(blockNumber) }
</td>
);
}
renderAddress (address) {
if (!address) {
return EMPTY_COLUMN;
}
return (
<td className={ styles.account }>
<IdentityIcon address={ address } />
{ this.renderAddressName(address) }
</td>
);
}
renderAddressName (address) {
const { accounts } = this.context;
const account = accounts.find((_account) => _account.address === address);
if (account) {
return (
<div className={ styles.name }>
{ account.name }
</div>
);
}
return (
<div className={ styles.address }>
{ address }
</div>
);
}
renderPrice (price) {
if (!price) {
return EMPTY_COLUMN;
}
return (
<td className={ styles.ethvalue }>
{ formatEth(price) }<small> ETH</small>
</td>
);
}
renderValue (value) {
if (!value) {
return EMPTY_COLUMN;
}
return (
<td className={ styles.gavvalue }>
{ formatCoins(value) }<small> GAV</small>
</td>
);
}
renderType (type) {
return (
<td className={ styles.type }>
{ type }
</td>
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './event';

View File

@@ -0,0 +1,38 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import Event from '../Event';
export default class EventBuyin extends Component {
static propTypes = {
event: PropTypes.object
}
render () {
const { event } = this.props;
const { buyer, price, amount } = event.params;
return (
<Event
event={ event }
fromAddress={ buyer }
value={ amount }
price={ price } />
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './eventBuyin';

View File

@@ -0,0 +1,36 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import Event from '../Event';
export default class EventNewTranch extends Component {
static propTypes = {
event: PropTypes.object
}
render () {
const { event } = this.props;
const { price } = event.params;
return (
<Event
event={ event }
price={ price } />
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './eventNewTranch';

View File

@@ -0,0 +1,38 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import Event from '../Event';
export default class EventRefund extends Component {
static propTypes = {
event: PropTypes.object
}
render () {
const { event } = this.props;
const { buyer, price, amount } = event.params;
return (
<Event
event={ event }
fromAddress={ buyer }
value={ amount }
price={ price } />
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './eventRefund';

View File

@@ -0,0 +1,38 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import Event from '../Event';
export default class EventTransfer extends Component {
static propTypes = {
event: PropTypes.object
}
render () {
const { event } = this.props;
const { from, to, value } = event.params;
return (
<Event
event={ event }
fromAddress={ from }
toAddress={ to }
value={ value } />
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './eventTransfer';

View File

@@ -0,0 +1,94 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.events {
padding: 4em 2em;
}
.list {
width: 100%;
border: none;
border-spacing: 0;
}
.list td {
vertical-align: top;
padding: 4px 0.5em;
max-height: 32px;
}
.event {
line-height: 32px;
vertical-align: top;
}
.blocknumber,
.ethvalue,
.gavvalue {
font-family: 'Roboto Mono', monospace;
}
.blocknumber,
.gavvalue {
text-align: right;
}
.ethvalue {
text-align: center;
}
.type {
}
.account {
}
.account img {
margin-bottom: -11px;
}
.address {
}
.name {
text-transform: uppercase;
}
.event div {
display: inline;
margin-right: 1em;
vertical-align: top;
}
.mined {
}
.pending {
opacity: 0.5;
}
.buyin {
}
.refund {
}
.transfer {
}
.newtranch {
background: rgba(50, 250, 50, 0.1);
}

View File

@@ -0,0 +1,158 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { api } from '../parity';
import EventBuyin from './EventBuyin';
import EventNewTranch from './EventNewTranch';
import EventRefund from './EventRefund';
import EventTransfer from './EventTransfer';
import styles from './events.css';
export default class Events extends Component {
static childContextTypes = {
accounts: PropTypes.array
}
static contextTypes = {
contract: PropTypes.object.isRequired,
instance: PropTypes.object.isRequired
}
static propTypes = {
accounts: PropTypes.array
}
state = {
allEvents: [],
minedEvents: [],
pendingEvents: []
}
componentDidMount () {
this.setupFilters();
}
render () {
return (
<div className={ styles.events }>
<table className={ styles.list }>
<tbody>
{ this.renderEvents() }
</tbody>
</table>
</div>
);
}
renderEvents () {
const { allEvents } = this.state;
if (!allEvents.length) {
return null;
}
return allEvents
.map((event) => {
switch (event.type) {
case 'Buyin':
return <EventBuyin key={ event.key } event={ event } />;
case 'NewTranch':
return <EventNewTranch key={ event.key } event={ event } />;
case 'Refund':
return <EventRefund key={ event.key } event={ event } />;
case 'Transfer':
return <EventTransfer key={ event.key } event={ event } />;
}
});
}
getChildContext () {
const { accounts } = this.props;
return {
accounts
};
}
setupFilters () {
const { contract } = this.context;
const sortEvents = (a, b) => b.blockNumber.cmp(a.blockNumber) || b.logIndex.cmp(a.logIndex);
const logToEvent = (log) => {
const key = api.util.sha3(JSON.stringify(log));
const { blockNumber, logIndex, transactionHash, transactionIndex, params, type } = log;
return {
type: log.event,
state: type,
blockNumber,
logIndex,
transactionHash,
transactionIndex,
params,
key
};
};
const options = {
fromBlock: 0,
toBlock: 'pending',
limit: 50
};
contract.subscribe(null, options, (error, _logs) => {
if (error) {
console.error('setupFilters', error);
return;
}
if (!_logs.length) {
return;
}
const logs = _logs.map(logToEvent);
const minedEvents = logs
.filter((log) => log.state === 'mined')
.reverse()
.concat(this.state.minedEvents)
.sort(sortEvents);
const pendingEvents = logs
.filter((log) => log.state === 'pending')
.reverse()
.concat(this.state.pendingEvents.filter((event) => {
return !logs.find((log) => {
const isMined = (log.state === 'mined') && (log.transactionHash === event.transactionHash);
const isPending = (log.state === 'pending') && (log.key === event.key);
return isMined || isPending;
});
}))
.sort(sortEvents);
const allEvents = pendingEvents.concat(minedEvents);
this.setState({
allEvents,
minedEvents,
pendingEvents
});
});
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './events';

View File

@@ -0,0 +1,23 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.icon {
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 0.5em;
}

View File

@@ -0,0 +1,36 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { api } from '../parity';
import styles from './identityIcon.css';
export default class IdentityIcon extends Component {
static propTypes = {
address: PropTypes.string.isRequired
}
render () {
const { address } = this.props;
return (
<img
className={ styles.icon }
src={ api.util.createIdentityImg(address, 4) } />
);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './identityIcon';

View File

@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './loading';

View File

@@ -0,0 +1,21 @@
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.loading {
width: 100%;
text-align: center;
padding-top: 2em;
}

Some files were not shown because too many files have changed in this diff Show More