Merge pull request #50 from rstormsf/core

(Feature) Add dropdown for selecting mining key, add limit notification
This commit is contained in:
Victor Baranov 2018-01-06 10:03:25 +03:00 committed by GitHub
commit 93ded37229
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 291 additions and 142 deletions

5
jsconfig.json Normal file
View File

@ -0,0 +1,5 @@
{
"compilerOptions": {
"experimentalDecorators": true
}
}

30
package-lock.json generated
View File

@ -4588,6 +4588,13 @@
} }
} }
}, },
"string_decoder": {
"version": "1.0.1",
"bundled": true,
"requires": {
"safe-buffer": "5.0.1"
}
},
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
@ -4597,13 +4604,6 @@
"strip-ansi": "3.0.1" "strip-ansi": "3.0.1"
} }
}, },
"string_decoder": {
"version": "1.0.1",
"bundled": true,
"requires": {
"safe-buffer": "5.0.1"
}
},
"stringstream": { "stringstream": {
"version": "0.0.5", "version": "0.0.5",
"bundled": true, "bundled": true,
@ -10293,6 +10293,14 @@
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
}, },
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"requires": {
"safe-buffer": "5.1.1"
}
},
"string-length": { "string-length": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz",
@ -10335,14 +10343,6 @@
"function-bind": "1.1.1" "function-bind": "1.1.1"
} }
}, },
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"requires": {
"safe-buffer": "5.1.1"
}
},
"stringstream": { "stringstream": {
"version": "0.0.5", "version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",

View File

@ -2,7 +2,7 @@
"name": "poa-dapps-voting", "name": "poa-dapps-voting",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"homepage": "https://poanetwork.github.io/poa-dapps-voting", "homepage": "https://poanetwork.github.io/",
"dependencies": { "dependencies": {
"autoprefixer": "7.1.6", "autoprefixer": "7.1.6",
"babel-core": "6.26.0", "babel-core": "6.26.0",

View File

@ -38,9 +38,10 @@ class App extends Component {
const { commonStore } = this.props; const { commonStore } = this.props;
const currentPath = this.props.location.pathname; const currentPath = this.props.location.pathname;
let showNavPan = let showNavPan =
currentPath == `${commonStore.rootPath}` currentPath === `${commonStore.rootPath}`
|| currentPath == `${commonStore.rootPath}/` || currentPath === "/"
|| currentPath == `${commonStore.rootPath}/active`; || currentPath === `${commonStore.rootPath}/`
|| currentPath === `${commonStore.rootPath}/active`;
return showNavPan; return showNavPan;
} }
@ -61,6 +62,7 @@ class App extends Component {
{loading} {loading}
<Header /> <Header />
{nav} {nav}
<Route exact path={`/`} render={this.onBallotsRender}/>
<Route exact path={`${commonStore.rootPath}/`} render={this.onBallotsRender}/> <Route exact path={`${commonStore.rootPath}/`} render={this.onBallotsRender}/>
<Route exact path={`${commonStore.rootPath}/active`} render={this.onActiveBallotsRender}/> <Route exact path={`${commonStore.rootPath}/active`} render={this.onActiveBallotsRender}/>
<Route path={`${commonStore.rootPath}/new`} render={this.onNewBallotRender}/> <Route path={`${commonStore.rootPath}/new`} render={this.onNewBallotRender}/>

View File

@ -772,6 +772,10 @@ button {
.ballots-footer { .ballots-footer {
display: flex; display: flex;
align-items: center;
justify-content: space-between; }
.ballots-footer-left {
display: inline-flex;
align-items: center; } align-items: center; }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.ballots-footer { .ballots-footer {

View File

@ -1,7 +1,12 @@
.ballots-footer { .ballots-footer {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between;
&-left {
display: inline-flex;
align-items: center;
}
@media screen and (max-width: $tablet-width) { @media screen and (max-width: $tablet-width) {
padding-top: $tablet-indent; padding-top: $tablet-indent;
} }

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import moment from 'moment'; import moment from 'moment';
import { observable, action, computed } from "mobx"; import { observable, action, computed, autorun } from "mobx";
import { inject, observer } from "mobx-react"; import { inject, observer } from "mobx-react";
import { toAscii } from "../helpers"; import { toAscii } from "../helpers";
import { constants } from "../constants"; import { constants } from "../constants";
@ -265,6 +265,15 @@ export class BallotKeysCard extends React.Component {
this.getProgress(); this.getProgress();
this.getIsFinalized(); this.getIsFinalized();
} }
componentDidMount() {
this.interval = setInterval(() => {
this.calcTimeToFinish()
}, 1000)
}
componentWillUnmount() {
window.clearInterval(this.interval);
}
hideCard = () => { hideCard = () => {
let { commonStore } = this.props; let { commonStore } = this.props;
@ -360,9 +369,12 @@ export class BallotKeysCard extends React.Component {
</div> </div>
<hr /> <hr />
<div className="ballots-footer"> <div className="ballots-footer">
<div className="ballots-footer-left">
<button type="button" onClick={(e) => this.finalize(e)} className="ballots-footer-finalize">Finalize ballot</button> <button type="button" onClick={(e) => this.finalize(e)} className="ballots-footer-finalize">Finalize ballot</button>
<p>{constants.CARD_FINALIZE_DESCRIPTION}</p> <p>{constants.CARD_FINALIZE_DESCRIPTION}</p>
</div> </div>
<div type="button" className="ballots-i--vote ballots-i--vote_no">Keys Ballot ID: {this.props.id}</div>
</div>
</div> </div>
); );
} }

View File

@ -1,10 +1,13 @@
import React from 'react'; import React from "react";
import { inject, observer } from "mobx-react"; import { inject, observer } from "mobx-react";
import Select from "react-select";
import "react-select/dist/react-select.css";
@inject("ballotStore") @inject("ballotStore", "contractsStore")
@observer @observer
export class BallotKeysMetadata extends React.Component { export class BallotKeysMetadata extends React.Component {
render() { render() {
const options = this.props.contractsStore.validatorsMetadata.slice();
const { ballotStore } = this.props; const { ballotStore } = this.props;
return ( return (
<div> <div>
@ -24,9 +27,12 @@ export class BallotKeysMetadata extends React.Component {
<div className="right"> <div className="right">
<div className="form-el"> <div className="form-el">
<label htmlFor="key">Mining Key</label> <label htmlFor="key">Mining Key</label>
<input type="text" id="key" <Select.Creatable
name="form-field-name"
id="key"
value={ballotStore.ballotKeys.miningKey} value={ballotStore.ballotKeys.miningKey}
onChange={e => ballotStore.changeBallotMetadata(e, "miningKey", "ballotKeys")} onChange={ballotStore.setMiningKey}
options={options}
/> />
<p className="hint"> <p className="hint">
Mining key address of validator to vote for. Example: 0xc70760D23557A4FDE612C0bE63b26EBD023C51Ee. Mining key address of validator to vote for. Example: 0xc70760D23557A4FDE612C0bE63b26EBD023C51Ee.

View File

@ -6,6 +6,8 @@ import { toAscii } from "../helpers";
import { constants } from "../constants"; import { constants } from "../constants";
import swal from 'sweetalert2'; import swal from 'sweetalert2';
const ACCEPT = 1;
const REJECT = 2;
@inject("commonStore", "contractsStore", "routing") @inject("commonStore", "contractsStore", "routing")
@observer @observer
export class BallotMinThresholdCard extends React.Component { export class BallotMinThresholdCard extends React.Component {
@ -132,7 +134,7 @@ export class BallotMinThresholdCard extends React.Component {
return isActive; return isActive;
} }
vote = async (e, _type) => { vote = async ({choice}) => {
const { commonStore, contractsStore, id } = this.props; const { commonStore, contractsStore, id } = this.props;
const { push } = this.props.routing; const { push } = this.props.routing;
if (!contractsStore.isValidVotingKey) { if (!contractsStore.isValidVotingKey) {
@ -146,7 +148,7 @@ export class BallotMinThresholdCard extends React.Component {
swal("Warning!", constants.INVALID_VOTE_MSG, "warning"); swal("Warning!", constants.INVALID_VOTE_MSG, "warning");
return; return;
} }
contractsStore.votingToChangeMinThreshold.vote(id, _type, contractsStore.votingKey) contractsStore.votingToChangeMinThreshold.vote(id, choice, contractsStore.votingKey)
.on("receipt", () => { .on("receipt", () => {
commonStore.hideLoading(); commonStore.hideLoading();
swal("Congratulations!", constants.VOTED_SUCCESS_MSG, "success").then((result) => { swal("Congratulations!", constants.VOTED_SUCCESS_MSG, "success").then((result) => {
@ -249,26 +251,26 @@ export class BallotMinThresholdCard extends React.Component {
</div> </div>
<div className="ballots-i-scale"> <div className="ballots-i-scale">
<div className="ballots-i-scale-column"> <div className="ballots-i-scale-column">
<button type="button" onClick={(e) => this.vote(e, this.props.id, 1)} className="ballots-i--vote ballots-i--vote_yes">Vote</button> <button type="button" onClick={(e) => this.vote({choice: REJECT})} className="ballots-i--vote ballots-i--vote_no">No</button>
<div className="vote-scale--container">
<p className="vote-scale--value">Yes</p>
<p className="vote-scale--votes">Votes: {this.votesForNumber}</p>
<p className="vote-scale--percentage">{this.votesForPercents}%</p>
<div className="vote-scale">
<div className="vote-scale--fill vote-scale--fill_yes" style={{width: `${this.votesForPercents}%`}}></div>
</div>
</div>
</div>
<div className="ballots-i-scale-column">
<div className="vote-scale--container"> <div className="vote-scale--container">
<p className="vote-scale--value">No</p> <p className="vote-scale--value">No</p>
<p className="vote-scale--votes">Votes: {this.votesAgainstNumber}</p> <p className="vote-scale--votes">Votes: {this.votesAgainstNumber}</p>
<p className="vote-scale--percentage">{this.votesAgainstPercents}%</p> <p className="vote-scale--percentage">{this.votesAgainstPercents}%</p>
<div className="vote-scale"> <div className="vote-scale">
<div className="vote-scale--fill vote-scale--fill_no" style={{width: `${this.votesAgainstPercents}%`}}></div> <div className="vote-scale--fill vote-scale--fill_yes" style={{width: `${this.votesAgainstPercents}%`}}></div>
</div> </div>
</div> </div>
<button type="button" onClick={(e) => this.vote(e, 2)} className="ballots-i--vote ballots-i--vote_no">Vote</button> </div>
<div className="ballots-i-scale-column">
<div className="vote-scale--container">
<p className="vote-scale--value">Yes</p>
<p className="vote-scale--votes">Votes: {this.votesForNumber}</p>
<p className="vote-scale--percentage">{this.votesForPercents}%</p>
<div className="vote-scale">
<div className="vote-scale--fill vote-scale--fill_no" style={{width: `${this.votesForPercents}%`}}></div>
</div>
</div>
<button type="button" onClick={(e) => this.vote({choice: ACCEPT})} className="ballots-i--vote ballots-i--vote_yes">Yes</button>
</div> </div>
</div> </div>
<div className="info"> <div className="info">
@ -276,9 +278,12 @@ export class BallotMinThresholdCard extends React.Component {
</div> </div>
<hr /> <hr />
<div className="ballots-footer"> <div className="ballots-footer">
<div className="ballots-footer-left">
<button type="button" onClick={(e) => this.finalize(e)} className="ballots-footer-finalize">Finalize ballot</button> <button type="button" onClick={(e) => this.finalize(e)} className="ballots-footer-finalize">Finalize ballot</button>
<p>{constants.CARD_FINALIZE_DESCRIPTION}</p> <p>{constants.CARD_FINALIZE_DESCRIPTION}</p>
</div> </div>
<div type="button" className="ballots-i--vote ballots-i--vote_no">Consensus Ballot ID: {this.props.id}</div>
</div>
</div> </div>
); );
} }

View File

@ -6,6 +6,8 @@ import { toAscii } from "../helpers";
import { constants } from "../constants"; import { constants } from "../constants";
import swal from 'sweetalert2'; import swal from 'sweetalert2';
const ACCEPT = 1;
const REJECT = 2;
@inject("commonStore", "contractsStore", "ballotStore", "routing") @inject("commonStore", "contractsStore", "ballotStore", "routing")
@observer @observer
export class BallotProxyCard extends React.Component { export class BallotProxyCard extends React.Component {
@ -140,7 +142,7 @@ export class BallotProxyCard extends React.Component {
return isActive; return isActive;
} }
vote = async (e, _type) => { vote = async ({choice}) => {
const { commonStore, contractsStore, id } = this.props; const { commonStore, contractsStore, id } = this.props;
const { push } = this.props.routing; const { push } = this.props.routing;
if (!contractsStore.isValidVotingKey) { if (!contractsStore.isValidVotingKey) {
@ -154,7 +156,7 @@ export class BallotProxyCard extends React.Component {
swal("Warning!", constants.INVALID_VOTE_MSG, "warning"); swal("Warning!", constants.INVALID_VOTE_MSG, "warning");
return; return;
} }
contractsStore.votingToChangeProxy.vote(id, _type, contractsStore.votingKey) contractsStore.votingToChangeProxy.vote(id, choice, contractsStore.votingKey)
.on("receipt", () => { .on("receipt", () => {
commonStore.hideLoading(); commonStore.hideLoading();
swal("Congratulations!", constants.VOTED_SUCCESS_MSG, "success").then((result) => { swal("Congratulations!", constants.VOTED_SUCCESS_MSG, "success").then((result) => {
@ -267,26 +269,26 @@ export class BallotProxyCard extends React.Component {
</div> </div>
<div className="ballots-i-scale"> <div className="ballots-i-scale">
<div className="ballots-i-scale-column"> <div className="ballots-i-scale-column">
<button type="button" onClick={(e) => this.vote(e, 1)} className="ballots-i--vote ballots-i--vote_yes">Vote</button> <button type="button" onClick={(e) => this.vote({choice: REJECT})} className="ballots-i--vote ballots-i--vote_no">No</button>
<div className="vote-scale--container">
<p className="vote-scale--value">Yes</p>
<p className="vote-scale--votes">Votes: {this.votesForNumber}</p>
<p className="vote-scale--percentage">{this.votesForPercents}%</p>
<div className="vote-scale">
<div className="vote-scale--fill vote-scale--fill_yes" style={{width: `${this.votesForPercents}%`}}></div>
</div>
</div>
</div>
<div className="ballots-i-scale-column">
<div className="vote-scale--container"> <div className="vote-scale--container">
<p className="vote-scale--value">No</p> <p className="vote-scale--value">No</p>
<p className="vote-scale--votes">Votes: {this.votesAgainstNumber}</p> <p className="vote-scale--votes">Votes: {this.votesAgainstNumber}</p>
<p className="vote-scale--percentage">{this.votesAgainstPercents}%</p> <p className="vote-scale--percentage">{this.votesAgainstPercents}%</p>
<div className="vote-scale"> <div className="vote-scale">
<div className="vote-scale--fill vote-scale--fill_no" style={{width: `${this.votesAgainstPercents}%`}}></div> <div className="vote-scale--fill vote-scale--fill_yes" style={{width: `${this.votesAgainstPercents}%`}}></div>
</div> </div>
</div> </div>
<button type="button" onClick={(e) => this.vote(e, 2)} className="ballots-i--vote ballots-i--vote_no">Vote</button> </div>
<div className="ballots-i-scale-column">
<div className="vote-scale--container">
<p className="vote-scale--value">Yes</p>
<p className="vote-scale--votes">Votes: {this.votesForNumber}</p>
<p className="vote-scale--percentage">{this.votesForPercents}%</p>
<div className="vote-scale">
<div className="vote-scale--fill vote-scale--fill_no" style={{width: `${this.votesForPercents}%`}}></div>
</div>
</div>
<button type="button" onClick={(e) => this.vote({choice: ACCEPT})} className="ballots-i--vote ballots-i--vote_yes">Yes</button>
</div> </div>
</div> </div>
<div className="info"> <div className="info">
@ -294,9 +296,12 @@ export class BallotProxyCard extends React.Component {
</div> </div>
<hr /> <hr />
<div className="ballots-footer"> <div className="ballots-footer">
<div className="ballots-footer-left">
<button type="button" onClick={(e) => this.finalize(e)} className="ballots-footer-finalize">Finalize ballot</button> <button type="button" onClick={(e) => this.finalize(e)} className="ballots-footer-finalize">Finalize ballot</button>
<p>{constants.CARD_FINALIZE_DESCRIPTION}</p> <p>{constants.CARD_FINALIZE_DESCRIPTION}</p>
</div> </div>
<div type="button" className="ballots-i--vote ballots-i--vote_no">Proxy Ballot ID: {this.props.id}</div>
</div>
</div> </div>
); );
} }

View File

@ -53,7 +53,6 @@ export class NewBallot extends React.Component {
commonStore.hideLoading(); commonStore.hideLoading();
return false; return false;
} }
let isMiningKeyAddress = contractsStore.web3Instance.isAddress(ballotStore.ballotKeys.miningKey); let isMiningKeyAddress = contractsStore.web3Instance.isAddress(ballotStore.ballotKeys.miningKey);
if (!isMiningKeyAddress) { if (!isMiningKeyAddress) {
@ -105,7 +104,6 @@ export class NewBallot extends React.Component {
ballotStore.ballotKeys.keysBallotType, ballotStore.ballotKeys.keysBallotType,
contractsStore.votingKey contractsStore.votingKey
]; ];
console.log(inputToMethod)
let method = contractsStore.votingToChangeKeys.createVotingForKeys( let method = contractsStore.votingToChangeKeys.createVotingForKeys(
...inputToMethod ...inputToMethod
); );
@ -120,7 +118,6 @@ export class NewBallot extends React.Component {
ballotStore.ballotMinThreshold.proposedValue, ballotStore.ballotMinThreshold.proposedValue,
contractsStore.votingKey contractsStore.votingKey
]; ];
console.log(inputToMethod)
let method = contractsStore.votingToChangeMinThreshold.createBallotToChangeThreshold( let method = contractsStore.votingToChangeMinThreshold.createBallotToChangeThreshold(
...inputToMethod ...inputToMethod
); );
@ -189,7 +186,7 @@ export class NewBallot extends React.Component {
let validator = ballotStore.isNewValidatorPersonalData ? <Validator />: ""; let validator = ballotStore.isNewValidatorPersonalData ? <Validator />: "";
let keysTypes = ballotStore.isBallotForKey ? <KeysTypes />: ""; let keysTypes = ballotStore.isBallotForKey ? <KeysTypes />: "";
let metadata let metadata
let minThreshold let minThreshold = 0;
switch (ballotStore.ballotType) { switch (ballotStore.ballotType) {
case ballotStore.BallotType.keys: case ballotStore.BallotType.keys:
metadata = <BallotKeysMetadata />; metadata = <BallotKeysMetadata />;
@ -218,7 +215,7 @@ export class NewBallot extends React.Component {
checked={ballotStore.isBallotForKey} checked={ballotStore.isBallotForKey}
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.keys)} onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.keys)}
/> />
<label htmlFor="ballot-for-validators" className="radio">Ballot for validators</label> <label htmlFor="ballot-for-validators" className="radio">Validator Management Ballot</label>
<p className="hint"> <p className="hint">
Ballot to add, remove or swap any type of key for existing or new validators. Ballot to add, remove or swap any type of key for existing or new validators.
</p> </p>
@ -231,7 +228,7 @@ export class NewBallot extends React.Component {
checked={ballotStore.isBallotForMinThreshold} checked={ballotStore.isBallotForMinThreshold}
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.minThreshold)} onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.minThreshold)}
/> />
<label htmlFor="ballot-for-consensus" className="radio">Ballot for consensus</label> <label htmlFor="ballot-for-consensus" className="radio">Consenus Threshold Ballot</label>
<p className="hint"> <p className="hint">
Ballot to change the minimum threshold for consensus to vote for keys. Ballot to change the minimum threshold for consensus to vote for keys.
</p> </p>
@ -244,7 +241,7 @@ export class NewBallot extends React.Component {
checked={ballotStore.isBallotForProxy} checked={ballotStore.isBallotForProxy}
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.proxy)} onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.proxy)}
/> />
<label htmlFor="ballot-for-proxy" className="radio">Ballot for proxy</label> <label htmlFor="ballot-for-proxy" className="radio">Modify Proxy Contract Ballot</label>
<p className="hint"> <p className="hint">
Ballot to change one of the proxy contracts. Ballot to change one of the proxy contracts.
</p> </p>
@ -257,7 +254,10 @@ export class NewBallot extends React.Component {
{metadata} {metadata}
<div className="new-form-footer"> <div className="new-form-footer">
<div className="info"> <div className="info">
Minimum {minThreshold} from {contractsStore.validatorsLength} validators required to pass the proposal Minimum {minThreshold} from {contractsStore.validatorsLength} validators required to pass the proposal<br />
You can create {contractsStore.validatorLimits.keys} ballot for keys<br />
You can create {contractsStore.validatorLimits.minThreshold} ballot for consensus<br />
You can create {contractsStore.validatorLimits.proxy} ballot for proxy<br />
</div> </div>
<button type="button" className="add-ballot" onClick={e => this.onClick(e)}>Add ballot</button> <button type="button" className="add-ballot" onClick={e => this.onClick(e)}>Add ballot</button>
</div> </div>

View File

@ -1,13 +1,12 @@
import ballotsStorageAbi from './ballotsStorage.abi.json' import ballotsStorageAbi from './ballotsStorage.abi.json'
import Web3 from 'web3'; import Web3 from 'web3';
import {BALLOTS_STORAGE_ADDRESS} from './addresses'; import networkAddresses from './addresses';
console.log('Ballots Storage Address ' , BALLOTS_STORAGE_ADDRESS)
export default class POAConsensus { export default class POAConsensus {
constructor(){ constructor({web3, netId}){
if(window.web3.currentProvider){ const {BALLOTS_STORAGE_ADDRESS} = networkAddresses(netId);
let web3_10 = new Web3(window.web3.currentProvider); console.log('Ballots Storage Address ' , BALLOTS_STORAGE_ADDRESS);
let web3_10 = new Web3(web3.currentProvider);
this.ballotsStorageInstance = new web3_10.eth.Contract(ballotsStorageAbi, BALLOTS_STORAGE_ADDRESS); this.ballotsStorageInstance = new web3_10.eth.Contract(ballotsStorageAbi, BALLOTS_STORAGE_ADDRESS);
} }
}
} }

View File

@ -1,15 +1,14 @@
import poaConsensusAbi from './poaConsensus.abi.json' import poaConsensusAbi from './poaConsensus.abi.json'
import Web3 from 'web3'; import Web3 from 'web3';
import {POA_ADDRESS} from './addresses'; import networkAddresses from './addresses';
console.log('POA Address ' , POA_ADDRESS)
export default class POAConsensus { export default class POAConsensus {
constructor(){ constructor({web3, netId}){
if(window.web3.currentProvider){ const {POA_ADDRESS} = networkAddresses(netId);
let web3_10 = new Web3(window.web3.currentProvider); console.log('POA Address ' , POA_ADDRESS)
let web3_10 = new Web3(web3.currentProvider);
this.poaInstance = new web3_10.eth.Contract(poaConsensusAbi, POA_ADDRESS); this.poaInstance = new web3_10.eth.Contract(poaConsensusAbi, POA_ADDRESS);
} }
}
async getValidators(){ async getValidators(){
return await this.poaInstance.methods.getValidators().call(); return await this.poaInstance.methods.getValidators().call();
} }

View File

@ -1,7 +1,7 @@
import MetadataAbi from './validatorMetadata.abi.json' import MetadataAbi from './validatorMetadata.abi.json'
import Web3 from 'web3'; import Web3 from 'web3';
import moment from 'moment'; import moment from 'moment';
import {METADATA_ADDRESS} from './addresses'; import networkAddresses from './addresses';
var toAscii = function(hex) { var toAscii = function(hex) {
var str = '', var str = '',
i = 0, i = 0,
@ -17,14 +17,14 @@ var toAscii = function(hex) {
return str; return str;
}; };
console.log('Metadata contract:', METADATA_ADDRESS)
export default class Metadata { export default class Metadata {
constructor(){ constructor({web3, netId}){
if(window.web3.currentProvider){ const {METADATA_ADDRESS} = networkAddresses(netId);
this.web3_10 = new Web3(window.web3.currentProvider); console.log('Metadata contract:', METADATA_ADDRESS)
this.web3_10 = new Web3(web3.currentProvider);
this.metadataInstance = new this.web3_10.eth.Contract(MetadataAbi, METADATA_ADDRESS); this.metadataInstance = new this.web3_10.eth.Contract(MetadataAbi, METADATA_ADDRESS);
} }
}
async getValidatorData({votingKey, miningKey}){ async getValidatorData({votingKey, miningKey}){
miningKey = miningKey || await this.getMiningByVoting(votingKey); miningKey = miningKey || await this.getMiningByVoting(votingKey);

View File

@ -1,15 +1,14 @@
import votingToChangeKeysABI from './votingToChangeKeys.abi.json' import votingToChangeKeysABI from './votingToChangeKeys.abi.json'
import Web3 from 'web3'; import Web3 from 'web3';
import {VOTING_TO_CHANGE_KEYS_ADDRESS} from './addresses' import networkAddresses from './addresses';
console.log('VotingToChangeKeys ', VOTING_TO_CHANGE_KEYS_ADDRESS)
export default class VotingToChangeKeys { export default class VotingToChangeKeys {
constructor(){ constructor({web3, netId}){
if(window.web3.currentProvider){ const {VOTING_TO_CHANGE_KEYS_ADDRESS} = networkAddresses(netId);
let web3_10 = new Web3(window.web3.currentProvider); console.log('VotingToChangeKeys ', VOTING_TO_CHANGE_KEYS_ADDRESS);
let web3_10 = new Web3(web3.currentProvider);
this.votingToChangeKeysInstance = new web3_10.eth.Contract(votingToChangeKeysABI, VOTING_TO_CHANGE_KEYS_ADDRESS); this.votingToChangeKeysInstance = new web3_10.eth.Contract(votingToChangeKeysABI, VOTING_TO_CHANGE_KEYS_ADDRESS);
} }
}
//setters //setters
createVotingForKeys(startTime, endTime, affectedKey, affectedKeyType, miningKey, ballotType, sender) { createVotingForKeys(startTime, endTime, affectedKey, affectedKeyType, miningKey, ballotType, sender) {
@ -68,4 +67,18 @@ export default class VotingToChangeKeys {
getAffectedKey(_id) { getAffectedKey(_id) {
return this.votingToChangeKeysInstance.methods.getAffectedKey(_id).call(); return this.votingToChangeKeysInstance.methods.getAffectedKey(_id).call();
} }
getMiningByVotingKey(_votingKey) {
return this.votingToChangeKeysInstance.methods.getMiningByVotingKey(_votingKey).call();
}
async getValidatorActiveBallots(_votingKey) {
const miningKey = await this.getMiningByVotingKey(_votingKey);
return await this.votingToChangeKeysInstance.methods.validatorActiveBallots(miningKey).call();
}
async getBallotLimit(_votingKey) {
const currentLimit = await this.votingToChangeKeysInstance.methods.getBallotLimitPerValidator().call();
return currentLimit - await this.getValidatorActiveBallots(_votingKey);
}
} }

View File

@ -1,15 +1,14 @@
import votingToChangeMinThresholdABI from './votingToChangeMinThreshold.abi.json' import votingToChangeMinThresholdABI from './votingToChangeMinThreshold.abi.json'
import Web3 from 'web3'; import Web3 from 'web3';
import {VOTING_TO_CHANGE_MIN_THRESHOLD} from './addresses' import networkAddresses from './addresses';
console.log('VotingToChangeMinThreshold ', VOTING_TO_CHANGE_MIN_THRESHOLD)
export default class VotingToChangeMinThreshold { export default class VotingToChangeMinThreshold {
constructor(){ constructor({web3, netId}){
if(window.web3.currentProvider){ const {VOTING_TO_CHANGE_MIN_THRESHOLD} = networkAddresses(netId);
let web3_10 = new Web3(window.web3.currentProvider); let web3_10 = new Web3(web3.currentProvider);
console.log('VotingToChangeMinThreshold ', VOTING_TO_CHANGE_MIN_THRESHOLD)
this.votingToChangeMinThresholdInstance = new web3_10.eth.Contract(votingToChangeMinThresholdABI, VOTING_TO_CHANGE_MIN_THRESHOLD); this.votingToChangeMinThresholdInstance = new web3_10.eth.Contract(votingToChangeMinThresholdABI, VOTING_TO_CHANGE_MIN_THRESHOLD);
} }
}
//setters //setters
createBallotToChangeThreshold(startTime, endTime, proposedValue, sender) { createBallotToChangeThreshold(startTime, endTime, proposedValue, sender) {
@ -60,4 +59,18 @@ export default class VotingToChangeMinThreshold {
getProposedValue(_id) { getProposedValue(_id) {
return this.votingToChangeMinThresholdInstance.methods.getProposedValue(_id).call(); return this.votingToChangeMinThresholdInstance.methods.getProposedValue(_id).call();
} }
getMiningByVotingKey(_votingKey) {
return this.votingToChangeMinThresholdInstance.methods.getMiningByVotingKey(_votingKey).call();
}
async getValidatorActiveBallots(_votingKey) {
const miningKey = await this.getMiningByVotingKey(_votingKey);
return await this.votingToChangeMinThresholdInstance.methods.validatorActiveBallots(miningKey).call();
}
async getBallotLimit(_votingKey) {
const currentLimit = await this.votingToChangeMinThresholdInstance.methods.getBallotLimitPerValidator().call();
return currentLimit - await this.getValidatorActiveBallots(_votingKey);
}
} }

View File

@ -1,15 +1,14 @@
import votingToChangeProxyABI from './votingToChangeProxy.abi.json' import votingToChangeProxyABI from './votingToChangeProxy.abi.json'
import Web3 from 'web3'; import Web3 from 'web3';
import {VOTING_TO_CHANGE_PROXY} from './addresses' import networkAddresses from './addresses';
console.log('VotingToChangeProxy ', VOTING_TO_CHANGE_PROXY)
export default class VotingToChangeProxy { export default class VotingToChangeProxy {
constructor(){ constructor({web3, netId}){
if(window.web3.currentProvider){ const {VOTING_TO_CHANGE_PROXY} = networkAddresses(netId);
let web3_10 = new Web3(window.web3.currentProvider); console.log('VotingToChangeProxy ', VOTING_TO_CHANGE_PROXY)
let web3_10 = new Web3(web3.currentProvider);
this.votingToChangeProxyInstance = new web3_10.eth.Contract(votingToChangeProxyABI, VOTING_TO_CHANGE_PROXY); this.votingToChangeProxyInstance = new web3_10.eth.Contract(votingToChangeProxyABI, VOTING_TO_CHANGE_PROXY);
} }
}
//setters //setters
createBallotToChangeProxyAddress(startTime, endTime, proposedValue, contractType, sender) { createBallotToChangeProxyAddress(startTime, endTime, proposedValue, contractType, sender) {
@ -64,4 +63,18 @@ export default class VotingToChangeProxy {
getContractType(_id) { getContractType(_id) {
return this.votingToChangeProxyInstance.methods.getContractType(_id).call(); return this.votingToChangeProxyInstance.methods.getContractType(_id).call();
} }
getMiningByVotingKey(_votingKey) {
return this.votingToChangeProxyInstance.methods.getMiningByVotingKey(_votingKey).call();
}
async getValidatorActiveBallots(_votingKey) {
const miningKey = await this.getMiningByVotingKey(_votingKey);
return await this.votingToChangeProxyInstance.methods.validatorActiveBallots(miningKey).call();
}
async getBallotLimit(_votingKey) {
const currentLimit = await this.votingToChangeProxyInstance.methods.getBallotLimitPerValidator().call();
return currentLimit - await this.getValidatorActiveBallots(_votingKey);
}
} }

View File

@ -1,8 +1,38 @@
module.exports = { // const local = {
// VOTING_TO_CHANGE_KEYS_ADDRESS: '0x758492834ed6454f41d6d3d6b73d6e46d4555429',
// VOTING_TO_CHANGE_MIN_THRESHOLD: '0xcbf043db3498b5064bd62341be0c0e3fb0344b1b',
// VOTING_TO_CHANGE_PROXY: '0xcb3f870269a3f7215eb87d9548ee5b7eff6396dd',
// BALLOTS_STORAGE_ADDRESS: '0x144947d78b932ea0dff14d75e1f7cd1b2f131426',
// METADATA_ADDRESS: '0x3111c94b9243a8a99d5a867e00609900e437e2c0',
// POA_ADDRESS: '0xf472e0e43570b9afaab67089615080cf7c20018d',
// }
const CORE_ADDRESSES = {
VOTING_TO_CHANGE_KEYS_ADDRESS: '0x49df4ec19243263e5db22da5865b4f482b8323a0', VOTING_TO_CHANGE_KEYS_ADDRESS: '0x49df4ec19243263e5db22da5865b4f482b8323a0',
VOTING_TO_CHANGE_MIN_THRESHOLD: '0x8829ebe113535826e8af17ed51f83755f675789a', VOTING_TO_CHANGE_MIN_THRESHOLD: '0x8829ebe113535826e8af17ed51f83755f675789a',
VOTING_TO_CHANGE_PROXY: '0x6b728399b41a38d4109f7af2213d4cc31ca87812', VOTING_TO_CHANGE_PROXY: '0x6b728399b41a38d4109f7af2213d4cc31ca87812',
BALLOTS_STORAGE_ADDRESS: '0x0d7590c7aedf1e7e85fc9a1ee88f6f17d3ba762f',
METADATA_ADDRESS: '0xcBB2912666c7e8023B7ec78B6842702eB26336aC', METADATA_ADDRESS: '0xcBB2912666c7e8023B7ec78B6842702eB26336aC',
POA_ADDRESS: '0x8bf38d4764929064f2d4d3a56520a76ab3df415b', POA_ADDRESS: '0x8bf38d4764929064f2d4d3a56520a76ab3df415b',
BALLOTS_STORAGE_ADDRESS: '0x0d7590c7aedf1e7e85fc9a1ee88f6f17d3ba762f'
} }
const SOKOL_ADDRESSES = {
VOTING_TO_CHANGE_KEYS_ADDRESS: '0x145a3d3bd5db8a0ad863b4949b6088d133726cdb',
VOTING_TO_CHANGE_MIN_THRESHOLD: '0xad623f870298774765bc5e56ebeafac721028867',
VOTING_TO_CHANGE_PROXY: '0x6fb85b2030a68a76ab237d2392b09e28e6f03fa9',
BALLOTS_STORAGE_ADDRESS: '0x1e0eaa06d02f965be2dfe0bc9ff52b2d82133461',
METADATA_ADDRESS: '0xce9ff1123223d13672cce06dd073d3749764daa6',
POA_ADDRESS: '0x8bf38d4764929064f2d4d3a56520a76ab3df415b',
}
module.exports = (netId) => {
switch (netId) {
case '77':
return SOKOL_ADDRESSES
case '99':
return CORE_ADDRESSES
default:
return CORE_ADDRESSES
}
}

View File

@ -29,6 +29,7 @@ let getWeb3 = () => {
errorMsg = constants.WRONG_NETWORK_MSG errorMsg = constants.WRONG_NETWORK_MSG
console.log('This is an unknown network.', netId) console.log('This is an unknown network.', netId)
} }
document.title = `${netIdName} - POA Network Governance DApp`
var defaultAccount = web3.eth.defaultAccount || null; var defaultAccount = web3.eth.defaultAccount || null;
if(defaultAccount === null){ if(defaultAccount === null){
reject({message: constants.NO_METAMASK_MSG}) reject({message: constants.NO_METAMASK_MSG})

View File

@ -27,24 +27,27 @@ class AppMainRouter extends Component {
commonStore.showLoading(); commonStore.showLoading();
getWeb3().then(async (web3Config) => { getWeb3().then(async (web3Config) => {
contractsStore.setWeb3Instance(web3Config); await contractsStore.setWeb3Instance(web3Config);
await contractsStore.setPoaConsensus(web3Config); await contractsStore.setPoaConsensus(web3Config);
contractsStore.setBallotsStorage(web3Config); await contractsStore.setBallotsStorage(web3Config);
await contractsStore.setVotingToChangeKeys(web3Config);
await contractsStore.setVotingToChangeMinThreshold(web3Config);
await contractsStore.setVotingToChangeProxy(web3Config);
await contractsStore.setValidatorMetadata(web3Config);
contractsStore.getValidatorsLength(); contractsStore.getValidatorsLength();
await contractsStore.getKeysBallotThreshold(); contractsStore.getKeysBallotThreshold();
contractsStore.getMinThresholdBallotThreshold(); contractsStore.getMinThresholdBallotThreshold();
contractsStore.getProxyBallotThreshold(); contractsStore.getProxyBallotThreshold();
contractsStore.setVotingToChangeKeys(web3Config);
contractsStore.setVotingToChangeMinThreshold(web3Config);
contractsStore.setVotingToChangeProxy(web3Config);
contractsStore.setValidatorMetadata(web3Config);
contractsStore.setVotingKey(web3Config);
contractsStore.getAllKeysBallots(); contractsStore.getAllKeysBallots();
contractsStore.getAllMinThresholdBallots(); contractsStore.getAllMinThresholdBallots();
contractsStore.getAllProxyBallots(); contractsStore.getAllProxyBallots();
contractsStore.setVotingKey(web3Config);
await contractsStore.setMiningKey(web3Config); await contractsStore.setMiningKey(web3Config);
console.log("votingKey", contractsStore.votingKey) contractsStore.getValidatorActiveBallots();
console.log("miningKey", contractsStore.miningKey) contractsStore.getAllValidatorMetadata();
console.log("votingKey", contractsStore.votingKey);
console.log("miningKey", contractsStore.miningKey);
commonStore.hideLoading();
}).catch((error) => { }).catch((error) => {
commonStore.hideLoading(); commonStore.hideLoading();
swal({ swal({

View File

@ -1,4 +1,4 @@
import { observable, computed, action } from 'mobx'; import { observable, computed, action, toJS } from 'mobx';
import moment from 'moment'; import moment from 'moment';
class BallotStore { class BallotStore {
@ -25,6 +25,7 @@ class BallotStore {
5: 'BallotsStorage' 5: 'BallotsStorage'
} }
@observable ballotType; @observable ballotType;
@observable keysBallotType;
@observable endTime; @observable endTime;
@observable ballotKeys; @observable ballotKeys;
@ -33,12 +34,12 @@ class BallotStore {
constructor() { constructor() {
this.ballotType = this.BallotType.keys; this.ballotType = null;
this.endTime = ""; this.endTime = "";
this.ballotKeys = { this.ballotKeys = {
keyType: this.KeyType.mining, keyType: null,
keysBallotType: this.KeysBallotType.add, keysBallotType: null,
//memo: "", //memo: "",
affectedKey: "", affectedKey: "",
miningKey: "" miningKey: ""
@ -126,7 +127,12 @@ class BallotStore {
this[parent][field] = newVal; this[parent][field] = newVal;
else else
this[field] = newVal; this[field] = newVal;
console.log("ballot metadata", field, parent?this[parent][field]:this[field]) console.log("ballot metadata", field, parent?this[parent][field]:this[field]);
}
@action("change ballot metadata")
setMiningKey = (value) => {
this.ballotKeys.miningKey = value;
console.log("ballot mining key", toJS(value));
} }
} }

View File

@ -19,7 +19,6 @@ import "babel-polyfill";
class ContractsStore { class ContractsStore {
@observable activeKeysBallotsIDs; @observable activeKeysBallotsIDs;
@observable poaConsensus; @observable poaConsensus;
@observable ballotsStorage; @observable ballotsStorage;
@observable votingToChangeKeys; @observable votingToChangeKeys;
@ -33,12 +32,15 @@ class ContractsStore {
@observable keysBallotThreshold; @observable keysBallotThreshold;
@observable minThresholdBallotThreshold; @observable minThresholdBallotThreshold;
@observable proxyBallotThreshold; @observable proxyBallotThreshold;
@observable validatorLimits;
@observable validatorsMetadata;
constructor() { constructor() {
this.votingKey = null; this.votingKey = null;
this.miningKey = null; this.miningKey = null;
this.activeKeysBallotsIDs = []; this.activeKeysBallotsIDs = [];
this.validatorsMetadata = [];
this.validatorLimits = {keys: null, minThreshold: null, proxy: null};
getWeb3().then(async (web3Config) => { getWeb3().then(async (web3Config) => {
contractsStore.setWeb3Instance(web3Config); contractsStore.setWeb3Instance(web3Config);
}) })
@ -55,8 +57,8 @@ class ContractsStore {
} }
@action("Get min threshold ballot threshold") @action("Get min threshold ballot threshold")
getMinThresholdBallotThreshold() { async getMinThresholdBallotThreshold() {
this.minThresholdBallotThreshold = this.keysBallotThreshold; this.minThresholdBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.methods.getBallotThreshold(1).call();
} }
@action("get proxy ballot threshold") @action("get proxy ballot threshold")
@ -67,47 +69,54 @@ class ContractsStore {
@action("Set web3Instance") @action("Set web3Instance")
setWeb3Instance = (web3Config) => { setWeb3Instance = (web3Config) => {
this.web3Instance = web3Config.web3Instance; this.web3Instance = web3Config.web3Instance;
this.netId = web3Config.netId;
} }
@action("Set PoA Consensus contract") @action("Set PoA Consensus contract")
setPoaConsensus = (web3Config) => { setPoaConsensus = (web3Config) => {
this.poaConsensus = new PoaConsensus({ this.poaConsensus = new PoaConsensus({
web3: web3Config.web3Instance web3: web3Config.web3Instance,
netId: web3Config.netId
}); });
} }
@action("Set Ballots Storage contract") @action("Set Ballots Storage contract")
setBallotsStorage = (web3Config) => { setBallotsStorage = (web3Config) => {
this.ballotsStorage = new BallotsStorage({ this.ballotsStorage = new BallotsStorage({
web3: web3Config.web3Instance web3: web3Config.web3Instance,
netId: web3Config.netId
}); });
} }
@action("Set VotingToChangeKeys contract") @action("Set VotingToChangeKeys contract")
setVotingToChangeKeys = (web3Config) => { setVotingToChangeKeys = (web3Config) => {
this.votingToChangeKeys = new VotingToChangeKeys({ this.votingToChangeKeys = new VotingToChangeKeys({
web3: web3Config.web3Instance web3: web3Config.web3Instance,
netId: web3Config.netId
}); });
} }
@action("Set VotingToChangeMinThreshold contract") @action("Set VotingToChangeMinThreshold contract")
setVotingToChangeMinThreshold = (web3Config) => { setVotingToChangeMinThreshold = (web3Config) => {
this.votingToChangeMinThreshold = new VotingToChangeMinThreshold({ this.votingToChangeMinThreshold = new VotingToChangeMinThreshold({
web3: web3Config.web3Instance web3: web3Config.web3Instance,
netId: web3Config.netId
}); });
} }
@action("Set VotingToChangeProxy contract") @action("Set VotingToChangeProxy contract")
setVotingToChangeProxy = (web3Config) => { setVotingToChangeProxy = (web3Config) => {
this.votingToChangeProxy = new VotingToChangeProxy({ this.votingToChangeProxy = new VotingToChangeProxy({
web3: web3Config.web3Instance web3: web3Config.web3Instance,
netId: web3Config.netId
}); });
} }
@action("Set ValidatorMetadata contract") @action("Set ValidatorMetadata contract")
setValidatorMetadata = (web3Config) => { setValidatorMetadata = (web3Config) => {
this.validatorMetadata = new ValidatorMetadata({ this.validatorMetadata = new ValidatorMetadata({
web3: web3Config.web3Instance web3: web3Config.web3Instance,
netId: web3Config.netId
}); });
} }
@ -173,6 +182,25 @@ class ContractsStore {
commonStore.hideLoading(); commonStore.hideLoading();
} }
} }
@action
async getValidatorActiveBallots() {
if(this.web3Instance && this.netId){
await this.setVotingToChangeKeys({web3Instance: this.web3Instance, netId: this.netId})
await this.setVotingToChangeMinThreshold({web3Instance: this.web3Instance, netId: this.netId})
await this.setVotingToChangeProxy({web3Instance: this.web3Instance, netId: this.netId})
this.validatorLimits.keys = await this.votingToChangeKeys.getBallotLimit(this.web3Instance.eth.defaultAccount);
this.validatorLimits.minThreshold = await this.votingToChangeMinThreshold.getBallotLimit(this.web3Instance.eth.defaultAccount);
this.validatorLimits.proxy = await this.votingToChangeProxy.getBallotLimit(this.web3Instance.eth.defaultAccount);
}
}
@action
async getAllValidatorMetadata() {
const keys = await this.poaConsensus.getValidators();
keys.forEach(async (key) => {
const metadata = await this.validatorMetadata.getValidatorData({miningKey: key})
this.validatorsMetadata.push({label: `${key} ${metadata.lastName}`, value: key})
})
}
} }
const contractsStore = new ContractsStore(); const contractsStore = new ContractsStore();