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 { 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 <NewBallot networkBranch={this.getVotingNetworkBranch()} />
}

View File

@ -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

View File

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

View File

@ -17,6 +17,7 @@ import { getNetworkBranch } from '../../utils/utils'
import { inject, observer } from 'mobx-react'
import messages from '../../utils/messages'
import { sendTransactionByVotingKey } from '../../utils/helpers'
import { enableWallet } from '../../utils/getWeb3'
@inject('commonStore', 'ballotStore', 'validatorStore', 'contractsStore', 'routing', 'ballotsStore')
@observer
@ -253,7 +254,14 @@ export class NewBallot extends React.Component {
const { commonStore, contractsStore, ballotStore, ballotsStore } = this.props
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')
return
} else if (!contractsStore.networkMatch) {

View File

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

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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 (
<Provider {...stores}>

View File

@ -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()
}
)

View File

@ -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)
}
})
}