Merge branch 'bootstrap' of https://github.com/status-im/contracts into bootstrap
This commit is contained in:
commit
264f30ff2b
|
@ -1,3 +1,9 @@
|
|||
{
|
||||
"extends": "airbnb"
|
||||
}
|
||||
"extends": "airbnb",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"rules": {
|
||||
"react/prop-types": 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import ERC20Token from 'Embark/contracts/ERC20Token';
|
||||
import { actions as accountActions } from '../reducers/accounts'
|
||||
|
||||
const { receiveAccounts } = accountActions
|
||||
export const fetchAndDispatchAccountsWithBalances = (web3, dispatch) => {
|
||||
web3.eth.getAccounts((err, addresses) => {
|
||||
if (addresses) {
|
||||
const defaultAccount = web3.eth.defaultAccount || addresses[0]
|
||||
const accounts = addresses.map(async address => {
|
||||
const balance = await web3.eth.getBalance(address, 'latest')
|
||||
const ERC20TokenBalance = await ERC20Token.methods.balanceOf(address).call()
|
||||
return { address, balance, ERC20TokenBalance }
|
||||
})
|
||||
Promise.all(accounts).then(accounts => {
|
||||
dispatch(receiveAccounts(defaultAccount, accounts))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,112 +1,66 @@
|
|||
import web3 from "Embark/web3"
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import web3 from 'Embark/web3'
|
||||
import React from 'react';
|
||||
import { Nav, MenuItem , NavDropdown} from 'react-bootstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import { Nav, MenuItem, NavDropdown } from 'react-bootstrap';
|
||||
import Blockies from 'react-blockies';
|
||||
|
||||
import { string, bool, func, arrayOf, shape } from 'prop-types';
|
||||
import { getAccounts, getDefaultAccount, accountsIsLoading, actions as accountActions } from '../reducers/accounts';
|
||||
import './accountlist.css';
|
||||
|
||||
class AccList extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classNameNavDropdown: props.classNameNavDropdown,
|
||||
defaultAccount: "0x0000000000000000000000000000000000000000",
|
||||
addresses: [],
|
||||
balances: []
|
||||
}
|
||||
__embarkContext.execWhenReady(() => {
|
||||
this.load()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
load() {
|
||||
web3.eth.getAccounts((err, addresses) => {
|
||||
if (addresses) {
|
||||
var defaultAccount = web3.eth.defaultAccount;
|
||||
if(!defaultAccount){
|
||||
web3.eth.defaultAccount = addresses[0];
|
||||
}
|
||||
|
||||
var balances = [];
|
||||
balances.length == addresses.length;
|
||||
addresses.forEach((address, index) => {
|
||||
web3.eth.getBalance(address, 'latest', (err, balance) => {
|
||||
balances[index] = balance;
|
||||
if(index+1 == balances.length){
|
||||
this.setState({
|
||||
balances: balances
|
||||
});
|
||||
}
|
||||
})
|
||||
})
|
||||
this.setState({
|
||||
defaultAccount: defaultAccount,
|
||||
addresses: addresses
|
||||
});
|
||||
|
||||
} else {
|
||||
console.log("No addresses available.");
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
setDefaultAccount(index) {
|
||||
var defaultAcc = this.state.addresses[index];
|
||||
if(defaultAcc){
|
||||
web3.eth.defaultAccount = defaultAcc;
|
||||
this.setState({defaultAccount: defaultAcc });
|
||||
} else {
|
||||
console.log("invalid account")
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
var accsTitle;
|
||||
var accsList = [];
|
||||
if (this.state.addresses) {
|
||||
accsTitle = this.state.defaultAccount;
|
||||
this.state.addresses.forEach(
|
||||
(name, index) => {
|
||||
accsList.push(
|
||||
<MenuItem key={index} onClick={(e) => this.setDefaultAccount(index) }>
|
||||
<div className="account">
|
||||
<div className="accountIdenticon">
|
||||
<Blockies seed={name} />
|
||||
</div>
|
||||
<div className="accountHexString">
|
||||
{name}
|
||||
</div>
|
||||
<div className="accountBalance">
|
||||
Ξ {this.state.balances[index] / (10**18)}
|
||||
</div>
|
||||
</div>
|
||||
</MenuItem>);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="accounts">
|
||||
<div className="selectedIdenticon">
|
||||
<Blockies seed={ this.state.defaultAccount } />
|
||||
const AccList = ({
|
||||
accounts, defaultAccount, changeAccount, isLoading, classNameNavDropdown,
|
||||
}) => (
|
||||
<React.Fragment>
|
||||
{!isLoading ?
|
||||
<div className="accounts">
|
||||
<div className="selectedIdenticon">
|
||||
<Blockies seed={defaultAccount} />
|
||||
</div>
|
||||
<div className="accountList">
|
||||
<Nav>
|
||||
<NavDropdown key={1} title={defaultAccount} id="basic-nav-dropdown" className={classNameNavDropdown}>
|
||||
{accounts.map(account => (
|
||||
<MenuItem key={account.address} onClick={() => changeAccount(account.address)}>
|
||||
<div className="account">
|
||||
<div className="accountIdenticon">
|
||||
<Blockies seed={account.address} />
|
||||
</div>
|
||||
<div className="accountList">
|
||||
<Nav>
|
||||
<NavDropdown key={1} title={accsTitle} id="basic-nav-dropdown" className={ this.state.classNameNavDropdown }>
|
||||
{accsList}
|
||||
</NavDropdown>
|
||||
</Nav>
|
||||
<div className="accountHexString">
|
||||
{account.address}
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
<div className="accountBalance">
|
||||
Ξ {account.balance / (10 ** 18)}
|
||||
</div>
|
||||
</div>
|
||||
</MenuItem>
|
||||
))}
|
||||
</NavDropdown>
|
||||
</Nav>
|
||||
</div>
|
||||
</div>
|
||||
: <div>Loading...</div>}
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
}
|
||||
AccList.propTypes = {
|
||||
accounts: arrayOf(shape({ address: string, balance: string })).isRequired,
|
||||
defaultAccount: string,
|
||||
changeAccount: func.isRequired,
|
||||
isLoading: bool.isRequired,
|
||||
classNameNavDropdown: string
|
||||
}
|
||||
|
||||
export default AccList;
|
||||
const mapStateToProps = state => ({
|
||||
accounts: getAccounts(state),
|
||||
defaultAccount: getDefaultAccount(state),
|
||||
isLoading: accountsIsLoading(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
changeAccount(address) {
|
||||
web3.eth.defaultAccount = address;
|
||||
dispatch(accountActions.updateDefaultAccount(address));
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AccList);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import ERC20Token from 'Embark/contracts/ERC20Token';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap';
|
||||
import { getCurrentAccount, accountsIsLoading } from '../reducers/accounts';
|
||||
|
||||
class ERC20TokenUI extends React.Component {
|
||||
|
||||
|
@ -67,59 +69,64 @@ class ERC20TokenUI extends React.Component {
|
|||
console.log(txt);
|
||||
}
|
||||
|
||||
render(){
|
||||
return (<React.Fragment>
|
||||
|
||||
<h3> Read your account token balance </h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<HelpBlock>Your test token balance is <span className="accountBalance">{this.state.accountBalance}</span></HelpBlock>
|
||||
<Button bsStyle="primary" onClick={(e) => this.getDefaultAccountBalance()}>Get Balance</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> Read account token balance</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<label>
|
||||
Of:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.accountB}
|
||||
onChange={(e) => this.balanceOf(e)} />
|
||||
</label>
|
||||
<label>
|
||||
<HelpBlock><span className="balanceOf">{this.state.balanceOf}</span></HelpBlock>
|
||||
</label>
|
||||
|
||||
</FormGroup>
|
||||
</Form>
|
||||
render() {
|
||||
const { account, isLoading } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<h3> Read your account token balance </h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
{!isLoading && <HelpBlock>Your test token balance is <span className="accountBalance">{account.ERC20TokenBalance}</span></HelpBlock>}
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> Read account token balance</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<label>
|
||||
Of:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.accountB}
|
||||
onChange={(e) => this.balanceOf(e)} />
|
||||
</label>
|
||||
<label>
|
||||
<HelpBlock><span className="balanceOf">{this.state.balanceOf}</span></HelpBlock>
|
||||
</label>
|
||||
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> Transfer/Approve token balance</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<label>
|
||||
To:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.transferTo}
|
||||
onChange={(e) => this.update_transferTo(e) } />
|
||||
</label>
|
||||
<label>
|
||||
Amount:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.transferAmount}
|
||||
onChange={(e) => this.update_transferAmount(e) } />
|
||||
</label>
|
||||
<Button bsStyle="primary" onClick={(e) => this.transfer(e)}>Transfer</Button>
|
||||
<Button bsStyle="primary" onClick={(e) => this.approve(e)}>Approve</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> Transfer/Approve token balance</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<label>
|
||||
To:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.transferTo}
|
||||
onChange={(e) => this.update_transferTo(e) } />
|
||||
</label>
|
||||
<label>
|
||||
Amount:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.transferAmount}
|
||||
onChange={(e) => this.update_transferAmount(e) } />
|
||||
</label>
|
||||
<Button bsStyle="primary" onClick={(e) => this.transfer(e)}>Transfer</Button>
|
||||
<Button bsStyle="primary" onClick={(e) => this.approve(e)}>Approve</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ERC20TokenUI;
|
||||
const mapStateToProps = state => ({
|
||||
account: getCurrentAccount(state),
|
||||
isLoading: accountsIsLoading(state),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(ERC20TokenUI);
|
||||
|
|
|
@ -3,6 +3,8 @@ import TestToken from 'Embark/contracts/TestToken';
|
|||
import React from 'react';
|
||||
import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap';
|
||||
import ERC20TokenUI from './erc20token';
|
||||
import { connect } from 'react-redux';
|
||||
import { actions as accountActions } from '../reducers/accounts';
|
||||
|
||||
class TestTokenUI extends React.Component {
|
||||
|
||||
|
@ -17,18 +19,20 @@ class TestTokenUI extends React.Component {
|
|||
this.setState({amountToMint: e.target.value});
|
||||
}
|
||||
|
||||
mint(e){
|
||||
mint(e){
|
||||
const { addToBalance } = this.props;
|
||||
e.preventDefault();
|
||||
|
||||
var value = parseInt(this.state.amountToMint, 10);
|
||||
|
||||
if (EmbarkJS.isNewWeb3()) {
|
||||
TestToken.methods.mint(value).send({from: web3.eth.defaultAccount});
|
||||
TestToken.methods.mint(value).send({from: web3.eth.defaultAccount})
|
||||
.then(r => { addToBalance(value) });
|
||||
} else {
|
||||
TestToken.mint(value);
|
||||
this._addToLog("#blockchain", "TestToken.mint(" + value + ")");
|
||||
TestToken.mint(value).send({from: web3.eth.defaultAccount})
|
||||
.then(r => { addToBalance(value) });
|
||||
}
|
||||
this._addToLog(TestToken.options.address +".mint("+value+").send({from: " + web3.eth.defaultAccount + "})");
|
||||
console.log(TestToken.options.address +".mint("+value+").send({from: " + web3.eth.defaultAccount + "})");
|
||||
}
|
||||
|
||||
render(){
|
||||
|
@ -51,4 +55,10 @@ class TestTokenUI extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default TestTokenUI;
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
addToBalance(amount) {
|
||||
dispatch(accountActions.addToErc20TokenBalance(amount));
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps)(TestTokenUI);
|
||||
|
|
|
@ -44,4 +44,4 @@ class App extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<App></App>, document.getElementById('app'));
|
||||
export default App;
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
<body class="container">
|
||||
<div id="app">
|
||||
</div>
|
||||
<script src="js/dapp.js"></script>
|
||||
<script src="js/index.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import store from './store/configureStore';
|
||||
import App from './dapp';
|
||||
import init from './store/init'
|
||||
import './dapp.css';
|
||||
|
||||
init();
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>,
|
||||
document.getElementById('app')
|
||||
);
|
|
@ -0,0 +1,54 @@
|
|||
import { createTypes, actionCreator } from 'redux-action-creator'
|
||||
import { createSelector } from 'reselect'
|
||||
|
||||
export const types = createTypes([
|
||||
'RECEIVE_ACCOUNTS',
|
||||
'UPDATE_DEFAULT_ACCOUNT',
|
||||
'ADD_TO_ERC20_TOKEN_BALANCE'
|
||||
], 'ACCOUNTS')
|
||||
export const actions = {
|
||||
receiveAccounts: actionCreator(types.RECEIVE_ACCOUNTS, 'defaultAccount','accounts'),
|
||||
updateDefaultAccount: actionCreator(types.UPDATE_DEFAULT_ACCOUNT, 'defaultAccount'),
|
||||
addToErc20TokenBalance: actionCreator(types.ADD_TO_ERC20_TOKEN_BALANCE, 'amount')
|
||||
}
|
||||
|
||||
export default function(state = { loading: true, accounts: [] }, action) {
|
||||
switch (action.type) {
|
||||
case types.RECEIVE_ACCOUNTS: {
|
||||
const { defaultAccount, accounts } = action.payload
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
defaultAccount,
|
||||
accounts
|
||||
}
|
||||
}
|
||||
case types.UPDATE_DEFAULT_ACCOUNT: {
|
||||
const { defaultAccount } = action.payload
|
||||
return { ...state, defaultAccount }
|
||||
}
|
||||
case types.ADD_TO_ERC20_TOKEN_BALANCE: {
|
||||
const currentAccount = { ...getCurrentAccount({accounts: state}) }
|
||||
currentAccount.ERC20TokenBalance = Number(currentAccount.ERC20TokenBalance) + Number(action.payload.amount)
|
||||
const accounts = [ ...state.accounts ]
|
||||
const idx = accounts.findIndex(a => a.address === currentAccount.address)
|
||||
accounts[idx] = currentAccount
|
||||
return {
|
||||
...state,
|
||||
accounts
|
||||
}
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export const getAccountState = state => state.acounts;
|
||||
export const getAccounts = state => state.accounts.accounts;
|
||||
export const getDefaultAccount = state => state.accounts.defaultAccount;
|
||||
export const accountsIsLoading = state => state.accounts.loading;
|
||||
export const getCurrentAccount = createSelector(
|
||||
getDefaultAccount,
|
||||
getAccounts,
|
||||
(defaultAccount, accounts) => accounts.find(a => a.address === defaultAccount)
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import accounts from './accounts'
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
accounts
|
||||
});
|
||||
|
||||
export default rootReducer;
|
|
@ -0,0 +1,11 @@
|
|||
import { createStore, applyMiddleware } from 'redux';
|
||||
import rootReducer from '../reducers/rootReducer';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
const store = createStore(
|
||||
rootReducer,
|
||||
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
|
||||
applyMiddleware(thunk)
|
||||
);
|
||||
|
||||
export default store;
|
|
@ -0,0 +1,12 @@
|
|||
import web3 from "Embark/web3"
|
||||
import EmbarkJS from 'Embark/EmbarkJS'
|
||||
import store from './configureStore'
|
||||
import { fetchAndDispatchAccountsWithBalances } from '../actions/accounts'
|
||||
|
||||
const dispatch = action => store.dispatch(action)
|
||||
|
||||
export default () => {
|
||||
__embarkContext.execWhenReady(async () => {
|
||||
fetchAndDispatchAccountsWithBalances(web3, dispatch)
|
||||
})
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
"contracts": ["contracts/**"],
|
||||
"app": {
|
||||
"js/dapp.js": ["app/dapp.js"],
|
||||
"js/index.js": ["app/index.js"],
|
||||
"index.html": "app/index.html",
|
||||
"images/": ["app/images/**"]
|
||||
},
|
||||
|
|
|
@ -18,10 +18,16 @@
|
|||
},
|
||||
"homepage": "https://github.com/status-im/contracts#readme",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.6.1",
|
||||
"react": "^16.3.2",
|
||||
"react-blockies": "^1.3.0",
|
||||
"react-bootstrap": "^0.32.1",
|
||||
"react-dom": "^16.3.2"
|
||||
"react-dom": "^16.3.2",
|
||||
"react-redux": "^5.0.7",
|
||||
"redux": "^4.0.0",
|
||||
"redux-action-creator": "^2.3.0",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"reselect": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
|
|
Loading…
Reference in New Issue