Merge pull request #213 from poanetwork/enable-wallet-only-when-needed

Call `window.ethereum.enable` only when that's really needed
This commit is contained in:
varasev 2020-01-09 17:38:53 +03:00 committed by GitHub
commit 23ee507584
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 178 additions and 124 deletions

View File

@ -6,6 +6,7 @@ import { constants } from './utils/constants'
import { getNetworkBranch } from './utils/utils' import { getNetworkBranch } from './utils/utils'
import { inject, observer } from 'mobx-react' import { inject, observer } from 'mobx-react'
import messages from './utils/messages' import messages from './utils/messages'
import { enableWallet } from './utils/getWeb3'
import './assets/stylesheets/index.css' import './assets/stylesheets/index.css'
@ -42,28 +43,31 @@ class App extends Component {
const { commonStore, contractsStore } = this.props const { commonStore, contractsStore } = this.props
if (!commonStore.loading) { if (!commonStore.loading) {
if (!contractsStore.injectedWeb3) { enableWallet(contractsStore.updateKeys)
commonStore.hideLoading() .then(() => {
swal({ if (!contractsStore.injectedWeb3) {
title: 'Error', swal({
html: messages.NO_METAMASK_MSG, title: 'Error',
type: '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) { .catch(error => {
commonStore.hideLoading() swal('Error', error.message, 'error')
swal({
title: 'Warning!',
html: messages.networkMatchError(contractsStore.netId),
type: 'warning'
}) })
} else if (contractsStore.votingKey && !contractsStore.isValidVotingKey) {
commonStore.hideLoading()
swal({
title: 'Warning!',
html: messages.invalidVotingKeyMsg(contractsStore.votingKey),
type: 'warning'
})
}
} }
return <NewBallot networkBranch={this.getVotingNetworkBranch()} /> return <NewBallot networkBranch={this.getVotingNetworkBranch()} />
} }

View File

@ -10,6 +10,7 @@ import { inject, observer } from 'mobx-react'
import messages from '../../utils/messages' import messages from '../../utils/messages'
import { observable, action, computed } from 'mobx' import { observable, action, computed } from 'mobx'
import { sendTransactionByVotingKey } from '../../utils/helpers' import { sendTransactionByVotingKey } from '../../utils/helpers'
import { enableWallet } from '../../utils/getWeb3'
const ACCEPT = 1 const ACCEPT = 1
const REJECT = 2 const REJECT = 2
@ -374,6 +375,27 @@ export class BallotCard extends React.Component {
this.quorumState = await this.repeatGetProperty(contractsStore, votingType, id, 'getQuorumState', 0) 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 }) => { vote = async ({ choice }) => {
if (this.isCanceled) { if (this.isCanceled) {
swal('Warning!', messages.INVALID_VOTE_MSG, 'warning') 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') swal('Warning!', messages.ballotIsNotActiveMsg(this.timeTo.displayValue), 'warning')
return return
} }
const { commonStore, contractsStore, id, votingType, ballotsStore, pos } = this.props
const { push } = this.props.routing if (!(await this.networkAndKeyValidation())) {
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')
return return
} }
const { commonStore, contractsStore, id, votingType, ballotsStore, pos } = this.props
const { push } = this.props.routing
commonStore.showLoading() commonStore.showLoading()
let isValidVote = await this.isValidVote() let isValidVote = await this.isValidVote()
if (!isValidVote) { if (!isValidVote) {
@ -473,6 +490,11 @@ export class BallotCard extends React.Component {
const { votingState, contractsStore, commonStore, ballotsStore, votingType, id, pos } = this.props const { votingState, contractsStore, commonStore, ballotsStore, votingType, id, pos } = this.props
const { push } = this.props.routing const { push } = this.props.routing
const contract = this.getContract(contractsStore, votingType) const contract = this.getContract(contractsStore, votingType)
if (!(await this.networkAndKeyValidation())) {
return
}
let canCancel = true let canCancel = true
if (!this.timeToCancel.val) { if (!this.timeToCancel.val) {
@ -525,16 +547,11 @@ export class BallotCard extends React.Component {
} }
const { commonStore, contractsStore, id, votingType, ballotsStore, pos } = this.props const { commonStore, contractsStore, id, votingType, ballotsStore, pos } = this.props
const { push } = this.props.routing const { push } = this.props.routing
if (!contractsStore.votingKey) {
swal('Warning!', messages.NO_METAMASK_MSG, 'warning') if (!(await this.networkAndKeyValidation())) {
return
} else if (!contractsStore.networkMatch) {
swal('Warning!', messages.networkMatchError(contractsStore.netId), 'warning')
return
} else if (!contractsStore.isValidVotingKey) {
swal('Warning!', messages.invalidVotingKeyMsg(contractsStore.votingKey), 'warning')
return return
} }
if (this.isFinalized) { if (this.isFinalized) {
swal('Warning!', messages.ALREADY_FINALIZED_MSG, 'warning') swal('Warning!', messages.ALREADY_FINALIZED_MSG, 'warning')
return return

View File

@ -45,7 +45,7 @@ export class BallotKeysMetadata extends React.Component {
<FormSelect <FormSelect
disabled={ballotStore.isNewValidatorPersonalData} disabled={ballotStore.isNewValidatorPersonalData}
hint="Mining key address of validator to vote for.<br />Example: 0xc70760D23557A4FDE612C0bE63b26EBD023C51Ee." hint="Mining key address of validator to vote for.<br />Example: 0xc70760D23557A4FDE612C0bE63b26EBD023C51Ee."
id="mining-key" id="mining-key-select"
name="form-field-name" name="form-field-name"
networkBranch={networkBranch} networkBranch={networkBranch}
onChange={ballotStore.setMiningKey} onChange={ballotStore.setMiningKey}

View File

@ -17,6 +17,7 @@ import { getNetworkBranch } from '../../utils/utils'
import { inject, observer } from 'mobx-react' import { inject, observer } from 'mobx-react'
import messages from '../../utils/messages' import messages from '../../utils/messages'
import { sendTransactionByVotingKey } from '../../utils/helpers' import { sendTransactionByVotingKey } from '../../utils/helpers'
import { enableWallet } from '../../utils/getWeb3'
@inject('commonStore', 'ballotStore', 'validatorStore', 'contractsStore', 'routing', 'ballotsStore') @inject('commonStore', 'ballotStore', 'validatorStore', 'contractsStore', 'routing', 'ballotsStore')
@observer @observer
@ -253,7 +254,14 @@ export class NewBallot extends React.Component {
const { commonStore, contractsStore, ballotStore, ballotsStore } = this.props const { commonStore, contractsStore, ballotStore, ballotsStore } = this.props
const { push } = this.props.routing const { push } = this.props.routing
if (!contractsStore.votingKey) { try {
await enableWallet(contractsStore.updateKeys)
} catch (error) {
swal('Error', error.message, 'error')
return
}
if (contractsStore.isEmptyVotingKey) {
swal('Warning!', messages.NO_METAMASK_MSG, 'warning') swal('Warning!', messages.NO_METAMASK_MSG, 'warning')
return return
} else if (!contractsStore.networkMatch) { } else if (!contractsStore.networkMatch) {

View File

@ -8,11 +8,11 @@ export const NewBallotMenuInfo = ({ minThreshold, validatorsLength, keys, valida
<li className="mn-NewBallotMenuInfo_ListItem"> <li className="mn-NewBallotMenuInfo_ListItem">
Minimum {minThreshold} from {validatorsLength} validators are required to pass the&nbsp; proposal Minimum {minThreshold} from {validatorsLength} validators are required to pass the&nbsp; proposal
</li> </li>
<li className="mn-NewBallotMenuInfo_ListItem">You can create {keys} ballot(s) for keys</li> <li className="mn-NewBallotMenuInfo_ListItem">You can create {Number(keys)} ballot(s) for keys</li>
<li className="mn-NewBallotMenuInfo_ListItem"> <li className="mn-NewBallotMenuInfo_ListItem">
You can create {validatorLimitsMinThreshold} ballot(s) for consensus You can create {Number(validatorLimitsMinThreshold)} ballot(s) for consensus
</li> </li>
<li className="mn-NewBallotMenuInfo_ListItem">You can create {proxy} ballot(s) for proxy</li> <li className="mn-NewBallotMenuInfo_ListItem">You can create {Number(proxy)} ballot(s) for proxy</li>
</ul> </ul>
</div> </div>
) )

View File

@ -90,7 +90,7 @@ export default class VotingToChangeKeys {
return _limitPerValidator - _activeBallots return _limitPerValidator - _activeBallots
} }
async minBallotDuration() { minBallotDuration() {
return await this.instance.methods.minBallotDuration().call() return this.instance.methods.minBallotDuration().call()
} }
} }

View File

@ -82,7 +82,7 @@ export default class VotingToChangeMinThreshold {
return _limitPerValidator - _activeBallots return _limitPerValidator - _activeBallots
} }
async minBallotDuration() { minBallotDuration() {
return await this.instance.methods.minBallotDuration().call() return this.instance.methods.minBallotDuration().call()
} }
} }

View File

@ -78,7 +78,7 @@ export default class VotingToChangeProxy {
return _limitPerValidator - _activeBallots return _limitPerValidator - _activeBallots
} }
async minBallotDuration() { minBallotDuration() {
return await this.instance.methods.minBallotDuration().call() return this.instance.methods.minBallotDuration().call()
} }
} }

View File

@ -38,7 +38,7 @@ class AppMainRouter extends Component {
initChain = () => { initChain = () => {
const netId = window.sessionStorage.netId const netId = window.sessionStorage.netId
getWeb3(netId, this.onAccountChange) getWeb3(netId, contractsStore.updateKeys)
.then(async web3Config => { .then(async web3Config => {
await this.initialize(web3Config) await this.initialize(web3Config)
commonStore.hideLoading() commonStore.hideLoading()
@ -88,13 +88,9 @@ class AppMainRouter extends Component {
await Promise.all(promises) await Promise.all(promises)
await this.setKeys(web3Config.defaultAccount) await contractsStore.updateKeys(web3Config.defaultAccount)
contractsStore.getKeysBallotThreshold() await contractsStore.getMinBallotDurationsAndThresholds()
contractsStore.getProxyBallotThreshold()
contractsStore.getBallotCancelingThreshold()
await contractsStore.getBallotsLimits()
await contractsStore.getAllValidatorMetadata() await contractsStore.getAllValidatorMetadata()
await contractsStore.getAllBallots() await contractsStore.getAllBallots()
@ -109,18 +105,6 @@ class AppMainRouter extends Component {
this.initChain() 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() { render() {
return ( return (
<Provider {...stores}> <Provider {...stores}>

View File

@ -49,39 +49,26 @@ class ContractsStore {
@observable injectedWeb3 @observable injectedWeb3
constructor() { constructor() {
this.votingKey = null this.votingKey = '0x0000000000000000000000000000000000000000'
this.miningKey = null this.miningKey = '0x0000000000000000000000000000000000000000'
this.validatorsMetadata = {} this.validatorsMetadata = {}
this.validatorLimits = { keys: null, minThreshold: null, proxy: null } this.validatorLimits = { keys: null, minThreshold: null, proxy: null }
this.minBallotDuration = { keys: 0, minThreshold: 0, proxy: 0 } this.minBallotDuration = { keys: 0, minThreshold: 0, proxy: 0 }
this.injectedWeb3 = false this.injectedWeb3 = false
} }
@computed
get isEmptyVotingKey() {
return !this.votingKey || this.votingKey === '0x0000000000000000000000000000000000000000'
}
@computed @computed
get isValidVotingKey() { get isValidVotingKey() {
if (this.isEmptyVotingKey) return false
if (this.miningKey && this.miningKey !== '0x0000000000000000000000000000000000000000') return true if (this.miningKey && this.miningKey !== '0x0000000000000000000000000000000000000000') return true
return false 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') @action('Set web3Instance')
setWeb3Instance = web3Config => { setWeb3Instance = web3Config => {
this.web3Instance = web3Config.web3Instance this.web3Instance = web3Config.web3Instance
@ -206,12 +193,32 @@ class ContractsStore {
@action('Set mining key') @action('Set mining key')
setMiningKey = async account => { setMiningKey = async account => {
try { let miningKey = '0x0000000000000000000000000000000000000000'
this.miningKey = await this.keysManager.instance.methods.miningKeyByVoting(account).call() if (account && account !== '0x0000000000000000000000000000000000000000') {
} catch (e) { try {
console.log(e) miningKey = await this.keysManager.instance.methods.miningKeyByVoting(account).call()
this.miningKey = '0x0000000000000000000000000000000000000000' } 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') @action('Get all keys ballots')
@ -410,41 +417,63 @@ class ContractsStore {
async getBallotsLimits() { async getBallotsLimits() {
return new Promise(async resolve => { return new Promise(async resolve => {
if (this.web3Instance && this.netId) { 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) if (this.isValidVotingKey) {
const getMinThresholdLimit = await this.votingToChangeMinThreshold.getBallotLimit( const limitPerValidator = await this.ballotsStorage.instance.methods.getBallotLimitPerValidator().call()
this.miningKey, keysLimit = await this.votingToChangeKeys.getBallotLimit(this.miningKey, limitPerValidator)
limitPerValidator minThresholdLimit = await this.votingToChangeMinThreshold.getBallotLimit(this.miningKey, limitPerValidator)
) proxyLimit = await this.votingToChangeProxy.getBallotLimit(this.miningKey, limitPerValidator)
const getProxyLimit = await this.votingToChangeProxy.getBallotLimit(this.miningKey, limitPerValidator) }
const getKeysMinBallotDuration = await this.votingToChangeKeys.minBallotDuration() this.validatorLimits.keys = keysLimit
const getMinThresholdMinBallotDuration = await this.votingToChangeMinThreshold.minBallotDuration() this.validatorLimits.minThreshold = minThresholdLimit
const getProxyMinBallotDuration = await this.votingToChangeProxy.minBallotDuration() 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([ await Promise.all([
getKeysLimit,
getMinThresholdLimit,
getProxyLimit,
getKeysMinBallotDuration, getKeysMinBallotDuration,
getMinThresholdMinBallotDuration, getMinThresholdMinBallotDuration,
getProxyMinBallotDuration getProxyMinBallotDuration,
getBallotThreshold,
getProxyThreshold,
getBallotCancelingThreshold
]).then( ]).then(
([ ([
keysLimit,
minThresholdLimit,
proxyLimit,
keysMinBallotDuration, keysMinBallotDuration,
minThresholdMinBallotDuration, minThresholdMinBallotDuration,
proxyMinBallotDuration proxyMinBallotDuration,
keysBallotThreshold,
proxyBallotThreshold,
cancelingThreshold
]) => { ]) => {
this.validatorLimits.keys = keysLimit
this.validatorLimits.minThreshold = minThresholdLimit
this.validatorLimits.proxy = proxyLimit
this.minBallotDuration.keys = keysMinBallotDuration this.minBallotDuration.keys = keysMinBallotDuration
this.minBallotDuration.minThreshold = minThresholdMinBallotDuration this.minBallotDuration.minThreshold = minThresholdMinBallotDuration
this.minBallotDuration.proxy = proxyMinBallotDuration this.minBallotDuration.proxy = proxyMinBallotDuration
this.keysBallotThreshold = keysBallotThreshold
this.minThresholdBallotThreshold = keysBallotThreshold
this.proxyBallotThreshold = proxyBallotThreshold
this.emissionFundsBallotThreshold = proxyBallotThreshold
this.ballotCancelingThreshold = cancelingThreshold
resolve() resolve()
} }
) )

View File

@ -1,21 +1,33 @@
import Web3 from 'web3' import Web3 from 'web3'
import helpers from './helpers' import helpers from './helpers'
import { constants } from './constants' import { constants } from './constants'
import messages from './messages'
const defaultNetId = helpers.netIdByBranch(constants.CORE) 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 let web3 = null
// Checking if Web3 has been injected by the browser (Mist/MetaMask) // Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (window.ethereum) { if (window.ethereum) {
web3 = new Web3(window.ethereum) web3 = new Web3(window.ethereum)
console.log('Injected web3 detected.') 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 window.ethereum.autoRefreshOnNetworkChange = true
} else if (window.web3) { } else if (window.web3) {
web3 = new Web3(window.web3.currentProvider) web3 = new Web3(window.web3.currentProvider)
@ -63,12 +75,12 @@ export default async function getWeb3(netId, onAccountChange) {
} }
if (web3.currentProvider.publicConfigStore) { if (web3.currentProvider.publicConfigStore) {
let currentAccount = defaultAccount ? defaultAccount.toLowerCase() : '' let currentAccount = defaultAccount ? defaultAccount.toLowerCase() : null
web3.currentProvider.publicConfigStore.on('update', function(obj) { web3.currentProvider.publicConfigStore.on('update', function(obj) {
const account = obj.selectedAddress const account = obj.selectedAddress
if (account && account !== currentAccount) { if (account !== currentAccount) {
currentAccount = account currentAccount = account
onAccountChange(account) updateKeys(account)
} }
}) })
} }