diff --git a/src/App.js b/src/App.js index fc8024a..31d1289 100644 --- a/src/App.js +++ b/src/App.js @@ -6,6 +6,7 @@ import { constants } from './utils/constants' import { getNetworkBranch } from './utils/utils' import { inject, observer } from 'mobx-react' import messages from './utils/messages' +import { enableWallet } from './utils/getWeb3' import './assets/stylesheets/index.css' @@ -42,28 +43,31 @@ class App extends Component { const { commonStore, contractsStore } = this.props if (!commonStore.loading) { - if (!contractsStore.injectedWeb3) { - commonStore.hideLoading() - swal({ - title: 'Error', - html: messages.NO_METAMASK_MSG, - type: 'error' + enableWallet(contractsStore.updateKeys) + .then(() => { + if (!contractsStore.injectedWeb3) { + swal({ + title: 'Error', + html: messages.NO_METAMASK_MSG, + type: 'error' + }) + } else if (!contractsStore.networkMatch) { + swal({ + title: 'Warning!', + html: messages.networkMatchError(contractsStore.netId), + type: 'warning' + }) + } else if (!contractsStore.isValidVotingKey) { + swal({ + title: 'Warning!', + html: messages.invalidVotingKeyMsg(contractsStore.votingKey), + type: 'warning' + }) + } }) - } else if (!contractsStore.networkMatch) { - commonStore.hideLoading() - swal({ - title: 'Warning!', - html: messages.networkMatchError(contractsStore.netId), - type: 'warning' + .catch(error => { + swal('Error', error.message, 'error') }) - } else if (contractsStore.votingKey && !contractsStore.isValidVotingKey) { - commonStore.hideLoading() - swal({ - title: 'Warning!', - html: messages.invalidVotingKeyMsg(contractsStore.votingKey), - type: 'warning' - }) - } } return } diff --git a/src/components/BallotCard/index.js b/src/components/BallotCard/index.js index 9db8426..f4a76fd 100644 --- a/src/components/BallotCard/index.js +++ b/src/components/BallotCard/index.js @@ -10,6 +10,7 @@ import { inject, observer } from 'mobx-react' import messages from '../../utils/messages' import { observable, action, computed } from 'mobx' import { sendTransactionByVotingKey } from '../../utils/helpers' +import { enableWallet } from '../../utils/getWeb3' const ACCEPT = 1 const REJECT = 2 @@ -374,6 +375,27 @@ export class BallotCard extends React.Component { this.quorumState = await this.repeatGetProperty(contractsStore, votingType, id, 'getQuorumState', 0) } + networkAndKeyValidation = async () => { + const { contractsStore } = this.props + try { + await enableWallet(contractsStore.updateKeys) + } catch (error) { + swal('Error', error.message, 'error') + return false + } + if (contractsStore.isEmptyVotingKey) { + swal('Warning!', messages.NO_METAMASK_MSG, 'warning') + return false + } else if (!contractsStore.networkMatch) { + swal('Warning!', messages.networkMatchError(contractsStore.netId), 'warning') + return false + } else if (!contractsStore.isValidVotingKey) { + swal('Warning!', messages.invalidVotingKeyMsg(contractsStore.votingKey), 'warning') + return false + } + return true + } + vote = async ({ choice }) => { if (this.isCanceled) { swal('Warning!', messages.INVALID_VOTE_MSG, 'warning') @@ -383,18 +405,13 @@ export class BallotCard extends React.Component { swal('Warning!', messages.ballotIsNotActiveMsg(this.timeTo.displayValue), 'warning') return } - const { commonStore, contractsStore, id, votingType, ballotsStore, pos } = this.props - const { push } = this.props.routing - if (!contractsStore.votingKey) { - swal('Warning!', messages.NO_METAMASK_MSG, 'warning') - return - } else if (!contractsStore.networkMatch) { - swal('Warning!', messages.networkMatchError(contractsStore.netId), 'warning') - return - } else if (!contractsStore.isValidVotingKey) { - swal('Warning!', messages.invalidVotingKeyMsg(contractsStore.votingKey), 'warning') + + if (!(await this.networkAndKeyValidation())) { return } + + const { commonStore, contractsStore, id, votingType, ballotsStore, pos } = this.props + const { push } = this.props.routing commonStore.showLoading() let isValidVote = await this.isValidVote() if (!isValidVote) { @@ -473,6 +490,11 @@ export class BallotCard extends React.Component { const { votingState, contractsStore, commonStore, ballotsStore, votingType, id, pos } = this.props const { push } = this.props.routing const contract = this.getContract(contractsStore, votingType) + + if (!(await this.networkAndKeyValidation())) { + return + } + let canCancel = true if (!this.timeToCancel.val) { @@ -525,16 +547,11 @@ export class BallotCard extends React.Component { } const { commonStore, contractsStore, id, votingType, ballotsStore, pos } = this.props const { push } = this.props.routing - if (!contractsStore.votingKey) { - swal('Warning!', messages.NO_METAMASK_MSG, 'warning') - return - } else if (!contractsStore.networkMatch) { - swal('Warning!', messages.networkMatchError(contractsStore.netId), 'warning') - return - } else if (!contractsStore.isValidVotingKey) { - swal('Warning!', messages.invalidVotingKeyMsg(contractsStore.votingKey), 'warning') + + if (!(await this.networkAndKeyValidation())) { return } + if (this.isFinalized) { swal('Warning!', messages.ALREADY_FINALIZED_MSG, 'warning') return diff --git a/src/components/BallotKeysMetadata/index.js b/src/components/BallotKeysMetadata/index.js index 2015263..3d1bccb 100644 --- a/src/components/BallotKeysMetadata/index.js +++ b/src/components/BallotKeysMetadata/index.js @@ -45,7 +45,7 @@ export class BallotKeysMetadata extends React.Component { Minimum {minThreshold} from {validatorsLength} validators are required to pass the  proposal -
  • You can create {keys} ballot(s) for keys
  • +
  • You can create {Number(keys)} ballot(s) for keys
  • - You can create {validatorLimitsMinThreshold} ballot(s) for consensus + You can create {Number(validatorLimitsMinThreshold)} ballot(s) for consensus
  • -
  • You can create {proxy} ballot(s) for proxy
  • +
  • You can create {Number(proxy)} ballot(s) for proxy
  • ) diff --git a/src/contracts/VotingToChangeKeys.contract.js b/src/contracts/VotingToChangeKeys.contract.js index be61d85..5b486f9 100644 --- a/src/contracts/VotingToChangeKeys.contract.js +++ b/src/contracts/VotingToChangeKeys.contract.js @@ -90,7 +90,7 @@ export default class VotingToChangeKeys { return _limitPerValidator - _activeBallots } - async minBallotDuration() { - return await this.instance.methods.minBallotDuration().call() + minBallotDuration() { + return this.instance.methods.minBallotDuration().call() } } diff --git a/src/contracts/VotingToChangeMinThreshold.contract.js b/src/contracts/VotingToChangeMinThreshold.contract.js index 827d903..fb3d3c0 100644 --- a/src/contracts/VotingToChangeMinThreshold.contract.js +++ b/src/contracts/VotingToChangeMinThreshold.contract.js @@ -82,7 +82,7 @@ export default class VotingToChangeMinThreshold { return _limitPerValidator - _activeBallots } - async minBallotDuration() { - return await this.instance.methods.minBallotDuration().call() + minBallotDuration() { + return this.instance.methods.minBallotDuration().call() } } diff --git a/src/contracts/VotingToChangeProxy.contract.js b/src/contracts/VotingToChangeProxy.contract.js index b207ad0..4e7a251 100644 --- a/src/contracts/VotingToChangeProxy.contract.js +++ b/src/contracts/VotingToChangeProxy.contract.js @@ -78,7 +78,7 @@ export default class VotingToChangeProxy { return _limitPerValidator - _activeBallots } - async minBallotDuration() { - return await this.instance.methods.minBallotDuration().call() + minBallotDuration() { + return this.instance.methods.minBallotDuration().call() } } diff --git a/src/index.js b/src/index.js index 4025217..5f7c621 100644 --- a/src/index.js +++ b/src/index.js @@ -38,7 +38,7 @@ class AppMainRouter extends Component { initChain = () => { const netId = window.sessionStorage.netId - getWeb3(netId, this.onAccountChange) + getWeb3(netId, contractsStore.updateKeys) .then(async web3Config => { await this.initialize(web3Config) commonStore.hideLoading() @@ -88,13 +88,9 @@ class AppMainRouter extends Component { await Promise.all(promises) - await this.setKeys(web3Config.defaultAccount) + await contractsStore.updateKeys(web3Config.defaultAccount) - contractsStore.getKeysBallotThreshold() - contractsStore.getProxyBallotThreshold() - contractsStore.getBallotCancelingThreshold() - - await contractsStore.getBallotsLimits() + await contractsStore.getMinBallotDurationsAndThresholds() await contractsStore.getAllValidatorMetadata() await contractsStore.getAllBallots() @@ -109,18 +105,6 @@ class AppMainRouter extends Component { this.initChain() } - onAccountChange = account => { - this.setKeys(account) - } - - setKeys = async account => { - await contractsStore.setMiningKey(account) - await contractsStore.setVotingKey(account) - - console.log('votingKey', contractsStore.votingKey) - console.log('miningKey', contractsStore.miningKey) - } - render() { return ( diff --git a/src/stores/ContractsStore.js b/src/stores/ContractsStore.js index 1ec1914..5d98682 100644 --- a/src/stores/ContractsStore.js +++ b/src/stores/ContractsStore.js @@ -49,39 +49,26 @@ class ContractsStore { @observable injectedWeb3 constructor() { - this.votingKey = null - this.miningKey = null + this.votingKey = '0x0000000000000000000000000000000000000000' + this.miningKey = '0x0000000000000000000000000000000000000000' this.validatorsMetadata = {} this.validatorLimits = { keys: null, minThreshold: null, proxy: null } this.minBallotDuration = { keys: 0, minThreshold: 0, proxy: 0 } this.injectedWeb3 = false } + @computed + get isEmptyVotingKey() { + return !this.votingKey || this.votingKey === '0x0000000000000000000000000000000000000000' + } + @computed get isValidVotingKey() { + if (this.isEmptyVotingKey) return false if (this.miningKey && this.miningKey !== '0x0000000000000000000000000000000000000000') return true return false } - @action('Get keys ballot threshold') - getKeysBallotThreshold = async () => { - this.keysBallotThreshold = await this.ballotsStorage.instance.methods.getBallotThreshold(1).call() - this.minThresholdBallotThreshold = this.keysBallotThreshold - } - - @action('Get proxy ballot threshold') - getProxyBallotThreshold = async () => { - this.proxyBallotThreshold = await this.ballotsStorage.instance.methods.getProxyThreshold().call() - this.emissionFundsBallotThreshold = this.proxyBallotThreshold - } - - @action('Get ballot canceling threshold') - getBallotCancelingThreshold = async () => { - this.ballotCancelingThreshold = this.votingToManageEmissionFunds - ? Number(await this.votingToManageEmissionFunds.ballotCancelingThreshold()) - : 0 - } - @action('Set web3Instance') setWeb3Instance = web3Config => { this.web3Instance = web3Config.web3Instance @@ -206,12 +193,32 @@ class ContractsStore { @action('Set mining key') setMiningKey = async account => { - try { - this.miningKey = await this.keysManager.instance.methods.miningKeyByVoting(account).call() - } catch (e) { - console.log(e) - this.miningKey = '0x0000000000000000000000000000000000000000' + let miningKey = '0x0000000000000000000000000000000000000000' + if (account && account !== '0x0000000000000000000000000000000000000000') { + try { + miningKey = await this.keysManager.instance.methods.miningKeyByVoting(account).call() + } catch (e) { + console.log(e) + } } + this.miningKey = miningKey + } + + @action('Update keys') + updateKeys = async account => { + account = account || '0x0000000000000000000000000000000000000000' + + if (this.votingKey && this.votingKey.toLowerCase() === account.toLowerCase()) { + return + } + + this.setVotingKey(account) + await this.setMiningKey(account) + + console.log('votingKey', this.votingKey) + console.log('miningKey', this.miningKey) + + await this.getBallotsLimits() } @action('Get all keys ballots') @@ -410,41 +417,63 @@ class ContractsStore { async getBallotsLimits() { return new Promise(async resolve => { if (this.web3Instance && this.netId) { - const limitPerValidator = await this.ballotsStorage.instance.methods.getBallotLimitPerValidator().call() + let keysLimit = 0 + let minThresholdLimit = 0 + let proxyLimit = 0 - const getKeysLimit = await this.votingToChangeKeys.getBallotLimit(this.miningKey, limitPerValidator) - const getMinThresholdLimit = await this.votingToChangeMinThreshold.getBallotLimit( - this.miningKey, - limitPerValidator - ) - const getProxyLimit = await this.votingToChangeProxy.getBallotLimit(this.miningKey, limitPerValidator) + if (this.isValidVotingKey) { + const limitPerValidator = await this.ballotsStorage.instance.methods.getBallotLimitPerValidator().call() + keysLimit = await this.votingToChangeKeys.getBallotLimit(this.miningKey, limitPerValidator) + minThresholdLimit = await this.votingToChangeMinThreshold.getBallotLimit(this.miningKey, limitPerValidator) + proxyLimit = await this.votingToChangeProxy.getBallotLimit(this.miningKey, limitPerValidator) + } - const getKeysMinBallotDuration = await this.votingToChangeKeys.minBallotDuration() - const getMinThresholdMinBallotDuration = await this.votingToChangeMinThreshold.minBallotDuration() - const getProxyMinBallotDuration = await this.votingToChangeProxy.minBallotDuration() + this.validatorLimits.keys = keysLimit + this.validatorLimits.minThreshold = minThresholdLimit + this.validatorLimits.proxy = proxyLimit + } + resolve() + }) + } + + @action + async getMinBallotDurationsAndThresholds() { + return new Promise(async resolve => { + if (this.web3Instance && this.netId) { + const getKeysMinBallotDuration = this.votingToChangeKeys.minBallotDuration() + const getMinThresholdMinBallotDuration = this.votingToChangeMinThreshold.minBallotDuration() + const getProxyMinBallotDuration = this.votingToChangeProxy.minBallotDuration() + + const getBallotThreshold = this.ballotsStorage.instance.methods.getBallotThreshold(1).call() + const getProxyThreshold = this.ballotsStorage.instance.methods.getProxyThreshold().call() + const getBallotCancelingThreshold = this.votingToManageEmissionFunds + ? this.votingToManageEmissionFunds.ballotCancelingThreshold() + : 0 await Promise.all([ - getKeysLimit, - getMinThresholdLimit, - getProxyLimit, getKeysMinBallotDuration, getMinThresholdMinBallotDuration, - getProxyMinBallotDuration + getProxyMinBallotDuration, + getBallotThreshold, + getProxyThreshold, + getBallotCancelingThreshold ]).then( ([ - keysLimit, - minThresholdLimit, - proxyLimit, keysMinBallotDuration, minThresholdMinBallotDuration, - proxyMinBallotDuration + proxyMinBallotDuration, + keysBallotThreshold, + proxyBallotThreshold, + cancelingThreshold ]) => { - this.validatorLimits.keys = keysLimit - this.validatorLimits.minThreshold = minThresholdLimit - this.validatorLimits.proxy = proxyLimit this.minBallotDuration.keys = keysMinBallotDuration this.minBallotDuration.minThreshold = minThresholdMinBallotDuration this.minBallotDuration.proxy = proxyMinBallotDuration + this.keysBallotThreshold = keysBallotThreshold + this.minThresholdBallotThreshold = keysBallotThreshold + this.proxyBallotThreshold = proxyBallotThreshold + this.emissionFundsBallotThreshold = proxyBallotThreshold + this.ballotCancelingThreshold = cancelingThreshold resolve() } ) diff --git a/src/utils/getWeb3.js b/src/utils/getWeb3.js index 9553b48..6c3fc92 100644 --- a/src/utils/getWeb3.js +++ b/src/utils/getWeb3.js @@ -1,21 +1,33 @@ import Web3 from 'web3' import helpers from './helpers' import { constants } from './constants' +import messages from './messages' const defaultNetId = helpers.netIdByBranch(constants.CORE) -export default async function getWeb3(netId, onAccountChange) { +export async function enableWallet(updateKeys) { + if (window.ethereum) { + try { + await window.ethereum.enable() + } catch (e) { + await updateKeys(null) + throw Error(messages.USER_DENIED_ACCOUNT_ACCESS) + } + + const web3 = new Web3(window.ethereum) + const accounts = await web3.eth.getAccounts() + + await updateKeys(accounts[0]) + } +} + +export default async function getWeb3(netId, updateKeys) { let web3 = null // Checking if Web3 has been injected by the browser (Mist/MetaMask) if (window.ethereum) { web3 = new Web3(window.ethereum) console.log('Injected web3 detected.') - try { - await window.ethereum.enable() - } catch (e) { - throw Error('You have denied access to your accounts') - } window.ethereum.autoRefreshOnNetworkChange = true } else if (window.web3) { web3 = new Web3(window.web3.currentProvider) @@ -63,12 +75,12 @@ export default async function getWeb3(netId, onAccountChange) { } if (web3.currentProvider.publicConfigStore) { - let currentAccount = defaultAccount ? defaultAccount.toLowerCase() : '' + let currentAccount = defaultAccount ? defaultAccount.toLowerCase() : null web3.currentProvider.publicConfigStore.on('update', function(obj) { const account = obj.selectedAddress - if (account && account !== currentAccount) { + if (account !== currentAccount) { currentAccount = account - onAccountChange(account) + updateKeys(account) } }) }